A superfast, lightweight, memory-efficient CPU-only OCR API. Upload any image (PNG/JPEG/GIF/BMP/TIFF/WebP) or PDF and get per-page OCR text with line boxes and confidence — no GPU, no LLM, no external OCR daemon.
| document type | handling | typical latency |
|---|---|---|
| image | RapidOCR PP-OCRv5 (ONNX Runtime, CPU) | ~0.2–1 s/page |
| digital PDF | text layer read directly (no OCR at all) | ~10–50 ms |
| scanned PDF | render page via pdftoppm, then OCR |
~1–2 s/page |
| same doc again | SHA-256 result cache | ~1 ms |
- RapidOCR PP-OCRv5 (PP-OCRv5_mobile det + cls + rec models) runs on ONNX Runtime with a single intra-op thread — ideal for shared CPU hosts. Models are embedded in the binary and extracted to the cache dir on first run.
- Only a small C library is needed at runtime:
libonnxruntime.so(Linux) /libonnxruntime.dylib(macOS). Place it next to the binary or pointORT_LIB_PATHat it. - Digital PDFs never touch the OCR engine: their embedded text layer is
extracted with a pure-Go PDF reader. Pages without a text layer are rendered
with
pdftoppm(poppler-utils) and OCR'd, in parallel. - The response is plain OCR data — no schema, no heuristics, no LLM. Your app does the parsing.
make build # equivalent to: go build -o invoiceocr .go:embed bundles the ONNX models into the binary; go build requires the
models/ directory (already in the repo).
Download libonnxruntime.so from an
onnxruntime release
(≥ 1.24) and put it next to the binary:
curl -LO https://github.com/microsoft/onnxruntime/releases/download/v1.24.1/onnxruntime-linux-x64-1.24.1.tgz
tar xzf onnxruntime-linux-x64-1.24.1.tgz --strip-components=1 onnxruntime-linux-x64-1.24.1/lib/libonnxruntime.somake run # builds then serves on 127.0.0.1:8080
./invoiceocr # or run the binary directly
./invoiceocr -addr :9000| variable | default | description |
|---|---|---|
ADDR |
127.0.0.1:8080 |
listen address (-addr flag overrides) |
ORT_LIB_PATH |
libonnxruntime.so |
path to the ONNX Runtime shared library |
MODEL_DIR |
(embedded) | optional directory of ONNX models on disk |
ORT_THREADS |
1 |
intra-op threads per inference session |
OCR_MAX_DET_SIDE |
1280 |
detection resize limit (longer side, px) |
OCR_MAX_CONCURRENCY |
GOMAXPROCS |
parallel scanned-page OCR jobs |
PDF_BIN |
pdftoppm |
path to pdftoppm (poppler-utils) |
PDF_MAX_PAGES |
20 |
cap on pages processed per PDF |
PDF_DPI |
200 |
render resolution for scanned pages |
OCR_CACHE_MAX |
500 |
in-memory result cache entries (LRU) |
OCR_CACHE_TTL_SECONDS |
86400 |
cache entry lifetime |
MAX_UPLOAD_MB |
20 |
max request body size |
API_KEY |
(off) | require Authorization: Bearer <key> |
DEBUG |
(off) | include per-stage timing (stages field) |
Engine readiness probe:
{ "status": "ok", "ocr": { "ready": true, "engine": "rapidocr-pp-ocrv5", "lib": "libonnxruntime.so", "threads": 1 } }Upload a document as multipart (file part) or as JSON with image_base64.
curl -X POST http://127.0.0.1:8080/v1/ocr -F "[email protected]"Response (application/json):
{
"success": true,
"file_type": "pdf",
"pages": [
{
"page": 1,
"method": "ocr",
"text": "INVOICE\nACME SUPPLIES INC.\n4000 Industrial Parkway...",
"confidence": 0.979,
"lines": [
{ "text": "INVOICE", "score": 1.0, "box": [[48,110],[170,108],[171,130],[49,132]] }
]
}
],
"elapsed_ms": 3256,
"cached": false
}methodis"ocr"(image/scanned page) or"text_layer"(digital PDF page).linesare in reading order, top-to-bottom, left-to-right.- Non-image/PDF input returns
422withsuccess: falseand a warning.
More examples, including the JSON body and API-key calls: examples/curl.sh.
cmd/ocr-invoice/ entry point (server bootstrap, routes, graceful shutdown)
internal/server/ OCR engine, pipeline, cache, PDF handling, HTTP handlers
ocr.go RapidOCR engine: ONNX sessions, reading order
image.go image decoding (PNG/JPEG/GIF/BMP/TIFF/WebP)
pdf.go PDF text layer (layout-aware) + scanned-page rendering
extract.go per-document pipeline (sniff → text layer → OCR → cache)
cache.go in-memory LRU result cache (SHA-256 keyed)
server.go HTTP handlers, upload parsing, auth middleware
config.go environment configuration
internal/models/ PP-OCRv5 det/cls/rec ONNX models + char dict (go:embed)
examples/ sample fixtures (sample-invoice.png, ac-statement-new.pdf) + curl.sh
tools/samplegen/ regenerates the sample invoice fixture
libonnxruntime.so runtime dependency (copy next to the binary when deploying)
make test # offline unit + pipeline tests (stub engine)
make smoke # real PP-OCRv5 smoke test (needs libonnxruntime.so)Equivalently: go test ./... and ORT_SMOKE=1 go test -run TestRealOCR -v ..