aiptimizer/TurboOCR

TurboOCR, >200 img/s OmnidocBench. TensorRT FP16, PP-OCRv6, HTTP + gRPC

C++

1,134

260 commits

updated Sep 27, 2026

See the code

README

🧪 Apple Metal and Intel OpenVINO backends are in testing, with AMD ROCm in development. NVIDIA is the only backend shipped today.

TurboOCR — the fastest GPU document parser.

English | 简体中文

The fastest GPU document parser — OCR · layout · tables · formulas → Markdown, at 200–559 images/s on one GPU.
C++ / CUDA / TensorRT / PP-OCRv6 — Linux + NVIDIA GPU

🎉 v3.0 — now powered by PP-OCRv6

New medium / small / tiny tiers · higher accuracy · faster defaults · breaking changes

⭐ Star TurboOCR on GitHub — it helps others (and agents) find it.

up to 559 img/s turboocr.com Release Docker C++20 CUDA TensorRT 10.16 gRPC PaddleOCR MIT License

Quick Start · Accuracy · Benchmarks · Models · v3 changes · API · Docs


An extremely fast GPU document parser — not just OCR. PP-OCRv6 detection + recognition, plus layout, tables (→ HTML), formulas (→ LaTeX) and reading-order Markdown, the whole pipeline on a single multi-stream CUDA/TensorRT engine, locally (no VLM), behind HTTP and gRPC. Whole-page OCR runs at up to 559 images/s on receipts (one RTX 5090), and full structured parsing (layout + tables + formulas) at ~20 pages/s — where VLM document parsers like PaddleOCR-VL run ~1 page/s. On forms and receipts it is accurate and 15–90× faster than classic OCR engines.

  • 🚀 **559 img/s (receipts) · 520 (forms) · 200+ (dense docs) on one RTX 5090 — fastest by default
  • 🎯 Accurate on forms & receipts — competitive with PaddleOCR-VL, PaddleOCR-Python, RapidOCR, EasyOCR and Tesseract (benchmarks)
  • 🧠 PP-OCRv6 — one model covers Latin + Chinese + Japanese; pick tiny (default) / small / medium
  • 🌐 More scripts — Arabic, Cyrillic, Korean, Thai, Greek via retained PP-OCRv5 recognizers
  • 📄 PDF native — pages rendered and OCR'd in parallel, optional page-image export & auto-rotation
  • 🧩 Layout + reading order — PP-DocLayoutV3 (25 classes) and the order it predicts itself (column-aware XY-cut as fallback), opt-in per request
  • 🔢 Tables & formulas — opt-in SLANet+ table → HTML and PP-FormulaNet-S formula → LaTeX, emitted alongside the text (how to enable)
  • 🔤 Word boxes — ?words=1 adds every word of a line with its own box, cut at the line's real ink gaps
  • 🐳 One-line Docker deploy with TensorRT engines auto-built on first start, Prometheus metrics on /metrics

Full documentation: docs/


Quick Start

Requirements: Linux, NVIDIA driver 595+, Turing or newer GPU (RTX 20-series / GTX 16-series+). Plan for ~4 GB VRAM text-only and ~8 GB for the full pipeline (layout + tables + formulas); each extra PIPELINE_POOL_SIZE replica adds roughly another full set, so lower it on smaller cards.

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

First startup builds TensorRT engines from ONNX. This takes about 90 seconds on a 5090 GPU and up to an hour on older ones. Set TRT_OPT_LEVEL=3 to cut build time 3 to 5x with a small speed regression. The named volume caches the engines, so subsequent starts are instant. During the build, requests return a connection refused error from nginx until the backend is ready. nginx (port 8000) reverse-proxies to Drogon (port 8080), and both start automatically.

curl -X POST http://localhost:8000/ocr/raw \
  --data-binary @document.png -H "Content-Type: image/png"
{"results": [{"text": "Invoice Total", "confidence": 0.97, "bounding_box": [[42,10],[210,10],[210,38],[42,38]]}]}

Start it with the stages you want

All weights are baked into the image — just set the backend env var to load a stage (no paths needed). Layout is on by default; each extra stage still only runs when the request asks for it.

