helloya20's picture
Upload 2345 files
f0743f4 verified
import { useMemo } from 'react';
import { useRecoilValue } from 'recoil';
import TextareaAutosize from 'react-textarea-autosize';
import { useAvailablePluginsQuery } from 'librechat-data-provider/react-query';
import {
Input,
Label,
Slider,
HoverCard,
InputNumber,
SelectDropDown,
HoverCardTrigger,
} from '@librechat/client';
import type { TModelSelectProps, OnInputNumberChange } from '~/common';
import type { TPlugin } from 'librechat-data-provider';
import {
removeFocusOutlines,
defaultTextProps,
removeFocusRings,
processPlugins,
selectPlugins,
optionText,
cn,
} from '~/utils';
import OptionHoverAlt from '~/components/SidePanel/Parameters/OptionHover';
import MultiSelectDropDown from '~/components/Input/ModelSelect/MultiSelectDropDown';
import { useLocalize, useDebouncedInput } from '~/hooks';
import OptionHover from './OptionHover';
import { ESide } from '~/common';
import store from '~/store';
export default function Settings({
conversation,
setOption,
setTools,
checkPluginSelection,
models,
readonly,
}: TModelSelectProps & {
setTools: (newValue: string, remove?: boolean | undefined) => void;
checkPluginSelection: (value: string) => boolean;
}) {
const localize = useLocalize();
const availableTools = useRecoilValue(store.availableTools);
const { data: allPlugins } = useAvailablePluginsQuery({
select: selectPlugins,
});
const conversationTools: TPlugin[] = useMemo(() => {
if (!conversation?.tools) {
return [];
}
return processPlugins(conversation.tools, allPlugins?.map);
}, [conversation, allPlugins]);
const availablePlugins = useMemo(() => {
if (!availableTools) {
return [];
}
return Object.values(availableTools);
}, [availableTools]);
const {
model,
modelLabel,
chatGptLabel,
promptPrefix,
temperature,
top_p: topP,
frequency_penalty: freqP,
presence_penalty: presP,
maxContextTokens,
} = conversation ?? {};
const [setChatGptLabel, chatGptLabelValue] = useDebouncedInput<string | null | undefined>({
setOption,
optionKey: 'chatGptLabel',
initialValue: modelLabel ?? chatGptLabel,
});
const [setPromptPrefix, promptPrefixValue] = useDebouncedInput<string | null | undefined>({
setOption,
optionKey: 'promptPrefix',
initialValue: promptPrefix,
});
const [setTemperature, temperatureValue] = useDebouncedInput<number | null | undefined>({
setOption,
optionKey: 'temperature',
initialValue: temperature,
});
const [setTopP, topPValue] = useDebouncedInput<number | null | undefined>({
setOption,
optionKey: 'top_p',
initialValue: topP,
});
const [setFreqP, freqPValue] = useDebouncedInput<number | null | undefined>({
setOption,
optionKey: 'frequency_penalty',
initialValue: freqP,
});
const [setPresP, presPValue] = useDebouncedInput<number | null | undefined>({
setOption,
optionKey: 'presence_penalty',
initialValue: presP,
});
const [setMaxContextTokens, maxContextTokensValue] = useDebouncedInput<number | null | undefined>(
{
setOption,
optionKey: 'maxContextTokens',
initialValue: maxContextTokens,
},
);
const setModel = setOption('model');
if (!conversation) {
return null;
}
return (
<div className="grid grid-cols-5 gap-6">
<div className="col-span-5 flex flex-col items-center justify-start gap-6 sm:col-span-3">
<div className="grid w-full items-center gap-2">
<SelectDropDown
title={localize('com_endpoint_completion_model')}
value={model ?? ''}
setValue={setModel}
availableValues={models}
disabled={readonly}
className={cn(defaultTextProps, 'flex w-full resize-none', removeFocusRings)}
containerClassName="flex w-full resize-none"
/>
</div>
<>
<div className="grid w-full items-center gap-2">
<Label htmlFor="chatGptLabel" className="text-left text-sm font-medium">
{localize('com_endpoint_custom_name')}{' '}
<small className="opacity-40">{localize('com_endpoint_default_empty')}</small>
</Label>
<Input
id="chatGptLabel"
disabled={readonly}
value={chatGptLabelValue || ''}
onChange={(e) => setChatGptLabel(e.target.value ?? null)}
placeholder={localize('com_endpoint_openai_custom_name_placeholder')}
className={cn(
defaultTextProps,
'flex h-10 max-h-10 w-full resize-none px-3 py-2',
removeFocusOutlines,
)}
/>
</div>
<div className="grid w-full items-center gap-2">
<Label htmlFor="promptPrefix" className="text-left text-sm font-medium">
{localize('com_endpoint_prompt_prefix')}{' '}
<small className="opacity-40">{localize('com_endpoint_default_empty')}</small>
</Label>
<TextareaAutosize
id="promptPrefix"
disabled={readonly}
value={promptPrefixValue || ''}
onChange={(e) => setPromptPrefix(e.target.value ?? null)}
placeholder={localize(
'com_endpoint_plug_set_custom_instructions_for_gpt_placeholder',
)}
className={cn(
defaultTextProps,
'flex max-h-[138px] min-h-[100px] w-full resize-none px-3 py-2',
)}
/>
</div>
</>
</div>
<div className="col-span-5 flex flex-col items-center justify-start gap-6 px-3 sm:col-span-2">
<MultiSelectDropDown
showAbove={false}
showLabel={false}
setSelected={setTools}
value={conversationTools}
optionValueKey="pluginKey"
availableValues={availablePlugins}
isSelected={checkPluginSelection}
searchPlaceholder={localize('com_ui_select_search_plugin')}
className={cn(defaultTextProps, 'flex w-full resize-none', removeFocusOutlines)}
optionsClassName="w-full max-h-[275px] dark:bg-gray-700 z-10 border dark:border-gray-600"
containerClassName="flex w-full resize-none border border-transparent"
labelClassName="dark:text-white"
/>
<HoverCard openDelay={300}>
<HoverCardTrigger className="grid w-full items-center gap-2">
<div className="mt-1 flex w-full justify-between">
<Label htmlFor="max-context-tokens" className="text-left text-sm font-medium">
{localize('com_endpoint_context_tokens')}{' '}
</Label>
<InputNumber
id="max-context-tokens"
stringMode={false}
disabled={readonly}
value={maxContextTokensValue as number}
onChange={setMaxContextTokens as OnInputNumberChange}
placeholder={localize('com_nav_theme_system')}
min={10}
max={2000000}
step={1000}
controls={false}
className={cn(
defaultTextProps,
cn(
optionText,
'reset-rc-number-input reset-rc-number-input-text-right h-auto w-12 border-0 group-hover/temp:border-gray-200',
'w-1/3',
),
)}
/>
</div>
</HoverCardTrigger>
<OptionHoverAlt
description="com_endpoint_context_info"
langCode={true}
side={ESide.Left}
/>
</HoverCard>
<HoverCard openDelay={300}>
<HoverCardTrigger className="grid w-full items-center gap-2">
<div className="flex justify-between">
<Label htmlFor="temp-int" className="text-left text-sm font-medium">
{localize('com_endpoint_temperature')}{' '}
<small className="opacity-40">
({localize('com_endpoint_default_with_num', { 0: '0.8' })})
</small>
</Label>
<InputNumber
id="temp-int"
disabled={readonly}
value={temperatureValue}
onChange={(value) => setTemperature(Number(value))}
max={2}
min={0}
step={0.01}
controls={false}
className={cn(
defaultTextProps,
cn(
optionText,
'reset-rc-number-input reset-rc-number-input-text-right h-auto w-12 border-0 group-hover/temp:border-gray-200',
),
)}
/>
</div>
<Slider
disabled={readonly}
value={[temperatureValue ?? 0.8]}
onValueChange={(value) => setTemperature(value[0])}
onDoubleClick={() => setTemperature(0.8)}
max={2}
min={0}
step={0.01}
className="flex h-4 w-full"
aria-labelledby="temp-int"
/>
</HoverCardTrigger>
<OptionHover endpoint={conversation.endpoint ?? ''} type="temp" side={ESide.Left} />
</HoverCard>
<HoverCard openDelay={300}>
<HoverCardTrigger className="grid w-full items-center gap-2">
<div className="flex justify-between">
<Label htmlFor="top-p-int" className="text-left text-sm font-medium">
{localize('com_endpoint_top_p')}{' '}
<small className="opacity-40">
({localize('com_endpoint_default_with_num', { 0: '1' })})
</small>
</Label>
<InputNumber
id="top-p-int"
disabled={readonly}
value={topPValue}
onChange={(value) => setTopP(Number(value))}
max={1}
min={0}
step={0.01}
controls={false}
className={cn(
defaultTextProps,
cn(
optionText,
'reset-rc-number-input reset-rc-number-input-text-right h-auto w-12 border-0 group-hover/temp:border-gray-200',
),
)}
/>
</div>
<Slider
disabled={readonly}
value={[topPValue ?? 1]}
onValueChange={(value) => setTopP(value[0])}
onDoubleClick={() => setTopP(1)}
max={1}
min={0}
step={0.01}
className="flex h-4 w-full"
aria-labelledby="top-p-int"
/>
</HoverCardTrigger>
<OptionHover endpoint={conversation.endpoint ?? ''} type="topp" side={ESide.Left} />
</HoverCard>
<HoverCard openDelay={300}>
<HoverCardTrigger className="grid w-full items-center gap-2">
<div className="flex justify-between">
<Label htmlFor="freq-penalty-int" className="text-left text-sm font-medium">
{localize('com_endpoint_frequency_penalty')}{' '}
<small className="opacity-40">
({localize('com_endpoint_default_with_num', { 0: '0' })})
</small>
</Label>
<InputNumber
id="freq-penalty-int"
disabled={readonly}
value={freqPValue}
onChange={(value) => setFreqP(Number(value))}
max={2}
min={-2}
step={0.01}
controls={false}
className={cn(
defaultTextProps,
cn(
optionText,
'reset-rc-number-input reset-rc-number-input-text-right h-auto w-12 border-0 group-hover/temp:border-gray-200',
),
)}
/>
</div>
<Slider
disabled={readonly}
value={[freqPValue ?? 0]}
onValueChange={(value) => setFreqP(value[0])}
onDoubleClick={() => setFreqP(0)}
max={2}
min={-2}
step={0.01}
className="flex h-4 w-full"
aria-labelledby="freq-penalty-int"
/>
</HoverCardTrigger>
<OptionHover endpoint={conversation.endpoint ?? ''} type="freq" side={ESide.Left} />
</HoverCard>
<HoverCard openDelay={300}>
<HoverCardTrigger className="grid w-full items-center gap-2">
<div className="flex justify-between">
<Label htmlFor="pres-penalty-int" className="text-left text-sm font-medium">
{localize('com_endpoint_presence_penalty')}{' '}
<small className="opacity-40">
({localize('com_endpoint_default_with_num', { 0: '0' })})
</small>
</Label>
<InputNumber
id="pres-penalty-int"
disabled={readonly}
value={presPValue}
onChange={(value) => setPresP(Number(value))}
max={2}
min={-2}
step={0.01}
controls={false}
className={cn(
defaultTextProps,
cn(
optionText,
'reset-rc-number-input reset-rc-number-input-text-right h-auto w-12 border-0 group-hover/temp:border-gray-200',
),
)}
/>
</div>
<Slider
disabled={readonly}
value={[presPValue ?? 0]}
onValueChange={(value) => setPresP(value[0])}
onDoubleClick={() => setPresP(0)}
max={2}
min={-2}
step={0.01}
className="flex h-4 w-full"
aria-labelledby="pres-penalty-int"
/>
</HoverCardTrigger>
<OptionHover endpoint={conversation.endpoint ?? ''} type="pres" side={ESide.Left} />
</HoverCard>
</div>
</div>
);
}