feat(settings): refactor LLM model management UI and components

This commit is contained in:
2025-10-21 18:21:48 +08:00
parent bcfcc4b40a
commit 4784fcb23f
7 changed files with 225 additions and 360 deletions

View File

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

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?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> <defs>
<style> <style>
.cls-1 { .cls-1 {
@@ -7,7 +7,7 @@
} }
</style> </style>
</defs> </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"/> <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> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 595 B

After

Width:  |  Height:  |  Size: 589 B

View File

@@ -1,28 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?> <?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"> viewBox="0 0 283.46 283.46">
<defs> <defs>
<style> <style>
.cls-1 { .cls-1 {
fill: url(#_未命名的渐变_5-2); fill: url(#gradient_5-2);
} }
.cls-2 { .cls-2 {
fill: url(#_未命名的渐变_9); fill: url(#gradient_9);
} }
.cls-3 { .cls-3 {
fill: url(#_未命名的渐变_5); fill: url(#gradient_5);
} }
</style> </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"> gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#e9a85e" /> <stop offset="0" stop-color="#e9a85e" />
<stop offset="1" stop-color="#f52b76" /> <stop offset="1" stop-color="#f52b76" />
</linearGradient> </linearGradient>
<linearGradient id="_未命名的渐变_5-2" data-name="未命名的渐变 5" x1="25.96" y1="286.21" x2="252.09" y2=".3" <linearGradient id="gradient_5-2" data-name="gradient 5" x1="25.96" y1="286.21" x2="252.09" y2=".3"
xlink:href="#_未命名的渐变_5" /> xlink:href="#gradient_5" />
<linearGradient id="_未命名的渐变_9" data-name="未命名的渐变 9" x1="-474.33" y1="476.58" x2="-160.37" y2="476.58" <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"> gradientTransform="translate(669.07 -75.9) rotate(33.75)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#6a0cf5" /> <stop offset="0" stop-color="#6a0cf5" />
<stop offset="1" stop-color="#ab66f3" /> <stop offset="1" stop-color="#ab66f3" />

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -6,7 +6,7 @@ const svgPath = '/src/assets/svg'
interface AppSvgIconProps extends SvgIconProps { interface AppSvgIconProps extends SvgIconProps {
name: string; name: string;
point: 'llm' | 'chunk' | 'file' | 'default'; point?: 'llm' | 'chunk' | 'file' | 'default';
} }
const getPointPath = (point: AppSvgIconProps['point']) => { const getPointPath = (point: AppSvgIconProps['point']) => {

View File

@@ -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<string, string> = {
<Box> 'LLM': '#1976d2',
<Typography variant="h6" gutterBottom> 'TEXT EMBEDDING': '#388e3c',
</Typography> 'TEXT RE-RANK': '#f57c00',
</Box> '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

View File

@@ -9,266 +9,27 @@ import {
IconButton, IconButton,
Collapse, Collapse,
Grid, Grid,
Divider,
Dialog,
DialogTitle,
DialogContent,
DialogActions,
FormControl,
InputLabel,
Select,
MenuItem,
Alert, Alert,
CircularProgress, CircularProgress,
Tooltip, Tooltip,
Accordion,
AccordionSummary,
AccordionDetails,
Divider,
} from '@mui/material'; } from '@mui/material';
import { import {
ExpandMore as ExpandMoreIcon, ExpandMore as ExpandMoreIcon,
ExpandLess as ExpandLessIcon, ExpandLess as ExpandLessIcon,
Settings as SettingsIcon,
Delete as DeleteIcon,
Edit as EditIcon, Edit as EditIcon,
Add as AddIcon, Delete as DeleteIcon,
Visibility as VisibilityIcon,
VisibilityOff as VisibilityOffIcon,
} from '@mui/icons-material'; } from '@mui/icons-material';
import { useLlmModelSetting } from '@/hooks/setting-hooks'; import { useLlmModelSetting } from '@/hooks/setting-hooks';
import { useModelDialogs } from './hooks/useModelDialogs'; 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 { LLM_FACTORY_LIST, IconMap, type LLMFactory } from '@/constants/llm';
import type { IFactory, IMyLlmModel, ILlmItem } from '@/interfaces/database/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() { function ModelsPage() {
@@ -336,116 +97,124 @@ function ModelsPage() {
LLM LLM
</Typography> </Typography>
{/* 系统默认模型设置 */}
<SystemModelSetting myLlm={myLlm} />
{/* My LLM 部分 */} {/* My LLM 部分 */}
{/* <Box mb={4}> <Box mb={4} mt={2}>
<Typography variant="h5" gutterBottom>
我的 LLM 模型
</Typography>
{!myLlm || Object.keys(myLlm).length === 0 ? ( {!myLlm || Object.keys(myLlm).length === 0 ? (
<Alert severity="info"> <Alert severity="info">
LLM LLM
</Alert> </Alert>
) : ( ) : (
<Grid container spacing={2}> <Accordion defaultExpanded>
{Object.entries(myLlm).map(([factoryName, group]) => ( <AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Grid size={12} key={factoryName}> <Typography variant="h5" gutterBottom>
<Card variant="outlined"> LLM
<CardContent> </Typography>
<Typography variant="h6" gutterBottom> </AccordionSummary>
{factoryName} <AccordionDetails>
</Typography> <Grid container spacing={2}>
<Box display="flex" gap={1} mb={2}> {Object.entries(myLlm).map(([factoryName, group]) => (
{group.tags.split(',').map((tag) => ( <Grid size={12} key={factoryName}>
<Chip <Card variant="outlined">
key={tag} <CardContent>
label={tag.trim()} <Typography variant="h6" gutterBottom>
size="small" {factoryName}
sx={{ </Typography>
backgroundColor: MODEL_TYPE_COLORS[tag.trim()] || '#757575', <Box display="flex" gap={1} mb={2}>
color: 'white', {group.tags.split(',').map((tag) => (
}}
/>
))}
</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 <Chip
label={model.type} key={tag}
label={tag.trim()}
size="small" size="small"
sx={{ sx={{
backgroundColor: MODEL_TYPE_COLORS[model.type.toUpperCase()] || '#757575', backgroundColor: MODEL_TYPE_COLORS[tag.trim()] || '#757575',
color: 'white', color: 'white',
mb: 1,
}} }}
/> />
<Typography variant="caption" display="block" color="text.secondary"> ))}
Max Tokens: {model.max_tokens} </Box>
</Typography> <Grid container spacing={2}>
<Typography variant="caption" display="block" color="text.secondary"> {group.llm.map((model) => (
Used: {model.used_token} <Grid size={{ xs: 12, sm: 6, md: 4 }} key={model.name}>
</Typography> <Card variant="outlined" sx={{ p: 2 }}>
{model.api_base && ( <Box display="flex" justifyContent="space-between" alignItems="flex-start" mb={1}>
<Typography variant="caption" display="block" color="text.secondary"> <Typography variant="body2" fontWeight="bold">
Base URL: {model.api_base} {model.name}
</Typography> </Typography>
)} <Box>
</Card> <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>
</Grid> </Card>
</CardContent> </Grid>
</Card> ))}
</Grid> </Grid>
))} </AccordionDetails>
</Grid> </Accordion>
)} )}
</Box> */} </Box>
{/* LLM Factory 部分 */} {/* LLM Factory 部分 */}
<Box> <Box>
<Typography variant="h5" gutterBottom> <Accordion defaultExpanded>
LLM <AccordionSummary expandIcon={<ExpandMoreIcon />}>
</Typography> <Typography variant="h5" gutterBottom>
<Typography variant="body2" color="text.secondary" gutterBottom> LLM
AI </Typography>
</Typography> <AppSvgIcon name='arxiv' />
</AccordionSummary>
{llmFactory.map((factory) => ( <AccordionDetails>
<ModelFactoryCard <Grid container spacing={2}>
key={factory.name} {
factory={factory} llmFactory.map((factory) => (
myModels={getModelsForFactory(factory.name as LLMFactory)} <Grid size={{ xs: 6, sm: 4, md: 3 }} key={factory.name}>
onConfigure={handleConfigureFactory} <LLMFactoryCard
onDeleteFactory={handleDeleteFactory} key={factory.name}
onDeleteModel={handleDeleteModel} factory={factory}
onEditModel={handleEditModel} onConfigure={handleConfigureFactory}
/> />
))} </Grid>
))
}
</Grid>
</AccordionDetails>
</Accordion>
</Box> </Box>
{/* 模型配置对话框 */} {/* 模型配置对话框 */}

View File

@@ -5,7 +5,15 @@ import svgr from "vite-plugin-svgr";
// https://vite.dev/config/ // https://vite.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [react(), svgr()], plugins: [
react(),
svgr({
svgrOptions: {
icon: true,
prettier: true,
}
})
],
resolve: { resolve: {
alias: { alias: {
'@': path.resolve(__dirname, './src'), '@': path.resolve(__dirname, './src'),