This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle
What I Built
Walk into any cyber café or Jan Seva Kendra in small-town Uttar Pradesh and there is a typing counter, and the counter has a queue. A woman wants to know why her widow pension stopped in April. A student needs a bonafide certificate by Monday. Someone's electricity bill is four times what it was last month. Each of them pays ₹30–100 to have it typed as a formal Hindi application — सेवा में, विषय, महोदय, प्रार्थना, भवदीय — addressed to exactly the right office, because a letter to the wrong office goes nowhere.
The operator types these letters from memory, twenty a day, fifteen to twenty minutes each. The addressee is sometimes wrong (is a ration-card correction the जिला पूर्ति अधिकारी or the पूर्ति निरीक्षक?). The ₹10 RTI fee and the 30-day reply rule get quoted from memory. The customer stands there while Windows updates.
Arzi Likho (अर्ज़ी लिखो — "write the application") turns that into three minutes:
- Pick the matter — twelve of them: RTI application and RTI first appeal, ration card, pension, electricity, police complaint, public grievance, certificates, school, bank, document correction, biodata. Pick the district — all 75 UP districts, Raebareli by default.
- Fill five to ten plain-Hindi fields. Not "compose a letter" — just: who, where, what happened, what you want.
- Out comes the full formal letter, plus a "कहाँ जमा करें" box — the office, the online portal (rtionline, jansunwai, edistrict, sspy…), the helpline (1912, 1076, 112, 1967, 1947), the fee, the time limit and the attachments checklist. Then: print, .docx download (cafés live in Word), an English version for offices that accept one, and a WhatsApp follow-up message with the reference number left blank for later.
Who would pay, and why: the operator — I'd charge about ₹199/month — because it turns a 20-minute error-prone typing job into a 3-minute one at the same ₹30–50 per customer, and the addressee, the act, the fee and the portal are never wrong, because they aren't typed from memory at all. To be honest about the "side hustle" part: I have not signed up a paying café yet. That's the next step, not this week's claim; this week was about proving the drafts are good enough to sell.
Demo
Live: https://arzi-likho.onrender.com/ — free Render instance, so the first load can take 30–60 s while it wakes. Then pick a matter, fill the form, and Gemma 4 writes the letter in 30–90 s (the status line tells the customer so honestly).
| The 12 matters | The form | Writing… | The letter |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
(The "कहाँ जमा करें" box on its own: 5-kahan.png.)
What the letters actually looked like when I ran four real-shaped cases against the live app:
- RTI against the electricity department (46 s). My two rough points came back as proper numbered prose: "वांछित सूचनाएं इस प्रकार हैं: 1. पिछले वित्त वर्ष में मेरे खाते में जमा कुल बिल राशि का विवरण। 2. गलत बिल वसूली के संबंध में जारी किए गए आदेश की प्रति।"
- Police complaint, woman applicant (83 s): "रात्रि लगभग 8 बजे, जब मैं घर से सब्ज़ी लेने गई थी और वापस लौट रही थी, तब गाँव के पश्चिमी छोर पर खेत के पास दो अज्ञात युवकों ने मेरा रास्ता रोक लिया।" — the feminine गई थी / रही हूँ holds through the whole letter, because gender is a form field, not a guess. The पुलिस अधीक्षक gets a प्रतिलिपि line, as a police complaint should.
- Village grievance (30 s): routed to the खंड विकास अधिकारी (city cases go to the नगर पालिका instead). I hadn't typed the block name, so the letter reads "विकास खंड — [खंड का नाम]". That bracket is the feature I'm proudest of: a missing fact stays a visible blank; it is never invented.
- Widow pension, stalled installments (41 s), closing line: "अतः प्रार्थना है कि कृपया मेरी पेंशन की रुकी हुई किश्तों की जांच कर उनका भुगतान जल्द से जल्द कराने की कृपा करें।"
The same call returns a formal English version of the letter, and a WhatsApp follow-up the operator can paste when the customer comes back asking what happened.
Code
https://github.com/Yuser00123/arzi-likho — MIT. Python 3.12, Gradio 6 on FastAPI, one render.yaml, ten offline tests (python test_app.py — no key, no network, LLM_PROVIDER=mock). The file that matters most is forms.py: twelve matters × (fields, addressee, act/section, fee, time limit, portals, attachments) × 75 districts, as plain editable Python.
How I Built It
Picking the hustle before building it. Before writing code, I read the week's other 186 submissions. Receipt/invoice sorters: seventeen and counting. Etsy/eBay listing writers: eleven. "Scope-creep shields" for freelancers: a whole genre. Nobody was doing Indian government paperwork, in Hindi, for the counter that actually types it — so that's the lane. A cyber café is the rare customer you can name, walk to, and watch paying ₹30 in cash for the exact artefact the tool produces.
The design decision everything hangs on: templates write the letter, the model writes the sentences.
| Part of the letter | Who writes it |
|---|---|
| Addressee — जिला पूर्ति अधिकारी? अधिशासी अभियंता? थानाध्यक्ष? |
forms.py template |
| Act & section (RTI §6(1), §19(1), CrPC §154), fee (₹10), 30-day limit | forms.py |
| Portals and helplines in the कहाँ जमा करें box | forms.py |
| Skeleton — date, सेवा में block, विषय, salutation, प्रार्थना, signature, संलग्नक | letter.py |
| The narrative — what happened, since when, what is wanted | Gemma 4 |
| English version + WhatsApp follow-up | Gemma 4 |
Gemma never chooses an office, never quotes a fee, never cites a section. Its job is the part that is actually writing: turning "पेंशन अप्रैल से बंद है, बैंक बोला विभाग से पूछो" into two dignified paragraphs of सरकारी हिंदी. The system prompt's hardest rules: use only the facts in the form; a blank becomes a [कोष्ठक] placeholder, never an invention; no legal advice, no threats, no promises; the request line starts with कृपया because the app supplies the "अतः प्रार्थना है कि" itself.
Testing the model like code. I drove the deployed app through its own API (gradio_client) instead of eyeballing screenshots, and asserted on the letters. That's how I caught my favourite bug of the week: every letter's closing line read "अतः प्रार्थना है कि अतः आपसे विनम्र निवेदन है कि…" — my template's prefix and Gemma's own prefix, doubled. Fixed three ways: a prompt rule, a sanitizer that strips leading connectives no matter who added them, and a cleaner subject template for police complaints. The same API pass confirmed the feminine grammar, the village/city addressee routing and the 30–83 s timings.
Keeping the counter alive when the model isn't. The model's JSON is clamped to a schema: a partial response gets its missing parts filled from deterministic templates, and if the API is down entirely, the whole letter still comes out in mock mode — the counter must never stall in front of a paying customer. Ten offline tests exercise all twelve matters this way, including "no [ left when the form is complete" and "every portal lands in the कहाँ जमा करें box."
The UI is one fixed pool. Twelve matters have different fields, but instead of dynamic component creation the app relabels and shows/hides a fixed pool of seventeen inputs — the matter switch is instant, nothing jumps. The letter itself is a plain editable textbox: the operator fixes a name or adds a line before printing (the print stylesheet prints only the letter), and the .docx is regenerated from whatever they edited. Drafts live in gr.BrowserState — in the browser, not on the server: an Aadhaar number in a police complaint should not be in anyone's logs, including mine.
Where I didn't start from zero: llm.py is the engine I built for my Week 1 project, Pakshi Padosi — streaming-safe <thought> stripping for Gemma 4, retries with a time budget, and one wrapper that runs the same model on Google's free tier or on a café's own PC with two environment variables. Reusing it is the open-source way of having a weekend.
Full disclosure, same as last week: an AI coding agent did most of the typing on this project. The template data, the prompt rules, the Hindi register calls — and the mistakes — are mine.
Why Does Open Innovation Matter?
The data on the counter isn't the user's — it's their customers'. Ration-card numbers, pension files, a widow's bank details, a police complaint about a threat. My demo runs on Render with the Gemini API's free tier because that is what I can host for ₹0 — but the same code, pointed at Ollama (LLM_BASE_URL=http://localhost:11434/v1), runs entirely on the café's own PC with no internet and no third party. That's not a checkbox; it's the difference between a tool a café can put on its counter and one it shouldn't.
The maths needs open weights. A ₹30 application cannot carry per-token API costs plus a subscription and still leave the café a margin. Open weights run on hardware that already exists, at ₹0 per page.
The network is worse than you think. Village CSCs run on patchy 4G. The model doesn't need the internet — only the government e-portals do, and the box tells you which ones.
The templates are the product, and they're editable. A Raebareli operator can open forms.py, add their tehsil's office or correct a fee, and the app updates. No vendor ticket, no lock-in — and when a better Hindi model ships next year, it's two environment variables, not a migration.
The register is the moat. Closed general-purpose APIs drift into Hinglish or translate English letter structure literally. Here the सरकारी register is pinned by templates and the open model writes within it — and when an output is wrong I can see exactly which rule to fix: a prompt, a template, a sanitizer. You can't do that with a black box standing between a customer and their ration card.
Prize Categories
-
Best Use of Gemma —
gemma-4-31b-itwrites every letter's narrative, request line, English version and WhatsApp follow-up from field-notes-only prompts with[placeholder]discipline; the write-up covers thought-stripping, retry budgets, the schema clamp and the mock fallback that keeps the counter alive when the API is down. -
Best Use of Render — deployed from
render.yamlon the free plan with a/healthcheck; the fix-test-fix loop during live API testing (two same-day pushes, each live in about two minutes) is exactly what a one-person side hustle needs from a platform.
Built in Raebareli, Uttar Pradesh, 14–15 October 2026, mostly after dark.




Top comments (0)