feat(settings): refactor LLM model management UI and components
This commit is contained in:
@@ -1 +1 @@
|
||||
<svg id="_层_2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 274.37 172.76"><defs><style>.cls-2{fill:#36cfd1}.cls-3{fill:#624aff}</style></defs><g id="_层_1-2"><path class="cls-3" d="M24.78 73.55h25.65V99.2H24.78zm99.14 25.66h25.65v25.65h-25.65zm76.95 25.65h-25.65v22.19h47.84V99.21h-22.19v25.65z"/><path class="cls-2" d="M149.57 73.55h25.65V99.2h-25.65zM24.78 47.9h25.65v25.65H24.78z"/><path class="cls-3" d="M223.06 73.55h25.65V99.2h-25.65z"/><path class="cls-2" d="M223.06 47.9h25.65v25.65h-25.65z"/><path class="cls-3" d="M175.22 25.71V47.9h25.65v25.65h22.19V25.71h-47.84z"/><path class="cls-2" d="M98.27 73.55h25.65V99.2H98.27z"/><path class="cls-3" d="M72.62 47.9h25.65V25.71H50.43v47.84h22.19V47.9zm0 51.31H50.43v47.84h47.84v-22.19H72.62V99.21z"/><path style="fill:none" d="M0 0h274.37v172.76H0z"/></g></svg>
|
||||
<svg id="layer_2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 274.37 172.76"><defs><style>.cls-2{fill:#36cfd1}.cls-3{fill:#624aff}</style></defs><g id="layer_1-2"><path class="cls-3" d="M24.78 73.55h25.65V99.2H24.78zm99.14 25.66h25.65v25.65h-25.65zm76.95 25.65h-25.65v22.19h47.84V99.21h-22.19v25.65z"/><path class="cls-2" d="M149.57 73.55h25.65V99.2h-25.65zM24.78 47.9h25.65v25.65H24.78z"/><path class="cls-3" d="M223.06 73.55h25.65V99.2h-25.65z"/><path class="cls-2" d="M223.06 47.9h25.65v25.65h-25.65z"/><path class="cls-3" d="M175.22 25.71V47.9h25.65v25.65h22.19V25.71h-47.84z"/><path class="cls-2" d="M98.27 73.55h25.65V99.2H98.27z"/><path class="cls-3" d="M72.62 47.9h25.65V25.71H50.43v47.84h22.19V47.9zm0 51.31H50.43v47.84h47.84v-22.19H72.62V99.21z"/><path style="fill:none" d="M0 0h274.37v172.76H0z"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 821 B After Width: | Height: | Size: 822 B |
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="_图层_2" data-name="图层 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 111.08 53.12">
|
||||
<svg id="layer_2" data-name="layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 111.08 53.12">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
@@ -7,7 +7,7 @@
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<g id="_图层_1-2" data-name="图层 1">
|
||||
<g id="layer_1-2" data-name="layer 1">
|
||||
<path class="cls-1" d="M106.25,0h-48.3c-2.67,0-4.83,2.16-4.83,4.83v14.49c0,2.67-2.16,4.83-4.83,4.83H4.83c-2.67,0-4.83,2.16-4.83,4.83v19.32c0,2.67,2.16,4.83,4.83,4.83h48.3c2.67,0,4.83-2.16,4.83-4.83v-14.49c0-2.67,2.16-4.83,4.83-4.83h43.47c2.67,0,4.83-2.16,4.83-4.83V4.83c0-2.67-2.16-4.83-4.83-4.83Z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 595 B After Width: | Height: | Size: 589 B |
@@ -1,28 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
<svg id="layer_1" data-name="layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 283.46 283.46">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: url(#_未命名的渐变_5-2);
|
||||
fill: url(#gradient_5-2);
|
||||
}
|
||||
|
||||
.cls-2 {
|
||||
fill: url(#_未命名的渐变_9);
|
||||
fill: url(#gradient_9);
|
||||
}
|
||||
|
||||
.cls-3 {
|
||||
fill: url(#_未命名的渐变_5);
|
||||
fill: url(#gradient_5);
|
||||
}
|
||||
</style>
|
||||
<linearGradient id="_未命名的渐变_5" data-name="未命名的渐变 5" x1="27.03" y1="287.05" x2="253.15" y2="1.14"
|
||||
<linearGradient id="gradient_5" data-name="gradient 5" x1="27.03" y1="287.05" x2="253.15" y2="1.14"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#e9a85e" />
|
||||
<stop offset="1" stop-color="#f52b76" />
|
||||
</linearGradient>
|
||||
<linearGradient id="_未命名的渐变_5-2" data-name="未命名的渐变 5" x1="25.96" y1="286.21" x2="252.09" y2=".3"
|
||||
xlink:href="#_未命名的渐变_5" />
|
||||
<linearGradient id="_未命名的渐变_9" data-name="未命名的渐变 9" x1="-474.33" y1="476.58" x2="-160.37" y2="476.58"
|
||||
<linearGradient id="gradient_5-2" data-name="gradient 5" x1="25.96" y1="286.21" x2="252.09" y2=".3"
|
||||
xlink:href="#gradient_5" />
|
||||
<linearGradient id="gradient_9" data-name="gradient 9" x1="-474.33" y1="476.58" x2="-160.37" y2="476.58"
|
||||
gradientTransform="translate(669.07 -75.9) rotate(33.75)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a0cf5" />
|
||||
<stop offset="1" stop-color="#ab66f3" />
|
||||
|
||||
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.9 KiB |
@@ -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']) => {
|
||||
|
||||
@@ -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 (
|
||||
<Box>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
</Typography>
|
||||
</Box>
|
||||
)
|
||||
// 模型类型标签颜色映射
|
||||
export const MODEL_TYPE_COLORS: Record<string, string> = {
|
||||
'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<ModelFactoryCardProps> = ({
|
||||
factory,
|
||||
onConfigure,
|
||||
}) => {
|
||||
|
||||
// 获取工厂图标名称
|
||||
const getFactoryIconName = (factoryName: LLMFactory) => {
|
||||
return IconMap[factoryName] || 'default';
|
||||
};
|
||||
|
||||
return (
|
||||
<Card sx={{
|
||||
mb: 2,
|
||||
border: '1px solid #e0e0e0',
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column'
|
||||
}}>
|
||||
<CardContent sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start',
|
||||
textAlign: 'left',
|
||||
gap: 2,
|
||||
flex: 1,
|
||||
}}>
|
||||
{/* 图标 */}
|
||||
<LlmSvgIcon
|
||||
name={getFactoryIconName(factory.name as LLMFactory)}
|
||||
sx={{ width: 48, height: 48, color: 'primary.main' }}
|
||||
/>
|
||||
|
||||
{/* 标题 */}
|
||||
<Typography variant="h6" component="div" sx={{ fontWeight: 'bold' }}>
|
||||
{factory.name}
|
||||
</Typography>
|
||||
|
||||
{/* 标签 */}
|
||||
<Box display="flex" flexWrap="wrap" gap={0.5} justifyContent="left">
|
||||
{factory.model_types.map((type) => (
|
||||
<Chip
|
||||
key={type}
|
||||
label={type.toUpperCase()}
|
||||
size="small"
|
||||
sx={{
|
||||
backgroundColor: MODEL_TYPE_COLORS[type.toUpperCase()] || '#757575',
|
||||
color: 'white',
|
||||
fontSize: '0.65rem',
|
||||
height: '20px',
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
|
||||
{/* 配置按钮 */}
|
||||
<Button
|
||||
variant="text"
|
||||
size="small"
|
||||
onClick={() => onConfigure(factory)}
|
||||
sx={{
|
||||
mt: 'auto',
|
||||
color: 'primary.main',
|
||||
alignSelf: 'center',
|
||||
width: 'fit-content'
|
||||
}}
|
||||
>
|
||||
添加模型
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default LLMFactoryCard
|
||||
@@ -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<string, string> = {
|
||||
'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<ModelFactoryCardProps> = ({
|
||||
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 (
|
||||
<>
|
||||
<Card sx={{ mb: 2, border: '1px solid #e0e0e0' }}>
|
||||
<CardContent>
|
||||
<Box display="flex" alignItems="center" justifyContent="space-between">
|
||||
<Box display="flex" alignItems="center" gap={2}>
|
||||
<LlmSvgIcon
|
||||
name={getFactoryIconName(factory.name as LLMFactory)}
|
||||
sx={{ width: 40, height: 40, color: 'primary.main' }}/>
|
||||
<Box>
|
||||
<Typography variant="h6" component="div">
|
||||
{factory.name}
|
||||
</Typography>
|
||||
<Box display="flex" gap={1} mt={1}>
|
||||
{factory.model_types.map((type) => (
|
||||
<Chip
|
||||
key={type}
|
||||
label={type.toUpperCase()}
|
||||
size="small"
|
||||
sx={{
|
||||
backgroundColor: MODEL_TYPE_COLORS[type.toUpperCase()] || '#757575',
|
||||
color: 'white',
|
||||
fontSize: '0.7rem',
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box display="flex" alignItems="center" gap={1}>
|
||||
<Button
|
||||
variant="contained"
|
||||
size="small"
|
||||
startIcon={<SettingsIcon />}
|
||||
onClick={() => onConfigure(factory)}
|
||||
>
|
||||
配置
|
||||
</Button>
|
||||
{myModels.length > 0 && (
|
||||
<IconButton onClick={handleExpandClick}>
|
||||
{expanded ? <ExpandLessIcon /> : <ExpandMoreIcon />}
|
||||
</IconButton>
|
||||
)}
|
||||
<IconButton
|
||||
color="error"
|
||||
onClick={() => setShowDeleteConfirm(true)}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Collapse in={expanded} timeout="auto" unmountOnExit>
|
||||
<Divider sx={{ my: 2 }} />
|
||||
<Typography variant="subtitle2" gutterBottom>
|
||||
已配置的模型 ({myModels.length})
|
||||
</Typography>
|
||||
<Grid container spacing={2}>
|
||||
{myModels.map((model) => (
|
||||
<Grid size={{ xs: 12, sm: 6, md: 4 }} key={model.name}>
|
||||
<Card variant="outlined" sx={{ p: 2 }}>
|
||||
<Box display="flex" justifyContent="space-between" alignItems="start">
|
||||
<Box>
|
||||
<Typography variant="body2" fontWeight="bold">
|
||||
{model.name}
|
||||
</Typography>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
{model.type}
|
||||
</Typography>
|
||||
<Typography variant="caption" display="block" color="text.secondary">
|
||||
Max Tokens: {model.max_tokens}
|
||||
</Typography>
|
||||
<Typography variant="caption" display="block" color="text.secondary">
|
||||
Used: {model.used_token}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => onEditModel(factory, model)}
|
||||
>
|
||||
<EditIcon fontSize="small" />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
size="small"
|
||||
color="error"
|
||||
onClick={() => onDeleteModel(factory.name, model.name)}
|
||||
>
|
||||
<DeleteIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</Box>
|
||||
</Card>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Collapse>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 删除确认对话框 */}
|
||||
<Dialog open={showDeleteConfirm} onClose={() => setShowDeleteConfirm(false)}>
|
||||
<DialogTitle>确认删除</DialogTitle>
|
||||
<DialogContent>
|
||||
<Typography>
|
||||
确定要删除模型工厂 "{factory.name}" 吗?这将删除该工厂下的所有模型配置。
|
||||
</Typography>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={() => setShowDeleteConfirm(false)}>取消</Button>
|
||||
<Button onClick={handleDeleteFactory} color="error" variant="contained">
|
||||
删除
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
// 系统默认模型设置组件
|
||||
interface SystemModelSettingProps {
|
||||
myLlm: Record<string, IMyLlmModel> | undefined;
|
||||
}
|
||||
|
||||
const SystemModelSetting: React.FC<SystemModelSettingProps> = ({ 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 (
|
||||
<Card sx={{ mb: 3 }}>
|
||||
<CardContent>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
系统默认 LLM 模型
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary" gutterBottom>
|
||||
设置系统默认使用的大语言模型,用于对话和文本生成任务。
|
||||
</Typography>
|
||||
<Box display="flex" gap={2} alignItems="center" mt={2}>
|
||||
<FormControl sx={{ minWidth: 300 }}>
|
||||
<InputLabel>选择默认模型</InputLabel>
|
||||
<Select
|
||||
value={defaultModel}
|
||||
label="选择默认模型"
|
||||
onChange={(e) => setDefaultModel(e.target.value)}
|
||||
>
|
||||
{chatModels.map((model) => (
|
||||
<MenuItem key={`${model.name}-${model.type}`} value={model.name}>
|
||||
{model.name} ({model.type})
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={handleSaveDefaultModel}
|
||||
disabled={!defaultModel || loading}
|
||||
startIcon={loading ? <CircularProgress size={16} /> : undefined}
|
||||
>
|
||||
保存设置
|
||||
</Button>
|
||||
</Box>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
// 主页面组件
|
||||
function ModelsPage() {
|
||||
@@ -336,116 +97,124 @@ function ModelsPage() {
|
||||
管理您的 LLM 模型工厂和个人模型配置
|
||||
</Typography>
|
||||
|
||||
{/* 系统默认模型设置 */}
|
||||
<SystemModelSetting myLlm={myLlm} />
|
||||
|
||||
{/* My LLM 部分 */}
|
||||
{/* <Box mb={4}>
|
||||
<Typography variant="h5" gutterBottom>
|
||||
我的 LLM 模型
|
||||
</Typography>
|
||||
<Box mb={4} mt={2}>
|
||||
{!myLlm || Object.keys(myLlm).length === 0 ? (
|
||||
<Alert severity="info">
|
||||
您还没有配置任何 LLM 模型。请在下方的模型工厂中进行配置。
|
||||
</Alert>
|
||||
) : (
|
||||
<Grid container spacing={2}>
|
||||
{Object.entries(myLlm).map(([factoryName, group]) => (
|
||||
<Grid size={12} key={factoryName}>
|
||||
<Card variant="outlined">
|
||||
<CardContent>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
{factoryName}
|
||||
</Typography>
|
||||
<Box display="flex" gap={1} mb={2}>
|
||||
{group.tags.split(',').map((tag) => (
|
||||
<Chip
|
||||
key={tag}
|
||||
label={tag.trim()}
|
||||
size="small"
|
||||
sx={{
|
||||
backgroundColor: MODEL_TYPE_COLORS[tag.trim()] || '#757575',
|
||||
color: 'white',
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
<Grid container spacing={2}>
|
||||
{group.llm.map((model) => (
|
||||
<Grid size={{ xs: 12, sm: 6, md: 4 }} key={model.name}>
|
||||
<Card variant="outlined" sx={{ p: 2 }}>
|
||||
<Box display="flex" justifyContent="space-between" alignItems="flex-start" mb={1}>
|
||||
<Typography variant="body2" fontWeight="bold">
|
||||
{model.name}
|
||||
</Typography>
|
||||
<Box>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => handleEditModel({ name: factoryName } as IFactory, model)}
|
||||
>
|
||||
<EditIcon fontSize="small" />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
size="small"
|
||||
color="error"
|
||||
onClick={() => handleDeleteModel(factoryName, model.name)}
|
||||
>
|
||||
<DeleteIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</Box>
|
||||
<Accordion defaultExpanded>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<Typography variant="h5" gutterBottom>
|
||||
我的 LLM 模型
|
||||
</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<Grid container spacing={2}>
|
||||
{Object.entries(myLlm).map(([factoryName, group]) => (
|
||||
<Grid size={12} key={factoryName}>
|
||||
<Card variant="outlined">
|
||||
<CardContent>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
{factoryName}
|
||||
</Typography>
|
||||
<Box display="flex" gap={1} mb={2}>
|
||||
{group.tags.split(',').map((tag) => (
|
||||
<Chip
|
||||
label={model.type}
|
||||
key={tag}
|
||||
label={tag.trim()}
|
||||
size="small"
|
||||
sx={{
|
||||
backgroundColor: MODEL_TYPE_COLORS[model.type.toUpperCase()] || '#757575',
|
||||
backgroundColor: MODEL_TYPE_COLORS[tag.trim()] || '#757575',
|
||||
color: 'white',
|
||||
mb: 1,
|
||||
}}
|
||||
/>
|
||||
<Typography variant="caption" display="block" color="text.secondary">
|
||||
Max Tokens: {model.max_tokens}
|
||||
</Typography>
|
||||
<Typography variant="caption" display="block" color="text.secondary">
|
||||
Used: {model.used_token}
|
||||
</Typography>
|
||||
{model.api_base && (
|
||||
<Typography variant="caption" display="block" color="text.secondary">
|
||||
Base URL: {model.api_base}
|
||||
</Typography>
|
||||
)}
|
||||
</Card>
|
||||
))}
|
||||
</Box>
|
||||
<Grid container spacing={2}>
|
||||
{group.llm.map((model) => (
|
||||
<Grid size={{ xs: 12, sm: 6, md: 4 }} key={model.name}>
|
||||
<Card variant="outlined" sx={{ p: 2 }}>
|
||||
<Box display="flex" justifyContent="space-between" alignItems="flex-start" mb={1}>
|
||||
<Typography variant="body2" fontWeight="bold">
|
||||
{model.name}
|
||||
</Typography>
|
||||
<Box>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => handleEditModel({ name: factoryName } as IFactory, model)}
|
||||
>
|
||||
<EditIcon fontSize="small" />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
size="small"
|
||||
color="error"
|
||||
onClick={() => handleDeleteModel(factoryName, model.name)}
|
||||
>
|
||||
<DeleteIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</Box>
|
||||
<Chip
|
||||
label={model.type}
|
||||
size="small"
|
||||
sx={{
|
||||
backgroundColor: MODEL_TYPE_COLORS[model.type.toUpperCase()] || '#757575',
|
||||
color: 'white',
|
||||
mb: 1,
|
||||
}}
|
||||
/>
|
||||
<Typography variant="caption" display="block" color="text.secondary">
|
||||
Max Tokens: {model.max_tokens}
|
||||
</Typography>
|
||||
<Typography variant="caption" display="block" color="text.secondary">
|
||||
Used: {model.used_token}
|
||||
</Typography>
|
||||
{model.api_base && (
|
||||
<Typography variant="caption" display="block" color="text.secondary">
|
||||
Base URL: {model.api_base}
|
||||
</Typography>
|
||||
)}
|
||||
</Card>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
)}
|
||||
</Box> */}
|
||||
</Box>
|
||||
|
||||
{/* LLM Factory 部分 */}
|
||||
<Box>
|
||||
<Typography variant="h5" gutterBottom>
|
||||
LLM 模型工厂
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary" gutterBottom>
|
||||
配置各种 AI 服务提供商的模型
|
||||
</Typography>
|
||||
|
||||
{llmFactory.map((factory) => (
|
||||
<ModelFactoryCard
|
||||
key={factory.name}
|
||||
factory={factory}
|
||||
myModels={getModelsForFactory(factory.name as LLMFactory)}
|
||||
onConfigure={handleConfigureFactory}
|
||||
onDeleteFactory={handleDeleteFactory}
|
||||
onDeleteModel={handleDeleteModel}
|
||||
onEditModel={handleEditModel}
|
||||
/>
|
||||
))}
|
||||
<Accordion defaultExpanded>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<Typography variant="h5" gutterBottom>
|
||||
LLM 模型工厂
|
||||
</Typography>
|
||||
<AppSvgIcon name='arxiv' />
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<Grid container spacing={2}>
|
||||
{
|
||||
llmFactory.map((factory) => (
|
||||
<Grid size={{ xs: 6, sm: 4, md: 3 }} key={factory.name}>
|
||||
<LLMFactoryCard
|
||||
key={factory.name}
|
||||
factory={factory}
|
||||
onConfigure={handleConfigureFactory}
|
||||
/>
|
||||
</Grid>
|
||||
))
|
||||
}
|
||||
</Grid>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
</Box>
|
||||
|
||||
{/* 模型配置对话框 */}
|
||||
|
||||
Reference in New Issue
Block a user