# text + layout (default)
docker run --gpus all -p 8000:8000 -p 50051:50051 \
  -v trt-cache:/home/ocr/.cache/turbo-ocr ghcr.io/aiptimizer/turboocr:latest

# + tables (→ HTML)       add  -e TABLE_BACKEND=slanext
# + formulas (→ LaTeX)    add  -e FORMULA_BACKEND=ppformulanet_s
# + both                  add  -e TABLE_BACKEND=slanext -e FORMULA_BACKEND=ppformulanet_s
# bigger / other language add  -e OCR_MODEL=medium   (tiny | small | medium | arabic | eslav | korean | thai | greek)

Then opt in per request (combine freely; tables/formulas auto-enable layout):

curl -X POST "http://localhost:8000/ocr/raw?layout=1&tables=1&formulas=1" \
  --data-binary @paper.png -H "Content-Type: image/png"
# PDF:  POST /ocr/pdf   ·   PDF → Markdown: POST /ocr/pdf?markdown=1   ·   page → Markdown: POST /ocr/markdown   ·   gRPC: port 50051

GET /capabilities reports which stages a running server has loaded.

→ Docker & deployment · Build from source


Getting higher accuracy

The defaults maximize throughput. Three levers trade speed for accuracy:

1. Bigger model tier — -e OCR_MODEL=small or medium. Same languages, same API; small fixes most of tiny's misreads (lost spaces, stylized fonts) at ~half the speed, medium is the most accurate.

2. Higher detection resolution — images whose long side exceeds 1280 px are downscaled before detection (recognition always reads full-res crops), so small text on phone screenshots or dense scans can go undetected. Raise the cap:

-e DET_MAX_SIDE_LIMIT=2560   # one-time engine rebuild, then cached

3. Orientation on every line — by default the 0°/180° classifier only checks vertical-looking lines, so an upside-down horizontal line is never corrected. For scans with mixed or rotated lines:

-e CLS_ALL_BOXES=1                                # check every line (small throughput cost)
-e CLS_ONNX=x1_0                                  # optional: full-width classifier variant

What each of these costs, measured (every combination, plus full parse with tables + formulas):

Measured throughput cost of each accuracy lever per model tier, and of full parsing


Benchmarks

On a single RTX 5090, vs every common OCR engine:

  • Forms & receipts (English): accurate (FUNSD 92% / CORD 93% word-F1 on the medium tier) and 15–90× faster than every other engine — up to 559 img/s (receipts) on the default tiny tier. FUNSD/CORD are English/Latin-script datasets; the EN+ZH full-document numbers below include Chinese.
  • Full document parsing (EN+ZH): 0.90 Overall on a 125-doc OmniDocBench subset at 20 pages/s, within ~5 points of PaddleOCR-VL (0.95, same subset) which runs at ~1 pg/s — fully local, no API. (Subset including Chinese pages, not the full 1651-page set.)

→ Full benchmarks & methodology


Models

The pipeline is a small stack of specialised models, not one monolith. Text detection + recognition + line orientation always run; everything else is opt-in and only loads when configured. Each stage links to its own model page.

StageModel / archSizeSelected byDocs
Text detectionPP-OCRv6 det (DB, three tiers)1.7 / 9.4 / 59 MBOCR_MODEL tier (tiny/small/medium)detection
Text recognitionPP-OCRv6 rec (CRNN + CTC, Latin + Chinese + Japanese)4.3 / 20 / 73 MBOCR_MODEL tier — default tinyrecognition · selection
Line orientationPP-LCNet textline angle classifier (0°/180° per line)~1 MBalways on (vertical lines only; every line with CLS_ALL_BOXES=1)classification
Page orientationPP-LCNet_x1_0_doc_ori (0/90/180/270 whole page)~7 MBper request via /ocr/pdf?autorotate=1http api
LayoutPP-DocLayoutV3 (RT-DETR-L, 25 classes)~124 MBper request via ?layout=1; disable with DISABLE_LAYOUT=1layout
Table → HTMLSLANet-Plus (TRT FP16 CNN encoder + hand-written C++ GRU decoder)~5 MBTABLE_BACKEND=slanext (encoder auto-resolved from the bundle)table
Formula → LaTeXPP-FormulaNet-S, in-process pure-C++ (ORT-CUDA-13, no Python)~294 MBFORMULA_BACKEND=ppformulanet_sformula

