Skip to content

scriva documentation

scriva is a composable, engine-agnostic OCR framework for Python built on two pillars:

  • Worker — converts image regions or cells into text. Worker = image region → text + confidence
  • Orchestrator — handles everything around the Worker. Orchestrator = preprocess → split → assign workers → run OCR → review → reconstruct → export
import scriva
text = scriva.read("scan.png")

That uses sensible defaults end-to-end. When you want to swap a model, change a prompt, or stream events, drop down to a Worker / Orchestrator recipe — every default above is one chained method away.

import scriva
from scriva.schemas import Invoice
scriva.read("scan.png") # text out
scriva.extract("acme.pdf", schema=Invoice) # typed pydantic instance out
scriva.presets.invoice("acme.pdf") # tuned recipe + schema

Pick the highest-level entry that fits and drop a rung when you need more control. See scriva.extract and Presets.

from scriva import Orchestrator, Worker
worker = (
Worker.openai("gpt-4o")
.cache(".scriva_cache")
.score(method="rendering")
)
recipe = (
Orchestrator()
.deskew()
.split.grid()
.classify(blank=True, merged=True)
.recognize.by_kind({
"text": worker,
"number": Worker.number(),
"date": Worker.date(),
"checkbox": Worker.checkbox(),
"blank": Worker.skip(),
})
.review.hitl(when=lambda r: (r.confidence or 0) < 0.7)
.reconstruct.grid()
.export.xlsx("out.xlsx")
)
result = recipe("scan.png")

Three pillars for high-accuracy production OCR

Section titled “Three pillars for high-accuracy production OCR”

When the project’s bar is “wrong answers are unacceptable,” scriva exposes three composable pillars. Every other reference page slots into one of them.

  1. Learn from your environment. Keep a SampleStore of your own corrections. The same store powers few-shot exemplars on the Worker (Worker.few_shot(store)) and derived dictionaries on the Orchestrator’s reconstruct phase (reconstruct.dictionary.from_samples(...)). One store, two roads.
  2. Cross-check, then route. Three accuracy levers — human-in-the-loop review, cross-check against the original crop (round-trip rendering or multi-Worker consensus), and cross-check against ground-truth data — compose freely. See Orchestrator › High-accuracy patterns.
  3. Manipulate the pixels the Worker actually sees. Page-level preprocessing (orientation, deskew, dewarp) and region-level preprocessing (per-cell binarisation, horizontal/vertical slicing, per-role padding, glare removal, whiteboard clean-up) are both first-class. See Preprocessors.
  1. Concepts — the two pillars and the primitives.
  2. Quickstart — a runnable end-to-end example.
  3. Architecture — how the pillars compose.
  1. scriva.extract — schema-first one-liner, classify, batch, watch.
  2. Presets — pre-tuned recipes per document kind.
  3. Schemas — built-in pydantic models (Invoice, Receipt, IdCard, …).
  4. Working with resultsDocumentResult accessors and serialisation.
  5. CLIscriva extract, scriva watch, scriva eval, scriva annotate.
  1. Worker — engines, kinds, decorators, composition.
  2. Orchestrator — steps, options, events, accuracy patterns.
  1. Preprocessors.rotate() .crop() .deskew() .denoise() plus region refine.
  2. Detectors.split.grid() .split.vertical() .split.horizontal() .split.boxes().
  3. Post-processors.classify(...) and .reconstruct.* adapters.
  4. Exporters.export.xlsx() .csv() .json() .html() .parquet() .markdown() .debug() .samples().
  5. CachingWorker.cache(...) in depth.
  6. Sample storesWorker.few_shot(...) and active learning.
  1. Reliability — retries, rate limits, timeouts, cost caps, PII redaction, telemetry.
  2. Evaluationscriva.eval, ground-truth format, calibration.
  1. Cookbook — worked recipes per document kind and per workflow.
  2. Domain packs — pre-built recipes for forms, P&ID, agentic extraction, annotation.
  3. Orchestrator › Accuracy patterns — HITL, confidence-driven re-OCR, Worker diff.
  4. Cookbook › Rebuilding ocr-agent — case study porting a Japanese-forms / P&ID / annotation app, plus FastAPI hosting.
You want to…Read…
just read an image to textQuickstart › one-liner
extract a typed pydantic instancescriva.extract
understand the designConcepts
OCR an invoice / receipt / IDCookbook
OCR a tabular form to ExcelDomains › forms
route an unknown documentscriva.classify_document
ingest a folder continuouslyCookbook › Batch & watch
swap OpenAI for AnthropicWorker › engine factories
OCR numbers / dates / checkboxes specificallyWorker › kind factories
add a new output formatExporters
serialise a result on the flyResults › serialisation verbs
cut API spendCaching
set a hard cost capReliability › Cost caps
retry on 429 / 5xxWorker › .retry()
redact PII before sending to a VLMReliability › PII redaction
stream pages from a 100-page PDFCookbook › Long PDFs
score a recipe against ground truthEvaluation
OCR pages in parallelOrchestrator › options
straighten a rotated scanPreprocessors › deskew/orient
binarise / sharpen each cell separatelyPreprocessors › Region refine
slice a tall cell into rowsPreprocessors › Slicers
use a few-shot exemplar from past correctionsWorker › .few_shot()
derive a correction dictionary from a labelled storePost-processors › dictionary.from_samples
let a human review detected cellsOrchestrator › Lever 1: HITL
cross-check the recognised text against the cropOrchestrator › Lever 2: Cross-check vs original
cross-check a run against ground truthOrchestrator › Lever 3: Cross-check vs ground-truth
re-OCR only the low-confidence cellsOrchestrator › 2c Confidence-driven re-OCR
plug in your own ML detectorDetectors › Writing your own
write a one-off stepOrchestrator › Writing your own step
use scriva from the shellCLI
port a FastAPI OCR app onto scrivaCookbook › Rebuilding ocr-agent