<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ajewole Israel</title>
    <description>The latest articles on DEV Community by Ajewole Israel (@ajewole_israel_264e4297c3).</description>
    <link>https://dev.to/ajewole_israel_264e4297c3</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4205793%2F8d666980-a871-4a2b-88be-b7ed192ea641.jpg</url>
      <title>DEV Community: Ajewole Israel</title>
      <link>https://dev.to/ajewole_israel_264e4297c3</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ajewole_israel_264e4297c3"/>
    <language>en</language>
    <item>
      <title>Sloth Secretary 🦥: I Made Gemma Take the Meeting Minutes So I Could Take a Nap</title>
      <dc:creator>Ajewole Israel</dc:creator>
      <pubDate>Sun, 25 Oct 2026 04:22:46 +0000</pubDate>
      <link>https://dev.to/ajewole_israel_264e4297c3/sloth-secretary-i-made-gemma-take-the-meeting-minutes-so-i-could-take-a-nap-15ii</link>
      <guid>https://dev.to/ajewole_israel_264e4297c3/sloth-secretary-i-made-gemma-take-the-meeting-minutes-so-i-could-take-a-nap-15ii</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week3-2026-10-19"&gt;Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I'm Israel, a student developer in Lagos, and in my learning pod (about ten of us, called "Flexbox") I hold the most dangerous title in any group chat: &lt;strong&gt;secretary&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When the call ends and everyone says "nice one, guys" and leaves, the secretary is the one still sitting there with a recording and a job: write the brief. Decisions, open questions, who's doing what by when. Before anyone forgets.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;Sloth Secretary&lt;/strong&gt;, a small offline Python CLI that does the boring part for me:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sloth pod-call.m4a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Give it an audio or video file from any call app and it writes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;2-line TL;DR&lt;/strong&gt; (you can read it while your data is still loading)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;decisions&lt;/strong&gt; and &lt;strong&gt;open questions&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;action items grouped by person&lt;/strong&gt;, with due dates when someone said one&lt;/li&gt;
&lt;li&gt;a Markdown file plus a &lt;strong&gt;ready-to-paste WhatsApp/Telegram message&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of it runs on my laptop: open Whisper weights for the listening, &lt;strong&gt;Gemma&lt;/strong&gt; for the writing. There's no API key, nothing gets uploaded, and nobody sends me a bill.&lt;/p&gt;

