Skip to main content

VeriScript

Offline document restoration. A photo, scan or PDF goes in; a cleaned page with a searchable PDF, overlay, transcript, Markdown and OCR JSON comes out — with honest flags on the numbers it is not sure about. Devanagari (Nepali/Hindi) first, English supported by the same pipeline.

Everything runs on your machine. No cloud calls, no telemetry, no account.

Live demo: https://veriscript.live — one page at a time, no signup; demo uploads are deleted after the 60-minute retention window.

photo/scan/PDF ──▶ orientation ──▶ layout ──▶ OCR ──▶ risk flags ──▶ searchable PDF
                                                                  ├─ overlay.png (review boxes)
                                                                  ├─ transcript.txt
                                                                  ├─ transcript.md (Markdown)
                                                                  └─ ocr.json (tokens + queue)

Before / after

VeriScript before and after: an aged letterpress page and a shadowed invoice photo, restored with the numbered review queue

Real pipeline output. Green = accepted, amber = uncertain, red = digit conflict with the alternative reading kept. The letterpress page is from heiDATA (doi:10.11588/data/EGOKEI, CC BY 4.0); the photo row is this repository's own synthetic fixture under a simulated phone shadow. Regenerate with python scripts/make_demo_image.py.

Why it exists

  • It will not invent the numbers on your bill. Digits are the highest-risk tokens, so they are re-read, risk-ranked and put in a review queue instead of being silently guessed. The queue is measured, not asserted (EVALUATION.md).
  • Devanagari is a first-class citizen, not a language pack. Letterpress books, modern government PDFs and phone photos each have frozen evaluation sets with published numbers and confidence intervals.
  • Offline by default. Privacy is the reason to use this instead of a cloud lens: the pipeline runs with networking disabled.

Install

pip install veriscript              # document pipeline + CLI (no torch)
pip install "veriscript[photo]"     # + photo upscaling (torch)
pip install "veriscript[verifier]"  # + the optional bodhan digit verifier

From a source checkout:

pip install -r requirements.txt        # full runtime (includes torch)
pip install -r requirements-dev.txt    # + dev/eval tooling (optional)

Optional: Tesseract 5 as a second OCR backend (clean-scan fallback and the OSD rotation fallback).

Use

CLI

# Photo/scan in: searchable PDF + overlay + transcript + Markdown + JSON out
python cli.py --mode document --input page.jpg --output out/run1

# PDF in: first page by default; --max-pages 3 = first three pages
python cli.py --mode document --input scan.pdf --output out/run1 --max-pages 3

# PDF → Markdown: per-page .md always; --max-pages 0 adds one combined .md
python cli.py --mode document --input report.pdf --output out/report --max-pages 0

# Same CLI as a module / installed console script:
python -m veriscript --mode document --input report.pdf --output out/report

# Photo upscaling (shares the same CLI/app)
python cli.py --mode photo --input photos/ --output out/upscaled --scale 4

Useful knobs (all default to the measured best configuration):

--ocr rapidocr|tesseract     --lang en|ne|hi       --deskew
--no-reading-order           --rotate auto|off     --repass-digits/--no-repass-digits
--digit-verifier off|bodhan  (optional second-model digit check)
--no-pdf --no-overlay --no-txt --no-md

Web app (the studio)

The single UI — FastAPI + SolidJS, running the same pipeline and outputs (searchable PDF, transcript, Markdown, OCR JSON) as the CLI.

pip install -r webapp/requirements-web.txt    # backend, on top of requirements.txt
cd webapp/frontend && npm install && npm run build && cd ../..
python webapp/server.py                       # http://127.0.0.1:8000

Hosted deployments (Docker, basic auth, HF Spaces/Render/Fly) are covered in docs/DEPLOY.md. The server binds to localhost by default; the pipeline, models and any training artifacts stay server-side. The photo upscaler is CLI-only (its weights are non-commercial); the web studio is document-only — see docs/PLAN_WEB_FULL.md.

For JS/TS integrations there is a typed HTTP client in packages/veriscript-client (npm: veriscript-client; not published yet).

Outputs (per page)

For an input page.jpg, every run writes:

File Contents
page.pdf searchable PDF — cleaned image + invisible Unicode text layer (Devanagari included; bundled Mukta font), selectable/copyable
page_overlay.png cleaned page with numbered review boxes for the flagged tokens
page.txt reading-order plain text
page.md Markdown transcript — the text plus the review queue as a table (this is the PDF → Markdown output)
page.json tokens, risk flags, review queue, orientation/reading-order evidence
report_pNNN.* per-page set for a multi-page PDF (report_p000.pdf, report_p000.md, …)
report_combined.pdf / .txt / .md all pages joined with --max-pages 0; the combined Markdown has one ## Page N section per page

