From the 2026-07-24 IO/throughput audit: pytesseract spawns a fresh tesseract process (PNG temp file + fork/exec + traineddata init) per OCR attempt — measured ~98ms fixed floor inside every ~195-205ms call, paid up to 8x/card under escalation. A persistent in-process binding (tesserocr PyTessBaseAPI per compute worker) is estimated at 20-25% of TOTAL per-card wall-clock. Prerequisites before any code change: (1) ARM64/aarch64 availability of libtesseract-dev/leptonica + tesserocr wheel in the django image; (2) an A/B parity spike proving byte-identical TSV/text output vs current run_tesseract* helpers on a real sample; (3) local_fallback/local_phash call sites (PROTECTED CORE importers) pass their existing tests unmodified — substrate swap under an unchanged public API only.
🤖 Generated with Claude Code
From the 2026-07-24 IO/throughput audit: pytesseract spawns a fresh tesseract process (PNG temp file + fork/exec + traineddata init) per OCR attempt — measured ~98ms fixed floor inside every ~195-205ms call, paid up to 8x/card under escalation. A persistent in-process binding (tesserocr PyTessBaseAPI per compute worker) is estimated at 20-25% of TOTAL per-card wall-clock. Prerequisites before any code change: (1) ARM64/aarch64 availability of libtesseract-dev/leptonica + tesserocr wheel in the django image; (2) an A/B parity spike proving byte-identical TSV/text output vs current run_tesseract* helpers on a real sample; (3) local_fallback/local_phash call sites (PROTECTED CORE importers) pass their existing tests unmodified — substrate swap under an unchanged public API only.
🤖 Generated with Claude Code