&lt;p&gt;And for the truly lazy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sloth &lt;span class="nt"&gt;--watch&lt;/span&gt; ~/Recordings/pod-calls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Drop a recording into the folder, go and do something else, and the minutes turn up next to it. Hang around, save energy, get there eventually. Very sloth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;My real pod's call stays private (more on that below), so I wrote a &lt;strong&gt;fictional&lt;/strong&gt; 4-minute standup: Chiamaka, Tunde, Ngozi and Emeka of "Pod Baobab" building &lt;em&gt;DanfoFare&lt;/em&gt;, an app for crowdsourcing Lagos bus fares. I turned the script into audio offline with Piper TTS, one open voice per person, and ran the real pipeline on it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5iw7mnjhui53vovtvtsx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5iw7mnjhui53vovtvtsx.png" alt="Terminal run of Sloth Secretary" width="799" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here are the minutes it wrote, rendered:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1iswu6lpy0utr3e8ozv6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1iswu6lpy0utr3e8ozv6.png" alt="Generated minutes" width="800" height="844"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(There's a 13-second animated version, &lt;code&gt;assets/demo.gif&lt;/code&gt; / &lt;code&gt;demo.mp4&lt;/code&gt;, in the repo.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;These are the real, untouched outputs, so here's an honest grade. Gemma 3 4B caught all 8 tasks and gave each one the right owner. It also put the projector room on Wednesday (it's &lt;strong&gt;Thursday&lt;/strong&gt;), dropped the Sunday deadline on Emeka's Supabase task, and missed one decision ("no real phone numbers in the demo") and one open question ("who presents?"). That's why Sloth Secretary &lt;strong&gt;never sends anything by itself&lt;/strong&gt;: it prints a preview, &lt;code&gt;--edit&lt;/code&gt; opens the draft in your editor, and &lt;code&gt;sloth x.minutes.json&lt;/code&gt; re-renders after your fix. The sloth writes the draft; you spend thirty seconds checking it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://huggingface.co/Ajewoleisrael2/sloth-secretary" rel="noopener noreferrer"&gt;https://huggingface.co/Ajewoleisrael2/sloth-secretary&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;Five plain steps, all open source:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;ffmpeg&lt;/strong&gt; turns whatever the call app exported (&lt;code&gt;.m4a&lt;/code&gt;, &lt;code&gt;.mp4&lt;/code&gt;, &lt;code&gt;.ogg&lt;/code&gt;, WhatsApp voice notes) into 16 kHz mono WAV.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;faster-whisper&lt;/strong&gt; (open Whisper weights, &lt;code&gt;small&lt;/code&gt;, CPU, int8) transcribes it with timestamps. Voice-activity detection skips the long "can you hear me? …you're on mute" stretches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemma via Ollama&lt;/strong&gt; reads the transcript and returns JSON that has to match a schema (structured outputs), so even a small model can't wander off into an essay. &lt;code&gt;--model&lt;/code&gt; swaps in any Ollama model, and &lt;code&gt;--backend llamacpp --gguf model.gguf&lt;/code&gt; runs a GGUF through llama-cpp-python with no Ollama at all. I tested both with Gemma.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Map-reduce for long calls.&lt;/strong&gt; Small models forget the middle of a 50-minute transcript, so it's cut into ~10-minute chunks (with two lines of overlap, so "Tunde, can you…?" never loses its "Yes, by Wednesday"). Each chunk becomes notes, and the notes get merged.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A validator that doesn't trust the model.&lt;/strong&gt; It dedupes items, folds the TL;DR down to two lines, and adds a "⚠️ Please double-check" section when something looks off: a "decision" that overlaps an open question, a task owned by "Me", or a name that never appears in the transcript.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That validator exists because of my &lt;strong&gt;first run&lt;/strong&gt;. Whisper had never met Ngozi (and my American and British demo voices didn't help), so it wrote "Gozi". Emeka became "Imeka", and Supabase became "Superbase". Then Gemma, being helpful, listed "use 30 days of data" as a &lt;em&gt;decision&lt;/em&gt;, when the group had literally said "let's not decide now." So I added &lt;code&gt;--names&lt;/code&gt; (or a lazy &lt;code&gt;sloth-names.txt&lt;/code&gt; in the watch folder). The names go into Whisper's initial prompt and hotwords, and the validator snaps misheard names onto the real ones. On the second run every name was right and the fake decision was gone. Both runs are in &lt;code&gt;examples/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The sloth earned its name the hard way, too. My first full hour-long run on an 8 GB test machine ran out of RAM, and Gemma 4B got OOM-killed on chunk 3 of 6. Now Whisper runs in a child process and hands its memory back before Gemma loads, a crashed model runner gets one patient retry, and every finished chunk is cached. If NEPA interrupts a run, the same command picks up where it stopped. Slow and steady, but it finishes.&lt;/p&gt;

&lt;p&gt;It's under 1,000 lines of Python with one required dependency (&lt;code&gt;faster-whisper&lt;/code&gt;). Ollama gets plain &lt;code&gt;urllib&lt;/code&gt;, and watch mode just polls, waiting until a file stops growing so it never grabs a recording that's still copying off your phone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;My teammates' voices aren't mine to upload.&lt;/strong&gt; People say things on a pod call they'd never post: "I travelled for a wedding," "I haven't started," "my laptop is dying." A secretary should protect that. Here the audio, transcript and minutes never leave the laptop. Once the models are downloaded, it runs with the Wi-Fi off.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data costs real money in Lagos.&lt;/strong&gt; Uploading an hour of audio burns data before a cloud API even sends its bill. Here the models download once, and every call after that costs nothing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NEPA doesn't check your sprint schedule.&lt;/strong&gt; When the power or the router goes, a cloud tool stops working. This one keeps going on a laptop battery.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zero API bill.&lt;/strong&gt; A student budget has no line for "transcription subscription."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I can swap the brain.&lt;/strong&gt; When a better open model comes out, I change one flag. Nobody can deprecate my secretary.&lt;/p&gt;

