This is my submission for the Hacktoberfest Open-Source AI Challenge: Week 1 — Touch Grass.
The best birding happens exactly where your phone becomes a brick: deep forest, mountain trails, that marsh 40 minutes from the nearest cell tower. The moment a call you don't recognize echoes through the trees, the usual flow is: record it, hope you remember it later, upload it when you get home, wait for the cloud.
I wanted the whole loop to close on the trail. So I built trail-bird-id: point it at an audio file, get the species. No internet. No account. No API key. No per-call cost. Just a laptop (or a Raspberry Pi) and an open-weight model.
$ python identify.py trail_recording_07h42.mp3
Analyzing trail_recording_07h42.mp3 (fully offline, BirdNET V2.4, 6,522 species)...
1. Black-capped Sparrow (Arremon abeillei) conf=0.99 @ 0.0-3.0s
2. Streaked Saltator (Saltator striatipectus) conf=0.86 @ 3.0-6.0s
The heavy lifting is BirdNET — an open-source audio classifier from the Cornell Lab of Ornithology and Chemnitz University of Technology (CC BY-SA 4.0), trained on 6,522 species. It ships as a ~50 MB TFLite/TensorFlow model inside the pip package, which is the whole trick: installing the library means installing the brain.
My contribution is a ~60-line wrapper, identify.py, that runs the model in 3-second windows over any wav/mp3/ogg file and aggregates to the best-confidence detection per species:
uv venv --python 3.11 .venv
uv pip install --python .venv/bin/python birdnet-analyzer
.venv/bin/python identify.py your_recording.mp3 --top 5
That's the entire setup. No Docker, no GPU, no cloud credentials.
I don't trust demos that only show one cherry-picked clip, so I tested against four field recordings from Wikimedia Commons where the species is known from the recording metadata (xeno-canto / iNaturalist sourced):
| Recording | Expected species | Top-1 prediction | Confidence |
|---|---|---|---|
| Black-capped Sparrow XC250490 (Niels Krabbe, CC BY-SA) | Arremon abeillei | ✅ Black-capped Sparrow | 0.99 |
| Australian Magpie song (CC BY-SA) | Gymnorhina tibicen | ✅ Australian Magpie | 0.99 |
| Brown Hawk-Owl, South Bengal (CC BY) | Ninox scutulata | ✅ Brown Boobook*(same bird, name updated by taxonomists — the model is more current than the file title)* | 1.00 |
| Guira Cuckoo (CC0) | Guira guira | ✅ Guira Cuckoo | 0.95 |
4/4 top-1 correct, across four continents and four very different vocalizations (sparrow song, magpie caroling, an owl's hoot, cuckoo chatter). Runtime: ~6.7 seconds wall-clock for a 40-second recording, on a plain CPU.
"Works offline" is easy to claim. So I re-ran identification with all egress blocked — every proxy environment variable pointed at a dead localhost port, so any HTTP call from the Python stack would fail instantly:
$ env HTTPS_PROXY=http://127.0.0.1:9 HTTP_PROXY=http://127.0.0.1:9 \
ALL_PROXY=socks5://127.0.0.1:9 NO_PROXY= \
.venv/bin/python identify.py audio/australian_magpie.ogg
1. Australian Magpie (Gymnorhina tibicen) conf=0.99 @ 9.0-12.0s
Still works, because there is no network code to fail. The weights live in site-packages/birdnet_analyzer/checkpoints/. The trail is the deployment target, and the trail has no SLA.
This is where the open approach doesn't just match the closed one — it wins:
--lat/--lon filters to species plausible for your coordinates), or fine-tune on your own recordings. Try doing that with a closed mobile app.
The screen is the shortest part of this experience: record outside, identify anywhere, get back to listening. 🌲