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
+6 -6
View File
@@ -1,8 +1,8 @@
---
description: "SnapOtter 的 monorepo 结构、应用与包架构、请求生命周期以及资源占用。"
i18n_source_hash: 9e8f80499a37
i18n_provenance: human
i18n_output_hash: bc9e6a754251
i18n_source_hash: 733cb3c10884
i18n_provenance: human
---
# 架构 {#architecture}
@@ -36,13 +36,13 @@ snapotter/
### `@snapotter/ai` {#snapotter-ai}
一个用于为 ML 操作调用 Python 脚本的桥接层。首次使用时,桥接层会启动一个常驻的 Python dispatcher 进程,预先导入重量级库(PIL、NumPy、MediaPipe、rembg),从而让后续的 AI 调用跳过导入开销。如果 dispatcher 尚未就绪,桥接层会回退到为每个请求生成一个全新的 Python 子进程
调用本机和 Python ML 运行时的桥接层。 大多数 Python 工具使用持久性 dispatcher 来预导入重库(PIL、NumPy、MediaPipe、rembg),因此后续调用跳过导入开销。 OCR 与可变共享环境隔离:`fast` 调用本机 Tesseract,而 `balanced``best` 使用固定到活动不可变 RapidOCR/ONNX 生成的专用持久 JSONL dispatcher。 每个请求都包含一个 generation lease。 激活首先在候选者上运行 smoke test,然后自动切换到其 dispatcher。 先前的 dispatcher 在其生成被垃圾收集之前耗尽
**模型不会被预加载。** 每个工具脚本在请求时从磁盘加载其模型权重,并在请求结束时释放。完整的内存概况见[资源占用](#resource-footprint)。
支持的操作:背景移除(rembg/BiRefNet、放大RealESRGAN、人脸模糊MediaPipe、人脸增强GFPGAN/CodeFormer、对象擦除LaMa ONNX、OCRPaddleOCR/Tesseract)、上色(DDColor、噪声除、红眼除、照片修复、证件照生成、透明度修复(BiRefNet HR-matting以及内容感知缩放Go caire 二进制)。
支持的操作:背景去除 (rembg/BiRefNet)、放大 (RealESRGAN)、人脸模糊 (MediaPipe)、人脸增强 (GFPGAN/CodeFormer)、对象擦除 (LaMa ONNX)、OCR带有 PP-OCR ONNX 型号的 Tesseract 和 RapidOCR)、着色 (DDColor)、噪声除、红眼除、照片修复、护照照片生成、透明度修复(BiRefNet HR-matting内容感知调整大小Go caire 二进制)。
Python 脚本位于 `packages/ai/python/`。Docker 镜像会在构建期间预下载所有模型权重,因此容器可完全离线工作
Python 脚本位于 `packages/ai/python/` 中。大型可选模型包根据需要安装到持久 `/data/ai` 卷中。准确的 OCR 使用签名的、特定于平台的工件;内置 Tesseract 层无需下载模型包
### `@snapotter/shared` {#snapotter-shared}
@@ -87,7 +87,7 @@ Python 脚本位于 `packages/ai/python/`。Docker 镜像会在构建期间预
2. 前端向 `/api/v1/tools/:section/:toolId` 发送一个包含文件和设置的 multipart POST。
3. API 路由使用 Zod 校验输入,然后分派处理。
4. 对于标准工具,作业会被入队到相应的 BullMQ 池(根据模态选择 image、media 或 docs)。进程内的 BullMQ worker 会根据 EXIF 元数据自动定向图像、运行该工具的处理函数并返回结果。
5. 对于 AI 工具,TypeScript 桥接层会向常驻的 Python dispatcher 发送请求(或作为回退生成一个全新的子进程),等待其完成,并读取输出文件
5. 对于大多数 AI 工具,TypeScript 桥会向持久 Python dispatcher 发送请求。 快速 OCR 而是调用 Tesseract,而准确的 OCR 从活动的不可变 OCR 生成中启动固定的可执行文件。 请求的 OCR 层在入口处固定,并且在执行期间永远不会默默更改
6. 作业进度会被持久化到 PostgreSQL 中的 `jobs` 表,因此状态可在容器重启后保留。实时更新通过 `/api/v1/jobs/:jobId/progress` 处的 SSE 传递。
7. API 返回一个 `jobId``downloadUrl`。用户从 `/api/v1/download/:jobId/:filename` 下载处理后的文件。
+42 -10
View File
@@ -1,8 +1,8 @@
---
description: "使用 Docker 将 SnapOtter 部署到生产环境。涵盖硬件要求、GPU 配置,以及 Nginx、Traefik 和 Cloudflare 的反向代理配置。"
i18n_source_hash: 6b6957060fa6
i18n_provenance: machine
i18n_output_hash: 11dd631a0383
i18n_output_hash: 63267650bd5f
i18n_source_hash: e0d8d5f6fc87
i18n_provenance: human
---
# 部署 {#deployment}
@@ -11,6 +11,12 @@ SnapOtter 以 3 容器 Docker Compose 栈的形式部署:SnapOtter 应用镜
关于 GPU 配置、Docker Compose 示例和版本锁定,请参阅 [Docker 镜像](./docker-tags)。
<!-- 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 -->
## 快速开始(CPU {#quick-start-cpu}
```yaml
@@ -113,7 +119,7 @@ docker compose up -d
## 快速开始(NVIDIA CUDA {#quick-start-nvidia-cuda}
如需在 AI 工具(背景移除、放大、人脸增强、OCR)上启用 NVIDIA CUDA 加速:
对于支持的 AI 工具上的 NVIDIA CUDA 加速(背景去除、放大、面部增强)
```yaml
# docker-compose-gpu.yml - Requires: NVIDIA GPU + nvidia-container-toolkit
@@ -251,10 +257,10 @@ deploy:
|---|---|
| CPU | 4 核 |
| 内存 | 4 GB |
| 磁盘 | 3 GB像)+ 24 GBAI 模型+ 工作区 |
| Disk | 3 GB像)+ 20 GB所有可选 AI + 工作区 |
| GPU | 不需要(CPU 回退) |
**将内存推高到 4 GB 的正是安装 AI 包这一步** 未安装任何 AI 时,应用空闲占用约 360 MB;安装全部七个包后,常驻内存维持在 ~2.6 GB,因为 Python AI 边车会在启动时预加载其模型(背景移除、放大、OCR、转录、人脸检测、修复)。非 AI 安装保持轻量;AI 安装需要 ≥4 GB
**安装和运行更大的 AI 捆绑包将 RAM 的建议量推至 4 GB** 如果未安装可选包,则应用程序空闲时间约为 360 MB。 旧版 Python 工具共享 sidecar,而精确的 OCR 使用固定到活动不可变生成的专用长寿命 dispatcher。 在激活之前,安装程序会在候选程序上运行 smoke test。 然后,它自动切换到新的 dispatcher,并在 garbage collection 之前耗尽之前的 dispatcher。 每个官方准确的 OCR 工件都必须在 4 GiB cgroup 内通过最坏情况的 release suite,而 4 GB 主机建议为 Node.js 应用程序、Postgres、Redis、队列和并发工作留出空间
大多数 AI 工具在 CPU 上完全可用;只有少数几个确实需要 GPU。在现代 4 核 CPU 上测得:
@@ -271,7 +277,7 @@ SnapOtter 有意不将这些模型下载烘焙进 Docker 镜像。AI 包仅在
有些工具依赖不止一个共享包。例如,证件照同时需要 `background-removal``face-detection`;如果 `background-removal` 已安装,启用证件照就只会下载缺失的 `face-detection` 包。同样的复用规则适用于所有 AI 工具。
AI 模型下载大小
可选 AI 包存储估算
| 包 | 磁盘大小 |
|---|---|
@@ -279,9 +285,16 @@ AI 模型下载大小:
| 放大 + 人脸增强 + 降噪 | 5-6 GB |
| 人脸检测 | 200-300 MB |
| 对象擦除 + 上色 | 1-2 GB |
| OCR | 5-6 GB |
| 精确 OCR`balanced`/`best` | ~208-234 MiB 下载 / ~409-488 MiB 安装 |
| 照片修复 | 4-5 GB |
| **全部包** | **~24 GB** |
| 转录 | 〜600MB |
| **所有捆绑包** | **已安装~20 GB** |
Fast OCR 通过 Tesseract 内置到映像中,增加约 25 个 MiB,并且不需要可选的 OCR 包或其 4 个 GiB 内存要求。 准确的包可以在官方找到 Linux amd64 和 arm64 容器和运行 ONNX Runtime 在 CPU。 NVIDIA 主机使用相同的 CPU OCR 运行时,因此 OCR 不依赖于 CUDA 版本或 GPU 架构。 准确的运行时需要至少 4 GiB 的有效内存:配置的容器 cgroup 限制,否则为主机内存。 在下载包之前,SnapOtter 拒绝低于签名兼容性最低值的系统。 在无法保证 libc 和 Python ABI 的 bare-metal/预建存档上,也会拒绝准确的包安装。
共享同一 `DATA_DIR` 的副本必须使用相同的 CPU 架构;请通过节点亲和性将多副本部署固定到兼容节点。混合使用 amd64/arm64 的副本需要独立的数据卷和彼此独立的 SnapOtter 部署。
精确的运行时保持一代处于活动状态,并在激活后清除其下载缓存。 对于此版本,首次安装暂时需要大约 620-720 MiB 用于存档和暂存,升级可以在老一代保持活动状态时达到接近 1.2 GiB 的峰值。 安装程序在下载或提取之前根据签名索引和当前代计算确切的要求,如果数据量太小,安装程序会提前失败。
```yaml
deploy:
@@ -353,7 +366,6 @@ SnapOtter 支持 **55+ 种输入格式** 和 **14 种输出格式**,包括来
- **内容感知缩放** 在大图(>5 MP)上会崩溃,原因是 caire 二进制文件的一个限制。较小的图像可以正常工作。
- **HEIF 解码** 耗时 13-23 秒。HEICApple 的变体)快得多,为 0.3-0.9 秒。
- **OCR 日语** 在 CPU 上失败,原因是 PaddlePaddle 的一个 MKLDNN 缺陷。在 GPU 上可以正常工作。
- **放大** 在 CPU 上处理小图以外的任何图像都会超时。实际使用需要 GPU。
- **CodeFormer** 人脸增强显著慢于 GFPGANGPU 上 53 秒 vs 2 秒)。大多数使用场景推荐 GFPGAN。
@@ -434,6 +446,26 @@ securityContext:
| `SESSION_DURATION_HOURS` | `168` | 登录会话有效期(7 天) |
| `CORS_ORIGIN` | (空) | 逗号分隔的允许来源,或留空表示同源 |
### 出站代理和私有 CA {#outbound-proxy-and-private-ca}
官方容器启用了 Node 的环境代理支持。 如果 SnapOtter 必须通过企业代理到达 OCR 运行时存储库或其他 HTTPS 服务,请设置 `HTTPS_PROXY`(并在需要时设置 `HTTP_PROXY`)。 将 `NO_PROXY` 设置为必须直接访问的以逗号分隔的主机列表,例如 Postgres、Redis 和内部对象存储。
如果代理或内部服务由私有证书颁发机构签名,请将 CA 证书挂载为只读并将 `NODE_EXTRA_CA_CERTS` 指向它。 Node进程启动时该文件必须存在:
```yaml
services:
app:
environment:
HTTPS_PROXY: http://proxy.example.internal:3128
HTTP_PROXY: http://proxy.example.internal:3128
NO_PROXY: postgres,redis,minio,localhost,127.0.0.1
NODE_EXTRA_CA_CERTS: /etc/snapotter/custom-ca.pem
volumes:
- ./company-ca.pem:/etc/snapotter/custom-ca.pem:ro
```
将代理凭据保留在 Compose 文件外部(例如,在受保护的 `.env` 文件或机密中)。不要禁用 TLS 验证:签名的 OCR 索引对发布元数据进行身份验证,而正常的 TLS 验证仍然保护传输和所有其他出站请求。
## 健康检查 {#health-check}
容器内置了健康检查:
+4 -4
View File
@@ -1,8 +1,8 @@
---
description: "SnapOtter Docker 镜像标签、GPU 基准测试、版本锁定,以及对 AMD64 和 ARM64 的多平台支持。"
i18n_source_hash: 148b3608e11a
i18n_provenance: human
i18n_output_hash: 444ed01d924d
i18n_source_hash: fda322e78b4b
i18n_provenance: human
---
# Docker 镜像 {#docker-image}
@@ -41,7 +41,6 @@ docker run -d --name SnapOtter --gpus all -p 1349:1349 -v SnapOtter-data:/data s
| 背景去除(isnet | 2,457ms | 1,137ms | 2.2x |
| 放大 2x | 350ms | 309ms | 1.1x |
| 放大 4x | 910ms | 310ms | 2.9x |
| OCRPaddleOCR | 137ms | 94ms | 1.5x |
| 人脸模糊 | 139ms | 122ms | 1.1x |
#### 冷启动(容器启动后的首次请求) {#cold-start-first-request-after-container-start}
@@ -50,7 +49,8 @@ docker run -d --name SnapOtter --gpus all -p 1349:1349 -v SnapOtter-data:/data s
|------|-----|-----|---------|
| 背景去除 | 22,286ms | 4,792ms | 4.7x |
| 放大 2x | 3,957ms | 2,318ms | 1.7x |
| OCRPaddleOCR | 1,469ms | 1,090ms | 1.3x |
OCR 不包含在 CUDA 比较中。内置 Tesseract 层和可选的 RapidOCR/ONNX 层都使用 CPU,包括当容器具有 NVIDIA GPU 访问权限时。
### CUDA 健康检查 {#cuda-health-check}
+3 -3
View File
@@ -1,8 +1,8 @@
---
description: "用一条 Docker 命令安装 SnapOtter。包含 Docker Compose 配置、从源码构建,以及完整的功能概览。"
i18n_source_hash: 4536d4558b8e
i18n_provenance: machine
i18n_output_hash: 3da9d8045239
i18n_source_hash: 24724b5595b2
i18n_provenance: human
---
# 快速上手 {#getting-started}
@@ -32,7 +32,7 @@ SnapOtter 默认包含匿名产品分析。要关闭它,请打开 **Settings
:::
::: tip NVIDIA CUDA 加速
添加 `--gpus all`获得 NVIDIA CUDA 加速的背景除、放大、OCR、人脸增强和修复
添加 `--gpus all`实现 NVIDIA CUDA 加速的背景除、放大、面部增强和恢复。 OCR 仍然基于 CPU,并且在有或没有 GPU 访问的情况下在同一映像中工作
```bash
docker run -d --name SnapOtter -p 1349:1349 --gpus all -v SnapOtter-data:/data snapotter/snapotter:latest