| import { ReactComponent as ChatConfigurationAtom } from '@/assets/svg/chat-configuration-atom.svg'; | |
| import { IModalManagerChildrenProps } from '@/components/modal-manager'; | |
| import { | |
| ModelVariableType, | |
| settledModelVariableMap, | |
| } from '@/constants/knowledge'; | |
| import { useTranslate } from '@/hooks/common-hooks'; | |
| import { useFetchModelId } from '@/hooks/logic-hooks'; | |
| import { IDialog } from '@/interfaces/database/chat'; | |
| import { getBase64FromUploadFileList } from '@/utils/file-util'; | |
| import { removeUselessFieldsFromValues } from '@/utils/form'; | |
| import { Divider, Flex, Form, Modal, Segmented, UploadFile } from 'antd'; | |
| import { SegmentedValue } from 'antd/es/segmented'; | |
| import camelCase from 'lodash/camelCase'; | |
| import { useEffect, useRef, useState } from 'react'; | |
| import { IPromptConfigParameters } from '../interface'; | |
| import AssistantSetting from './assistant-setting'; | |
| import ModelSetting from './model-setting'; | |
| import PromptEngine from './prompt-engine'; | |
| import styles from './index.less'; | |
| const layout = { | |
| labelCol: { span: 9 }, | |
| wrapperCol: { span: 15 }, | |
| }; | |
| const validateMessages = { | |
| required: '${label} is required!', | |
| types: { | |
| email: '${label} is not a valid email!', | |
| number: '${label} is not a valid number!', | |
| }, | |
| number: { | |
| range: '${label} must be between ${min} and ${max}', | |
| }, | |
| }; | |
| enum ConfigurationSegmented { | |
| AssistantSetting = 'Assistant Setting', | |
| PromptEngine = 'Prompt Engine', | |
| ModelSetting = 'Model Setting', | |
| } | |
| const segmentedMap = { | |
| [ConfigurationSegmented.AssistantSetting]: AssistantSetting, | |
| [ConfigurationSegmented.ModelSetting]: ModelSetting, | |
| [ConfigurationSegmented.PromptEngine]: PromptEngine, | |
| }; | |
| interface IProps extends IModalManagerChildrenProps { | |
| initialDialog: IDialog; | |
| loading: boolean; | |
| onOk: (dialog: IDialog) => void; | |
| clearDialog: () => void; | |
| } | |
| const ChatConfigurationModal = ({ | |
| visible, | |
| hideModal, | |
| initialDialog, | |
| loading, | |
| onOk, | |
| clearDialog, | |
| }: IProps) => { | |
| const [form] = Form.useForm(); | |
| const [value, setValue] = useState<ConfigurationSegmented>( | |
| ConfigurationSegmented.AssistantSetting, | |
| ); | |
| const promptEngineRef = useRef<Array<IPromptConfigParameters>>([]); | |
| const modelId = useFetchModelId(); | |
| const { t } = useTranslate('chat'); | |
| const handleOk = async () => { | |
| const values = await form.validateFields(); | |
| const nextValues: any = removeUselessFieldsFromValues( | |
| values, | |
| 'llm_setting.', | |
| ); | |
| const emptyResponse = nextValues.prompt_config?.empty_response ?? ''; | |
| const icon = await getBase64FromUploadFileList(values.icon); | |
| const finalValues = { | |
| dialog_id: initialDialog.id, | |
| ...nextValues, | |
| vector_similarity_weight: 1 - nextValues.vector_similarity_weight, | |
| prompt_config: { | |
| ...nextValues.prompt_config, | |
| parameters: promptEngineRef.current, | |
| empty_response: emptyResponse, | |
| }, | |
| icon, | |
| }; | |
| onOk(finalValues); | |
| }; | |
| const handleSegmentedChange = (val: SegmentedValue) => { | |
| setValue(val as ConfigurationSegmented); | |
| }; | |
| const handleModalAfterClose = () => { | |
| clearDialog(); | |
| form.resetFields(); | |
| }; | |
| const title = ( | |
| <Flex gap={16}> | |
| <ChatConfigurationAtom></ChatConfigurationAtom> | |
| <div> | |
| <b>{t('chatConfiguration')}</b> | |
| <div className={styles.chatConfigurationDescription}> | |
| {t('chatConfigurationDescription')} | |
| </div> | |
| </div> | |
| </Flex> | |
| ); | |
| useEffect(() => { | |
| if (visible) { | |
| const icon = initialDialog.icon; | |
| let fileList: UploadFile[] = []; | |
| if (icon) { | |
| fileList = [{ uid: '1', name: 'file', thumbUrl: icon, status: 'done' }]; | |
| } | |
| form.setFieldsValue({ | |
| ...initialDialog, | |
| llm_setting: | |
| initialDialog.llm_setting ?? | |
| settledModelVariableMap[ModelVariableType.Precise], | |
| icon: fileList, | |
| llm_id: initialDialog.llm_id ?? modelId, | |
| vector_similarity_weight: | |
| 1 - (initialDialog.vector_similarity_weight ?? 0.3), | |
| }); | |
| } | |
| }, [initialDialog, form, visible, modelId]); | |
| return ( | |
| <Modal | |
| title={title} | |
| width={688} | |
| open={visible} | |
| onOk={handleOk} | |
| onCancel={hideModal} | |
| confirmLoading={loading} | |
| destroyOnClose | |
| afterClose={handleModalAfterClose} | |
| > | |
| <Segmented | |
| size={'large'} | |
| value={value} | |
| onChange={handleSegmentedChange} | |
| options={Object.values(ConfigurationSegmented).map((x) => ({ | |
| label: t(camelCase(x)), | |
| value: x, | |
| }))} | |
| block | |
| /> | |
| <Divider></Divider> | |
| <Form | |
| {...layout} | |
| name="nest-messages" | |
| form={form} | |
| style={{ maxWidth: 600 }} | |
| validateMessages={validateMessages} | |
| colon={false} | |
| > | |
| {Object.entries(segmentedMap).map(([key, Element]) => ( | |
| <Element | |
| key={key} | |
| show={key === value} | |
| form={form} | |
| {...(key === ConfigurationSegmented.ModelSetting | |
| ? { initialLlmSetting: initialDialog.llm_setting, visible } | |
| : {})} | |
| {...(key === ConfigurationSegmented.PromptEngine | |
| ? { ref: promptEngineRef } | |
| : {})} | |
| ></Element> | |
| ))} | |
| </Form> | |
| </Modal> | |
| ); | |
| }; | |
| export default ChatConfigurationModal; | |