diff --git a/web/.umirc.ts b/web/.umirc.ts index 6c72be6c7fb0e5714171efdcd10c4871ddf50a63..7b36b570042d77895278c62043d3107693574c6d 100644 --- a/web/.umirc.ts +++ b/web/.umirc.ts @@ -11,6 +11,7 @@ export default defineConfig({ esbuildMinifyIIFE: true, icons: {}, hash: true, + favicons: ['/logo.svg'], history: { type: 'browser', }, diff --git a/web/public/logo.svg b/web/public/logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..54167d2fb3ffc323888d2bf7e46d0b8a6904e354 --- /dev/null +++ b/web/public/logo.svg @@ -0,0 +1,29 @@ +<svg width="32" height="34" viewBox="0 0 32 34" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path fill-rule="evenodd" clip-rule="evenodd" + d="M3.43265 20.7677C4.15835 21.5062 4.15834 22.7035 3.43262 23.4419L3.39546 23.4797C2.66974 24.2182 1.49312 24.2182 0.767417 23.4797C0.0417107 22.7412 0.0417219 21.544 0.767442 20.8055L0.804608 20.7677C1.53033 20.0292 2.70694 20.0293 3.43265 20.7677Z" + fill="#B2DDFF" /> + <path fill-rule="evenodd" clip-rule="evenodd" + d="M12.1689 21.3375C12.8933 22.0773 12.8912 23.2746 12.1641 24.0117L7.01662 29.2307C6.2896 29.9678 5.11299 29.9657 4.38859 29.2259C3.66419 28.4861 3.66632 27.2888 4.39334 26.5517L9.54085 21.3327C10.2679 20.5956 11.4445 20.5977 12.1689 21.3375Z" + fill="#53B1FD" /> + <path fill-rule="evenodd" clip-rule="evenodd" + d="M19.1551 30.3217C19.7244 29.4528 20.8781 29.218 21.7321 29.7973L21.8436 29.8729C22.6975 30.4522 22.9283 31.6262 22.359 32.4952C21.7897 33.3641 20.6359 33.5989 19.782 33.0196L19.6705 32.944C18.8165 32.3647 18.5858 31.1907 19.1551 30.3217Z" + fill="#B2DDFF" /> + <path fill-rule="evenodd" clip-rule="evenodd" + d="M31.4184 20.6544C32.1441 21.3929 32.1441 22.5902 31.4184 23.3286L28.8911 25.9003C28.1654 26.6388 26.9887 26.6388 26.263 25.9003C25.5373 25.1619 25.5373 23.9646 26.263 23.2261L28.7903 20.6544C29.516 19.916 30.6927 19.916 31.4184 20.6544Z" + fill="#53B1FD" /> + <path fill-rule="evenodd" clip-rule="evenodd" + d="M31.4557 11.1427C32.1814 11.8812 32.1814 13.0785 31.4557 13.8169L12.7797 32.8209C12.054 33.5594 10.8774 33.5594 10.1517 32.8209C9.42599 32.0825 9.42599 30.8852 10.1517 30.1467L28.8277 11.1427C29.5534 10.4043 30.73 10.4043 31.4557 11.1427Z" + fill="#1570EF" /> + <path fill-rule="evenodd" clip-rule="evenodd" + d="M27.925 5.29994C28.6508 6.0384 28.6508 7.23568 27.925 7.97414L17.184 18.9038C16.4583 19.6423 15.2817 19.6423 14.556 18.9038C13.8303 18.1653 13.8303 16.9681 14.556 16.2296L25.297 5.29994C26.0227 4.56148 27.1993 4.56148 27.925 5.29994Z" + fill="#1570EF" /> + <path fill-rule="evenodd" clip-rule="evenodd" + d="M22.256 1.59299C22.9822 2.33095 22.983 3.52823 22.2578 4.26718L8.45055 18.3358C7.72533 19.0748 6.54871 19.0756 5.82251 18.3376C5.09631 17.5996 5.09552 16.4024 5.82075 15.6634L19.6279 1.59478C20.3532 0.855827 21.5298 0.855022 22.256 1.59299Z" + fill="#1570EF" /> + <path fill-rule="evenodd" clip-rule="evenodd" + d="M8.58225 6.09619C9.30671 6.83592 9.30469 8.0332 8.57772 8.77038L3.17006 14.2541C2.4431 14.9913 1.26649 14.9893 0.542025 14.2495C-0.182438 13.5098 -0.180413 12.3125 0.546548 11.5753L5.95421 6.09159C6.68117 5.3544 7.85778 5.35646 8.58225 6.09619Z" + fill="#53B1FD" /> + <path fill-rule="evenodd" clip-rule="evenodd" + d="M11.893 0.624023C12.9193 0.624023 13.7513 1.47063 13.7513 2.51497V2.70406C13.7513 3.7484 12.9193 4.59501 11.893 4.59501C10.8667 4.59501 10.0347 3.7484 10.0347 2.70406V2.51497C10.0347 1.47063 10.8667 0.624023 11.893 0.624023Z" + fill="#B2DDFF" /> +</svg> \ No newline at end of file diff --git a/web/src/hooks/llmHooks.ts b/web/src/hooks/llmHooks.ts index 4ff3639696d8c5fb7dabe016def64470face8bb3..7800074db2736d160a35c036d54906bf1adc03d3 100644 --- a/web/src/hooks/llmHooks.ts +++ b/web/src/hooks/llmHooks.ts @@ -30,6 +30,7 @@ export const useSelectLlmOptions = () => { options: value.map((x) => ({ label: x.llm_name, value: x.llm_name, + disabled: !x.available, })), }; }); diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/configuration.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/configuration.tsx index f678c44b6b77cecd237de233f2babc1d174f06cd..b06eda3ae66666eaed24d3e16e6c879f2ea8fa22 100644 --- a/web/src/pages/add-knowledge/components/knowledge-setting/configuration.tsx +++ b/web/src/pages/add-knowledge/components/knowledge-setting/configuration.tsx @@ -10,10 +10,13 @@ import { import { Button, Divider, + Flex, Form, Input, + InputNumber, Radio, Select, + Slider, Space, Typography, Upload, @@ -80,6 +83,7 @@ const Configuration = () => { 'permission', 'embd_id', 'parser_id', + 'parser_config.chunk_token_num', ]), avatar: fileList, }); @@ -144,6 +148,7 @@ const Configuration = () => { name="embd_id" label="Embedding Model" rules={[{ required: true }]} + tooltip="xx" > <Select placeholder="Please select a country" @@ -153,6 +158,7 @@ const Configuration = () => { <Form.Item name="parser_id" label="Knowledge base category" + tooltip="xx" rules={[{ required: true }]} > <Select placeholder="Please select a country"> @@ -163,6 +169,48 @@ const Configuration = () => { ))} </Select> </Form.Item> + <Form.Item noStyle dependencies={['parser_id']}> + {({ getFieldValue }) => { + const parserId = getFieldValue('parser_id'); + + if (parserId === 'general') { + return ( + <Form.Item label="Chunk token number" tooltip="xxx"> + <Flex gap={20} align="center"> + <Flex flex={1}> + <Form.Item + name={['parser_config', 'chunk_token_num']} + noStyle + initialValue={128} + rules={[ + { required: true, message: 'Province is required' }, + ]} + > + <Slider className={styles.variableSlider} max={2048} /> + </Form.Item> + </Flex> + <Form.Item + name={['parser_config', 'chunk_token_num']} + noStyle + initialValue={128} + rules={[ + { required: true, message: 'Street is required' }, + ]} + > + <InputNumber + className={styles.sliderInputNumber} + max={2048} + min={0} + /> + </Form.Item> + </Flex> + </Form.Item> + ); + } + + return null; + }} + </Form.Item> <Form.Item> <div className={styles.buttonWrapper}> <Space> diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/index.less b/web/src/pages/add-knowledge/components/knowledge-setting/index.less index 0691fd904031769b6e4d1d919fcb137d5ad7853e..6592e1303d3ba4e8bb64bd42fca1c7f928f5ae25 100644 --- a/web/src/pages/add-knowledge/components/knowledge-setting/index.less +++ b/web/src/pages/add-knowledge/components/knowledge-setting/index.less @@ -27,4 +27,7 @@ .buttonWrapper { text-align: right; } + .variableSlider { + width: 100%; + } } diff --git a/web/src/pages/chat/chat-configuration-modal/index.tsx b/web/src/pages/chat/chat-configuration-modal/index.tsx index 9b0257abd5f919f3c9ce4979b3bf02f947a26a76..8e0f523b730c9bc56fec9113f702c0bd0b2d5d6a 100644 --- a/web/src/pages/chat/chat-configuration-modal/index.tsx +++ b/web/src/pages/chat/chat-configuration-modal/index.tsx @@ -1,19 +1,18 @@ import { ReactComponent as ChatConfigurationAtom } from '@/assets/svg/chat-configuration-atom.svg'; import { IModalManagerChildrenProps } from '@/components/modal-manager'; +import { IDialog } from '@/interfaces/database/chat'; import { Divider, Flex, Form, Modal, Segmented, UploadFile } from 'antd'; import { SegmentedValue } from 'antd/es/segmented'; import omit from 'lodash/omit'; import { useEffect, useRef, useState } from 'react'; -import AssistantSetting from './assistant-setting'; -import ModelSetting from './model-setting'; -import PromptEngine from './prompt-engine'; - -import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks'; import { variableEnabledFieldMap } from '../constants'; -import { useFetchDialog, useResetCurrentDialog, useSetDialog } from '../hooks'; import { IPromptConfigParameters } from '../interface'; import { excludeUnEnabledVariables } from '../utils'; +import AssistantSetting from './assistant-setting'; import { useFetchModelId } from './hooks'; +import ModelSetting from './model-setting'; +import PromptEngine from './prompt-engine'; + import styles from './index.less'; enum ConfigurationSegmented { @@ -45,22 +44,27 @@ const validateMessages = { }; interface IProps extends IModalManagerChildrenProps { - id: string; + initialDialog: IDialog; + loading: boolean; + onOk: (dialog: IDialog) => void; + clearDialog: () => void; } -const ChatConfigurationModal = ({ visible, hideModal, id }: IProps) => { +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 loading = useOneNamespaceEffectsLoading('chatModel', ['setDialog']); const modelId = useFetchModelId(visible); - const setDialog = useSetDialog(); - const currentDialog = useFetchDialog(id, visible); - const { resetCurrentDialog } = useResetCurrentDialog(); - const handleOk = async () => { const values = await form.validateFields(); const nextValues: any = omit(values, [ @@ -78,7 +82,7 @@ const ChatConfigurationModal = ({ visible, hideModal, id }: IProps) => { } const finalValues = { - dialog_id: id, + dialog_id: initialDialog.id, ...nextValues, prompt_config: { ...nextValues.prompt_config, @@ -87,13 +91,7 @@ const ChatConfigurationModal = ({ visible, hideModal, id }: IProps) => { }, icon, }; - console.info(promptEngineRef.current); - console.info(nextValues); - console.info(finalValues); - const retcode: number = await setDialog(finalValues); - if (retcode === 0) { - hideModal(); - } + onOk(finalValues); }; const handleCancel = () => { @@ -105,7 +103,7 @@ const ChatConfigurationModal = ({ visible, hideModal, id }: IProps) => { }; const handleModalAfterClose = () => { - resetCurrentDialog(); + clearDialog(); form.resetFields(); }; @@ -124,19 +122,19 @@ const ChatConfigurationModal = ({ visible, hideModal, id }: IProps) => { useEffect(() => { if (visible) { - const icon = currentDialog.icon; + const icon = initialDialog.icon; let fileList: UploadFile[] = []; if (icon) { fileList = [{ uid: '1', name: 'file', thumbUrl: icon, status: 'done' }]; } form.setFieldsValue({ - ...currentDialog, + ...initialDialog, icon: fileList, - llm_id: currentDialog.llm_id ?? modelId, + llm_id: initialDialog.llm_id ?? modelId, }); } - }, [currentDialog, form, visible, modelId]); + }, [initialDialog, form, visible, modelId]); return ( <Modal diff --git a/web/src/pages/chat/chat-configuration-modal/model-setting.tsx b/web/src/pages/chat/chat-configuration-modal/model-setting.tsx index 5f68a6dee4cb8edba6481842ac5f9ab1bd881c18..2f4c6668d20d3f1b415c682326f9aef721a951f9 100644 --- a/web/src/pages/chat/chat-configuration-modal/model-setting.tsx +++ b/web/src/pages/chat/chat-configuration-modal/model-setting.tsx @@ -54,7 +54,7 @@ const ModelSetting = ({ show, form }: ISegmentedContentProps) => { name="llm_id" rules={[{ required: true, message: 'Please select!' }]} > - <Select options={modelOptions} /> + <Select options={modelOptions} showSearch /> </Form.Item> <Divider></Divider> <Form.Item diff --git a/web/src/pages/chat/hooks.ts b/web/src/pages/chat/hooks.ts index 47a3721f808da922084f34e14a6dc3802cfe6094..b3e83bcd277639df2ae0b93a23aff32190092751 100644 --- a/web/src/pages/chat/hooks.ts +++ b/web/src/pages/chat/hooks.ts @@ -45,24 +45,42 @@ export const useSetDialog = () => { return setDialog; }; -export const useFetchDialog = (dialogId: string, visible: boolean): IDialog => { - const dispatch = useDispatch(); +export const useSelectCurrentDialog = () => { const currentDialog: IDialog = useSelector( (state: any) => state.chatModel.currentDialog, ); - const fetchDialog = useCallback(() => { - if (dialogId) { - dispatch({ - type: 'chatModel/getDialog', - payload: { dialog_id: dialogId }, - }); - } - }, [dispatch, dialogId]); + return currentDialog; +}; + +export const useFetchDialog = () => { + const dispatch = useDispatch(); + + const fetchDialog = useCallback( + (dialogId: string, needToBeSaved = true) => { + if (dialogId) { + return dispatch<any>({ + type: 'chatModel/getDialog', + payload: { dialog_id: dialogId, needToBeSaved }, + }); + } + }, + [dispatch], + ); + + return fetchDialog; +}; + +export const useFetchDialogOnMount = ( + dialogId: string, + visible: boolean, +): IDialog => { + const currentDialog: IDialog = useSelectCurrentDialog(); + const fetchDialog = useFetchDialog(); useEffect(() => { if (dialogId && visible) { - fetchDialog(); + fetchDialog(dialogId); } }, [dialogId, fetchDialog, visible]); @@ -123,14 +141,6 @@ export const useSelectPromptConfigParameters = (): VariableTableDataType[] => { return finalParameters; }; -export const useSelectCurrentDialog = () => { - const currentDialog: IDialog = useSelector( - (state: any) => state.chatModel.currentDialog, - ); - - return currentDialog; -}; - export const useRemoveDialog = () => { const dispatch = useDispatch(); @@ -231,6 +241,57 @@ export const useHandleItemHover = () => { }; }; +export const useEditDialog = () => { + const [dialog, setDialog] = useState<IDialog>({} as IDialog); + const fetchDialog = useFetchDialog(); + const submitDialog = useSetDialog(); + const loading = useOneNamespaceEffectsLoading('chatModel', ['setDialog']); + + const { + visible: dialogEditVisible, + hideModal: hideDialogEditModal, + showModal: showDialogEditModal, + } = useSetModalState(); + + const onDialogEditOk = useCallback( + async (dialog: IDialog) => { + const ret = await submitDialog(dialog); + + if (ret === 0) { + hideDialogEditModal(); + } + }, + [submitDialog, hideDialogEditModal], + ); + + const handleShowDialogEditModal = useCallback( + async (dialogId?: string) => { + if (dialogId) { + const ret = await fetchDialog(dialogId, false); + if (ret.retcode === 0) { + setDialog(ret.data); + } + } + showDialogEditModal(); + }, + [showDialogEditModal, fetchDialog], + ); + + const clearDialog = useCallback(() => { + setDialog({} as IDialog); + }, []); + + return { + dialogSettingLoading: loading, + initialDialog: dialog, + onDialogEditOk, + dialogEditVisible, + hideDialogEditModal, + showDialogEditModal: handleShowDialogEditModal, + clearDialog, + }; +}; + //#region conversation export const useFetchConversationList = () => { diff --git a/web/src/pages/chat/index.tsx b/web/src/pages/chat/index.tsx index 680cd7773231a440e460892e8464b5a83e5aeace..b6ee17a8ac8b48f764f4c672d7a68e752d3fb677 100644 --- a/web/src/pages/chat/index.tsx +++ b/web/src/pages/chat/index.tsx @@ -20,8 +20,9 @@ import ChatContainer from './chat-container'; import { useClickConversationCard, useClickDialogCard, + useEditDialog, useFetchConversationList, - useFetchDialog, + useFetchDialogOnMount, useGetChatSearchParams, useHandleItemHover, useRemoveConversation, @@ -60,8 +61,17 @@ const Chat = () => { hideConversationRenameModal, showConversationRenameModal, } = useRenameConversation(); + const { + dialogSettingLoading, + initialDialog, + onDialogEditOk, + dialogEditVisible, + clearDialog, + hideDialogEditModal, + showDialogEditModal, + } = useEditDialog(); - useFetchDialog(dialogId, true); + useFetchDialogOnMount(dialogId, true); const handleAppCardEnter = (id: string) => () => { handleItemEnter(id); @@ -76,10 +86,7 @@ const Chat = () => { (info: any) => { info?.domEvent?.preventDefault(); info?.domEvent?.stopPropagation(); - // if (dialogId) { - setCurrentDialog(dialogId ?? ''); - // } - showModal(); + showDialogEditModal(dialogId); }; const handleRemoveDialog = @@ -276,10 +283,13 @@ const Chat = () => { <Divider type={'vertical'} className={styles.divider}></Divider> <ChatContainer></ChatContainer> <ChatConfigurationModal - visible={visible} - showModal={showModal} - hideModal={hideModal} - id={currentDialog.id} + visible={dialogEditVisible} + initialDialog={initialDialog} + showModal={showDialogEditModal} + hideModal={hideDialogEditModal} + loading={dialogSettingLoading} + onOk={onDialogEditOk} + clearDialog={clearDialog} ></ChatConfigurationModal> <RenameModal visible={conversationRenameVisible} diff --git a/web/src/pages/chat/model.ts b/web/src/pages/chat/model.ts index f8950b34d1463b65087777260fd64c6c9429e333..22bf7b48e8c874b86c4fd27b558699db7001f130 100644 --- a/web/src/pages/chat/model.ts +++ b/web/src/pages/chat/model.ts @@ -63,16 +63,21 @@ const model: DvaModel<ChatModelState> = { effects: { *getDialog({ payload }, { call, put }) { - const { data } = yield call(chatService.getDialog, payload); - if (data.retcode === 0) { + const needToBeSaved = + payload.needToBeSaved === undefined ? true : payload.needToBeSaved; + const { data } = yield call(chatService.getDialog, { + dialog_id: payload.dialog_id, + }); + if (data.retcode === 0 && needToBeSaved) { yield put({ type: 'setCurrentDialog', payload: data.data }); } + return data; }, *setDialog({ payload }, { call, put }) { const { data } = yield call(chatService.setDialog, payload); if (data.retcode === 0) { yield put({ type: 'listDialog' }); - message.success('Created successfully !'); + message.success(payload.dialog_id ? 'Modified!' : 'Created!'); } return data.retcode; }, diff --git a/web/src/utils/history.ts b/web/src/utils/history.ts deleted file mode 100644 index f529e5d6f0f716098a8ed408bbb2df20fa4992de..0000000000000000000000000000000000000000 --- a/web/src/utils/history.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { createBrowserHistory } from 'history'; - -export const history = createBrowserHistory(); diff --git a/web/src/utils/request.ts b/web/src/utils/request.ts index fb164641fd99991279d30f1c450583de6d929c06..adc77c572c35b19d661b42bfc3f84cbe3edd2525 100644 --- a/web/src/utils/request.ts +++ b/web/src/utils/request.ts @@ -1,11 +1,8 @@ -import { message, notification } from 'antd'; -import { RequestMethod, extend } from 'umi-request'; - import { Authorization } from '@/constants/authorization'; -import api from '@/utils/api'; import authorizationUtil from '@/utils/authorizationUtil'; - -const { login } = api; +import { message, notification } from 'antd'; +import { history } from 'umi'; +import { RequestMethod, extend } from 'umi-request'; const ABORT_REQUEST_ERR_MESSAGE = 'The user aborted a request.'; // 手动ä¸ć–请求。errorHandler 抛出的error message @@ -120,7 +117,7 @@ request.interceptors.response.use(async (response: any, options) => { duration: 3, }); authorizationUtil.removeAll(); - // history.push('/login'); // Will not jump to the login page + history.push('/login'); // Will not jump to the login page } else if (data.retcode !== 0) { if (data.retcode === 100) { message.error(data.retmsg);