The three OCR tiers (tiny/small/medium) trade speed for accuracy, not language coverage — all cover Latin + Chinese + Japanese (Getting higher accuracy). Other scripts use retained PP-OCRv5 recognizers, also via OCR_MODEL: arabic, eslav (Cyrillic), korean, thai, greek. The legacy v5 Latin det/rec can also be swapped in for A/B comparison — see Running legacy PP-OCRv5.

→ Model selection guide


Tables & formulas

Table and formula recognition are strictly opt-in, per request. The router only loads a backend when one is configured at startup, and a stage runs only when the request explicitly asks for it with ?tables=1 and/or ?formulas=1 (gRPC: the tables / formulas request fields). layout alone never triggers them, so the default path pays nothing. When requested (and a backend is loaded), the response gains tables (HTML + cell quads) and/or formulas (LaTeX) arrays. tables=1/formulas=1 auto-enable layout. Asking for a stage the server wasn't started with is a hard error (400 TABLE_BACKEND_DISABLED / FORMULA_BACKEND_DISABLED), never a silent empty result — check GET /capabilities for what a server supports. (/ocr/markdown always includes both, best-effort, since a faithful Markdown export needs them.)

CapabilityEnable at startupRecognizer
Formula → LaTeXFORMULA_BACKEND=ppformulanet_sPP-FormulaNet-S
Table → HTMLTABLE_BACKEND=slanext (encoder auto-resolved from the bundle)SLANet-Plus

Startup + request examples are in Quick Start above.

→ Tables · Formulas


Upgrading to v3

v3 renames the server binaries, moves the default engine to PP-OCRv6, and changes several defaults (timeouts, detection resize, input caps). If you are coming from v2.x, read the full migration guide: Upgrading to v3 — breaking changes.


API

One binary serves HTTP and gRPC from a shared GPU pipeline pool.

EndpointPurpose
POST /ocr/rawOCR raw image bytes (fastest)
POST /ocrOCR base64 image in JSON
POST /ocr/pixelsZero-decode raw pixel buffer
POST /ocr/batchBatch of images
POST /ocr/pdfPDF → text (optional page images & auto-rotate); ?markdown=1 → whole PDF as Markdown
POST /ocr/markdownPage → faithful Markdown (GPU build; requires layout)
POST /inferOCR + layout / reading-order / blocks in one structured response
GET /capabilitiesRuntime feature & route discovery
GET /metricsPrometheus metrics
GET /health · /health/live · /health/readyLiveness / readiness probes

All OCR endpoints accept ?layout=1 (region detection + reading order), ?words=1 (word-level boxes inside every line), and ?tables=1 / ?formulas=1 to additionally run table → HTML / formula → LaTeX on detected regions (strict opt-in — see Tables & formulas).

→ HTTP API · gRPC API · Monitoring


Configuration

Everything is configured by environment variable (and an equivalent CLI flag). Common ones:

VariableDefaultDescription
OCR_MODELtinytiny / small / medium, or a PP-OCRv5 script model
DISABLE_LAYOUT01 skips the layout model (~300–500 MB VRAM)
LAYOUT_MERGE_MODEallNested-box policy: all (keep every box) / outer (outer regions only) / inner (innermost only). Old large/small/union accepted as aliases.
LAYOUT_KEEP_NESTED_CHILDREN0Only affects outer/inner modes: 1 still keeps the model's nested child regions (figure_title, footnote, formula_number, paragraph_title) instead of dropping them inside a parent. Formulas are always kept; no effect under default all.
CLS_ALL_BOXES01 runs the 0°/180° orientation classifier on every text line instead of only vertical-looking ones — for scans with mixed or upside-down lines.
REQUEST_TIMEOUT_MS60000Per-request inference deadline; on overrun returns 504 and frees the slot. 0 = unbounded (pre-v3 behaviour).
IDLE_CONNECTION_TIMEOUT_S120How long one HTTP request may run (the server and the bundled nginx close a connection silent that long); raise it for long PDFs, 0 = no limit
PIPELINE_POOL_SIZEautoConcurrent GPU pipelines

