Data pipeline · 2026
Dental Price Matcher
Turns a weekly dental supply order into a ranked list of cheaper places to buy it. Upload the distributor's order PDF; the pipeline parses every line, sweeps the open web for the same product, verifies each candidate page, and returns three Excel workbooks showing exactly where the practice is overpaying.

Overview
A dental practice orders the same twenty-odd consumables every week from a single distributor. Nobody has time to price-check twenty SKUs across a dozen suppliers by hand, so the practice quietly overpays — every week, indefinitely.
Parsing runs as a token state machine over PyMuPDF output with an OCR fallback for scanned orders, and every row must satisfy `qty × unit ≈ extended` before it is accepted — so misalignment fails loudly instead of producing phantom line items.
Role
Backend & frontend
Timeline
2026 · shipped
Stack
One door in, and a preview before anything is spent
The practice drops in the week’s distributor PDF. Before a single API call is made, the parser’s reading is shown back for confirmation — every SKU, quantity, unit and extended price. A bad parse is caught here rather than after it has burned credits and produced a report nobody can trust.

Watch it think
Enrichment, sweep and verification run as visible stages rather than a spinner. Groq or Gemini reads each free-text description into brand, variant, size and pack quantity; SerpAPI sweeps the open web with no hardcoded supplier list; Firecrawl re-reads every candidate page with JavaScript rendering. The activity log names what each service is doing and when.


Three workbooks and a paper trail
Every completed run is kept: exact price matches sorted by total savings, alternate purchases driven by a client-editable equivalency table, and a full evidence file carrying every URL, price, condition and rejection reason. A price movement can always be traced back to the page it came from.

Owned by the practice, not by me
Providers and keys live in the admin portal, masked and testable in place. The LLM provider is switchable, excluded domains and the equivalency table are editable without touching code — so the rules that decide what counts as a match stay in the client’s hands.

The challenge
What made it hard
A PDF is not data. Column misalignment in a parsed order invents line items that were never on it, and a phantom row poisons every number downstream.
Free-text product descriptions do not match across suppliers. "Same product" has to survive different brand spellings, pack sizes, variants and units before a price comparison means anything.
Search results lie. A shopping listing's title often disagrees with the page it points at, plenty of supplier prices sit behind a login wall, and category pages masquerade as products.
Approach
How it was built
Each line is enriched by Groq's llama-3.3-70b into brand, variant, size/form, pack quantity and MPN, then swept against SerpAPI Google Shopping with an organic backfill. There is no hardcoded supplier list, so any legitimate seller can surface; request pacing and backoff keep the whole thing inside a free-tier rate limit.
Every candidate page is re-read by Firecrawl with JS rendering against a JSON schema — price, pack, variant and login-wall status — and page content always beats the search-result title. Matching then combines deterministic pre-checks (price sanity, volume normalization, exact pack equality) with AI validation against four criteria: brand, product name, size/form and pack quantity.
The filtering rules are deliberately harsh and client-editable without code changes: excluded domains and their subdomains dropped, category and search URLs barred from ever becoming a match, pack-mismatched candidates kept out of the primary report at any price, and login-walled pricing rejected onto a flagged-sites sheet.
Outcome
What shipped
Three Excel reports per run: exact price matches sorted by total savings, alternate purchases driven by a client-editable equivalency table, and a full evidence audit carrying every URL, price, condition and rejection reason.
Runs as a CLI, as a FastAPI service, or through a React admin portal — upload, parse preview, processing, results, history and settings — with a dry-run mode that validates the parser against real orders without spending on APIs.
Want something like this?
Tell me what you're building and I'll tell you honestly how I'd approach it. Replies within hours.
Prefer email? Write to me directly at — it reaches the same inbox.