tm-desensitize/PROGRESS-backend.md

3.2 KiB
Raw Permalink Blame History

tmkit 后端管线 · 进展报告(管线组)

日期:2026-11-03 状态:✅ 最小可用版交付,pytest 12/12 全绿

做了什么

在 金唐智法/tm/tmkit/ 交付 Python 库 tmkit(纯库,不含 Web),四大核心模块 + 测试 + 文档:

模块 内容
splitter.py PDF 分流:get_text 检测文字层,逐页返回 native / scanned(阈值可调)
extractor.py 原生页按词抽取 bbox(get_text('words'));扫描页 raise NotImplementedError('OCR 待接入 PaddleOCR')
detector.py PII 识别引擎:身份证 18 位(GB 11643 校验位验证)、大陆手机号、银行卡(Luhn 校验)、统一社会信用代码(GB 32100 校验)、邮箱;输出 [{type, text, page, bbox}],支持 register() 自定义规则
redactor.py 坐标回写:两种方案都实现了——add_redact_annot + apply_redactions(默认,真删文字,测试验证 PII 从文本层消失、黑块像素可见)和 draw_rect 黑条(对比保留);输出脱敏后 PDF bytes
tests/ reportlab 动态生成 3 个样例 PDF(纯中文文本页 / 身份证+手机号+银行卡+邮箱页 / 空白扫描页,中文字体用 STSong-Light CID),12 个用例全链路验证
README.md 模块说明 + 代码示例 + 已知限制

测试结果(python3 -m pytest,12 passed)

  • 全链路断言:脱敏后 PDF 用 get_text 验证——身份证/手机号/银行卡/邮箱原文不存在、非敏感文本("张三""脱敏"等)保留、页数不变、bbox 区域像素为纯黑
  • 校验算法单测:身份证校验位、Luhn 各有正反例
  • 零误报:无 PII 的普通文本页检测结果为空
  • 自定义规则:注册"案号"正则规则后命中正常
  • 扫描页:正确抛 NotImplementedError(OCR 接口预留)

覆盖 PII 类型(5 类):身份证、手机号、银行卡、统一社会信用代码、邮箱

开发中解决的坑(经验沉淀)

  1. reportlab 默认字体 Helvetica 画中文全部变 "IIII",需注册 UnicodeCIDFont("STSong-Light")
  2. Python 正则 \b 在"中文紧贴数字"(如 身份证号110101...)处不成立(中文和数字都是 Unicode \w),已改用 ASCII-only lookaround 边界
  3. 回写方案选择:apply_redactions 删字最干净(文本层彻底无 PII),定为默认;draw_rect 黑条仅视觉遮挡、文字仍可复制提取,仅留作对比

已知限制 → 下一步

项 说明 计划
OCR 未接入 扫描页直接抛 NotImplementedError 接入 PaddleOCR,补齐扫描页链路(最高优先级)
跨行 PII 身份证分两行排版时不命中(行内拼接策略) 行间相邻性合并
中文姓名/地址 属于 NER 范畴,正则不适用 待接入 NER 模型(第二优先级)
旋转页/加密 PDF 未处理 视真实样本需求补
draw 模式 不删字,仅演示用 文档已标注风险

环境备忘

  • python3(系统 3.9)+ pymupdf 1.26.5 / reportlab 5.0.0 / pytest 8.4.2(pip --user)
  • 复跑:cd 金唐智法/tm && python3 -m pytest tmkit/tests/ -v