598 lines
24 KiB
JavaScript
598 lines
24 KiB
JavaScript
/**
|
||
* 主入口模块
|
||
* 页面初始化和导航控制
|
||
*/
|
||
|
||
// 各功能模块的表格配置
|
||
window.tableConfigs = {
|
||
'fine-tune': {
|
||
title: '模型调优',
|
||
api: 'fine-tune',
|
||
hasCreate: true,
|
||
createText: '创建训练任务',
|
||
columns: [
|
||
{ title: '任务名称', key: 'name' },
|
||
{ title: '任务状态', key: 'status', render: (val) => `<span class="px-2 py-1 rounded text-xs ${val === 'running' ? 'bg-green-100 text-green-700' : val === 'failed' ? 'bg-red-100 text-red-700' : 'bg-gray-100 text-gray-700'}">${val}</span>` },
|
||
{ title: '训练方式', key: 'train_type', render: (val) => val === 'SFT' ? 'SFT 微调训练' : (val === 'DPO' ? 'DPO 偏好训练' : (val === 'CPT' ? 'CPT 继续预训练' : '-')) },
|
||
{ title: '训练模板', key: 'template', render: (val) => val || '-' },
|
||
{ title: '基座模型', key: 'base_model', render: (val, row) => `<span class="model-name-cell" data-model-id="${val}">加载中...</span>` }
|
||
],
|
||
actions: ['stop', 'logs', 'delete']
|
||
},
|
||
'my-models': {
|
||
title: '我的模型',
|
||
api: 'model-manage/trained-models',
|
||
dataPath: 'models',
|
||
hasCreate: false,
|
||
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') : '-' }
|
||
],
|
||
actions: ['view', 'delete']
|
||
},
|
||
'model-eval': {
|
||
title: '模型评测',
|
||
isExternalPage: true,
|
||
createConfig: {
|
||
page: 'model-eval-create',
|
||
hasCreate: true,
|
||
createText: '新建评测'
|
||
}
|
||
},
|
||
'model-compare': {
|
||
title: '模型对比',
|
||
api: 'model-compare',
|
||
hasCreate: true,
|
||
createText: '新建对比',
|
||
columns: [
|
||
{ title: '对比名称', key: 'model_name' },
|
||
{ title: '描述', key: 'description', render: (val) => val || '-' },
|
||
{ title: '相关模型', key: 'models', render: (val) => {
|
||
if (!val) return '-';
|
||
try {
|
||
// 如果是字符串,尝试解析 JSON
|
||
let models = val;
|
||
if (typeof val === 'string') {
|
||
try {
|
||
models = JSON.parse(val);
|
||
} catch {
|
||
models = val.split(',').map(id => ({ model_name: id.trim() }));
|
||
}
|
||
}
|
||
// 如果是数组,提取模型名称
|
||
if (Array.isArray(models) && models.length > 0) {
|
||
return models.map(function(m) {
|
||
if (typeof m === 'object' && m !== null) {
|
||
return m.model_name || m.name || '未知模型';
|
||
}
|
||
return String(m);
|
||
}).join(', ');
|
||
}
|
||
// 如果是单个对象
|
||
if (typeof models === 'object' && models !== null) {
|
||
return models.model_name || models.name || '未知模型';
|
||
}
|
||
return String(models);
|
||
} catch (e) {
|
||
return '解析错误';
|
||
}
|
||
}},
|
||
{ title: '创建时间', key: 'create_time', render: (val) => val ? new Date(val).toLocaleString('zh-CN') : '-' }
|
||
],
|
||
actions: ['compare', 'delete']
|
||
},
|
||
'dataset-manage': {
|
||
title: '数据集管理',
|
||
api: 'dataset-manage',
|
||
hasCreate: true,
|
||
createText: '上传数据集',
|
||
columns: [
|
||
{ title: '数据集名称', key: 'name' },
|
||
{ title: '数据类型', key: 'type', render: (val) => {
|
||
const textMap = {
|
||
'train': '训练数据',
|
||
'test': '测试数据',
|
||
'eval': '评测数据',
|
||
'val': '验证数据',
|
||
'other': '其他'
|
||
};
|
||
const displayText = textMap[val?.toLowerCase()] || val || '-';
|
||
return '<span class="px-2 py-1 rounded text-xs bg-blue-100 text-blue-700">' + displayText + '</span>';
|
||
}},
|
||
{ title: '存储位置', key: 'storage_type', render: (val) => {
|
||
const textMap = {
|
||
'local': '本地存储',
|
||
'minio': 'MinIO',
|
||
'cloud': '云存储'
|
||
};
|
||
const displayText = textMap[val] || val || '-';
|
||
return '<span class="px-2 py-1 rounded text-xs bg-green-100 text-green-700">' + displayText + '</span>';
|
||
}},
|
||
{ title: '大小', key: 'size', render: (val) => (val && val !== '0 B' && val !== '0') ? val : '-' },
|
||
{ title: '数据条数', key: 'count', render: (val) => val || 0 },
|
||
{ title: '描述', key: 'description', render: (val) => val || '-' },
|
||
{ title: '创建时间', key: 'create_time', render: (val) => val ? new Date(val).toLocaleString('zh-CN') : '-' }
|
||
],
|
||
actions: ['preview', 'download', 'delete']
|
||
},
|
||
'data-generate': {
|
||
title: '其他工具',
|
||
isTools: true,
|
||
defaultTools: [
|
||
{ id: 'data-generate', name: '数据生成', icon: 'fa-database', description: '基于LLM生成微调数据集' },
|
||
{ id: 'json2jsonl', name: 'JSON转JSONL', icon: 'fa-code', description: '将JSON文件转换为JSONL格式' },
|
||
{ id: 'md-convert', name: '转换Markdown', icon: 'fa-file-text', description: '将Markdown文件转换为训练数据' }
|
||
],
|
||
customTools: []
|
||
},
|
||
'model-manage': {
|
||
title: '模型管理',
|
||
api: 'model-manage',
|
||
hasCreate: true,
|
||
hasModelTabs: true,
|
||
createText: '添加模型',
|
||
columns: [
|
||
{ title: '模型名称', key: 'name' },
|
||
{ title: '模型类型', key: 'type', render: (val) => {
|
||
const textMap = {
|
||
'LLM': '大语言模型',
|
||
'CV': '计算机视觉',
|
||
'NLP': '自然语言处理',
|
||
'Embedding': '向量模型',
|
||
'Other': '其他'
|
||
};
|
||
const displayText = textMap[val] || val || '-';
|
||
return '<span class="px-2 py-1 rounded text-xs bg-blue-100 text-blue-700">' + displayText + '</span>';
|
||
}},
|
||
{ title: '用途', key: 'purpose', render: (val) => {
|
||
const purposeMap = {
|
||
'training': { text: '训练', class: 'bg-blue-100 text-blue-700' },
|
||
'inference': { text: '推理', class: 'bg-green-100 text-green-700' },
|
||
'evaluation': { text: '评测', class: 'bg-purple-100 text-purple-700' }
|
||
};
|
||
const display = purposeMap[val] || { text: val || '-', class: 'bg-gray-100 text-gray-700' };
|
||
return '<span class="px-2 py-1 rounded text-xs ' + display.class + '">' + display.text + '</span>';
|
||
}},
|
||
{ title: '模型来源', key: 'model_source', render: (val) => {
|
||
const textMap = {
|
||
'local': '本地模型',
|
||
'api': '在线模型',
|
||
'online': '在线模型'
|
||
};
|
||
const displayText = textMap[val] || val || '-';
|
||
return '<span class="px-2 py-1 rounded text-xs bg-gray-100 text-gray-700">' + displayText + '</span>';
|
||
}},
|
||
{ title: '描述', key: 'description', render: (val) => val || '-' },
|
||
{ title: '创建时间', key: 'create_time', render: (val) => val ? new Date(val).toLocaleString('zh-CN') : '-' }
|
||
],
|
||
actions: ['edit', 'delete']
|
||
},
|
||
'config': {
|
||
title: '平台性能',
|
||
skipFetch: true,
|
||
hasCreate: false,
|
||
isHardwareMonitor: true
|
||
},
|
||
'logs': {
|
||
title: '查看日志',
|
||
skipFetch: true,
|
||
hasCreate: false,
|
||
isLogViewer: true
|
||
},
|
||
'model-compare-chat': {
|
||
title: '模型对比',
|
||
skipFetch: true,
|
||
hasCreate: false,
|
||
isExternalPage: true
|
||
},
|
||
'model-compare-result': {
|
||
title: '对比结果',
|
||
skipFetch: true,
|
||
hasCreate: false,
|
||
isExternalPage: true
|
||
},
|
||
'training-log': {
|
||
title: '训练日志',
|
||
skipFetch: true,
|
||
hasCreate: false,
|
||
isExternalPage: true
|
||
}
|
||
};
|
||
|
||
// 操作按钮映射
|
||
window.actionLabels = {
|
||
'stop': '停止',
|
||
'logs': '查看日志',
|
||
'delete': '删除',
|
||
'deploy': '部署',
|
||
'eval': '评测',
|
||
'report': '查看报告',
|
||
'scale': '扩容',
|
||
'preview': '预览',
|
||
'download': '下载',
|
||
'detail': '详情',
|
||
'edit': '编辑',
|
||
'compare': '开始对话',
|
||
'chat': '对话',
|
||
'view': '合并权重'
|
||
};
|
||
|
||
// 加载模型列表缓存
|
||
async function loadModelListCache() {
|
||
try {
|
||
const response = await fetch(`${window.API_BASE}/model-manage`);
|
||
const result = await response.json();
|
||
if (result.code === 0) {
|
||
window.modelListCache = result.data || [];
|
||
}
|
||
} catch (e) {
|
||
console.error('加载模型列表失败:', e);
|
||
window.modelListCache = [];
|
||
}
|
||
}
|
||
|
||
// 根据模型ID获取模型名称(同步版本)
|
||
function getModelName(modelId) {
|
||
if (!modelId) return '-';
|
||
const model = window.modelListCache.find(m =>
|
||
m.id == modelId ||
|
||
m.id === String(modelId) ||
|
||
m.id === Number(modelId)
|
||
);
|
||
if (model) {
|
||
return model.name;
|
||
}
|
||
return `模型${modelId}`;
|
||
}
|
||
|
||
// 异步获取模型名称并更新 DOM
|
||
async function fetchAndUpdateModelName(modelId, cellElement) {
|
||
if (!modelId) {
|
||
cellElement.textContent = '-';
|
||
return;
|
||
}
|
||
|
||
let model = window.modelListCache.find(m =>
|
||
m.id == modelId ||
|
||
m.id === String(modelId) ||
|
||
m.id === Number(modelId)
|
||
);
|
||
|
||
if (!model) {
|
||
try {
|
||
const response = await fetch(`${window.API_BASE}/model-manage`);
|
||
const result = await response.json();
|
||
if (result.code === 0) {
|
||
window.modelListCache = result.data || [];
|
||
model = window.modelListCache.find(m =>
|
||
m.id == modelId ||
|
||
m.id === String(modelId) ||
|
||
m.id === Number(modelId)
|
||
);
|
||
}
|
||
} catch (e) {
|
||
console.error('获取模型列表失败:', e);
|
||
}
|
||
}
|
||
|
||
if (model) {
|
||
cellElement.textContent = model.name;
|
||
} else {
|
||
cellElement.textContent = `模型${modelId}`;
|
||
}
|
||
}
|
||
|
||
// 根据模型ID列表获取模型名称列表
|
||
function getModelNames(modelIds) {
|
||
if (!modelIds || !Array.isArray(modelIds)) return '-';
|
||
return modelIds.map(id => getModelName(id)).join(', ');
|
||
}
|
||
|
||
// 显示创建表单页面
|
||
window.showCreateModal = function(apiType) {
|
||
if (apiType === 'fine-tune') {
|
||
window.location.href = 'fine-tune-create.html';
|
||
} else if (apiType === 'model-manage') {
|
||
window.location.href = 'model-manage-create.html';
|
||
} else if (apiType === 'model-eval') {
|
||
window.location.href = 'model-eval-create.html';
|
||
} else if (apiType === 'dataset-manage') {
|
||
window.location.href = 'dataset-create.html';
|
||
} else if (apiType === 'model-compare') {
|
||
window.location.href = 'model-compare-create.html';
|
||
} else {
|
||
window.showMessage('提示', '该功能开发中...', 'info');
|
||
}
|
||
};
|
||
|
||
// 返回列表页
|
||
window.goBack = function() {
|
||
if (window.currentParentPage) {
|
||
window.currentPage = window.currentParentPage;
|
||
window.currentParentPage = null;
|
||
loadPage(window.currentPage);
|
||
} else {
|
||
loadPage('fine-tune');
|
||
}
|
||
};
|
||
|
||
// 跳转到页面
|
||
window.navigateToPage = function(pageName) {
|
||
if (pageName.endsWith('-create')) {
|
||
window.location.href = `${pageName}.html`;
|
||
} else {
|
||
window.location.href = `main.html?page=${pageName}`;
|
||
}
|
||
};
|
||
|
||
// 返回到列表页
|
||
window.goBackToList = function() {
|
||
navigateToPage('fine-tune');
|
||
};
|
||
|
||
// 加载页面内容
|
||
async function loadPage(pageName) {
|
||
// 切换页面时清除选中状态
|
||
TableComponent.clearSelection();
|
||
|
||
// 离开日志页面时停止自动刷新
|
||
SystemService.stopLogAutoRefresh();
|
||
|
||
// 离开模型调优页面时停止进度刷新
|
||
if (window.currentPage === 'fine-tune' && pageName !== 'fine-tune') {
|
||
TrainingService.stopProgressRefresh();
|
||
}
|
||
|
||
const container = document.getElementById('page-content');
|
||
const config = window.tableConfigs[pageName];
|
||
|
||
if (!config) return;
|
||
|
||
// 更新当前页面
|
||
window.currentPage = pageName;
|
||
|
||
// 显示加载中
|
||
container.innerHTML = `
|
||
<div class="bg-white rounded-lg shadow-sm mb-6 p-8 text-center">
|
||
<i class="fa fa-spinner fa-spin text-3xl text-primary"></i>
|
||
<p class="mt-2 text-gray-500">加载中...</p>
|
||
</div>
|
||
`;
|
||
|
||
// 显示/隐藏返回按钮
|
||
const backBtn = document.getElementById('pageBackBtn');
|
||
if (config.isExternalPage) {
|
||
backBtn.classList.remove('hidden');
|
||
} else {
|
||
backBtn.classList.add('hidden');
|
||
}
|
||
|
||
try {
|
||
if (config.isExternalPage) {
|
||
// 外部页面
|
||
const response = await fetch(`${pageName}.html?t=${Date.now()}`);
|
||
if (response.ok) {
|
||
const html = await response.text();
|
||
const scriptRegex = /<script\b(?![^>]*\bsrc)[^>]*>([\s\S]*?)<\/script>/g;
|
||
const scriptContents = [];
|
||
let match;
|
||
while ((match = scriptRegex.exec(html)) !== null) {
|
||
scriptContents.push(match[1]);
|
||
}
|
||
const scriptContent = scriptContents.join('\n');
|
||
const htmlWithoutScript = html.replace(/<script\b[^>]*>[\s\S]*?<\/script>/g, '');
|
||
|
||
let headerHtml = '';
|
||
if (config.createConfig && config.createConfig.hasCreate) {
|
||
headerHtml = `
|
||
<div class="bg-white rounded-lg shadow-sm mb-6 p-4 border-b border-gray-100 flex items-center justify-between">
|
||
<div class="flex items-center space-x-8">
|
||
<button class="tab-btn active pb-3 text-sm font-medium flex items-center text-primary" data-tab="tasks" onclick="switchTab(this, 'tasks')">
|
||
<i class="fa fa-tasks mr-2"></i>评测任务
|
||
</button>
|
||
<button class="tab-btn pb-3 text-sm font-medium flex items-center text-gray-500" data-tab="leaderboard" onclick="switchTab(this, 'leaderboard')">
|
||
<i class="fa fa-trophy mr-2"></i>排行榜
|
||
</button>
|
||
<button class="tab-btn pb-3 text-sm font-medium flex items-center text-gray-500" data-tab="dimensions" onclick="switchTab(this, 'dimensions')">
|
||
<i class="fa fa-sliders mr-2"></i>评测维度
|
||
</button>
|
||
</div>
|
||
<div id="headerActionButtons" style="min-height: 36px;">
|
||
<button onclick="navigateToPage('${config.createConfig.page}')" class="bg-primary text-white px-4 py-2 rounded-lg text-sm hover:bg-primary/90 transition-colors flex items-center">
|
||
<i class="fa fa-plus mr-2"></i>${config.createConfig.createText}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<style>
|
||
.tab-btn { position: relative; transition: all 0.2s; }
|
||
.tab-btn.active { color: #1890ff; }
|
||
.tab-btn.active::after { content: ''; position: absolute; bottom: -16px; left: 0; right: 0; height: 2px; background-color: #1890ff; }
|
||
.tab-btn:hover:not(.active) { color: #1890ff; }
|
||
</style>
|
||
`;
|
||
}
|
||
|
||
container.innerHTML = headerHtml + htmlWithoutScript;
|
||
|
||
if (scriptContent && scriptContent.trim()) {
|
||
try {
|
||
const oldScript = document.getElementById('externalPageScript');
|
||
if (oldScript) oldScript.remove();
|
||
const scriptEl = document.createElement('script');
|
||
scriptEl.id = 'externalPageScript';
|
||
scriptEl.textContent = scriptContent;
|
||
document.body.appendChild(scriptEl);
|
||
} catch (e) {
|
||
console.error('执行脚本失败:', e);
|
||
}
|
||
}
|
||
} else {
|
||
throw new Error('页面加载失败');
|
||
}
|
||
} else if (config.isHardwareMonitor) {
|
||
container.innerHTML = PageRenderer.renderConfigPage(config, null);
|
||
PageRenderer.initGPUList();
|
||
PageRenderer.startRefreshTimer();
|
||
} else if (config.isLogViewer) {
|
||
container.innerHTML = PageRenderer.renderLogViewerPage(config);
|
||
SystemService.initLogViewer();
|
||
} else if (config.isForm) {
|
||
const data = await TableComponent.fetchData(`${window.API_BASE}/${config.api}`);
|
||
container.innerHTML = PageRenderer.renderConfigPage(config, data);
|
||
} else if (config.isTools) {
|
||
container.innerHTML = PageRenderer.renderToolsPage(config);
|
||
} else {
|
||
// 模型管理页面根据tab选择不同的API
|
||
let apiUrl = `${window.API_BASE}/${config.api}`;
|
||
if (config.hasModelTabs) {
|
||
if (window.currentModelTab === 'trained') {
|
||
apiUrl = `${window.API_BASE}/model-manage/trained-models`;
|
||
}
|
||
}
|
||
let data = await TableComponent.fetchData(apiUrl);
|
||
let dataPath = config.dataPath || null;
|
||
if (config.hasModelTabs && window.currentModelTab === 'trained') {
|
||
dataPath = 'models';
|
||
}
|
||
if (dataPath && typeof data === 'object' && data !== null) {
|
||
data = data[dataPath] || [];
|
||
}
|
||
window.currentPageData = data;
|
||
container.innerHTML = TableComponent.renderTablePage(config, data);
|
||
|
||
setTimeout(() => {
|
||
const modelCells = container.querySelectorAll('.model-name-cell');
|
||
modelCells.forEach(cell => {
|
||
const modelId = cell.getAttribute('data-model-id');
|
||
if (modelId) {
|
||
fetchAndUpdateModelName(modelId, cell);
|
||
}
|
||
});
|
||
}, 0);
|
||
}
|
||
} catch (error) {
|
||
console.error('加载数据失败:', error);
|
||
container.innerHTML = `
|
||
<div class="bg-white rounded-lg shadow-sm mb-6 p-8 text-center">
|
||
<i class="fa fa-exclamation-circle text-3xl text-danger"></i>
|
||
<p class="mt-2 text-gray-500">加载数据失败,请检查后端服务是否启动</p>
|
||
<p class="text-sm text-gray-400 mt-1">${error.message}</p>
|
||
</div>
|
||
`;
|
||
}
|
||
}
|
||
|
||
// 添加评测维度
|
||
window.addDimension = function() {
|
||
window.location.href = 'model-dimension-create.html';
|
||
};
|
||
|
||
// 删除评测维度
|
||
window.deleteDimension = async function(id) {
|
||
window.showConfirm('确认删除', '确定要删除此评测维度吗?', async () => {
|
||
try {
|
||
const response = await fetch(`${window.API_BASE}/dimension/${id}`, {
|
||
method: 'DELETE'
|
||
});
|
||
const result = await response.json();
|
||
if (result.code === 0) {
|
||
window.showMessage('成功', '删除成功', 'success', () => {
|
||
switchTab(document.querySelector('[data-tab="dimensions"]'), 'dimensions');
|
||
});
|
||
} else {
|
||
window.showMessage('错误', result.message || '删除失败', 'error');
|
||
}
|
||
} catch (error) {
|
||
console.error('删除维度失败:', error);
|
||
window.showMessage('错误', '删除失败: ' + error.message, 'error');
|
||
}
|
||
});
|
||
};
|
||
|
||
// 切换 Tab
|
||
window.switchTab = function(btn, tabId) {
|
||
const parent = btn.parentElement;
|
||
parent.querySelectorAll('.tab-btn').forEach(b => {
|
||
b.classList.remove('active', 'text-primary');
|
||
b.classList.add('text-gray-500');
|
||
});
|
||
btn.classList.add('active');
|
||
btn.classList.remove('text-gray-500');
|
||
|
||
if (typeof window.switchTabContent === 'function') {
|
||
window.switchTabContent(tabId);
|
||
}
|
||
|
||
const btnContainer = document.getElementById('headerActionButtons');
|
||
const currentConfig = window.tableConfigs[window.currentPage];
|
||
if (btnContainer) {
|
||
if (tabId === 'tasks') {
|
||
const page = currentConfig?.createConfig?.page || 'model-eval-create';
|
||
const text = currentConfig?.createConfig?.createText || '新建评测';
|
||
btnContainer.innerHTML = `
|
||
<button onclick="navigateToPage('${page}')" class="bg-primary text-white px-4 py-2 rounded-lg text-sm hover:bg-primary/90 transition-colors flex items-center">
|
||
<i class="fa fa-plus mr-2"></i>${text}
|
||
</button>
|
||
`;
|
||
} else if (tabId === 'leaderboard') {
|
||
btnContainer.innerHTML = '<span class="invisible px-4 py-2 rounded-lg">占位</span>';
|
||
} else if (tabId === 'dimensions') {
|
||
btnContainer.innerHTML = `
|
||
<button onclick="addDimension()" class="bg-primary text-white px-4 py-2 rounded-lg text-sm hover:bg-primary/90 transition-colors flex items-center">
|
||
<i class="fa fa-plus mr-2"></i>添加维度
|
||
</button>
|
||
`;
|
||
}
|
||
}
|
||
};
|
||
|
||
// ============ 初始化 ============
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// 从 localStorage 加载自定义工具
|
||
const savedCustomTools = localStorage.getItem('customTools');
|
||
if (savedCustomTools) {
|
||
window.tableConfigs['data-generate'].customTools = JSON.parse(savedCustomTools);
|
||
}
|
||
|
||
// 加载模型列表缓存
|
||
loadModelListCache();
|
||
|
||
// 检查URL参数
|
||
const urlParams = new URLSearchParams(window.location.search);
|
||
const pageParam = urlParams.get('page');
|
||
|
||
let defaultPage = 'fine-tune';
|
||
|
||
if (pageParam) {
|
||
defaultPage = pageParam;
|
||
} else {
|
||
const sessionPage = sessionStorage.getItem('lastPage');
|
||
const localPage = localStorage.getItem('lastPage');
|
||
const savedPage = sessionPage || localPage;
|
||
|
||
if (savedPage && window.tableConfigs[savedPage]) {
|
||
defaultPage = savedPage;
|
||
}
|
||
}
|
||
|
||
sessionStorage.setItem('lastPage', defaultPage);
|
||
|
||
// 加载页面
|
||
loadPage(defaultPage);
|
||
|
||
// 启动系统监控定时器
|
||
SystemService.fetchSystemMetrics();
|
||
setInterval(SystemService.fetchSystemMetrics, 30000);
|
||
|
||
// 启动训练进度自动刷新
|
||
TrainingService.startProgressRefresh();
|
||
|
||
// 初始化日志
|
||
const path = window.location.pathname;
|
||
const pageName = path.split('/').pop().replace('.html', '') || 'main';
|
||
webLogger.init(pageName);
|
||
webLogger.info('页面加载完成');
|
||
});
|