Metadata-Version: 2.4
Name: oq-ai-ocr
Version: 0.1.0
Summary: 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 all of it with evidence.
Author-email: Tushar Bansal <tushar@orbitqube.com>
License-Expression: AGPL-3.0-or-later
Project-URL: Homepage, https://github.com/orbitqube-tech/oq-ai-ocr
Keywords: ocr,document,extraction,pdf,paddleocr,onnx,evals
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: jiwer<5,>=4
Provides-Extra: rapidocr
Requires-Dist: rapidocr<4,>=3.9; extra == "rapidocr"
Requires-Dist: onnxruntime>=1.27; extra == "rapidocr"
Requires-Dist: opencv-python-headless>=4.8; extra == "rapidocr"
Provides-Extra: documents
Requires-Dist: pypdfium2>=5.12; extra == "documents"
Requires-Dist: pdfplumber>=0.11; extra == "documents"
Requires-Dist: python-docx>=1.2; extra == "documents"
Requires-Dist: python-pptx>=1; extra == "documents"
Requires-Dist: openpyxl>=3.1; extra == "documents"
Requires-Dist: pillow>=11; extra == "documents"
Requires-Dist: numpy>=2; extra == "documents"
Provides-Extra: ai
Requires-Dist: oq-ai-router>=0.1; extra == "ai"
Provides-Extra: server
Requires-Dist: fastapi>=0.115; extra == "server"
Requires-Dist: uvicorn[standard]>=0.30; extra == "server"
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Provides-Extra: all
Requires-Dist: oq-ai-ocr[documents,rapidocr,server]; extra == "all"

# 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, an escalation policy that
decides when a model is worth calling, and an eval harness that settles every threshold with a
measurement rather than an argument.

This is the Python implementation. A TypeScript one answers the same contract, so a result crosses
between them unchanged.

AGPL-3.0-or-later.

## Install

The core installs with no recognition engine and no model client at all, which is what lets a
consumer prove no model is even present. Extras pull the engine and the document readers:

```sh
pip install "oq-ai-ocr[rapidocr,documents]"
```

- `rapidocr` adds PP-OCR on ONNX Runtime, for reading scans.
- `documents` adds the PDF, Word, PowerPoint, Excel and image readers.
- `server` adds an optional HTTP surface.

## Use

```python
from oq_ai_ocr import extract

result = extract(data, filename="statement.pdf")
print(result.text)       # the whole document in reading order
print(result.engine)     # which engine read it, exactly
print(result.warnings)   # coded, one per thing that degraded the reading
```

## What it does, and does not

- **Reads a document's own text first**, and recognises pictures only when there is no usable text.
- **Runs locally.** No document is sent anywhere. Recognition models download once and cache.
- **Never raises for a document problem.** An unreadable page, an unavailable engine, a corrupt zip
  and a timeout come back as a degraded result carrying warnings, so one bad page does not lose the
  rest. It raises only for a programming problem.
- **Says what it did.** Every result names the engine that read it, marks each page as text-layer or
  recognised, and carries a coded warning for everything that degraded the reading.
- **No threshold is a guess.** Every number that decides behaviour comes from a run of the eval
  harness and names the run it came from.

## Reading order can be wrong

Recognised text is never perfect. Check a figure that matters before you trust it.
