2023-03-03 15:52:06 -05:00
|
|
|
import React, { useState, useEffect } from 'react';
|
|
|
|
|
import TextareaAutosize from 'react-textarea-autosize';
|
2023-02-13 15:58:35 -05:00
|
|
|
import { useSelector, useDispatch } from 'react-redux';
|
2023-03-03 15:52:06 -05:00
|
|
|
import { setModel, setDisabled, setCustomGpt } from '~/store/submitSlice';
|
2023-02-13 15:58:35 -05:00
|
|
|
import GPTIcon from '../svg/GPTIcon';
|
2023-02-15 12:29:56 -05:00
|
|
|
import BingIcon from '../svg/BingIcon';
|
2023-02-13 15:58:35 -05:00
|
|
|
import { Button } from '../ui/Button.tsx';
|
2023-03-03 15:52:06 -05:00
|
|
|
import { Input } from '../ui/Input.tsx';
|
|
|
|
|
import { Label } from '../ui/Label.tsx';
|
|
|
|
|
|
2023-02-13 15:58:35 -05:00
|
|
|
import {
|
|
|
|
|
DropdownMenu,
|
|
|
|
|
DropdownMenuContent,
|
|
|
|
|
DropdownMenuLabel,
|
|
|
|
|
DropdownMenuRadioGroup,
|
|
|
|
|
DropdownMenuRadioItem,
|
|
|
|
|
DropdownMenuSeparator,
|
|
|
|
|
DropdownMenuTrigger
|
|
|
|
|
} from '../ui/DropdownMenu.tsx';
|
|
|
|
|
|
2023-03-03 15:52:06 -05:00
|
|
|
import {
|
|
|
|
|
Dialog,
|
|
|
|
|
DialogTrigger,
|
|
|
|
|
DialogClose,
|
|
|
|
|
DialogContent,
|
|
|
|
|
DialogDescription,
|
|
|
|
|
DialogFooter,
|
|
|
|
|
DialogHeader,
|
|
|
|
|
DialogTitle
|
|
|
|
|
} from '../ui/Dialog.tsx';
|
|
|
|
|
|
2023-02-13 15:58:35 -05:00
|
|
|
export default function ModelMenu() {
|
2023-02-13 21:15:28 -05:00
|
|
|
const dispatch = useDispatch();
|
|
|
|
|
const { model } = useSelector((state) => state.submit);
|
2023-03-03 15:52:06 -05:00
|
|
|
const [chatGptLabel, setChatGptLabel] = useState('');
|
|
|
|
|
const [promptPrefix, setPromptPrefix] = useState('');
|
|
|
|
|
const [required, setRequired] = useState(false);
|
2023-02-13 15:58:35 -05:00
|
|
|
|
2023-02-22 21:30:48 -05:00
|
|
|
useEffect(() => {
|
|
|
|
|
const lastSelectedModel = JSON.parse(localStorage.getItem('model'));
|
2023-03-03 15:52:06 -05:00
|
|
|
if (lastSelectedModel && lastSelectedModel !== 'chatgptCustom') {
|
2023-02-22 21:30:48 -05:00
|
|
|
dispatch(setModel(lastSelectedModel));
|
|
|
|
|
}
|
2023-03-03 15:52:06 -05:00
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
2023-02-22 21:30:48 -05:00
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
localStorage.setItem('model', JSON.stringify(model));
|
|
|
|
|
}, [model]);
|
|
|
|
|
|
2023-03-03 15:52:06 -05:00
|
|
|
const onChange = (value) => {
|
|
|
|
|
if (value === 'chatgptCustom') {
|
|
|
|
|
// dispatch(setDisabled(true));
|
|
|
|
|
} else {
|
|
|
|
|
dispatch(setModel(value));
|
|
|
|
|
dispatch(setDisabled(false));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const submitHandler = (e) => {
|
|
|
|
|
if (chatGptLabel.length === 0) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
setRequired(true);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
dispatch(setCustomGpt({ chatGptLabel, promptPrefix }));
|
|
|
|
|
dispatch(setModel('chatgptCustom'));
|
|
|
|
|
dispatch(setDisabled(false));
|
|
|
|
|
};
|
|
|
|
|
|
2023-02-13 15:58:35 -05:00
|
|
|
const defaultColorProps = [
|
|
|
|
|
'text-gray-500',
|
|
|
|
|
'hover:bg-gray-100',
|
|
|
|
|
'disabled:hover:bg-transparent',
|
2023-03-03 16:33:02 -05:00
|
|
|
'dark:hover:bg-opacity-40',
|
2023-02-13 15:58:35 -05:00
|
|
|
'dark:hover:bg-gray-900',
|
|
|
|
|
'dark:hover:text-gray-400',
|
2023-03-03 16:33:02 -05:00
|
|
|
'dark:data-[state=open]:bg-transparent',
|
2023-02-13 15:58:35 -05:00
|
|
|
'dark:disabled:hover:bg-transparent'
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const chatgptColorProps = [
|
|
|
|
|
'text-green-700',
|
2023-02-13 20:13:59 -05:00
|
|
|
'dark:text-emerald-300',
|
2023-02-13 15:58:35 -05:00
|
|
|
'hover:bg-green-100',
|
|
|
|
|
'disabled:hover:bg-transparent',
|
|
|
|
|
'dark:hover:bg-opacity-50',
|
|
|
|
|
'dark:hover:bg-green-900',
|
|
|
|
|
'dark:hover:text-gray-100',
|
2023-03-03 16:33:02 -05:00
|
|
|
// 'dark:data-[state=open]:bg-green-100',
|
2023-02-13 15:58:35 -05:00
|
|
|
'dark:disabled:hover:bg-transparent'
|
|
|
|
|
];
|
|
|
|
|
|
2023-03-03 15:52:06 -05:00
|
|
|
const requiredProp = required ? { required: true } : {};
|
|
|
|
|
|
2023-02-13 15:58:35 -05:00
|
|
|
const colorProps = model === 'chatgpt' ? chatgptColorProps : defaultColorProps;
|
2023-03-03 15:52:06 -05:00
|
|
|
const icon = model === 'bingai' ? <BingIcon button={true} /> : <GPTIcon button={true} />;
|
2023-02-13 15:58:35 -05:00
|
|
|
|
|
|
|
|
return (
|
2023-03-03 15:52:06 -05:00
|
|
|
<Dialog>
|
|
|
|
|
<DropdownMenu>
|
|
|
|
|
<DropdownMenuTrigger asChild>
|
|
|
|
|
<Button
|
|
|
|
|
variant="outline"
|
|
|
|
|
// style={{backgroundColor: 'rgb(16, 163, 127)'}}
|
|
|
|
|
className={`absolute bottom-0.5 rounded-md border-0 p-1 pl-2 outline-none ${colorProps.join(
|
|
|
|
|
' '
|
|
|
|
|
)} focus:ring-0 focus:ring-offset-0 disabled:bottom-0.5 md:bottom-1 md:left-2 md:pl-1 md:disabled:bottom-1`}
|
|
|
|
|
>
|
|
|
|
|
{icon}
|
|
|
|
|
</Button>
|
|
|
|
|
</DropdownMenuTrigger>
|
2023-03-03 16:33:02 -05:00
|
|
|
<DropdownMenuContent className="w-56 dark:bg-gray-700">
|
2023-03-03 15:52:06 -05:00
|
|
|
<DropdownMenuLabel>Select a Model</DropdownMenuLabel>
|
|
|
|
|
<DropdownMenuSeparator />
|
|
|
|
|
<DropdownMenuRadioGroup
|
|
|
|
|
value={model}
|
|
|
|
|
onValueChange={onChange}
|
|
|
|
|
>
|
2023-03-03 16:33:02 -05:00
|
|
|
<DropdownMenuRadioItem value="chatgpt" className="dark:font-semibold">
|
2023-03-03 15:52:06 -05:00
|
|
|
ChatGPT <sup>$</sup>
|
|
|
|
|
</DropdownMenuRadioItem>
|
|
|
|
|
<DialogTrigger asChild>
|
2023-03-03 16:33:02 -05:00
|
|
|
<DropdownMenuRadioItem value="chatgptCustom" className="dark:font-semibold">
|
2023-03-03 15:52:06 -05:00
|
|
|
CustomGPT <sup>$</sup>
|
|
|
|
|
</DropdownMenuRadioItem>
|
|
|
|
|
</DialogTrigger>
|
2023-03-03 16:33:02 -05:00
|
|
|
<DropdownMenuRadioItem value="bingai" className="dark:font-semibold">BingAI</DropdownMenuRadioItem>
|
|
|
|
|
<DropdownMenuRadioItem value="chatgptBrowser" className="dark:font-semibold">ChatGPT</DropdownMenuRadioItem>
|
2023-03-03 15:52:06 -05:00
|
|
|
</DropdownMenuRadioGroup>
|
|
|
|
|
</DropdownMenuContent>
|
|
|
|
|
</DropdownMenu>
|
|
|
|
|
<DialogContent>
|
|
|
|
|
<DialogHeader>
|
|
|
|
|
<DialogTitle>Customize ChatGPT</DialogTitle>
|
|
|
|
|
<DialogDescription>
|
|
|
|
|
Note: important instructions are often better placed in your message rather than
|
|
|
|
|
the prefix.{' '}
|
|
|
|
|
<a href="https://platform.openai.com/docs/guides/chat/instructing-chat-models">
|
|
|
|
|
<u>More info here</u>
|
|
|
|
|
</a>
|
|
|
|
|
</DialogDescription>
|
|
|
|
|
</DialogHeader>
|
|
|
|
|
<div className="grid gap-4 py-4">
|
|
|
|
|
<div className="grid grid-cols-4 items-center gap-4">
|
|
|
|
|
<Label
|
|
|
|
|
htmlFor="chatGptLabel"
|
|
|
|
|
className="text-right"
|
|
|
|
|
>
|
|
|
|
|
Custom Name
|
|
|
|
|
</Label>
|
|
|
|
|
<Input
|
|
|
|
|
id="chatGptLabel"
|
|
|
|
|
value={chatGptLabel}
|
|
|
|
|
onChange={(e) => setChatGptLabel(e.target.value)}
|
|
|
|
|
placeholder="Set a custom name for ChatGPT"
|
|
|
|
|
className="col-span-3 invalid:border-red-400 invalid:text-red-600 invalid:placeholder-red-600 invalid:placeholder-opacity-70
|
2023-03-03 16:33:02 -05:00
|
|
|
focus:ring-opacity-20 focus:invalid:border-red-400 focus:invalid:ring-red-400 focus:invalid:ring-opacity-20 dark:invalid:border-red-600 dark:invalid:text-red-300 dark:focus:invalid:ring-red-600"
|
2023-03-03 15:52:06 -05:00
|
|
|
{...requiredProp}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="grid grid-cols-4 items-center gap-4">
|
|
|
|
|
<Label
|
|
|
|
|
htmlFor="promptPrefix"
|
|
|
|
|
className="text-right"
|
|
|
|
|
>
|
|
|
|
|
Prompt Prefix
|
|
|
|
|
</Label>
|
|
|
|
|
<TextareaAutosize
|
|
|
|
|
id="promptPrefix"
|
|
|
|
|
value={promptPrefix}
|
|
|
|
|
onChange={(e) => setPromptPrefix(e.target.value)}
|
|
|
|
|
placeholder="Set custom instructions. Defaults to: 'You are ChatGPT, a large language model trained by OpenAI.'"
|
|
|
|
|
className="col-span-3 flex h-20 w-full resize-none rounded-md border border-slate-300 bg-transparent py-2 px-3 text-sm placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-opacity-20 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-700 dark:text-slate-50 dark:focus:ring-slate-400 dark:focus:ring-offset-slate-900"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<DialogFooter>
|
|
|
|
|
<DialogClose>Cancel</DialogClose>
|
2023-03-03 16:33:02 -05:00
|
|
|
<Button
|
|
|
|
|
style={{backgroundColor: 'rgb(16, 163, 127)'}}
|
|
|
|
|
className="inline-flex h-10 items-center justify-center rounded-md border-none py-2 px-4 text-sm font-semibold text-white transition-colors"
|
|
|
|
|
>
|
|
|
|
|
Save
|
|
|
|
|
</Button>
|
2023-03-03 15:52:06 -05:00
|
|
|
<DialogClose
|
|
|
|
|
onClick={submitHandler}
|
|
|
|
|
className="inline-flex h-10 items-center justify-center rounded-md border-none bg-slate-900 py-2 px-4 text-sm font-semibold text-white transition-colors hover:bg-slate-700 focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-slate-200 dark:focus:ring-slate-400 dark:focus:ring-offset-slate-900"
|
|
|
|
|
>
|
|
|
|
|
Submit
|
|
|
|
|
</DialogClose>
|
|
|
|
|
</DialogFooter>
|
|
|
|
|
</DialogContent>
|
|
|
|
|
</Dialog>
|
2023-02-13 15:58:35 -05:00
|
|
|
);
|
|
|
|
|
}
|