DEV Community

Cover image for TrailCall — an offline bird-call ID companion for your next hike
Ravi Kumar
Ravi Kumar

Posted on

TrailCall — an offline bird-call ID companion for your next hike

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

TrailCall is a CLI that identifies bird species from audio recorded on
the trail — fully offline. Point it at a clip (recorded live from your mic
or an existing file) and it tells you which species are singing, with a
confidence score and timestamp for each call. No signal needed, no account,
no data leaving your device.

It also has an optional mode that turns the raw detections into a single,
friendly sentence — a "trail note" — using a local Gemma model, so you don't
have to read a table of species names and confidence scores off a screen
while you're trying to actually look at the bird. It's built for anyone
whose "what was that?" moment happens somewhere with no signal: hikers,
birders, and citizen-science volunteers alike.

Real-World Use Cases

This isn't just a novelty for a weekend hike — offline, on-device species ID
has real use across different kinds of outdoor exploration:

  • Solo backcountry hikers — on multi-day trips far past cell coverage,
    TrailCall turns "what was that?" into an answer on the spot, no satellite
    messenger or data plan required. The --trail-note mode means you get a
    spoken-style summary without pulling out a field guide or squinting at a
    table of species names.

  • Citizen science / biodiversity surveys — volunteers doing point-count
    surveys for projects like eBird or local Audubon chapters often work in
    exactly the kind of remote, low-signal habitat (wetlands, forest interior,
    high elevation) where cloud-based ID tools fail. A CLI that runs fully
    offline means the data collection doesn't depend on coverage maps.

  • Field researchers and conservationists — ecologists doing acoustic
    monitoring in remote reserves, or tracking species presence/absence across
    a season, can batch-run recordings through TrailCall on a laptop in camp
    with zero cloud dependency and zero recurring API cost — important when
    you're processing hundreds of clips, not one.

  • Outdoor education / guided nature walks — a trip leader with a group
    of kids or new birders can confirm a call in real time and have Gemma turn
    it into one friendly sentence to read aloud, instead of breaking the
    moment to look something up.

  • Off-grid homesteads and remote properties — for anyone living or
    working somewhere without reliable signal, it's a way to identify the
    birds around a property without needing a connection at all.

The common thread: every one of these situations is defined by being
away from reliable connectivity — which is exactly where a cloud-API
bird-ID app stops working and TrailCall keeps going.

Demo

$ python trailcall.py identify recordings/sample_soundscape.wav --lat 35.42 --lon -120.74 --trail-note

190 species loaded.
Detected 17 call(s):

  House Finch (Haemorhous mexicanus) - confidence 0.64, 9.0s-12.0s
  Dark-eyed Junco (Junco hyemalis) - confidence 0.46, 33.0s-36.0s
  Dark-eyed Junco (Junco hyemalis) - confidence 0.74, 42.0s-45.0s
  House Finch (Haemorhous mexicanus) - confidence 0.61, 54.0s-57.0s
  American Goldfinch (Spinus tristis) - confidence 0.42, 90.0s-93.0s
  ...

Trail note:
  We spotted a lovely mix of American Goldfinches, Dark-eyed Juncos, and House Finches!
Enter fullscreen mode Exit fullscreen mode

(Real output from running the full pipeline — BirdNET detection + Gemma trail note via Ollama — against a 2-minute field recording.)

setup
record command
identify command
identify --trail-note output

Code

Repo: https://github.com/ravii333/trailcall

trailcall/
├── trailcall.py      # CLI: record + identify commands
├── requirements.txt
└── README.md
Enter fullscreen mode Exit fullscreen mode

How I Built It

The pipeline is two stages, both running locally:

  1. Species detection — BirdNET,
    an open-weight acoustic classifier, via the birdnetlib Python wrapper.
    It loads a .tflite model once (first run only, then cached) and scores
    audio in short windows, returning species + confidence + timestamp for
    every call it recognizes above a threshold. Passing latitude/longitude
    narrows the candidate species list for the region and season, which
    measurably improves accuracy.

  2. Trail note generation (optional) — the raw detection list gets handed
    to a local Gemma 4 model (gemma4:e2b, the smallest Gemma 4 variant,
    ~2B params) served by Ollama over its local REST
    API. One short prompt, one short sentence back. If Ollama isn't running,
    the CLI fails that one feature gracefully with setup instructions instead
    of crashing — species detection keeps working either way.

Both stages run with zero API keys and zero network calls once the models
are cached.

Why Does Open Innovation Matter?

The whole point of "Touch Grass" is to get a screen-based tool out of the
way of an actual outdoor experience. That only works if the tool keeps
working with no signal — which rules out any cloud-API-based bird ID or
cloud LLM. Open-weight models (BirdNET, Gemma) are what make "point this at
a bird call deep in the woods and get an answer" possible at all:

  • Offline-first: nothing here needs a connection once the models are cached. That's a hard requirement on a trail, not a nice-to-have.
  • Privacy: field recordings never leave your device.
  • Cost: no per-call fees, which matters if you're identifying calls all day on a long hike.
  • Customizable: BirdNET supports swapping in a custom/regional model; the Gemma step works with any Ollama model, so the "voice" of the trail note is yours to tune.

A closed, API-gated version of this tool would be strictly worse at the one
job it has to do: work when you have no signal.

My Agent Session

Built with Claude Code — used it to scaffold the CLI, wire up the BirdNET
and Ollama/Gemma integrations, debug missing transitive dependencies
(librosa, audioread, tensorflow weren't declared by birdnetlib but
are required), and smoke-test against a real field recording before and
after adding the Gemma trail-note feature.

Prize Categories

  • Best Use of Gemma — the --trail-note feature runs Gemma 4 (gemma4:e2b) locally via Ollama to summarize detections into one spoken-style sentence, with no API key and no cloud call.

Top comments (0)