→ Full configuration reference (35+ variables)


Building from Source

# Docker (recommended)
docker build -f docker/Dockerfile.gpu -t turboocr .
docker run --gpus all -p 8000:8000 -p 50051:50051 \
  -v trt-cache:/home/ocr/.cache/turbo-ocr turboocr

# Native (PP-OCRv6 models auto-fetched into ./models/ on first build)
cmake -B build            # finds CUDA and TensorRT itself; -DTENSORRT_DIR=<dir> to point at an unpacked tarball
cmake --build build -j$(nproc)
LD_LIBRARY_PATH=/usr/local/tensorrt/lib ./build/turboocr-server

Needs GCC 13.3+/C++20, CUDA + TensorRT 10.2+, OpenCV 4.x, Drogon 1.9+, gRPC. Wuffs and PDFium are vendored in third_party/.

→ Build guide & GPU-architecture notes


Acknowledgements

Built on open-source work:

  • PaddleOCR (Baidu) — PP-OCRv6 / PP-OCRv5 detection, recognition, and classification models, plus PP-DocLayoutV3 layout detection. This project would not exist without their research and pre-trained weights.
  • Drogon — high-performance async C++ HTTP framework.
  • Wuffs — fast PNG decoder by Google (vendored).
  • PDFium — PDF rendering and text extraction (vendored).

License

MIT. See LICENSE.

⭐ Star TurboOCR on GitHub
Sponsored by Miruiq — AI-powered data extraction from PDFs and documents — and DiaIQ.

document-ai
document-parsing
easyocr
fastapi
fp16
gpu-ocr
grpc
inference-server
nvidia
ocr
paddleocr
pdf-extraction
qwen-vl
rag
tensorrt
text-detection
text-recognition

aiptimizer/TurboOCR

TurboOCR, >200 img/s OmnidocBench. TensorRT FP16, PP-OCRv6, HTTP + gRPC

C++

1,134

260 commits

updated Sep 27, 2026

See the code

README

🧪 Apple Metal and Intel OpenVINO backends are in testing, with AMD ROCm in development. NVIDIA is the only backend shipped today.

TurboOCR — the fastest GPU document parser.

English | 简体中文

The fastest GPU document parser — OCR · layout · tables · formulas → Markdown, at 200–559 images/s on one GPU.
C++ / CUDA / TensorRT / PP-OCRv6 — Linux + NVIDIA GPU

🎉 v3.0 — now powered by PP-OCRv6

New medium / small / tiny tiers · higher accuracy · faster defaults · breaking changes

⭐ Star TurboOCR on GitHub — it helps others (and agents) find it.

up to 559 img/s turboocr.com Release Docker C++20 CUDA TensorRT 10.16 gRPC PaddleOCR MIT License

Quick Start · Accuracy · Benchmarks · Models · v3 changes · API · Docs


An extremely fast GPU document parser — not just OCR. PP-OCRv6 detection + recognition, plus layout, tables (→ HTML), formulas (→ LaTeX) and reading-order Markdown, the whole pipeline on a single multi-stream CUDA/TensorRT engine, locally (no VLM), behind HTTP and gRPC. Whole-page OCR runs at up to 559 images/s on receipts (one RTX 5090), and full structured parsing (layout + tables + formulas) at ~20 pages/s — where VLM document parsers like PaddleOCR-VL run ~1 page/s. On forms and receipts it is accurate and 15–90× faster than classic OCR engines.

  • 🚀 **559 img/s (receipts) · 520 (forms) · 200+ (dense docs) on one RTX 5090 — fastest by default
  • 🎯 Accurate on forms & receipts — competitive with PaddleOCR-VL, PaddleOCR-Python, RapidOCR, EasyOCR and Tesseract (benchmarks)
  • 🧠 PP-OCRv6 — one model covers Latin + Chinese + Japanese; pick tiny (default) / small / medium
  • 🌐 More scripts — Arabic, Cyrillic, Korean, Thai, Greek via retained PP-OCRv5 recognizers
  • 📄 PDF native — pages rendered and OCR'd in parallel, optional page-image export & auto-rotation
  • 🧩 Layout + reading order — PP-DocLayoutV3 (25 classes) and the order it predicts itself (column-aware XY-cut as fallback), opt-in per request
  • 🔢 Tables & formulas — opt-in SLANet+ table → HTML and PP-FormulaNet-S formula → LaTeX, emitted alongside the text (how to enable)
  • 🔤 Word boxes — ?words=1 adds every word of a line with its own box, cut at the line's real ink gaps
  • 🐳 One-line Docker deploy with TensorRT engines auto-built on first start, Prometheus metrics on /metrics

