跳到正文
DEV Community· TaseenTariq·· 3 小時前AI 評分49

Anatono:我在黑客松用 100 分鐘打造 Gemma 4 藥物提醒工具

I built a Gemma 4 medicine reminder in 100 minutes at a hackathon

AI 導讀

Taseen Tariq 在黑客松用 100 分鐘打造 Anatono,這款工具以 Gemma 4 讀取藥品或處方照片,並將用藥指示轉為提醒。程式碼負責檢查藥物警示,Gemma 4 不會決定用戶是否應服藥。用戶可用英文、烏爾都語或羅馬字烏爾都語輸入或口述服用方式,提醒亦會加入手機日曆。

正文

This is a submission for the MLH x DEV Writing Challenge

What I Built

Anatono is a medicine reminder that starts from a photo. Snap a medicine strip, a box, or a whole handwritten
prescription. Type or say how you take it, in English, Urdu or Roman Urdu. Anatono turns that into reminders, and it
checks every medicine for warning signs before you take it. It's made for elders and the people who look after them.

I built it at MLH's Hacktoberfest Hack Day in Faisalabad on 23 October 2026. It's live at
anatono.site, and the code is open source (MIT).

GitHub logo taseen-t / anatono-meds

Anatono: snap a medicine or prescription, Gemma 4 reads and checks it, say how you take it, get reminders. Hack Day Faisalabad 2026.

Anatono

Never miss a dose again. Snap a medicine strip, a box or a whole handwritten prescription. Say or type how you take it, in English, Urdu or Roman Urdu. Anatono turns it into reminders, and checks every medicine for warning signs before you take it. Made for elders and the people who look after them.

Made by Taseen Tariq at Hack Day Faisalabad, 23 October 2026.

Try it: anatono.site (landing page) · anatono.site/app.html (the app) · Android app (APK)

Anatono in 30 seconds: a real run of the app

