mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 00:40:14 +01:00
feat: advanced style for openAI endpoint
This commit is contained in:
parent
60be4f12b7
commit
edaf7c3ad1
3 changed files with 276 additions and 80 deletions
|
|
@ -4,14 +4,12 @@ import { HoverCardPortal, HoverCardContent } from '~/components/ui/HoverCard.tsx
|
|||
const types = {
|
||||
temp: 'Higher values = more random, while lower values = more focused and deterministic. We recommend altering this or Top P but not both.',
|
||||
max: "The max tokens to generate. The total length of input tokens and generated tokens is limited by the model's context length.",
|
||||
'top-p':
|
||||
'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.',
|
||||
topp: '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: "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: "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;
|
||||
|
|
@ -21,7 +19,7 @@ function OptionHover({ type, side }) {
|
|||
<HoverCardPortal>
|
||||
<HoverCardContent
|
||||
side={side}
|
||||
className="w-52 "
|
||||
className="w-80 "
|
||||
// {...options}
|
||||
>
|
||||
<div className="space-y-2">
|
||||
|
|
|
|||
|
|
@ -7,12 +7,17 @@ import OptionHover from './OptionHover';
|
|||
import { HoverCard, HoverCardTrigger } 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';
|
||||
'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-gray-400 dark:bg-gray-700 dark:text-gray-50 dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] dark:focus:border-gray-400 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 border-transparent focus:ring-[#10a37f] focus:ring-offset-0 focus:ring-opacity-100';
|
||||
'p-0 shadow-none text-right pr-1 h-8 border-transparent focus:ring-[#10a37f] focus:ring-offset-0 focus:ring-opacity-100 hover:bg-gray-800/10 dark:hover:bg-white/10 focus:bg-gray-800/10 dark:focus:bg-white/10 transition-colors';
|
||||
|
||||
function Settings({ isOpen }) {
|
||||
// const endpointsConfig = useRecoilValue(store.endpointsConfig);
|
||||
|
||||
// const availableModels = endpointsConfig?.['openAI']?.['availableModels'] || [];
|
||||
|
||||
const [model, setModel] = useState('text-davinci-003');
|
||||
const [chatGptLabel, setChatGptLabel] = useState('');
|
||||
const [promptPrefix, setPromptPrefix] = useState('');
|
||||
const [temperature, setTemperature] = useState(1);
|
||||
|
|
@ -20,32 +25,55 @@ function Settings({ isOpen }) {
|
|||
const [topP, setTopP] = useState(1);
|
||||
const [freqP, setFreqP] = useState(0);
|
||||
const [presP, setPresP] = useState(0);
|
||||
const textareaRef = useRef(null);
|
||||
const inputRef = useRef(null);
|
||||
// const textareaRef = useRef(null);
|
||||
// const inputRef = useRef(null);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="grid gap-4 py-4 md:px-14 lg:px-20">
|
||||
<div className="grid grid-cols-4 items-center gap-4">
|
||||
<div className="grid grid-cols-2 gap-6">
|
||||
<div className="col-span-1 flex flex-col items-center justify-start gap-6">
|
||||
<div className="grid w-full items-center gap-2">
|
||||
<Label
|
||||
htmlFor="model"
|
||||
className="text-left text-sm font-medium"
|
||||
>
|
||||
Model
|
||||
</Label>
|
||||
<Input
|
||||
id="model"
|
||||
value={model}
|
||||
// ref={inputRef}
|
||||
onChange={e => setModel(e.target.value)}
|
||||
placeholder="Set a custom name for ChatGPT"
|
||||
className={cn(
|
||||
defaultTextProps,
|
||||
'flex h-10 max-h-10 w-full resize-none px-3 py-2 focus:outline-none focus:ring-0 focus:ring-opacity-0 focus:ring-offset-0'
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid w-full items-center gap-2">
|
||||
<Label
|
||||
htmlFor="chatGptLabel"
|
||||
className="text-right text-sm"
|
||||
className="text-left text-sm font-medium"
|
||||
>
|
||||
Custom Name
|
||||
</Label>
|
||||
<Input
|
||||
id="chatGptLabel"
|
||||
value={chatGptLabel}
|
||||
ref={inputRef}
|
||||
// ref={inputRef}
|
||||
onChange={e => setChatGptLabel(e.target.value)}
|
||||
placeholder="Set a custom name for ChatGPT"
|
||||
className={cn(defaultTextProps, 'col-span-3 flex h-10 max-h-10 w-full resize-none px-3 py-2 focus:ring-0 focus:ring-offset-0 focus:ring-opacity-0 focus:outline-none')}
|
||||
className={cn(
|
||||
defaultTextProps,
|
||||
'flex h-10 max-h-10 w-full resize-none px-3 py-2 focus:outline-none focus:ring-0 focus:ring-opacity-0 focus:ring-offset-0'
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid grid-cols-4 items-center gap-4">
|
||||
<div className="grid w-full items-center gap-2">
|
||||
<Label
|
||||
htmlFor="promptPrefix"
|
||||
className="text-right text-sm"
|
||||
className="text-left text-sm font-medium"
|
||||
>
|
||||
Prompt Prefix
|
||||
</Label>
|
||||
|
|
@ -54,19 +82,193 @@ function Settings({ isOpen }) {
|
|||
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={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}
|
||||
className={cn(
|
||||
defaultTextProps,
|
||||
'flex max-h-[300px] min-h-[100px] 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}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex justify-around">
|
||||
</div>
|
||||
<div className="col-span-1 flex flex-col items-center justify-start gap-6">
|
||||
<HoverCard>
|
||||
<HoverCardTrigger className="grid w-full items-center gap-2">
|
||||
<div className="flex justify-between">
|
||||
<Label
|
||||
htmlFor="chatGptLabel"
|
||||
className="text-left text-sm font-medium"
|
||||
>
|
||||
Temperature
|
||||
</Label>
|
||||
<Input
|
||||
id="temp-int"
|
||||
value={temperature}
|
||||
onChange={e => setTemperature(e.target.value)}
|
||||
className={cn(
|
||||
defaultTextProps,
|
||||
cn(optionText, 'h-auto w-12 border-0 group-hover/temp:border-gray-200')
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<Slider
|
||||
value={[temperature]}
|
||||
onValueChange={value => setTemperature(value)}
|
||||
max={2}
|
||||
min={0}
|
||||
step={0.01}
|
||||
className="flex h-4 w-full"
|
||||
/>
|
||||
</HoverCardTrigger>
|
||||
<OptionHover
|
||||
type="temp"
|
||||
side="left"
|
||||
/>
|
||||
</HoverCard>
|
||||
|
||||
<HoverCard>
|
||||
<HoverCardTrigger className="grid w-full items-center gap-2">
|
||||
<div className="flex justify-between">
|
||||
<Label
|
||||
htmlFor="chatGptLabel"
|
||||
className="text-left text-sm font-medium"
|
||||
>
|
||||
Max tokens
|
||||
</Label>
|
||||
<Input
|
||||
id="max-tokens-int"
|
||||
value={maxTokens}
|
||||
onChange={e => setMaxTokens(e.target.value)}
|
||||
className={cn(
|
||||
defaultTextProps,
|
||||
cn(optionText, 'h-auto w-12 border-0 group-hover/temp:border-gray-200')
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<Slider
|
||||
value={[maxTokens]}
|
||||
onValueChange={value => setMaxTokens(value)}
|
||||
max={2048} // should be dynamic to the currently selected model
|
||||
min={1}
|
||||
step={1}
|
||||
className="flex h-4 w-full"
|
||||
/>
|
||||
</HoverCardTrigger>
|
||||
<OptionHover
|
||||
type="max"
|
||||
side="left"
|
||||
/>
|
||||
</HoverCard>
|
||||
|
||||
<HoverCard>
|
||||
<HoverCardTrigger className="grid w-full items-center gap-2">
|
||||
<div className="flex justify-between">
|
||||
<Label
|
||||
htmlFor="chatGptLabel"
|
||||
className="text-left text-sm font-medium"
|
||||
>
|
||||
Top P
|
||||
</Label>
|
||||
<Input
|
||||
id="top-p-int"
|
||||
value={topP}
|
||||
onChange={e => setTopP(e.target.value)}
|
||||
className={cn(
|
||||
defaultTextProps,
|
||||
cn(optionText, 'h-auto w-12 border-0 group-hover/temp:border-gray-200')
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<Slider
|
||||
value={[topP]}
|
||||
onValueChange={value => setTopP(value)}
|
||||
max={1}
|
||||
min={0}
|
||||
step={0.01}
|
||||
className="flex h-4 w-full"
|
||||
/>
|
||||
</HoverCardTrigger>
|
||||
<OptionHover
|
||||
type="topp"
|
||||
side="left"
|
||||
/>
|
||||
</HoverCard>
|
||||
|
||||
<HoverCard>
|
||||
<HoverCardTrigger className="grid w-full items-center gap-2">
|
||||
<div className="flex justify-between">
|
||||
<Label
|
||||
htmlFor="chatGptLabel"
|
||||
className="text-left text-sm font-medium"
|
||||
>
|
||||
Frequency Penalty
|
||||
</Label>
|
||||
<Input
|
||||
id="freq-penalty-int"
|
||||
value={freqP}
|
||||
onChange={e => setFreqP(e.target.value)}
|
||||
className={cn(
|
||||
defaultTextProps,
|
||||
cn(optionText, 'h-auto w-12 border-0 group-hover/temp:border-gray-200')
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<Slider
|
||||
value={[freqP]}
|
||||
onValueChange={value => setFreqP(value)}
|
||||
max={2}
|
||||
min={-2}
|
||||
step={0.01}
|
||||
className="flex h-4 w-full"
|
||||
/>
|
||||
</HoverCardTrigger>
|
||||
<OptionHover
|
||||
type="freq"
|
||||
side="left"
|
||||
/>
|
||||
</HoverCard>
|
||||
|
||||
<HoverCard>
|
||||
<HoverCardTrigger className="grid w-full items-center gap-2">
|
||||
<div className="flex justify-between">
|
||||
<Label
|
||||
htmlFor="chatGptLabel"
|
||||
className="text-left text-sm font-medium"
|
||||
>
|
||||
Presence Penalty
|
||||
</Label>
|
||||
<Input
|
||||
id="pres-penalty-int"
|
||||
value={presP}
|
||||
onChange={e => setPresP(e.target.value)}
|
||||
className={cn(
|
||||
defaultTextProps,
|
||||
cn(optionText, 'h-auto w-12 border-0 group-hover/temp:border-gray-200')
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<Slider
|
||||
value={[presP]}
|
||||
onValueChange={value => setPresP(value)}
|
||||
max={2}
|
||||
min={-2}
|
||||
step={0.01}
|
||||
className="flex h-4 w-full"
|
||||
/>
|
||||
</HoverCardTrigger>
|
||||
<OptionHover
|
||||
type="pres"
|
||||
side="left"
|
||||
/>
|
||||
</HoverCard>
|
||||
{/* <div className="flex justify-around">
|
||||
<HoverCard>
|
||||
<HoverCardTrigger className="group/temp mr-4 flex w-full items-center justify-end gap-4">
|
||||
<Label
|
||||
|
|
@ -109,14 +311,6 @@ function Settings({ isOpen }) {
|
|||
</HoverCard>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 items-center gap-5">
|
||||
<Slider
|
||||
value={[temperature]}
|
||||
onValueChange={value => setTemperature(value)}
|
||||
max={2}
|
||||
min={0}
|
||||
step={0.01}
|
||||
className="w-full"
|
||||
/>
|
||||
<Slider
|
||||
value={[maxTokens]}
|
||||
onValueChange={value => setMaxTokens(value)}
|
||||
|
|
@ -225,6 +419,7 @@ function Settings({ isOpen }) {
|
|||
step={0.01}
|
||||
className="w-full"
|
||||
/>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Settings2 } from 'lucide-react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import ModelSelect from './ModelSelect';
|
||||
import { Button } from '../../ui/Button.tsx';
|
||||
import Settings from './Settings.jsx';
|
||||
|
|
@ -11,8 +11,30 @@ import store from '~/store';
|
|||
function OpenAIOptions() {
|
||||
const [advancedMode, setAdvancedMode] = useState(false);
|
||||
const [conversation, setConversation] = useRecoilState(store.conversation) || {};
|
||||
const endpointsConfig = useRecoilValue(store.endpointsConfig);
|
||||
const { endpoint, conversationId } = conversation;
|
||||
|
||||
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;
|
||||
if (conversationId !== 'new') return null;
|
||||
|
||||
const { model } = conversation;
|
||||
const availableModels = endpointsConfig?.['openAI']?.['availableModels'] || [];
|
||||
|
||||
const triggerAdvancedMode = () => setAdvancedMode(prev => !prev);
|
||||
|
||||
const switchToSimpleMode = () => {
|
||||
|
|
@ -34,26 +56,6 @@ function OpenAIOptions() {
|
|||
}));
|
||||
};
|
||||
|
||||
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;
|
||||
if (conversationId !== 'new') return null;
|
||||
|
||||
const { model } = conversation;
|
||||
|
||||
const cardStyle =
|
||||
'shadow-md rounded-md min-w-[75px] font-normal bg-white border-black/10 border dark:bg-gray-700 text-black dark:text-white';
|
||||
|
||||
|
|
@ -67,6 +69,7 @@ function OpenAIOptions() {
|
|||
>
|
||||
<ModelSelect
|
||||
model={model}
|
||||
availableModels={availableModels}
|
||||
onChange={setModel}
|
||||
type="button"
|
||||
className={cn(
|
||||
|
|
@ -107,7 +110,7 @@ function OpenAIOptions() {
|
|||
Switch to simple mode
|
||||
</Button>
|
||||
</div>
|
||||
<div className="h-[375px] p-5">
|
||||
<div className="px-4 py-4">
|
||||
<Settings isOpen={advancedMode} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue