import React, { useState, useEffect } from 'react'; import { Card, Button, Form, Input, Select, Space, message, Tabs, Slider, Typography, Divider, Row, Col, Tag, Modal, Tooltip, Switch } from 'antd'; import { RobotOutlined, AudioOutlined, SettingOutlined, SafetyCertificateOutlined, InfoCircleOutlined, CheckCircleOutlined, ThunderboltOutlined, PlusOutlined, EditOutlined, DeleteOutlined, StarOutlined, StarFilled, SaveOutlined } from '@ant-design/icons'; import { api } from '../api'; import ListTable from '../components/ListTable/ListTable'; import DetailDrawer from '../components/DetailDrawer/DetailDrawer'; const { Option } = Select; const { Title, Text } = Typography; const ModelManage: React.FC = () => { const [loading, setLoading] = useState(false); const [data, setData] = useState([]); const [vendors, setVendors] = useState([]); const [activeTab, setActiveTab] = useState('llm'); const [isDrawerVisible, setIsDrawerVisible] = useState(false); const [editingItem, setEditingItem] = useState(null); const [testLoading, setTestLoading] = useState(false); const [form] = Form.useForm(); const fetchModels = async (type: string) => { setLoading(true); try { const res = await api.listAIModels(type); setData(res); } catch (e) { message.error('加载模型列表失败'); } finally { setLoading(false); } }; const fetchVendors = async () => { try { const res = await api.listDictItems('MODEL_VENDOR'); setVendors(res); } catch (e) { console.error('获取供应商码表失败'); } }; useEffect(() => { fetchModels(activeTab); }, [activeTab]); useEffect(() => { fetchVendors(); }, []); const handleAdd = () => { setEditingItem(null); form.resetFields(); form.setFieldsValue({ model_type: activeTab, status: 1, is_default: data.length === 0, api_path: activeTab === 'llm' ? '/chat/completions' : '', temperature: 0.7, top_p: 0.9 }); setIsDrawerVisible(true); }; const handleEdit = (record: any) => { setEditingItem(record); const formData = { ...record }; if (record.config) { formData.temperature = record.config.temperature; formData.top_p = record.config.top_p; } form.setFieldsValue(formData); setIsDrawerVisible(true); }; const handleDelete = (id: number) => { Modal.confirm({ title: '确认删除', content: '删除后该模型配置将无法在业务中使用。', onOk: async () => { await api.deleteAIModel(id); message.success('已删除'); fetchModels(activeTab); }, }); }; const handleSetDefault = async (record: any) => { try { await api.updateAIModel(record.model_id, { ...record, is_default: true }); message.success(`${record.model_name} 已设为默认`); fetchModels(activeTab); } catch (e) { message.error('设置失败'); } }; const handleSave = async () => { const values = await form.validateFields(); const payload = { ...values, model_type: activeTab, config: activeTab === 'llm' ? { temperature: values.temperature, top_p: values.top_p } : {} }; try { if (editingItem) { await api.updateAIModel(editingItem.model_id, payload); } else { await api.createAIModel(payload); } setIsDrawerVisible(false); fetchModels(activeTab); message.success('配置已保存'); } catch (e: any) { message.error('保存失败: ' + e.message); } }; const handleTestConnection = () => { setTestLoading(true); setTimeout(() => { message.success('连接测试成功!模型响应正常。'); setTestLoading(false); }, 1500); }; const getVendorLabel = (value: string) => { return vendors.find(v => v.item_value === value)?.item_label || value; }; const columns = [ { title: '模型名称', dataIndex: 'model_name', key: 'model_name', render: (t: string, r: any) => ( {t} {r.is_default && 默认使用} {r.status === 0 && 已禁用} ) }, { title: '提供商', dataIndex: 'provider', key: 'provider', render: (v: string) => {getVendorLabel(v)} }, { title: 'Base URL', dataIndex: 'base_url', key: 'base_url', ellipsis: true }, { title: '操作', key: 'action', width: 200, render: (_: any, r: any) => ( {!r.is_default && ( )} ) } ]; const renderFormContent = () => (
{activeTab === 'llm' ? : }
{activeTab === 'llm' ? 'AI 总结模型配置' : '语音识别 (ASR) 配置'} {activeTab === 'llm' ? '选择用于生成会议纪要的大语言模型' : '转录模型与参数配置'}
} /> {activeTab === 'llm' && ( <> )} {activeTab === 'llm' && (
)} ); return (
通用设置
, disabled: true }, { key: 'llm', label:
AI 模型
, children: (
大模型配置列表 配置并管理用于会议总结的 LLM 服务
) }, { key: 'asr', label:
语音识别
, children: (
语音转译模型列表 管理用于音频转文字的 ASR 服务
) }, { key: 'voiceprint', label:
声纹识别
, disabled: true }, { key: 'security', label:
安全设置
, disabled: true }, { key: 'about', label:
关于系统
, disabled: true }, ]} /> setIsDrawerVisible(false)} title={{ text: editingItem ? '编辑配置' : '新增模型配置' }} width={600} headerActions={[ { key: 'save', label: activeTab === 'asr' ? '保存并重载 ASR' : '保存配置', type: 'primary', onClick: handleSave, style: activeTab === 'asr' ? { background: '#fa541c', borderColor: '#fa541c' } : {} } as any ]} >
{renderFormContent()}
); }; export default ModelManage;