# OCR 识别与自动填表系统设计方案

版本：v0.1  
日期：2026-05-08

> 2026-05-09 补充：后续 OCR 中台将作为独立新项目从 0 开始建设，不在当前原型代码上重构。中台产品定位、最新技术路线、可插拔 OCR 引擎、任务调度和监控方案见 `docs/ocr-platform-design.md`。当前项目保留为业务场景与算法接入验证原型。

## 1. 项目目标

建设一套本地部署的 OCR 识别与自动填表系统，用于识别图片/PDF 表格、手写填表内容，解析为统一的数据结构，并通过统一接口提供给业务系统自动填入 Web 表单。

第一阶段以“食品经营许可证”表单为样例，但系统设计必须支持后续接入更多表现形式不同、字段结构相近的业务表单。

## 2. 已有基础

- OCR 中台不依赖历史 OCR 项目或本地 PaddleOCR 源码目录。
- PaddleOCR 外部服务已部署到服务器 Docker，接口地址：`http://192.168.1.13:18080/layout-parsing`
- PP-ChatOCR 视觉分析服务已部署到服务器 Docker，接口地址：`http://192.168.1.13:18083/chatocr-visual`
- 当前服务使用 PP-StructureV3，保留版面、OCR、表格识别，关闭公式、图表、印章识别
- GPU 版服务已验证可用，图片请求 `fileType=1`
- 表单样例：`samples/forms/食品经营许可证-20260508-1057.txt`
- 前端 UI 必须复用 `website` 后台工作台风格，约束见 `docs/frontend-ui-style.md`
- 当前表单 JSON 格式与数据规范分析见 `docs/form-json-analysis.md`

样例表单解析结果：

- 表单名称：食品经营许可证
- 顶层分组：2 个
- 可输入字段及明细列约 31 个
- 字段类型包括：`TextInput`、`DateTime`、`SelectInput`、`MultipleSelect`、`CascadeSelect`、`NumberInput`、`TableList`
- 表单字段包含 `inputName`、`field id`、`title`、`valueType`、`required`、`options`、`triggers`、`regexp` 等关键信息

## 3. 总体架构

```mermaid
flowchart LR
  A["用户上传图片/PDF"] --> B["Java 后端任务接口"]
  B --> C["文件存储"]
  B --> D["OCR 任务队列"]
  D --> E["已配置 OCR Provider"]
  E --> F["OCR 原始结果"]
  F --> G["版面/表格/文本解析"]
  G --> H["字段匹配与标准化"]
  H --> I["人工校验/修正"]
  H --> J["统一数据访问接口"]
  I --> J
  J --> K["业务系统 Web 表单自动填充"]
  L["表单模板 JSON"] --> M["表单结构解析器"]
  M --> H
  M --> J
```

系统拆成四个核心层：

- OCR 能力层：通过统一适配器调用已配置外部 OCR provider。当前已验证 PaddleOCR `/layout-parsing` 可获取版面、文本、表格结构，PP-ChatOCR `/chatocr-visual` 和 `/chatocr-chat` 可作为可选视觉诊断与语义键值抽取能力。
- 表单理解层：解析业务表单 JSON，形成标准字段模型
- 内容解析层：把 OCR 原始结果映射到标准字段、明细表和字典值
- 服务接口层：向业务系统提供查询、校验、自动填表数据接口

## 3.1 窗口业务办理场景

系统的核心使用场景是窗口工作人员打开某个业务进行办理。每个业务先绑定一个业务表单模板，工作人员进入业务后看到的是可直接填写和提交的业务表单，而不是独立的 OCR 后台任务。

正常办理链路：

1. 窗口工作人员打开业务。
2. 系统加载该业务绑定的表单模板并渲染为 Web 表单。
3. 工作人员可以直接用键盘和鼠标逐项填写。
4. 点击提交后保存为一笔业务实例。

启用 OCR 后的插件式链路：

