From 0e2aff2a48e1a8536d40a0990cfc3a46b6779376 Mon Sep 17 00:00:00 2001 From: balibabu Date: Mon, 18 Mar 2024 16:45:01 +0800 Subject: [PATCH] feat: generate select options for SystemModelSettingModal grouped by type and add llm icon and add upgrade button to UserSettingTeam and replace the icon in the sidebar of the user settings page (#128) * feat: generate select options for SystemModelSettingModal grouped by type * feat: add llm icon * feat: add upgrade button to UserSettingTeam * feat: replace the icon in the sidebar of the user settings page --- web/src/assets/svg/logout.svg | 5 ++ web/src/assets/svg/model-providers.svg | 5 ++ web/src/assets/svg/password.svg | 5 ++ web/src/assets/svg/profile.svg | 5 ++ web/src/assets/svg/team.svg | 5 ++ web/src/hooks/llmHooks.ts | 53 ++++++++++++-- web/src/hooks/userSettingHook.ts | 11 ++- web/src/icons/moonshot.svg | 31 +++++++++ web/src/icons/openai.svg | 6 ++ web/src/icons/tongyi.svg | 7 ++ web/src/icons/wenxin.svg | 11 +++ web/src/icons/zhipu.svg | 12 ++++ web/src/layouts/components/user/index.tsx | 60 ++++------------ web/src/layouts/index.less | 4 ++ web/src/pages/setting/model.ts | 21 +----- web/src/pages/user-setting/constants.tsx | 20 +++--- .../pages/user-setting/setting-model/hooks.ts | 19 +++-- .../user-setting/setting-model/index.tsx | 69 +++++++++++++++---- .../system-model-setting-modal/index.tsx | 18 ++--- .../user-setting/setting-team/index.less | 6 ++ .../pages/user-setting/setting-team/index.tsx | 18 ++++- web/src/pages/user-setting/sidebar/index.tsx | 8 ++- 22 files changed, 287 insertions(+), 112 deletions(-) create mode 100644 web/src/assets/svg/logout.svg create mode 100644 web/src/assets/svg/model-providers.svg create mode 100644 web/src/assets/svg/password.svg create mode 100644 web/src/assets/svg/profile.svg create mode 100644 web/src/assets/svg/team.svg create mode 100644 web/src/icons/moonshot.svg create mode 100644 web/src/icons/openai.svg create mode 100644 web/src/icons/tongyi.svg create mode 100644 web/src/icons/wenxin.svg create mode 100644 web/src/icons/zhipu.svg create mode 100644 web/src/pages/user-setting/setting-team/index.less diff --git a/web/src/assets/svg/logout.svg b/web/src/assets/svg/logout.svg new file mode 100644 index 000000000..21dda4084 --- /dev/null +++ b/web/src/assets/svg/logout.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/web/src/assets/svg/model-providers.svg b/web/src/assets/svg/model-providers.svg new file mode 100644 index 000000000..7a885515b --- /dev/null +++ b/web/src/assets/svg/model-providers.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/web/src/assets/svg/password.svg b/web/src/assets/svg/password.svg new file mode 100644 index 000000000..dacbb242d --- /dev/null +++ b/web/src/assets/svg/password.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/web/src/assets/svg/profile.svg b/web/src/assets/svg/profile.svg new file mode 100644 index 000000000..65069a050 --- /dev/null +++ b/web/src/assets/svg/profile.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/web/src/assets/svg/team.svg b/web/src/assets/svg/team.svg new file mode 100644 index 000000000..36cc1d744 --- /dev/null +++ b/web/src/assets/svg/team.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/web/src/hooks/llmHooks.ts b/web/src/hooks/llmHooks.ts index 74363b21a..c48974c1a 100644 --- a/web/src/hooks/llmHooks.ts +++ b/web/src/hooks/llmHooks.ts @@ -7,7 +7,10 @@ import { import { useCallback, useEffect, useMemo } from 'react'; import { useDispatch, useSelector } from 'umi'; -export const useFetchLlmList = (modelType?: LlmModelType) => { +export const useFetchLlmList = ( + isOnMountFetching: boolean = true, + modelType?: LlmModelType, +) => { const dispatch = useDispatch(); const fetchLlmList = useCallback(() => { @@ -18,15 +21,25 @@ export const useFetchLlmList = (modelType?: LlmModelType) => { }, [dispatch, modelType]); useEffect(() => { - fetchLlmList(); - }, [fetchLlmList]); + if (isOnMountFetching) { + fetchLlmList(); + } + }, [fetchLlmList, isOnMountFetching]); + + return fetchLlmList; }; -export const useSelectLlmOptions = () => { +export const useSelectLlmInfo = () => { const llmInfo: IThirdOAIModelCollection = useSelector( (state: any) => state.settingModel.llmInfo, ); + return llmInfo; +}; + +export const useSelectLlmOptions = () => { + const llmInfo: IThirdOAIModelCollection = useSelectLlmInfo(); + const embeddingModelOptions = useMemo(() => { return Object.entries(llmInfo).map(([key, value]) => { return { @@ -43,6 +56,38 @@ export const useSelectLlmOptions = () => { return embeddingModelOptions; }; +export const useSelectLlmOptionsByModelType = () => { + const llmInfo: IThirdOAIModelCollection = useSelectLlmInfo(); + + const groupOptionsByModelType = (modelType: LlmModelType) => { + return Object.entries(llmInfo) + .filter(([, value]) => + modelType ? value.some((x) => x.model_type === modelType) : true, + ) + .map(([key, value]) => { + return { + label: key, + options: value + .filter((x) => (modelType ? x.model_type === modelType : true)) + .map((x) => ({ + label: x.llm_name, + value: x.llm_name, + disabled: !x.available, + })), + }; + }); + }; + + return { + [LlmModelType.Chat]: groupOptionsByModelType(LlmModelType.Chat), + [LlmModelType.Embedding]: groupOptionsByModelType(LlmModelType.Embedding), + [LlmModelType.Image2text]: groupOptionsByModelType(LlmModelType.Image2text), + [LlmModelType.Speech2text]: groupOptionsByModelType( + LlmModelType.Speech2text, + ), + }; +}; + export const useSelectLlmFactoryList = () => { const factoryList: IFactory[] = useSelector( (state: any) => state.settingModel.factoryList, diff --git a/web/src/hooks/userSettingHook.ts b/web/src/hooks/userSettingHook.ts index 7425dfd8b..c6d5065a7 100644 --- a/web/src/hooks/userSettingHook.ts +++ b/web/src/hooks/userSettingHook.ts @@ -1,7 +1,8 @@ import { ITenantInfo } from '@/interfaces/database/knowledge'; import { IUserInfo } from '@/interfaces/database/userSetting'; +import authorizationUtil from '@/utils/authorizationUtil'; import { useCallback, useEffect, useMemo } from 'react'; -import { useDispatch, useSelector } from 'umi'; +import { history, useDispatch, useSelector } from 'umi'; export const useFetchUserInfo = () => { const dispatch = useDispatch(); @@ -68,8 +69,12 @@ export const useSelectParserList = (): Array<{ export const useLogout = () => { const dispatch = useDispatch(); // TODO: clear redux state - const logout = useCallback((): number => { - return dispatch({ type: 'loginModel/logout' }); + const logout = useCallback(async () => { + const retcode = await dispatch({ type: 'loginModel/logout' }); + if (retcode === 0) { + authorizationUtil.removeAll(); + history.push('/login'); + } }, [dispatch]); return logout; diff --git a/web/src/icons/moonshot.svg b/web/src/icons/moonshot.svg new file mode 100644 index 000000000..f8e458bfb --- /dev/null +++ b/web/src/icons/moonshot.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/icons/openai.svg b/web/src/icons/openai.svg new file mode 100644 index 000000000..6114c7c7e --- /dev/null +++ b/web/src/icons/openai.svg @@ -0,0 +1,6 @@ + + + \ No newline at end of file diff --git a/web/src/icons/tongyi.svg b/web/src/icons/tongyi.svg new file mode 100644 index 000000000..d7104d6d3 --- /dev/null +++ b/web/src/icons/tongyi.svg @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/web/src/icons/wenxin.svg b/web/src/icons/wenxin.svg new file mode 100644 index 000000000..2c673b6a8 --- /dev/null +++ b/web/src/icons/wenxin.svg @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/web/src/icons/zhipu.svg b/web/src/icons/zhipu.svg new file mode 100644 index 000000000..5561830e6 --- /dev/null +++ b/web/src/icons/zhipu.svg @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/web/src/layouts/components/user/index.tsx b/web/src/layouts/components/user/index.tsx index 20ae8b339..e226c0000 100644 --- a/web/src/layouts/components/user/index.tsx +++ b/web/src/layouts/components/user/index.tsx @@ -1,59 +1,29 @@ -import { - useFetchUserInfo, - useLogout, - useSelectUserInfo, -} from '@/hooks/userSettingHook'; -import authorizationUtil from '@/utils/authorizationUtil'; -import type { MenuProps } from 'antd'; -import { Avatar, Button, Dropdown } from 'antd'; -import React, { useCallback, useMemo } from 'react'; -import { useTranslation } from 'react-i18next'; +import { useFetchUserInfo, useSelectUserInfo } from '@/hooks/userSettingHook'; +import { Avatar } from 'antd'; +import React from 'react'; import { history } from 'umi'; -const App: React.FC = () => { - const { t } = useTranslation(); - const userInfo = useSelectUserInfo(); - const logout = useLogout(); +import styles from '../../index.less'; - const handleLogout = useCallback(async () => { - const retcode = await logout(); - if (retcode === 0) { - authorizationUtil.removeAll(); - history.push('/login'); - } - }, [logout]); +const App: React.FC = () => { + const userInfo = useSelectUserInfo(); const toSetting = () => { history.push('/user-setting'); }; - const items: MenuProps['items'] = useMemo(() => { - return [ - { - key: '1', - onClick: handleLogout, - label: , - }, - { - key: '2', - onClick: toSetting, - label: , - }, - ]; - }, [t, handleLogout]); - useFetchUserInfo(); return ( - - - + ); }; diff --git a/web/src/layouts/index.less b/web/src/layouts/index.less index d52ab516a..60d35219b 100644 --- a/web/src/layouts/index.less +++ b/web/src/layouts/index.less @@ -21,3 +21,7 @@ body { .divider { margin: 0; } + +.clickAvailable { + cursor: pointer; +} diff --git a/web/src/pages/setting/model.ts b/web/src/pages/setting/model.ts index 3157f896b..7599f5df3 100644 --- a/web/src/pages/setting/model.ts +++ b/web/src/pages/setting/model.ts @@ -11,9 +11,6 @@ import { Nullable } from 'typings'; import { DvaModel } from 'umi'; export interface SettingModelState { - isShowPSwModal: boolean; - isShowTntModal: boolean; - isShowSSModal: boolean; llm_factory: string; tenantIfo: Nullable; llmInfo: IThirdAiModelCollection; @@ -25,9 +22,6 @@ export interface SettingModelState { const model: DvaModel = { namespace: 'settingModel', state: { - isShowPSwModal: false, - isShowTntModal: false, - isShowSSModal: false, llm_factory: '', tenantIfo: null, llmInfo: {}, @@ -55,12 +49,6 @@ const model: DvaModel = { const { retcode } = data; if (retcode === 0) { message.success('Modified!'); - yield put({ - type: 'updateState', - payload: { - isShowPSwModal: false, - }, - }); yield put({ type: 'getUserInfo', }); @@ -101,15 +89,8 @@ const model: DvaModel = { *set_tenant_info({ payload = {} }, { call, put }) { const { data } = yield call(userService.set_tenant_info, payload); const { retcode } = data; - // llm_id 对应chat_id - // asr_id 对应speech2txt if (retcode === 0) { - yield put({ - type: 'updateState', - payload: { - isShowSSModal: false, - }, - }); + message.success('Modified!'); yield put({ type: 'getTenantInfo', }); diff --git a/web/src/pages/user-setting/constants.tsx b/web/src/pages/user-setting/constants.tsx index 5c9790afa..73df9c7c5 100644 --- a/web/src/pages/user-setting/constants.tsx +++ b/web/src/pages/user-setting/constants.tsx @@ -1,16 +1,16 @@ +import { ReactComponent as LogoutIcon } from '@/assets/svg/logout.svg'; +import { ReactComponent as ModelIcon } from '@/assets/svg/model-providers.svg'; +import { ReactComponent as PasswordIcon } from '@/assets/svg/password.svg'; +import { ReactComponent as ProfileIcon } from '@/assets/svg/profile.svg'; +import { ReactComponent as TeamIcon } from '@/assets/svg/team.svg'; import { UserSettingRouteKey } from '@/constants/setting'; -import { - ContainerOutlined, - DesktopOutlined, - PieChartOutlined, -} from '@ant-design/icons'; export const UserSettingIconMap = { - [UserSettingRouteKey.Profile]: , - [UserSettingRouteKey.Password]: , - [UserSettingRouteKey.Model]: , - [UserSettingRouteKey.Team]: , - [UserSettingRouteKey.Logout]: , + [UserSettingRouteKey.Profile]: , + [UserSettingRouteKey.Password]: , + [UserSettingRouteKey.Model]: , + [UserSettingRouteKey.Team]: , + [UserSettingRouteKey.Logout]: , }; export * from '@/constants/setting'; diff --git a/web/src/pages/user-setting/setting-model/hooks.ts b/web/src/pages/user-setting/setting-model/hooks.ts index b0e70f290..0049cc6ec 100644 --- a/web/src/pages/user-setting/setting-model/hooks.ts +++ b/web/src/pages/user-setting/setting-model/hooks.ts @@ -5,13 +5,14 @@ import { useFetchLlmList, useSaveApiKey, useSaveTenantInfo, + useSelectLlmOptionsByModelType, } from '@/hooks/llmHooks'; import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks'; import { useFetchTenantInfo, useSelectTenantInfo, } from '@/hooks/userSettingHook'; -import { useCallback, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; type SavingParamsState = Omit; @@ -97,10 +98,18 @@ export const useSubmitSystemModelSetting = () => { }; }; -export const useFetchSystemModelSettingOnMount = () => { +export const useFetchSystemModelSettingOnMount = (visible: boolean) => { const systemSetting = useSelectTenantInfo(); - useFetchLlmList(); - useFetchTenantInfo(); + const allOptions = useSelectLlmOptionsByModelType(); + const fetchLlmList = useFetchLlmList(); + const fetchTenantInfo = useFetchTenantInfo(); - return systemSetting; + useEffect(() => { + if (visible) { + fetchLlmList(); + fetchTenantInfo(); + } + }, [fetchLlmList, fetchTenantInfo, visible]); + + return { systemSetting, allOptions }; }; diff --git a/web/src/pages/user-setting/setting-model/index.tsx b/web/src/pages/user-setting/setting-model/index.tsx index 8ce57d9ed..57cf93e81 100644 --- a/web/src/pages/user-setting/setting-model/index.tsx +++ b/web/src/pages/user-setting/setting-model/index.tsx @@ -5,12 +5,19 @@ import { useFetchLlmFactoryListOnMount, useFetchMyLlmListOnMount, } from '@/hooks/llmHooks'; -import { SettingOutlined } from '@ant-design/icons'; +import { ReactComponent as MoonshotIcon } from '@/icons/moonshot.svg'; +import { ReactComponent as OpenAiIcon } from '@/icons/openai.svg'; +import { ReactComponent as TongYiIcon } from '@/icons/tongyi.svg'; +import { ReactComponent as WenXinIcon } from '@/icons/wenxin.svg'; +import { ReactComponent as ZhiPuIcon } from '@/icons/zhipu.svg'; +import { SettingOutlined, UserOutlined } from '@ant-design/icons'; import { Avatar, Button, Card, Col, + Collapse, + CollapseProps, Divider, Flex, List, @@ -26,6 +33,23 @@ import SystemModelSettingModal from './system-model-setting-modal'; import styles from './index.less'; +const IconMap = { + 通义千问: TongYiIcon, + Moonshot: MoonshotIcon, + OpenAI: OpenAiIcon, + 智谱AI: ZhiPuIcon, + 文心一言: WenXinIcon, +}; + +const LlmIcon = ({ name }: { name: string }) => { + const Icon = IconMap[name as keyof typeof IconMap]; + return Icon ? ( + + ) : ( + } /> + ); +}; + const { Text } = Typography; interface IModelCardProps { item: LlmItem; @@ -49,7 +73,7 @@ const ModelCard = ({ item, clickApiKey }: IModelCardProps) => { - + {item.name} {item.tags} @@ -114,16 +138,11 @@ const UserSettingModel = () => { handleApiKeyClick(llmFactory); }; - return ( - <> -
- - + const items: CollapseProps['items'] = [ + { + key: '1', + label: 'Added models', + children: ( { )} /> -

Models to be added

+ ), + }, + { + key: '2', + label: 'Models to be added', + children: ( { - + {item.name} {item.tags} @@ -161,6 +185,21 @@ const UserSettingModel = () => { )} /> + ), + }, + ]; + + return ( + <> +
+ + +
{ const [form] = Form.useForm(); - const initialValues = useFetchSystemModelSettingOnMount(); + const { systemSetting: initialValues, allOptions } = + useFetchSystemModelSettingOnMount(visible); const handleOk = async () => { const values = await form.validateFields(); @@ -33,7 +35,7 @@ const SystemModelSettingModal = ({ return (
- - - - - -
diff --git a/web/src/pages/user-setting/setting-team/index.less b/web/src/pages/user-setting/setting-team/index.less new file mode 100644 index 000000000..bca9dc2e4 --- /dev/null +++ b/web/src/pages/user-setting/setting-team/index.less @@ -0,0 +1,6 @@ +.teamWrapper { + width: 100%; + .teamCard { + // width: 100%; + } +} diff --git a/web/src/pages/user-setting/setting-team/index.tsx b/web/src/pages/user-setting/setting-team/index.tsx index b4f16f9c7..48dab39e9 100644 --- a/web/src/pages/user-setting/setting-team/index.tsx +++ b/web/src/pages/user-setting/setting-team/index.tsx @@ -1,5 +1,21 @@ +import { Button, Card, Flex } from 'antd'; + +import { useSelectUserInfo } from '@/hooks/userSettingHook'; +import styles from './index.less'; + const UserSettingTeam = () => { - return
UserSettingTeam
; + const userInfo = useSelectUserInfo(); + + return ( +
+ + + {userInfo.nickname} Workspace + + + +
+ ); }; export default UserSettingTeam; diff --git a/web/src/pages/user-setting/sidebar/index.tsx b/web/src/pages/user-setting/sidebar/index.tsx index 2abd82a52..097ab5f64 100644 --- a/web/src/pages/user-setting/sidebar/index.tsx +++ b/web/src/pages/user-setting/sidebar/index.tsx @@ -10,6 +10,7 @@ import { UserSettingRouteMap, } from '../constants'; +import { useLogout } from '@/hooks/userSettingHook'; import styles from './index.less'; type MenuItem = Required['items'][number]; @@ -37,9 +38,14 @@ const items: MenuItem[] = Object.values(UserSettingRouteKey).map((value) => const SideBar = () => { const navigate = useNavigate(); const pathName = useSecondPathName(); + const logout = useLogout(); const handleMenuClick: MenuProps['onClick'] = ({ key }) => { - navigate(`/${UserSettingBaseKey}/${key}`); + if (key === UserSettingRouteKey.Logout) { + logout(); + } else { + navigate(`/${UserSettingBaseKey}/${key}`); + } }; const selectedKeys = useMemo(() => {