-
1.3.11 Stable
released this
2026-10-22 15:55:15 +08:00 | 0 commits to main since this release#34: OCR 新增整份文档解析
OcrClient.parse_document——CHSAnalyzer3 要把几百篇医学论文 PDF 整份转成带页码的正文与表格,而库只会返回版面框,且 PDF 被写死的image.jpg标签当成图片上传。两个症状同根: 库把 OCR 输入建模成「一张图 + 写死的标签」、输出建模成「只有框」,没有「文档」这个概念。设计research-wiki/designs/2026-10-21-issue34-ocr-document-design.md。新增
OcrClient.parse_document(document, *, session_id, parent_call_id, tenant_id, meta, call_deadline_s) -> OcrDocumentResult: PDF 或图片整份交给 MonkeyOCR,返回逐块OcrDocumentElement(继承OcrLayoutElement,仅多一个text:text/title纯文本、interline_equation裸 LaTeX、tableHTML、image空串)、page_sizes与整篇markdown。治理链路(限流/熔断/重试/换源/遥测/调用方维度/期限)复用parse_layout的同一循环。- 公共类型
OcrDocumentElement/OcrDocumentResult(包根导出);端口OcrDocumentPort;transport 协议OcrDocumentTransport(独立于OcrTransport,不动旧runtime_checkableProtocol 的成员,既有实现与测试替身不受影响)。 CallOperation/ 遥测operation列新增取值parse_document(无 DDL、无新列);占位<ocr:document image_bytes=N>,response 摘要<document elements=N pages=M md_chars=K>永不写入正文。- 内容只取自
_middle.json与配对的.md,有意不读_content_list.json(它是展示格式,星号、反引号、波浪线、美元符会被转义,实测 134 个文字块中 23 个含\$)。
修复
recognize_text(PDF)的静默错误结果: 此前一切上传都标image.jpg,而 MonkeyOCR 按扩展名分派。PDF 走图片分支时/ocr/text返回success:true与幻觉文本(实测"The image contains a single character: 1"),下游完全无感。上传标签现在按内容判定(图片魔数优先,再看前 1KB 内的%PDF-),三个方法共用一处;非 PDF 一律沿用image.jpg(字节级不变)。
行为变更
-
parse_layout(PDF)的上传分支改变(图片数据集 → PDF 数据集)。差分实测: 文本型与无文字层的位图型 2 页 PDF,_middle.json/_content_list.json/.md逐字相同;旋转页、带批注页未测,不构成保证。该路径无已知消费者(医院线只传图片)。 -
parse_document对坏输入的处置(仅新路径;共享分类不变): 无法识别的字节本地拒绝、不发请求(RequestRejectedError,不带status_code);服务把一切失败包成500 "Parsing failed: …",其中已知的确定性坏输入(Failed to open stream/Cannot open empty stream/cannot save with zero pages/is no PDF)归RequestRejectedError(status_code=500)——不重试、熔断记成功不计窗口。其余 500 仍是瞬时错误。标记集合可经MonkeyOcrTransport(deterministic_failure_markers=...)覆盖。 -
结果包解析的外部数据异常边界统一落
ResultInvalidError(含加密成员、未知压缩方法、巨大整数、深嵌套 JSON),不漏出原生异常——漏出会让客户端既不写终态遥测行、又不归还半开探针。 -
文档路径流式下载并限制整包 256 MiB;
_middle.json≤ 64 MiB、.md≤ 16 MiB;解析在线程里执行,取消与call_deadline_s基本不被占住(json.loads持有 GIL:实测 54 MiB 的 middle 解析约 1 秒、事件循环最大停顿约 0.3 秒;取消后线程自然收尾、占用默认 executor,正常大小是毫秒级)。parse_layout的口径(bbox 整数化退化校验、page_idx回退、无体积上限)保持原样。 -
共用的第一段协议新增
download_url校验: 服务响应里的畸形download_url(控制字符、坏方括号、越界端口)此前会让httpx.InvalidURL等原生异常漏出OcrClient(不写终态遥测行、半开探针不归还),现归瞬时错误、不发第二段请求。parse_layout共用这一处,属顺带修复;不限制主机(基线接受绝对地址)。 -
嗅探副作用: 前 1KB 内含
%PDF-字样的非 PDF 文本在recognize_text/parse_layout上的上传标签由image.jpg变为doc.pdf;BMP 魔数现要求 DIB 头大小字段合法(不再单凭BM两字节)。 -
文档路径读取错误响应体只读前 64 KiB(摘要只需要几 KiB),不再把巨大的错误体整个读进内存。
已知限制与运维须知(详见 README「1.3.11 OCR 整份文档解析」)
- 服务端丢弃脚注、页眉页脚、页码,表格脚注里的显著性/缩写说明不会出现在结果里。
timeout_s不是总耗时上界(逐次网络操作的超时);长文档的硬上限靠call_deadline_s,并应≤ lease_ttl_s。库内无基于延迟的熔断,长文档不会被判慢。- 若 MonkeyOCR 部署为 sync-only 后端(出厂默认
lmdeploy),/parse每实例全局串行,长文档会队头阻塞同实例上医院线的请求;请向运维确认 backend。 - 多行/多 span 文本块、
inline_equationspan、嵌套 caption/footnote 子块三条路径无真实样本,仅由构造 fixture 测试。 - 后续: #35(共享分类对确定性坏输入 500 仍归瞬时)、#36(
recognize_text不校验服务响应的success)、#37(parse_layout结果包解析仍漏出原生异常、download_url不限制主机)。
Downloads