1. 工作人员在业务办理页面中点击“智能识别填表”，系统打开独立的智能识别辅助页面。
2. 通过摄像头拍照，或手动上传已经拍好的图片/PDF。
3. OCR 插件创建识别任务并调用已配置 OCR provider。
4. 后端将识别结果解析为文本块、表格块和字段候选。
5. 智能识别辅助页面展示识别出的键值对，工作人员可以先修改识别文字。
6. 点击“回填到业务表单”后，系统按字段映射关系把值写入原业务表单。
7. 系统返回业务办理页面，工作人员最终确认无误后点击提交，生成一笔业务。

因此，OCR 不是独立业务系统，而是业务填表页上的能力插件。业务系统负责表单渲染、提交和业务实例保存；OCR 插件负责拍照/上传、识别、解析、匹配和回填建议。

界面风格按使用对象分层：

- 窗口业务办理页属于用户侧/窗口侧页面，默认保留传统键盘鼠标填表流程；只有用户点击“智能识别填表”后，才进入 OCR 辅助流程。
- 智能识别辅助页面可以参考原型中的政务受理流程、智能识别入口、材料采集、高拍仪扫描工作台、核验和回填体验。
- 模板管理、OCR 任务、字段映射、数据查询、运行监控、系统配置属于后台管理页，继续复用 `website` 后台工作台风格。

### 3.2 原型参考结论

参考原型：`samples/prototypes/智能识别填表原型.html`

原型中值得吸收的交互设计：

- 在业务表单入口处放置明显的“智能识别填表”引导，而不是把 OCR 藏在单独菜单中。
- 智能识别过程按“采集材料 -> OCR 核验 -> 回填表单”分步展示，工作人员知道当前处于哪一步。
- 采集材料界面保留左侧缩略图、中央图像预览、右侧设备/操作区，适合高拍仪或摄像头多页采集。
- OCR 核验界面采用左侧原图、右侧字段列表的双栏结构，点击字段后左侧定位识别区域。
- 字段核验需要显式展示高置信度、低置信度、已确认状态；低置信度字段应优先提示工作人员处理。
- 回填完成后，表单字段应有“来自智能识别”的视觉标记，便于工作人员复核。

当前第一版先实现业务办理页中的“智能识别填表”入口、独立 OCR 辅助页面、拍照/上传、拖拽上传、材料大预览、左图右字段核验、识别结果编辑、回填到原业务表单和提交业务，并在辅助页面吸收原型中的步骤条、缩略图区、设备操作区、材料就绪状态、置信度状态和回填标记。下一版应优先补齐原型中的“多页材料真实采集”“图片旋转/重拍”和“基于 OCR 坐标的精确字段定位”能力。

浏览器摄像头调用注意事项：直接使用 `getUserMedia` 需要 HTTPS 或 localhost。当前生产地址是 HTTP，因此页面提供上传图片/PDF作为可用路径；若要窗口电脑直接拍照，需要为前端站点配置 HTTPS，或接入高拍仪厂商本地控件/服务。

### 3.3 Form3 表单样式还原

业务表单模板来自 `zm-form3` 设计器，模板文件本身就是 Form3 JSON，包含 `GroupLayout`、`SpanLayout`、`TableList` 和具体控件定义。因此业务办理页不应只使用扁平字段列表渲染，否则会丢失设计器中的分组、分栏、明细表和控件表现。

当前实现策略：

- 后端在导入模板时保存原始 `raw_json`，业务表单接口同时返回标准字段列表和原始 JSON。
- 前端业务办理页通过 iframe 嵌入原 `zm-form-designer-module` 的 Vue2 `FormViewer` 预览器，直接使用原 Form3 运行器展示表单。
- iframe 父子页面通过 `postMessage` 传递 Form3 JSON、`nameModal` 和表单变更事件，避免 Vue2 Form3 组件直接混入 OCR 的 Vue3/Vite 应用。
- Form3 iframe 桥接必须区分“加载表单”和“同步表单值”：只有业务或模板切换时才重新发送 Form3 JSON，普通输入、明细表行编辑和 OCR 回填只同步 `nameModal`，避免重建 `FormViewer` 导致用户输入被刷新覆盖。
- 标准字段列表继续保留，用于 OCR 字段匹配、回填、查询和接口输出。

