DEV Community

ninefyi
ninefyi

Posted on

Voice2Note: I spoke to a ring for four hours, and the phone misheard me

Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass Submission 🌿

This is a submission for the Hacktoberfest Open-Source AI Challenge: Week 1, "Touch Grass"

What I Built

I wore a Pebble Index 01, a ring with one button and a microphone, and spent about four hours outside talking to it instead of taking out my phone. Hold the button, say a thing, let go. At home, a local Gemma turns the notes into a short journal, and I check it against my own words before it counts.

The plan was a hands-free field journal: screen in my pocket, say what I see. I will be straight about the result. I recorded three notes in four hours, and what I said was errands and one remark about the air (I was walking in a public park), not birds and trees. It felt convenient: pressing the record button was very easy. The pipeline works end to end, and what it does to speech is the interesting part, and not all of it is flattering.

Demo

Review Screen

Confirm and export Journal

The three notes, as the phone transcribed them, and what I actually said (I checked each one by listening to the saved audio):

Time Phone transcript What I said
08:42 Next thing I have to return the book at national rivalry. Next thing I have to return the book at national library.
09:41 This evening I will bring my son to go to kit gym today. This evening I will bring my son to go to kids gym today.
14:37 Today we have Air pollution outside. We have Air pollution outside.

All three had an error. By my count, that is 3 wrong words out of 29 (about 10%) and zero notes exactly right.

Code

https://github.com/ninefyi/hf26challenge-week1 (MIT). Everything below is in that repo: the receiver, the mailbox, the pull command, the quote check, the review screen, a stats command and 35 tests. The ring, its app and its on-phone transcription are Pebble's, not mine.

How I Built It

ring ─► Pebble app (transcribes on the phone) ─► webhook ─► Mailbox on Render (web service + Postgres)
   ─► `pull` at home saves the notes on my laptop, then tells the Mailbox to delete them
   ─► Gemma 3 12B via Ollama ─► review screen ─► journal.md
Enter fullscreen mode Exit fullscreen mode

1. Find out what the ring sends. There is no documentation, so I set up a logger and pressed the ring. The Pebble app POSTs multipart/form-data: an audio part (m4a, 16 kHz mono), a transcription made on the phone, and recordedAt in epoch milliseconds. I keep the audio for every note, as ground truth.

2. The phone is not a reliable stenographer. My test phrase "Offline test one" arrived as "Off-line tail one". On the real day, one word per note went wrong (table above). The model never hears the audio, only the transcript, so it cannot know.

3. A walk takes you out of your home Wi-Fi. My first receiver listened on my laptop, which cannot work when the phone is elsewhere. So I put a small Mailbox on Render's free plan: a web service plus Postgres. It accepts the webhook behind a secret token, and pull collects notes by hand, saves them locally, and only then deletes them from the Mailbox.

What I measured: the free service sleeps after 15 minutes. Of the three notes I used, two arrived while the service was asleep, each stored 10 to 14 seconds after the service started waking. So the Pebble app waited or retried long enough. That is two cases, not a guarantee, and I never tested a long stretch away from home.

4. Two things went wrong, and one I still cannot fully explain.

  • Render stopped picking up my commits. Several never went live until I pressed Manual Deploy, and I only noticed because the log lines were still in the old format. I had also renamed the GitHub repo around then, which may be the reason; I did not find out. I now return the running commit on /health so a stale deploy is visible.
  • My first pull said 0 notes while the database held six. I never proved why. The most likely cause: I pasted four commands at once, and read -s PULL_TOKEN swallowed the next line as the token. Run one at a time, it worked and saved all six notes, with their audio.

5. Gemma at home, twice. gemma3:12b through Ollama reads each note and writes a short paragraph. Each observation has to carry a quote that appears verbatim in the note, or it is dropped, which blocks invented facts. I ran the same three notes two ways.

From the phone's transcript (23 seconds):

The air pollution was noticeable outside today. Next, I need to return a book at National Rivalry. This evening, I will bring my son to Kit Gym.

From what I actually said (28 seconds):

I needed to return a book at the National Library. There was air pollution outside. This evening, I will bring my son to kids gym.

What I take from it:

  • It repeated the phone's mistakes and made them look sure. "National Rivalry" and "Kit Gym" came out capitalised like proper nouns. The quote check passed them, because it only looks at the transcript.
  • Better input fixed the nouns, not the structure. Both runs put the air-pollution remark (14:37) ahead of the evening plan (09:41). The model reordered my day.
  • It still colours things. "Noticeable" and "I needed" are the model's words, not mine.
  • It did not invent a species, a place or a task in either run, which is what the quote check is for.

My first version did worse. It wrote "lovely to see" and "I realized", and filed "Hello hello hello" as a sighting. I fixed those with a stricter prompt and a filler filter. That is as far as I got.

6. I confirm before it counts. The review screen shows my own words, the draft paragraph and an editable table. Untick a row to drop it. The saved journal says "Reviewed and confirmed by me" only after I press the button. I confirmed the journal exactly as Gemma drafted it: 0 of 3 rows changed, 0 sentences rewritten. That means the confirmed version still has the faults I listed above, the reordered day and the "I needed". I chose to publish the unedited version and show the faults, rather than tidy them away. The review screen is where I would have fixed them; I decided not to, and I want that on the record.

The confirmed journal:

I needed to return a book at the National Library. There was air pollution outside. This evening, I will bring my son to kids gym.

todo: returning a book (national library) · todo: kids gym · sighting: air pollution

Why Open Innovation Matters

The model that reads my voice notes is an open-weight model running on my own laptop. A hosted model would have heard what I said and, on a real walk, where I said it.

The honest trade-off: my notes pass through a Mailbox I run on Render before they reach my laptop, and are deleted once pulled. That is weaker than "nothing leaves my machine", and I chose it because the ring cannot reach my laptop when I am out.

Open also meant I could read the ring's webhook format myself, decide how the model may behave (the quote check), and pick the model size. Cost: Ollama and Render's free plan were free; the ring was already mine.

Where closed would have been easier: a hosted API would have been quicker and needed no Mailbox. And a better transcriber might not have heard "library" as "rivalry". I did not test one, so I do not know.

My Agent Session

I built this with Claude Code. It wrote a large share of the code and the first drafts of this post, which is why the post is marked as AI-assisted. I am not embedding the session transcript.

Prize Categories

  • Best Use of Gemma: Gemma 3 12B does the extraction and the paragraph, locally, and I have shown where it fails.
  • Best Use of Render: the Mailbox is a Render web service plus Postgres on the free plan. I have reported what the free plan did to me: sleeping, a database that expires after 30 days, and auto-deploy that stopped working for me.

Top comments (1)

Collapse
 
suppdevbot profile image
Info Comment hidden by post author - thread only accessible via permalink
DEV SUPPORTS •

You need to verify your account.

Enter fullscreen mode Exit fullscreen mode

tr.ee/dev-to

Some comments have been hidden by the post's author - find out more