DEV Community

zero-zero-youtube
zero-zero-youtube

Posted on AI-assisted

Handwritten faxes, tilted phone-camera receipts, messy PDFs — I built an AI pipeline that turns them all into clean structured data

Handwritten fax orders. Receipts photographed at an angle on a phone. PDFs that all use different layouts. I built a small pipeline using Claude Code that reads all of these and turns them into one clean, structured spreadsheet — and I want to walk through exactly how it performed, including where it broke.

This is meant to demonstrate something a lot of back-office teams deal with every day: manually copying information from paper/photos/scans into a spreadsheet. How far can AI actually take that job?

The Pipeline

The idea is simple:

Watch a folder
      ↓
Detect a new file (PDF/image)
      ↓
Have Claude read it
      ↓
Extract company name, date, line items, quantities, and totals as JSON
      ↓
Append to one CSV
Enter fullscreen mode Exit fullscreen mode

The key point: the same pipeline handles all of these regardless of how messy the input looks. I deliberately generated three very different test files:

  1. A clean, well-formatted PDF (fictional purchase order, 3 line items)
  2. A receipt that looks like it was photographed on a phone at an angle (tilt, shadow, JPEG artifacts)
  3. A fax-style image with handwriting (broken layout, faded text, noise)

Results

All three files produced results that matched the source content exactly. Total processing time for all three: about 25 seconds (roughly 5–10 seconds per file).

Here's a sample of what came out (all company names are fictional test data):

Source file Vendor Date Item Qty Unit price Total
fax_handwritten.png (fictional) 8/20 Cardboard box, size 60 40 @98 approx. ¥62,000
fax_handwritten.png (fictional) 8/20 Cloth tape 50m 12 @340 approx. ¥62,000
order_clean.pdf (fictional) Aug 21, 2026 A4 copy paper, 500 sheets 20 ¥520 ¥38,720
receipt_photo.jpg (fictional) Aug 19, 2026 USB drive 64GB 5 1,280 ¥15,334

What I find most interesting is the handwritten fax row. Notice "@98" and "approx. ¥62,000" — it preserved the ambiguity of the handwritten notation exactly as written, instead of silently converting it into a clean number. That's by design: the extraction prompt explicitly instructs the model not to guess when something is genuinely ambiguous. Quietly "fixing" ambiguous handwriting into a confident-looking number would actually make this system more dangerous in a real back-office setting, not less.

All three files also correctly identified the issuing vendor rather than the addressee as the vendor field — a sign this isn't naive OCR, it's actually reasoning about document structure.

Implementation Notes

Running through a Claude Code subscription instead of metered API calls

I originally called the Anthropic API directly, but switched to invoking the Claude Code CLI as a subprocess instead. Simple reason: I didn't want to rack up API costs while still validating the idea.

claude -p "<extraction prompt>" --allowed-tools Read --output-format json
Enter fullscreen mode Exit fullscreen mode

Each file is processed as a separate, non-interactive CLI call. Using --output-format json gives you a structured envelope (with fields like is_error, result) that's much more robust to parse than raw stdout.

This does come with a real limitation: spinning up a new process per file doesn't scale to bulk processing. If you need to run hundreds of documents at once, going back to the metered API is the more sensible choice. For a small-scale demo like this, that tradeoff is fine.

A bug I found the hard way: "failure" wasn't actually being treated as failure

While testing, I found a real gap in the design. When you feed it a corrupted file, Claude correctly returns all fields as null, per the instructions. The problem: that was being treated as a "success" — an empty row got appended to the CSV, and the source file got moved into the "processed" folder and effectively disappeared.

That meant a failure could silently destroy the only copy of that file's data, with no error surfaced. I fixed this by treating "all key fields are null" as an error case, so failed files stay in the input queue for retry instead of vanishing.

What this is actually useful for

The point of this demo isn't "it can read purchase orders." It's that work assumed to require manual handling — because every input looks different — can actually be automated with AI, with reasonable reliability.

The same pattern applies to things like:

  • Reconciling invoices that use a different format for every vendor
  • Digitizing orders that only ever arrive by fax
  • Turning paper forms/surveys into structured data

If you're trying to figure out how to actually wire this kind of thing into a real business process — not just "chat with an AI," but an actual pipeline — I take on contract work designing and implementing systems like this. Feel free to reach out.

Closing thoughts

This was a small-scale demo, not a production system. But it validated something real: turning messy, inconsistent input into meaningful structured data — a boring but very common back-office problem — is something AI can genuinely do today, not just in theory.

Hope this is useful if you're exploring something similar.

Top comments (0)