DEV Community

Cover image for Order Taker: turning "kal subah 2 box brownies" into real orders with open AI
Tanay
Tanay

Posted on

Order Taker: turning "kal subah 2 box brownies" into real orders with open AI

Hacktoberfest Weekend Challenge: Build for a Friend Submission 🤝

This is a submission for the Hacktoberfest Weekend Challenge: Build for a Friend

What I Built

Picture the home baker down your street. They take every order on WhatsApp:

Priya: Hi aunty! Can I get 1 kg chocolate truffle cake for Sunday evening? Eggless please 🙏
Priya: Write "Happy Birthday Arjun" on it
Rahul Bhaiya: 2 box brownies kal subah, address 14B Lakeview Apts
Rahul Bhaiya: sorry make it 3 boxes
Meena: Good night aunty 😊
Sneha: 12 cupcakes vanilla + 6 red velvet, Saturday 4pm pickup. My number 98450 12345

That's six messages in a mix of English and Hindi. There's an edit ("make it 3 boxes"), relative dates ("kal", "Sunday"), a pickup, and someone just saying good night. Multiply that by a busy festival week and orders get missed, quantities get mixed up, and customers keep messaging "aunty, is my cake ready?"

Order Taker is built for that person: someone who is great at baking, not at spreadsheets, and who runs the whole business from one WhatsApp chat.

  • The shop owner pastes (or uploads) the WhatsApp chat. A small team of AI helpers reads it, and a friendly "What's happening" box explains each step in plain English as it goes. Each order shows up as a card to Accept, Edit or Discard, with anything odd flagged: "Delivery or pickup? No address was given."
  • Accepted orders move along with one big thumb-sized button: Received → Confirmed → Preparing → Ready → Delivered. There's a per-day prep list ("3 boxes brownies, 2 kg chocolate cake") and a CSV export.
  • Customers log in from their phone with their number and a PIN that the shop sends them on WhatsApp. They see a progress bar for their order, and they can change or cancel it in the app. Before the shop confirms an order, changes apply straight away. After that, they go to the shop owner as a request to approve, shown old → new.

The whole thing runs on the shop owner's laptop. Customers' phones reach it over the same Wi‑Fi.

Demo

The app is deliberately not hosted anywhere: customer names, phone numbers and home addresses never leave the laptop. To try it yourself, follow the 3-step setup in the README with samples/sample_chat.txt.

Update: from one laptop to a fully deployed app

Keeping it on the laptop was a choice for this first version, not a limit of the design. The same code can become a normal hosted web app that customers open from anywhere, not just on the shop's Wi‑Fi:

  • The web app is a standard FastAPI service. Every machine-specific setting is already an env var (ORDER_DB, ORDER_PORT, ORDER_PUBLIC_URL, OLLAMA_URL), so it can run on Render, Fly.io or a small VPS behind HTTPS with secure-only cookies.
  • The data moves from one SQLite file to a managed Postgres database. The numbered migrations are plain SQL, so they carry over.
  • The AI stays open. OLLAMA_URL can point to an open-weight model on a GPU server you control, or even back to the shop's own laptop through a private tunnel. Then the model still runs on the owner's machine, while customers get a public link.
  • Next steps after that: WhatsApp Business webhooks so orders arrive automatically instead of being pasted, an SMS or WhatsApp one-time code instead of a shop-issued PIN, and one install serving many home businesses.

The trade-off is honest: once it's hosted, customer data lives on a server instead of only on the laptop. That's why the project's specs treat it as a deliberate change to its "local-first" rule. The owner should choose it on purpose, not have it happen by accident.

Code

GitHub logo Tanay3484 / order-taker

Turn messy WhatsApp orders into a clean order board for home bakers, with local multi-agent AI (Ollama) so customer data never leaves the laptop.

title Order Taker
emoji 🧁
colorFrom pink
colorTo yellow
sdk docker
app_port 7860
pinned false
license mit
short_description Local AI agents turn WhatsApp orders into a bakery board

Order Taker 🧁

Turns messy WhatsApp order messages into clean orders for a small home business. The shop owner pastes the chat, a team of small AI helpers reads it, and customers can log in from their phones to see where their order is.

Everything runs on the shop owner's laptop with an open-weight model via Ollama, so customer names, numbers and addresses never leave the machine.