OCR 插件最终会集成到原业务系统中，原系统已经具备 Form3 运行展示能力。因此生产集成时表单展示、校验、触发器、动态显隐和提交仍由原系统的 Form3 运行器负责。OCR 独立演示页也采用同一个 Form3 viewer iframe 方案，避免再维护一套轻量仿制渲染器。

### 3.4 Form3 原系统集成契约

OCR 插件与原系统的边界调整为：

- 原系统负责打开业务、加载业务绑定表单、使用原 Form3 运行器展示表单。
- OCR 插件负责拍照/上传、OCR 识别、结构化解析、字段匹配、人工核验和生成 Form3 可消费的回填数据。
- 回填数据优先使用 Form3 的 `nameModal` 契约，字段 key 使用表单设计器里的原始 `inputName`，可直接传给 `FormViewer.setNameModal(nameModal)`。
- 接口同时返回 `fieldIdModal`，用于需要按 Form3 内部 `fieldId` 调用 `setModal()` 的场景。
- 接口同时返回 `canonicalModal` 和字段元信息，便于业务系统记录 OCR 来源、置信度、人工核验状态和字段映射过程。

Form3 兼容回填接口：

- `GET /api/fill-data/{taskId}/form3`

成功响应采用 Form3 常见的 `code/msg/data` 包装：

```json
{
  "code": 0,
  "msg": "success",
  "data": {
    "taskId": 1001,
    "taskNo": "OCR202605080001",
    "formTemplateId": 2,
    "status": "REVIEWED",
    "nameModal": {
      "spjy_foodopername": "某某食品经营部"
    },
    "fieldIdModal": {
      "field_xxx": "某某食品经营部"
    },
    "canonicalModal": {
      "spjy_foodopername": "某某食品经营部"
    },
    "fields": [
      {
        "fieldId": "field_xxx",
        "inputName": "spjy_foodopername",
        "canonicalKey": "spjy_foodopername",
        "title": "经营者名称",
        "value": "某某食品经营部",
        "confidence": 0.93,
        "reviewStatus": "PENDING"
      }
    ],
    "warnings": []
  }
}
```

原系统典型调用方式：

```js
const result = await fetch(`/api/fill-data/${taskId}/form3`).then(r => r.json())
window.zmform3.currentForm().setNameModal(result.data.nameModal)
```

## 4. 技术选型

后端：

- Java 17+
- Spring Boot 3.x
- Java 包名：`com.zhengmeng.ocr`
- Spring Web / Validation / Scheduling
- MyBatis-Plus 或 Spring Data JDBC，优先选择团队更熟悉的一种
- MySQL 8.x
- OpenAPI/Swagger 用于接口文档

数据库初始化状态见 `docs/database-setup.md`。当前已创建 `zmocr` 数据库和 `zmocr_app` 用户，并已完成 `zmocr.*` 授权验证。

前端：

- Vue 3 + JavaScript + Vite
- 使用 Lucide Vue 图标，必要时再引入 shadcn-vue/Radix Vue 类组件
- 后台管理页面必须贴合 `website` 后台工作台风格，不采用独立默认主题；窗口业务办理页允许参考用户侧原型，但要与整体系统外壳保持一致

OCR 服务：

- PaddleOCR PP-StructureV3
- PP-ChatOCR 视觉分析和语义键值抽取；`/chatocr-chat` 使用表单字段、结构候选字段和通用政务表单字段组成 `keyList`，并通过环境变量注入 OpenAI 兼容大模型 `chatBotConfig`
- 作为独立 Docker 服务运行，Java 后端通过 HTTP 调用

