Files
AIclinicalresearch/docs/03-业务模块/DC-数据清洗整理/07-技术债务/Tool-B技术债务清单.md
HaHafeng 91cab452d1 fix(dc/tool-c): Fix special character handling and improve UX
Major fixes:
- Fix pivot transformation with special characters in column names
- Fix compute column validation for Chinese punctuation
- Fix recode dialog to fetch unique values from full dataset via new API
- Add column mapping mechanism to handle special characters

Database migration:
- Add column_mapping field to dc_tool_c_sessions table
- Migration file: 20251208_add_column_mapping

UX improvements:
- Darken table grid lines for better visibility
- Reduce column width by 40% with tooltip support
- Insert new columns next to source columns
- Preserve original row order after operations
- Add notice about 50-row preview limit

Modified files:
- Backend: SessionService, SessionController, QuickActionService, routes
- Python: pivot.py, compute.py, recode.py, binning.py, conditional.py
- Frontend: DataGrid, RecodeDialog, index.tsx, ag-grid-custom.css
- Database: schema.prisma, migration SQL

Status: Code complete, database migrated, ready for testing
2025-12-08 23:20:55 +08:00

14 KiB
Raw Blame History

Tool B - 病历结构化机器人 技术债务清单

创建日期: 2025-12-03
状态: 待处理
优先级: P1=高优先级, P2=中优先级, P3=低优先级


📋 技术债务列表

[P1] #1 - Excel导出与前端显示结果不一致

问题描述:

  • 用户在步骤4交叉验证页面看到的提取结果与导出的Excel文件内容不一致
  • 列顺序混乱,部分字段缺失或数据错位

重现步骤:

  1. 完成双模型提取并进入步骤4
  2. 点击"导出当前结果"或在步骤5点击"下载结果Excel"
  3. 打开Excel对比前端显示的结果

根本原因:

  • JavaScript对象展开...extractedData时顺序不固定
  • 未按模板定义的字段顺序构建Excel列

当前状态:

  • 已部分修复按targetFields顺序导出
  • 仍需验证:多次导出结果是否稳定一致

解决方案:

  1. 严格按照task.targetFields定义的字段顺序导出
  2. 添加表头样式(加粗、冻结首行)
  3. 添加数据验证(确保所有字段都存在)
  4. 添加导出测试用例

预计工时: 2小时
影响范围: 后端 ExtractionController.exportResults方法


[P2] #2 - 步骤3进度条显示不够细腻

