Skip to content
JustFadyPublic

About

Document pipeline that survives real PDFs: classify, extract to a schema, validate with cross-field rules, route exceptions, measure per-field precision

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

docpipe

A document pipeline that survives contact with real PDFs. Extraction is the easy part; validation is what earns trust, so this does both and routes anything doubtful to a human with the evidence attached.

$ docpipe run ./inbox --out ./out
processed 4 documents: 2 ok, 2 exceptions → out/exceptions.md

$ docpipe eval ./inbox ./labels.json
documents 3 · type accuracy 100%

field              precision  recall    n
due_date                100%    100%    2
invoice_number          100%    100%    2
subtotal                100%    100%    2
total                   100%    100%    3

The pattern

  1. Classify the document type (invoice, purchase order, …) and refuse to guess below a confidence floor.
  2. Extract to a strict schema: typed fields, each with a confidence and the page it came from.
  3. Validate: required fields, formats (regex), types (numbers, dates in any common format), confidence floors, and cross-field rules like total == subtotal + tax with a tolerance.
  4. Route: records that pass go to records.jsonl / summary.csv; anything with an error goes to exceptions.md for a person, with the extracted values and page numbers.
  5. Measure: docpipe eval scores per-field precision/recall against your labels, so you know the numbers before it touches production.

Install

uv tool install "docpipe[anthropic]"      # or pipx
export ANTHROPIC_API_KEY=...              # omit to use the offline regex extractor
docpipe run ./pdfs --out ./out            # built-in invoice / purchase-order schema
docpipe --schema schema.yaml run ./pdfs   # your own document types

Schema

min_confidence: 0.6
doc_types:
  invoice:
    keywords: [invoice, "amount due", "bill to"]
    fields:
      invoice_number: {type: string, required: true, regex: "^[A-Z]{2,5}-\\d{3,8}$",
                       patterns: ["Invoice\\s*#?\\s*([A-Z]{2,5}-\\d{3,8})"]}
      subtotal:       {type: number, required: true, patterns: ["Subtotal:?\\s*\\$?([\\d,]+\\.\\d{2})"]}
      tax:            {type: number, default: 0, patterns: ["Tax:?\\s*\\$?([\\d,]+\\.\\d{2})"]}
      total:          {type: number, required: true, patterns: ["\\bTotal(?: Due)?:?\\s*\\$?([\\d,]+\\.\\d{2})"]}
      due_date:       {type: date,   required: true, patterns: ["Due(?: Date)?:?\\s*(\\S.+)$"]}
    rules:
      - {expr: "total == subtotal + tax", tolerance: 0.01, message: "total must equal subtotal + tax"}
      - {expr: "total > 0", message: "total must be positive"}

patterns drive the offline extractor and double as a cheap sanity check next to the model. Rules are tiny arithmetic/comparison expressions over numeric fields; nothing else is evaluated.

Extractors

  • anthropic: Claude returns JSON with a quote per field; the quote is used to locate the page.
  • rule: regex patterns from the schema. Deterministic; used for tests, CI and quick baselines.

Scanned PDFs have no text layer: run OCR first (or add an OCR loader) and feed the text in.

Development

uv venv && uv pip install -e ".[dev]" && .venv/bin/python -m pytest -q

The tests build a real single-page PDF in memory and run it through the whole pipeline.

License

MIT © Fady Youssef

About

Document pipeline that survives real PDFs: classify, extract to a schema, validate with cross-field rules, route exceptions, measure per-field precision

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages