fix: make OCR portable and reliable across AMD64 and ARM64 (#519)

* fix: make OCR portable and reliable

* fix: harden OCR installation portability

* fix: pin OCR partials across downloads

* fix: make OCR execution reliably asynchronous

* fix: harden OCR portability and docs routes

* fix: preserve decoder and docs safeguards
This commit is contained in:
SnapOtter
2026-07-15 03:34:24 +08:00
committed by GitHub
parent 58121f205f
commit 991c981529
409 changed files with 67151 additions and 8076 deletions
+41 -17
View File
@@ -1,18 +1,26 @@
---
description: "AI 引擎参考,涵盖所有本地 ML 工具。抠图、放大、OCR、人脸检测、照片修复等。"
i18n_source_hash: 14728c1dcd05
i18n_provenance: machine
i18n_output_hash: 4f22ccca588a
i18n_output_hash: bf13c82eb496
i18n_source_hash: aa9a56cdddc7
i18n_provenance: human
---
# AI 引擎参考 {#ai-engine-reference}
`@snapotter/ai`将 Node.js 与一个**常驻的 Python 边车进程**桥接,用于所有 ML 操作。调度器进程在请求之间保持存活,以获得快速热启动性能。启动时会自动检测 NVIDIA CUDA,并在可用时使用;否则 AI 工具在 CPU 上运行
`@snapotter/ai`协调本机工具和 Python 运行时以进行本地 ML 操作。 大多数 ML 工具使用持久的 Python sidecar 来实现快速热启动。 OCR 是故意分开的: `fast` 调用本机 Tesseract 二进制文件, 而 `balanced``best` 使用专用的持久性 JSONL dispatcher,固定到 `/data/ai/v3` 下的活动不可变 RapidOCR 代。 每个请求都包含一个 generation lease。 在升级期间,SnapOtter 在激活之前在候选者上运行 smoke test,自动切换到新的 dispatcher,然后在 garbage collection 之前耗尽旧代
NVIDIA CUDA 由支持它的运行时自动检测和使用。 OCR 在每个主机上使用 CPU,包括具有 NVIDIA GPU 的系统,避免 CUDA 和该工具的驱动程序耦合。
目前不支持通过 VA-API、Quick Sync 或 OpenCL 使用 Intel/AMD 集成显卡加速 AI 推理。将 `/dev/dri` 映射到容器中并不会加速这些 Python 边车工具,除非有支持 CUDA 的 NVIDIA GPU 可用。
19 个 Python 边车 AI 工具,覆盖四种模态(图像、音频、视频、文档),另有 2 个具备可选 AI 能力的工具。所有模型均在本地运行,首次下载模型后无需联网。
<!-- korean-ocr-contract:start -->
::: info 韩语 OCR 兼容性
快速 OCR 支持 `auto``en``de``es``fr``zh``ja`,但不支持韩语 (`ko`)。韩语需要精确 OCR 包以及 `balanced``best`。该包可在官方 Linux amd64 和 arm64 容器上运行;即使是 NVIDIA 主机,OCR 仍使用 CPU。不受支持的系统会返回明确的兼容性错误,绝不会静默回退到 `fast`。韩语与 `fast` 或旧版 `tesseract` 别名的组合会在入队前以 `FEATURE_INCOMPATIBLE``fast-korean-unsupported` 拒绝。
:::
<!-- korean-ocr-contract:end -->
## 架构 {#architecture}
```
@@ -22,15 +30,17 @@ Node.js Tool Route
@snapotter/ai bridge.ts
| (stdin/stdout JSON + stderr progress events)
v
Python dispatcher (persistent process, "ai" profile)
+-- Native Tesseract + Ghostscript (fast image/PDF OCR)
|
+-- Isolated OCR runtime (persistent JSONL dispatcher)
| `-- RapidOCR + ONNX Runtime CPU + pinned PP-OCR models
|
`-- Python dispatcher (persistent process, "ai" profile)
|
|-- remove_bg.py (rembg / BiRefNet)
|-- upscale.py (RealESRGAN)
|-- inpaint.py (LaMa ONNX)
|-- outpaint.py (LaMa canvas expansion)
|-- ocr.py (PaddleOCR / Tesseract)
|-- ocr_pdf.py (page-by-page document OCR)
|-- ocr_preprocess.py (image enhancement for OCR)
|-- detect_faces.py (MediaPipe)
|-- face_landmarks.py (MediaPipe landmarks)
|-- enhance_faces.py (GFPGAN / CodeFormer)
@@ -52,7 +62,7 @@ AI 模型按共享依赖栈打包,而不是每个工具一个归档。当多
Docker 镜像随附应用程序以及通用运行时。大型模型归档会按需下载到常驻的 `/data/ai` 卷中,然后供每个需要它的工具复用。如果某个包因为另一个工具需要而已经安装,那么启用一个新的依赖工具时不会再次下载该包。
每个 AI 工具在运行前都需要一个或多个功能包。管理后台 UI 通过 `POST /api/v1/admin/tools/:toolId/features/install` 工具进行安装,它解析完整的包列表,跳过已安装的包,仅将缺失的下载排入队列。例如,在新实例上启用护照照片会将 `background-removal``face-detection` 排入队列;在已安装抠图之后再启用它,则只会将 `face-detection` 排入队列
大多数人工智能工具都需要一个或多个功能包才能运行。 管理 UI 通过 `POST /api/v1/admin/tools/:toolId/features/install` 工具安装这些包,它解析完整的捆绑包列表,跳过已安装的捆绑包,并仅对缺少的下载进行排队。 例如,在新实例队列 `background-removal``face-detection` 上启用 Passport Photo; 在已安装后台删除后启用它仅排队 `face-detection`。 OCR 是例外,因为 `fast` 不需要包装; 通过 UI 或 `POST /api/v1/admin/features/ocr/install` 安装其可选的精确运行时
| 功能包 | 大小 | 共享依赖组 | 使用它的工具 |
|--------|------|-------------------------|-------------------|
@@ -61,7 +71,7 @@ Docker 镜像随附应用程序以及通用运行时。大型模型归档会按
| `object-eraser-colorize` | 1-2 GB | LaMa 图像修复/外扩与 DDColor | erase-object、colorize、ai-canvas-expand |
| `upscale-enhance` | 5-6 GB | RealESRGAN、GFPGAN / CodeFormer、降噪 | upscale、enhance-faces、noise-removal |
| `photo-restoration` | 4-5 GB | 划痕修复与修复流水线 | restore-photo |
| `ocr` | 5-6 GB | PaddleOCR / Tesseract OCR | ocr、ocr-pdf |
| `ocr` | ~208-234 MiB 下载 / ~409-488 MiB 安装 | 可选 RapidOCR 3.9.1、ONNX Runtime 1.20.1 和固定 PP-OCR 型号 | ocr、ocr-pdf(仅限 `balanced``best` |
| `transcription` | ~600 MB | faster-whisper 语音转文本模型 | transcribe-audio、auto-subtitles |
具有跨包依赖的工具:
@@ -71,7 +81,17 @@ Docker 镜像随附应用程序以及通用运行时。大型模型归档会按
| `passport-photo` | `background-removal``face-detection` | 先移除背景,然后使用人脸关键点将裁剪对齐到护照和证件照规则。 |
| `enhance-faces` | `upscale-enhance``face-detection` | 在对选定的人脸区域运行 GFPGAN 或 CodeFormer 增强之前先检测人脸。 |
只有当某个工具的全部所需功能包都已安装时,该工具才可用。部分安装是有效的,并会以增量方式处理:已安装的包会被复用,失的包显示为下载,排队安装逐个执行,从而避免并发修改共享的 Python 环境。
仅当安装了工具所需的所有捆绑包(OCR 除外)后,该工具才可用:其内置 `fast` 层在没有可选 OCR 包的情况下仍然可用。 部分安装是有效的,并且是增量处理:已安装的捆绑包被重用,失的捆绑包显示为下载,排队安装一次运行一个,因此共享的 Python 环境不会同时修改
### 准确的 OCR 运行时安装{#accurate-ocr-runtime-installation}
准确的 OCR 包是官方 Linux amd64 或 Linux arm64 容器的特定于平台的运行时。 amd64 构建使用 Python 3.12 arm64 版本使用 Python 3.11。 两个版本都通过 ONNX Runtime 的 `CPUExecutionProvider` 运行 RapidOCR,因此同一包可在仅 CPU 和 NVIDIA Docker 主机上运行。 准确的运行时需要至少 4 GiB 的有效内存:配置的容器 cgroup 限制,否则为主机内存。 低于该签名兼容性最低值的系统在下载前会被拒绝。 此要求不适用于内置 Fast OCR。 Bare-metal 构建被拒绝,因为它们的 libc 和 Python ABI 无法安全推断; 当主机提供 Tesseract 和 Ghostscript 时,快速 OCR 保持可用。
可选工件大约压缩 208-234 MiB 并提取 409-488 MiB,具体取决于架构。 签名索引绑定安装程序强制执行的精确压缩和提取字节计数。 内置 Tesseract 在官方镜像上增加了约25个 MiB,并且不需要`/data/ai`中的文件。
在线安装会获取已签名的版本索引以及当前平台的精确内容寻址工件。 SnapOtter 在原子激活新一代之前验证 Ed25519 索引签名、工件大小、SHA-256 摘要、模型摘要、路径、文件模式和暂存 smoke test。 失败的安装会使之前的健康生成保持活动状态。
对于气隙安装,请使用名为 `index``archive` 的多部分字段将版本的 `ocr-runtime-index.json` 和匹配的 OCR 运行时存档上传到 `POST /api/v1/admin/features/import`。 离线导入应用与在线安装相同的签名、哈希、提取、兼容性和冒烟测试检查; 没有可信签名索引的存档将被拒绝。
---
@@ -143,16 +163,16 @@ Docker 镜像随附应用程序以及通用运行时。大型模型归档会按
## OCR / 文本提取 {#ocr-text-extraction}
**工具路由:** `ocr`
**型:** Tesseract(快速)、PaddleOCR PP-OCRv5(均衡)、PaddleOCR-VL 1.5(最佳)
**型** Tesseract (`fast`) RapidOCR PP-OCRv6 小型号(`balanced`);具有校准变体评分的 PP-OCRv6 中型模型 (`best`)
| 参数 | 类型 | 默认值 | 说明 |
|-----------|------|---------|-------------|
| `quality` | `"fast"` \| `"balanced"` \| `"best"` | `"balanced"` | 处理档次 |
| `quality` | `"fast"` \| `"balanced"` \| `"best"` | 动态的 | 省略 `quality``engine` 时,SnapOtter 会按 `best``balanced``fast` 的顺序选择可用的最高质量层。韩语绝不会选择 `fast`;它会使用 `best`,其次是 `balanced`,否则返回精确运行时的安装或兼容性错误。 |
| `language` | string | `"auto"` | 语言:`auto``en``de``fr``es``zh``ja``ko` |
| `enhance` | boolean | `true` | 预处理图像以提升 OCR 准确率 |
| `engine` | string | - | 已弃用。将 `tesseract` 映射到 `fast` `paddleocr` 映射到 `balanced` |
| `enhance` | 布尔值 | 取决于层级 | 提高局部对比度。快速直接应用;仅当校准得分提高 OCR 时,准确的等级才会保留变体。默认为“最佳” |
| `engine` | 细绳 | - | 已弃用的兼容性别名。将 `tesseract` 映射到 `fast`并将旧版 `paddleocr` 映射到 `balanced`;它不加载 PaddlePaddle |
返回带有边界框、置信度分数和提取文本块的结构化结果
返回提取文本以及来源元数据:引擎、请求的和实际的质量、设备、提供商、降级状态、警告和准确的运行时/模型版本(如果适用)。 明确的质量要求永远不会退回到另一层。 如果 `balanced``best` 不可用,则 API 返回 `FEATURE_NOT_INSTALLED``FEATURE_INCOMPATIBLE`,而不是静默运行 `fast`
## PDF OCR {#pdf-ocr}
@@ -163,9 +183,13 @@ Docker 镜像随附应用程序以及通用运行时。大型模型归档会按
| 参数 | 类型 | 默认值 | 说明 |
|-----------|------|---------|-------------|
| `quality` | `"fast"` \| `"balanced"` \| `"best"` | `"balanced"` | 处理档次 |
| `quality` | `"fast"` \| `"balanced"` \| `"best"` | 动态的 | 省略 `quality``engine` 时,SnapOtter 会按 `best``balanced``fast` 的顺序选择可用的最高质量层。韩语绝不会选择 `fast`;它会使用 `best`,其次是 `balanced`,否则返回精确运行时的安装或兼容性错误。 |
| `language` | string | `"auto"` | 语言:`auto``en``de``fr``es``zh``ja``ko` |
| `pages` | string | `"all"` | 页面选择:`"all"``"1-3"``"1,3,5"` |
| `enhance` | 布尔值 | 取决于层级 | 提高局部对比度。快速直接应用;仅当校准得分提高 OCR 时,准确的等级才会保留变体。默认为“最佳” |
| `engine` | 细绳 | - | 已弃用的兼容性别名。将 `tesseract` 映射到 `fast`,并将旧版 `paddleocr` 值映射到 `balanced`;它不加载 PaddlePaddle |
同样的不降级规则适用于 PDF OCR。 PDF 页面在识别前会进行光栅化处理,一次请求最多可以选择50个页面。
## 人脸 / PII 模糊 {#face-pii-blur}
+20 -5
View File
@@ -1,8 +1,8 @@
---
description: "完整的 REST API 参考。工具端点、批处理、流水线、文件库、身份验证、团队以及管理操作。"
i18n_source_hash: 8646977f7cc9
i18n_provenance: machine
i18n_output_hash: c43973438a42
i18n_source_hash: b89b5df16af5
i18n_provenance: human
---
# REST API 参考 {#rest-api-reference}
@@ -178,7 +178,7 @@ curl -X POST http://localhost:1349/api/v1/tools/<section>/<toolId>/batch \
| `remove-background` | 移除背景 | rembg (BiRefNet / U2-Net) | `model``backgroundType`transparent/color/gradient/blur/image)、`backgroundColor``gradientColor1``gradientColor2``gradientAngle``blurEnabled``blurIntensity``shadowEnabled``shadowOpacity` |
| `upscale` | 图片放大 | RealESRGAN | `scale`2/4)、`model``faceEnhance``denoise``format``quality` |
| `erase-object` | 对象擦除 | LaMa (ONNX) | 蒙版作为第二个文件部分发送(字段名 `mask`)、`format``quality` |
| `ocr` | OCR / 文本提取 | PaddleOCR / Tesseract | `quality`fast/balanced/best)、`language``enhance` |
| `ocr` | OCR / 文本提取 | Tesseract(快速); RapidOCR + PP-OCR ONNX(平衡/最佳) | `quality`(快速/平衡/最佳)、`language``enhance` |
| `blur-faces` | 人脸 / PII 模糊 | MediaPipe | `blurRadius``sensitivity` |
| `smart-crop` | 智能裁剪 | MediaPipe + Sharp | `mode`subject/face/trim)、`strategy`attention/entropy)、`width``height``padding``facePreset`closeup/head-shoulders/upper-body/half-body)、`sensitivity``threshold``padToSquare``padColor``targetSize``quality` |
| `image-enhancement` | 图片增强 | 基于分析 | `mode`auto/exposure/contrast/color/sharpness)、`strength` |
@@ -425,7 +425,9 @@ curl -X POST http://localhost:1349/api/v1/tools/image/html-to-image \
## 批处理 {#batch-processing}
将某个支持批处理的通用工具一次性应用到多个文件。返回一个 ZIP 归档。自定义的多文件或多步路由(例如 PDF 签名、PDF OCR 以及 PDF 转图片预设路由)使用它们自己的端点约定,而非通用的 `/batch` 路由。
将某个支持批处理的通用工具一次性应用到多个文件。返回一个 ZIP 归档。自定义的多文件或多步路由(例如 PDF 签名以及 PDF 转图片预设路由)使用它们自己的端点约定,而非通用的 `/batch` 路由。
`ocr-pdf` 工具支持此通用 `/batch` 路由。
```bash
curl -X POST http://localhost:1349/api/v1/tools/image/compress/batch \
@@ -594,6 +596,8 @@ data: {"jobId":"...","type":"batch","status":"processing","completedFiles":2,"to
管理 AI 功能捆绑包(在 Docker 环境中安装/卸载 AI 模型包)。从自定义自动化启用某个工具时,优先使用工具级安装端点:某些 AI 工具需要多个共享捆绑包,而该端点会跳过已安装的捆绑包,仅将缺失的排队安装。
OCR 是可选增强功能而不是硬依赖项。 其 `fast` Tesseract 层无需包装即可工作; `POST /api/v1/admin/features/ocr/install` 在 Linux amd64 或 arm64 上安装 `balanced``best` 的签名 RapidOCR 包。 准确的 OCR 运行时在仅 CPU 和 NVIDIA 主机上使用 CPU,并且需要至少 4 GiB 的有效内存(配置的容器 cgroup 限制,否则主机内存)。 SnapOtter 报告 `requiredMemoryBytes``effectiveMemoryBytes``insufficient-memory` 兼容性原因,并在下载前拒绝不兼容的安装。 此内存要求不适用于 `fast`。 该包大约需要下载 208-234 MiB 和安装 409-488 MiB,具体取决于目标; 签名索引绑定安装期间强制执行的确切大小。
| 方法 | 路径 | 访问权限 | 说明 |
|--------|------|--------|-------------|
| `GET` | `/api/v1/features` | 需身份验证 | 列出所有功能捆绑包及其安装状态 |
@@ -601,7 +605,18 @@ data: {"jobId":"...","type":"batch","status":"processing","completedFiles":2,"to
| `POST` | `/api/v1/admin/tools/:toolId/features/install` | 管理员(`features:manage`) | 安装某工具所需的每个捆绑包;返回每个捆绑包的已排队/已跳过状态 |
| `POST` | `/api/v1/admin/features/:bundleId/uninstall` | 管理员(`features:manage`) | 卸载一个功能捆绑包并清理模型文件 |
| `GET` | `/api/v1/admin/features/disk-usage` | 管理员(`features:manage`) | 获取 AI 模型的总磁盘占用 |
| `POST` | `/api/v1/admin/features/import` | 管理员`features:manage` | 导入一个离线 AI 捆绑包归档 |
| `POST` | `/api/v1/admin/features/import` | 管理员 (`features:manage`) | 导入旧版 AI 捆绑包 (`file`) 或已签名的离线 OCR 版本(`index``archive` |
气隙 OCR 导入必须包含版本的签名 `ocr-runtime-index.json` 和匹配的平台存档。 SnapOtter 应用与在线安装相同的 Ed25519 签名、工件哈希、兼容性、提取和冒烟测试检查:
```bash
curl -X POST http://localhost:1349/api/v1/admin/features/import \
-H "Authorization: Bearer <admin-token>" \
-F "index=@ocr-runtime-index.json" \
-F "archive=@ocr-linux-amd64-cpu-py312.tar.gz"
```
在 arm64 上使用 `linux-arm64-cpu-py311` 存档。另一个目标的签名工件被拒绝而不是安装。
## 管理操作 {#admin-operations}