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: "Estrutura do monorepo, arquitetura de apps e pacotes, ciclo de vida das requisições e uso de recursos do SnapOtter."
i18n_source_hash: 9e8f80499a37
i18n_provenance: human
i18n_output_hash: 93555b8e15c0
i18n_source_hash: 733cb3c10884
i18n_provenance: human
---
# Arquitetura {#architecture}
@@ -36,13 +36,13 @@ Este pacote não tem dependências de rede e roda inteiramente em processo.
### `@snapotter/ai` {#snapotter-ai}
Uma camada de ponte que chama scripts Python para operações de ML. No primeiro uso, a ponte inicia um processo de dispatcher Python persistente que pré-importa bibliotecas pesadas (PIL, NumPy, MediaPipe, rembg) para que as chamadas de IA subsequentes dispensem o custo de importação. Se o dispatcher ainda não estiver pronto, a ponte recorre a gerar um novo subprocesso Python por requisição.
Uma camada de ponte que chama tempos de execução nativos e Python ML. A maioria das ferramentas Python usa um dispatcher persistente que pré-importa bibliotecas pesadas (PIL, NumPy, MediaPipe, rembg) para que as chamadas subsequentes ignorem a sobrecarga de importação. OCR é isolado desse ambiente compartilhado mutável: `fast` invoca Tesseract nativo, enquanto `balanced` e `best` usam um JSONL dispatcher persistente dedicado fixado na geração RapidOCR/ONNX ativa e imutável. Cada solicitação contém um generation lease. A ativação primeiro executa um smoke test em um candidato e depois alterna atomicamente para seu dispatcher. O dispatcher anterior é drenado antes que sua geração seja coletada como lixo.
**Os modelos não são pré-carregados.** Cada script de ferramenta carrega os pesos do seu modelo do disco no momento da requisição e os descarta quando a requisição termina. Consulte [Uso de recursos](#resource-footprint) para o perfil de memória completo.
Operações suportadas: remoção de fundo (rembg/BiRefNet), upscaling (RealESRGAN), desfoque de rostos (MediaPipe), aprimoramento de rostos (GFPGAN/CodeFormer), apagamento de objetos (LaMa ONNX), OCR (PaddleOCR/Tesseract), colorização (DDColor), remoção de ruído, remoção de olhos vermelhos, restauração de fotos, geração de foto de passaporte, correção de transparência (HR-matting do BiRefNet) e redimensionamento com reconhecimento de conteúdo (binário caire em Go).
Operações suportadas: remoção de fundo (rembg/BiRefNet), upscaling (RealESRGAN), desfoque de rosto (MediaPipe), aprimoramento de rosto (GFPGAN/CodeFormer), apagamento de objeto (LaMa ONNX), OCR (Tesseract e RapidOCR com modelos PP-OCR ONNX), colorização (DDColor), remoção de ruído, remoção de olhos vermelhos, restauração de fotos, foto de passaporte geração, correção de transparência (BiRefNet HR-matting) e redimensionamento com reconhecimento de conteúdo (Go caire binário).
Os scripts Python ficam em `packages/ai/python/`. A imagem Docker pré-baixa todos os pesos de modelo durante o build para que o contêiner funcione totalmente offline.
Os scripts Python residem em `packages/ai/python/`. Grandes pacotes de modelos opcionais são instalados sob demanda no volume `/data/ai` persistente. O OCR preciso usa artefatos assinados e específicos da plataforma; a camada Tesseract integrada não requer download de pacote de modelo.
### `@snapotter/shared` {#snapotter-shared}
@@ -87,7 +87,7 @@ Este site VitePress. Implantado no Cloudflare Pages automaticamente a cada push
2. O frontend envia um POST multipart para `/api/v1/tools/:section/:toolId` com o arquivo e as configurações.
3. A rota da API valida a entrada com o Zod e depois despacha o processamento.
4. Para ferramentas padrão, o job é enfileirado no pool BullMQ apropriado (image, media ou docs, conforme a modalidade). O worker BullMQ em processo orienta automaticamente a imagem com base nos metadados EXIF, executa a função de processamento da ferramenta e retorna o resultado.
5. Para ferramentas de IA, a ponte TypeScript envia uma requisição ao dispatcher Python persistente (ou gera um novo subprocesso como fallback), aguarda a conclusão e lê o arquivo de saída.
5. Para a maioria das ferramentas de IA, a ponte TypeScript envia uma solicitação ao Python dispatcher persistente. Em vez disso, o OCR rápido invoca Tesseract, e o OCR preciso inicia o executável fixado a partir da geração OCR imutável ativa. A camada OCR solicitada é fixada na entrada e nunca é alterada silenciosamente durante a execução.
6. O progresso do job é persistido na tabela `jobs` no PostgreSQL, de modo que o estado sobrevive a reinícios do contêiner. As atualizações em tempo real são entregues via SSE em `/api/v1/jobs/:jobId/progress`.
7. A API retorna um `jobId` e um `downloadUrl`. O usuário baixa o arquivo processado de `/api/v1/download/:jobId/:filename`.
+42 -10
View File
@@ -1,8 +1,8 @@
---
description: "Implante o SnapOtter em produção com Docker. Requisitos de hardware, configuração de GPU e configs de proxy reverso para Nginx, Traefik e Cloudflare."
i18n_source_hash: 6b6957060fa6
i18n_provenance: machine
i18n_output_hash: 05bdb8a0d544
i18n_output_hash: b3176447b423
i18n_source_hash: e0d8d5f6fc87
i18n_provenance: human
---
# Implantação {#deployment}
@@ -11,6 +11,12 @@ O SnapOtter é implantado como uma stack Docker Compose de 3 contêineres: a ima
Consulte [Imagem Docker](./docker-tags) para configuração de GPU, exemplos de Docker Compose e fixação de versão.
<!-- korean-ocr-contract:start -->
::: info Compatibilidade do OCR em coreano
O OCR rápido oferece suporte a `auto`, `en`, `de`, `es`, `fr`, `zh` e `ja`, mas não a coreano (`ko`). Coreano exige o pacote de OCR preciso e `balanced` ou `best`. O pacote funciona nos contêineres oficiais Linux amd64 e arm64, inclusive em hosts NVIDIA, onde o OCR continua na CPU. Sistemas não compatíveis recebem um erro explícito e nunca retornam silenciosamente para `fast`. Coreano com `fast` ou com o alias legado `tesseract` é rejeitado antes da fila com `FEATURE_INCOMPATIBLE` e `fast-korean-unsupported`.
:::
<!-- korean-ocr-contract:end -->
## Início Rápido (CPU) {#quick-start-cpu}
```yaml
@@ -113,7 +119,7 @@ O app fica então disponível em `http://localhost:1349`.
## Início Rápido (NVIDIA CUDA) {#quick-start-nvidia-cuda}
Para aceleração NVIDIA CUDA em ferramentas de IA (remoção de fundo, upscaling, aprimoramento de rosto, OCR):
Para aceleração NVIDIA CUDA em ferramentas de IA suportadas (remoção de fundo, aumento de escala, aprimoramento de rosto):
```yaml
# docker-compose-gpu.yml - Requires: NVIDIA GPU + nvidia-container-toolkit
@@ -251,10 +257,10 @@ deploy:
|---|---|
| CPU | 4 núcleos |
| RAM | 4 GB |
| Disco | 3 GB (imagem) + 24 GB (modelos de IA) + workspace |
| Disk | 3 GB (imagem) + cerca de 20 GB (todos os pacotes AI opcionais) + espaço de trabalho |
| GPU | Não obrigatória (fallback para CPU) |
**Instalar os bundles de IA é o que empurra a RAM para 4 GB.** Sem nenhuma IA instalada, o app fica ocioso em torno de 360 MB; com todos os sete bundles instalados, ele mantém ~2,6 GB residentes, porque o sidecar de IA em Python pré-carrega seus modelos (remoção de fundo, upscaling, OCR, transcrição, detecção de rosto, restauração) na inicialização. Instalações sem IA permanecem leves; instalações de IA precisam de ≥4 GB.
**Instalar e executar pacotes maiores de IA é o que leva a recomendação para 4 GB de RAM.** Sem pacotes opcionais instalados, o aplicativo fica ocioso em torno de 360 MB. As ferramentas Python legadas compartilham um sidecar, enquanto o OCR preciso usa um dispatcher dedicado de longa duração fixado à geração imutável ativa. Antes da ativação, o instalador executa um smoke test no candidato. Em seguida, ele muda atomicamente para o novo dispatcher e drena o dispatcher anterior antes de garbage collection. Cada artefato oficial de OCR preciso deve passar seu pior caso release suite dentro de 4 GiB cgroup, enquanto a recomendação de host de 4 GB deixa espaço para o aplicativo Node.js, Postgres, Redis, filas e trabalho simultâneo.
A maioria das ferramentas de IA é perfeitamente utilizável em CPU; algumas realmente precisam de uma GPU. Medido em uma CPU moderna de 4 núcleos:
@@ -271,7 +277,7 @@ O SnapOtter intencionalmente não incorpora esses downloads de modelos na imagem
Algumas ferramentas dependem de mais de um bundle compartilhado. Por exemplo, Foto de Passaporte precisa tanto de `background-removal` quanto de `face-detection`; se `background-removal` já estiver instalado, habilitar Foto de Passaporte baixa apenas o bundle `face-detection` que faltava. A mesma reutilização se aplica a todas as ferramentas de IA.
Tamanhos de download dos modelos de IA:
Estimativas opcionais de armazenamento do pacote AI:
| Bundle | Tamanho em Disco |
|---|---|
@@ -279,9 +285,16 @@ Tamanhos de download dos modelos de IA:
| Upscale + Aprimoramento de rosto + Remoção de ruído | 5-6 GB |
| Detecção de rosto | 200-300 MB |
| Apagador de objetos + Colorizar | 1-2 GB |
| OCR | 5-6 GB |
| OCR preciso (`balanced`/`best`) | ~208-234 MiB baixado / ~409-488 MiB instalado |
| Restauração de foto | 4-5 GB |
| **Todos os bundles** | **~24 GB** |
| Transcrição | ~600MB |
| **Todos os pacotes** | **~20 GB instalados** |
O OCR rápido é integrado à imagem por meio do Tesseract, adiciona cerca de 25 MiB e não requer o pacote OCR opcional ou seu requisito de memória de 4 GiB. O pacote exato está disponível nos contêineres oficiais Linux amd64 e arm64 e executa ONNX Runtime em CPU. Os hosts NVIDIA usam o mesmo tempo de execução CPU OCR, portanto, OCR não depende da versão CUDA ou da arquitetura GPU. O tempo de execução preciso requer pelo menos 4 GiB de memória efetiva: o limite cgroup do contêiner configurado, caso contrário, memória do host. SnapOtter rejeita sistemas abaixo do mínimo de compatibilidade assinado antes de baixar o pacote. A instalação do pacote preciso também é rejeitada em arquivos bare-metal/pré-construídos cujos libc e Python ABI não podem ser garantidos.
As réplicas que compartilham o mesmo `DATA_DIR` devem usar a mesma arquitetura de CPU; fixe implantações com várias réplicas em nós compatíveis usando afinidade de nós. Réplicas amd64/arm64 mistas precisam de volumes de dados separados e implantações independentes do SnapOtter.
O tempo de execução preciso mantém uma geração ativa e limpa seu cache de download após a ativação. Para esta versão, uma primeira instalação precisa temporariamente de aproximadamente 620-720 MiB para o arquivo mais teste, e uma atualização pode atingir um pico próximo a 1,2 GiB enquanto a geração antiga permanece ativa. O instalador calcula o requisito exato do índice assinado e das gerações atuais antes de fazer download ou extrair e falha antecipadamente se o volume de dados for muito pequeno.
```yaml
deploy:
@@ -353,7 +366,6 @@ Consulte a [lista completa de formatos](/pt-BR/guide/supported-formats) para det
- **Redimensionamento consciente de conteúdo** trava em imagens grandes (>5 MP) devido a uma limitação no binário caire. Funciona bem com imagens menores.
- **Decodificação HEIF** leva de 13 a 23 segundos. HEIC (a variante da Apple) é muito mais rápido, de 0,3 a 0,9 segundos.
- **OCR em japonês** falha em CPU devido a um bug do MKLDNN do PaddlePaddle. Funciona em GPU.
- **Upscale** expira em CPU para qualquer coisa além de imagens pequenas. GPU é obrigatória para uso prático.
- O aprimoramento de rosto **CodeFormer** é significativamente mais lento que o GFPGAN (53s vs 2s em GPU). GFPGAN é recomendado para a maioria dos casos de uso.
@@ -434,6 +446,26 @@ O erro de inicialização nomeia o UID exato a usar, então o caminho mais rápi
| `SESSION_DURATION_HOURS` | `168` | Tempo de vida da sessão de login (7 dias) |
| `CORS_ORIGIN` | (vazio) | Origens permitidas separadas por vírgula, ou vazio para mesma origem |
### Proxy de saída e CA privada {#outbound-proxy-and-private-ca}
O contêiner oficial permite o suporte de proxy de ambiente do Node. Se SnapOtter precisar acessar o repositório de tempo de execução OCR ou outros serviços HTTPS por meio de um proxy corporativo, configure `HTTPS_PROXY` (e `HTTP_PROXY` quando necessário). Configure `NO_PROXY` para uma lista separada por vírgula de hosts que devem ser acessados diretamente, como Postgres, Redis e armazenamento de objeto interno.
Se o proxy ou um serviço interno for assinado por uma autoridade de certificação privada, monte o certificado CA somente leitura e aponte `NODE_EXTRA_CA_CERTS` para ele. O arquivo deve existir quando o processo do Node for iniciado:
```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
```
Mantenha as credenciais de proxy fora do arquivo Compose (por exemplo, em um arquivo ou segredo `.env` protegido). Não desative a verificação TLS: o índice OCR assinado autentica os metadados de lançamento, enquanto a validação TLS normal ainda protege o transporte e todas as outras solicitações de saída.
## Verificação de Saúde {#health-check}
O contêiner inclui uma verificação de saúde embutida:
+4 -4
View File
@@ -1,8 +1,8 @@
---
description: "Tags de imagem Docker do SnapOtter, benchmarks de GPU, fixação de versão e suporte multiplataforma para AMD64 e ARM64."
i18n_source_hash: 148b3608e11a
i18n_provenance: human
i18n_output_hash: 5f53a19b9daf
i18n_source_hash: fda322e78b4b
i18n_provenance: human
---
# Imagem Docker {#docker-image}
@@ -41,7 +41,6 @@ Testado em uma NVIDIA RTX 4070 (12 GB de VRAM) com um retrato JPEG de 572x1024.
| Remoção de fundo (isnet) | 2.457ms | 1.137ms | 2,2x |
| Upscale 2x | 350ms | 309ms | 1,1x |
| Upscale 4x | 910ms | 310ms | 2,9x |
| OCR (PaddleOCR) | 137ms | 94ms | 1,5x |
| Desfoque de rosto | 139ms | 122ms | 1,1x |
#### Inicialização a frio (primeira requisição após o início do contêiner) {#cold-start-first-request-after-container-start}
@@ -50,7 +49,8 @@ Testado em uma NVIDIA RTX 4070 (12 GB de VRAM) com um retrato JPEG de 572x1024.
|------|-----|-----|---------|
| Remoção de fundo | 22.286ms | 4.792ms | 4,7x |
| Upscale 2x | 3.957ms | 2.318ms | 1,7x |
| OCR (PaddleOCR) | 1.469ms | 1.090ms | 1,3x |
OCR não está incluído na comparação CUDA. Tanto a camada Tesseract integrada quanto as camadas RapidOCR/ONNX opcionais usam CPU, inclusive quando o contêiner tem acesso NVIDIA GPU.
### Verificação de integridade do CUDA {#cuda-health-check}
+3 -3
View File
@@ -1,8 +1,8 @@
---
description: "Instale o SnapOtter com Docker em um único comando. Inclui configuração de Docker Compose, build a partir do código-fonte e uma visão geral completa das features."
i18n_source_hash: 4536d4558b8e
i18n_provenance: machine
i18n_output_hash: 8584b5780f52
i18n_source_hash: 24724b5595b2
i18n_provenance: human
---
# Primeiros Passos {#getting-started}
@@ -32,7 +32,7 @@ Para detalhes sobre o que é coletado, veja [O que o SnapOtter coleta](/pt-BR/gu
:::
::: tip Aceleração NVIDIA CUDA
Adicione `--gpus all` para remoção de fundo, upscaling, OCR, aprimoramento de rosto e restauração acelerados por NVIDIA CUDA:
Adicione `--gpus all` para remoção de fundo, aumento de escala, aprimoramento de rosto e restauração acelerados por NVIDIA CUDA. OCR permanece baseado em CPU e funciona na mesma imagem com ou sem acesso GPU:
```bash
docker run -d --name SnapOtter -p 1349:1349 --gpus all -v SnapOtter-data:/data snapotter/snapotter:latest