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: "Struttura del monorepo, architettura di app e pacchetti, ciclo di vita di una richiesta e impronta sulle risorse di SnapOtter."
i18n_source_hash: 9e8f80499a37
i18n_provenance: human
i18n_output_hash: 5a4f11a25575
i18n_source_hash: 733cb3c10884
i18n_provenance: human
---
# Architettura {#architecture}
@@ -36,13 +36,13 @@ Questo pacchetto non ha dipendenze di rete e gira interamente in-process.
### `@snapotter/ai` {#snapotter-ai}
Uno strato bridge che chiama gli script Python per le operazioni ML. Al primo uso, il bridge avvia un processo dispatcher Python persistente che pre-importa le librerie pesanti (PIL, NumPy, MediaPipe, rembg) così che le chiamate AI successive saltino l'overhead di importazione. Se il dispatcher non è ancora pronto, il bridge ripiega sull'avvio di un nuovo sottoprocesso Python per ogni richiesta.
Un livello bridge che chiama runtime nativi e Python ML. La maggior parte degli strumenti Python utilizzano un dispatcher persistente che preimporta librerie pesanti (PIL, NumPy, MediaPipe, rembg) in modo che le chiamate successive saltino il sovraccarico dell'importazione. OCR è isolato da quell'ambiente condiviso mutevole: `fast` richiama Tesseract nativo, mentre `balanced` e `best` utilizzano un JSONL dispatcher persistente dedicato aggiunto alla generazione attiva immutabile RapidOCR/ONNX. Ogni richiesta contiene un generation lease. L'attivazione esegue prima un smoke test su un candidato, quindi passa atomicamente al suo dispatcher. Il precedente dispatcher viene scaricato prima che la sua generazione venga sottoposta a garbage collection.
**I modelli non sono precaricati.** Ogni script dello strumento carica i pesi del proprio modello dal disco al momento della richiesta e li scarta quando la richiesta termina. Consulta [Impronta sulle risorse](#resource-footprint) per il profilo di memoria completo.
Operazioni supportate: rimozione dello sfondo (rembg/BiRefNet), upscaling (RealESRGAN), sfocatura dei volti (MediaPipe), miglioramento dei volti (GFPGAN/CodeFormer), cancellazione di oggetti (LaMa ONNX), OCR (PaddleOCR/Tesseract), colorazione (DDColor), rimozione del rumore, rimozione degli occhi rossi, restauro fotografico, generazione di foto tessera, correzione della trasparenza (matting HR di BiRefNet) e ridimensionamento content-aware (binario Go caire).
Operazioni supportate: rimozione dello sfondo (rembg/BiRefNet), upscaling (RealESRGAN), sfocatura del volto (MediaPipe), miglioramento del volto (GFPGAN/CodeFormer), cancellazione degli oggetti (LaMa ONNX), OCR (Tesseract e RapidOCR con modelli PP-OCR ONNX), colorazione (DDColor), rimozione del rumore, rimozione degli occhi rossi, restauro di foto, foto tessera generazione, correzione della trasparenza (BiRefNet HR-matting) e ridimensionamento in base al contenuto (Go caire binario).
Gli script Python risiedono in `packages/ai/python/`. L'immagine Docker pre-scarica tutti i pesi dei modelli durante la build così che il container funzioni completamente offline.
Gli script Python risiedono in `packages/ai/python/`. I pacchetti di modelli opzionali di grandi dimensioni vengono installati su richiesta nel volume `/data/ai` persistente. OCR accurato utilizza artefatti firmati specifici della piattaforma; il livello Tesseract integrato non richiede il download del pacchetto di modelli.
### `@snapotter/shared` {#snapotter-shared}
@@ -87,7 +87,7 @@ Questo sito VitePress. Distribuito su Cloudflare Pages automaticamente al push s
2. Il frontend invia un POST multipart a `/api/v1/tools/:section/:toolId` con il file e le impostazioni.
3. La route API valida l'input con Zod, poi avvia l'elaborazione.
4. Per gli strumenti standard, il lavoro viene accodato al pool BullMQ appropriato (image, media o docs in base alla modalità). Il worker BullMQ in-process orienta automaticamente l'immagine in base ai metadati EXIF, esegue la funzione di elaborazione dello strumento e restituisce il risultato.
5. Per gli strumenti AI, il bridge TypeScript invia una richiesta al dispatcher Python persistente (o avvia un nuovo sottoprocesso come fallback), attende che finisca e legge il file di output.
5. Per la maggior parte degli strumenti IA, il bridge TypeScript invia una richiesta al persistente Python dispatcher. OCR veloce richiama invece Tesseract e OCR accurato avvia l'eseguibile bloccato dalla generazione OCR immutabile attiva. Il livello OCR richiesto è fisso in ingresso e non viene mai modificato automaticamente durante l'esecuzione.
6. L'avanzamento del lavoro viene persistito nella tabella `jobs` in PostgreSQL così che lo stato sopravviva ai riavvii del container. Gli aggiornamenti in tempo reale vengono consegnati via SSE su `/api/v1/jobs/:jobId/progress`.
7. L'API restituisce un `jobId` e un `downloadUrl`. L'utente scarica il file elaborato da `/api/v1/download/:jobId/:filename`.
+42 -10
View File
@@ -1,8 +1,8 @@
---
description: "Distribuisci SnapOtter in produzione con Docker. Requisiti hardware, configurazione GPU e configurazioni di reverse proxy per Nginx, Traefik e Cloudflare."
i18n_source_hash: 6b6957060fa6
i18n_provenance: machine
i18n_output_hash: e874e52fefd6
i18n_output_hash: 28e72d02cd08
i18n_source_hash: e0d8d5f6fc87
i18n_provenance: human
---
# Distribuzione {#deployment}
@@ -11,6 +11,12 @@ SnapOtter si distribuisce come stack Docker Compose a 3 container: l'immagine de
Vedi [Immagine Docker](./docker-tags) per la configurazione GPU, esempi di Docker Compose e il pinning delle versioni.
<!-- korean-ocr-contract:start -->
::: info Compatibilità OCR per il coreano
OCR veloce supporta `auto`, `en`, `de`, `es`, `fr`, `zh` e `ja`, ma non il coreano (`ko`). Il coreano richiede il pacchetto OCR accurato e `balanced` o `best`. Il pacchetto funziona nei container Linux amd64 e arm64 ufficiali, inclusi gli host NVIDIA, dove lOCR resta sulla CPU. I sistemi non supportati ricevono un errore di compatibilità esplicito e non passano mai silenziosamente a `fast`. Il coreano con `fast` o con lalias legacy `tesseract` viene rifiutato prima dellaccodamento con `FEATURE_INCOMPATIBLE` e `fast-korean-unsupported`.
:::
<!-- korean-ocr-contract:end -->
## Avvio rapido (CPU) {#quick-start-cpu}
```yaml
@@ -113,7 +119,7 @@ L'app è quindi disponibile all'indirizzo `http://localhost:1349`.
## Avvio rapido (NVIDIA CUDA) {#quick-start-nvidia-cuda}
Per l'accelerazione NVIDIA CUDA sugli strumenti AI (rimozione dello sfondo, upscaling, miglioramento dei volti, OCR):
Per l'accelerazione NVIDIA CUDA sugli strumenti AI supportati (rimozione dello sfondo, upscaling, miglioramento del volto):
```yaml
# docker-compose-gpu.yml - Requires: NVIDIA GPU + nvidia-container-toolkit
@@ -251,10 +257,10 @@ deploy:
|---|---|
| CPU | 4 core |
| RAM | 4 GB |
| Disco | 3 GB (immagine) + 24 GB (modelli AI) + area di lavoro |
| Disk | 3 GB (immagine) + circa 20 GB (tutti i pacchetti AI opzionali) + spazio di lavoro |
| GPU | Non richiesta (fallback su CPU) |
**L'installazione dei bundle AI è ciò che porta la RAM a 4 GB.** Senza alcun AI installato, l'app resta inattiva intorno ai 360 MB; con tutti e sette i bundle installati mantiene ~2,6 GB residenti, perché il sidecar AI Python pre-carica i suoi modelli (rimozione dello sfondo, upscaling, OCR, trascrizione, rilevamento dei volti, restauro) all'avvio. Le installazioni non-AI restano leggere; le installazioni AI richiedono ≥4 GB.
**L'installazione e l'esecuzione dei bundle AI più grandi è ciò che spinge la raccomandazione a 4 GB di RAM.** Senza pacchetti opzionali installati, l'app rimane inattiva a circa 360 MB. Gli strumenti Python legacy condividono uno sidecar, mentre lo OCR accurato utilizza uno dispatcher dedicato di lunga durata fissato alla generazione immutabile attiva. Prima dell'attivazione, l'installatore esegue un smoke test sul candidato. Quindi passa atomicamente al nuovo dispatcher e drena il precedente dispatcher prima di garbage collection. Ogni artefatto OCR accurato ufficiale deve superare il suo caso peggiore release suite all'interno di un GiB cgroup da 4, mentre la raccomandazione host da 4 GB lascia spazio per l'applicazione Node.js, Postgres, Redis, code e lavoro simultaneo.
La maggior parte degli strumenti AI è perfettamente utilizzabile su CPU; un paio vogliono davvero una GPU. Misurato su una moderna CPU a 4 core:
@@ -271,7 +277,7 @@ SnapOtter volutamente non integra questi download di modelli nell'immagine Docke
Alcuni strumenti dipendono da più di un bundle condiviso. Ad esempio, Foto Tessera necessita sia di `background-removal` sia di `face-detection`; se `background-removal` è già installato, abilitare Foto Tessera scarica solo il bundle `face-detection` mancante. Lo stesso riutilizzo si applica a tutti gli strumenti AI.
Dimensioni di download dei modelli AI:
Stime facoltative di stoccaggio dei pacchetti AI:
| Bundle | Dimensione su disco |
|---|---|
@@ -279,9 +285,16 @@ Dimensioni di download dei modelli AI:
| Upscaling + Miglioramento volti + Rimozione rumore | 5-6 GB |
| Rilevamento volti | 200-300 MB |
| Gomma per oggetti + Colorizzazione | 1-2 GB |
| OCR | 5-6 GB |
| OCR preciso (`balanced`/`best`) | ~208-234 MiB scaricato / ~409-488 MiB installato |
| Restauro foto | 4-5 GB |
| **Tutti i bundle** | **~24 GB** |
| Trascrizione | ~600 MB |
| **Tutti i pacchetti** | **~20 GB installati** |
OCR veloce è integrato nell'immagine tramite Tesseract, aggiunge circa 25 MiB e non richiede il pacchetto OCR opzionale o i suoi 4 requisiti di memoria GiB. Il pacchetto accurato è disponibile nei contenitori ufficiali Linux amd64 e arm64 ed esegue ONNX Runtime su CPU. Gli host NVIDIA utilizzano lo stesso runtime CPU OCR, quindi OCR non dipende dalla versione CUDA o dall'architettura GPU. Il runtime accurato richiede almeno 4 GiB di memoria effettiva: il limite cgroup del contenitore configurato, altrimenti memoria host. SnapOtter rifiuta i sistemi al di sotto del minimo di compatibilità firmato prima di scaricare il pacchetto. L'installazione accurata del pacchetto viene rifiutata anche su bare-metal/archivi precostruiti i cui libc e Python ABI non possono essere garantiti.
Le repliche che condividono lo stesso `DATA_DIR` devono usare la stessa architettura CPU; vincola i deployment con più repliche a nodi compatibili tramite la node affinity. Le repliche miste amd64/arm64 richiedono volumi di dati separati e deployment SnapOtter indipendenti.
Il runtime accurato mantiene una generazione attiva e svuota la cache di download dopo l'attivazione. Per questa versione, una prima installazione richiede temporaneamente circa 620-720 MiB per l'archivio più lo staging, e un aggiornamento può raggiungere un picco vicino a 1.2 GiB mentre la vecchia generazione rimane attiva. Il programma di installazione calcola i requisiti esatti dall'indice firmato e dalle generazioni attuali prima del download o dell'estrazione e fallisce anticipatamente se il volume dei dati è troppo piccolo.
```yaml
deploy:
@@ -353,7 +366,6 @@ Vedi l'[elenco completo dei formati](/it/guide/supported-formats) per i dettagli
- **Il ridimensionamento content-aware** si blocca su immagini grandi (>5 MP) a causa di una limitazione nel binario caire. Funziona bene con immagini più piccole.
- **La decodifica HEIF** richiede 13-23 secondi. HEIC (la variante di Apple) è molto più veloce, tra 0,3 e 0,9 secondi.
- **L'OCR giapponese** fallisce su CPU a causa di un bug MKLDNN di PaddlePaddle. Funziona su GPU.
- **L'upscaling** va in timeout su CPU per qualsiasi cosa oltre le immagini piccole. GPU richiesta per un uso pratico.
- **Il miglioramento dei volti CodeFormer** è significativamente più lento di GFPGAN (53s contro 2s su GPU). GFPGAN è consigliato per la maggior parte dei casi d'uso.
@@ -434,6 +446,26 @@ L'errore di avvio indica l'UID esatto da usare, quindi il percorso più rapido
| `SESSION_DURATION_HOURS` | `168` | Durata della sessione di login (7 giorni) |
| `CORS_ORIGIN` | (vuoto) | Origini consentite separate da virgola, oppure vuoto per la stessa origine |
### Proxy in uscita e CA privata {#outbound-proxy-and-private-ca}
Il contenitore ufficiale abilita il supporto proxy dell'ambiente di Node. Se SnapOtter deve raggiungere il repository di runtime OCR o altri servizi HTTPS tramite un proxy aziendale, impostare `HTTPS_PROXY` (e `HTTP_PROXY` quando necessario). Imposta `NO_PROXY` su un elenco separato da virgole di host che devono essere raggiunti direttamente, come Postgres, Redis e archiviazione di oggetti interni.
Se il proxy o un servizio interno è firmato da un'autorità di certificazione privata, montare il certificato CA in sola lettura e puntarvi `NODE_EXTRA_CA_CERTS`. Il file deve esistere all'avvio del processo 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
```
Conserva le credenziali proxy all'esterno del file Compose (ad esempio in un file `.env` protetto o segreto). Non disabilitare la verifica TLS: l'indice OCR firmato autentica i metadati della release, mentre la normale validazione TLS protegge comunque il trasporto e ogni altra richiesta in uscita.
## Controllo di integrità {#health-check}
Il container include un controllo di integrità integrato:
+4 -4
View File
@@ -1,8 +1,8 @@
---
description: "Tag delle immagini Docker di SnapOtter, benchmark GPU, blocco delle versioni e supporto multipiattaforma per AMD64 e ARM64."
i18n_source_hash: 148b3608e11a
i18n_provenance: human
i18n_output_hash: a04890140b33
i18n_source_hash: fda322e78b4b
i18n_provenance: human
---
# Immagine Docker {#docker-image}
@@ -41,7 +41,6 @@ Testato su una NVIDIA RTX 4070 (12 GB di VRAM) con un ritratto JPEG 572x1024.
| Rimozione sfondo (isnet) | 2.457 ms | 1.137 ms | 2,2x |
| Upscale 2x | 350 ms | 309 ms | 1,1x |
| Upscale 4x | 910 ms | 310 ms | 2,9x |
| OCR (PaddleOCR) | 137 ms | 94 ms | 1,5x |
| Sfocatura volti | 139 ms | 122 ms | 1,1x |
#### Avvio a freddo (prima richiesta dopo l'avvio del container) {#cold-start-first-request-after-container-start}
@@ -50,7 +49,8 @@ Testato su una NVIDIA RTX 4070 (12 GB di VRAM) con un ritratto JPEG 572x1024.
|------|-----|-----|---------|
| Rimozione sfondo | 22.286 ms | 4.792 ms | 4,7x |
| Upscale 2x | 3.957 ms | 2.318 ms | 1,7x |
| OCR (PaddleOCR) | 1.469 ms | 1.090 ms | 1,3x |
OCR non è incluso nel confronto CUDA. Sia il livello Tesseract integrato che i livelli RapidOCR/ONNX opzionali utilizzano CPU, anche quando il contenitore ha accesso NVIDIA GPU.
### Controllo di integrità CUDA {#cuda-health-check}
+3 -3
View File
@@ -1,8 +1,8 @@
---
description: "Installa SnapOtter con Docker in un solo comando. Include la configurazione di Docker Compose, la compilazione dal codice sorgente e una panoramica completa delle funzionalità."
i18n_source_hash: 4536d4558b8e
i18n_provenance: machine
i18n_output_hash: 193499a11aa6
i18n_source_hash: 24724b5595b2
i18n_provenance: human
---
# Per iniziare {#getting-started}
@@ -32,7 +32,7 @@ Per i dettagli su ciò che viene raccolto, vedi [Cosa raccoglie SnapOtter](/it/g
:::
::: tip Accelerazione NVIDIA CUDA
Aggiungi `--gpus all` per rimozione dello sfondo, upscaling, OCR, miglioramento dei volti e restauro accelerati da NVIDIA CUDA:
Aggiungi `--gpus all` per NVIDIA rimozione dello sfondo, upscaling, miglioramento del volto e ripristino accelerati da CUDA. OCR rimane basato sulla CPU e funziona nella stessa immagine con o senza accesso GPU:
```bash
docker run -d --name SnapOtter -p 1349:1349 --gpus all -v SnapOtter-data:/data snapotter/snapotter:latest