# 文档解析与本地 OCR ## 1. 目标 GoodBuddy 需要用同一条可信文档解析链路服务以下场景: - 聊天附件问答; - 知识库导入、同步、分块与来源定位; - 后续的合同审阅、表格分析、演示文稿理解和文档转换。 文档解析不是对话模型的附属功能。它是主进程管理的独立基础能力,设置入口为“设置中心 / 文档解析”。 ## 2. 当前基线 原生解析器已经支持: - UTF-8 文本、代码、配置、HTML; - 带文本层的 PDF; - DOCX 正文; - XLSX 工作表 XML 与共享字符串; - PPTX 幻灯片文字。 现有局限: - 纯扫描 PDF 没有文本层时无法提取内容; - DOC、XLS、PPT 等旧版二进制 Office 格式不支持; - Office 解析主要提取文字,不能完整保留表格、公式、图表和版面; - 聊天附件和知识库直接调用底层解析函数,缺少可配置的统一工作流; - 没有本地 OCR 模型状态、真实解析测试和按场景策略。 ## 3. 产品原则 ### 3.1 双通道解析 PDF 不是所有文档唯一的中间格式。解析应同时保留: 1. 原生语义通道:标题、段落、单元格、公式、备注和对象关系; 2. 渲染视觉通道:页码、版面、图表、图片和 OCR 结果。 两条通道合并为统一文档结构。转换为 PDF 用于补充视觉信息,不得覆盖更可靠的原生语义结果。 ### 3.2 场景工作流 | 场景 | 默认预设 | 行为 | | --- | --- | --- | | 聊天附件 | 自动解析 | 优先快速提取,文本不足时按需 OCR,有界截断后加入当前请求 | | 知识库导入 | 完整索引 | 完整解析、按页或工作表定位、按需 OCR、分块与索引 | | 扫描文档 | OCR | 页面渲染、文字识别、置信度与定位保留 | | 表格分析 | 语义优先 | 单元格和值优先,PDF 或图片补充图表与打印布局 | | 高保真审阅 | 视觉增强 | 原生解析、页面渲染、OCR 或视觉理解合并 | ### 3.3 本地优先 - 文本层和本地 OCR 均在设备上处理; - 本地处理不因 Ask 或 Execute 模式改变; - OCR 来源必须在“本地模型 / 远程服务”之间明确选择; - 配置并保存远程服务即表示用户选择该处理路径,不再增加逐场景授权; - API 密钥只能保存在主进程加密设置中; - 测试文件不得自动进入聊天或知识库。 ## 4. 设置设计 设置中心新增“文档解析”分类,结构如下: 1. 分类页头:“测试解析”“保存设置”; 2. 运行状态:原生解析、文档转换、本地 OCR; 3. 使用场景:聊天附件、知识库导入; 4. 文档转换; 5. OCR 识别; 6. 高级解析设置; OCR 模型区沿用语音模型管理模式: - 应用不内置模型权重; - 用户按需从 ModelScope 下载,下载完成后离线使用; - 显示来源、语言、运行时、模型体积、安装与校验状态; - 联网设备可导出已安装模型 ZIP,离线或内网设备可直接导入; - 支持下载进度、取消、删除、ZIP 导入导出、打开模型仓库和受管目录; - “打开 ModelScope”直接显示在 OCR 模型卡片右上角,不使用手动导入折叠区; - 模型操作即时生效,解析策略仍通过分类页头的“保存设置”提交。 ### 4.1 第一阶段字段 - 聊天附件预设:`auto`、`fast-text`、`high-fidelity`; - 知识库预设:`complete-index`、`fast-index`、`high-fidelity`; - PDF OCR 策略:`auto`、`always`、`disabled`; - OCR 来源:第一阶段固定为 `local`,远程服务入口禁用; - 本地 OCR 模型:`pp-ocrv6-tiny`、`pp-ocrv6-small`、`pp-ocrv6-medium`; - 单文档最大页数; - OCR 并发数; - 单页超时。 OCR 来源使用互斥选择。本地模型选中后才显示模型下拉列表、按需下载、导入和本地 OCR 参数;远程服务计划接入 MinerU、PaddleOCR-VL 等接口,第一阶段保持可读但禁用。来源选择本身就是用户的明确决策,不再显示额外的“隐私与云端处理”授权区。 ## 5. 架构 ```text 聊天附件 ─┐ ├─ DocumentParsingService 知识库导入 ┘ ├─ NativeDocumentParser ├─ PdfTextQualityEvaluator ├─ PdfPageRenderer ├─ LocalOcrProvider ├─ DocumentConversionProvider └─ ParsedDocument merger ``` `DocumentParsingService` 是唯一场景入口: ```ts type DocumentParsingPurpose = 'chat-attachment' | 'knowledge-index' type DocumentParsingService = { parse( name: string, bytes: Buffer, purpose: DocumentParsingPurpose, signal?: AbortSignal ): Promise } ``` 聊天上下文管理器与知识库服务依赖该接口,不直接选择 OCR Provider。 ## 6. 统一结果 第一阶段兼容现有 `ParsedDocument`,并逐步扩展: ```ts type ParsedDocument = { title: string sourceFormat: string content: string sections: Array<{ locator: string content: string method?: 'native' | 'ocr' | 'converted' | 'vision' confidence?: number }> warnings?: string[] } ``` 定位字段必须对使用者有意义: - PDF:`第 3 页`; - XLSX:`工作表:预算 / A1:F28`; - PPTX:`幻灯片 5`; - DOCX:标题路径或页码; - 文本:`全文`。 ## 7. 本地 OCR 基线 ### 7.1 模型与运行时 全平台功能基线: - 模型:PP-OCRv6 ONNX/ORT; - 轻量下载档位:Tiny,约 6 MiB,用于低资源设备和六平台离线链路; - 推荐下载档位:Small,约 30 MiB,官方支持 50 种语言; - 高精度下载档位:Medium,约 132 MiB,官方支持 50 种语言,但识别较慢且需要更多内存; - 运行时:ONNX Runtime WebAssembly; - 处理环境:隔离 Worker; - 加速:WebGPU 或平台原生执行 Provider,仅作为可选层; - 回退:任何加速失败后使用 WASM CPU。 需要覆盖的发布矩阵: - Windows x64、Windows arm64; - macOS x64、macOS arm64; - Linux x64、Linux arm64。 模型清单必须固定以下信息: - 上游仓库和不可变 revision; - 文件名、字节数和 SHA-256; - 模型族、语言、质量和速度; - 许可证名称、完整许可证和来源; - 检测模型、识别模型、字符字典的匹配关系。 运行时不得从 `main`、`latest` 或其他可变地址加载模型。 ### 7.2 下载与安装 Tiny、Small 和 Medium 模型均由 PaddlePaddle 官方 ModelScope 仓库提供。Small 是默认推荐档位;Medium 面向更高识别质量,但具有更高内存占用和延迟。每个档位的检测模型、识别模型与字符字典配置分别使用固定提交,并在应用内记录文件字节数和 SHA-256。 下载流程: 1. 主进程从固定 ModelScope `resolve//...` 地址读取文件; 2. 禁用凭据与缓存,限制重定向次数和单文件大小; 3. 写入受管目录下的随机临时安装目录; 4. 边下载边计算 SHA-256,并核对完整字节数; 5. 三个文件全部通过校验后写入安装清单; 6. 原子重命名为正式模型目录; 7. 失败、取消或退出时删除临时文件。 模型只在下载或用户显式打开仓库时访问网络。OCR 推理从受管目录读取已校验文件,不发起网络请求。 ### 7.3 离线 ZIP 迁移 语音模型和 OCR 模型使用同一种离线迁移流程: 1. 联网设备完成受信任来源下载和校验; 2. 在模型卡片选择“导出 ZIP”; 3. 将 ZIP 通过组织批准的介质传输到离线或内网设备; 4. 在相同模型的卡片选择“导入 ZIP”; 5. 主进程按当前应用内置目录重新校验,并在全部通过后原子安装。 ZIP 根目录包含模型文件和 `goodbuddy-model.json`。清单格式为 `goodbuddy-model-archive`,当前版本为 `1`,记录: - 模型类型:`speech` 或 `document-ocr`; - 内置模型 ID 和显示名称; - 文件名、角色、原始字节数和 SHA-256; - 导出时间。 导出不能直接信任已有安装清单,必须重新读取并校验每个文件。导入不能只信任 ZIP 自声明内容,模型 ID、文件角色、字节数和哈希必须再次与当前应用内置目录完全匹配。导入通过后复用普通本地安装的受控临时目录和原子重命名路径。 归档处理使用有界流式读写,不把大型模型或整个展开结果复制到内存。主进程限制压缩包大小、条目数、清单大小、单文件大小和总展开大小,并拒绝: - 绝对路径、`..`、目录或嵌套路径; - 大小写不敏感的重复条目; - 未声明、缺失或角色不匹配的文件; - 模型类型或模型 ID 不匹配; - 解压后大小或 SHA-256 不匹配; - 超过边界的压缩包和压缩炸弹。 取消文件对话框不会改变安装状态。导入和导出也不会切换当前语音/OCR 模型,不会隐式保存文档解析设置。 ### 7.4 PDF 流程 1. 使用 PDF.js 读取每页文本层; 2. 评估有效字符数、乱码率和图片占比; 3. `auto` 模式只渲染文本不足的页面; 4. `always` 模式渲染所有页面; 5. Worker 将页面限制在配置的最大边长内; 6. OCR 返回文字、坐标和置信度; 7. 按页合并原生文本与 OCR,不重复可靠文本; 8. 达到页数、超时、取消或输出限制时停止并返回明确错误。 受密码保护、损坏或超限的 PDF 不得进入 OCR。 ## 8. Office 与转换 ### 8.1 新格式 - DOCX:正文、标题、表格、批注和图片关系; - XLSX:工作表、单元格地址、值、公式、合并关系和图表; - PPTX:幻灯片、文字对象、备注、图片和阅读顺序。 Office 内嵌图片 OCR 属于增强流程,不能替代原生结构解析。 ### 8.2 旧格式 DOC、XLS、PPT 通过 `DocumentConversionProvider` 转换: 1. 转换为 DOCX、XLSX 或 PPTX,供语义解析; 2. 转换为 PDF,供页码、版面和视觉解析; 3. 合并结果并记录转换警告。 本地 LibreOffice Provider 必须: - 在隔离子进程中运行; - 禁用宏和网络; - 使用单任务临时目录; - 限制输入大小、输出大小、内存和超时; - 在成功、失败、取消和退出时清理; - 不接受用户提供的任意命令参数。 ## 9. 安全边界 - 文件路径解析、读取、大小检查和格式校验在主进程完成; - OCR Worker 只接收当前任务所需的有界页面图像和只读模型; - 不向 Worker 暴露文件系统、Electron API、凭据或任意网络访问; - 文档内容视为不可信数据,不解释其中的提示词为系统指令; - 模型和转换程序必须固定版本并校验哈希; - OCR 输出受字符数限制,错误不得包含绝对路径或未脱敏文档内容; - 取消、超时和应用关闭必须终止待处理页面并释放模型会话。 ## 10. 错误与回退 必须区分: - 不支持的格式; - 文档损坏或受密码保护; - 文本层为空但 OCR 未启用; - OCR 模型不可用; - OCR 超时或取消; - 文档页数、大小或输出超限; - 本地转换服务未配置; - 所选远程 OCR 服务不可用或配置不完整。 `auto` 工作流可以从 OCR 回退到可靠的原生文本,但不能把空结果标记为成功。知识库导入失败时保留来源和可重试上下文。 ## 11. 实施阶段 ### 阶段一 - 新增文档解析设置分类和持久化契约; - 建立 `DocumentParsingService`,供聊天和知识库共用; - 将无文本 PDF 识别为可触发 OCR 的明确状态; - 接入 PP-OCRv6 Tiny、Small、Medium 的 ModelScope 下载、校验、ZIP 离线迁移、删除与 WASM Worker; - 实现真实文件测试和六平台验证入口。 ### 阶段二 - 增强 DOCX、XLSX、PPTX 语义结构; - 实现按页混合文本层与 OCR; - 增加版面、表格和阅读顺序。 ### 阶段三 - 增加 LibreOffice 和 API 转换 Provider; - 支持 DOC、XLS、PPT; - 增加 MinerU、PaddleOCR-VL 等远程 OCR 服务连接配置; - 增加高保真工作流和解析结果预览。 ## 12. 验收 - 同一份扫描 PDF 可从聊天附件和知识库得到一致的逐页文本; - 文本型 PDF 在 `auto` 模式下不运行 OCR; - 本地 OCR 在六个平台和两种架构上完全离线运行; - 模型文件损坏时拒绝加载并显示可恢复错误; - 未安装模型时扫描文档提示用户前往“文档解析”下载,文本型文档仍可原生解析; - 下载中可显示文件与总进度并允许取消,失败或取消后不留下已安装状态; - ModelScope 下载与 ZIP 导入均经过同一大小和 SHA-256 校验; - 语音和 OCR 模型可在联网设备导出 ZIP,并在离线设备导入后完成真实推理; - 路径穿越、未知条目、错误模型 ID、篡改文件和超限 ZIP 均被拒绝; - 超页数、超时、取消和关闭不会留下运行任务; - 测试解析不会创建聊天消息或知识库文档; - 选择本地模型时没有任何文档上传; - 文档中的提示词不会改变系统、模式或工具权限。