1. 增加了合并权重

2. 修改了一些列表展示的bug
This commit is contained in:
2026-01-29 23:10:21 +08:00
parent 0f98d67e41
commit 85710d865c
4 changed files with 672 additions and 433 deletions

View File

@@ -608,7 +608,7 @@
'edit': '编辑',
'compare': '开始对话',
'chat': '对话',
'view': '去推理'
'view': '合并权重'
};
// 训练进度缓存
@@ -1108,11 +1108,11 @@
function toggleSelectAll(checkbox, api) {
// 使用保存的当前页面数据
if (checkbox.checked) {
// 全选当前页面的所有数据
currentPageData.forEach(item => selectedItems.add(item.id));
// 全选当前页面的所有数据(支持 name 或 id
currentPageData.forEach(item => selectedItems.add(item.name || item.id));
} else {
// 取消全选,移除当前页面所有数据的选中状态
currentPageData.forEach(item => selectedItems.delete(item.id));
currentPageData.forEach(item => selectedItems.delete(item.name || item.id));
}
refreshCurrentPage();
}
@@ -1266,14 +1266,16 @@
// 渲染表格页面
function renderTablePage(config, data) {
const createButton = config.hasCreate ? `
<button onclick="showCreateModal('${config.api}')" class="bg-primary text-white px-3 py-1.5 rounded text-sm hover:bg-primary/90 transition-colors">
<i class="fa fa-plus mr-1"></i>${config.createText}
</button>
` : '';
// 定义表格列
const columns = [
{ title: '模型名称', key: 'name' },
{ title: '训练方法', key: 'train_methods', render: (val) => val && val[0] ? val[0].name : '-' },
{ title: '基座模型', key: 'base_model_path', render: (val) => `<span class="text-xs text-gray-500 truncate block" title="${val}">${val || '-'}</span>` },
{ title: '创建时间', key: 'create_time', render: (val) => val ? new Date(val).toLocaleString('zh-CN') : '-' }
];
// 搜索框(模型管理和数据集管理)
const searchBox = (config.api === 'model-manage' || config.api === 'dataset-manage') ? `
// 搜索框
const searchBox = (config.api === 'model-manage' || config.api === 'model-manage/trained-models' || config.api === 'dataset-manage') ? `
<div class="relative">
<input type="text" id="tableSearchInput" placeholder="搜索${config.title}..."
class="w-72 pl-9 pr-3 py-1.5 rounded border border-gray-300 text-sm focus:outline-none focus:border-primary focus:ring-1 focus:border-primary"
@@ -1283,7 +1285,14 @@
` : '';
// 是否支持多选(模型管理和数据集管理)
const supportsMultiSelect = config.api === 'model-manage' || config.api === 'dataset-manage';
const supportsMultiSelect = config.api === 'model-manage' || config.api === 'model-manage/trained-models' || config.api === 'dataset-manage';
// 创建按钮根据API类型决定是否显示
const createButton = config.api === 'dataset-manage' ? `
<button onclick="showCreateModal('${config.api}')" class="bg-primary text-white px-3 py-1.5 rounded text-sm hover:bg-primary/90 transition-colors">
<i class="fa fa-plus mr-1"></i>创建数据集
</button>
` : '';
// 批量删除按钮(仅当有选中项时显示)
const batchDeleteButton = supportsMultiSelect && selectedItems.size > 0 ? `
@@ -1292,7 +1301,6 @@
</button>
` : '';
const columns = config.columns;
const hasData = data && data.length > 0;
// 多选列头
@@ -1334,12 +1342,12 @@
</thead>
<tbody>
${hasData ? data.map(item => `
<tr class="border-b border-gray-100 table-row-hover ${selectedItems.has(item.id) ? 'bg-blue-50' : ''}">
<tr class="border-b border-gray-100 table-row-hover ${selectedItems.has(item.name || item.id) ? 'bg-blue-50' : ''}">
${supportsMultiSelect ? `
<td class="px-4 py-4 text-sm text-center">
<input type="checkbox" class="w-4 h-4 text-primary rounded border-gray-300 cursor-pointer"
${selectedItems.has(item.id) ? 'checked' : ''}
onchange="toggleItemSelection(${item.id}, '${config.api}')">
${selectedItems.has(item.name || item.id) ? 'checked' : ''}
onchange="toggleItemSelection('${item.name || item.id}', '${config.api}')">
</td>
` : ''}
${columns.map(col => `
@@ -1349,33 +1357,15 @@
`).join('')}
<td class="px-4 py-4 text-sm text-center">
<div class="flex justify-center space-x-2">
${config.actions.map(action => {
${['view', 'delete'].map(action => {
let onclick = '';
let btnClass = 'text-primary hover:text-primary/80';
// 对于 fine-tune 的停止按钮,检查状态
if (action === 'stop' && config.api === 'fine-tune') {
// 状态为 completed 或 failed 时隐藏停止按钮
if (item.status === 'completed' || item.status === 'failed') {
return '';
}
onclick = `stopItem(${item.id})`;
btnClass = 'text-orange-500 hover:text-orange-600';
if (action === 'view') {
onclick = `viewTrainedModel('${item.name}', '${item.train_methods?.[0]?.name || 'lora'}', '${item.base_model_path || ''}')`;
} else if (action === 'delete') {
onclick = `deleteItem('${config.api}', ${item.id})`;
onclick = `deleteItem('${config.api}', '${item.id}')`;
btnClass = 'text-danger hover:text-danger/80';
} else if (action === 'edit') {
onclick = `editItem('${config.api}', ${item.id})`;
} else if (action === 'preview' && config.api === 'dataset-manage') {
onclick = `window.location.href = 'dataset-preview.html?id=${item.id}'`;
} else if (action === 'download' && config.api === 'dataset-manage') {
onclick = `downloadDataset('${item.id}')`;
} else if (action === 'compare' && config.api === 'model-compare') {
onclick = `startCompare(${item.id})`;
} else if (action === 'logs' && config.api === 'fine-tune') {
onclick = `navigateToTrainingLog(${item.id})`;
} else if (action === 'view' && config.api === 'model-manage/trained-models') {
onclick = `viewTrainedModel('${item.name}', '${item.train_methods?.[0]?.name || '-'}', '${item.path || ''}')`;
} else {
onclick = `showMessage('提示', '${actionLabels[action] || action}功能开发中...', 'info')`;
}
@@ -3164,10 +3154,55 @@
document.body.style.overflow = '';
}
// 查看已训练模型详情 - 跳转到推理页面
window.viewTrainedModel = function(name, method, path) {
// 跳转到推理测试页面main.html在pages目录下所以直接用文件名
window.location.href = `model-inference.html?model=${encodeURIComponent(name)}&method=${encodeURIComponent(method)}`;
// 刷新表格数据 - 重新加载当前页面(必须在 viewTrainedModel 之前定义)
window.loadTableData = function() {
const activeLink = document.querySelector('.nav-link.sidebar-item-active');
if (activeLink) {
loadPage(activeLink.dataset.page);
}
};
// 合并模型权重
window.viewTrainedModel = async function(name, method, path) {
// 显示加载中弹窗
const loadingModal = document.getElementById('loadingModal');
if (loadingModal) {
document.getElementById('loadingMessage').textContent = '正在合并模型权重,请稍候...';
loadingModal.classList.remove('hidden');
}
try {
const response = await fetch(`${API_BASE}/model-manage/merge`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
model_name: name,
train_method: method || 'lora',
base_model_path: path
})
});
const result = await response.json();
// 隐藏加载弹窗
if (loadingModal) {
loadingModal.classList.add('hidden');
}
if (result.code === 0) {
showMessage('成功', '模型权重合并成功!', 'success');
// 刷新模型列表
loadTableData();
} else {
showMessage('失败', result.message || '合并失败', 'error');
}
} catch (error) {
console.error('[DEBUG] 合并失败:', error);
if (loadingModal) {
loadingModal.classList.add('hidden');
}
showMessage('错误', '合并失败: ' + error.message, 'error');
}
};
// 确认弹窗(两个按钮)- 使用 window 确保全局可访问
@@ -3446,5 +3481,15 @@
</div>
</div>
</div>
<!-- 加载中弹窗 -->
<div id="loadingModal" class="hidden fixed inset-0 bg-black/50 z-50 flex items-center justify-center">
<div class="bg-white rounded-xl shadow-xl max-w-sm w-full mx-4 overflow-hidden transform transition-all">
<div class="flex flex-col items-center justify-center min-h-[160px] py-6">
<i class="fa fa-spinner fa-spin text-3xl text-primary mb-4"></i>
<p id="loadingMessage" class="text-gray-600 text-sm">正在处理...</p>
</div>
</div>
</div>
</body>
</html>