import React, { useState, useEffect } from 'react'; import { Table, Card, Button, Input, Space, Drawer, Form, Select, Tag, message, Popconfirm, Typography, Divider, Tooltip, Row, Col, InputNumber, Switch, Radio } from 'antd'; import { PlusOutlined, EditOutlined, DeleteOutlined, SyncOutlined, SearchOutlined, SafetyCertificateOutlined, SaveOutlined, ApiOutlined, CheckCircleOutlined } from '@ant-design/icons'; import { useDict } from '../../hooks/useDict'; import { getAiModelPage, saveAiModel, updateAiModel, deleteAiModel, getRemoteModelList, AiModelVO, AiModelDTO } from '../../api/business/aimodel'; const { Option } = Select; const { Text, Title } = Typography; const AiModels: React.FC = () => { const [form] = Form.useForm(); const { items: providers } = useDict('biz_ai_provider'); const [loading, setLoading] = useState(false); const [data, setData] = useState([]); const [total, setTotal] = useState(0); const [current, setCurrent] = useState(1); const [size, setSize] = useState(10); const [searchName, setSearchName] = useState(''); const [searchType, setSearchType] = useState(undefined); const [drawerVisible, setDrawerVisible] = useState(false); const [editingId, setEditingId] = useState(null); const [submitLoading, setSubmitLoading] = useState(false); const [fetchLoading, setFetchLoading] = useState(false); const [remoteModels, setRemoteModels] = useState([]); const [modelType, setModelType] = useState<'ASR' | 'LLM'>('ASR'); // Check if current user is platform admin const isPlatformAdmin = React.useMemo(() => { const profileStr = sessionStorage.getItem("userProfile"); if (profileStr) { const profile = JSON.parse(profileStr); return profile.isPlatformAdmin === true; } return false; }, []); useEffect(() => { fetchData(); }, [current, size, searchName, searchType]); const fetchData = async () => { setLoading(true); try { const res = await getAiModelPage({ current, size, name: searchName, type: searchType }); if (res.data && res.data.data && res.data.data.records) { setData(res.data.data.records); setTotal(res.data.data.total); } } catch (err) { console.error(err); } finally { setLoading(false); } }; const handleOpenDrawer = (record?: AiModelVO) => { setRemoteModels([]); if (record) { setEditingId(record.id); setModelType(record.modelType); form.setFieldsValue(record); if (record.modelCode) setRemoteModels([record.modelCode]); } else { setEditingId(null); setModelType('ASR'); form.resetFields(); form.setFieldsValue({ status: 1, isDefault: 0, temperature: 0.7, topP: 0.9, modelType: 'ASR' }); } setDrawerVisible(true); }; const handleFetchRemote = async () => { const vals = form.getFieldsValue(['provider', 'baseUrl', 'apiKey']); if (!vals.provider || !vals.baseUrl) { message.warning('请先填写提供商和基础地址'); return; } setFetchLoading(true); try { const res = await getRemoteModelList(vals); // res.data 是后端的 ApiResponse, res.data.data 才是模型字符串数组 if (res.data && Array.isArray(res.data.data)) { setRemoteModels(res.data.data); message.success(`成功获取 ${res.data.data.length} 个模型`); } else { setRemoteModels([]); } } catch (err) { console.error(err); } finally { setFetchLoading(false); } }; const handleSubmit = async () => { try { const values = await form.validateFields(); setSubmitLoading(true); if (editingId) { await updateAiModel({ ...values, id: editingId }); message.success('更新成功'); } else { await saveAiModel(values); message.success('添加成功'); } setDrawerVisible(false); fetchData(); } catch (err) { console.error(err); } finally { setSubmitLoading(false); } }; const columns = [ { title: '模型名称', dataIndex: 'modelName', key: 'modelName', render: (text: string, record: AiModelVO) => ( {text} {record.isDefault === 1 && 默认} {record.tenantId === 0 && } ) }, { title: '类型', dataIndex: 'modelType', key: 'modelType', render: (type: string) => {type === 'ASR' ? '语音识别' : '会议总结'} }, { title: '提供商', dataIndex: 'provider', key: 'provider', render: (val: string) => { const item = providers.find(i => i.itemValue === val); return item ? {item.itemLabel} : val; } }, { title: '模型代码', dataIndex: 'modelCode', key: 'modelCode', }, { title: '状态', dataIndex: 'status', key: 'status', render: (status: number) => status === 1 ? 启用 : 禁用 }, { title: '操作', key: 'action', render: (_: any, record: AiModelVO) => { const canEdit = record.tenantId !== 0 || isPlatformAdmin; return ( {canEdit && } {canEdit && ( deleteAiModel(record.id).then(() => fetchData())}> )} ); } } ]; return (
setSearchType(e.target.value)} buttonStyle="solid"> 全部 语音识别 会议总结 } allowClear onPressEnter={(e) => setSearchName((e.target as any).value)} style={{ width: 180 }} /> }> { setCurrent(p); setSize(s); }}} /> {editingId ? '编辑模型配置' : '添加模型配置'}} width={600} onClose={() => setDrawerVisible(false)} open={drawerVisible} extra={ } >
setModelType(e.target.value)} disabled={!!editingId}> 语音识别 (ASR) 会议总结 (LLM)
业务参数 { // 如果是数组(tags模式返回数组),取最后一个值作为最终模型编码 return Array.isArray(value) ? value[value.length - 1] : value; }} > {modelType === 'ASR' && ( )} {modelType === 'LLM' && ( <> )} form.setFieldsValue({ isDefault: checked ? 1 : 0 })} checked={form.getFieldValue('isDefault') === 1} /> form.setFieldsValue({ status: checked ? 1 : 0 })} checked={form.getFieldValue('status') === 1} /> ); }; export default AiModels;