Case study — 2025
Grocery List Summarizer
A Streamlit app that turns a photo of a grocery list into categorized, stored data — Gemini extracts the items, Groq classifies each into one of six categories, and MongoDB keeps per-user history with automatic totals.
The problem
Grocery tracking dies at data entry. The useful output — what you bought, what it cost, what keeps coming back — starts as a paper list, and typing every item into a spreadsheet is the part everyone abandons. The bet of this project was simpler: photograph the list and let the machine do the data entry.
The catch is that a grocery list is not a receipt. Items are handwritten or printed, abbreviated, and mixed together, and the whole point of storing one is to answer questions like “what did I spend on dry fruits this month?” — which only works if every item lands in a known category. So the pipeline has two model jobs: get the text off the image, then put every item into a fixed category before anything is stored.
Architecture
The whole thing is one Streamlit app with three pages. On the upload page you pick a user, drop in a JPG/JPEG image of a grocery list, and the app does the rest: Gemini AI extracts the text, Groq classifies each item into one of six categories, the app computes an approximate total, and the record — items, category, total, and date — is stored in MongoDB Atlas under that user. The data page renders the full history as an interactive, wide-layout DataFrame, per user, with automatic totals.
Decisions
Two models, each doing what it is good at. Gemini handles the messy part — getting readable text off a photographed list. Groq, cheap and fast, handles the routine step — classification. Splitting the work keeps each model’s job small and legible, and keeps the more expensive model off the step that runs on every upload.
Six categories, decided up front. Spices and Seasonings, Food Staples, Dry Fruits and Seeds, Oils / Sauces and Condiments, Cleaning and Household, Personal Care. A closed list makes classification a mapping rather than a taxonomy exercise, and it makes the dashboard a simple group-by. The categories are the contract; everything else in the app is built on them.
Store the record, not the raw text. Each upload is saved as classified items plus an approximate total and a date, keyed per user — so the history view is a query, not a re-parse of old images. Data is kept separate per user; the app currently tracks two users, and the model handles more without a schema change.
One app, no service to run. Upload, classification, storage, and the dashboard all live in a single Streamlit application. The trade is the right one here: a small, known audience, no external API consumers, and no deployment surface to babysit.
What broke
Duplicate date entries in the history view. Records that share a date show as repeated rows in the DataFrame, so the same shopping day appears twice in the display. The data underneath is correct; the view is the problem.
JPG/JPEG only. Uploads are deliberately restricted to those two formats for now, which means a screenshot or a HEIC photo from a phone won’t go through.
No authentication yet. User selection is a manual dropdown, not an account boundary — anyone running the app can view or add data for any user. Fine for the current two-person audience; it would need to change before this goes further.
Where it stands
Working end to end for its two users, and actively under development. The known issues above are the current work list.
