feat(dc): Complete Tool B MVP with full API integration and bug fixes
Phase 5: Export Feature - Add Excel export API endpoint (GET /tasks/:id/export) - Fix Content-Disposition header encoding for Chinese filenames - Fix export field order to match template definition - Export finalResult or resultA as fallback API Integration Fixes (Phase 1-5): - Fix API response parsing (return result.data consistently) - Fix field name mismatch (fileKey -> sourceFileKey) - Fix Excel parsing bug (range:99 -> slice(0,100)) - Add file upload with Excel parsing (columns, totalRows) - Add detailed error logging for debugging LLM Integration Fixes: - Fix LLM call method: LLMFactory.createLLM -> getAdapter - Fix adapter interface: generateText -> chat([messages]) - Fix response fields: text -> content, tokensUsed -> usage.totalTokens - Fix model names: qwen-max -> qwen3-72b React Infinite Loop Fixes: - Step2: Remove updateState from useEffect deps - Step3: Add useRef to prevent Strict Mode double execution - Step3: Clear interval on API failure (max 3 retries) - Step4: Add useRef to prevent infinite data loading - Add cleanup functions to all useEffect hooks Frontend Enhancements: - Add comprehensive error handling with user-friendly messages - Remove debug console.logs (production ready) - Fix TypeScript type definitions (TaskProgress, ExtractionItem) - Improve Step4Verify data transformation logic Backend Enhancements: - Add detailed logging at each step for debugging - Add parameter validation in controllers - Improve error messages with stack traces (dev mode) - Add export field ordering by template definition Documentation Updates: - Update module status: Tool B MVP completed - Create MVP completion summary (06-开发记录) - Create technical debt document (07-技术债务) - Update API documentation with test status - Update database documentation with verified status - Update system overview with DC module status - Document 4 known issues (Excel preprocessing, progress display, etc.) Testing Results: - File upload: 9 rows parsed successfully - Health check: Column validation working - Dual model extraction: DeepSeek-V3 + Qwen-Max both working - Processing time: ~49s for 9 records (~5s per record) - Token usage: ~10k tokens total (~1.1k per record) - Conflict detection: 1 clean, 8 conflicts (88.9% conflict rate) - Excel export: Working with proper encoding Files Changed: Backend (~500 lines): - ExtractionController.ts: Add upload endpoint, improve logging - DualModelExtractionService.ts: Fix LLM call methods, add detailed logs - HealthCheckService.ts: Fix Excel range parsing - routes/index.ts: Add upload route Frontend (~200 lines): - toolB.ts: Fix API response parsing, add error handling - Step1Upload.tsx: Integrate upload and health check APIs - Step2Schema.tsx: Fix infinite loop, load templates from API - Step3Processing.tsx: Fix infinite loop, integrate progress polling - Step4Verify.tsx: Fix infinite loop, transform backend data correctly - Step5Result.tsx: Integrate export API - index.tsx: Add file metadata to state Scripts: - check-task-progress.mjs: Database inspection utility Docs (~8 files): - 00-模块当前状态与开发指南.md: Update to v2.0 - API设计文档.md: Mark all endpoints as tested - 数据库设计文档.md: Update verification status - DC模块Tool-B开发计划.md: Add MVP completion notice - DC模块Tool-B开发任务清单.md: Update progress to 100% - Tool-B-MVP完成总结.md: New completion summary - Tool-B技术债务清单.md: New technical debt document - 00-系统当前状态与开发指南.md: Update DC module status Status: Tool B MVP complete and production ready
This commit is contained in:
101
backend/scripts/check-task-progress.mjs
Normal file
101
backend/scripts/check-task-progress.mjs
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* 检查DC模块任务进度
|
||||
* 用于诊断LLM是否正常工作
|
||||
*/
|
||||
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function checkTaskProgress() {
|
||||
try {
|
||||
console.log('📊 检查DC模块任务进度...\n');
|
||||
|
||||
// 1. 获取最新的任务
|
||||
const latestTasks = await prisma.dCExtractionTask.findMany({
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: 3,
|
||||
select: {
|
||||
id: true,
|
||||
projectName: true,
|
||||
status: true,
|
||||
totalCount: true,
|
||||
processedCount: true,
|
||||
cleanCount: true,
|
||||
conflictCount: true,
|
||||
failedCount: true,
|
||||
totalTokens: true,
|
||||
createdAt: true,
|
||||
startedAt: true,
|
||||
completedAt: true,
|
||||
error: true
|
||||
}
|
||||
});
|
||||
|
||||
console.log('=== 最近3个任务 ===');
|
||||
latestTasks.forEach((task, index) => {
|
||||
console.log(`\n${index + 1}. 任务: ${task.projectName}`);
|
||||
console.log(` ID: ${task.id}`);
|
||||
console.log(` 状态: ${task.status}`);
|
||||
console.log(` 进度: ${task.processedCount}/${task.totalCount} (${task.totalCount > 0 ? Math.round(task.processedCount / task.totalCount * 100) : 0}%)`);
|
||||
console.log(` 结果: 一致=${task.cleanCount}, 冲突=${task.conflictCount}, 失败=${task.failedCount}`);
|
||||
console.log(` Tokens: ${task.totalTokens || 0}`);
|
||||
console.log(` 创建时间: ${task.createdAt.toLocaleString('zh-CN')}`);
|
||||
console.log(` 开始时间: ${task.startedAt ? task.startedAt.toLocaleString('zh-CN') : '未开始'}`);
|
||||
console.log(` 完成时间: ${task.completedAt ? task.completedAt.toLocaleString('zh-CN') : '未完成'}`);
|
||||
if (task.error) {
|
||||
console.log(` ❌ 错误: ${task.error}`);
|
||||
}
|
||||
});
|
||||
|
||||
// 2. 如果有任务,检查第一个任务的items详情
|
||||
if (latestTasks.length > 0) {
|
||||
const taskId = latestTasks[0].id;
|
||||
console.log(`\n\n=== 最新任务的Item详情 (${taskId}) ===`);
|
||||
|
||||
const items = await prisma.dCExtractionItem.findMany({
|
||||
where: { taskId },
|
||||
orderBy: { rowIndex: 'asc' },
|
||||
take: 3, // 只显示前3条
|
||||
select: {
|
||||
id: true,
|
||||
rowIndex: true,
|
||||
originalText: true,
|
||||
status: true,
|
||||
resultA: true,
|
||||
resultB: true,
|
||||
finalResult: true,
|
||||
tokensA: true,
|
||||
tokensB: true,
|
||||
conflictFields: true,
|
||||
error: true
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`\n总共 ${items.length} 条记录(显示前3条):\n`);
|
||||
|
||||
items.forEach(item => {
|
||||
console.log(`行 ${item.rowIndex}:`);
|
||||
console.log(` 原文: ${item.originalText.substring(0, 60)}...`);
|
||||
console.log(` 状态: ${item.status}`);
|
||||
console.log(` DeepSeek结果: ${item.resultA ? JSON.stringify(item.resultA).substring(0, 100) + '...' : '未提取'}`);
|
||||
console.log(` Qwen结果: ${item.resultB ? JSON.stringify(item.resultB).substring(0, 100) + '...' : '未提取'}`);
|
||||
console.log(` 🎯 最终结果(finalResult): ${item.finalResult ? JSON.stringify(item.finalResult) : 'null'}`);
|
||||
console.log(` Tokens: DeepSeek=${item.tokensA || 0}, Qwen=${item.tokensB || 0}`);
|
||||
console.log(` 冲突字段: ${item.conflictFields.length > 0 ? item.conflictFields.join(', ') : '无'}`);
|
||||
if (item.error) {
|
||||
console.log(` ❌ 错误: ${item.error}`);
|
||||
}
|
||||
console.log('');
|
||||
});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 检查失败:', error);
|
||||
} finally {
|
||||
await prisma.$disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
checkTaskProgress();
|
||||
|
||||
Reference in New Issue
Block a user