Intake
This is the part everyone does by hand. A load request turns up written badly — half a sentence, a weight buried mid-paragraph, the delivery conditions mentioned in passing — and someone has to read it and type it into a system. Load one of the deliberately sloppy samples below and watch the values get pulled out of it, each one scored for how much of it is actually certain.
Scanning is switched off in this demo so the walkthrough stays on the processing pipeline. When it is on it runs entirely in your browser and the image is never uploaded, and it is built for clear printed text — a bill of lading, a rate confirmation, a screenshot of an email. Handwriting is a different engine again; how that path works, and what it costs to switch on, is spelled out below.
Reading handwriting — how it would work, and why it is off here
The reader above is a printed-text engine; its models are trained on type. Point it at a handwritten counter note and it does not return a worse version of the note — it returns the ruled lines of the paper and the grain of the desk as punctuation. That is not a tuning problem, so the honest fix is a second engine built for the job rather than a better set of knobs on this one.
That second engine is a cloud reader. Concretely, on the path we have built:POST vision.googleapis.com/v1/images:annotate withDOCUMENT_TEXT_DETECTION and the handwriting language hinten-t-i0-handwrit. What comes back is the full transcript plus a per-word confidence, which drops into the same scan report you would see above — same weak-word list, same “check these first”. Nothing downstream changes: extraction, the confidence scores, the amber flags and Resolve all sit behind the reader and do not care which one ran.
Why it is switched off. Handwriting is the one path where the image has to leave the device — browser, to a route on this site, to the vendor. That is a decision a client should make on purpose, with the vendor terms in front of them, rather than something a demo does to them quietly. So the request builder, the response parser and the server route are all written and under test in this codebase; the interface simply does not offer them.
Want to see it read an actual handwritten note? Say the word. Turning it on is a credential and a redeploy — we would enable it and send you a fresh link the same day.
Where a vendor call like that would live in production
The path we built is your browser → a route on this site → the vendor. The API key sits in an environment variable on the server and is never sent to the browser. That matters more than it sounds: a key placed in client-side JavaScript is a published key — anyone can read it out of the page and spend against it.
One app route is the right size for a demo. At company scale a call like this usually belongs in a dedicated routing layer — a Cloudflare Worker, an API gateway, a small proxy service — sitting between the app and the vendor. What that buys you:
- One place holds the credential. Rotating a key becomes a change in one service rather than a redeploy of every app that calls the vendor.
- Budgets and rate limits per tenant. A cap at the edge helps contain a runaway retry loop or a scraper before it works through your quota.
- Redaction before egress. Names, contact details and account numbers can be stripped or masked at the boundary, so less leaves the perimeter than the caller happened to send. This demo already does that for text.
- Swapping vendors without touching the app. A second provider, an on-premises model, or a failover when one is down — all a routing decision.
- Caching and de-duplication. The same document scanned twice need not be paid for twice.
- One audit trail and one place to enforce residency. A single chokepoint can record what left, when, and on whose behalf, and keep a region's traffic inside that region.
- Timeout and retry policy in one place rather than reimplemented, differently, by every caller.
And on what would happen at the far end, these are Google’spublished statements rather than assurances we can give on their behalf. For synchronous requests of that kind, Google states images are “processed in memory and not persisted to disk”, and that it “does not use the content you send to train and improve our Cloud Vision features”. Google also notes it temporarily logs some request metadata. Anything you intend to rely on contractually is worth reading in full, and worth a lawyer’s eye: Vision data usage · Google Cloud terms of service · Cloud privacy notice · Data processing addendum
The system at work
All three views sit side by side: the pipeline that runs, the options it produces, and the architecture underneath. Play replays a finished run through all three in order, or switch to tabs to take them one at a time.
What is real here
Real
- The rate model, distance math, accessorial rules, and lane ranking all run for real — same inputs, same numbers, every time.
- The extraction step produces a typed record with per-field confidence, every field shows the score it earned and how it was arrived at, and anything below the review threshold is surfaced for human correction rather than silently accepted. Which of those corrections you are allowed to make depends on the role signed in at the top of the page, and the role that acted is written into every line of the decision log.
- Image scanning is switched off in this demo — deliberately, so the walkthrough stays on the processing pipeline rather than on a file picker. The reader itself is built and tested: it runs entirely in your browser, the image never leaves your machine, and it names which engine ran, how long it took and its least-confident words. It reads printed documents well; handwriting is a different engine. Ask and it goes back on.
- The engine is a pure, dependency-free TypeScript module with its own test suite; the UI is a Next.js 16 / React 19 app around it.
- The weight estimator is real arithmetic on the sampled rows — median and interquartile range (not a mean, which one outlier would wreck), matched on commodity and equipment, then checked against the legal payload for that trailer. Every decision on a flagged field is recorded with the basis behind it.
Stubbed on purpose
- Field extraction is a deterministic parser standing in for an LLM call. In the production shape of this, that step is a model call returning a Zod-validated object — the rest of the pipeline is unchanged, which is the point.
- Rates, transit times, and carrier scores are plausible synthetic values, not a live market feed.
- The shipment history behind “Resolve” is generated locally, not a live database — the query shape, the statistics, and the read-only framing are what a real integration looks like; the rows are synthetic. The other resolution strategies are registry entries with no adapter behind them yet.
- Distances are straight-line estimates against a small city table, not routed road miles.
- Handwriting reading is built but not switched on for this demo. A printed-text engine cannot read script at all, so that path needs a cloud reader — and reaching one means the image leaves the device, which is a call a client should make deliberately rather than have a demo make for them. The request builder, the response parser and the server route exist here with their own tests; the interface keeps them off. Intake explains the whole path, and we can enable it on request and send an updated link.
Try it yourself
None of this is a video. Load one of the deliberately messy sample requests, watch it become a typed record with a confidence score on every field, and price it against the rate model. Then open Resolve on anything flagged amber to see an uncertain number settled from historical shipments rather than assumed.
Built by Michael O'Hair · Neptoniq Creations LLC · Reno, NV