Full documentation: docs/


Quick Start

Requirements: Linux, NVIDIA driver 595+, Turing or newer GPU (RTX 20-series / GTX 16-series+). Plan for ~4 GB VRAM text-only and ~8 GB for the full pipeline (layout + tables + formulas); each extra PIPELINE_POOL_SIZE replica adds roughly another full set, so lower it on smaller cards.

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

First startup builds TensorRT engines from ONNX. This takes about 90 seconds on a 5090 GPU and up to an hour on older ones. Set TRT_OPT_LEVEL=3 to cut build time 3 to 5x with a small speed regression. The named volume caches the engines, so subsequent starts are instant. During the build, requests return a connection refused error from nginx until the backend is ready. nginx (port 8000) reverse-proxies to Drogon (port 8080), and both start automatically.

curl -X POST http://localhost:8000/ocr/raw \
  --data-binary @document.png -H "Content-Type: image/png"
{"results": [{"text": "Invoice Total", "confidence": 0.97, "bounding_box": [[42,10],[210,10],[210,38],[42,38]]}]}

Start it with the stages you want

All weights are baked into the image — just set the backend env var to load a stage (no paths needed). Layout is on by default; each extra stage still only runs when the request asks for it.

# text + layout (default)
docker run --gpus all -p 8000:8000 -p 50051:50051 \
  -v trt-cache:/home/ocr/.cache/turbo-ocr ghcr.io/aiptimizer/turboocr:latest

# + tables (→ HTML)       add  -e TABLE_BACKEND=slanext
# + formulas (→ LaTeX)    add  -e FORMULA_BACKEND=ppformulanet_s
# + both                  add  -e TABLE_BACKEND=slanext -e FORMULA_BACKEND=ppformulanet_s
# bigger / other language add  -e OCR_MODEL=medium   (tiny | small | medium | arabic | eslav | korean | thai | greek)

Then opt in per request (combine freely; tables/formulas auto-enable layout):

curl -X POST "http://localhost:8000/ocr/raw?layout=1&tables=1&formulas=1" \
  --data-binary @paper.png -H "Content-Type: image/png"
# PDF:  POST /ocr/pdf   ·   PDF → Markdown: POST /ocr/pdf?markdown=1   ·   page → Markdown: POST /ocr/markdown   ·   gRPC: port 50051

GET /capabilities reports which stages a running server has loaded.

→ Docker & deployment · Build from source


Getting higher accuracy

The defaults maximize throughput. Three levers trade speed for accuracy:

1. Bigger model tier — -e OCR_MODEL=small or medium. Same languages, same API; small fixes most of tiny's misreads (lost spaces, stylized fonts) at ~half the speed, medium is the most accurate.

2. Higher detection resolution — images whose long side exceeds 1280 px are downscaled before detection (recognition always reads full-res crops), so small text on phone screenshots or dense scans can go undetected. Raise the cap:

-e DET_MAX_SIDE_LIMIT=2560   # one-time engine rebuild, then cached

3. Orientation on every line — by default the 0°/180° classifier only checks vertical-looking lines, so an upside-down horizontal line is never corrected. For scans with mixed or rotated lines:

-e CLS_ALL_BOXES=1                                # check every line (small throughput cost)
-e CLS_ONNX=x1_0                                  # optional: full-width classifier variant

What each of these costs, measured (every combination, plus full parse with tables + formulas):

Measured throughput cost of each accuracy lever per model tier, and of full parsing


Benchmarks

