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,28 +1,30 @@
|
||||
---
|
||||
description: Extract text from images using AI-powered optical character recognition.
|
||||
description: Extract text from images locally with built-in Tesseract or the optional high-accuracy RapidOCR runtime.
|
||||
---
|
||||
|
||||
# OCR / Text Extraction {#ocr-text-extraction}
|
||||
|
||||
Extract text from images using AI-powered optical character recognition. Supports multiple languages and quality tiers.
|
||||
Extract text from images without sending the image to an external service. The built-in `fast` tier uses Tesseract. The optional `balanced` and `best` tiers use RapidOCR with pinned PP-OCR ONNX models.
|
||||
|
||||
## API Endpoint {#api-endpoint}
|
||||
|
||||
`POST /api/v1/tools/image/ocr`
|
||||
|
||||
**Processing:** Synchronous JSON response. If `clientJobId` is provided, progress is also reported through SSE.
|
||||
**Processing:** OCR is always asynchronous. After validation and enqueueing, the endpoint immediately returns `202 Accepted` with a `jobId`. Follow the job's SSE progress stream to its terminal `complete` or `failed` event; a successful event's `result` contains the OCR fields.
|
||||
|
||||
**Model bundle:** `ocr` (5-6 GB)
|
||||
**Accurate OCR pack:** Optional `ocr` runtime (about 208-234 MiB to download and 409-488 MiB installed, depending on the target). `fast` does not require this pack; the installer verifies the exact sizes bound by the signed index.
|
||||
|
||||
## Parameters {#parameters}
|
||||
|
||||
| Parameter | Type | Required | Default | Description |
|
||||
|-----------|------|----------|---------|-------------|
|
||||
| file | file | Yes | - | Image file (multipart) |
|
||||
| quality | string | No | `"balanced"` | Quality tier: `fast` (Tesseract), `balanced` (PaddleOCR v5), `best` (PaddleOCR VL) |
|
||||
| language | string | No | `"auto"` | Language hint: `auto`, `en`, `de`, `fr`, `es`, `zh`, `ja`, `ko` |
|
||||
| enhance | boolean | No | `true` | Pre-process image for better OCR accuracy |
|
||||
| engine | string | No | - | Deprecated. Use `quality` instead. Maps `tesseract` to `fast`, `paddleocr` to `balanced` |
|
||||
| file | file | Yes | - | Image file (multipart), up to 512 MiB encoded and 40 megapixels decoded; a lower operator upload limit still applies |
|
||||
| quality | string | No | Dynamic | Quality tier: `fast` (Tesseract), `balanced` (RapidOCR with the small PP-OCRv6 models), or `best` (the higher-accuracy medium PP-OCRv6 models with calibrated variant scoring) |
|
||||
| language | string | No | `"auto"` | Language hint: `auto`, `en`, `de`, `fr`, `es`, `zh`, `ja`, `ko`. Fast does not support `ko` |
|
||||
| enhance | boolean | No | Tier-dependent | Improve local contrast before recognition. Fast applies it directly; Balanced and Best retain the variant only when calibrated scoring improves the result. Defaults to `true` for `best` and `false` for `fast`/`balanced` |
|
||||
| engine | string | No | - | Deprecated compatibility alias. Use `quality` instead. `tesseract` maps to `fast`; the legacy `paddleocr` value maps to `balanced` but does not load PaddlePaddle |
|
||||
|
||||
If `quality` and the deprecated `engine` field are both omitted, SnapOtter selects the highest available tier in this order: `best`, `balanced`, `fast`. Korean never selects `fast`; it uses `best`, then `balanced`, or returns the accurate-runtime install or compatibility error.
|
||||
|
||||
## Example Request {#example-request}
|
||||
|
||||
@@ -32,31 +34,55 @@ curl -X POST http://localhost:1349/api/v1/tools/image/ocr \
|
||||
-F 'settings={"quality":"best","language":"en","enhance":true}'
|
||||
```
|
||||
|
||||
## Response (200 OK) {#response-200-ok}
|
||||
## Accepted response (202) {#accepted-response-202}
|
||||
|
||||
```json
|
||||
{
|
||||
"jobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
"filename": "document.png",
|
||||
"text": "Extracted text content from the image...",
|
||||
"engine": "paddleocr-vl"
|
||||
"async": true
|
||||
}
|
||||
```
|
||||
|
||||
### Progress (SSE, optional) {#progress-sse-optional}
|
||||
### Progress and result (SSE) {#progress-sse-optional}
|
||||
|
||||
If a `clientJobId` form field is provided, progress events are streamed:
|
||||
Connect to `GET /api/v1/jobs/{jobId}/progress` with the `jobId` returned by the `202` response (or the supplied `clientJobId`). Keep the stream open until the terminal `complete` or `failed` event. A successful terminal frame contains the OCR output in `result`:
|
||||
|
||||
```json
|
||||
{
|
||||
"jobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
"type": "single",
|
||||
"phase": "complete",
|
||||
"stage": "complete",
|
||||
"percent": 100,
|
||||
"result": {
|
||||
"jobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
"downloadUrl": "/api/v1/download/a1b2c3d4-e5f6-7890-abcd-ef1234567890/document_ocr.txt",
|
||||
"originalSize": 12345,
|
||||
"processedSize": 47,
|
||||
"text": "Extracted text content from the image...",
|
||||
"engine": "rapidocr-onnx",
|
||||
"requestedQuality": "best",
|
||||
"actualQuality": "best",
|
||||
"device": "cpu",
|
||||
"provider": "CPUExecutionProvider",
|
||||
"degraded": false,
|
||||
"warnings": [],
|
||||
"runtimeVersion": "2.1.0",
|
||||
"modelVersion": "PP-OCRv6-best-v1-medium"
|
||||
}
|
||||
}
|
||||
```
|
||||
event: progress
|
||||
data: {"phase":"processing","stage":"Recognizing text...","percent":50}
|
||||
```
|
||||
|
||||
Processing failures arrive in the terminal `failed` event's `error` field; they are not returned as an HTTP `422` after enqueueing.
|
||||
|
||||
## Notes {#notes}
|
||||
|
||||
- Requires the `ocr` model bundle to be installed (5-6 GB).
|
||||
- OCR returns extracted text directly rather than an image download URL.
|
||||
- Uses a fallback chain: if a higher-quality tier crashes (e.g., PaddleOCR segfault), it automatically retries with the next lower tier.
|
||||
- If a tier returns empty text without crashing, it also falls back to the next tier.
|
||||
- Quality tiers map to engines: `fast` = Tesseract, `balanced` = PaddleOCR v5, `best` = PaddleOCR VL.
|
||||
- `fast` is available in supported SnapOtter images for `auto`, `en`, `de`, `es`, `fr`, `zh`, and `ja`. It does not support Korean (`ko`); Korean requires the optional accurate OCR pack and `balanced` or `best`.
|
||||
- Built-in Tesseract adds about 25 MiB to the official image. The accurate pack is stored in `/data/ai`, not baked into the image.
|
||||
- The accurate pack is published for the official Linux amd64 and arm64 containers. It deliberately uses ONNX Runtime's CPU provider, including on NVIDIA hosts, so it does not depend on CUDA libraries or GPU compatibility. Unsupported hosts receive an explicit incompatibility error for Korean instead of silently falling back to Fast.
|
||||
- The successful terminal `result` includes both the extracted text in `text` and a downloadable `.txt` artifact in `downloadUrl`.
|
||||
- SnapOtter honors an explicitly requested tier. If `balanced` or `best` is unavailable, the API returns `501` with `FEATURE_NOT_INSTALLED` or `FEATURE_INCOMPATIBLE`; it never silently downgrades the request to another tier. Explicit Fast or legacy `tesseract` with Korean returns `FEATURE_INCOMPATIBLE` and `fast-korean-unsupported` before queueing.
|
||||
- A successful empty result remains an empty result. Runtime failures return an error instead of retrying with a lower-quality engine.
|
||||
- The successful terminal `result` reports both `requestedQuality` and `actualQuality`, plus the engine, device, provider, runtime and model versions, and any warnings.
|
||||
- Supports HEIC/HEIF, RAW, TGA, PSD, EXR, and HDR input formats via automatic decoding.
|
||||
- Oversized encoded inputs return `413`. Images over 40 megapixels and OCR responses over their bounded output limits are rejected instead of being partially processed.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
---
|
||||
description: Extract text from PDF documents using AI-powered OCR.
|
||||
description: Extract text from scanned PDFs locally with built-in Tesseract or the optional high-accuracy RapidOCR runtime.
|
||||
---
|
||||
|
||||
# PDF OCR {#pdf-ocr}
|
||||
|
||||
Extract text from PDF documents using AI-powered optical character recognition. Supports multiple quality tiers and languages. Requires the OCR feature bundle to be installed.
|
||||
Extract text from scanned PDF documents page by page without sending the PDF to an external service. The built-in `fast` tier uses Tesseract. The optional `balanced` and `best` tiers use RapidOCR with pinned PP-OCR ONNX models.
|
||||
|
||||
## API Endpoint {#api-endpoint}
|
||||
|
||||
@@ -16,9 +16,14 @@ Accepts multipart form data with a PDF file and an optional JSON `settings` fiel
|
||||
|
||||
| Parameter | Type | Required | Default | Description |
|
||||
|-----------|------|----------|---------|-------------|
|
||||
| quality | string | No | `"balanced"` | OCR quality tier: `fast`, `balanced`, `best` |
|
||||
| language | string | No | `"auto"` | Document language: `auto`, `en`, `de`, `fr`, `es`, `zh`, `ja`, `ko` |
|
||||
| file | file | Yes | - | PDF file (multipart), up to 512 MiB encoded; a lower operator upload limit still applies |
|
||||
| quality | string | No | Dynamic | OCR quality tier: `fast`, `balanced`, or `best` |
|
||||
| language | string | No | `"auto"` | Document language: `auto`, `en`, `de`, `fr`, `es`, `zh`, `ja`, `ko`. Fast does not support `ko` |
|
||||
| pages | string | No | `"all"` | Page selection, e.g. `"all"`, `"1-3"`, `"1,3,5"` |
|
||||
| enhance | boolean | No | Tier-dependent | Improve local contrast before recognition. Fast applies it directly; Balanced and Best retain the variant only when calibrated scoring improves the result. Defaults to `true` for `best` and `false` for `fast`/`balanced` |
|
||||
| engine | string | No | - | Deprecated compatibility alias. Use `quality` instead. `tesseract` maps to `fast`; the legacy `paddleocr` value maps to `balanced` but does not load PaddlePaddle |
|
||||
|
||||
If `quality` and the deprecated `engine` field are both omitted, SnapOtter selects the highest available tier in this order: `best`, `balanced`, `fast`. Korean never selects `fast`; it uses `best`, then `balanced`, or returns the accurate-runtime install or compatibility error.
|
||||
|
||||
## Example Request {#example-request}
|
||||
|
||||
@@ -26,7 +31,7 @@ Accepts multipart form data with a PDF file and an optional JSON `settings` fiel
|
||||
curl -X POST http://localhost:1349/api/v1/tools/pdf/ocr-pdf \
|
||||
-H "Authorization: Bearer si_your-api-key" \
|
||||
-F "file=@scanned.pdf" \
|
||||
-F 'settings={"quality": "best", "language": "en", "pages": "1-5"}'
|
||||
-F 'settings={"quality": "best", "language": "en", "pages": "1-5", "enhance": true}'
|
||||
```
|
||||
|
||||
## Example Response {#example-response}
|
||||
@@ -43,8 +48,12 @@ Returns `202 Accepted`. Track progress via SSE at `/api/v1/jobs/{jobId}/progress
|
||||
## Notes {#notes}
|
||||
|
||||
- Accepted input format: `.pdf`.
|
||||
- This is an AI tool that requires the **OCR feature bundle** to be installed. If the bundle is not installed, the API returns `501 Not Implemented`.
|
||||
- The `fast` quality tier uses a lighter model for quicker processing; `best` uses a more accurate model at the cost of speed.
|
||||
- The `auto` language setting attempts to detect the document language automatically.
|
||||
- `fast` is built in and adds about 25 MiB to the official image. `balanced` and `best` require the optional accurate OCR pack (about 208-234 MiB to download and 409-488 MiB installed, depending on the target).
|
||||
- Fast supports `auto`, `en`, `de`, `es`, `fr`, `zh`, and `ja`, but not Korean (`ko`). Korean requires the accurate pack and `balanced` or `best`.
|
||||
- The accurate pack supports official Linux amd64 and arm64 containers and uses ONNX Runtime on CPU, including on NVIDIA hosts. Unsupported hosts receive an explicit incompatibility error for Korean rather than a Fast fallback.
|
||||
- An explicitly requested tier is never silently downgraded. If `balanced` or `best` is unavailable, the API returns `501` with `FEATURE_NOT_INSTALLED` or `FEATURE_INCOMPATIBLE`. Explicit Fast or legacy `tesseract` with Korean returns `FEATURE_INCOMPATIBLE` and `fast-korean-unsupported` before queueing.
|
||||
- PDF pages are rasterized at high resolution before OCR. `best` runs the higher-accuracy medium PP-OCRv6 models and scores orientation and enhancement variants, improving recognition at the cost of speed.
|
||||
- The `auto` language setting enables recognition across the supported script set; an explicit hint can improve results for a known document language.
|
||||
- You can target specific pages using ranges (`"1-3"`), comma-separated lists (`"1,3,5"`), or `"all"` for every page.
|
||||
- A request can process at most 50 pages. Rasterized scratch data is capped at 512 MiB and the aggregate UTF-8 OCR response is capped at 1,000,000 bytes; over-limit jobs fail rather than returning partial text.
|
||||
- For PDFs that already contain selectable text, consider using the faster [PDF to Text](./pdf-to-text) tool instead.
|
||||
|
||||
Reference in New Issue
Block a user