# 文档解析与本地 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<ParsedDocument>
}
```

聊天上下文管理器与知识库服务依赖该接口，不直接选择 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/<revision>/...` 地址读取文件；
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 均被拒绝；
- 超页数、超时、取消和关闭不会留下运行任务；
- 测试解析不会创建聊天消息或知识库文档；
- 选择本地模型时没有任何文档上传；
- 文档中的提示词不会改变系统、模式或工具权限。