文件存储：

- 第一版使用本地服务器文件目录
- 数据库仅保存文件元数据、路径、hash、识别结果摘要
- 上传文件第一版保留 1 个月
- 第一版暂不做敏感信息脱敏
- 后续如需要可替换为 MinIO 或业务系统已有文件服务

## 5. 后端模块设计

### 5.1 表单模板模块

职责：

- 导入业务表单 JSON
- 递归解析 `GroupLayout`、`SpanLayout`、`TableList` 等嵌套结构
- 提取字段元数据，形成稳定的标准字段定义
- 保留原始 `inputName`，同时解析出 canonical field key
- 提取选项、字典编码、正则校验、必填、显隐触发规则

关键输出：

```json
{
  "formTemplateId": 601,
  "formName": "食品经营许可证",
  "fields": [
    {
      "fieldId": "field35675",
      "title": "经营者名称",
      "component": "TextInput",
      "inputNameRaw": "spjy_foodopername",
      "canonicalKey": "spjy_foodopername",
      "valueType": "String",
      "required": true,
      "groupPath": "基本信息/基本信息1"
    }
  ]
}
```

### 5.2 OCR 任务模块

职责：

- 接收上传图片/PDF
- 创建异步识别任务
- 调用已配置 OCR provider 生成主结构数据；按配置可调用 PP-ChatOCR `/chatocr-visual` 生成视觉对照数据，并调用 `/chatocr-chat` 生成原生语义键值对；ChatOCR 失败不得影响主结构结果
- 保存 OCR 原始返回、版面块、表格块、文本行
- 支持任务状态查询、失败重试、日志查看

任务状态：

- `CREATED`
- `UPLOADED`
- `OCR_RUNNING`
- `OCR_DONE`
- `PARSING`
- `NEED_REVIEW`
- `CONFIRMED`
- `FAILED`

### 5.3 内容解析与字段映射模块

职责：

- 将 OCR 文本行、表格单元格、版面块转成统一候选项
- 根据表单字段标题、别名、字典、位置、字段类型进行匹配
- 支持人工维护字段映射规则
- 输出字段值、置信度、来源证据

匹配策略第一版按优先级执行：

1. 精确字段标题匹配，如“经营者名称”
2. 字段别名匹配，如“经营者”“申请人名称”
3. `inputName`/业务字段编码映射
4. 同行/邻近位置键值对匹配
5. 表格列标题匹配
6. 字典值归一化，如“企业” -> `1`
7. 正则和类型校验，如日期、手机号、身份证号、数字面积

### 5.4 标准化数据模块

职责：

- 统一输出字段值、字段来源、置信度、校验结果
- 同时支持按 `fieldId`、`canonicalKey`、`inputNameRaw` 查询
- 支持明细表数据，如食品安全管理人员信息
- 保存人工修正记录，后续反哺映射规则

统一结果结构：

```json
{
  "taskId": "T202605080001",
  "formTemplateId": 601,
  "formName": "食品经营许可证",
  "status": "NEED_REVIEW",
  "fields": {
    "spjy_foodopername": {
      "fieldId": "field35675",
      "title": "经营者名称",
      "value": "某某餐饮店",
      "rawValue": "某某餐饮店",
      "confidence": 0.93,
      "source": {
        "page": 1,
        "blockId": "b-001",
        "bbox": [120, 80, 380, 112]
      },
      "validation": {
        "valid": true,
        "message": null
      }
    }
  },
  "tables": {
    "table_b8b541f4a70": [
      {
        "spjy_aqgly_xm": "张三",
        "spjy_aqgly_xb": "男",
        "spjy_aqgly_lxdh": "13800138000"
      }
    ]
  }
}
```

### 5.5 自动填表接口模块

职责：

- 为业务系统提供填表数据
- 业务系统可按任务 ID 获取一份可直接填入表单的数据
- 支持字段置信度、校验错误、缺失字段一并返回
- 支持“只返回高置信度字段”或“返回全部字段等待人工确认”