The web studio serves the same artifacts under canonical names (restored.png, searchable.pdf, transcript.txt, transcript.md, ocr.json, combined.md). --no-md (CLI) or the Markdown toggle (web) skips the .md files.

Measured behaviour

Numbers below come from hash-frozen evaluation sets with bootstrap 95% CIs (full tables, provenance and rebuild commands: docs/EVALUATION.md). No number in this repo is marketing.

Capability Measured
Orientation (EXIF + 0/90/180/270 via OCR evidence) 16/16 synthetic; 0/30 false rotations on upright real scans; 90/90 rotated pages decided
Devanagari — modern government PDFs (raw engine) CER 0.135 [0.097–0.186], exact-token recall 0.877 (n=41, Gemini-2.5-Pro anchor GT, engine-corroborated)
Devanagari — letterpress books (the honest bar) CER 0.434 [0.387–0.481] raw; 0.373 under the default auto line reader (42/69 pages engaged, Appendix AE); exact-token recall 0.647 (n=69, human-corrected ALTO GT)
Devanagari — rendered fixtures clean CER 0.030/0.028; degraded ne 0.094 (pass) / hi 0.170 (heavy fails)
Digit honesty — 2× re-pass (default ON for Devanagari) review-queue digit recall@10 0.88 letterpress / 0.38 PDFs (was 0.73 / 0.15), ≈ +0.4 s/page
Flags + calibration script_mismatch, invalid_sequence (impossible combining sequence), isotonic cal_conf; ECE 0.82 → 0.30 on scans; optional unknown_word lexicon flag (needs scripts/fetch_nepali_lexicon.py) lifts the frozen-PDF review queue R@10 0.148 → 0.175 with the digit queue unchanged
Optional digit verifier (--digit-verifier bodhan) flags 0.71 recall / 0.81 precision; opt-in (cost gate failed: +8.3 s/page)
Multi-page PDF --max-pages 0 → every page + <stem>_combined.pdf/.txt; GUI "All pages" checkbox
Two-column reading order arXiv set WER 0.870 → 0.268 (−69%) on split pages; >2 columns unsupported
Phone-photo proxy (not real photos) CER 0.370 medium / 0.757 heavy (clean 0.135) — recognition, not honesty, is what breaks
Mixed-page router (opt-in) restored text + untouched logos/photos (non-text PSNR 60–67 dB vs 18–23 dB naive); 1 invented token on photo texture → not auto-enabled
Detection on real pages covers 97.5% of ALTO line boxes (area view) — recognition, not detection, is the bottleneck

Known limitations are listed with their evidence in docs/EVALUATION.md and the full research log in docs/PLAN.md. Since 2026-10-01 the image paths (CLI and web studio) default to the auto line-reader gate — running text + aged paper only. PDF inputs keep the engine reading, and the hosted document-only demo ships no reader checkpoint, so it stays on the engine there.

How it compares

Head-to-head on the frozen Devanagari hard-10 (the table-heavy hardest 10 of the 41-page nepali_pdf_v2 set, Gemini-2.5-Pro anchor GT; every arm scored by the same metric code — canonical write-up in docs/BENCHMARK.md, raw lab notes and reproduction commands in evals/bakeoff_results.md):

Engine CER (mean [95% CI]) Median CER bagCER Speed (s/page) Runs on CPU
Surya OCR 2 0.166 [0.100–0.258] 0.107 0.360 172.0 ✗
Qwen3-VL-8B NF4 0.176 [0.129–0.235] 0.141 0.369 152.7 ✗
VeriScript pipeline (default) 0.255 [0.202–0.329] 0.227 0.376 7.3 ✓
raw RapidOCR engine 0.530 [0.463–0.585] 0.543 0.380 3.8 ✓
PaddleOCR 3.x full pipeline 0.662 [0.585–0.713] 0.687 0.400 21.8 ✓

Speeds are per page on the harness hardware — ours, raw and Surya on an RTX 2050 4 GB (Surya via llama.cpp/Vulkan), Qwen on a T4 (NF4), PaddleOCR on CPU. Runs on CPU: ✓ = CPU-first (PaddleOCR was measured CPU-only here; VeriScript and RapidOCR ship CPU-first); ✗ = GPU-class in practice — a GPU was used and CPU would be far slower.

Metrics. CER (character error rate) is the edit distance between the OCR output and the ground truth (insertions + deletions + substitutions) divided by the number of ground-truth characters: order-sensitive, 0 is perfect, lower is better. bagCER is the same character distance after alphabetically sorting the tokens on both sides — it ignores reading order, so it isolates glyph recognition from layout (a page with perfect words in the wrong order still scores 0). Median CER is the middle page's CER, robust to a single catastrophic page; s/page is seconds per page.

