<?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: Brage 1025</title>
    <description>The latest articles on DEV Community by Brage 1025 (@brage1025).</description>
    <link>https://dev.to/brage1025</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%2F4154955%2Fec67d466-ac5f-40ef-b39b-2c78e20835bd.jpg</url>
      <title>DEV Community: Brage 1025</title>
      <link>https://dev.to/brage1025</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/brage1025"/>
    <language>en</language>
    <item>
      <title>Who's Singing?: An offline bird-call identifier</title>
      <dc:creator>Brage 1025</dc:creator>
      <pubDate>Thu, 08 Oct 2026 11:19:59 +0000</pubDate>
      <link>https://dev.to/brage1025/whos-singing-an-offline-bird-call-identifier-2609</link>
      <guid>https://dev.to/brage1025/whos-singing-an-offline-bird-call-identifier-2609</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week1-2026-10-05"&gt;Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Who's Singing?&lt;/strong&gt; is an offline bird-call identifier for your walks. You record 30~60 seconds of audio on your phone, run one command, and get a list of which birds were singing, how much to trust each one, and a short note written by a local LLM.&lt;/p&gt;

&lt;p&gt;The idea is to keep the screen the shortest part of the experience. You spend the time &lt;strong&gt;outside&lt;/strong&gt; listening, walking with your ears open and your phone ready to record in your pocket. The the laptop is only checked at the end, usually when you're done for the day. It's for anyone who has stopped on a trail and wondered "what &lt;em&gt;is&lt;/em&gt; that?". It works even at your hut or campsite where there's no signal, because nothing in it needs the internet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Who's singing:

  Great Tit                  confident  best  66.2%  (4 detections)
  Great Spotted Woodpecker   likely     best  80.1%  (2 detections)
  Eurasian Blue Tit          possible   best  41.2%  (2 detections)

Field note (written by qwen2.5:3b):
  On this walk, I clearly heard a Great Tit, four times. I also probably
  heard a Great Spotted Woodpecker, twice.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/g2nv-HsVla0" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;To try it yourself, you need a bird recording of your own (the repo doesn't include audio):&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Brage1025/whos-singing.git
&lt;span class="nb"&gt;cd &lt;/span&gt;whos-singing

python &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv
&lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate        &lt;span class="c"&gt;# Windows: .venv\Scripts\activate&lt;/span&gt;
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt

ollama pull qwen2.5:3b           &lt;span class="c"&gt;# For the field note&lt;/span&gt;

python whos_singing.py my-walk.mp3 &lt;span class="nt"&gt;--lat&lt;/span&gt; 59.91 &lt;span class="nt"&gt;--lon&lt;/span&gt; 10.75
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Swap &lt;code&gt;my-walk.mp3&lt;/code&gt; for a recording from your phone, and the coordinates for where you made it. The location is what lets BirdNET leave out species that don't live near you.&lt;/p&gt;
&lt;h2&gt;
  
  
  Code:
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Brage1025" rel="noopener noreferrer"&gt;
        Brage1025
      &lt;/a&gt; / &lt;a href="https://github.com/Brage1025/whos-singing" rel="noopener noreferrer"&gt;
        whos-singing
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      My submission for the Hacktoberfest 2026 Open-Source AI Challenge, Week 1: Touch Grass
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Who's Singing?&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;An offline bird-call identifier for your walks. Record 30~60 seconds of audio on your phone, run one command, and get a list of which birds were singing, how much to trust each one, and a short note written by a local LLM.&lt;/p&gt;

&lt;p&gt;Built for the Hacktoberfest Open-Source AI Challenge, Week 1: &lt;strong&gt;Touch Grass&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Demo:&lt;/strong&gt; &lt;a href="https://youtu.be/g2nv-HsVla0" rel="nofollow noopener noreferrer"&gt;Watch it run with Wi-Fi off&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The screen is the shortest part of the experience: you spend your time &lt;strong&gt;outside&lt;/strong&gt; listening, and only check the laptop at the end.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why open-source AI?&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;Two open models do the work, both are running on your own machine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Works without internet.&lt;/strong&gt; After a one-time download of the models, no internet is needed. Tested with Wi-Fi turned off.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your recordings stay with you.&lt;/strong&gt; Audio, locations, and your bird list are never uploaded anywhere.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free to run.&lt;/strong&gt; No API keys, no per-request costs and no token limits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swappable&lt;/strong&gt;…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Brage1025/whos-singing" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;

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

