How to run Bird Audio Analyzer from source, test it, build installers, and cut a release. Researchers who only want to use the app should follow Installing Bird Audio Analyzer instead.
- Prerequisites
- Clone and install
- Run in development
- Tests
- How the packaged app finds the pipeline
- Build installers locally
- Continuous integration and releases
- Headless CLI
- Analysis scripts
| Tool | Why | Install |
|---|---|---|
| uv | Python environment and dependencies for the ML pipeline | https://github.com/astral-sh/uv |
| Rust + Cargo | builds batch-core and the Tauri shell |
https://rustup.rs/ |
| Tauri prerequisites | platform webview and build tooling | https://tauri.app/start/prerequisites/ |
| Node.js 20+ | builds the React frontend | https://nodejs.org/ |
| git-lfs | the detector models in models/ are stored with Git LFS |
https://git-lfs.com/ |
git lfs install # once per machine
git clone https://github.com/Human-Augment-Analytics/bird-audio.git
cd bird-audio
npm install # frontend dependencies
uv sync # Python environment (.venv) for the ML pipelineCheck that the models are real files and not LFS pointers:
ls -la models/ # buzz_localizer.pt ≈ 49 MB, classifier.pt ≈ 25 MBIf they are a few hundred bytes, run git lfs pull.
npm run tauri devThe first launch compiles the Rust backend (a few minutes); later runs are incremental. In development the app uses the repository checkout directly: scripts/, birdpipe/, models/ and the .venv that uv sync created. The health panel's Prepare System button runs uv sync in the checkout.
The frontend alone can be served with npm run dev, but the Tauri commands it calls will not exist.
uv run pytest -q # Python: birdpipe, scripts, worker protocol
cargo test -p batch-core # Rust engine, store, identity, export
cargo test --manifest-path src-tauri/Cargo.toml # Tauri commands and runtime root
npx tsc -p tsconfig.app.json --noEmit # TypeScript
npm run linttests/test_quarter_blocks.py and tests/test_consolidate.py pin the numerical behaviour of the pipeline; if you touch scripts/ml_engine.py or birdpipe/, run them and compare a real file before and after (see docs/architecture.md, Reproducibility).
An installed copy has no repository, so the bundle carries everything the Python side needs as Tauri resources under Contents/Resources/payload/ (macOS) or the equivalent resource directory on Windows and Linux:
payload/
├── scripts/*.py
├── birdpipe/*.py
├── config/features.yaml
├── models/buzz_localizer.pt, classifier.pt
├── pyproject.toml
├── uv.lock
└── .python-version
plus a uv binary shipped as a Tauri sidecar next to the app executable (src-tauri/binaries/uv-<target-triple>, downloaded by CI; .gitignored).
At start-up src-tauri/src/runtime.rs decides the project root:
- Debug builds and any build launched from inside a checkout use the repository (
models/andpyproject.tomlfound next to the crate or by walking up from the executable or working directory). - Otherwise the payload is copied to a writable per-user directory,
<app data dir>/runtime(for example~/Library/Application Support/com.bird.audioanalyzer/runtimeon macOS). A.payload-versionstamp records the app version; the copy is refreshed when the version changes, but the.venv/thatuv synccreated there is kept so updates do not re-download PyTorch.
Every command that shells out (check_health, prepare_system, the worker spawn, the analysis scripts) uses that root as its working directory and the sidecar uv when present, falling back to ~/.local/bin/uv, Homebrew, /usr/local/bin and PATH.
The health check runs uv run --no-sync python -c "import torch, ..." so that a probe never starts the multi-gigabyte download on its own; Prepare System runs uv sync. uv downloads a managed CPython matching .python-version when the machine has none, so no system Python is required.
Download the uv sidecar for your platform once (the CI workflow does the same):
mkdir -p src-tauri/binaries
# macOS Apple Silicon
curl -sL https://github.com/astral-sh/uv/releases/download/0.12.10/uv-aarch64-apple-darwin.tar.gz \
| tar xz && mv uv-aarch64-apple-darwin/uv src-tauri/binaries/uv-aarch64-apple-darwin && rmdir uv-aarch64-apple-darwinThen:
npm run tauri build # all bundle targets for this platform
npm run tauri build -- --bundles app # macOS: just the .app, fastest for testingOutput lands in target/release/bundle/. To test as a user would, copy the .app to /Applications and launch it from there with a clean app-data directory:
rm -rf ~/Library/Application\ Support/com.bird.audioanalyzer
open "/Applications/Bird Audio Analyzer.app"The console (or Console.app) shows [bird-audio] pipeline root: … on start-up. To force a cold Prepare System that really downloads everything, launch the binary directly with a fresh uv cache:
UV_CACHE_DIR=/tmp/uvcache UV_PYTHON_INSTALL_DIR=/tmp/uvpy \
"/Applications/Bird Audio Analyzer.app/Contents/MacOS/bird-batch-gui"Release builds ignore the compile-time checkout path on purpose, so the copy in /Applications behaves exactly like one on another machine.
The installers are not code-signed. macOS users must allow the app once in System Settings, Privacy & Security and Windows users click through SmartScreen; install.md documents both. Signing needs an Apple Developer ID and a Windows code-signing certificate; the Tauri action supports both through repository secrets when the project acquires them.
.github/workflows/build-desktop.yml builds the macOS (Apple Silicon), Windows and Linux installers with tauri-apps/tauri-action. It runs on:
- every push to
main: creates a draft release taggedv<version>where the version comes fromsrc-tauri/tauri.conf.json; - every push to a
release-test/**branch: creates a draft pre-release taggedtest-<run number>-v<version>for trying an installer before merging; - manual dispatch from the Actions tab.
The workflow checks out with Git LFS (and fails early if the model files are pointers), downloads the pinned uv sidecar per platform, then builds.
To cut a release:
- Bump the version in
package.json,src-tauri/tauri.conf.jsonandsrc-tauri/Cargo.toml(runnpm install --package-lock-onlyandcargo buildto refresh the lock files), commit, and merge tomain. - Wait for the workflow. It uploads seven installers to a draft release.
- Edit the draft: title, notes, and publish (
gh release edit v<version> --draft=false --latest --notes-file notes.md).
A change to scripts/ml_engine.py, birdpipe/, or the models changes the session identity, so users who re-run a folder after updating get a fresh session (see docs/architecture.md, Reproducibility).
cargo run -p batch-core --bin batch -- \
--input data/ \
--device cpu \
--db data/batch.db \
--export-csv events.csvSame engine and database as the app: process overnight on the command line, then open the folder in the app to review. --worker-cmd and --cwd point the CLI at a different pipeline root, for example an installed app's runtime directory. Pass a path without spaces (a symlink is fine); the command string is split on whitespace.
Command-line tools under scripts/ read a finished batch.db:
uv run python scripts/ecological_analysis.py --db data/batch.db --metadata deployments.csv --out out/ecology --measure-effort
uv run python scripts/threshold_sensitivity.py --db data/batch.db --out out/sensitivity
uv run python scripts/verification_planner.py --db data/batch.db --threshold 0.5 --target-half-width 0.05 --strategy uncertainty --budget 50
uv run python scripts/run_manifest.py --db data/batch.db --out out/manifest.json
uv run python scripts/export_protocol.py --db data/batch.db --out out/protocolSee Advanced search and active learning and the active learning tutorial for the model-improvement loop, and App reference for the Tauri command surface and schema.