This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle
What I Built
One evening I was sitting at my local kirana store, gossiping with bhaiya like I usually do. A customer bought 2 Maggi and a Parle-G, and bhaiya opened an old diary and wrote it down by hand. Then another customer came. And another. Same diary, same pen.
I asked him, "Bhaiya, aapko kaise pata chalta hai kya sabse zyada bikta hai?"
He laughed: "Andaaza hai. Roz dekhta hoon toh pata chal jaata hai."
No numbers, no records, just a guess. And that guess decides how much stock he buys from the wholesaler every week. Guess wrong, and his money is stuck in items that don't sell, or he runs out of the ones that do.
That's why I built ShopKaro, an app that replaces the paper diary for small kirana shops. Every product is a big button. The shopkeeper taps it when something sells, and that's it. From those taps, ShopKaro builds real data:
- Tap to sell: one tap records a sale. Works offline and syncs when the internet comes back.
- Add products by photo: snap the packet and the AI fills in the name and details.
- Hinglish voice and text entry: say "2 Maggi, 1 doodh" and it's logged.
- Dashboard: best sellers, slow movers, sales by hour and day, revenue.
- Weekly reorder list: predicts how much of each product to buy next week.
- Weekly report in Hindi or English: "Maggi sold 30% more this week, order 2 extra boxes."
Who would pay?
India has millions of kirana shops, and most still run on a diary. If a shopkeeper stops overstocking even a few slow-moving items, he saves far more than a small monthly fee. The plan is ₹99/month, with the first month free.
Demo
Live app: ShopKaro
Hosted on Render's free plan, so the first load can take 30–60 seconds while it wakes up.
Code
ShopKaro
Tap-to-sell billing for Indian kirana shops — works even when the internet doesn't.
Entry for the DEV Hacktoberfest 2026 Challenges, Week 2: Side Hustle (Oct 12–18, 2026).
Why
A kirana shopkeeper serves 150+ customers a day. Billing apps today assume a stable internet connection, English literacy, and a keyboard. When the network drops mid-sale (and in a small shop it does), the queue stalls and the customer waits.
ShopKaro is built for that reality:
-
Tap tiles, not forms. Products are big tappable tiles with monogram chips — no typing
during a sale.
×1 ×2 ×3 ×5multipliers cover the common cases in one tap. -
Works offline. Every sale is written to IndexedDB first, then replayed to the API with
idempotent
client_ids when the connection returns. The UI shows exactly how many sales are waiting to sync. - Speak your…
How I Built It
App stack
- SvelteKit + TypeScript frontend, built mobile-first, because a shopkeeper will use it on a cheap phone. Big buttons, bottom navigation on phones, a sidebar on desktop, and a service-worker offline queue so a bad network never loses a sale.
- Go backend API.
- PostgreSQL on Tiger Data (Timescale). Every tap is a time-series event, so hypertables keep the hourly and daily dashboards fast.
The open-source AI at the core
-
Gemma (
gemma3:4b) via Ollama is the brain. It turns messy Hinglish like "do Amul doodh aur ek Surf" into structured sale entries, reads product details from a packet photo, and writes the weekly summary in simple Hindi or English. A 4B model is small enough to run on cheap hardware. If Gemma isn't reachable, a rule-based fallback kicks in so the shop never stops. - Whisper handles voice input, with the browser Speech API as a fallback.
- TabPFN powers the weekly reorder forecast. A single shop doesn't have a huge dataset, and TabPFN is built for small tabular data, so it's a natural fit. If no API key is set, a seasonal-trend fallback takes over.
- Temporal schedules the weekly report and reorder jobs so they never get missed.
- Render hosts the app.
How Gemma understands Hinglish
Here's the heart of it. I send Gemma the shop's catalog plus whatever the shopkeeper said, and it returns strict JSON:
var catalog strings.Builder
for _, p := range products {
fmt.Fprintf(&catalog, "%d|%s|%s|%s|%.2f\n", p.ID, p.Name, p.Category, strings.Join(p.Aliases, "/"), p.Price)
}
system := `You convert a shopkeeper's spoken or typed shopping phrase into product entries.
You receive a catalog with lines: id|name|category|aliases|price.
Return ONLY JSON: {"entries":[{"product_id":<id>,"qty":<int>}],"unmatched":["<leftover text>"]}.
Rules: quantities default to 1; match Hinglish words (doodh->milk, namak->salt, anda->egg, atta->flour, tel->oil, ...). Never invent ids.`
user := "CATALOG:\n" + catalog.String() + "\nPHRASE:\n" + text
out, err := o.ChatJSON(ctx, o.Model(), system, user) // Ollama /api/chat, format=json, temperature 0
Saying "2 Maggi, 1 doodh, do parle g" gives:
{"entries":[{"product_id":4,"qty":2},{"product_id":1,"qty":1},{"product_id":5,"qty":2}],"unmatched":[]}
Gemma understood "doodh" as milk and "do" as 2 without any fine-tuning. Setting temperature to 0 with JSON mode keeps the output predictable, and anything it can't match goes into unmatched, so it never makes up a product.
Why Does Open Innovation Matter?
For a kirana shop, cost and privacy decide everything.
Cost: A shopkeeper will never pay for an expensive API call every time he logs a sale. An open-weight model like Gemma runs on cheap hardware, or even locally, so the per-sale cost is basically zero. That's what makes ₹99/month possible.
Privacy: A shop's sales data is its business. With an open model, that data doesn't have to leave for some big company's servers.
Control: Indian shopkeepers talk in Hinglish and local product names like "doodh" and "Parle-G". With a closed API, I could only hope it understood. With an open model, I can tune it, run it anywhere, and own the whole stack.
My First User
I gave ShopKaro to bhaiya, the same shopkeeper who gave me the idea.
His honest feedback: he found it a little confusing. So the next step is to make it even simpler. Fewer screens, bigger buttons, and voice-first entry. He also said he can't pay yet 🥲, but a real shopkeeper using it and telling me what's wrong is worth more to me right now than ₹99.
Prize Categories
- Best Use of Gemma
- Best Use of TabPFN
- Best Use of Tiger Data
- Best Use of Temporal
- Best Use of Render







Top comments (0)