▶ Watch the 30-second demo: a real run of the app (Gemma 4's waits shown sped up), with captions.

Verify in 30 seconds

Model Gemma 4 (gemma-4-26b-a4b-it; gemma-4-31b-it only as a fallback) through the Gemini API (google-genai). Licence: Apache 2.0. anatono.py line 24
Where Gemma is called ask() in anatono.py line 69 → ask_gemma() (line 85). It reads every photo (read_photo

…

Why medicines

My sister is a doctor. With a doctor in the family, I learned that writing the prescription is the
easy part. The hard part happens at home: the right medicine, at the right time, every day, with no doctor in the room.

This is the kind of paper that goes home. It's a sample I made for the demo, not a real patient:

A sample handwritten prescription: Amoxil 500mg 1+0+1 for 5 days after meals, Omez 20mg 1+0+0 before breakfast for 14 days, Brufen syrup 2 tsp TDS if fever

Three medicines, three schedules, all in shorthand: 1+0+1, TDS, x 14 days. Easy for a doctor, hard for a
patient. Then you're supposed to type it all into a reminder app yourself, in English. That's where people give up.

And it isn't just one family. The WHO says about 1 in 2 people on long-term medicines don't take them as
prescribed (Adherence to Long-Term Therapies, 2003), and 1 in 10
medical products in low- and middle-income countries is substandard or falsified
(WHO, 2017).
So Anatono does two things: it reminds you, and it checks the medicine.

How it works

  1. Read. Gemma 4 reads the photo: name, salt, strength, maker, batch number, dates, registration number, and the dose as the doctor wrote it.
  2. Check. Plain code, not the model, decides whether each medicine is ok, careful or stop. An expired medicine gets no reminders.
  3. Understand the dose. Type or say it any way you like. "ek goli subah aur raat khane ke baad paanch din" (one tablet morning and night, after food, five days) becomes 1 tablet at 8:00 AM and 9:00 PM, after food, for 5 days.
  4. Confirm and remind. Nothing is saved until you tap "Add to my routine". Reminders show in the app and go into your phone's own calendar as alarms, so they ring even when the app is closed.

The one rule: Gemma 4 reads, code decides

The model is good at reading messy handwriting and messy sentences. It shouldn't be the one deciding whether you take a
pill. So Gemma 4 only turns a photo or a sentence into JSON, and plain Python makes every decision after that.

Each medicine collects flags: expired (stop), expiring soon, a made-on date after the expiry date, a missing batch
number, expiry, maker or registration number ("Genuine packs print it."), the same ingredient as something already in
your routine, or a warning sign Gemma spotted on the pack. Then one line decides:

level = ("stop" if any(f[0] == "stop" for f in flags) or sum(f[0] == "careful" for f in flags) >= 3
         else "careful" if flags else "ok")

A stop card says "Don't take this one. Show it to your pharmacist." and has no dose form at all.

Doses work the same way. Gemma 4 turns your words into amount, times ("morning", "night"…), food, days,
as_needed and anything it was unclear about. Code turns that into clock times (morning 8:00, afternoon 2:00 PM,
evening 6:00 PM, night 9:00 PM), only accepts 1 to 365 days, flags more than 6 doses a day, and reads prescription
shorthand on its own so it can check Gemma's answer:

def pattern_slots(text):
    """'1+0+1' / '1-1-1' / '0+0+1' -> the slots it means, or None. Code's own reading, to cross-check Gemma."""
    m = re.search(r"(?<![\d/])([\d½]+)\s*[+\-]\s*([\d½]+)\s*[+\-]\s*([\d½]+)(?:\s*[+\-]\s*([\d½]+))?(?![\d/])", text or "")
    if not m:
        return None
    parts = [p for p in m.groups() if p is not None]
    names = ["morning", "afternoon", "night"] if len(parts) == 3 else ["morning", "afternoon", "evening", "night"]
    return [n for n, p in zip(names, parts) if p not in ("0",)]

If Gemma's times don't match, you see a note like "'1+0+1' usually means morning and night. Please check the times."
You always see what was understood and can change the times before anything is saved. Anatono never changes a dose.

There's also an agent skill, anatono-nuskha
("nuskha" is Urdu for prescription), built to the Agent Skills open standard. Any skills-compatible agent can run the
same pipeline from the command line: photo in, checks and a calendar file out. Its rules tell the agent to read the
flags back and get a yes before saving, to never change or round a dose, and to say "warning signs", never "fake".

What I learned

  • Put the safety rules in code, not in the prompt. Then the model can't talk its way around them, and I can test them. python3 anatono.py runs a self-check of the rules with no API call.
  • Design around a slow model. On the night, one read of the sample prescription took about a minute and another took three. More on what I did about it under Partner Technologies.
  • Be honest about limits. A photo can't prove a medicine is genuine. So Anatono only ever says "warning signs", the FAQ says why, and the README has a "Limits, honestly" section.
  • Dropping an idea late can be the right call. The organisers' guide said to stop adding features 90 minutes before the deadline. I started a whole new project with 100 minutes left. It worked out because I picked a problem I already knew from home.
  • A small one from the last minutes. Two minutes before the deadline, the calendar buttons were showing on an empty routine even though they had the hidden attribute. A .stack { display: grid } rule was beating hidden. One line fixed it: [hidden] { display: none !important; }.

Demo

A one-minute run of the web app. Gemma 4 reads the prescription (Amoxil 500mg and Omez 20mg, both OK), understands
"ek goli subah aur raat, khane ke baad, 5 din" as 8:00 AM and 9:00 PM for 5 days, and plain code stops an expired
pack. The app has changed a little since this was recorded, and the live app now runs on Gemma 4 only.

Try it yourself:

  • The app: anatono.site/app.html. Tap Try a sample to read the prescription above. Reading can take a minute or more (see below). Works in any phone browser and installs as an app on Android.
  • The landing page: anatono.site
  • Android: anatono.apk, the same web app wrapped to open full screen like any app.
  • The code: github.com/taseen-t/anatono-meds, MIT. The README has a "Verify in 30 seconds" box with the model, the exact lines that call it, the licence and the key dependencies.

Partner Technologies

Gemma 4, through the Gemini API. Gemma 4 is the centre of Anatono: it reads every photo and understands every
dose. I use gemma-4-26b-a4b-it through the google-genai Python SDK, with gemma-4-31b-it only as a fallback. Both
are Gemma 4, under the Apache 2.0 licence. The key stays on the server, so the
browser never sees it.

What working with it was like:

  • It sometimes answers with a 500, or with JSON wrapped in extra text. So every call pulls the JSON object out of the reply, and if anything fails it tries the 26B model twice, then the 31B one:
  def ask_gemma(contents):
      """Gemma 4 through the Gemini API. It sometimes answers 500 or loose JSON: try the 26B model twice, then the 31B
      one (both Gemma 4)."""
      client = genai.Client()                       # keep a reference: a dropped client closes its connection
      tries = [MODEL, MODEL, MODEL_BACKUP]
      for attempt, model in enumerate(tries):
          try:
              return as_json(client.models.generate_content(model=model, contents=contents).text)
          except Exception:  # noqa: BLE001
              if attempt == len(tries) - 1:
                  raise
              time.sleep(2 * (attempt + 1))
  • Gemma 4 on the API doesn't take audio. So when you tap the mic, gemini-3.5-flash-lite only writes down the words you said, and Gemma 4 does all the understanding.
  • Other surprises: asking for a thinking level gave a 400, and gemma-4-e4b-it gave a 404 on the API, so I stuck with the 26B model.
  • The hosted model can be slow. On the night, the sample prescription took anywhere from about a minute to three.
    At a live demo that's a long time. After the deadline I made three changes:

    1. Ask less first. The first call only reads the medicines. "What is it for", in English and Urdu, comes from a second, shorter call that fills in after the cards are already on screen.
    2. Read a tall page in two parts. A full prescription is cut into two overlapping halves. The app reads part 1, shows those medicines, and offers "Read the remaining medicines". A medicine that shows up in both halves is kept once (matched by name and strength).
     def pieces(img):
         """A tall page (a full prescription) is cut into two overlapping halves, because Gemma 4 on the API is slow and
         two short answers come back sooner than one long one. The overlap keeps a line cut in half readable in one piece."""
         w, h = img.size
         if h < 1.2 * w:
             return [img]
         return [img.crop((0, 0, w, int(h * .58))), img.crop((0, int(h * .42), w, h))]
    
  1. Read once, not twice (the next day). The phone and the server both keep what was read, keyed by a SHA-256 of the photo. On a repeat only the code checks run again, because they depend on today's date and on what's already in your routine.

Hackathon Experience

I went to MLH's Hacktoberfest Hack Day in Faisalabad on 23 October 2026.

The organisers sent a "before you arrive" list: accounts on GitHub, DEV and Google, a Gemini API key from Google AI
Studio, and one line: "Do this at home, not on venue Wi-Fi." The rule was that setup before the day is fine,
but project code isn't. So I came with a ready laptop and no code.

Honestly, I started with a different idea. In the afternoon I built a karaoke vocal coach and called it Anatono: it
split a song into music and voice, showed the lyrics in time with the song, and Gemma 4 gave you a score and tips on
your singing. It worked, but I didn't like it. At 7:20 PM, with 100 minutes to go, I dropped it. I kept the name and
picked the problem I already knew from home.

The new project's first commit went in at 8:21 PM. The repo went public on GitHub at 8:50 PM, and at 8:52 PM Gemma 4
was answering on anatono.site, a domain I'd bought that same day.

Since the deadline

I kept building overnight. All of these use the same Gemma 4 reading and the same code checks behind anatono.site:

  • scroll and page-change animations on the landing page
  • the Android download, which opens full screen with no browser bar
  • a native iPhone app (SwiftUI, with real iOS reminders that ring with the app closed), running in the simulator
  • a native Android app (Kotlin, reminders in the phone's calendar, Urdu in Nastaliq script), in testing

What's next

  • Gemma 4 on the phone, so it reads offline in seconds instead of waiting on the hosted model.
  • Family mode: remind a parent's phone from yours, and see when a dose is taken.
  • Doctors first: put it in front of the people who write these prescriptions, starting with my sister.

And the limits, honestly: a photo can't prove a medicine is genuine, so Anatono only shows warning signs. It's a
reminder, not medical advice, and it never changes a dose. Photos are sent to Google's Gemini API to be read; your
routine stays on your phone.

Thanks to MLH and the Faisalabad organisers for the day.

An AI assistant wrote this post from my build notes and the repo's history.

來源:DEV Community · dev.to