mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
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:
@@ -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)、OCR(PaddleOCR/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` 下载处理后的文件。
|
||||
|
||||
|
||||
@@ -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 GB(AI 模型)+ 工作区 |
|
||||
| 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 秒。HEIC(Apple 的变体)快得多,为 0.3-0.9 秒。
|
||||
- **OCR 日语** 在 CPU 上失败,原因是 PaddlePaddle 的一个 MKLDNN 缺陷。在 GPU 上可以正常工作。
|
||||
- **放大** 在 CPU 上处理小图以外的任何图像都会超时。实际使用需要 GPU。
|
||||
- **CodeFormer** 人脸增强显著慢于 GFPGAN(GPU 上 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}
|
||||
|
||||
容器内置了健康检查:
|
||||
|
||||
@@ -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 |
|
||||
| OCR(PaddleOCR) | 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 |
|
||||
| OCR(PaddleOCR) | 1,469ms | 1,090ms | 1.3x |
|
||||
|
||||
OCR 不包含在 CUDA 比较中。内置 Tesseract 层和可选的 RapidOCR/ONNX 层都使用 CPU,包括当容器具有 NVIDIA GPU 访问权限时。
|
||||
|
||||
### CUDA 健康检查 {#cuda-health-check}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user