Skip to content

feat: Demo tab replaces the ONNX demo page and the Streamlit app - #32

Merged
El1as42 merged 20 commits into
mainfrom
feat/demo-tab
Oct 26, 2026
Merged

El1as42 merged 20 commits into
mainfrom
feat/demo-tab

Conversation

@El1as42

@El1as42 El1as42 commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • New top-level Demo tab (/demo/): Just-Bird runs in the browser across the full page width, without the docs sidebars. It is a port of the BirdBox tab of the BirdNET website demo, without species labels: every box is a bird.
  • It replaces the old ONNX demo page and the Streamlit app, which are both removed. No page, README or comment mentions Streamlit any more, and Installation moves into the Home tab, so the Getting Started tab is gone.
  • Instant sliders: the model runs once per recording. Confidence and phrase gap then update the boxes in a few milliseconds, with exactly the boxes a graph run with those values would give.

The demo

  • Audio: file picker or drag and drop, the sample soundscape (the BirdNET website's sample), microphone recordings up to 5 minutes, Xeno-canto numbers. Decoded to 32 kHz mono, cut to 10 minutes.
  • Spectrogram: zoom, pan, minimap, colormaps, brightness and contrast, linear or mel scale. The display settings also switch to the PCEN mel spectrogram the model detects on.
  • Boxes: click to play and select. They can be verified (V), moved, resized, removed (Delete) and drawn (B); N and P step through them. The table highlights the box under the pointer.
  • Exports in the BirdBox output formats: json-with-algorithm-metadata, simplified CSV, Raven selection table, plus a CSV with every table column. The JSON and the full CSV say which boxes were verified, adjusted or drawn.
  • Sound starts muted (clicking a box plays it), with a volume fader and M to toggle. Quiet recordings are played louder, up to +30 dB; the sample needs +27 dB. Detection always uses the original audio.

How the sliders stay exact

  • onnx-graph.js declares the graph's raw_all tensor (per-window boxes, the input of its window fusion) as an extra graph output when the model loads. docs/models/Just-Bird_fp16.onnx stays unchanged.
  • The worker runs ONNX Runtime Web 1.20.1, the WASM-only bundle (same reasons as fix: WASM-only ONNX Runtime bundle for the browser demo (WebKit memory) #31), and requests only raw_all at confidence 0.05, so the graph's own fusion is skipped.
  • fusion.js is a float32 port of merge_raw_songs(..., "fusion"). NMS only lets higher-scoring boxes suppress lower ones, so the rows above a threshold equal a graph run at that threshold.
  • tests/js/demo_fusion_parity.mjs compares fusion.js with the graph's own detections output for 16 (conf, phrase gap) settings. On tests/test.wav and the old 15 s sample: 32/32 settings identical, zero deviation. The Demo page's new "Adding models" section asks for this check after a new export.

Other changes

  • Old ONNX demo removed: docs/getting-started/demo_onnx.md and its scripts and styles. ONNX Runtime used to load on every docs page; now only the Demo page loads it. Its "Adding models" section moved to the Demo page. The demo runs the first window-fusion entry of manifest.json, which gains conf (where the confidence slider starts) and species_mapping (for the exported JSON); names label the exported boxes.
  • Streamlit removed: src/streamlit/, .streamlit/, its docs page and screenshot, the three Streamlit constants in src/config.py, and streamlit and Pillow in requirements.txt (only the app used Pillow; Ultralytics still installs it). Line anchors into src/config.py follow.
  • Sample audio: docs/audio/sample_15s.wav is replaced by BirdNET_soundscape_32kHz.flac, the BirdNET website's sample. It is BirdNET-Analyzer's example soundscape (MIT) at 32 kHz; NOTICE.md lists it.
  • README: the demo section links the Demo tab and shows a light or dark screenshot, matching the reader's theme. The BibTeX license now reads MIT (code), AGPL-3.0 (project as a whole).
  • Moved pages: /getting-started/installation/ is now /installation/, and /getting-started/demo_onnx/ and /getting-started/demo_streamlit/ are gone. No redirects, so outside links to those pages break.

Test plan

  • mkdocs build without warnings; check_license_headers.py passes
  • tests/js/demo_fusion_parity.mjs: 32/32 settings identical
  • Headless Chromium, built site: sample, sliders, editing, drawing, keyboard, all four exports, light and dark mode, phone width; no console errors
  • Same box counts as the BirdNET website on the sample (55); an 11-minute file is cut to 10:00 with a notice (Chromium, 55 s)
  • Firefox and WebKit headless: the demo works, same boxes
  • Sound: mute, fader, Space and M in Chromium and Firefox; signal level after the gain stage measured
  • Microphone recording and Xeno-canto loading (not available in headless tests)
  • Real Safari on macOS / iOS
  • Firefox speed on a real machine: headless Firefox here ran the model about 8 to 15 times slower than Chromium, and the BirdNET website's demo was just as slow there

🤖 Generated with Claude Code

El1as42 and others added 20 commits October 26, 2026 20:49
Building blocks for a new browser demo. onnx-graph.js declares the graph's
raw_all tensor (per-window boxes, the input of its window fusion) as an extra
graph output when the model is loaded, so docs/models/Just-Bird_fp16.onnx stays
as it is. The worker runs ONNX Runtime Web 1.20.1 (WASM-only bundle) and
requests only raw_all at confidence 0.05, which skips the fusion step.
fusion.js is a float32 port of merge_raw_songs(..., "fusion"); on the 15 s
sample it gives the same boxes as the graph for 20 (conf, phrase gap)
settings, so slider changes need no new graph run.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
STFT spectrogram up to 15 kHz computed in a worker and drawn from cached
tiles, with a minimap, zoom and pan by wheel, drag or pinch, a playback
cursor, and overlay and editing hooks for the detection boxes. Colormap,
linear or mel scale, brightness and contrast are remembered in the browser.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Files by picker or drag and drop, the 15 s sample, microphone recordings of
up to 5 minutes and Xeno-canto recordings by number. Audio is decoded to
32 kHz mono and cut to 10 minutes, as in the earlier ONNX demo.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
New top-level Demo tab. The page template (overrides/demo.html, theme
custom_dir) drops both sidebars and uses the full width under the header.
Confidence and phrase gap sliders update the boxes instantly from the one
graph run. Boxes can be played, verified, moved, resized, removed and drawn,
and export as the BirdBox JSON, simplified CSV and Raven selection table
layouts plus a full CSV; the JSON and full CSV mark reviewed and drawn boxes.
No species labels: every box is a bird. The demo scripts and styles load on
this page only.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The viewer's display settings switch between the STFT spectrogram and the
PCEN mel spectrogram BirdBox detects on (flattop 2048-point FFT, hop 375,
256 mel bands from 50 Hz to 15 kHz), computed like onnx_spectrogram.js of the
earlier demo but streamed in slices. Mel rows get their own mel axis, so the
boxes stay in place; the choice is remembered.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
tests/js/demo_fusion_parity.mjs runs docs/models/Just-Bird_fp16.onnx with
the demo's ONNX Runtime Web bundle (1.20.1, WASM) and compares fusion.js on
raw_all with the graph's own detections for 16 (conf, phrase gap) settings.
On docs/audio/sample_15s.wav and tests/test.wav all 32 settings give the
same boxes. Rerun after changing the fusion in onnx_export.py or the model.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Clicking a box plays it, so sound was on before anyone asked for it. The
player now starts at volume 0. A mute button and fader next to the file name
(M toggles) set the level, which the browser remembers. When something plays
without sound, the fader is highlighted and a one-time hint offers to turn
the sound on. iOS ignores the element volume, so there the fader works as an
on/off switch.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
A click on a box scrolled the page down to its table row. Now nothing
scrolls; the row is still highlighted. N and P scroll only the table's own
list to the row, never the page.

The demo's keys are now handled before Material's shortcuts see them:
Material reads N and P as next and previous page, so stepping through the
boxes with N left the demo and lost the recording.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The Demo tab and the ONNX demo page now load the 2-minute sample of the
BirdNET website demo instead of the first 15 s of tests/test.wav, which is
removed. It is the example soundscape of BirdNET-Analyzer
(birdnet_analyzer/example/soundscape.wav, MIT License) at 32 kHz, so it needs
no resampling; NOTICE.md lists it. Both demos find 55 boxes in it at the
default settings, as the website does. The fusion parity test now runs on
tests/test.wav by default.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The explanations under the spectrogram opened on the first visit. They now
stay closed until the ? button opens them, on every visit, so nothing is
stored for them in the browser any more.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The fader set the element volume to its square, and the mute button turned
sound on at 0.7, so 0.49. The sample soundscape peaks at -32 dBFS and averages
-49 dB, which then stayed at or below the edge of hearing on most speakers. The
fader is now linear and the mute button turns sound on at full volume, as
loud as before the fader existed.

Space on the focused mute button toggled the button again (muting) instead of
playing; Space now plays and pauses there and on the fader, and M works with
the fader focused.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The sample soundscape averages -49 dB and peaks at -32 dBFS, about 25 dB
below ordinary recordings (tests/test.wav: -25 dB mean, 0 dBFS peak), so even
at full volume it was barely audible while other files were fine. An audio
element cannot play louder than the file, so playback now runs through a Web
Audio gain node from the first play on. Each recording gets a playback gain
that brings its 99.99th percentile of |sample| to -6 dBFS, up to +30 dB;
recordings at a normal level or louder keep gain 1. The sample is played
27 dB louder, and the file line says so. Detection still uses the decoded
audio as it is. With the gain node the fader also works on iOS, which ignores
the element volume.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The Getting Started page "Demo ONNX", its scripts and styles are removed; the
Demo tab does all it did. Its "Adding models" section moves to the Demo page,
updated for the demo: it runs the first window-fusion model of
docs/models/manifest.json, whose new conf and species_mapping fields set the
confidence slider and the exported model_config, and names labels the
exported boxes. demo_fusion_parity.mjs takes a model path for checking a new
export. ONNX Runtime Web and the demo scripts no longer load on every docs
page, only on the Demo page.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The table's list scrolled smoothly, so quick N or P presses cut each scroll
short, and it only checked the list's own box, which can reach below the
window. The list now scrolls instantly and keeps the row between the page
header and the bottom of the window. The page itself still never scrolls.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The Demo tab replaces it, so the app (src/streamlit/, .streamlit/), its docs
page and screenshot, its constants in src/config.py and the streamlit and
Pillow requirements are removed, and no page mentions it any more. The
README's demo section now links the Demo tab and shows a screenshot of it
(the sample soundscape, so NOTICE.md lists it with that file). The line
anchors into src/config.py follow the removed constants.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
With the demo pages gone, Getting Started only held Installation. It is now
the second page of the Home tab (docs/installation.md, /installation/), and
the Getting Started tab is removed. Links to it, including the ones that
tests/model_format_parity.py writes into the model-type pages, follow the new
path. The detect-and-merge figure moves from img/getting-started/ to
img/how-it-works/, next to the page that shows it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
A picture element picks docs/img/demo_screenshot_dark.png for readers in dark
mode and docs/img/demo_screenshot_light.png otherwise, both taken from the
Demo tab with the sample soundscape.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The BibTeX entry in the README said MIT only, which reads as if all of
BirdBox could be used under MIT. It now says MIT for the code and AGPL-3.0
for the project as a whole, as NOTICE.md and the License section explain.
CITATION.cff keeps license: MIT, since a list there would mean either
license, and its message already explains the AGPL-3.0 part.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@El1as42
El1as42 merged commit 80eed3a into main Oct 26, 2026
1 check passed
@El1as42
El1as42 deleted the feat/demo-tab branch October 27, 2026 14:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant