DEV Community

Rahul Tapase
Rahul Tapase

Posted on AI-assisted

My mom runs tuition from a paper register. I built her one that reads Hinglish, runs offline, and never does the maths itself

Hacktoberfest Weekend Challenge: Build for a Friend Submission 🤝

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

What I Built

My mom teaches home tuition. About 25 kids come to her, from class 1 to class 10.

Everything lives in a paper register. Attendance goes in one column, fees in another, and in the margins there are notes like "paid half, rest next week". Parents message her on WhatsApp: "Ma'am 1000 bhej diya, baaki next week". At the end of the month she goes back through the register and the WhatsApp chats and adds up, by hand, who has paid for which month and who still owes. Then comes the part she likes least: reminding parents about fees without sounding rude.

So I built Tuition Register. She types a line the way she'd write it in the register:

riya nahi aayi, aman ne 1500 diye oct ke, baaki 500 next week

and it becomes three entries: Riya absent today, ₹1,500 from Aman for October, and ₹500 promised by next Monday. From those it keeps a month-by-month dues list and drafts a polite reminder she can copy into WhatsApp.

The one rule I built everything around: Gemma reads, code counts. The model copies words out of her line. It never computes a balance, a date or an amount. Code checks everything the model says, and anything it can't confirm goes to a Confirm tray for one tap instead of being saved quietly.

To be upfront: Mom hasn't used it yet. Everything below was tested on synthetic lines I wrote in her style. Sitting with her at the next month-end is the real test.

TL;DR

  • 60 synthetic Hinglish register lines, 79 facts, measured with Wi-Fi off
  • Gemma 4 E2B on its own got 94% of facts right (precision and recall)
  • Without the checker it would have silently saved 7 wrong entries out of 79. With it: 2, and 7 facts went to the Confirm tray instead
  • 3.3 s per line (p50) on a laptop with a 4 GB RTX 2050
  • ₹0 to run, no API key, nothing leaves the house

Demo

It runs locally on a laptop, so there's no live link. Setup takes about three commands and is in the README. Here's the flow:

1. She writes a line. Code shows what the model picked out of it. Green means checked, amber means "please look". The Neha card is amber because there are two students called Neha:

Write tab with green and amber cards

2. The Confirm tray. It asks which Neha. Nothing is saved until she picks one:

Confirm tray asking which Neha

3. Dues for the month. Who still owes, who's paid, and open promises:

Dues tab

4. Tap a student for their ledger and a reminder. The model wrote the wording. Code put in "₹800" and "October":

Student ledger and reminder message

Code

Tuition Register

A tuition fee and attendance register my mom can write to like a notebook. She types a line the way she'd write it in her paper register (riya nahi aayi, aman ne 1500 diye oct ke, baaki 500 next week). A local Gemma model (Ollama) copies out the names, amounts and months as exact spans. Code turns them into numbers and dates, checks everything (rules V1 to V8), and does all the money maths. Anything it can't confirm goes to a Confirm tray instead of being saved. Runs fully offline.

Built Oct 5, 2026 for the DEV Hacktoberfest Weekend Challenge: Build for a Friend.

All data in this repo is synthetic. The 18-student roster and the 60 test lines were written by me in the style of a home-tuition register. No real children's names or payments. Mom hasn't used it yet.

Write Confirm tray Dues
…

Python (FastAPI + SQLite), one HTML page with vanilla JS, 137 tests, and the eval set and results committed in eval/.

How I Built It

Stack. Gemma 4 E2B running in Ollama on my laptop, FastAPI, SQLite, and a single HTML page with vanilla JS and no build step. Every piece is small and offline. The page is mobile-first so it works from her phone over home Wi-Fi.

1. The model copies, it doesn't convert. Ollama's format option takes a JSON schema, so the output is always valid JSON. The schema only asks for spans exactly as written:

{"type": "payment", "student_text": "aman", "amount_text": "1500", "month_text": "oct", "date_text": null}
Enter fullscreen mode Exit fullscreen mode

Then plain Python takes over. 1.5k, 1,500, 15 sau and dedh hazaar all become 1500. pichle mahine becomes 2026-09. next week becomes a date. kal means both "yesterday" and "tomorrow" in Hindi, so code reads it as the past for a payment and the future for a promise. Nicknames like "Riyu" and "Amu" are matched against the roster with rapidfuzz.

Because the model only returns spans, every claim it makes can be checked against what she actually typed. The app even shows her line back with those words highlighted.

2. The checker (V1 to V8). Every extracted fact runs through these rules:

Rule Check
V1 Every span actually appears in her line (catches made-up values)
V2 / V3 The amount parses, and it isn't more than 6× that student's fee
V4 The name matches exactly one student, clearly ahead of the next best
V5 / V6 The month or date resolves, and required fields are present
V7 Coverage: every student named in the line appears in some entry
V8 Not already saved today

V7 is my favourite. Most checkers only look at what the model produced, but this one looks for what it left out. If she writes "mohit, arjun aur shreya nahi aaye" and the model returns only Mohit, she gets a card saying "You mentioned Arjun. Nothing saved for them."

3. All the money maths is in code. A payment goes to the month she named. Without a month, it goes to the oldest unpaid month, and anything extra carries forward as advance. One payment can cover two months ("sep oct dono ke"). Promises are tracked, but they never change a balance.

4. Reminders: the model writes the tone, code writes the numbers. Gemma writes a template like Namaste ji, {name} ki {month} ki fees ₹{amount} baaki hai… in Hinglish, English or Hindi, in a gentle, normal or firm-but-polite tone. Code rejects any template with a digit, a missing placeholder or the wrong language, and falls back to a built-in one. On the first try, E2B wrote "Hi [Parent's Name]…" in English when I asked for Hinglish, so the validator now checks for leftover brackets and for the language too.

5. I measured it. I wrote 60 synthetic lines in her style: single and multi-student attendance, payments in words ("aath sau"), partial payments with promises, WhatsApp messages from parents, typos ("kavya n 1500 diy"), English lines, chit-chat with nothing to save, and a few traps. I labelled them by hand from the rules, not by running the model. The few-shot examples in the prompt use different names, and a test enforces that. I ran it with Wi-Fi off, and the script records that the internet was unreachable.

Model Fact precision Fact recall Silent errors, no checker Silent errors, with checker Sent to Confirm tray p50 latency
Gemma 4 E2B (default) 94% 94% 7 of 79 2 7 facts (9%) 3.3 s
Gemma 3 1B 56% 52% 34 of 73 4 42 facts (58%) + 7 "missed?" 3.0 s

Some things the checker stopped:

  • rahul ne 1000 diye: there's no Rahul in the roster. A plain closest-name lookup would have credited ₹1,000 to Aman. V4 asked "New student?" instead.
  • aman ne 15000 diye: probably a typo for 1500. V3 flagged it as unusual instead of clearing ten months of fees.
  • neha absent: two students are called Neha. It asked which one.

And the 2 it didn't catch, because honesty matters more here than a clean table:

  • Ma'am Ishaan kal nahi aayega ("won't come tomorrow"). Code reads kal as yesterday for attendance, so the absence landed on the wrong day.
  • rohan ne 1200 jama kiye is mahine ke. The model dropped "is mahine ke" (this month), so the payment went to the oldest unpaid month instead of October. Rohan's total is still right, but the month is wrong.

6. Two Gemmas side by side. Gemma 3 1B is a bit faster, but it often copied the whole line into the name field, mixed up payments and attendance, and dropped 38 facts. The checker still kept its silent errors down to 4, but at the cost of sending more than half of everything to the tray, and that's not something Mom would put up with. E2B is the default.

7. How it was built. I worked with an AI coding agent (Kiro) through a spec I wrote: the rules, the schema, the ledger rules and the eval design. I made the calls on scope, rules and tests, and the agent did a lot of the typing.

Why Does Open Innovation Matter?

These are children's names and their parents' payments. They aren't mine or my mom's to upload to someone else's server. With an open-weight model running in Ollama, nothing leaves the laptop. I didn't just assume that: the eval ran with Wi-Fi off, and the results file records it.

It costs ₹0 to run, for good. No API key, no subscription, no per-call bill. That matters for a home tuition business.

I could choose the model to fit the machine. The laptop has a 4 GB GPU. Because the weights are open, I could try a 1B model and the newer E2B on the same 60 lines, with the same checker on the same hardware, and pick based on numbers rather than a pricing page.

I could shape the output itself. JSON-schema output, temperature 0, thinking turned off for speed, and a prompt tuned for Hinglish register notes. The checker trusts the model only as far as it can verify, which is easier when you control the whole pipeline.

With a closed API, every one of these would have been harder or impossible: uploading kids' data, paying per line, needing internet at the tuition table, and no way to compare model sizes on my own machine.

Limitations

  • The test set is small and synthetic: 60 lines I wrote in her style. It's a sanity check, not a benchmark, and her real writing will be messier.
  • kal (yesterday or tomorrow) is still a guess for attendance. She can fix it in the tray or the day's list.
  • Typing Hindi in Devanagari script hasn't been tested yet.
  • LAN mode for her phone has only a simple shared PIN. It's for a home network only.
  • No voice input yet.
  • Mom hasn't used it.

What's next

Hand it to Mom and test it on her real month-end. Then: voice notes through a local Whisper, Devanagari input, and a one-page monthly summary.

Prize Categories

  • Best Use of Gemma: Gemma 4 E2B is the default model and the core of the app. Gemma 3 1B is the comparison.

Top comments (0)