@orbitqube/oq-ai-ocr
v0.1.3
Published
Document ingestion and OCR: byte-level format detection, text-layer-first reading, local PP-OCR engines, an escalation policy, and the eval harness that settles the thresholds with evidence. The TypeScript half of one contract shared with a Python impleme
Maintainers
Readme
oq-ai-ocr
Document ingestion and optical character recognition (OCR, reading text off a picture), by OrbitQube. It is everything around the recognition engine and not the engine itself: byte-level format detection, text-layer-before-OCR reading, the format readers, and a pipeline that says exactly what it did and warns on everything that degraded the reading.
This is the TypeScript implementation. A Python one answers the same contract, so a result crosses between them unchanged.
AGPL-3.0-or-later.
Install
npm install @orbitqube/oq-ai-ocrReads PDF, PowerPoint, Word, images and plain text out of the box.
import { extract } from "@orbitqube/oq-ai-ocr";
const bytes = new Uint8Array(await readFile("statement.pdf"));
const result = await extract(bytes, { filename: "statement.pdf" });
console.log(result.text); // the whole document in reading order
console.log(result.engine); // which engine read it, exactly
console.log(result.warnings); // coded, one per thing that degraded the readingThe accurate scan engine is optional
Reading a poor scan well needs PP-OCR, which is large, so you install it yourself. Without it, a
scan is still read by the always-present fallback and the result says so with an
engine_unavailable warning. Install it to read dense text and figures materially better:
npm install ppu-paddle-ocr onnxruntime-nodeIt is deliberately not declared as a dependency of this package, not even an optional peer: package managers install optional peers automatically, which would put roughly 300 MB into every consumer's tree whether or not they ever read a scan. The engine is loaded through a dynamic import that fails softly when it is absent, so declaring it would buy nothing and cost everyone the size.
Rasterizing a scanned PDF into images also needs the optional @napi-rs/canvas. Both are only
touched when a document actually has to be read as pictures.
What it does, and does not
- Reads the text layer first, and recognises pictures only when there is no usable text.
- Runs locally. No document is sent anywhere. Point
modelPathat a local directory of model files to keep a run fully offline; the first run otherwise downloads and caches them. - Never throws for a document problem. An unreadable page, an absent engine, a corrupt zip and a timeout come back as a degraded result with warnings, so one bad page does not lose the rest.
- Says where every page's text came from (
text_layerorocr) and names the engine, so a result is reproducible and a caller knows which numbers to trust.
Extending it
The format detector is a registry: createDetector({ signatures }) teaches it a format this
library has never met. A recognition engine is just a function (images, opts) => OcrRun, so a host
can inject its own with the engine option.
Reading order can be wrong
Recognised text is never perfect. Check a figure that matters before you trust it. The library carries an eval harness (character error rate, word error rate, numeric accuracy, reading-order fidelity) so a change to the engine or a tier can be measured rather than argued.
