/* 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. For commercial licensing, please contact support@quantumnous.com */ import React, { useEffect, useState, useCallback } from 'react'; import { Button, Card, Form, Table, Modal, Typography, Toast, } from '@douyinfe/semi-ui'; import { API, showError, showSuccess } from '../../helpers'; import { useTranslation } from 'react-i18next'; import { Plus, Pencil, Trash2, RefreshCw } from 'lucide-react'; const { Text } = Typography; const EMPTY_MODEL = { name: '', provider: '', intelligence: 0, speed: 0, price: 0, latency: 0, context_window: '', type: 'non-reasoning', openness: 'proprietary', category: 'language', }; export default function BenchmarkDataManager() { const { t } = useTranslation(); const [models, setModels] = useState([]); const [loading, setLoading] = useState(false); const [saving, setSaving] = useState(false); const [editModalVisible, setEditModalVisible] = useState(false); const [editingIndex, setEditingIndex] = useState(null); const [editForm, setEditForm] = useState({ ...EMPTY_MODEL }); const fetchData = useCallback(async () => { setLoading(true); try { const res = await API.get('/api/option/'); if (res.data.success && res.data.data) { const option = res.data.data.find( (o) => o.key === 'benchmark_data.models', ); if (option && option.value) { setModels(JSON.parse(option.value)); } else { // try to fetch via the specific key const fallbackRes = await API.get( '/api/option/?key=benchmark_data.models', ); if (fallbackRes.data?.data) { setModels(JSON.parse(fallbackRes.data.data.value || '[]')); } } } } catch (error) { showError(t('获取评测数据失败')); } finally { setLoading(false); } }, [t]); useEffect(() => { fetchData(); }, [fetchData]); const saveData = async (newModels) => { setSaving(true); try { const res = await API.put('/api/option/', { key: 'benchmark_data.models', value: JSON.stringify(newModels), }); if (res.data.success) { showSuccess(t('保存成功')); setModels(newModels); } else { showError(res.data.message || t('保存失败')); } } catch (error) { showError(t('保存失败,请重试')); } finally { setSaving(false); } }; const openAddModal = () => { setEditingIndex(null); setEditForm({ ...EMPTY_MODEL }); setEditModalVisible(true); }; const openEditModal = (index) => { setEditingIndex(index); setEditForm({ ...models[index] }); setEditModalVisible(true); }; const handleSaveModel = async () => { if (!editForm.name || !editForm.provider) { showError(t('模型名称和供应商不能为空')); return; } const newModels = [...models]; if (editingIndex !== null) { newModels[editingIndex] = { ...editForm }; } else { newModels.push({ ...editForm }); } await saveData(newModels); setEditModalVisible(false); }; const handleDeleteModel = async (index) => { const newModels = models.filter((_, i) => i !== index); await saveData(newModels); }; const handleFieldChange = (field, value) => { setEditForm((prev) => ({ ...prev, [field]: ['intelligence', 'speed', 'price', 'latency'].includes(field) ? parseFloat(value) || 0 : value, })); }; const columns = [ { title: t('模型名称'), dataIndex: 'name', width: 180, render: (text, record) => (
{text}
{record.provider}
), }, { title: t('智能指数'), dataIndex: 'intelligence', width: 100, render: (val) => ( {val} ), }, { title: t('速度 (tok/s)'), dataIndex: 'speed', width: 120, render: (val) => ( {val?.toLocaleString()} ), }, { title: t('价格 ($/M)'), dataIndex: 'price', width: 100, render: (val) => ( ${val?.toFixed(2)} ), }, { title: t('延迟 (s)'), dataIndex: 'latency', width: 100, render: (val) => ( {val?.toFixed(2)}s ), }, { title: t('类型'), dataIndex: 'type', width: 80, render: (val) => ( {val === 'reasoning' ? t('推理') : t('通用')} ), }, { title: t('操作'), width: 120, render: (_, __, index) => (
), }, ]; return ( } > {t('在此管理 AI 模型评测数据,添加、编辑或删除模型条目。保存后前端评测页面将自动更新。')} idx} size='small' bordered /> {/* Edit/Add Modal */} setEditModalVisible(false)} okText={t('保存')} cancelText={t('取消')} confirmLoading={saving} style={{ width: 520 }} >
handleFieldChange('name', v)} placeholder='e.g. Claude Opus 4.8' /> handleFieldChange('provider', v)} placeholder='e.g. Anthropic' /> handleFieldChange('intelligence', v)} min={0} max={100} /> handleFieldChange('speed', v)} min={0} /> handleFieldChange('price', v)} min={0} step={0.01} /> handleFieldChange('latency', v)} min={0} step={0.01} /> handleFieldChange('context_window', v)} placeholder='e.g. 128K' /> handleFieldChange('type', v)} > {t('推理模型')} {t('通用模型')} handleFieldChange('openness', v)} > {t('闭源')} {t('开放权重')} handleFieldChange('category', v)} > {t('语言模型')} {t('图像模型')} {t('视频模型')}
); }