You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. import { ReactComponent as ChatConfigurationAtom } from '@/assets/svg/chat-configuration-atom.svg';
  2. import { IModalManagerChildrenProps } from '@/components/modal-manager';
  3. import {
  4. ModelVariableType,
  5. settledModelVariableMap,
  6. } from '@/constants/knowledge';
  7. import { IDialog } from '@/interfaces/database/chat';
  8. import { Divider, Flex, Form, Modal, Segmented, UploadFile } from 'antd';
  9. import { SegmentedValue } from 'antd/es/segmented';
  10. import omit from 'lodash/omit';
  11. import { useEffect, useRef, useState } from 'react';
  12. import { variableEnabledFieldMap } from '../constants';
  13. import { IPromptConfigParameters } from '../interface';
  14. import { excludeUnEnabledVariables } from '../utils';
  15. import AssistantSetting from './assistant-setting';
  16. import { useFetchModelId } from './hooks';
  17. import ModelSetting from './model-setting';
  18. import PromptEngine from './prompt-engine';
  19. import styles from './index.less';
  20. enum ConfigurationSegmented {
  21. AssistantSetting = 'Assistant Setting',
  22. PromptEngine = 'Prompt Engine',
  23. ModelSetting = 'Model Setting',
  24. }
  25. const segmentedMap = {
  26. [ConfigurationSegmented.AssistantSetting]: AssistantSetting,
  27. [ConfigurationSegmented.ModelSetting]: ModelSetting,
  28. [ConfigurationSegmented.PromptEngine]: PromptEngine,
  29. };
  30. const layout = {
  31. labelCol: { span: 7 },
  32. wrapperCol: { span: 17 },
  33. };
  34. const validateMessages = {
  35. required: '${label} is required!',
  36. types: {
  37. email: '${label} is not a valid email!',
  38. number: '${label} is not a valid number!',
  39. },
  40. number: {
  41. range: '${label} must be between ${min} and ${max}',
  42. },
  43. };
  44. interface IProps extends IModalManagerChildrenProps {
  45. initialDialog: IDialog;
  46. loading: boolean;
  47. onOk: (dialog: IDialog) => void;
  48. clearDialog: () => void;
  49. }
  50. const ChatConfigurationModal = ({
  51. visible,
  52. hideModal,
  53. initialDialog,
  54. loading,
  55. onOk,
  56. clearDialog,
  57. }: IProps) => {
  58. const [form] = Form.useForm();
  59. const [value, setValue] = useState<ConfigurationSegmented>(
  60. ConfigurationSegmented.AssistantSetting,
  61. );
  62. const promptEngineRef = useRef<Array<IPromptConfigParameters>>([]);
  63. const modelId = useFetchModelId(visible);
  64. const handleOk = async () => {
  65. const values = await form.validateFields();
  66. const nextValues: any = omit(values, [
  67. ...Object.keys(variableEnabledFieldMap),
  68. 'parameters',
  69. ...excludeUnEnabledVariables(values),
  70. ]);
  71. const emptyResponse = nextValues.prompt_config?.empty_response ?? '';
  72. const fileList = values.icon;
  73. let icon;
  74. if (Array.isArray(fileList) && fileList.length > 0) {
  75. icon = fileList[0].thumbUrl;
  76. }
  77. const finalValues = {
  78. dialog_id: initialDialog.id,
  79. ...nextValues,
  80. prompt_config: {
  81. ...nextValues.prompt_config,
  82. parameters: promptEngineRef.current,
  83. empty_response: emptyResponse,
  84. },
  85. icon,
  86. };
  87. onOk(finalValues);
  88. };
  89. const handleCancel = () => {
  90. hideModal();
  91. };
  92. const handleSegmentedChange = (val: SegmentedValue) => {
  93. setValue(val as ConfigurationSegmented);
  94. };
  95. const handleModalAfterClose = () => {
  96. clearDialog();
  97. form.resetFields();
  98. };
  99. const title = (
  100. <Flex gap={16}>
  101. <ChatConfigurationAtom></ChatConfigurationAtom>
  102. <div>
  103. <b>Chat Configuration</b>
  104. <div className={styles.chatConfigurationDescription}>
  105. Here, dress up a dedicated assistant for your special knowledge bases!
  106. 💕
  107. </div>
  108. </div>
  109. </Flex>
  110. );
  111. useEffect(() => {
  112. if (visible) {
  113. const icon = initialDialog.icon;
  114. let fileList: UploadFile[] = [];
  115. if (icon) {
  116. fileList = [{ uid: '1', name: 'file', thumbUrl: icon, status: 'done' }];
  117. }
  118. form.setFieldsValue({
  119. ...initialDialog,
  120. llm_setting:
  121. initialDialog.llm_setting ??
  122. settledModelVariableMap[ModelVariableType.Precise],
  123. icon: fileList,
  124. llm_id: initialDialog.llm_id ?? modelId,
  125. });
  126. }
  127. }, [initialDialog, form, visible, modelId]);
  128. return (
  129. <Modal
  130. title={title}
  131. width={688}
  132. open={visible}
  133. onOk={handleOk}
  134. onCancel={handleCancel}
  135. confirmLoading={loading}
  136. destroyOnClose
  137. afterClose={handleModalAfterClose}
  138. >
  139. <Segmented
  140. size={'large'}
  141. value={value}
  142. onChange={handleSegmentedChange}
  143. options={Object.values(ConfigurationSegmented)}
  144. block
  145. />
  146. <Divider></Divider>
  147. <Form
  148. {...layout}
  149. name="nest-messages"
  150. form={form}
  151. style={{ maxWidth: 600 }}
  152. validateMessages={validateMessages}
  153. colon={false}
  154. >
  155. {Object.entries(segmentedMap).map(([key, Element]) => (
  156. <Element
  157. key={key}
  158. show={key === value}
  159. form={form}
  160. {...(key === ConfigurationSegmented.PromptEngine
  161. ? { ref: promptEngineRef }
  162. : {})}
  163. ></Element>
  164. ))}
  165. </Form>
  166. </Modal>
  167. );
  168. };
  169. export default ChatConfigurationModal;