Reading. bagCER is tied across every arm (0.360–0.400): glyph recognition is a commodity, and the page-CER spread is reading order, table structure and digit handling — which is where this pipeline earns its keep (0.530 → 0.255 over the raw engine on the same frozen pages, while staying CPU-first, offline and Apache-2.0). Surya 2 reads best by median at ~23× our page time and OpenRAIL-M weights, and the GPU arms invent text the source never contained (82–224 tokens over the 10 pages); only this stack ships an alternative-reading digit review queue.

Project layout

veriscript/               the product package
  cli.py                  command-line entry point (document + photo)
  core/                   dataset IO + metrics (doc_data, doc_metrics), degradation
  document/               pipeline: OCR, layout, orientation, restore, export, router, verifier
  deva/                   Devanagari line reader (CRNN+CTC), opt-in via --deva-lines
  photo/                  photo/vector stack (parked; CLI photo mode)
  branding.py, logging_setup.py, lexicon.py, calibration.py
cli.py                    compatibility launcher for `python -m veriscript`
webapp/                   the studio: FastAPI backend (vvweb/) + SolidJS frontend
deva_crnn/                training package for the line reader (repo tooling)
evals/harness/            evaluation harnesses (frozen sets, metrics, gates)
evals/manifests/          content-hash frozen evaluation sets
scripts/                  data acquisition, training export, gates, release tooling
tests/                    the test suite (pytest counts them; ~338)
docs/                     architecture, evaluation, deployment, licensing, plan

Docs

Document Contents
docs/ARCHITECTURE.md module map, data flow, extension points
docs/EVALUATION.md frozen sets, metrics, how to reproduce every number
docs/DEPLOY.md hosted web app (Docker, auth, spaces)
docs/LICENSES.md dependency + model license gate
docs/RELEASE.md release checklist, versioning, desktop packaging path
docs/PLAN_WEB_FULL.md web studio: audit, diet and phased plan
docs/MARKET.md market landscape, competitors, positioning
evals/bakeoff_results.md head-to-head bake-off results on the frozen sets
docs/PLAN.md the full research log and decision record

Tests

python -m pytest tests/ -q

The suite (≈336 collected) covers: OCR/export/routing/CLI/web, layout, orientation, language plumbing, frozen-manifest and CI guards, GT-validity audits, error taxonomy, anchor harness, queue metrics, Unicode-path IO, Devanagari line synthesis, CRNN plumbing (height/width round-trip, beam search, cosine fine-tune), the real-line mining gate, the opt-in line reader (merge geometry, table-rule blocking, auto policy, graceful degradation, provenance), the lexicon fetch/build + unknown_word flag mechanics, the textbook harvest parsers + real-print scan probe, the CC-100 corpus builder + controlled sampler, the Vertex wheel builder and the trainer GCS output path, the Devanagari PDF text-layer extraction round-trips, the logging configuration + server-error capture, and the Markdown export (per page and combined).

Data, models and licensing

This repository contains code and evaluation evidence only: no training datasets, no model checkpoints and no redistributed third-party corpora. Evaluation manifests record hashes and provenance; the data itself stays local (data/, weights/ and artifacts/ are git-ignored). The optional Devanagari lexicon behind the unknown_word flag is built locally by scripts/fetch_nepali_lexicon.py (Apache-2.0 + MIT sources) and is not redistributed. Third-party license obligations and the air-gap story are tracked in docs/LICENSES.md.

MIT licensed — see LICENSE. Third-party components keep their own licenses (RapidOCR/PP-OCR Apache-2.0, reportlab/pypdfium2 permissive, PySide6 LGPL, UltraSharp weights CC-BY-NC-SA and therefore excluded from commercial builds).

Metadata

Release files for veriscript 1.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for veriscript 1.6.0
File Size Uploaded
veriscript-1.6.0.tar.gz 426.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for veriscript 1.6.0
File Interpreter ABI Platform
veriscript-1.6.0-py3-none-any.whl Python 3 none any Details

Total release size: 784.9 kB

Release files / veriscript-1.6.0.tar.gz

Download URL veriscript-1.6.0.tar.gz
Size 426.5 kB
Tags Source
SHA-256 checksum
How to use checksums
ab2c923893180bfdfc66a5879ff29e5501b6ae46a434c2aa11da13f89bc5e552
BLAKE2b-256 checksum
How to use checksums
69b29d23eeb218c5245979fa07317c0690b336a3bf5bf71624889b05e840553b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release files / veriscript-1.6.0-py3-none-any.whl

Download URL veriscript-1.6.0-py3-none-any.whl
Size 358.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2725971ed7b2b9f741ba190915fa00f10de89bb64087e68a510705d35accfbdc
BLAKE2b-256 checksum
How to use checksums
5f339605bfc73816c5d4ada2763da8d3848ac1898463113f96282fd365ad22f7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.6.0 This release

2 release files

1.5.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page