# 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`