From 7c0fb078f8fb2f7a5e0e588b0514131d8187b545 Mon Sep 17 00:00:00 2001 From: balibabu Date: Mon, 11 Mar 2024 16:13:34 +0800 Subject: [PATCH] feat: display chunk token number when category of knowledge as general and unavailable llm models appear disabled and if the backend returns 401, it will jump to the login page and fixed the issue where the greeting would disappear when clicking on a new dialog (#117) * feat: Fixed the issue where the greeting would disappear when clicking on a new dialog * feat: replace favicon with logo.svg * feat: if the backend returns 401, it will jump to the login page. * feat: unavailable llm models appear disabled * feat: display chunk token number when category of knowledge as general --- web/.umirc.ts | 1 + web/public/logo.svg | 29 ++++++ web/src/hooks/llmHooks.ts | 1 + .../knowledge-setting/configuration.tsx | 48 +++++++++ .../components/knowledge-setting/index.less | 3 + .../chat/chat-configuration-modal/index.tsx | 50 +++++----- .../model-setting.tsx | 2 +- web/src/pages/chat/hooks.ts | 99 +++++++++++++++---- web/src/pages/chat/index.tsx | 30 ++++-- web/src/pages/chat/model.ts | 11 ++- web/src/utils/history.ts | 3 - web/src/utils/request.ts | 11 +-- 12 files changed, 219 insertions(+), 69 deletions(-) create mode 100644 web/public/logo.svg delete mode 100644 web/src/utils/history.ts diff --git a/web/.umirc.ts b/web/.umirc.ts index 6c72be6c7..7b36b5700 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 000000000..54167d2fb --- /dev/null +++ b/web/public/logo.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/hooks/llmHooks.ts b/web/src/hooks/llmHooks.ts index 4ff363969..7800074db 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 f678c44b6..b06eda3ae 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" > @@ -163,6 +169,48 @@ const Configuration = () => { ))} + + {({ getFieldValue }) => { + const parserId = getFieldValue('parser_id'); + + if (parserId === 'general') { + return ( + + + + + + + + + + + + + ); + } + + return null; + }} +
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 0691fd904..6592e1303 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 9b0257abd..8e0f523b7 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 { variableEnabledFieldMap } from '../constants'; +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 { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks'; -import { variableEnabledFieldMap } from '../constants'; -import { useFetchDialog, useResetCurrentDialog, useSetDialog } from '../hooks'; -import { IPromptConfigParameters } from '../interface'; -import { excludeUnEnabledVariables } from '../utils'; -import { useFetchModelId } from './hooks'; 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.AssistantSetting, ); const promptEngineRef = useRef>([]); - 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 ( { name="llm_id" rules={[{ required: true, message: 'Please select!' }]} > - { 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({ + 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({} 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 680cd7773..b6ee17a8a 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 = () => { = { 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 f529e5d6f..000000000 --- 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 fb164641f..adc77c572 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);