/* Copyright (C) 2025 QuantumNous This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ import React, { useState, useEffect, useRef, useMemo } from 'react'; import { SideSheet, Form, Button, Space, Spin, Typography, Card, Tag, Avatar, Col, Row, } from '@douyinfe/semi-ui'; import { IconSave, IconClose, IconLayers, } from '@douyinfe/semi-icons'; import { API, showError, showSuccess } from '../../../../helpers'; import { useTranslation } from 'react-i18next'; import { useIsMobile } from '../../../../hooks/common/useIsMobile'; const endpointOptions = [ { label: 'OpenAI', value: 'openai' }, { label: 'Anthropic', value: 'anthropic' }, { label: 'Gemini', value: 'gemini' }, { label: 'Image Generation', value: 'image-generation' }, { label: 'Jina Rerank', value: 'jina-rerank' }, ]; const { Text, Title } = Typography; const EditModelModal = (props) => { const { t } = useTranslation(); const [loading, setLoading] = useState(false); const isMobile = useIsMobile(); const formApiRef = useRef(null); const isEdit = props.editingModel && props.editingModel.id !== undefined; const placement = useMemo(() => (isEdit ? 'right' : 'left'), [isEdit]); // 供应商列表 const [vendors, setVendors] = useState([]); // 获取供应商列表 const fetchVendors = async () => { try { const res = await API.get('/api/vendors/?page_size=1000'); // 获取全部供应商 if (res.data.success) { const items = res.data.data.items || res.data.data || []; setVendors(Array.isArray(items) ? items : []); } } catch (error) { // ignore } }; useEffect(() => { if (props.visiable) { fetchVendors(); } }, [props.visiable]); const getInitValues = () => ({ model_name: '', description: '', tags: [], vendor_id: undefined, vendor: '', vendor_icon: '', endpoints: [], status: true, }); const handleCancel = () => { props.handleClose(); }; const loadModel = async () => { if (!isEdit || !props.editingModel.id) return; setLoading(true); try { const res = await API.get(`/api/models/${props.editingModel.id}`); const { success, message, data } = res.data; if (success) { // 处理tags if (data.tags) { data.tags = data.tags.split(',').filter(Boolean); } else { data.tags = []; } // 处理endpoints if (data.endpoints) { try { data.endpoints = JSON.parse(data.endpoints); } catch (e) { data.endpoints = []; } } else { data.endpoints = []; } // 处理status,将数字转为布尔值 data.status = data.status === 1; if (formApiRef.current) { formApiRef.current.setValues({ ...getInitValues(), ...data }); } } else { showError(message); } } catch (error) { showError(t('加载模型信息失败')); } setLoading(false); }; useEffect(() => { if (formApiRef.current) { if (!isEdit) { formApiRef.current.setValues(getInitValues()); } } }, [props.editingModel?.id]); useEffect(() => { if (props.visiable) { if (isEdit) { loadModel(); } else { formApiRef.current?.setValues(getInitValues()); } } else { formApiRef.current?.reset(); } }, [props.visiable, props.editingModel?.id]); const submit = async (values) => { setLoading(true); try { const submitData = { ...values, tags: Array.isArray(values.tags) ? values.tags.join(',') : values.tags, endpoints: JSON.stringify(values.endpoints || []), status: values.status ? 1 : 0, }; if (isEdit) { submitData.id = props.editingModel.id; const res = await API.put('/api/models/', submitData); const { success, message } = res.data; if (success) { showSuccess(t('模型更新成功!')); props.refresh(); props.handleClose(); } else { showError(t(message)); } } else { const res = await API.post('/api/models/', submitData); const { success, message } = res.data; if (success) { showSuccess(t('模型创建成功!')); props.refresh(); props.handleClose(); } else { showError(t(message)); } } } catch (error) { showError(error.response?.data?.message || t('操作失败')); } setLoading(false); formApiRef.current?.setValues(getInitValues()); }; return ( {isEdit ? ( {t('更新')} ) : ( {t('新建')} )} {isEdit ? t('更新模型信息') : t('创建新的模型')} } bodyStyle={{ padding: '0' }} visible={props.visiable} width={isMobile ? '100%' : 600} footer={
} closeIcon={null} onCancel={() => handleCancel()} >
(formApiRef.current = api)} onSubmit={submit} > {({ values }) => (
{/* 基本信息 */}
{t('基本信息')}
{t('设置模型的基本信息')}
{/* 供应商信息 */}
{t('供应商信息')}
{t('设置模型的供应商相关信息')}
({ label: v.name, value: v.id }))} filter showClear style={{ width: '100%' }} onChange={(value) => { const vendorInfo = vendors.find(v => v.id === value); if (vendorInfo && formApiRef.current) { formApiRef.current.setValue('vendor', vendorInfo.name); } }} />
{/* 功能配置 */}
{t('功能配置')}
{t('设置模型的功能和状态')}
)}
); }; export default EditModelModal;