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
This commit is contained in:
balibabu
2024-03-11 16:13:34 +08:00
committed by GitHub
parent c7c451bb9f
commit 7c0fb078f8
12 changed files with 219 additions and 69 deletions

View File

@ -30,6 +30,7 @@ export const useSelectLlmOptions = () => {
options: value.map((x) => ({
label: x.llm_name,
value: x.llm_name,
disabled: !x.available,
})),
};
});

View File

@ -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>

View File

@ -27,4 +27,7 @@
.buttonWrapper {
text-align: right;
}
.variableSlider {
width: 100%;
}
}

View File

@ -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>(
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

View File

@ -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

View File

@ -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 = () => {

View File

@ -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}

View File

@ -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;
},

View File

@ -1,3 +0,0 @@
import { createBrowserHistory } from 'history';
export const history = createBrowserHistory();

View File

@ -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);