tetrak_ocr.auto_local

auto-local OCR backend: fan out over the local engines and keep the best.

Runs every eligible local backend, scores each transcript with qa_score.combined_score() (dictionary coverage x inverse log-perplexity), and returns the highest-ranked one. It exists because no single local engine wins across document types, so choosing per file beats choosing per batch.

The winning transcript passes a quality gate: if it falls below qa_score.MIN_QUALITY_THRESHOLD, LowQualityError is raised so the caller can route the document to the triage queue rather than silently writing a bad result. The same gate is available for any single backend via tetrak-ocr batch –quality-gate; this one additionally carries the per-backend score table, which is what makes the triage manifest worth reading.

Backend eligibility:

GPU available + Marker installed:

Images: Marker, Vision, EasyOCR, Paddle, Tesseract-auto (each if installed) PDFs: Marker, Tesseract-auto

No GPU:

Images: Vision, EasyOCR, Paddle, Tesseract-auto (each if installed) PDFs: Tesseract-auto

With –with-paddle-vl, PaddleOCR-VL joins both lists, images and PDFs alike. It is opt-in rather than automatic because it runs in minutes where the rest of the pool runs in seconds – see _build_candidates().

Vision, EasyOCR and Paddle cannot read PDFs, so all three are excluded for those. Vision is additionally macOS-only; on any other platform its extra cannot install and it simply never appears as a candidate.

Fan-out runs its backends sequentially, by design. Running them in parallel looks like free speed and is not: these engines are individually heavy on CPU and RAM, and several hold module-level model singletons. Starting two or three at once on one machine risks memory pressure and contention that would make runtimes less predictable, not more – which matters most on exactly the large batch jobs where the time would otherwise be worth saving.

There was briefly a second strategy here, auto-local-fast, which ran only the top-ranked eligible backend. The benchmark retired it: in every installed configuration it was at best equal to running tesseract-auto directly, and on a GPU machine it resolved to Marker and cost twenty-four times as much for less accuracy. If a single cheap engine is what you want, name it – and add –quality-gate if you want the triage queue with it.

Public API:

has_gpu() -> bool — True if CUDA, ROCm, or Apple MPS is detected ocr_image(path) -> str — OCR a file; raises LowQualityError if poor SUPPORTED_EXTENSIONS — set of supported file extensions

Model weights are downloaded on first use and cached locally. Singleton patterns (same as EasyOCR, PaddleOCR) ensure each model loads only once.

Functions

has_gpu()

Return True if a GPU is available for neural-network acceleration.

ocr_image(path[, with_paddle_vl])

OCR a file by running every eligible local backend and keeping the best.