What it does

  • Shop owner (admin): paste or upload the WhatsApp chat. Watch a plain-English "What's happening" feed while it's read. Check, edit and accept each order, then move it along: Received → Confirmed → Preparing → Ready → Delivered.
  • Customers: log in with their phone number and a PIN the shop sends…

How I Built It

Open-weight model, running locally: qwen2.5:7b through Ollama, on an ordinary laptop with a 4 GB GTX 1650. Every model call uses Ollama's structured output with a JSON schema, and the result is validated with Pydantic before anything is stored.

Multi-agent intake, without a framework. The flow is a fixed pipeline, so plain asyncio was enough (about 150 lines), and it let me attach a progress message to every step:

pasted chat ─▶ Master (plain code): split by person, skip messages already read,
                spot pure "good night / thank you" without any AI
                  │  one track per person, all at the same time
                  ├─▶ [Sorter, small model*] ─▶ [Extractor, 7B] ─▶ [Checker, plain code] ─▶ draft card
                  └─▶ …
Enter fullscreen mode Exit fullscreen mode
  • Master splits the chat by sender and skips messages it has already handled, so you can paste the whole chat every evening and only new messages get read.
  • Extractor (one per person) sees only that person's messages and their open orders. That's how "sorry make it 3 boxes" becomes a change to the existing order instead of a duplicate.
  • Checker is just rules: missing date, missing address/pickup, missing phone, duplicates.
  • The AI proposes, a human decides. Nothing becomes a real order until the shop owner taps Accept.

The most interesting lesson: let code do what code is good at. On the first real run, the 7B model read Priya's "Sunday" as a Thursday and Sneha's "Saturday" as a Wednesday. Small models are bad at calendar arithmetic. So now the model only copies what the customer wrote ("Sunday", "kal", "5th Oct"), and a small lookup table in Python turns it into a date, counted from when the message was sent. Same with phone numbers: a regex finds "My number 98450 12345" every time; the model didn't.

Honest numbers on my laptop (the model only partly fits on the GPU, so Ollama runs one request at a time):

Old (one big call) Multi-agent
First order ready to check ~41 s ~20 s
Whole chat done ~41 s ~55 s
Dates, phone, chit-chat correct on the sample ✗ ✓

So on modest hardware the win is time to first order and correctness, not total time. On a machine with more VRAM and OLLAMA_NUM_PARALLEL set, the per-person tracks really do run side by side. The repo includes scripts/bench_intake.py so anyone can measure their own machine.

No "Processing…" spinner. A spinner that sits there for a minute makes non-technical users think the app is broken. Instead, the progress box narrates every step: "Meena is just chatting. Nothing to order.", "Still working on Priya's messages, nearly there…", "All done in 53 seconds: 3 things to check, 1 just chatting." These messages come from fixed templates, never from raw model output. A test fails the build if any of them contains words like "JSON", "API", "token" or "Ollama".

Spec Driven Development. Before writing code, I wrote a short constitution (local-first, plain English, AI proposes / human decides, mobile-first) and five feature specs with numbered acceptance criteria. Every one of the 154 tests names the criterion it covers (INT-21, TRK-23…). When the real model proved a spec wrong (the dates!), I updated the spec first and then the code. It's all in specs/.

Stack: FastAPI, SQLite, Jinja2, a little vanilla JS, Server-Sent Events for the live feed. No CDNs, no external calls.

Why Does Open Innovation Matter?

For this user, a closed API wasn't really an option:

  • Privacy: these chats are full of customers' phone numbers and home addresses. With an open-weight model running locally, none of it leaves the laptop. There's no third-party processor and nothing to explain to customers.
  • Cost: a home bakery might get 40 messages a day. Any per-token bill is real money for a tiny business. Local inference costs nothing per message.
  • It works when the internet doesn't: the app and the model run on the laptop, and phones only need the home Wi‑Fi.
  • Control: I could look at exactly where the model failed (weekday maths, optional JSON fields) and design around it. When I needed every field filled in, I tightened the JSON schema sent to Ollama. Swapping to another model is one env var (ORDER_MODEL=llama3.2).

And because the app is MIT-licensed, any other home business can run it, and any developer can add their language's words for "tomorrow".

My Agent Session

I built this pair-programming with Claude Code as my coding agent, using a spec-first workflow: we agreed the constitution and specs together, then it implemented feature by feature against them and ran the real model to check its own work.

Top comments (0)