PrettyPipeline
Turn PDFs into structured JSON. OCR runs on your GPU. Field extraction uses a cheap cloud LLM. You define the schema.
PDF → PyMuPDF (pages → images) → Unlimited-OCR (local) → raw text
↓
GPT-5.4 nano (OpenAI) → JSON + needs_review
Why this is cheap
Cloud OCR APIs charge per page. PrettyPipeline does the expensive vision work locally with baidu/Unlimited-OCR (MIT, 3B params, 32K context). A whole PDF is parsed in one infer_multi() pass — no page-chunking.
The only paid call is GPT-5.4 nano on that text (~$0.20 / 1M input tokens), prompted with your JSON schema. You pay for a small text completion, not for pixels.
Nulls, model-marked uncertain fields, values not found in the source text, and OCR that looks garbled are flagged in needs_review instead of being silently accepted.
Digital PDFs — embedded text is used when available (fast, accurate). OCR runs only for scans or with --force-ocr.
Install
Python 3.10–3.13 (3.12 recommended). NVIDIA GPU (CUDA) or Apple Silicon (MPS). CPU works but is slow.
pip install prettypipeline-ocr
The CLI name is prettypipeline. From this repo:
python3.12 -m venv .venv
source .venv/bin/activate
pip install -e .
NVIDIA Linux — install a CUDA wheel of PyTorch first if pip gave you CPU-only:
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu124
pip install prettypipeline-ocr
The first run downloads baidu/Unlimited-OCR from Hugging Face (~6GB).
Quick start
export OPENAI_API_KEY=sk-...
prettypipeline run invoice.pdf --schema examples/invoice.schema.json
prettypipeline run invoice.pdf --schema examples/invoice.schema.json -o out.json
prettypipeline run invoice.pdf --schema examples/invoice.schema.json --ocr-only
Demo invoice in this repo:
prettypipeline run tests/fixtures/sample_invoice.pdf \
--schema examples/invoice.schema.json -o out.json
Digital PDFs use embedded text automatically. Use --force-ocr to always run Unlimited-OCR.
Schema
--schema is any JSON Schema. Nothing is hardcoded — swap the file to extract a different document type.
{
"type": "object",
"properties": {
"date": { "type": ["string", "null"] },
"vendor": { "type": ["string", "null"] },
"line_items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"description": { "type": ["string", "null"] },
"amount": { "type": ["number", "null"] }
}
}
},
"total": { "type": ["number", "null"] }
}
}
See examples/invoice.schema.json for a fuller invoice example.
CLI
prettypipeline run FILE.pdf --schema SCHEMA.json
-o, --output PATH write JSON to a file (also printed)
--ocr-only skip the OpenAI step
--force-ocr always OCR, skip embedded PDF text
--device cuda|mps|cpu override auto-detect (cuda → mps → cpu)
--dpi N PDF raster DPI (default 300)
--max-length N OCR cap (default 2048 on MPS, 32768 on CUDA/CPU)
OPENAI_API_KEY is required unless you pass --ocr-only. It is never hardcoded.
Output
{
"data": {
"date": null,
"vendor": "DEMO - Sliced Invoices",
"bill_to": "Test Business",
"line_items": [],
"total": null
},
"needs_review": [
{ "field": "date", "reason": "null" },
{ "field": "total", "reason": "null" }
],
"ocr_text": "…"
}
reason |
meaning |
|---|---|
null |
model returned null |
uncertain |
model marked the field as a guess |
not_in_source |
extracted value not found in document text |
Hardware
| Device | Support |
|---|---|
| NVIDIA CUDA (target: RTX 4060 Ti) | Native. Unlimited-OCR is written for CUDA. |
| Apple Silicon (MPS) | Supported. The model hardcodes .cuda(); PrettyPipeline remaps those calls to MPS. Short docs: --max-length 2048 — generation can loop on MPS. |
| CPU | Works, slow. |
License
MIT. Unlimited-OCR is also MIT.
Sample invoice fixture: Sliced Invoices.
Metadata
Release files for prettypipeline-ocr 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| prettypipeline_ocr-0.2.0.tar.gz | 12.4 kB | Without provenance | Details for prettypipeline_ocr-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| prettypipeline_ocr-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for prettypipeline_ocr-0.2.0-py3-none-any.whl |
Total release size: 23.3 kB
Release files / prettypipeline_ocr-0.2.0.tar.gz
| Download URL | prettypipeline_ocr-0.2.0.tar.gz |
|---|---|
| Size | 12.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e67b28522283774c72dc406f91190090083b586ffa5253705fe741a72cbf287b
|
|
BLAKE2b-256 checksum How to use checksums |
9bd62302b0ab4de7d7e230b762900e6a7780f65e3f17859b938ec0532db20ffe
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.9
|
Release files / prettypipeline_ocr-0.2.0-py3-none-any.whl
| Download URL | prettypipeline_ocr-0.2.0-py3-none-any.whl |
|---|---|
| Size | 10.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8882d837d5e0ef154238778748dd304be50240864ad63ff2e0f10eacc06fbc1f
|
|
BLAKE2b-256 checksum How to use checksums |
16349dbc738fe5c278b257f03ded8e8b77348b4600174f00c865201150fff409
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.9
|
Security for prettypipeline-ocr 0.2.0
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.