This release is a pre-release and may not be stable for production use.
turboocr
Python for TurboOCR: the typed client for a TurboOCR server (sync + async, HTTP + gRPC, layout-aware Markdown rendering, searchable-PDF generation) — and, via one extra, the in-process native engine, so the same package OCRs locally with no server at all.
- Install · Quickstart · What you get
- Examples · API reference · CLI · Errors
Install
pip install turboocr # HTTP client + CLI + searchable-PDF
pip install 'turboocr[grpc]' # add the gRPC transport
pip install 'turboocr[all]' # everything optional (currently == [grpc])
To also run OCR in-process (no server), add exactly one backend extra —
it pins the matching native turboocr-engine-* wheel:
pip install 'turboocr[cpu]' # any CPU — and Apple Silicon (Metal/ANE build)
pip install 'turboocr[cuda12]' # NVIDIA (TensorRT + CUDA EP), driver R525+
pip install 'turboocr[cuda13]' # same, CUDA 13 — driver R580+
pip install 'turboocr[openvino]' # Intel CPU / iGPU / Arc / NPU
pip install 'turboocr[rocm]' # AMD (ROCm)
turboocr doctor names the right one for your machine. With an engine
installed, turboocr.OCR() runs locally:
import turboocr
page = turboocr.OCR().read("invoice.png") # in-process, no server
print(page.text)
Without one, the client API works everywhere and turboocr.OCR() raises an
ImportError naming the extra to install. Feature extras combine with any
backend: 'turboocr[cuda,pdf]' (PDF in/out), [pandas].
Requires Python 3.12+.
Quickstart
Start a TurboOCR server (the C++/CUDA OCR engine; for serverless in-process OCR see the backend extras above):
docker run --gpus all -p 8000:8000 -p 50051:50051 \
-v trt-cache:/home/ocr/.cache/turbo-ocr \
-e TABLE_BACKEND=slanext -e FORMULA_BACKEND=ppformulanet_s \
ghcr.io/aiptimizer/turboocr:latest
The default OCR_MODEL=tiny covers Latin + Chinese + Japanese; small/medium
trade speed for accuracy, and arabic, eslav, korean, thai, greek are
baked in too. The two backend env vars enable table → HTML and formula → LaTeX
recognition (strict per-request opt-ins). See the
TurboOCR repo for build-from-source,
benchmarks, and the full set of server env vars.
Then recognise an image and turn a PDF into Markdown:
from pathlib import Path
from turboocr import Client
with Client(base_url="http://localhost:8000") as client:
# Image OCR
img = client.recognize_image("page.png", layout=True, include_blocks=True)
print(f"{len(img.results)} text items, {len(img.blocks)} blocks")
print(img.text)
# PDF → Markdown file (rendered server-side: tables → HTML, formulas →
# LaTeX, figures embedded as data URIs — a real, self-contained .md)
Path("paper.md").write_text(client.pdf_markdown("paper.pdf", dpi=150))
# Tables + formulas as structured fields (strict opt-in, v3.1+ server)
rich = client.recognize_image("paper.png", tables=True, formulas=True)
for table in rich.tables:
print(table.html)
for formula in rich.formulas:
print(formula.latex)
# Searchable PDF (invisible text overlay)
overlay = client.make_searchable_pdf("scan.pdf", dpi=200)
open("scan.searchable.pdf", "wb").write(overlay)
That's the 80% case. Full runnable examples for async, gRPC, batch, retries,
custom httpx.Client, hooks, Markdown styling, folder pipelines, and more live
in examples/ — every script runs end-to-end against the bundled
ACME invoice fixture.
What you get
- Sync + async, HTTP + gRPC. Four clients (
Client,AsyncClient,GrpcClient,AsyncGrpcClient) with identical method surfaces. - Typed, immutable responses (pydantic v2). IDE autocomplete, and if a newer
server adds a field your SDK doesn't know about, parsing still succeeds — the
extra lands on
.model_extrainstead of crashing. - Layout-aware Markdown.
render_to_markdown(...)walks the reading order and maps each layout class (doc_title,display_formula,table, …) to a Markdown construct. Pluggable viaMarkdownStyle. - Searchable PDFs.
make_searchable_pdf(...)overlays an invisible text layer aligned to the page geometry. Auto-discovers a Unicode font for non-Latin scripts, or passfont_path=. - Production-friendly. Configurable retry policy (HTTP status + gRPC status
Retry-After), per-request timeouts, customhttpx.Client,on_request/on_responseevent hooks, uuid7X-Request-IDper call.
- Tables → HTML, formulas → LaTeX.
tables=True/formulas=True(server v3.1+, strict opt-in) populateresponse.tables[*].htmlandresponse.formulas[*].latex;client.capabilities()tells you what the running server has loaded. - Server-side Markdown.
client.pdf_markdown(...)converts a whole PDF in one call (as_pages=Truefor per-page chunks — the RAG-friendly shape);client.page_markdown(...)does a single image.render_to_markdown(...)stays for client-side, style-customizable rendering. - Per-page streaming.
client.stream(...)yields NDJSON events as each page completes, so you can start consuming page 1 while page N is still being OCR'd. - Precise exception hierarchy. Maps the server's error codes to typed exceptions — see Errors.
turbo-ocrCLI included in the default install.
Configuration
from turboocr import Client, RetryPolicy
client = Client(
base_url="http://localhost:8000", # or TURBO_OCR_BASE_URL env
api_key="sk-...", # or TURBO_OCR_API_KEY env
auth_scheme="bearer", # "bearer" | "x-api-key"
timeout=30.0,
default_headers={"X-Tenant": "acme"},
retry=RetryPolicy(attempts=5, backoff=0.5),
)
Pass http_client=httpx.Client(...) for custom TLS, connection limits, or
proxies — see examples/08_custom_httpx_client.py.
Retry defaults: HTTP {429, 502, 503, 504}, gRPC
{UNAVAILABLE, DEADLINE_EXCEEDED, RESOURCE_EXHAUSTED}, 3 attempts, exponential
backoff + jitter, Retry-After honoured. Tune via RetryPolicy(...) — see
examples/07_retry_and_timeout.py.
Errors
TurboOcrError
├── APIConnectionError # transport-level
│ ├── Timeout
│ ├── NetworkError
│ └── ProtocolError
├── InvalidParameter # 4xx: bad params / headers / dims
├── EmptyBody # 4xx: empty body / batch / PDF
├── BackendDisabled # tables/formulas/autorotate without that backend
│ └── LayoutDisabled # layout requested with DISABLE_LAYOUT=1
├── ImageDecodeError # bad bytes / bad base64
├── DimensionsTooLarge # image / PDF / batch over server limits
├── PoolExhausted # "Server at capacity" / SERVER_BUSY
├── PdfRenderError # PDF rasterization failed
├── InferenceTimeout # per-request deadline elapsed (504)
└── ServerError # 5xx, no specific code
Server-side exceptions carry .code, .status_code, and .payload. Transport
exceptions inherit from APIConnectionError.
| Symptom | Cause | Fix |
|---|---|---|
NetworkError: Connection refused |
server not running | start the docker container (above) |
DimensionsTooLarge |
image > MAX_IMAGE_DIM (default 16384) |
downscale, or raise the server limit |
LayoutDisabled |
server started with DISABLE_LAYOUT=1 |
restart without that env var |
BackendDisabled |
tables=True/formulas=True without the backend |
start with TABLE_BACKEND=slanext / FORMULA_BACKEND=ppformulanet_s |
PoolExhausted |
server queue full | retry with backoff, or scale PIPELINE_POOL_SIZE |
Timeout |
per-request timeout hit | pass timeout=N, or raise RetryPolicy.attempts |
CLI
turbo-ocr ocr page.png --output markdown --tables --formulas
turbo-ocr pdf doc.pdf --dpi 150 --output json
turbo-ocr markdown doc.pdf -o doc.md # server-side PDF → Markdown
turbo-ocr searchable-pdf doc.pdf -o out.pdf --font-path /path/to/font.ttf
turbo-ocr capabilities
turbo-ocr health --ready
--output accepts json | blocks | text | markdown. Reads TURBO_OCR_BASE_URL
and TURBO_OCR_API_KEY from the environment. Run turbo-ocr --help
for the full surface.
Logging
import logging
logging.getLogger("turboocr").setLevel(logging.DEBUG)
Emits method path -> status (Xms) [req=<short-id>] per HTTP request. Retry
warnings go to turboocr.retry / turboocr.grpc.retry. Searchable-PDF font
resolution logs to turboocr.searchable_pdf. Every HTTP request sends a uuid7
X-Request-ID header (gRPC uses x-request-id metadata).
Learn more
examples/— 14 runnable scripts (each runs against the bundled ACME invoice fixture, no server config needed beyondTURBO_OCR_BASE_URL)docs/— full docs source (MkDocs + mkdocstrings, deployed at https://aiptimizer.github.io/TurboOCR-python/). Preview locally withuv run --extra docs mkdocs serve -f docs/mkdocs.yml- Server compatibility:
SERVER_API_VERSION_MIN/SERVER_API_VERSION_MAX_EXCLUSIVEdocument the supported server range;extra="allow"on response models means additive server changes don't break parsing
Testing
pytest -q # offline (respx)
TURBO_OCR_BASE_URL=http://localhost:8000 pytest tests/integration -v
python examples/03_searchable_pdf.py # smoke test
License
MIT. See LICENSE.
turboocr.com · ⭐ Star TurboOCR on GitHub
Sponsored by Miruiq — AI-powered data extraction from PDFs and documents — and DiaIQ.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file turboocr-4.0.0a1.tar.gz.
File metadata
- Download URL: turboocr-4.0.0a1.tar.gz
- Upload date:
- Size: 251.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
19142dc6c1e54b63aa5c3b35cc6d75e0f7a9dc0e444470eb1a314da9e209c690
|
|
| MD5 |
8b2ef769c159f90f1bdedfb51b9309f2
|
|
| BLAKE2b-256 |
14e1df4958b2df4d4858a87d795b3a65254962c6d43ce6e1dc6a6da82b5b1d29
|
Provenance
The following attestation bundles were made for turboocr-4.0.0a1.tar.gz:
Publisher:
wheels.yml on aiptimizer/TurboOCR
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
turboocr-4.0.0a1.tar.gz -
Subject digest:
19142dc6c1e54b63aa5c3b35cc6d75e0f7a9dc0e444470eb1a314da9e209c690 - Sigstore transparency entry: 2504229969
- Sigstore integration time:
-
Permalink:
aiptimizer/TurboOCR@e3fa6783c9bb57ffeebd1844b1ebba4977785060 -
Branch / Tag:
refs/tags/publish-v4.0.0-alpha.1 - Owner: https://github.com/aiptimizer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
wheels.yml@e3fa6783c9bb57ffeebd1844b1ebba4977785060 -
Trigger Event:
push
-
Statement type:
File details
Details for the file turboocr-4.0.0a1-py3-none-any.whl.
File metadata
- Download URL: turboocr-4.0.0a1-py3-none-any.whl
- Upload date:
- Size: 68.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b9b0b853ca22ba97bb7bcc7e8151998624c0ccf21c99a27d8d2ce402e3699e20
|
|
| MD5 |
7693f3b6aa8605a3a8b0f01c5c059a5d
|
|
| BLAKE2b-256 |
234279bb321609765de7f232f026b80297ff5410ac9b268cbd33cbbd0cdb3a9d
|
Provenance
The following attestation bundles were made for turboocr-4.0.0a1-py3-none-any.whl:
Publisher:
wheels.yml on aiptimizer/TurboOCR
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
turboocr-4.0.0a1-py3-none-any.whl -
Subject digest:
b9b0b853ca22ba97bb7bcc7e8151998624c0ccf21c99a27d8d2ce402e3699e20 - Sigstore transparency entry: 2504230953
- Sigstore integration time:
-
Permalink:
aiptimizer/TurboOCR@e3fa6783c9bb57ffeebd1844b1ebba4977785060 -
Branch / Tag:
refs/tags/publish-v4.0.0-alpha.1 - Owner: https://github.com/aiptimizer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
wheels.yml@e3fa6783c9bb57ffeebd1844b1ebba4977785060 -
Trigger Event:
push
-
Statement type: