import assert from 'node:assert/strict' import { readFile } from 'node:fs/promises' import { fileURLToPath } from 'node:url' import path from 'node:path' const scriptDir = path.dirname(fileURLToPath(import.meta.url)) const mockDataPath = path.resolve(scriptDir, '../src/mock/data.ts') const mockAdapterPath = path.resolve(scriptDir, '../src/mock/adapter.ts') const modelPath = path.resolve(scriptDir, '../src/views/system/training-log/trainingLogModel.ts') const [mockData, mockAdapter, modelSource] = await Promise.all([ readFile(mockDataPath, 'utf8'), readFile(mockAdapterPath, 'utf8'), readFile(modelPath, 'utf8'), ]) function objectFromMarker(source, marker) { const markerIndex = source.indexOf(marker) assert.notEqual(markerIndex, -1, `未找到 Mock 数据标记:${marker}`) const openBrace = source.lastIndexOf('{', markerIndex) assert.notEqual(openBrace, -1, `Mock 数据缺少对象起点:${marker}`) let depth = 0 for (let index = openBrace; index < source.length; index += 1) { if (source[index] === '{') depth += 1 if (source[index] === '}') depth -= 1 if (depth === 0) return source.slice(openBrace, index + 1) } assert.fail(`Mock 数据缺少对象终点:${marker}`) } const taskNames = [ 'finance-sft-001', 'legal-sft-002', 'medical-cpt-001', 'service-dpo-001', 'finance-sft-002', 'general-sft-001', ] const commonTrainingFields = [ 'output_model_name', 'batch_size', 'learning_rate', 'n_epochs', 'save_steps', 'lr_scheduler_type', 'max_length', 'warmup_ratio', 'weight_decay', ] for (const taskName of taskNames) { const task = objectFromMarker(mockData, `name: '${taskName}'`) for (const field of commonTrainingFields) { assert.match(task, new RegExp(`\\b${field}\\s*:`), `${taskName} 缺少训练参数:${field}`) } if (/train_method:\s*'lora'/.test(task)) { for (const field of ['lora_rank', 'lora_alpha', 'lora_dropout']) { assert.match(task, new RegExp(`\\b${field}\\s*:`), `${taskName} 缺少 LoRA 参数:${field}`) } } } const medicalTask = objectFromMarker(mockData, "name: 'medical-cpt-001'") assert.match(medicalTask, /\bprocess_id\s*:/, '运行中的医疗训练任务缺少进程 ID') assert.match(mockData, /medical-cpt-001_pid28741\.log/, '医疗训练任务缺少 PID 对应的日志文件') assert.match(mockData, /export const mockTrainingLogContents/, '训练日志没有按文件提供独立 Mock 内容') assert.match(mockData, /Num examples\s*=\s*9,800/, '医疗训练日志缺少样本规模信息') assert.match(mockData, /Total optimization steps\s*=\s*921/, '医疗训练日志缺少真实训练步数信息') assert.match(mockData, /\\'epoch\\':\s*1\.92/, '医疗训练日志的 Epoch 未与 64% 进度对齐') assert.match(mockData, /\\'loss\\':\s*1\.146/, '医疗训练日志缺少当前 Loss 指标') assert.match(mockAdapter, /const file = String\(params\.file/, '训练日志接口没有读取请求中的日志文件名') assert.match(mockAdapter, /mockTrainingLogContents\[file\]/, '训练日志接口没有按请求文件返回对应内容') assert.match(modelSource, /epoch:\s*number\[\]/, '训练指标模型没有保留逐步 Epoch') console.log('训练日志 Mock 数据回归检查通过')