Stu Mason · Folkestone, Kent
One entryMerged PR· crunch.stumason.dev· PHP

PR #25 merged: Dedicated OCR sidecar: Tesseract (default) + PaddleOCR, engine= selectable (#13)

additions
+415
deletions
-26
files changed
14

Closes #13.

What

Florence-2 hallucinates on dense UI text (a clean crop → "3ArchivedWifoy"), which is exactly the roll workload. New dedicated ocr-sidecar with engine selectable per request:

engineRAMspeednotes
tesseract (default)~70MB~0.2slayout-preserving, tiny, reliable
paddle~1GB (lazy)0.3s small / 5–10s densePaddleOCR PP-OCRv6, best accuracy on small/low-contrast glyphs
florence~8sroutes to the vision sidecar (parity/fallback)

Paddle is lazy-loaded — the ~1GB model only enters RAM on the first engine=paddle call, so the service idles at ~70MB. Models are pre-baked into the image (no cold-start download). Kept out of the vision sidecar on purpose: that's a single synchronous worker on a tight timeout, so a 5–10s paddle call there would worsen the overload bug.

API

  • POST /ocr gains engine= (tesseract|paddle|florence, default tesseract) + psm= (tesseract page-seg mode; 7 = single line, good for a button-label crop). Response now reports {engine, model, text}.
  • POST /ocr/batch takes a batch-level engine=/psm=.

Validated before deploy

Ran the sidecar locally on an aarch64 box (≈ the prod CAX41) against real UI crops — both engines work; PaddleOCR cleanly reads "Upgrade Plan"/sidebar items that Tesseract gets icon-noise on, reading order reassembled. Confirmed the paddlepaddle==3.2.2 cp311 manylinux2014_aarch64 wheel exists so the Coolify build will succeed. Default = tesseract, so even if paddle ever has issues, the common path is the reliable one.

Tests

Action routes by engine (florence→vision, default→ocr sidecar), response labels, batch engine threading, unknown-engine 422.

Deploy note

Adds an ocr service to the compose stack (build pulls paddle + bakes models — one-time, ~1GB image). I'll verify both engines live after the deploy.

Follow-up

Wire engine= into the roll/edator client once this is live; sweep into the #17 benchmark sheet.

🤖 Generated with Claude Code