On a single RTX 5090, vs every common OCR engine:

  • Forms & receipts (English): accurate (FUNSD 92% / CORD 93% word-F1 on the medium tier) and 15–90× faster than every other engine — up to 559 img/s (receipts) on the default tiny tier. FUNSD/CORD are English/Latin-script datasets; the EN+ZH full-document numbers below include Chinese.
  • Full document parsing (EN+ZH): 0.90 Overall on a 125-doc OmniDocBench subset at 20 pages/s, within ~5 points of PaddleOCR-VL (0.95, same subset) which runs at ~1 pg/s — fully local, no API. (Subset including Chinese pages, not the full 1651-page set.)

→ Full benchmarks & methodology


Models

The pipeline is a small stack of specialised models, not one monolith. Text detection + recognition + line orientation always run; everything else is opt-in and only loads when configured. Each stage links to its own model page.

StageModel / archSizeSelected byDocs
Text detectionPP-OCRv6 det (DB, three tiers)1.7 / 9.4 / 59 MBOCR_MODEL tier (tiny/small/medium)detection
Text recognitionPP-OCRv6 rec (CRNN + CTC, Latin + Chinese + Japanese)4.3 / 20 / 73 MBOCR_MODEL tier — default tinyrecognition · selection
Line orientationPP-LCNet textline angle classifier (0°/180° per line)~1 MBalways on (vertical lines only; every line with CLS_ALL_BOXES=1)classification
Page orientationPP-LCNet_x1_0_doc_ori (0/90/180/270 whole page)~7 MBper request via /ocr/pdf?autorotate=1http api
LayoutPP-DocLayoutV3 (RT-DETR-L, 25 classes)~124 MBper request via ?layout=1; disable with DISABLE_LAYOUT=1layout
Table → HTMLSLANet-Plus (TRT FP16 CNN encoder + hand-written C++ GRU decoder)~5 MBTABLE_BACKEND=slanext (encoder auto-resolved from the bundle)table
Formula → LaTeXPP-FormulaNet-S, in-process pure-C++ (ORT-CUDA-13, no Python)~294 MBFORMULA_BACKEND=ppformulanet_sformula

The three OCR tiers (tiny/small/medium) trade speed for accuracy, not language coverage — all cover Latin + Chinese + Japanese (Getting higher accuracy). Other scripts use retained PP-OCRv5 recognizers, also via OCR_MODEL: arabic, eslav (Cyrillic), korean, thai, greek. The legacy v5 Latin det/rec can also be swapped in for A/B comparison — see Running legacy PP-OCRv5.

→ Model selection guide


Tables & formulas

Table and formula recognition are strictly opt-in, per request. The router only loads a backend when one is configured at startup, and a stage runs only when the request explicitly asks for it with ?tables=1 and/or ?formulas=1 (gRPC: the tables / formulas request fields). layout alone never triggers them, so the default path pays nothing. When requested (and a backend is loaded), the response gains tables (HTML + cell quads) and/or formulas (LaTeX) arrays. tables=1/formulas=1 auto-enable layout. Asking for a stage the server wasn't started with is a hard error (400 TABLE_BACKEND_DISABLED / FORMULA_BACKEND_DISABLED), never a silent empty result — check GET /capabilities for what a server supports. (/ocr/markdown always includes both, best-effort, since a faithful Markdown export needs them.)

CapabilityEnable at startupRecognizer
Formula → LaTeXFORMULA_BACKEND=ppformulanet_sPP-FormulaNet-S
Table → HTMLTABLE_BACKEND=slanext (encoder auto-resolved from the bundle)SLANet-Plus

Startup + request examples are in Quick Start above.

→ Tables · Formulas


Upgrading to v3

v3 renames the server binaries, moves the default engine to PP-OCRv6, and changes several defaults (timeouts, detection resize, input caps). If you are coming from v2.x, read the full migration guide: Upgrading to v3 — breaking changes.


API

One binary serves HTTP and gRPC from a shared GPU pipeline pool.

