File size: 3,994 Bytes
aa2e6af | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | import { useMemo } from 'react';
import { useForm, useFieldArray, Controller, useWatch } from 'react-hook-form';
import type { TPromptGroup } from 'librechat-data-provider';
import { extractVariableInfo, wrapVariable, replaceSpecialVars } from '~/utils';
import { useAuthContext, useLocalize, useSubmitMessage } from '~/hooks';
import { Input } from '~/components/ui';
type FormValues = {
fields: { variable: string; value: string }[];
};
export default function VariableForm({
group,
onClose,
}: {
group: TPromptGroup;
onClose: () => void;
}) {
const localize = useLocalize();
const { user } = useAuthContext();
const mainText = useMemo(() => {
const initialText = group.productionPrompt?.prompt ?? '';
return replaceSpecialVars({ text: initialText, user });
}, [group.productionPrompt?.prompt, user]);
const { allVariables, uniqueVariables, variableIndexMap } = useMemo(
() => extractVariableInfo(mainText),
[mainText],
);
const { submitPrompt } = useSubmitMessage();
const { control, handleSubmit } = useForm<FormValues>({
defaultValues: {
fields: uniqueVariables.map((variable) => ({ variable: wrapVariable(variable), value: '' })),
},
});
const { fields } = useFieldArray({
control,
name: 'fields',
});
const fieldValues = useWatch({
control,
name: 'fields',
});
if (!uniqueVariables.length) {
return null;
}
const generateHighlightedText = () => {
let tempText = mainText;
const parts: JSX.Element[] = [];
allVariables.forEach((variable, index) => {
const placeholder = `{{${variable}}}`;
const partsBeforePlaceholder = tempText.split(placeholder);
const fieldIndex = variableIndexMap.get(variable) as string | number;
const fieldValue = fieldValues[fieldIndex].value as string;
parts.push(
<span key={`before-${index}`}>{partsBeforePlaceholder[0]}</span>,
<span
key={`highlight-${index}`}
className="rounded bg-yellow-100 p-1 font-medium dark:text-gray-800"
>
{fieldValue !== '' ? fieldValue : placeholder}
</span>,
);
tempText = partsBeforePlaceholder.slice(1).join(placeholder);
});
parts.push(<span key="last-part">{tempText}</span>);
return parts;
};
const onSubmit = (data: FormValues) => {
let text = mainText;
data.fields.forEach(({ variable, value }) => {
if (value) {
const regex = new RegExp(variable, 'g');
text = text.replace(regex, value);
}
});
submitPrompt(text);
onClose();
};
return (
<div className="container mx-auto p-1">
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
<div className="mb-6 max-h-screen overflow-auto rounded-md bg-gray-100 p-4 dark:bg-gray-700/50 dark:text-gray-300 md:max-h-80">
<p className="text-md whitespace-pre-wrap">{generateHighlightedText()}</p>
</div>
<div className="grid grid-cols-2 gap-4 sm:grid-cols-3 md:grid-cols-4">
{fields.map((field, index) => (
<div key={field.id} className="flex flex-col">
<Controller
name={`fields.${index}.value`}
control={control}
render={({ field }) => (
<Input
{...field}
id={`fields.${index}.value`}
className="input text-grey-darker rounded border px-3 py-2 focus:bg-white dark:border-gray-500 dark:focus:bg-gray-700"
placeholder={uniqueVariables[index]}
/>
)}
/>
</div>
))}
</div>
<div className="flex justify-end">
<button
type="submit"
className="btn rounded bg-green-500 font-bold text-white transition-all hover:bg-green-600"
>
{localize('com_ui_submit')}
</button>
</div>
</form>
</div>
);
}
|