问题描述:

  • 当前进度条直接从0%跳到100%,缺少中间过程
  • 用户无法感知大模型正在处理第几条记录
  • 没有实时反馈当前处理状态(如"正在处理第3/9条"

期望效果:

提取进度: 33% (3/9条已完成)

日志输出:
[13:43:12] 正在创建提取任务...
[13:43:12] 任务创建成功 (ID: xxx)
[13:43:12] 初始化双模型引擎 (DeepSeek-V3 & Qwen-Max)...
[13:43:13] [1/9] 正在提取: 【右肺下叶】浸润性腺癌...
[13:43:18] [1/9] ✅ 提取完成 (DeepSeek: 549 tokens, Qwen: 627 tokens)
[13:43:19] [2/9] 正在提取: 【右肺上叶】浸润性腺癌...
[13:43:24] [2/9] ✅ 提取完成 (DeepSeek: 486 tokens, Qwen: 551 tokens)
...
[13:43:30] PII 脱敏完成
[13:43:30] ✅ 所有记录提取完成!

解决方案:

后端改动:

  1. DualModelExtractionService.batchExtract的for循环中每处理完一条记录就更新进度
  2. 添加currentItem字段到Task表可选用于实时显示当前处理的记录
  3. 或者使用Redis存储实时进度信息更云原生

前端改动:

  1. 轮询API时解析processedCounttotalCount
  2. 动态生成日志:[${processedCount}/${totalCount}] 正在提取...
  3. 进度条平滑过渡CSS transition

预计工时: 3小时
影响范围:

  • 后端DualModelExtractionService.batchExtract
  • 前端Step3Processing.tsx

[P1] #3 - Excel文件预处理与脏数据清洗

问题描述: 医疗科研场景下Excel文件质量参差不齐存在大量脏数据导致解析失败或结果错误。

子问题1表头特殊字符

  • 现象: 列名包含换行符\n、空格、制表符等,导致列名匹配失败
  • 示例: "病人ID\n(Patient ID)" → 前端下拉框显示异常
  • 影响: 用户无法选择正确的列

子问题2公式 (Formulas)

  • 现象: 单元格包含公式=A1+B1xlsx库读取时返回公式文本而非计算结果
  • 示例:
    • 原始值:=SUM(A1:A10)
    • 读取结果:字符串"=SUM(A1:A10)"(而非数字)
    • 外部引用:=[外部文件]Sheet1!A1#REF!
  • 影响: 数值型字段(如年龄、血糖值)变成文本,无法统计

子问题3合并单元格 (Merged Cells)

  • 现象: 医生习惯合并"住院号"列,对应多行化验记录
  • 示例:
    住院号    检查项目    结果
    H001     血常规      正常  ← 只有这行有住院号
    (合并)    肝功能      异常  ← 这行住院号为null
    (合并)    肾功能      正常  ← 这行住院号为null
    
  • 影响: 后续行的关联字段丢失,无法追溯到患者

子问题4日期地狱 (Date Parsing Hell)

  • 现象: Excel日期存储为数字Serial Number或多种文本格式
  • 示例:
    • 44927 → 应该解析为 2023-01-01
    • 2023.1.1(文本)
    • 2023年1月1日(中文)
    • Jan 1, 2023(英文)
  • 影响: 日期字段无法排序、筛选、统计

子问题5不可见字符与脏文本 (Ghost Characters)

  • 现象: 看起来是"男",实际包含不可见字符
  • 示例:
    • "男 " (尾部空格)
    • "男\u200b" (零宽空格 Zero-Width Space)
    • "男\ufeff" (BOM字符)
  • 影响: 条件判断失败:if (sex === '男') → false
  • 医学场景特例:
    • 化验单复制粘贴时带入富文本格式
    • 不同医院HIS系统导出编码不统一

解决方案:

架构设计独立的Excel预处理服务

// backend/src/modules/dc/services/ExcelPreprocessor.ts
export class ExcelPreprocessor {
  /**
   * 清洗表头
   */
  cleanHeaders(headers: string[]): string[] {
    return headers.map(h => h
      .replace(/[\n\r\t]/g, ' ')  // 移除换行、制表符
      .trim()                      // 去除首尾空格
      .replace(/\s+/g, ' ')        // 多个空格合并为一个
    );
  }
  
  /**
   * 处理公式单元格
   */
  processFormulas(worksheet: xlsx.WorkSheet): void {
    // 使用 xlsx 的 { cellFormula: false } 选项
    // 或手动遍历单元格,计算公式结果
  }
  
  /**
   * 展开合并单元格
   */
  unflattenMergedCells(worksheet: xlsx.WorkSheet): void {
    // 1. 找到所有合并区域 worksheet['!merges']
    // 2. 将主单元格的值填充到所有子单元格
  }
  
  /**
   * 统一日期格式
   */
  normalizeDates(value: any): string | null {
    if (typeof value === 'number') {
      // Excel Serial Number → ISO Date
      return this.excelSerialToDate(value);
    }
    if (typeof value === 'string') {
      // 尝试多种格式解析
      return this.parseChineseDate(value) || 
             this.parseSlashDate(value) ||
             this.parseDotDate(value);
    }
    return null;
  }
  
  /**
   * 清除不可见字符
   */
  cleanInvisibleChars(text: string): string {
    return text
      .replace(/\u200b/g, '')     // 零宽空格
      .replace(/\ufeff/g, '')     // BOM
      .replace(/\u00a0/g, ' ')    // 不间断空格 → 普通空格
      .trim();
  }
}

使用位置:

  1. uploadFile API - 上传后立即预处理,返回清洗后的列名
  2. healthCheck API - 使用清洗后的数据进行检查
  3. createTask API - 使用清洗后的数据创建items

预计工时: 16小时复杂度高需要大量测试
影响范围:

  • 新增:ExcelPreprocessor.ts (~400行)
  • 修改:ExtractionController.ts 的文件处理逻辑
  • 测试:覆盖各种脏数据场景

依赖:

  • xlsx库的高级功能cellFormula、!merges等
  • dayjs或date-fns日期解析

[P2] #4 - 支持用户自定义提取模板

问题描述: 当前系统只支持3个预设模板肺癌病理、糖尿病入院、高血压门诊无法满足用户的多样化需求。

需求场景:

  1. 科研人员研究罕见病(如:系统性红斑狼疮、重症肌无力)
  2. 需要提取的字段与预设模板不同
  3. 每个研究项目的数据规范可能不同

期望功能:

1. 前端:自定义模板编辑器

步骤2.1:选择模板来源
- [ ] 使用系统预设模板
- [x] 创建自定义模板

步骤2.2:定义模板信息
- 模板名称:[我的肺癌研究模板]
- 疾病类型:[自定义:系统性红斑狼疮]
- 报告类型:[自定义:实验室检查]

步骤2.3:定义提取字段(可视化编辑)
┌─────────────────────────────────────┐
│ 字段1: [抗核抗体滴度]               │
│ 描述:  [如 1:320, 1:640]            │
│ 宽度:  [w-32] ▼                     │
│ [ 删除 ]                            │
├─────────────────────────────────────┤
│ 字段2: [补体C3]                     │
│ 描述:  [单位g/L]                    │
│ [ 删除 ]                            │
└─────────────────────────────────────┘
[+ 添加字段]

步骤2.4AI生成Prompt自动化
[ 🤖 让AI帮我生成提示词 ]

后台自动生成:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
你是一名风湿免疫科专家。请从以下系统性红斑狼疮
患者的实验室检查报告中提取关键信息。

提取字段(必须返回以下所有字段):
- 抗核抗体滴度:如 1:320, 1:640
- 补体C3单位g/L

**输出格式严格的JSON格式**
```json
{
  "抗核抗体滴度": "...",
  "补体C3": "..."
}

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[ 编辑Prompt ] [ 预览效果 ] [ 保存模板 ]


#### **2. 后端模板管理API**
```typescript
// 新增API端点
POST   /api/v1/dc/tool-b/templates          // 创建自定义模板
PUT    /api/v1/dc/tool-b/templates/:id      // 更新模板
DELETE /api/v1/dc/tool-b/templates/:id      // 删除模板
GET    /api/v1/dc/tool-b/templates/:id      // 获取模板详情

// Prompt自动生成服务
POST   /api/v1/dc/tool-b/templates/generate-prompt
Request:
{
  "diseaseType": "系统性红斑狼疮",
  "reportType": "实验室检查",
  "fields": [
    { "name": "抗核抗体滴度", "desc": "如 1:320, 1:640" },
    { "name": "补体C3", "desc": "单位g/L" }
  ]
}

Response:
{
  "promptTemplate": "你是一名风湿免疫科专家...",
  "estimatedTokens": 450
}

3. AI Prompt生成逻辑

// 使用元PromptMeta-Prompt
async generatePrompt(
  diseaseType: string,
  reportType: string,
  fields: { name: string; desc: string }[]
): Promise<string> {
  const metaPrompt = `
你是一名医学AI Prompt工程师。请为病历结构化提取任务生成专业的提示词。

任务背景:
- 疾病类型:${diseaseType}
- 报告类型:${reportType}

提取字段:
${fields.map((f, i) => `${i + 1}. ${f.name}${f.desc}`).join('\n')}

要求:
1. 模拟该疾病领域的专家角色
2. 清晰说明每个字段的提取规则
3. 要求输出严格的JSON格式
4. 处理"未提及"的情况

请生成完整的Prompt。`;

  // 调用GPT-5或Claude生成Prompt
  const llm = LLMFactory.getAdapter('gpt-5');
  const response = await llm.chat([
    { role: 'user', content: metaPrompt }
  ]);
  
  return response.content;
}

技术亮点:

  • Prompt即代码Prompt-as-Code模板可版本控制、A/B测试
  • AI生成AI的PromptMeta-Prompt:降低用户门槛
  • 模板市场(未来):用户可分享、下载优质模板

预计工时: 12小时
影响范围:

  • 新增:CustomTemplateService.ts (~300行)
  • 新增:PromptGeneratorService.ts (~200行)
  • 前端Step2Schema.tsx 新增自定义模板编辑UI
  • 数据库DCTemplate表已支持无需改动

📊 优先级评估

债务ID 问题 优先级 工时 影响用户 技术风险
#1 Excel导出不一致 P1 2h 高(核心功能)
#2 进度条显示优化 P2 3h 中(体验优化)
#3 Excel预处理 P1 16h 高(数据质量)
#4 自定义模板 P2 12h 中(扩展性)

总计: 33小时约4个工作日


🎯 建议处理顺序

Sprint 1核心功能修复P1优先

  1. #1 - Excel导出修复2小时立即处理
  2. #3 - Excel预处理16小时分阶段实现
    • Phase 1表头清洗2小时
    • Phase 2合并单元格展开4小时
    • Phase 3公式处理3小时
    • Phase 4日期统一3小时
    • Phase 5不可见字符清理2小时
    • Phase 6集成测试2小时

Sprint 2体验优化P2

  1. #2 - 进度条优化3小时
  2. #4 - 自定义模板12小时
    • Phase 1后端模板CRUD4小时
    • Phase 2Prompt自动生成4小时
    • Phase 3前端模板编辑器4小时

💡 长期优化建议

1. 数据质量评分系统

为上传的Excel文件打分0-100分

  • 90-100优质数据直接处理
  • ⚠️ 60-89一般质量提示可能问题
  • 0-59低质量强制要求用户清洗后再上传

2. Excel模板标准化

提供标准Excel模板下载用户按模板填写减少脏数据

病历结构化标准模板 v1.0.xlsx
- 表头行冻结
- 数据验证(下拉框)
- 字段说明(批注)
- 示例数据

3. 智能修复建议

检测到问题时AI给出修复建议

⚠️ 检测到22个合并单元格可能导致数据丢失
建议操作:
[ 自动展开合并单元格 ]  [ 忽略并继续 ]

📝 开发记录

日期 处理内容 状态 备注
2025-12-03 创建技术债务文档 初始记录4个问题
2025-12-03 #1 Excel导出顺序修复 🔄 已修改代码,待验证
- #2 进度条优化 ⏸️ 待开发
- #3 Excel预处理 ⏸️ 待开发
- #4 自定义模板 ⏸️ 待开发

🔗 相关文档


文档维护: 每次处理技术债务时更新此文档