// 标签切换功能 function openTab(evt, tabName) { var i, tabContent, tabLinks; tabContent = document.getElementsByClassName("tab-content"); for (i = 0; i < tabContent.length; i++) { tabContent[i].classList.add("hidden"); } tabLinks = document.getElementsByClassName("tab"); for (i = 0; i < tabLinks.length; i++) { tabLinks[i].classList.remove("active"); } document.getElementById(tabName).classList.remove("hidden"); evt.currentTarget.classList.add("active"); // 如果切换到进程页面,刷新进程列表 if (tabName === 'processes') { loadProcesses(); } else if (tabName === 'logfiles') { loadLogFiles(); } } // 根据训练类型显示/隐藏特定参数 document.getElementById('train_type').addEventListener('change', function() { const trainType = this.value; const pretrainSftFields = document.querySelectorAll('.pretrain-sft'); const loraFields = document.querySelectorAll('.lora'); pretrainSftFields.forEach(field => { field.style.display = (trainType === 'pretrain' || trainType === 'sft') ? 'block' : 'none'; }); loraFields.forEach(field => { field.style.display = trainType === 'lora' ? 'block' : 'none'; }); // 设置默认值 if (trainType === 'pretrain') { document.getElementById('save_dir').value = '../out'; document.getElementById('save_weight').value = 'pretrain'; document.getElementById('epochs').value = '1'; document.getElementById('batch_size').value = '32'; document.getElementById('learning_rate').value = '5e-4'; document.getElementById('data_path').value = '../dataset/pretrain_hq.jsonl'; document.getElementById('from_weight').value = 'none'; document.getElementById('log_interval').value = '100'; document.getElementById('save_interval').value = '100'; } else if (trainType === 'sft') { document.getElementById('save_dir').value = '../out'; document.getElementById('save_weight').value = 'full_sft'; document.getElementById('epochs').value = '2'; document.getElementById('batch_size').value = '16'; document.getElementById('learning_rate').value = '5e-7'; document.getElementById('data_path').value = '../dataset/sft_mini_512.jsonl'; document.getElementById('from_weight').value = 'pretrain'; document.getElementById('log_interval').value = '100'; document.getElementById('save_interval').value = '100'; } else if (trainType === 'lora') { document.getElementById('save_dir').value = '../out/lora'; document.getElementById('lora_name').value = 'lora_identity'; document.getElementById('epochs').value = '50'; document.getElementById('batch_size').value = '32'; document.getElementById('learning_rate').value = '1e-4'; document.getElementById('data_path').value = '../dataset/lora_identity.jsonl'; document.getElementById('from_weight').value = 'full_sft'; document.getElementById('log_interval').value = '10'; document.getElementById('save_interval').value = '1'; } }); // 初始触发一次change事件以设置默认值 document.getElementById('train_type').dispatchEvent(new Event('change')); // 加载进程列表 function loadProcesses() { fetch('/processes') .then(response => response.json()) .then(data => { const processList = document.getElementById('process-list'); processList.innerHTML = ''; if (data.length === 0) { processList.innerHTML = '
暂无训练进程
'; return; } data.forEach(process => { const processItem = document.createElement('div'); processItem.className = 'process-item'; let statusClass = ''; // 根据后端返回的status字段设置状态类 if (process.status === '运行中') { statusClass = 'status-running'; } else if (process.status === '手动停止') { statusClass = 'status-manual-stop'; } else if (process.status === '出错') { statusClass = 'status-error'; } else { statusClass = 'status-completed'; } processItem.innerHTML = `暂无日志文件
'; return; } // 按日期倒序排序 data.sort((a, b) => new Date(b.modified_time) - new Date(a.modified_time)); data.forEach(logfile => { const fileItem = document.createElement('div'); fileItem.className = 'process-item'; // 从文件名提取训练类型 let trainType = '未知'; if (logfile.filename.includes('train_pretrain_')) { trainType = 'pretrain'; } else if (logfile.filename.includes('train_sft_')) { trainType = 'sft'; } else if (logfile.filename.includes('train_lora_')) { trainType = 'lora'; } fileItem.innerHTML = `