Skip to content

Quickstart

TurboOCR ships as a single container. Pull it, run it on a GPU, POST a document, parse the JSON. This page gets you from zero to a real response in under five minutes. It’s a full document parser — text, layout, tables, and formulas — not just OCR.

Linux host with an NVIDIA Turing or newer GPU (RTX 20-series / GTX 16-series and up) and driver 595+. Docker with the NVIDIA Container Toolkit so --gpus all works. Plan for ~4 GB VRAM text-only and ~8 GB for the full pipeline (layout + tables + formulas). Every model and language bundle is baked into the image.

Pull and start :latest from GHCR (pin :v3.1.0 in production). HTTP serves on port 8000, gRPC on 50051. The named volume keeps the compiled TensorRT engines around between restarts.

Terminal window
docker run --gpus all -p 8000:8000 -p 50051:50051 \
-v trt-cache:/home/ocr/.cache/turbo-ocr \
ghcr.io/aiptimizer/turboocr:latest

The first start compiles TensorRT engines from ONNX (about 90 seconds on a 5090, up to an hour on older GPUs — set TRT_OPT_LEVEL=3 to cut that 3–5× with a small speed regression). Every restart after that loads from the trt-cache volume and is instant. Use a named volume, not a host bind-mount — bind-mounting an empty directory shadows the baked-in models.

When the logs report ready, sanity-check the server:

Terminal window
curl http://localhost:8000/health

Several endpoints cover most workloads. POST /ocr/raw takes raw image bytes (fastest path); POST /ocr/pdf renders and OCRs every PDF page in parallel. Other routes: POST /ocr (base64 image in JSON), POST /ocr/pixels (zero-decode raw pixel buffer), POST /ocr/batch (many images per request), POST /infer (OCR + layout / reading-order / blocks in one structured response) and POST /ocr/markdown (page → faithful Markdown). See the API Reference for full schemas.

Terminal window
curl -X POST http://localhost:8000/ocr/raw \
--data-binary @document.png \
-H "Content-Type: image/png"
Terminal window
pip install turboocr
from turboocr import Client
with Client(
base_url="http://localhost:8000",
api_key="tocr_live_...",
) as client:
response = client.recognize_image("invoice.jpg")
print(response.results[0].text)

Image endpoints return a flat results array. Each entry has the recognized text, a confidence score in [0, 1], and a 4-point bounding polygon in pixel coordinates (top-left, top-right, bottom-right, bottom-left).

{
"results": [
{
"text": "Invoice Total",
"confidence": 0.97,
"bounding_box": [[42, 10], [210, 10], [210, 38], [42, 38]]
},
{
"text": "$1,284.00",
"confidence": 0.95,
"bounding_box": [[220, 10], [320, 10], [320, 38], [220, 38]]
}
]
}

PDF responses wrap one results array per page under pages[], with the page index, render DPI, and pixel dimensions. Append ?layout=1 to either endpoint to also detect document regions; each result then carries a layout_id linking it to the containing region. /infer also accepts ?reading_order=1 (adds a reading-order array, XY-cut over the layout regions) and ?as_blocks=1 (aggregates lines into paragraph blocks); both auto-enable ?layout=1.

If a configured stage produces nothing, the JSON carries text_degraded / table_degraded / formula_degraded (plus a *_warning string) rather than a silent empty result — a partial result is never an unmarked clean 200.

Tables and formulas are strictly opt-in: the backend must be loaded at startup and the request must ask for it. All weights are already baked into the image — you just set the backend env var to load the stage (no paths needed). Layout is on by default; each extra stage still only runs when the request asks for it.

Terminal window
# Text + layout is the default. Add backends to load the table and
# formula stages, and pick a bigger / other-language OCR tier.
docker run --gpus all -p 8000:8000 -p 50051:50051 \
-e TABLE_BACKEND=slanext \
-e FORMULA_BACKEND=ppformulanet_s \
-e OCR_MODEL=medium \
-v trt-cache:/home/ocr/.cache/turbo-ocr \
ghcr.io/aiptimizer/turboocr:latest
# OCR_MODEL: tiny (default) | small | medium | arabic | eslav | korean | thai | greek
# FORMULA_BACKEND: ppformulanet_s (Latin/EN) | ppformulanet_plus_m (Chinese-capable) | vlm

Then opt in per request — ?tables=1 and ?formulas=1 combine freely and auto-enable layout:

Terminal window
# Full structured parse: layout regions + tables -> HTML + formulas -> LaTeX.
# tables=1 / formulas=1 auto-enable layout. The backends must be loaded at
# startup (TABLE_BACKEND / FORMULA_BACKEND) or you get a 400, never empties.
curl -X POST "http://localhost:8000/ocr/raw?layout=1&tables=1&formulas=1" \
--data-binary @paper.png \
-H "Content-Type: image/png"

The response gains a tables array (HTML + cell quads) and/or a formulas array (LaTeX). Asking for a stage the server wasn’t started with is a hard 400 (TABLE_BACKEND_DISABLED / FORMULA_BACKEND_DISABLED), never a silent empty result.

For a whole-page export, POST /ocr/markdown returns faithful Markdown with tables and formulas inline (GPU build; requires layout):

Terminal window
# Page -> faithful Markdown (GPU build). Requires layout; tables + formulas
# are always included best-effort, since a faithful export needs them.
curl -X POST "http://localhost:8000/ocr/markdown" \
--data-binary @page.png \
-H "Content-Type: image/png"

Not sure which stages a running server has loaded? Ask it:

Terminal window
# Discover which stages and routes a running server actually has loaded.
curl http://localhost:8000/capabilities

Prefer to point and click? The Studio web UI lets you drop in an image or PDF, run OCR, see the layout overlay and reading order, select recognized text on the page, and download a searchable PDF. Server + GUI start together with one command from the repo root (the demo compose already enables the table and formula stages):

Terminal window
docker compose -f docker-compose.demo.yml up --build

Then open http://localhost:3000. For CPU-only dev, use docker-compose.demo.cpu.yml instead (CPU is dev/CI only — single-digit img/s).