chat / client /src /components /SidePanel /Parameters /DynamicSlider.tsx
Zhitomir's picture
chat init
aa2e6af
Raw
History Blame Contribute Delete
5.71 kB
import { useMemo, useCallback } from 'react';
import { OptionTypes } from 'librechat-data-provider';
import type { DynamicSettingProps } from 'librechat-data-provider';
import { Label, Slider, HoverCard, Input, InputNumber, HoverCardTrigger } from '~/components/ui';
import { useLocalize, useDebouncedInput, useParameterEffects } from '~/hooks';
import { cn, defaultTextProps, optionText } from '~/utils';
import { ESide, defaultDebouncedDelay } from '~/common';
import { useChatContext } from '~/Providers';
import OptionHover from './OptionHover';
function DynamicSlider({
label,
settingKey,
defaultValue,
range,
description,
columnSpan,
setOption,
optionType,
options,
readonly = false,
showDefault = true,
includeInput = true,
labelCode,
descriptionCode,
conversation,
}: DynamicSettingProps) {
const localize = useLocalize();
const { preset } = useChatContext();
const isEnum = useMemo(() => !range && options && options.length > 0, [options, range]);
const [setInputValue, inputValue] = useDebouncedInput<string | number>({
optionKey: optionType !== OptionTypes.Custom ? settingKey : undefined,
initialValue: optionType !== OptionTypes.Custom ? conversation?.[settingKey] : defaultValue,
setter: () => ({}),
setOption,
delay: isEnum ? 0 : defaultDebouncedDelay,
});
useParameterEffects({
preset,
settingKey,
defaultValue,
conversation,
inputValue,
setInputValue,
preventDelayedUpdate: isEnum,
});
const selectedValue = useMemo(() => {
if (isEnum) {
return conversation?.[settingKey] ?? defaultValue;
}
// TODO: custom logic, add to payload but not to conversation
return inputValue;
}, [conversation, defaultValue, settingKey, inputValue, isEnum]);
const enumToNumeric = useMemo(() => {
if (isEnum && options) {
return options.reduce((acc, mapping, index) => {
acc[mapping] = index;
return acc;
}, {} as Record<string, number>);
}
return {};
}, [isEnum, options]);
const valueToEnumOption = useMemo(() => {
if (isEnum && options) {
return options.reduce((acc, option, index) => {
acc[index] = option;
return acc;
}, {} as Record<number, string>);
}
return {};
}, [isEnum, options]);
const handleValueChange = useCallback(
(value: number) => {
if (isEnum) {
setInputValue(valueToEnumOption[value]);
} else {
setInputValue(value);
}
},
[isEnum, setInputValue, valueToEnumOption],
);
if (!range && !isEnum) {
return null;
}
return (
<div
className={cn(
'flex flex-col items-center justify-start gap-6',
columnSpan ? `col-span-${columnSpan}` : 'col-span-full',
)}
>
<HoverCard openDelay={300}>
<HoverCardTrigger className="grid w-full items-center gap-2">
<div className="flex justify-between">
<Label
htmlFor={`${settingKey}-dynamic-setting`}
className="text-left text-sm font-medium"
>
{labelCode ? localize(label ?? '') || label : label ?? settingKey}{' '}
{showDefault && (
<small className="opacity-40">
({localize('com_endpoint_default')}: {defaultValue})
</small>
)}
</Label>
{includeInput && !isEnum ? (
<InputNumber
id={`${settingKey}-dynamic-setting-input-number`}
disabled={readonly}
value={inputValue ?? defaultValue}
onChange={(value) => setInputValue(Number(value))}
max={range ? range.max : (options?.length ?? 0) - 1}
min={range ? range.min : 0}
step={range ? range.step ?? 1 : 1}
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',
),
)}
/>
) : (
<Input
id={`${settingKey}-dynamic-setting-input`}
disabled={readonly}
value={selectedValue ?? defaultValue}
onChange={() => ({})}
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
id={`${settingKey}-dynamic-setting-slider`}
disabled={readonly}
value={[
isEnum
? enumToNumeric[(selectedValue as number) ?? '']
: (inputValue as number) ?? (defaultValue as number),
]}
onValueChange={(value) => handleValueChange(value[0])}
doubleClickHandler={() => setInputValue(defaultValue as string | number)}
max={isEnum && options ? options.length - 1 : range ? range.max : 0}
min={range ? range.min : 0}
step={range ? range.step ?? 1 : 1}
className="flex h-4 w-full"
/>
</HoverCardTrigger>
{description && (
<OptionHover
description={descriptionCode ? localize(description) || description : description}
side={ESide.Left}
/>
)}
</HoverCard>
</div>
);
}
export default DynamicSlider;