1. 模型对比列表调通
This commit is contained in:
@@ -34,7 +34,8 @@
|
||||
"Bash(./test_all.sh)",
|
||||
"Bash(/data/code/FT_Platform/YG_FT_Platform/test_data_dir.sh:*)",
|
||||
"Bash(grep:*)",
|
||||
"Bash(mysql:*)"
|
||||
"Bash(mysql:*)",
|
||||
"Bash(ls:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
57
src/main.py
57
src/main.py
@@ -103,6 +103,17 @@ def init_database():
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4""",
|
||||
|
||||
# 模型对比表
|
||||
"""CREATE TABLE IF NOT EXISTS model_compare (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
model_name VARCHAR(255) NOT NULL,
|
||||
description TEXT,
|
||||
models JSON,
|
||||
status VARCHAR(50) DEFAULT 'pending',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4""",
|
||||
|
||||
# 数据集管理表
|
||||
"""CREATE TABLE IF NOT EXISTS dataset_manage (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
@@ -248,12 +259,20 @@ def generic_get_by_id(table_name, id_val):
|
||||
|
||||
def generic_create(table_name, data):
|
||||
"""通用创建"""
|
||||
import json
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor()
|
||||
# 处理JSON字段,将列表和字典转为JSON字符串
|
||||
processed_values = []
|
||||
for value in data.values():
|
||||
if isinstance(value, (list, dict)):
|
||||
processed_values.append(json.dumps(value, ensure_ascii=False))
|
||||
else:
|
||||
processed_values.append(value)
|
||||
columns = ', '.join(data.keys())
|
||||
placeholders = ', '.join(['%s'] * len(data))
|
||||
sql = f"INSERT INTO {table_name} ({columns}) VALUES ({placeholders})"
|
||||
cursor.execute(sql, list(data.values()))
|
||||
cursor.execute(sql, processed_values)
|
||||
conn.commit()
|
||||
new_id = cursor.lastrowid
|
||||
cursor.close()
|
||||
@@ -263,11 +282,19 @@ def generic_create(table_name, data):
|
||||
|
||||
def generic_update(table_name, id_val, data):
|
||||
"""通用更新"""
|
||||
import json
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor()
|
||||
# 处理JSON字段,将列表和字典转为JSON字符串
|
||||
processed_values = []
|
||||
for value in data.values():
|
||||
if isinstance(value, (list, dict)):
|
||||
processed_values.append(json.dumps(value, ensure_ascii=False))
|
||||
else:
|
||||
processed_values.append(value)
|
||||
set_clause = ', '.join([f"{k} = %s" for k in data.keys()])
|
||||
sql = f"UPDATE {table_name} SET {set_clause} WHERE id = %s"
|
||||
values = list(data.values()) + [id_val]
|
||||
values = processed_values + [id_val]
|
||||
cursor.execute(sql, values)
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
@@ -407,6 +434,32 @@ def delete_model_deploy(id):
|
||||
return jsonify({'code': 0, 'message': '删除成功'})
|
||||
|
||||
|
||||
# ============ 模型对比接口 ============
|
||||
@app.route('/api/model-compare', methods=['GET'])
|
||||
def get_model_compare():
|
||||
return jsonify({'code': 0, 'data': generic_get_all('model_compare')})
|
||||
|
||||
|
||||
@app.route('/api/model-compare', methods=['POST'])
|
||||
def create_model_compare():
|
||||
data = request.json
|
||||
new_id = generic_create('model_compare', data)
|
||||
return jsonify({'code': 0, 'message': '创建成功', 'id': new_id})
|
||||
|
||||
|
||||
@app.route('/api/model-compare/<int:id>', methods=['PUT'])
|
||||
def update_model_compare(id):
|
||||
data = request.json
|
||||
generic_update('model_compare', id, data)
|
||||
return jsonify({'code': 0, 'message': '更新成功'})
|
||||
|
||||
|
||||
@app.route('/api/model-compare/<int:id>', methods=['DELETE'])
|
||||
def delete_model_compare(id):
|
||||
generic_delete('model_compare', id)
|
||||
return jsonify({'code': 0, 'message': '删除成功'})
|
||||
|
||||
|
||||
# ============ 数据生成接口 ============
|
||||
@app.route('/api/data-generate', methods=['GET'])
|
||||
def get_data_generate():
|
||||
|
||||
@@ -166,9 +166,9 @@
|
||||
<i class="fa fa-line-chart w-5 text-center"></i>
|
||||
<span class="ml-2">模型评测</span>
|
||||
</a>
|
||||
<a href="#" data-page="model-deploy" class="nav-link flex items-center px-4 py-2.5 hover:bg-[#001529]/20 transition-colors">
|
||||
<a href="#" data-page="model-compare" class="nav-link flex items-center px-4 py-2.5 hover:bg-[#001529]/20 transition-colors">
|
||||
<i class="fa fa-server w-5 text-center"></i>
|
||||
<span class="ml-2">模型部署</span>
|
||||
<span class="ml-2">模型对比</span>
|
||||
</a>
|
||||
|
||||
<!-- 第二分区:资源管理 -->
|
||||
@@ -290,19 +290,25 @@
|
||||
],
|
||||
actions: ['report', 'delete']
|
||||
},
|
||||
'model-deploy': {
|
||||
'model-compare': {
|
||||
title: '模型对比',
|
||||
api: 'model-deploy',
|
||||
api: 'model-compare',
|
||||
hasCreate: true,
|
||||
createText: '新建对比',
|
||||
columns: [
|
||||
{ title: '服务名称', key: 'model_name' },
|
||||
{ title: '端点', key: 'endpoint' },
|
||||
{ title: '实例', key: 'instance' },
|
||||
{ title: '对比名称', key: 'model_name' },
|
||||
{ title: '描述', key: 'description', render: (val) => val || '-' },
|
||||
{ title: '模型列表', key: 'models', render: (val) => {
|
||||
if (!val) return '-';
|
||||
try {
|
||||
const models = typeof val === 'string' ? JSON.parse(val) : val;
|
||||
return models.length + '个模型';
|
||||
} catch { return '-'; }
|
||||
}},
|
||||
{ title: '状态', key: 'status', render: (val) => `<span class="px-2 py-1 rounded text-xs ${val === 'running' ? 'bg-green-100 text-green-700' : val === 'stopped' ? 'bg-red-100 text-red-700' : 'bg-gray-100 text-gray-700'}">${val}</span>` },
|
||||
{ title: '创建时间', key: 'create_time', render: (val) => val ? new Date(val).toLocaleString('zh-CN') : '-' }
|
||||
],
|
||||
actions: ['stop', 'scale', 'delete']
|
||||
actions: ['delete']
|
||||
},
|
||||
'dataset-manage': {
|
||||
title: '数据集管理',
|
||||
@@ -1364,8 +1370,8 @@
|
||||
window.location.href = 'model-eval-create.html';
|
||||
} else if (apiType === 'dataset-manage') {
|
||||
window.location.href = 'dataset-create.html';
|
||||
} else if (apiType === 'model-deploy') {
|
||||
window.location.href = 'model-deploy-create.html';
|
||||
} else if (apiType === 'model-compare') {
|
||||
window.location.href = 'model-compare-create.html';
|
||||
} else {
|
||||
showMessage('提示', '该功能开发中...', 'info');
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
<i class="fa fa-line-chart w-5 text-center"></i>
|
||||
<span class="ml-2">模型评测</span>
|
||||
</a>
|
||||
<a href="main.html?page=model-deploy" data-page="model-deploy" class="nav-link flex items-center px-4 py-2.5 hover:bg-[#001529]/20 transition-colors">
|
||||
<a href="main.html?page=model-compare" data-page="model-compare" class="nav-link flex items-center px-4 py-2.5 hover:bg-[#001529]/20 transition-colors">
|
||||
<i class="fa fa-server w-5 text-center"></i>
|
||||
<span class="ml-2">模型对比</span>
|
||||
</a>
|
||||
@@ -154,7 +154,7 @@
|
||||
<div class="bg-white rounded-lg shadow-sm">
|
||||
<div class="flex items-center justify-between p-4 border-b border-gray-100">
|
||||
<div class="flex items-center text-sm">
|
||||
<a href="main.html?page=model-deploy" class="text-primary hover:underline">模型对比</a>
|
||||
<a href="main.html?page=model-compare" class="text-primary hover:underline">模型对比</a>
|
||||
<span class="mx-2 text-gray-300">/</span>
|
||||
<span class="text-gray-800 font-medium">新建对比</span>
|
||||
</div>
|
||||
@@ -182,12 +182,19 @@
|
||||
<div class="mb-6">
|
||||
<h3 class="text-sm font-semibold text-gray-700 mb-4 pb-2 border-b border-gray-100">选择对比模型 <span class="text-red-500">*</span></h3>
|
||||
<div class="mb-3 flex items-center justify-between">
|
||||
<div class="flex items-center space-x-3">
|
||||
<span class="text-sm text-gray-600">已选择 <span id="selectedCount" class="text-primary font-medium">0</span> / 4 个模型</span>
|
||||
<span class="text-xs text-gray-400">最多选择4个模型进行对比</span>
|
||||
</div>
|
||||
<!-- 模型列表容器 -->
|
||||
<div id="modelList" class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="col-span-2 text-center py-8 text-gray-400">
|
||||
<div class="relative">
|
||||
<input type="text" id="modelSearchInput" placeholder="搜索模型..."
|
||||
class="pl-8 pr-3 py-1.5 border border-gray-300 rounded-lg text-sm focus:border-primary focus:outline-none w-48">
|
||||
<i class="fa fa-search absolute left-2.5 top-1/2 transform -translate-y-1/2 text-gray-400 text-xs"></i>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 模型列表容器(带滚动) -->
|
||||
<div id="modelList" class="border border-gray-200 rounded-lg max-h-80 overflow-y-auto">
|
||||
<div class="p-8 text-center text-gray-400">
|
||||
<i class="fa fa-spinner fa-spin text-2xl mb-2"></i>
|
||||
<p>加载模型列表中...</p>
|
||||
</div>
|
||||
@@ -241,7 +248,7 @@
|
||||
|
||||
// 返回列表页
|
||||
function goBack() {
|
||||
window.location.href = 'main.html?page=model-deploy';
|
||||
window.location.href = 'main.html?page=model-compare';
|
||||
}
|
||||
|
||||
// 加载模型列表
|
||||
@@ -271,7 +278,7 @@
|
||||
const container = document.getElementById('modelList');
|
||||
if (allModels.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div class="col-span-2 text-center py-8 text-gray-400">
|
||||
<div class="p-8 text-center text-gray-400">
|
||||
<i class="fa fa-inbox text-2xl mb-2"></i>
|
||||
<p>暂无模型,请先添加模型</p>
|
||||
</div>
|
||||
@@ -291,21 +298,23 @@
|
||||
}[model.type] || model.type || '其他';
|
||||
|
||||
return `
|
||||
<div class="model-card border border-gray-200 rounded-lg p-4 cursor-pointer ${isSelected ? 'selected' : ''} ${isDisabled ? 'disabled' : ''}"
|
||||
<div class="model-card border-b border-gray-100 last:border-b-0 p-4 cursor-pointer ${isSelected ? 'selected bg-blue-50/50' : ''} ${isDisabled ? 'disabled opacity-50' : ''} hover:bg-gray-50 transition-colors"
|
||||
onclick="toggleModel(${model.id})">
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center mb-2">
|
||||
<span class="font-medium text-gray-800">${model.name}</span>
|
||||
<span class="ml-2 px-2 py-0.5 bg-blue-100 text-blue-700 text-xs rounded">${typeText}</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-500 mb-2">${model.description || '暂无描述'}</p>
|
||||
<p class="text-xs text-gray-400">${model.model_source === 'local' ? '本地模型' : '在线模型'} | ${model.create_time ? new Date(model.create_time).toLocaleDateString('zh-CN') : '-'}</p>
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<div class="w-6 h-6 rounded-full border-2 ${isSelected ? 'border-primary bg-primary' : 'border-gray-300'} flex items-center justify-center">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center flex-1 min-w-0">
|
||||
<div class="w-5 h-5 rounded-full border-2 ${isSelected ? 'border-primary bg-primary' : 'border-gray-300'} flex items-center justify-center mr-3 flex-shrink-0">
|
||||
${isSelected ? '<i class="fa fa-check text-white text-xs"></i>' : ''}
|
||||
</div>
|
||||
<div class="min-w-0">
|
||||
<div class="flex items-center mb-1">
|
||||
<span class="font-medium text-gray-800 truncate">${model.name}</span>
|
||||
<span class="ml-2 px-2 py-0.5 bg-blue-100 text-blue-700 text-xs rounded flex-shrink-0">${typeText}</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-500 truncate">${model.description || '暂无描述'}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-4 text-xs text-gray-400 flex-shrink-0">
|
||||
${model.model_source === 'local' ? '本地模型' : '在线模型'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -328,6 +337,67 @@
|
||||
renderModels();
|
||||
}
|
||||
|
||||
// 筛选模型
|
||||
function filterModels(keyword) {
|
||||
const filtered = allModels.filter(model => {
|
||||
const name = model.name?.toLowerCase() || '';
|
||||
const desc = model.description?.toLowerCase() || '';
|
||||
const type = model.type?.toLowerCase() || '';
|
||||
const kw = keyword.toLowerCase();
|
||||
return name.includes(kw) || desc.includes(kw) || type.includes(kw);
|
||||
});
|
||||
renderFilteredModels(filtered);
|
||||
}
|
||||
|
||||
// 渲染筛选后的模型列表
|
||||
function renderFilteredModels(models) {
|
||||
const container = document.getElementById('modelList');
|
||||
if (models.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div class="p-8 text-center text-gray-400">
|
||||
<i class="fa fa-search text-2xl mb-2"></i>
|
||||
<p>未找到匹配的模型</p>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = models.map(model => {
|
||||
const isSelected = selectedModels.has(model.id);
|
||||
const isDisabled = !isSelected && selectedModels.size >= 4;
|
||||
const typeText = {
|
||||
'LLM': '大语言模型',
|
||||
'CV': '计算机视觉',
|
||||
'NLP': '自然语言处理',
|
||||
'Embedding': '向量模型',
|
||||
'Other': '其他'
|
||||
}[model.type] || model.type || '其他';
|
||||
|
||||
return `
|
||||
<div class="model-card border-b border-gray-100 last:border-b-0 p-4 cursor-pointer ${isSelected ? 'selected bg-blue-50/50' : ''} ${isDisabled ? 'disabled opacity-50' : ''} hover:bg-gray-50 transition-colors"
|
||||
onclick="toggleModel(${model.id})">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center flex-1 min-w-0">
|
||||
<div class="w-5 h-5 rounded-full border-2 ${isSelected ? 'border-primary bg-primary' : 'border-gray-300'} flex items-center justify-center mr-3 flex-shrink-0">
|
||||
${isSelected ? '<i class="fa fa-check text-white text-xs"></i>' : ''}
|
||||
</div>
|
||||
<div class="min-w-0">
|
||||
<div class="flex items-center mb-1">
|
||||
<span class="font-medium text-gray-800 truncate">${model.name}</span>
|
||||
<span class="ml-2 px-2 py-0.5 bg-blue-100 text-blue-700 text-xs rounded flex-shrink-0">${typeText}</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-500 truncate">${model.description || '暂无描述'}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-4 text-xs text-gray-400 flex-shrink-0">
|
||||
${model.model_source === 'local' ? '本地模型' : '在线模型'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
// 更新已选数量
|
||||
function updateSelectedCount() {
|
||||
document.getElementById('selectedCount').textContent = selectedModels.size;
|
||||
@@ -392,15 +462,15 @@
|
||||
}
|
||||
|
||||
const data = {
|
||||
name: name,
|
||||
model_name: name,
|
||||
description: description,
|
||||
models: Array.from(selectedModels),
|
||||
status: 'pending',
|
||||
create_time: new Date().toISOString()
|
||||
create_time: new Date().toLocaleString('zh-CN', { hour12: false }).replace(/\//g, '-')
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/model-deploy`, {
|
||||
const response = await fetch(`${API_BASE}/model-compare`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data)
|
||||
@@ -436,6 +506,19 @@
|
||||
});
|
||||
}
|
||||
|
||||
// 绑定模型搜索框事件
|
||||
const modelSearchInput = document.getElementById('modelSearchInput');
|
||||
if (modelSearchInput) {
|
||||
modelSearchInput.addEventListener('input', (e) => {
|
||||
const keyword = e.target.value.trim();
|
||||
if (keyword) {
|
||||
filterModels(keyword);
|
||||
} else {
|
||||
renderModels();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 加载模型列表
|
||||
loadModels();
|
||||
});
|
||||
Reference in New Issue
Block a user