模型开始训练界面以及查看日志功能完善

This commit is contained in:
2026-01-29 10:36:59 +08:00
parent a560d24e2f
commit e9e0e21e47
11 changed files with 2485 additions and 179 deletions

View File

@@ -219,6 +219,9 @@
<button onclick="switchTab('evaluation')" id="tab-evaluation" class="tab-btn" style="display: inline-flex; align-items: center; justify-content: center;">
评测模型
</button>
<button onclick="switchTab('trained')" id="tab-trained" class="tab-btn" style="display: inline-flex; align-items: center; justify-content: center;">
已训练模型
</button>
</div>
</div>
@@ -235,7 +238,7 @@
</div>
<!-- 模型表格 -->
<div class="bg-white rounded-lg shadow-sm">
<div id="modelsTableContainer" class="bg-white rounded-lg shadow-sm">
<div class="overflow-x-auto">
<table class="w-full">
<thead class="bg-gray-50">
@@ -260,6 +263,33 @@
<p class="text-gray-500">暂无模型数据</p>
</div>
</div>
<!-- 已训练模型表格 -->
<div id="trainedModelsContainer" class="hidden bg-white rounded-lg shadow-sm">
<div class="p-4 border-b border-gray-200">
<p class="text-sm text-gray-500">已训练模型存储在 /app/base/saves 目录下</p>
</div>
<div class="overflow-x-auto">
<table class="w-full">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">基座模型</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">训练方法</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">模型路径</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">操作</th>
</tr>
</thead>
<tbody id="trainedModelsBody" class="bg-white divide-y divide-gray-200">
<!-- 动态加载 -->
</tbody>
</table>
</div>
<!-- 空状态 -->
<div id="trainedEmptyState" class="hidden px-6 py-12 text-center">
<i class="fa fa-inbox text-4xl text-gray-300 mb-3"></i>
<p class="text-gray-500">暂无已训练模型</p>
</div>
</div>
</div>
<script>
@@ -272,6 +302,7 @@
const API_BASE = getApiBase();
let allModels = [];
let trainedModels = [];
let currentTab = 'all';
// Tab 切换
@@ -284,7 +315,25 @@
const activeTab = document.getElementById(`tab-${tab}`);
activeTab.classList.add('tab-active');
renderModels();
// 显示/隐藏搜索框和添加按钮
const toolbar = document.querySelector('div[style*="justify-content: space-between"]');
if (toolbar) {
toolbar.style.display = tab === 'trained' ? 'none' : 'flex';
}
// 显示/隐藏表格容器
const modelsTable = document.getElementById('modelsTableContainer');
const trainedModelsContainer = document.getElementById('trainedModelsContainer');
if (tab === 'trained') {
modelsTable.classList.add('hidden');
trainedModelsContainer.classList.remove('hidden');
loadTrainedModels();
} else {
modelsTable.classList.remove('hidden');
trainedModelsContainer.classList.add('hidden');
renderModels();
}
}
// 加载模型数据
@@ -302,6 +351,23 @@
}
}
// 加载已训练模型数据
async function loadTrainedModels() {
try {
const response = await fetch(`${API_BASE}/model-manage/trained-models`);
const result = await response.json();
console.log('[DEBUG] 已训练模型:', result);
if (result.code === 0) {
trainedModels = result.data?.models || [];
renderTrainedModels();
}
} catch (error) {
console.error('加载已训练模型失败:', error);
}
}
// 筛选模型
function filterModels() {
renderModels();
@@ -396,6 +462,70 @@
}).join('');
}
// 渲染已训练模型列表
function renderTrainedModels() {
const tbody = document.getElementById('trainedModelsBody');
const emptyState = document.getElementById('trainedEmptyState');
// 收集所有训练方法
let allTrainMethods = [];
trainedModels.forEach(model => {
if (model.train_methods && model.train_methods.length > 0) {
model.train_methods.forEach(method => {
allTrainMethods.push({
baseModel: model.name,
trainMethod: method.name,
path: method.path
});
});
}
});
if (allTrainMethods.length === 0) {
tbody.innerHTML = '';
emptyState.classList.remove('hidden');
return;
}
emptyState.classList.add('hidden');
tbody.innerHTML = allTrainMethods.map(item => {
// 训练方法显示
const methodMap = {
'lora': 'LoRA',
'qlora': 'QLoRA',
'full': '全量微调',
'prefix': 'Prefix Tuning',
'adapter': 'Adapter'
};
const methodDisplay = methodMap[item.trainMethod] || item.trainMethod;
return `
<tr class="hover:bg-gray-50">
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm font-medium text-gray-900">${item.baseModel}</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 py-1 text-xs font-medium rounded bg-green-100 text-green-700">${methodDisplay}</span>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm text-gray-500 max-w-xs truncate" title="${item.path}">${item.path}</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
<button onclick="viewTrainedModel('${item.path.replace(/\\/g, '\\\\')}')" class="text-primary hover:text-primary/80 mr-3">
<i class="fa fa-folder-open"></i> 查看
</button>
</td>
</tr>
`;
}).join('');
}
// 查看已训练模型
function viewTrainedModel(path) {
alert(`模型路径: ${path}\n\n您可以从此路径加载模型进行推理或评测。`);
}
// 编辑模型
function editModel(id) {
window.location.href = `model-manage-create.html?id=${id}`;