&lt;p&gt;Two open models run on my own machine:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/birdnet-team/BirdNET-Analyzer" rel="noopener noreferrer"&gt;BirdNET-Analyzer&lt;/a&gt;&lt;/strong&gt; (Cornell Lab of Ornithology and Chemnitz University of Technology) does the identification. It scores each 3-second slice of audio against thousands of species. I pass in my latitude, longitude and the week of the year, and its species list shrinks from 6,522 to about 240, so a recording from Oslo stops returning sunbirds and cuckooshrikes from other continents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A small local LLM through &lt;a href="https://ollama.com" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;&lt;/strong&gt; writes the one-line note. I defaulted to &lt;code&gt;qwen2.5:3b&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Around them I wrote a short Python script that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;merges the 3-second detections into one row per species,&lt;/li&gt;
&lt;li&gt;assigns a &lt;strong&gt;confidence tier&lt;/strong&gt; (&lt;code&gt;confident&lt;/code&gt;, &lt;code&gt;likely&lt;/code&gt;, &lt;code&gt;possible&lt;/code&gt;), because a single high score on one window is weak evidence and repeated detections are stronger,&lt;/li&gt;
&lt;li&gt;sends only confident and likely birds to the LLM,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;checks the note in code&lt;/strong&gt; and replaces it with a plain template if it's wrong,&lt;/li&gt;
&lt;li&gt;logs each session to a local CSV, so over time it builds a private bird list.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The LLM kept getting it wrong:
&lt;/h3&gt;

&lt;p&gt;This was the most useful part of the project. The identification worked from the start. The note took five rounds:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Given only species names, the model invented facts.&lt;/strong&gt; It gave a Great Tit "brightly colored heads" and described a European bird's call for a North American one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;After I forbade facts, the note got clumsy&lt;/strong&gt; and hedged a confident bird with "probably".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;After I added an example to the prompt, the model copied it.&lt;/strong&gt; It reported a Wren, which was never in the recording.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Then it repeated a real bird&lt;/strong&gt; ("I clearly heard a Great Tit... I probably heard a Great Tit").&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;So the code now rejects any note&lt;/strong&gt; that misses a bird, repeats one, names one that wasn't detected, or uses "clearly" or "probably" wording that doesn't match the tiers. Certainty wording is now decided in code to ensure quality and stability, not by the model.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I then compared two models on the same recording with the final prompt and check, five runs each:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Passed the check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;qwen2.5:3b&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5 of 5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;llama3.2&lt;/code&gt; (3B)&lt;/td&gt;
&lt;td&gt;1 of 5, the other four fell back to the template&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That's one recording and one prompt, so it's a small test, not a benchmark. But it took only minutes, and switching the winner was as easy as changing one flag: &lt;code&gt;--model&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  How it did on real audio:
&lt;/h3&gt;

&lt;p&gt;I tested on three recordings: an old one of my own and two from a friend who prefers to stay anonymous. Only one of the friend's recordings has ground truth, because she knew what was there. That one was recorded just outside Oslo. She saw the Great Tits and Blue Tits, and heard the woodpecker without seeing it. So all three detections were real.&lt;/p&gt;

&lt;p&gt;BirdNET found everything with no false detections. The weak spot was my own tiers. The Blue Tit was a real bird, but two detections with a best score of 41% put it in &lt;code&gt;possible&lt;/code&gt;, so the note left it out. I'd rather the tool under-claim than confidently name a bird that wasn't there, so I kept that threshold, but it's a trade-off I made by judgment, and I didn't tune it on a single recording.&lt;/p&gt;

&lt;p&gt;I also owe an honest note: I didn't get out on a walk myself this week, so I haven't field-tested it outdoors. Everything above was run on recordings, offline.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It runs with no internet.&lt;/strong&gt; After a one-time model download I turned Wi-Fi off and ran the full pipeline, including the note. That's what makes a bird identifier usable on a trail or out on field work with no signal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recordings stay on my machine.&lt;/strong&gt; Audio, locations and my bird list are never uploaded. So I can decide if it's nobody else's business or not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It costs nothing to run.&lt;/strong&gt; No API key, no per-request charge and no token limits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I could see and fix the weak link.&lt;/strong&gt; When the small model invented a Wren, I could inspect the prompt, change the model, add a validator and compare alternatives side by side. With a closed API I'd have received the same wrong note with no easy way to tell why.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The two parts are separately swappable.&lt;/strong&gt; BirdNET handles identification and the LLM handles wording, so I can replace either without touching the other.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One caveat on "open": BirdNET's model is open-weight but carries a non-commercial license, so it's free to inspect and use for a project like this, not free of conditions. The code in my repository is MIT.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Special thanks to my dear friend, who prefers to stay anonymous, for the field recording and for telling me what she actually saw and heard.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>hacktoberfest</category>
    </item>
  </channel>
</rss>