EndpointPurpose
POST /ocr/rawOCR raw image bytes (fastest)
POST /ocrOCR base64 image in JSON
POST /ocr/pixelsZero-decode raw pixel buffer
POST /ocr/batchBatch of images
POST /ocr/pdfPDF → text (optional page images & auto-rotate); ?markdown=1 → whole PDF as Markdown
POST /ocr/markdownPage → faithful Markdown (GPU build; requires layout)
POST /inferOCR + layout / reading-order / blocks in one structured response
GET /capabilitiesRuntime feature & route discovery
GET /metricsPrometheus metrics
GET /health · /health/live · /health/readyLiveness / readiness probes

All OCR endpoints accept ?layout=1 (region detection + reading order), ?words=1 (word-level boxes inside every line), and ?tables=1 / ?formulas=1 to additionally run table → HTML / formula → LaTeX on detected regions (strict opt-in — see Tables & formulas).

→ HTTP API · gRPC API · Monitoring


Configuration

Everything is configured by environment variable (and an equivalent CLI flag). Common ones:

VariableDefaultDescription
OCR_MODELtinytiny / small / medium, or a PP-OCRv5 script model
DISABLE_LAYOUT01 skips the layout model (~300–500 MB VRAM)
LAYOUT_MERGE_MODEallNested-box policy: all (keep every box) / outer (outer regions only) / inner (innermost only). Old large/small/union accepted as aliases.
LAYOUT_KEEP_NESTED_CHILDREN0Only affects outer/inner modes: 1 still keeps the model's nested child regions (figure_title, footnote, formula_number, paragraph_title) instead of dropping them inside a parent. Formulas are always kept; no effect under default all.
CLS_ALL_BOXES01 runs the 0°/180° orientation classifier on every text line instead of only vertical-looking ones — for scans with mixed or upside-down lines.
REQUEST_TIMEOUT_MS60000Per-request inference deadline; on overrun returns 504 and frees the slot. 0 = unbounded (pre-v3 behaviour).
IDLE_CONNECTION_TIMEOUT_S120How long one HTTP request may run (the server and the bundled nginx close a connection silent that long); raise it for long PDFs, 0 = no limit
PIPELINE_POOL_SIZEautoConcurrent GPU pipelines

→ Full configuration reference (35+ variables)


Building from Source

# Docker (recommended)
docker build -f docker/Dockerfile.gpu -t turboocr .
docker run --gpus all -p 8000:8000 -p 50051:50051 \
  -v trt-cache:/home/ocr/.cache/turbo-ocr turboocr

# Native (PP-OCRv6 models auto-fetched into ./models/ on first build)
cmake -B build            # finds CUDA and TensorRT itself; -DTENSORRT_DIR=<dir> to point at an unpacked tarball
cmake --build build -j$(nproc)
LD_LIBRARY_PATH=/usr/local/tensorrt/lib ./build/turboocr-server

Needs GCC 13.3+/C++20, CUDA + TensorRT 10.2+, OpenCV 4.x, Drogon 1.9+, gRPC. Wuffs and PDFium are vendored in third_party/.

→ Build guide & GPU-architecture notes


Acknowledgements

Built on open-source work:

  • PaddleOCR (Baidu) — PP-OCRv6 / PP-OCRv5 detection, recognition, and classification models, plus PP-DocLayoutV3 layout detection. This project would not exist without their research and pre-trained weights.
  • Drogon — high-performance async C++ HTTP framework.
  • Wuffs — fast PNG decoder by Google (vendored).
  • PDFium — PDF rendering and text extraction (vendored).

License

MIT. See LICENSE.

⭐ Star TurboOCR on GitHub
Sponsored by Miruiq — AI-powered data extraction from PDFs and documents — and DiaIQ.

document-ai
document-parsing
easyocr
fastapi
fp16
gpu-ocr
grpc
inference-server
nvidia
ocr
paddleocr
pdf-extraction
qwen-vl
rag
tensorrt
text-detection
text-recognition

Project health

Latest release

0.3.0 · Jul 16, 2026

Releases this year

3

Significant stargazers

Nils Reimers

768 followers · starred Jul 2026

Florian BRUNIAUX

635 followers · starred Jul 2026

Yoong Hor Meng

32 followers · starred Aug 2026

Shuduo Sang

109 followers · starred Jul 2026