填表响应建议结构：

```json
{
  "formId": 601,
  "taskId": "T202605080001",
  "fillMode": "REVIEW_REQUIRED",
  "fieldValuesByFieldId": {
    "field35675": "某某餐饮店"
  },
  "fieldValuesByInputName": {
    "spjy_foodopername": "某某餐饮店"
  },
  "tableValues": {
    "table_b8b541f4a70": [
      {
        "spjy_aqgly_xm": "张三",
        "spjy_aqgly_lxdh": "13800138000"
      }
    ]
  },
  "warnings": [
    {
      "fieldId": "field55825",
      "title": "申请日期",
      "message": "未识别到可靠日期"
    }
  ]
}
```

## 6. 数据库设计草案

核心表：

- `ocr_form_template`
  - 表单模板主表，保存 `form_id`、`temp_id`、`form_name`、版本、原始 JSON、启用状态
- `ocr_form_field`
  - 表单字段表，保存 `field_id`、`title`、`component`、`input_name_raw`、`canonical_key`、`value_type`、`required`、`group_path`
- `ocr_field_option`
  - 字段选项/字典表，保存 label/value、层级、字典编码
- `ocr_field_mapping_rule`
  - 字段映射规则，保存字段别名、正则、位置规则、表格列规则、优先级
- `ocr_task`
  - OCR 任务主表，保存任务状态、表单模板、文件信息、耗时、错误信息
- `ocr_file`
  - 上传文件元数据，保存路径、hash、mime、页数、大小
- `ocr_raw_result`
  - OCR provider 原始返回，建议 JSON 字段保存
- `ocr_text_block`
  - OCR 文本块/文本行，保存 page、bbox、text、confidence
- `ocr_table_block`
  - 表格结构和单元格 JSON
- `ocr_extracted_field`
  - 字段识别结果，保存字段值、置信度、来源证据、校验状态
- `ocr_review_change`
  - 人工校验/修正记录
- `ocr_fill_snapshot`
  - 对业务系统输出过的填表数据快照
- `ocr_system_config`
  - OCR provider 地址、阈值、文件保留策略等系统配置

## 7. API 设计草案

表单模板：

- `POST /api/form-templates/import`
- `GET /api/form-templates`
- `GET /api/form-templates/{id}`
- `GET /api/form-templates/{id}/fields`
- `POST /api/form-templates/{id}/mapping-rules`

OCR 任务：

- `POST /api/ocr/tasks`
- `POST /api/ocr/tasks/{taskId}/retry`
- `GET /api/ocr/tasks`
- `GET /api/ocr/tasks/{taskId}`
- `GET /api/ocr/tasks/{taskId}/result`
- `GET /api/ocr/tasks/{taskId}/raw-result`
- `GET /api/ocr/tasks/{taskId}/extracted-fields`

人工校验：

- `PUT /api/ocr/tasks/{taskId}/fields/{fieldId}`
- `POST /api/ocr/tasks/{taskId}/confirm`

自动填表：

- `GET /api/fill-data/{taskId}`
- `GET /api/fill-data/{taskId}/form3`
- `GET /api/fill-data/{taskId}?mode=high-confidence`
- `POST /api/fill-data/query`
- `GET /api/fill-sdk/ocr-fill.js`

自动填表第一版同时提供两种能力：

- 业务系统调用接口获取 JSON 后自行填表
- 原系统调用 Form3 兼容接口获取 `nameModal`，交给原 Form3 运行器执行回填
- OCR 系统提供前端 SDK/脚本，业务系统页面可按约定加载后自动写入字段

运行监控：

- `GET /api/health`
- `GET /api/health/paddleocr`
- `GET /api/monitor/tasks`
- `GET /api/monitor/gpu`

## 8. 前端页面规划

UI 风格必须遵守 `docs/frontend-ui-style.md`。