&lt;p&gt;The tradeoff is real. A 4B model on a CPU is slower and vaguer than a giant cloud model, and Gemma 3 &lt;strong&gt;1B&lt;/strong&gt; was faster still but wrote things like "Update on the fare chart (by Ongoing)". For me, local, private and free wins, &lt;em&gt;as long as a human gets the last look&lt;/em&gt;. That's why the preview step is part of the design.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lazy Payoff
&lt;/h2&gt;

&lt;p&gt;On 16 October 2026 my pod had a ~53-minute ideation call, and I was secretary. When it ended, I had nearly an hour of audio to go back through, pulling out the ideas, decisions and who-does-what, and a brief to write before everyone forgot. My first local transcription with Whisper &lt;code&gt;base&lt;/code&gt; came out patchy. Still, it showed me the hard part could run on my own machine, and that night this project started.&lt;/p&gt;

&lt;p&gt;Real numbers, measured in a &lt;strong&gt;CPU-only&lt;/strong&gt; sandbox (2 ARM vCPUs, 8 GB RAM, no GPU):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Run&lt;/th&gt;
&lt;th&gt;Audio&lt;/th&gt;
&lt;th&gt;Transcribe (Whisper small)&lt;/th&gt;
&lt;th&gt;Gemma&lt;/th&gt;
&lt;th&gt;Total&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Demo standup, single pass&lt;/td&gt;
&lt;td&gt;3 min 56 s&lt;/td&gt;
&lt;td&gt;41.3 s&lt;/td&gt;
&lt;td&gt;77.3 s (gemma3:4b)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1 min 59 s&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Same transcript, forced map-reduce (3 chunks)&lt;/td&gt;
&lt;td&gt;3 min 56 s&lt;/td&gt;
&lt;td&gt;(reused)&lt;/td&gt;
&lt;td&gt;247 s (gemma3:4b)&lt;/td&gt;
&lt;td&gt;4 min 7 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;The real pod call&lt;/strong&gt; (63-min file, talking ends ~53 min; timings only, minutes deleted)&lt;/td&gt;
&lt;td&gt;63 min 10 s&lt;/td&gt;
&lt;td&gt;310 s&lt;/td&gt;
&lt;td&gt;1,004 s (gemma3:4b, 11 chunks, low-RAM flags, 1 crash auto-retried)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;21 min 56 s&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Whisper finished the hour in about 5 minutes, because VAD skips the "you're on mute" silences. Gemma spent about 17 minutes reading eleven chunks and merging them. It crashed once along the way, and the retry carried on without me. The whole call came back as a draft in &lt;strong&gt;22 minutes with nobody watching&lt;/strong&gt;, on two CPU cores.&lt;/p&gt;

&lt;p&gt;That's how the secretary job went from &lt;strong&gt;an evening chore to a coffee break&lt;/strong&gt;. I start it, make tea, come back to a draft, give it a proper skim, fix what's wrong, and paste it into the group chat.&lt;/p&gt;

&lt;p&gt;I'll take that trade every week. The sloth gets the hour, and I keep my evening.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Best Use of Gemma&lt;/strong&gt;: Gemma 3 is the writing brain. I ran &lt;code&gt;gemma3:4b&lt;/code&gt; (the default) and &lt;code&gt;gemma3:1b&lt;/code&gt; locally through Ollama, and &lt;code&gt;gemma-3-1b-it&lt;/code&gt; as a Q4_K_M GGUF through llama-cpp-python, all on CPU and all offline.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
