From 4784fcb23f5a6232aa4d17f6854c192e8a747f92 Mon Sep 17 00:00:00 2001 From: "guangfei.zhao" Date: Tue, 21 Oct 2025 18:21:48 +0800 Subject: [PATCH] feat(settings): refactor LLM model management UI and components --- src/assets/svg/llm/modelscope.svg | 2 +- src/assets/svg/llm/siliconflow.svg | 4 +- src/assets/svg/llm/xinference.svg | 16 +- src/components/AppSvgIcon.tsx | 2 +- .../setting/components/LLMFactoryCard.tsx | 106 ++++- src/pages/setting/models.tsx | 445 +++++------------- vite.config.ts | 10 +- 7 files changed, 225 insertions(+), 360 deletions(-) diff --git a/src/assets/svg/llm/modelscope.svg b/src/assets/svg/llm/modelscope.svg index 8b3778f..cdeb9e5 100644 --- a/src/assets/svg/llm/modelscope.svg +++ b/src/assets/svg/llm/modelscope.svg @@ -1 +1 @@ - + \ No newline at end of file diff --git a/src/assets/svg/llm/siliconflow.svg b/src/assets/svg/llm/siliconflow.svg index c678506..544672f 100644 --- a/src/assets/svg/llm/siliconflow.svg +++ b/src/assets/svg/llm/siliconflow.svg @@ -1,5 +1,5 @@ - + - + \ No newline at end of file diff --git a/src/assets/svg/llm/xinference.svg b/src/assets/svg/llm/xinference.svg index 8d2ab4f..18d2d1d 100644 --- a/src/assets/svg/llm/xinference.svg +++ b/src/assets/svg/llm/xinference.svg @@ -1,28 +1,28 @@ - - - - + diff --git a/src/components/AppSvgIcon.tsx b/src/components/AppSvgIcon.tsx index 7e33302..c64a847 100644 --- a/src/components/AppSvgIcon.tsx +++ b/src/components/AppSvgIcon.tsx @@ -6,7 +6,7 @@ const svgPath = '/src/assets/svg' interface AppSvgIconProps extends SvgIconProps { name: string; - point: 'llm' | 'chunk' | 'file' | 'default'; + point?: 'llm' | 'chunk' | 'file' | 'default'; } const getPointPath = (point: AppSvgIconProps['point']) => { diff --git a/src/pages/setting/components/LLMFactoryCard.tsx b/src/pages/setting/components/LLMFactoryCard.tsx index 4819f66..2ddbc17 100644 --- a/src/pages/setting/components/LLMFactoryCard.tsx +++ b/src/pages/setting/components/LLMFactoryCard.tsx @@ -1,12 +1,100 @@ -import { Box, Typography } from "@mui/material"; +import { + Settings as SettingsIcon, +} from '@mui/icons-material' +import { LlmSvgIcon } from "@/components/AppSvgIcon"; +import { IconMap, type LLMFactory } from "@/constants/llm"; +import type { IFactory } from "@/interfaces/database/llm"; +import { Box, Button, Card, CardContent, Chip, Typography } from "@mui/material"; +import { useState } from "react"; -function LLMFactoryCard() { - return ( - - - - - ) +// 模型类型标签颜色映射 +export const MODEL_TYPE_COLORS: Record = { + 'LLM': '#1976d2', + 'TEXT EMBEDDING': '#388e3c', + 'TEXT RE-RANK': '#f57c00', + 'TTS': '#7b1fa2', + 'SPEECH2TEXT': '#c2185b', + 'IMAGE2TEXT': '#5d4037', + 'MODERATION': '#455a64', +}; + +// 模型工厂卡片组件 +interface ModelFactoryCardProps { + factory: IFactory; + onConfigure: (factory: IFactory) => void; } -export default LLMFactoryCard; +const LLMFactoryCard: React.FC = ({ + factory, + onConfigure, +}) => { + + // 获取工厂图标名称 + const getFactoryIconName = (factoryName: LLMFactory) => { + return IconMap[factoryName] || 'default'; + }; + + return ( + + + {/* 图标 */} + + + {/* 标题 */} + + {factory.name} + + + {/* 标签 */} + + {factory.model_types.map((type) => ( + + ))} + + + {/* 配置按钮 */} + + + + ); +}; + +export default LLMFactoryCard \ No newline at end of file diff --git a/src/pages/setting/models.tsx b/src/pages/setting/models.tsx index 7d29350..5c68daa 100644 --- a/src/pages/setting/models.tsx +++ b/src/pages/setting/models.tsx @@ -9,266 +9,27 @@ import { IconButton, Collapse, Grid, - Divider, - Dialog, - DialogTitle, - DialogContent, - DialogActions, - FormControl, - InputLabel, - Select, - MenuItem, Alert, CircularProgress, Tooltip, + Accordion, + AccordionSummary, + AccordionDetails, + Divider, } from '@mui/material'; import { ExpandMore as ExpandMoreIcon, ExpandLess as ExpandLessIcon, - Settings as SettingsIcon, - Delete as DeleteIcon, Edit as EditIcon, - Add as AddIcon, - Visibility as VisibilityIcon, - VisibilityOff as VisibilityOffIcon, + Delete as DeleteIcon, } from '@mui/icons-material'; import { useLlmModelSetting } from '@/hooks/setting-hooks'; import { useModelDialogs } from './hooks/useModelDialogs'; -import { LlmSvgIcon } from '@/components/AppSvgIcon'; +import AppSvgIcon, { LlmSvgIcon } from '@/components/AppSvgIcon'; import { LLM_FACTORY_LIST, IconMap, type LLMFactory } from '@/constants/llm'; import type { IFactory, IMyLlmModel, ILlmItem } from '@/interfaces/database/llm'; +import LLMFactoryCard, { MODEL_TYPE_COLORS } from './components/LLMFactoryCard'; -// 模型类型标签颜色映射 -const MODEL_TYPE_COLORS: Record = { - 'LLM': '#1976d2', - 'TEXT EMBEDDING': '#388e3c', - 'TEXT RE-RANK': '#f57c00', - 'TTS': '#7b1fa2', - 'SPEECH2TEXT': '#c2185b', - 'IMAGE2TEXT': '#5d4037', - 'MODERATION': '#455a64', -}; - -// 模型工厂卡片组件 -interface ModelFactoryCardProps { - factory: IFactory; - myModels: ILlmItem[]; - onConfigure: (factory: IFactory) => void; - onDeleteFactory: (factoryName: string) => void; - onDeleteModel: (factoryName: string, modelName: string) => void; - onEditModel: (factory: IFactory, model: ILlmItem) => void; -} - -const ModelFactoryCard: React.FC = ({ - factory, - myModels, - onConfigure, - onDeleteFactory, - onDeleteModel, - onEditModel, -}) => { - const [expanded, setExpanded] = useState(false); - const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); - - const handleExpandClick = () => { - setExpanded(!expanded); - }; - - const handleDeleteFactory = () => { - onDeleteFactory(factory.name); - setShowDeleteConfirm(false); - }; - - // 获取工厂图标名称 - const getFactoryIconName = (factoryName: LLMFactory) => { - return IconMap[factoryName] || 'default'; - }; - - return ( - <> - - - - - - - - {factory.name} - - - {factory.model_types.map((type) => ( - - ))} - - - - - } - onClick={() => onConfigure(factory)} - > - 配置 - - {myModels.length > 0 && ( - - {expanded ? : } - - )} - setShowDeleteConfirm(true)} - > - - - - - - - - - 已配置的模型 ({myModels.length}) - - - {myModels.map((model) => ( - - - - - - {model.name} - - - {model.type} - - - Max Tokens: {model.max_tokens} - - - Used: {model.used_token} - - - - onEditModel(factory, model)} - > - - - onDeleteModel(factory.name, model.name)} - > - - - - - - - ))} - - - - - - {/* 删除确认对话框 */} - setShowDeleteConfirm(false)}> - 确认删除 - - - 确定要删除模型工厂 "{factory.name}" 吗?这将删除该工厂下的所有模型配置。 - - - - - - - - - ); -}; - -// 系统默认模型设置组件 -interface SystemModelSettingProps { - myLlm: Record | undefined; -} - -const SystemModelSetting: React.FC = ({ myLlm }) => { - const [defaultModel, setDefaultModel] = useState(''); - const [loading, setLoading] = useState(false); - - // 获取所有可用的聊天模型 - const chatModels = myLlm ? Object.values(myLlm).flatMap(group => - group.llm.filter(model => model.type.toLowerCase().includes('chat') || model.type.toLowerCase().includes('llm')) - ) : []; - - const handleSaveDefaultModel = async () => { - if (!defaultModel) return; - - setLoading(true); - try { - // TODO: 调用设置系统默认模型的 API - console.log('Setting default model:', defaultModel); - // await userService.setSystemDefaultModel({ model: defaultModel }); - } catch (error) { - console.error('设置默认模型失败:', error); - } finally { - setLoading(false); - } - }; - - return ( - - - - 系统默认 LLM 模型 - - - 设置系统默认使用的大语言模型,用于对话和文本生成任务。 - - - - 选择默认模型 - - - : undefined} - > - 保存设置 - - - - - ); -}; // 主页面组件 function ModelsPage() { @@ -336,116 +97,124 @@ function ModelsPage() { 管理您的 LLM 模型工厂和个人模型配置 - {/* 系统默认模型设置 */} - - {/* My LLM 部分 */} - {/* - - 我的 LLM 模型 - + {!myLlm || Object.keys(myLlm).length === 0 ? ( 您还没有配置任何 LLM 模型。请在下方的模型工厂中进行配置。 ) : ( - - {Object.entries(myLlm).map(([factoryName, group]) => ( - - - - - {factoryName} - - - {group.tags.split(',').map((tag) => ( - - ))} - - - {group.llm.map((model) => ( - - - - - {model.name} - - - handleEditModel({ name: factoryName } as IFactory, model)} - > - - - handleDeleteModel(factoryName, model.name)} - > - - - - + + }> + + 我的 LLM 模型 + + + + + {Object.entries(myLlm).map(([factoryName, group]) => ( + + + + + {factoryName} + + + {group.tags.split(',').map((tag) => ( - - Max Tokens: {model.max_tokens} - - - Used: {model.used_token} - - {model.api_base && ( - - Base URL: {model.api_base} - - )} - + ))} + + + {group.llm.map((model) => ( + + + + + {model.name} + + + handleEditModel({ name: factoryName } as IFactory, model)} + > + + + handleDeleteModel(factoryName, model.name)} + > + + + + + + + Max Tokens: {model.max_tokens} + + + Used: {model.used_token} + + {model.api_base && ( + + Base URL: {model.api_base} + + )} + + + ))} - ))} - - - + + + + ))} - ))} - + + )} - */} + {/* LLM Factory 部分 */} - - LLM 模型工厂 - - - 配置各种 AI 服务提供商的模型 - - - {llmFactory.map((factory) => ( - - ))} + + }> + + LLM 模型工厂 + + + + + + { + llmFactory.map((factory) => ( + + + + )) + } + + + {/* 模型配置对话框 */} diff --git a/vite.config.ts b/vite.config.ts index 100a46a..d098f1d 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -5,7 +5,15 @@ import svgr from "vite-plugin-svgr"; // https://vite.dev/config/ export default defineConfig({ - plugins: [react(), svgr()], + plugins: [ + react(), + svgr({ + svgrOptions: { + icon: true, + prettier: true, + } + }) + ], resolve: { alias: { '@': path.resolve(__dirname, './src'),