# Kwota: a Nigerian plumber talks through the job in Pidgin, and the customer gets a priced quote on WhatsApp

> Source: <https://dev.to/aghazie_david_4dc30f4c9a8/kwota-a-nigerian-plumber-talks-through-the-job-in-pidgin-and-the-customer-gets-a-priced-quote-on-1f04>
> Published: 2026-10-19 01:06:59+00:00

*This is a submission for the [Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle](https://dev.to/challenges/hacktoberfest-week2-2026-10-12)*

In Nigeria, if your tap is leaking, you call a plumber you know. He comes, looks under the sink, says "e no too bad", and tells you he'll "send you the price". Then the price arrives two days later, or not at all, often as a voice note or a photo of a page torn from an exercise book.

That gap between *looking at the job* and *sending the quote* is where artisans lose work. Writing quotes is unpaid evening work. A slow quote goes to the next plumber, and a handwritten one looks less trustworthy than it should.

**Kwota** (it's how "quote" sounds when you say it in Pidgin) closes that gap before the artisan leaves the customer's gate:

**Who pays?** Independent artisans: plumbers, painters, tilers, AC technicians and electricians. There are millions of them, and their whole business already runs on WhatsApp. A neat quote that lands in ten minutes wins jobs. The model I have in mind is a small monthly fee (around ₦1,500, about the cost of a recharge card), or pay-per-quote for artisans who only quote a few times a month.

Two rules shaped everything:

Live on Hugging Face Spaces (free ZeroGPU): [https://huggingface.co/spaces/Cipoklean/kwota](https://huggingface.co/spaces/Cipoklean/kwota)

Open it, pick a trade (plumber, painter or tiler sample price lists), then record or type the job. A typed run of the voice note above gives:

| Item | Qty | Unit price | Amount | Check | 
|---|---|---|---|---|
| Leak repair labour | 2 point | ₦6,000 | ₦12,000 | ✓ heard "two points" | 
| ½ inch PVC pressure pipe | 3 length | ₦3,800 | ₦11,400 | ✓ heard "three lengths" | 
| Elbow / bend fitting | 4 pc | ₦700 | ₦2,800 | ✓ heard "four" | 
| Workmanship | 1 job | ₦15,000 | ₦15,000 | ⚠ price you said | 

Then **Make the quote** produces the PDF (with a proper ₦ sign, which needed a bundled font) and a `wa.me` link with the message ready to send.

There's also a **Test the ear** tab. Upload a batch of voice notes and the numbers each one *should* contain, and it scores how well the speech model kept them.

| title | Kwota | 
|---|---|
| emoji | 🧾 | 
| colorFrom | green | 
| colorTo | gray | 
| sdk | gradio | 
| sdk_version | 6.30.0 | 
| python_version | 3.12 | 
| app_file | app.py | 
| pinned | false | 
| license | mit | 
| short_description | Talk a job through in Pidgin, send a quote on WhatsApp | 

Kwota turns a Nigerian artisan's walk-through voice note into a clean, priced quote they can send on WhatsApp before leaving the customer's gate.

A plumber, painter or tiler inspects the job, takes a few photos and talks
*"Madam, the kitchen tap dey leak for two points. I go change three lengths of half inch pipe, four elbows."*
Kwota hears it, maps it onto **the artisan's own price list**, shows every number it heard
for a quick check, then makes a PDF and opens WhatsApp with the quote typed out.

Quoting is unpaid evening work. Slow quotes lose jobs, and handwritten ones look less trustworthy than they should. Most artisans already run…

Plain Python and Gradio: `kwota/asr.py` (speech), `kwota/numbers.py` (quantity extraction), `kwota/quote.py` (price lists, the Gemma draft and its validator), `kwota/llm.py` (Gemma backends), `kwota/document.py` (PDF and WhatsApp). 15 tests cover the number and quote logic.

```
voice note ──► NaijaVox-2.0 (open ASR: Pidgin, Yoruba, Hausa, Igbo, Nigerian English)
                    │
photos ──► Gemma 3 (multimodal) ──► one-line job scope (never sizes, never prices)
                    │
transcript ──► Gemma 3 12B ──► line items chosen from YOUR price list, as JSON
                    │
          numbers.py ──► every quantity actually heard, plus the words it came from
                    │
    confirm screen: anything unheard is flagged, and everything is editable
                    │
            PDF quote + wa.me link
```

**Listening: NaijaVox-2.0.** An open speech model trained on Nigerian speech. Whisper-style models trained mostly on global English fall apart on "e dey leak for two points". Long voice notes get cut into 28-second chunks with overlap, so nothing falls between the cracks.

**Thinking: Gemma 3 12B** (`unsloth/gemma-3-12b-it`, an ungated mirror), running on the Space's ZeroGPU. Gemma gets the transcript and the price list (ids, units, aliases, but **no prices**) and returns JSON: which item ids were mentioned, the quantity, and the exact words it came from. It also writes the one-sentence job description, and reads photos when they're attached. The same code runs offline through Ollama (`gemma3:4b`) on a laptop, which matters for an artisan who doesn't want his customers' data on someone else's server.

**Not trusting the model: `validate()` + `numbers.py`.** This is the part I'm proudest of, because speech recognition *will* get words wrong. NaijaVox's own benchmark puts Pidgin word error at roughly one word in seven, and a misheard number costs the artisan real money. So:

`numbers.py` deterministically pulls out every quantity in the transcript: digits, English number words, `⚠ check qty`. If Gemma picks an id that isn't on the list, it's dropped. Prices are always looked up, never generated.
**A bug worth telling.** During the final test, *"Workmanship na fifteen thousand"* produced a quote of **₦150,000,000**. The matcher read "fifteen thousand" as fifteen thousand call-outs at ₦10,000 each. That's exactly the failure this whole design exists to catch, and it slipped through anyway. Now a bare amount of a thousand or more is treated as naira, never as a count. On a per-job line it becomes the price the artisan said, flagged for him to confirm, and a test pins it down. Any plumber who saw a ₦150m quote would have closed the app forever.

**Memory without a server.** The business name, phone number and edited price list live in the artisan's own browser (Gradio `BrowserState`). Kwota has no database and no account to create.

Because the people Kwota serves are exactly who closed AI handles worst, and can least afford.

`gemma3:4b` for offline use.
Built solo in Nigeria. If you know an artisan who quotes by voice note, send them the link. I'd love to hear what they'd want next.
