This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady

What I Built

I worked for about 20 years as a pharmacy assistant in community pharmacies in Bucharest. One thing I saw again and again: people bring a bag of old medicines to the counter, or don't know which boxes at home are still in date. Checking a cabinet box by box is exactly the kind of chore everyone puts off, so I wanted a tool that does the boring reading for you, without sending photos of your medicines anywhere.

Lazy Medicine Cabinet is a small web app that runs entirely on my laptop. I take a photo of my medicine boxes, and Gemma 3 (4B, vision) running locally through Ollama reads them and makes an inventory: the product name as printed, the expiry date as printed, and a status (Expired, Expires within 30 days, Expires within 90 days, OK), with the time left ("68 days left", "Expired 2 months ago"). I can correct any line by hand.

The app has three tabs:

  • Cabinet: summary cards, the list with a small thumbnail of the source photo for each line, filters and sorting by expiry date, and a "Next check" date at the top.
  • Pharmacy bag: the expired items to take back to a pharmacy, as a printable list.
  • About: the disclaimer, the privacy promise and how it works.

A "Try the demo cabinet" button fills the app with seven fictional boxes, using the results Gemma actually produced in my tests, clearly labelled as demo data.

It is deliberately slow and steady: on my dual-core laptop with no graphics card, one photo takes about a minute (60 to 85 seconds in my runs). For a "check the cabinet once in a while" job, that is fine, and it means no cloud, no account and no telemetry.

It can misread labels, and it never gives medical advice, doses or interactions. The app says so on screen, and every line is meant to be checked against the real box.

Demo

Cabinet tab with the demo boxes

Pharmacy bag tab

An unreadable date flagged instead of guessed

Phone layout

The test photos are generated pictures of fictional boxes (invented brand names, no real logos or packaging), not real products. The video narration uses a synthetic voice (Piper TTS).

Code

GitHub logo iancuileana83-lab / lazy-medicine-cabinet

Photograph your medicine boxes; a local Gemma model (Ollama) lists names and expiry dates. Nothing leaves your laptop. No medical advice.

Lazy Medicine Cabinet

Take a photo of your medicine boxes. A Gemma 3 vision model running locally on your laptop (through Ollama) reads the boxes and builds a small inventory: product name as printed, expiry date, and a status (expired, expires within 30 days, expires within 90 days, OK). You can correct any line by hand. Expired items get a reminder to take them back to a pharmacy.

Nothing leaves your laptop. No cloud APIs, no telemetry, no external fonts or scripts. The web server listens on 127.0.0.1 only, and its only outgoing connection is to Ollama on the same machine. The photos you scan stay only on your laptop, in data/photos/, so you can see where each line came from. They are deleted when the line is removed, or with "Clear all".

Important. Lazy Medicine Cabinet can misread labels. Always check each line against the real box…

MIT license.

How I Built It

  • Model: gemma3:4b via Ollama on 127.0.0.1:11434. The model only transcribes: name and expiry text exactly as printed, as structured JSON. The prompt forbids describing uses or adding doses or advice.
  • Dates and status are code, not model: a small, tested parser turns EXP 03/2027, 2026-10-31, Exp. 08.2026 and similar into a date. Month-only dates count as valid until the end of that month. Anything unparseable is shown as "Date not found, please check the box and enter it by hand."
  • App: plain Node (no framework) serving a single page on localhost only. The browser shrinks photos to 1024 px before sending them, which matters a lot on a CPU-only machine. The logo, icons and illustration are inline SVG, so nothing is loaded from the internet.
  • Storage: the list, the next-check date and the photos are saved only on this laptop, and a photo is deleted when its line is removed or with "Clear all".
  • Tests: 26 tests: date parsing and status boundaries, model-output parsing with a mocked Ollama, and Playwright end-to-end tests (including one that asserts no request leaves localhost).
  • Honest accuracy check: I generated 5 photos of 7 fictional boxes (angle, blur, glare, one date printed small on the side, one photo with three boxes) and compared Gemma's output with the truth.
    • A first, simple prompt got the full product name right on only some boxes. Asking for brand, medicine name and strength together got 7 of 7.
    • Dates were read correctly on 6 of 7 both times, with different boxes failing each time. For example, 12/2026 was read as 32/2026. The app does not guess: it shows "Date not found" instead of a wrong status.
    • These are generated images with clean fonts, so real boxes will be harder. One run per prompt on one machine is a small sample.

Why Does Open Innovation Matter?

A medicine cabinet is about as private as a photo gets. With an open-weight model I can run the whole thing on a laptop that is not connected to anything, read the code, and change the prompt. Nobody can change the terms or switch off the service, and it costs nothing to run. It also keeps the scope honest: the model is only allowed to read text, and the safety-relevant logic (dates, status, reminders, disclaimers) lives in plain code anyone can audit.

My Agent Session

I built this with Claude Code as a coding agent. It checked my laptop, proposed the model, wrote the code and tests, and ran the before/after prompt comparison. I made the product decisions and reviewed and approved every medicine-related text myself.

The Lazy Payoff

Instead of turning every box over and squinting at tiny print, you take one photo, wait a minute, fix the odd line, and get a list of what to take back to the pharmacy. The slow part is done by the laptop, not by you.

Prize Categories

Best Use of Gemma: Gemma 3 4B (vision) runs locally through Ollama; it is the core of the app.