# paperless-paddle-ocr **Repository Path**: mktime/paperless-paddle-ocr ## Basic Information - **Project Name**: paperless-paddle-ocr - **Description**: 使用 PaddleOCR 替换 paperless-ngx 自带的 OCR 引擎,增强对中文(及日文、韩文等)文档的文字识别能力。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-15 - **Last Updated**: 2026-08-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # RapidOCR Updater for Paperless-ngx 使用 RapidOCR 替换 paperless-ngx 自带的 OCR 引擎,增强对**中文**(及日文、韩文等)文档的文字识别能力。 ## 动机 Paperless-ngx 自带的 OCR(基于 Tesseract)对中文支持不够好,识别准确率低。而 RapidOCR 基于百度 PaddleOCR 的 PP-OCRv6 模型(转换为 ONNX 格式,推理更快、依赖更轻),对中文的识别效果显著更优。 本工具作为 paperless-ngx 的**外挂**运行,通过其 Webhook + REST API 实现无缝集成: ``` paperless-ngx 上传文档 → 自带 OCR 完成 → 触发 DOCUMENT_ADDED 工作流 ↓ Webhook POST 到本工具 ↓ 本工具下载原始文件 → RapidOCR 识别 ↓ PATCH /api/documents/{id}/ 更新 content 字段 ↓ paperless-ngx 自动重建搜索索引 ``` ## 环境要求 - Python ≥ 3.10 - paperless-ngx(需能访问其 REST API) - RapidOCR(PP-OCRv6,ONNX Runtime,无需安装 PaddlePaddle) - pypdfium2(将 PDF 按页渲染为图像后再识别) ## 安装 ```bash # 安装依赖 pip install requests rapidocr onnxruntime pypdfium2 ``` 或使用 `uv`(推荐): ```bash uv pip install requests rapidocr onnxruntime pypdfium2 ``` ### Docker 部署(推荐) 本仓库自带 `Dockerfile`,且 `docker-compose.yml` 中已包含 `ocr` 服务,可与 paperless-ngx 一起启动。 ```bash # 1. 复制环境变量模板并填写(重点是 PAPERLESS_TOKEN) cp .env.example .env # 2. 编辑 .env,填入 paperless-ngx 的 API Token(见下文获取方式) # 3. 构建镜像并启动全部服务(paperless + broker + tika + gotenberg + ocr) docker compose up -d --build # 也可以只构建/只启动 OCR 服务 docker compose build ocr docker compose up -d ocr ``` > `.env` 已被 `.gitignore` 忽略,不会把 token 提交到仓库。 #### 环境变量(`.env`) | 变量 | 默认值 | 说明 | |------|--------|------| | `PAPERLESS_TOKEN` | (必填) | paperless-ngx API 令牌 | | `PAPERLESS_BASE_URL` | `http://webserver:8000` | paperless-ngx 地址;与本 compose 一起运行时保持默认,独立部署时改成实际地址 | | `OCR_PORT` | `9090` | 映射到宿主机的 Webhook 端口(容器内固定监听 9090) | | `OCR_MODEL_TYPE` | `small` | PP-OCRv6 模型大小:`tiny` / `small` / `medium` | | `OCR_FORCE` | `false` | 是否强制重新 OCR(`true` 时即使文档已有内容也会重新识别) | | `PAPERLESS_OCR_MODE` | `off` | 关闭 paperless-ngx 自带 OCR(tesseract 对中文准确率低),完全交给本工具的 webhook | | `PAPERLESS_ARCHIVE_FILE_GENERATION` | `never` | 不生成归档 PDF(归档文本层为 tesseract 低质量结果,本方案不需要) | 同 compose 部署时,Webhook URL 直接写 `http://ocr:9090/`,不需要 `host.docker.internal` 或 `extra_hosts`(见下文 Webhook 配置)。 #### 镜像说明 - 基础镜像 `python:3.10-slim-bookworm`,以非 root 用户运行。 - 镜像内 apt 与 pip 默认使用**清华源**加速下载;如需换回官方源,可构建时指定 `docker build --build-arg PIP_INDEX_URL=https://pypi.org/simple ...`。 - PP-OCRv6 `small` 检测/识别模型与方向分类模型已随 `rapidocr` wheel 内置, 默认配置下镜像离线可用。 - `tiny` / `medium` 模型未内置,首次运行时会自动从 modelscope 下载(容器需能访问外网)。 - 纯 CPU 推理;ONNX Runtime 按 `pyproject.toml` 固定为 `>=1.23,<1.24`, 支持 Linux amd64/arm64 与 macOS Apple Silicon。 ## Paperless-ngx 配置 ### 1. 获取 API Token Web UI → 右上角头像 → 你的 Profile → 点击 "Generate API Token"(或 "生成 API 令牌"),复制生成的 token。 也可通过命令行获取: ```bash curl -X POST http://localhost:8000/api/token/ \ -H 'Content-Type: application/json' \ -d '{"username":"admin","password":"your-password"}' ``` ### 2. Docker 网络配置(Docker 部署必读) > 如果使用本仓库的 `docker-compose.yml`(推荐),`ocr` 与 paperless-ngx 位于 > 同一 compose 网络,Webhook URL 直接写 `http://ocr:9090/`,**可跳过本节**。 如果你的 paperless-ngx 与 OCR 服务**不在同一个 compose**(例如 OCR 单独部署), 容器内的服务默认无法访问宿主机网络。需要进行以下配置: #### 2.1 修改 `docker-compose.yml` 在 paperless-ngx 的 webserver 服务中添加 `extra_hosts`,允许容器通过 `host.docker.internal` 访问宿主机: ```yaml services: webserver: # ... 其他配置 ... # === 允许容器访问宿主机网络 === extra_hosts: - "host.docker.internal:host-gateway" ``` #### 2.2 允许内网 Webhook 请求 在 paperless-ngx 的环境变量中添加以下配置(否则 Webhook 向宿主机发请求会被 SSRF 防护拦截): ```yaml services: webserver: environment: # ... 其他环境变量 ... # === 关键安全配置 === # 1. 显式允许访问内网 IP(不加此项,内网 Webhook 会被 Paperless-ngx 作为 SSRF 风险拦截) PAPERLESS_WEBHOOKS_ALLOW_INTERNAL_REQUESTS: "true" # 2. 如果你的 Webhook 使用了非标准端口(如 9090),需要将其加入允许的端口列表 PAPERLESS_WEBHOOKS_ALLOWED_PORTS: "80,443,9090" ``` > **安全提醒**: 以上配置会放宽 SSRF 防护。请仅在受信网络环境中使用,不要将 paperless-ngx 直接暴露在公网。 #### 2.3 完整 `docker-compose.yml` 示例 ```yaml services: webserver: image: ghcr.io/paperless-ngx/paperless-ngx:latest # ... 省略其他配置(volumes、depends_on 等)... extra_hosts: - "host.docker.internal:host-gateway" environment: PAPERLESS_WEBHOOKS_ALLOW_INTERNAL_REQUESTS: "true" PAPERLESS_WEBHOOKS_ALLOWED_PORTS: "80,443,9090" ``` 配置完成后重启容器: ```bash docker compose down && docker compose up -d ``` #### 2.4 Webhook URL 写法 | 部署方式 | Webhook URL | |----------|-------------| | 同一 docker-compose(推荐) | `http://ocr:9090/` | | Docker(独立 compose / 同一宿主机) | `http://host.docker.internal:9090/` | | 裸机 / 同网络 | `http://<宿主机 IP>:9090/` | | 公网 | `https://your-domain.com:9090/` | ### 3. 创建 Workflow(工作流) 在 paperless-ngx Web UI 中: 1. 进入 **工作流**(Workflows)→ **添加工作流** 2. **触发器**(Trigger)设置为 `DOCUMENT_ADDED`(文档添加时) 3. **动作**(Action)选择 `WEBHOOK` 4. 配置 Webhook: - **URL**: `http://host.docker.internal:9090/`(Docker 部署;其他场景见 [2.4 节](#24-webhook-url-写法)) - **请求体模板**(Body template): ```json {"doc_id": {{doc_id}}, "title": "{{doc_title}}"} ``` - **As JSON**: 开启 - **包含文档文件**: 关闭(本工具自行通过 API 下载) > **注意**: 建议直接使用 `{{doc_id}}` 传递文档 ID;部分 paperless-ngx 版本中 > `{{doc_url}}` 会渲染成 `None/documents//`,虽然本工具的正则仍能提取 ID, > 但直接用 `{{doc_id}}` 更稳妥。 ### 4. 关闭 paperless-ngx 自带 OCR(推荐) paperless-ngx 自带的 OCR 基于 tesseract,容器默认只带英文/欧洲语言包, 对中文文档识别率很低(产生乱码 `content`)。本工具通过 webhook 将 RapidOCR 结果写回 `content` 字段并参与全文检索,因此可以在 paperless-ngx 的 `.env` 中 关闭自带 OCR: ```bash PAPERLESS_OCR_MODE=off PAPERLESS_ARCHIVE_FILE_GENERATION=never ``` - `PAPERLESS_OCR_MODE=off`:完全不调用 tesseract/ocrmypdf,扫描件不再产生乱码文本。 - `PAPERLESS_ARCHIVE_FILE_GENERATION=never`:不生成归档 PDF(归档文本层同样是 tesseract 的低质量结果,本方案不需要)。 修改后重启 webserver 生效: ```bash docker compose up -d --force-recreate webserver ``` 注意:关闭后新扫描件在消费完成时 `content` 为空,由 `DOCUMENT_ADDED` 工作流触发 RapidOCR webhook 写回正确内容(需保证 webhook 服务正常运行);数字版 PDF (自带文本层)仍会直接提取文本,不受影响。 ## 使用方式 ### Server 模式(推荐 — 持续运行) Docker 部署(见上文)直接通过 `docker compose up -d` 运行;以下为裸机运行方式。 ```bash uv run ocr_updater_example.py \ --token \ --force \ --server --port 9090 \ --ocr-lang ch ``` 参数说明: | 参数 | 默认值 | 说明 | |------|--------|------| | `--token` | `$PAPERLESS_TOKEN` | paperless-ngx API 令牌(必填) | | `--base-url` | `http://localhost:8000` | paperless-ngx 地址 | | `--server` | - | 以 Webhook 服务器模式运行 | | `--port` | `8080` | 监听端口 | | `--host` | `0.0.0.0` | 监听地址 | | `--ocr-lang` | `ch` | 语言代码(兼容保留:PP-OCRv6 为多语种单一模型,不改变加载的模型) | | `--model-type` | `small` | PP-OCRv6 模型大小:`tiny` / `small` / `medium` | | `--force` | 关闭 | 强制重新 OCR(即使文档已有内容) | 以上参数均可通过环境变量覆盖:`OCR_HOST`、`OCR_PORT`、`OCR_MODEL_TYPE`、 `OCR_FORCE`(布尔值接受 `1` / `true` / `yes` / `on`),Docker 部署时由 `.env` 提供。 语言代码参考: | 代码 | 语言 | |------|------| | `ch` | 简体中文 | | `chinese_cht` | 繁体中文 | | `en` | 英文 | | `japan` | 日文 | | `korean` | 韩文 | > PP-OCRv6 中语言代码不改变模型;`tiny` 模型不支持 `japan`。模型大小由 `--model-type` 决定。 ### One-shot 模式(处理单个文档) ```bash uv run ocr_updater_example.py \ --token \ --base-url http://localhost:8000 \ --doc-id 42 \ --ocr-lang ch \ --force ``` ## 注册为 Systemd 服务(Linux) 创建 `/etc/systemd/system/paperless-ocr.service`: ```ini [Unit] Description=Paperless-ngx RapidOCR Webhook Server After=network.target [Service] Type=simple User=paperless WorkingDirectory=/opt/paperless-ngx/ocr Environment="PAPERLESS_TOKEN=your-api-token" Environment="PAPERLESS_BASE_URL=http://localhost:8000" ExecStart=/home/paperless/.local/bin/uv run ocr_updater_example.py --server --port 9090 --ocr-lang ch Restart=on-failure RestartSec=30 [Install] WantedBy=multi-user.target ``` ```bash sudo systemctl daemon-reload sudo systemctl enable --now paperless-ocr ``` ## 支持的文档格式 | 类型 | 处理方式 | |------|----------| | 图片(png / jpg / jpeg / bmp / tif / tiff / webp) | RapidOCR 直接识别 | | PDF | 先用 pypdfium2 按页渲染(144 DPI),再逐页识别 | | DOCX(Word 文档) | 优先直接提取文档内置文字(无需 OCR);若内置文字过少(疑似扫描件),则对 `word/media/` 中的内嵌图片逐张 OCR | | 其他格式(doc / odt / xlsx / pptx / txt 等) | 暂不支持,跳过并记录 WARNING,不会中断其他文档的处理 | ## 工作原理 ### 核心 API 调用 程序通过 paperless-ngx 的 REST API 完成整个流程: 1. **`GET /api/documents/{id}/`** — 获取文档元数据,检查当前 content 长度 2. **`GET /api/documents/{id}/download/?original=true`** — 下载原始文件 3. **RapidOCR 识别** — 对下载的文件进行文字识别(PDF 先按页渲染为图像;DOCX 优先提取内置文字,扫描件则识别内嵌图片) 4. **`PATCH /api/documents/{id}/`** — 更新 `content` 字段(OCR 文本) `content` 字段更新后,paperless-ngx 的 `DocumentViewSet.update()` 会自动调用 `index.add_or_update_document()` 重建搜索索引,新识别的内容立即可搜索。 ### Webhook 处理 Paperless-ngx 的 Webhook body 可能以多种格式发送(JSON 对象/JSON 字符串/双重编码),本工具内置 `_normalize_webhook_payload()` 方法自动处理这些情况。 文档 ID 也可从多种来源提取:直接的 `doc_id` 字段、`doc_url` URL 路径(如 `/documents/8/`)、或顶层的 `id` 字段。 ## 已知问题 ### 模型与运行环境 - RapidOCR 默认使用 PP-OCRv6 `small`(检测 + 识别)与 PP-OCRv4 `mobile`(方向分类)ONNX 模型;`small` 模型已内置在 `rapidocr` wheel 中,`tiny` / `medium` 首次运行自动下载。可用 `--model-type` 选择。 - 纯 CPU 推理(ONNX Runtime),无需 GPU,适配 macOS Apple Silicon(如 Mac mini M4)与 Linux x86_64。 - PP-OCRv6 的检测/识别模型为多语种单一模型,`--ocr-lang` 仅作兼容保留。 - PDF 输入通过 pypdfium2 按页渲染(144 DPI)后逐页识别。 - DOCX 原生文字直接读取 `word/document.xml`(仅支持 Office Open XML 的 `.docx`,旧版 `.doc` 请先在 Word 中另存为 `.docx` 或转成 PDF)。