页面：

- 工作台
  - 今日识别任务、成功率、待校验、失败任务、最近任务
- OCR 识别
  - 上传图片/PDF、选择表单模板、查看任务进度、查看识别数据详情
  - 识别数据详情包含结构化字段、原始文本块、表格块和缺失/低置信度提示
- 表单模板
  - 导入表单 JSON、查看字段树、字段类型、必填项、字典选项
- 字段映射
  - 维护字段别名、字典归一化、表格列映射、置信度阈值
- 数据查询
  - 按表单、任务、字段、日期查询标准化结果
- 运行监控
  - OCR provider 服务状态、GPU/CPU 使用、任务队列、错误日志
- 系统配置
  - OCR 服务地址、MySQL 配置、文件存储路径、阈值配置

## 9. 部署设计

服务器组件：

- `mysql`
- `ocr-backend`
- `ocr-frontend`
- `maodou-paddleocr`

第一版部署方式：

- OCR provider 以外部 Docker 服务方式接入，中台不内置算法服务。
- Java 后端通过配置项访问 `http://192.168.1.13:18080`
- MySQL 使用本地服务器实例
- 前端可由 Nginx 静态托管，也可由 Spring Boot 开发阶段代理

建议环境变量：

```text
OCR_DB_HOST=
OCR_DB_PORT=3306
OCR_DB_NAME=zmocr
OCR_DB_USER=
OCR_DB_PASSWORD=
OCR_PADDLE_BASE_URL=http://192.168.1.13:18080
OCR_FILE_STORAGE_PATH=/data/ocr/files
OCR_MIN_CONFIDENCE=0.80
```

当前项目数据库建议配置：

```text
OCR_DB_HOST=192.168.1.222
OCR_DB_PORT=3306
OCR_DB_NAME=zmocr
OCR_DB_USER=zmocr_app
OCR_DB_PASSWORD=<通过服务器私有配置注入>
```

## 10. 第一版范围

第一版必须完成：

- 表单 JSON 导入和字段解析
- 支持扫描本项目 `samples/forms` 或配置目录中的表单定义文件
- 上传图片/PDF 创建 OCR 任务
- 调用已配置 OCR provider 服务
- 保存 OCR 原始结果
- 对样例“食品经营许可证”完成主要字段映射
- 输出统一填表 JSON
- 提供基本人工校验页面
- 提供业务系统可调用的填表接口

第一版暂不追求：

- 完全自动识别所有手写字段
- 复杂跨页表格推理
- 训练自有 OCR 模型
- 多租户权限体系
- 大规模分布式任务队列

## 11. 风险与处理

- 手写识别准确率不稳定：第一版必须有人工校验闭环，并保存修正记录
- 表单 `inputName` 包含复制/字典/清理表达式：必须保留原值，同时解析 canonical key
- 业务表单触发规则复杂：第一版先返回字段值和校验提示，复杂显隐由业务表单自身执行
- OCR provider 返回结构可能变化：后端通过 `OcrEngineAdapter` 封装，避免业务逻辑直接依赖原始返回
- 字典值归一化容易错：字段映射必须保存 label/value 双值和置信度

## 12. 需要确认的问题

1. 是否需要用户登录、角色权限和操作审计。
2. 手写识别验收标准：允许多少字段需要人工确认，哪些字段必须高准确率自动填。
3. 预计并发量：每天任务量、单文件页数、是否需要排队和限流。

已确认决策：

- Java 包名采用 `com.zhengmeng.ocr`
- MySQL 数据库使用 `zmocr`，应用用户使用 `zmocr_app`
- 自动填表同时提供后端 JSON 接口和前端 SDK/脚本
- 表单定义文件放在本项目 `samples/forms` 或配置目录中，后续会继续增加
- 当前阶段重点分析表单格式和数据规范
- 上传文件保留 1 个月
- 暂不考虑敏感信息脱敏
