文档解析与 OCR
本页说明上传文档如何变成可检索的文本层(content_text):四类文件各走什么抽取路径、扫描件与图片如何 OCR、第三方解析库的选型结论,以及存量数据的回填机制。文本层产出后的分块与索引见分块与索引机制。
四类抽取路径
抽取入口统一在 app/services/document_service.py 的 extract_text,按扩展名/MIME 分派:
| 文件类型 | 抽取路径 | 关键机制 | 代码位置 |
|---|---|---|---|
| PDF(文字层) | pypdf 文字层基线 + pymupdf find_tables 结构化 | 线框表格输出 Markdown 管道表;表外文本与无表页逐字保持 pypdf 现链;顺带治好 pypdf 解不动 CMap 缺失 CJK 字体的乱码 | document_ocr.extract_pdf_text_structured |
| 扫描件 PDF + 图片 | RapidOCR(rapidocr-onnxruntime) | 文字层优先:先用 pypdf 判定缺文字页(单页 < 10 字),仅缺文字页进 OCR;全局信号量限 1 并发;依赖缺失优雅降级为只抽文字层 | document_ocr.ocr_pdf_pages / ocr_image_file |
| XLSX | openpyxl 普通模式 | 每工作表输出 ## 工作表:{名} 章节头 + Markdown 管道表(首个 ≥2 非空单元格的行作表头,无够格表头不硬造);单元格批注内联为「值(批注:…)」 | document_service._extract_text_from_xlsx |
| DOCX | python-docx | 按 body 子元素顺序遍历 w:p/w:tbl:段落与表格混排保持原文顺序;表格转 Markdown 管道表(旧口径只取段落、表格整个丢弃,已根修) | document_service._extract_text_from_docx |
统一产出形态
四条路径的产出都是带 Markdown 管道表的纯文本,落 Document.content_text。管道表形态与下游 row:: 表格行结构化索引(见分块与索引机制)对齐:章节头让行条目带工作表/章节前缀,列名进「列名: 值」拼接。extraction_status 三态:pending(待抽取/待 OCR)→ success / error。
扫描件与图片 OCR 的工程纪律
- 文字层优先:有文字层的页绝不进 OCR,只补缺文字页;OCR 文本按页序与文字层合并回
content_text。 - 内存峰值 = 一页:逐页渲染(200 DPI)、逐页识别、逐页释放,绝不整本进内存。
- 全局信号量限 1 并发(
_ocr_semaphore):onnxruntime CPU 推理本身吃满核,后来的后台线程排队,并发只会把内存拱爆。 - 优雅降级:pymupdf / rapidocr 全部 lazy import + 失败标记;缺依赖 = 只抽文字层 + warning 日志,绝不炸上传链路。
XLSX 批注的坑
openpyxl 的 read_only 模式拿不到 cell.comment(批注整个丢失),必须用普通模式加载并配合 closing 保证 workbook 句柄关闭(document_service.py:124 血泪实证)。
Docling 评估结论:不进
曾评估 Docling 作为统一解析后端(spike 代码保留,DOC_PARSER_BACKEND=docling 启用,默认关):依赖体积磁盘约 1.8GB、实测转换峰值工作集约 1.9GB,对桌面安装包与云端小机都不可接受。结论是不进;正解是 pymupdf find_tables 的表格结构化路线(顺带治好 CJK 乱码),即上面的现行方案。
存量回填:extract_md_tables_v1
XLSX/DOCX 抽取口径升级为管道表后,存量 success 文档的 content_text 还是旧格式(XLSX 空格拼接无表结构、DOCX 表格整个丢弃),需要一次性回填(document_service.backfill_md_table_documents):
- 启动后约 120s 后台线程跑一次,完成标记
extract_md_tables_v1落system_configs(_MD_TABLES_MARKER_KEY),有 marker 即跳过,幂等; - 逐文档重抽取,有差异才更新:文本不变不动库;更新后重走 FTS 重同步 + 向量重嵌;
- 全部处理成功才落 marker,中途失败下次启动续跑。
桌面 sidecar 的 OCR 全家桶
桌面端把 OCR 依赖整体打进 PyInstaller sidecar(约 693MB):pymupdf、rapidocr-onnxruntime、onnxruntime、cv2 收进 spec。0.2.115 起 sidecar 含 Markdown 管道表抽取码,存量 xlsx/docx 首启自动回填(同上 marker 机制)。桌面与云端跑同一份抽取代码。
下一步
- 分块与索引机制——
content_text如何切块进三索引 - 笔记、剪藏与知识管理——文档在线编辑与仓库模式
- 浏览器剪藏扩展——网页内容的入库路径