diff --git a/client/package-lock.json b/client/package-lock.json
index 2c9320b5fb..c7665d2d23 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -12,6 +12,7 @@
"@radix-ui/react-alert-dialog": "^1.0.2",
"@radix-ui/react-dialog": "^1.0.2",
"@radix-ui/react-dropdown-menu": "^2.0.2",
+ "@radix-ui/react-hover-card": "^1.0.5",
"@radix-ui/react-label": "^2.0.0",
"@radix-ui/react-slider": "^1.1.1",
"@radix-ui/react-tabs": "^1.0.3",
@@ -2974,6 +2975,27 @@
"react-dom": "^16.8 || ^17.0 || ^18.0"
}
},
+ "node_modules/@radix-ui/react-hover-card": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.0.5.tgz",
+ "integrity": "sha512-jXRuZEkxSWdHZbVyL0J46cm7pQjmOMpwJEFKY+VqAJnV+FxS+zIZExI1OCeIiDwCBzUy6If1FfouOsfqBxr86g==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.0",
+ "@radix-ui/react-compose-refs": "1.0.0",
+ "@radix-ui/react-context": "1.0.0",
+ "@radix-ui/react-dismissable-layer": "1.0.3",
+ "@radix-ui/react-popper": "1.1.1",
+ "@radix-ui/react-portal": "1.0.2",
+ "@radix-ui/react-presence": "1.0.0",
+ "@radix-ui/react-primitive": "1.0.2",
+ "@radix-ui/react-use-controllable-state": "1.0.0"
+ },
+ "peerDependencies": {
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ }
+ },
"node_modules/@radix-ui/react-id": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.0.tgz",
@@ -15802,6 +15824,23 @@
"@radix-ui/react-use-callback-ref": "1.0.0"
}
},
+ "@radix-ui/react-hover-card": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.0.5.tgz",
+ "integrity": "sha512-jXRuZEkxSWdHZbVyL0J46cm7pQjmOMpwJEFKY+VqAJnV+FxS+zIZExI1OCeIiDwCBzUy6If1FfouOsfqBxr86g==",
+ "requires": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.0",
+ "@radix-ui/react-compose-refs": "1.0.0",
+ "@radix-ui/react-context": "1.0.0",
+ "@radix-ui/react-dismissable-layer": "1.0.3",
+ "@radix-ui/react-popper": "1.1.1",
+ "@radix-ui/react-portal": "1.0.2",
+ "@radix-ui/react-presence": "1.0.0",
+ "@radix-ui/react-primitive": "1.0.2",
+ "@radix-ui/react-use-controllable-state": "1.0.0"
+ }
+ },
"@radix-ui/react-id": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.0.tgz",
diff --git a/client/package.json b/client/package.json
index 547e18ee2c..13610d2f23 100644
--- a/client/package.json
+++ b/client/package.json
@@ -22,6 +22,7 @@
"@radix-ui/react-alert-dialog": "^1.0.2",
"@radix-ui/react-dialog": "^1.0.2",
"@radix-ui/react-dropdown-menu": "^2.0.2",
+ "@radix-ui/react-hover-card": "^1.0.5",
"@radix-ui/react-label": "^2.0.0",
"@radix-ui/react-slider": "^1.1.1",
"@radix-ui/react-tabs": "^1.0.3",
diff --git a/client/src/components/Input/OpenAIOptions/ModelSelect.jsx b/client/src/components/Input/OpenAIOptions/ModelSelect.jsx
new file mode 100644
index 0000000000..73e2a7303b
--- /dev/null
+++ b/client/src/components/Input/OpenAIOptions/ModelSelect.jsx
@@ -0,0 +1,54 @@
+import React, { useState } from 'react';
+import { Button } from '../../ui/Button.tsx';
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuLabel,
+ DropdownMenuRadioGroup,
+ DropdownMenuSeparator,
+ DropdownMenuTrigger,
+ DropdownMenuRadioItem
+} from '../../ui/DropdownMenu.tsx';
+
+const ModelSelect = ({ model, onChange, models, ...props }) => {
+ const [menuOpen, setMenuOpen] = useState(false);
+
+ models = ['gpt-4', 'text-davinci-003', 'gpt-3.5-turbo', 'gpt-3.5-turbo-0301'];
+
+ return (
+
+
+
+
+ event.preventDefault()}
+ >
+ Select a model
+
+
+ {models.map(model => (
+
+ {model}
+
+ ))}
+
+
+
+ );
+};
+
+export default ModelSelect;
diff --git a/client/src/components/Input/OpenAIOptions/OptionHover.jsx b/client/src/components/Input/OpenAIOptions/OptionHover.jsx
new file mode 100644
index 0000000000..8f36468ee9
--- /dev/null
+++ b/client/src/components/Input/OpenAIOptions/OptionHover.jsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import {
+ // HoverCard,
+ // HoverCardTrigger,
+ HoverCardPortal,
+ HoverCardContent
+} from '~/components/ui/HoverCard.tsx';
+
+// import { cn } from '~/utils/';
+
+const types = {
+ temp: {
+ description:
+ 'Higher values = more random, while lower values = more focused and deterministic. We recommend altering this or Top P but not both.'
+ },
+ max: {
+ description:
+ 'The max tokens to generate. The total length of input tokens and generated tokens is limited by the model\'s context length.'
+ },
+ 'top-p': {
+ description:
+ 'An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered. We recommend altering this or temperature but not both.'
+ },
+ freq: {
+ description:
+ 'Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model\'s likelihood to repeat the same line verbatim.'
+ },
+ pres: {
+ description:
+ 'Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model\'s likelihood to talk about new topics.'
+ },
+};
+
+function OptionHover({ type, side }) {
+
+ const options = {};
+
+ if (type === 'pres') {
+ options.sideOffset = 45;
+ }
+
+ return (
+
+
+
+
{types[type].description}
+
+
+
+ );
+}
+
+export default OptionHover;
diff --git a/client/src/components/Input/OpenAIOptions/Settings.jsx b/client/src/components/Input/OpenAIOptions/Settings.jsx
index 60d06ec1fe..6ea499464d 100644
--- a/client/src/components/Input/OpenAIOptions/Settings.jsx
+++ b/client/src/components/Input/OpenAIOptions/Settings.jsx
@@ -3,17 +3,24 @@ import TextareaAutosize from 'react-textarea-autosize';
import { Input } from '~/components/ui/Input.tsx';
import { Label } from '~/components/ui/Label.tsx';
import { Slider } from '~/components/ui/Slider.tsx';
+import OptionHover from './OptionHover';
+import {
+ HoverCard,
+ HoverCardTrigger
+ // HoverCardContent,
+} from '~/components/ui/HoverCard.tsx';
import { cn } from '~/utils/';
const defaultTextProps =
'rounded-md border border-gray-300 bg-transparent text-sm shadow-[0_0_10px_rgba(0,0,0,0.10)] outline-none placeholder:text-gray-400 focus:outline-none focus:ring-gray-400 focus:ring-opacity-20 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-none dark:bg-gray-700 dark:text-gray-50 dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] dark:focus:border-none dark:focus:border-transparent dark:focus:outline-none dark:focus:ring-0 dark:focus:ring-gray-400 dark:focus:ring-offset-0';
-const optionText = 'p-0 shadow-none text-right pr-1 h-8';
+const optionText =
+ 'p-0 shadow-none text-right pr-1 h-8 border-transparent focus:ring-[#10a37f] focus:ring-offset-0 focus:ring-opacity-100';
function Settings() {
const [chatGptLabel, setChatGptLabel] = useState('');
const [promptPrefix, setPromptPrefix] = useState('');
const [temperature, setTemperature] = useState(1);
- const [maxLength, setMaxLength] = useState(2048);
+ const [maxTokens, setMaxTokens] = useState(2048);
const [topP, setTopP] = useState(1);
const [freqP, setFreqP] = useState(0);
const [presP, setPresP] = useState(0);
@@ -32,151 +39,216 @@ function Settings() {
More info here
*/}
-
-
-
-
setChatGptLabel(e.target.value)}
- placeholder="Set a custom name for ChatGPT"
- className=" col-span-3 shadow-[0_0_10px_rgba(0,0,0,0.10)] outline-none placeholder:text-gray-400 dark:bg-gray-700
+ <>
+
+
+
+ setChatGptLabel(e.target.value)}
+ placeholder="Set a custom name for ChatGPT"
+ className=" col-span-3 shadow-[0_0_10px_rgba(0,0,0,0.10)] outline-none placeholder:text-gray-400 dark:bg-gray-700
dark:text-gray-50 dark:shadow-[0_0_15px_rgba(0,0,0,0.10)]"
- />
-
-
-
- setPromptPrefix(e.target.value)}
- placeholder="Set custom instructions. Defaults to: 'You are ChatGPT, a large language model trained by OpenAI.'"
- className={cn(defaultTextProps, 'col-span-3 flex h-10 max-h-10 w-full resize-none px-3 py-2 ')}
- onFocus={() => {
- textareaRef.current.classList.remove('max-h-10');
- textareaRef.current.classList.add('max-h-52');
- }}
- onBlur={() => {
- textareaRef.current.classList.remove('max-h-52');
- textareaRef.current.classList.add('max-h-10');
- }}
- ref={textareaRef}
- />
-
-
-
-
- setTemperature(e.target.value)}
- placeholder="1.0"
- className={cn(defaultTextProps, `w-9 ${optionText}`)}
/>
-
+
- setMaxLength(e.target.value)}
- placeholder="1.0"
- className={cn(defaultTextProps, `w-11 ${optionText}`)}
+ setPromptPrefix(e.target.value)}
+ placeholder="Set custom instructions. Defaults to: 'You are ChatGPT, a large language model trained by OpenAI.'"
+ className={cn(defaultTextProps, 'col-span-3 flex h-10 max-h-10 w-full resize-none px-3 py-2 ')}
+ onFocus={() => {
+ textareaRef.current.classList.remove('max-h-10');
+ textareaRef.current.classList.add('max-h-52');
+ }}
+ onBlur={() => {
+ textareaRef.current.classList.remove('max-h-52');
+ textareaRef.current.classList.add('max-h-10');
+ }}
+ ref={textareaRef}
/>
-
+
-
- setTemperature(value)}
- max={2}
- min={0}
- step={0.01}
- className="w-full"
- />
- setMaxLength(value)}
- max={2048}
- min={1}
- step={1}
- className="w-full"
- />
-
-
-
-
-
-
setTopP(e.target.value)}
- placeholder="1.0"
- className={cn(defaultTextProps, `w-9 ${optionText}`)}
+
+ setTemperature(value)}
+ max={2}
+ min={0}
+ step={0.01}
+ className="w-full"
+ />
+ setMaxTokens(value)}
+ max={2048} // should be dynamic to the currently selected model
+ min={1}
+ step={1}
+ className="w-full"
/>
-
-
- setTopP(value)}
- max={2}
- min={0}
- step={0.01}
- className="w-full"
- />
- setFreqP(value)}
- max={2}
- min={0}
- step={0.01}
- className="w-full"
- />
-
-
+ >
);
}
diff --git a/client/src/components/Input/OpenAIOptions/index.jsx b/client/src/components/Input/OpenAIOptions/index.jsx
index 04138e6d77..0d1050df2c 100644
--- a/client/src/components/Input/OpenAIOptions/index.jsx
+++ b/client/src/components/Input/OpenAIOptions/index.jsx
@@ -1,6 +1,6 @@
-import React, { useState, useEffect, forwardRef } from 'react';
-import { Tabs, TabsList, TabsTrigger } from '../../ui/Tabs.tsx';
-import { useRecoilValue, useRecoilState } from 'recoil';
+import React, { useEffect, useState } from 'react';
+import { useSetRecoilState } from 'recoil';
+import ModelSelect from './ModelSelect';
import { Button } from '../../ui/Button.tsx';
import Settings from './Settings.jsx';
@@ -8,29 +8,75 @@ import store from '~/store';
function OpenAIOptions({ conversation = {} }) {
const { endpoint } = conversation;
- const { advancedMode, setAdvancedMode } = useState(false);
+ const [advancedMode, setAdvancedMode] = useState(false);
+ const setConversation = useSetRecoilState(store.conversation);
const triggerAdvancedMode = () => setAdvancedMode(prev => !prev);
+ const switchToSimpleMode = () => {
+ setConversation(prevState => ({
+ ...prevState,
+ chatGptLabel: null,
+ promptPrefix: null,
+ temperature: 0.8,
+ top_p: 1,
+ presence_penalty: 1
+ }));
+ setAdvancedMode(false);
+ };
+
+ const setModel = newModel => {
+ setConversation(prevState => ({
+ ...prevState,
+ model: newModel
+ }));
+ };
+
+ useEffect(() => {
+ const { endpoint, chatGptLabel, promptPrefix, temperature, top_p, presence_penalty } = conversation;
+
+ if (endpoint !== 'openAI') return;
+
+ const mustInAdvancedMode =
+ chatGptLabel !== null ||
+ promptPrefix !== null ||
+ temperature !== 0.8 ||
+ top_p !== 1 ||
+ presence_penalty !== 1;
+
+ if (mustInAdvancedMode && !advancedMode) setAdvancedMode(true);
+ }, [conversation, advancedMode]);
+
if (endpoint !== 'openAI') return null;
const { model } = conversation;
const cardStyle =
- 'shadow-md px-4 h-[40px] rounded-md min-w-[75px] font-normal bg-white border-black/10 border dark:bg-gray-700 text-black dark:text-white';
+ 'shadow-md rounded-md min-w-[75px] font-normal bg-white border-black/10 border dark:bg-gray-700 text-black dark:text-white';
return (
<>
-
+
+
-