fix(invoice-organizer): PDF 文本层名称字段标签污染防护 (#138)

PDF 的文本层顺序由生成它的开票系统决定,不保证等于版面阅读顺序。部分模板会把
「两栏的全部标签」连续输出完,再输出「两栏的全部取值」,按「标签后紧跟的下一段
文字」配对会把字段标签本身当成取值——一次真实批量整理里,某网约车平台开具的两张
「旅客运输服务」数电票的 sellerName 被抽成了字面的「统一社会信用代码/纳税人识别号:」。

新增「名称字段的标签污染防护(PDF 文本层)」一节:名称等于或主要由已知字段标签
组成时判定为提取失败,先在同页重新定位、再退到整页视觉阅读,仍不能确定则按技能
既定的「抽不齐必填字段就隔离」处理,不得从主题/文件名/相邻税号猜公司名。

明确标注这条只针对 PDF 文本层:OFD 页面文本按坐标重建阅读顺序、模板标签与取值
已合并到同一行,结构化来源更不依赖文本顺序,均不受此问题影响,OFD 章节未改动。
This commit is contained in:
2026-09-06 10:46:46 -04:00
committed by GitHub
parent f1f38d7766
commit 450be28a2b

View File

@@ -145,6 +145,16 @@ OFD **不会**被渲染成图片,也不做签章有效性校验(只报告是
5. **金额取小写。** `价税合计(大写) 壹仟玖佰伍拾玖元玖角捌分 小写¥1959.98` —— 取 `(小写)` 后面的数字。大写金额用来做校验,不用来当值。 5. **金额取小写。** `价税合计(大写) 壹仟玖佰伍拾玖元玖角捌分 小写¥1959.98` —— 取 `(小写)` 后面的数字。大写金额用来做校验,不用来当值。
6. **税率不一定是百分比。** `免税` / `不征税` / `***` 都会出现,原样记录,不要强行转成 0。 6. **税率不一定是百分比。** `免税` / `不征税` / `***` 都会出现,原样记录,不要强行转成 0。
### 名称字段的标签污染防护PDF 文本层)
PDF 的文本层顺序由生成它的开票系统决定,不保证等于版面阅读顺序。部分模板会把「两栏的全部标签」连续输出完,再输出「两栏的全部取值」(`名称:` `统一社会信用代码/纳税人识别号:` 各连续出现两次,之后才是两个公司名和两个税号)——这是一次真实批量整理里实测踩到的坑:某网约车平台开具的两张「旅客运输服务」数电票,`sellerName` 被按"标签后紧跟的下一段文字"这个假设错误抽成了字面的「统一社会信用代码/纳税人识别号:」。**这条只针对 PDF 文本层**——OFD 的页面文本按坐标重建阅读顺序,模板标签与取值已经合并在同一行(见上一节),不会出现这种错位;结构化来源①②③同样不受影响,遇到 PDF 判断不可靠时优先切到 OFD 的结构化字段或视觉识别,而不是死磕文本层位置匹配。
对 PDF 文本层抽出的 `sellerName` / `buyerName` 做以下硬校验:
- 若名称等于或主要由 `统一社会信用代码``纳税人识别号``名称``名称:``销售方信息``购买方信息` 等字段标签组成,必须视为**提取失败**,不得以低置信度直接采信。
- 先尝试从同页其他文本块重新定位(常见于双栏模板整段错位,两个值仍在文本里,只是顺序对不上);仍不能可靠确定时,改用整页视觉阅读(`pdf_mode:"render"`)。
- 视觉阅读仍不能确定时,按「抽不齐必填字段就隔离」处理——名称是必填字段,抽不出真实值就不是「低置信度」,是缺失:整份文件移入 `_quarantine/``.reason.txt` 写清「PDF 文本层名称字段疑似标签污染,视觉复核仍无法判定」;不得从邮件主题、文件名或相邻税号猜测公司名,也不要拿标签本身或空值凑一条低置信度记录混进台账。
### ⚠️ 文本里会有 NUL 字节 ### ⚠️ 文本里会有 NUL 字节
PDF 文本抽取的结果里常出现 `\x00`(未映射字形),位置多在 `价税合计(大写)` 与中文大写之间。 PDF 文本抽取的结果里常出现 `\x00`(未映射字形),位置多在 `价税合计(大写)` 与中文大写之间。