Webui: open video source, restructure lyrics form, and add a visual per-line review #4

Merged
branderson merged 15 commits from worktree-webui-lyrics-review into main 2026-07-28 01:42:57 -07:00
Owner

Summary generated by LLM agent

Summary

Three related webui improvements for songtrace's song review flow:

  • Song creation form: the video/YouTube source field is now visible up front instead of hidden behind an "Advanced" collapsible, and the lyrics textarea moved into a taller, narrower right-hand column.
  • Alignment pipeline: extra/never-sung reference lines are now detected via difflib opcode classification and excluded from the proportional time-distribution used for force-alignment (with a warning), instead of silently distorting timing for the lines that were sung. Sung-but-unreferenced audio (ad-libs, spoken asides) is similarly flagged and excluded from note generation.
  • Review UI: once a song finishes processing, the "Review" panel is now a visual, per-line SVG piano-roll — pitched notes rendered under each lyric line, low-confidence notes color-coded, dropped (never-sung) lines shown struck-through, and unmatched/missing audio spans shown as inline chronological markers. This replaces the old flat text warnings list. Backed by a new GET /api/jobs/{job_id}/review endpoint.

CLI behavior is unchanged; this only touches the webui and the pipeline stages that feed it.

Notable fix from final review

A whole-branch review caught a real bug that no single task's narrower review could see: classify_lyrics_match() was scoping "missing span" (unmatched audio) bounds to the entire containing vocal section rather than just the unmatched audio itself. Since vocal_sections() merges any segments within 6s of each other, a matched lyric line sharing a section with even a small ad-lib had all of its notes silently dropped from the piano roll. Fixed by scoping missing spans to the padded/merged bounds of just the unmatched segments (commit 2a7b53e), plus a related ordering bug in build_notes() that could corrupt line-initial spacing/break timing for a skipped row's own line. Both fixes have dedicated regression tests.

Known residual risks (please verify locally)

  1. No browser available in the sandbox this was built in (no Chrome/Chromium/Playwright) — the new review UI's DOM structure and class assignment were verified by executing the real committed JS against real API responses via a Node.js DOM stub, but actual visual/CSS rendering was never painted by a real browser. Worth a manual look before merging.
  2. docs/images/webui.png was not regenerated for the same reason. To update it: pip install -e '.[dev]' && playwright install chromium && python scripts/screenshot_webui.py (the script now includes a "Landslide" fixture demonstrating dropped lines, a missing span, and low-confidence notes).

Test plan

  • Full test suite passes: 253 passed, 1 skipped (PYTHONPATH=src .venv/bin/python -m pytest tests/ -q)
  • Implemented via subagent-driven development: fresh implementer per task, task-scoped review + fix loop after each, and a final whole-branch review with one fix round
  • Manual browser check of the new review UI (blocked in this sandbox — see above)
  • Regenerate docs/images/webui.png locally
**Summary generated by LLM agent** ## Summary Three related webui improvements for songtrace's song review flow: - **Song creation form**: the video/YouTube source field is now visible up front instead of hidden behind an "Advanced" collapsible, and the lyrics textarea moved into a taller, narrower right-hand column. - **Alignment pipeline**: extra/never-sung reference lines are now detected via `difflib` opcode classification and excluded from the proportional time-distribution used for force-alignment (with a warning), instead of silently distorting timing for the lines that *were* sung. Sung-but-unreferenced audio (ad-libs, spoken asides) is similarly flagged and excluded from note generation. - **Review UI**: once a song finishes processing, the "Review" panel is now a visual, per-line SVG piano-roll — pitched notes rendered under each lyric line, low-confidence notes color-coded, dropped (never-sung) lines shown struck-through, and unmatched/missing audio spans shown as inline chronological markers. This replaces the old flat text warnings list. Backed by a new `GET /api/jobs/{job_id}/review` endpoint. CLI behavior is unchanged; this only touches the webui and the pipeline stages that feed it. ## Notable fix from final review A whole-branch review caught a real bug that no single task's narrower review could see: `classify_lyrics_match()` was scoping "missing span" (unmatched audio) bounds to the *entire* containing vocal section rather than just the unmatched audio itself. Since `vocal_sections()` merges any segments within 6s of each other, a matched lyric line sharing a section with even a small ad-lib had **all of its notes silently dropped** from the piano roll. Fixed by scoping missing spans to the padded/merged bounds of just the unmatched segments (commit `2a7b53e`), plus a related ordering bug in `build_notes()` that could corrupt line-initial spacing/break timing for a skipped row's own line. Both fixes have dedicated regression tests. ## Known residual risks (please verify locally) 1. **No browser available in the sandbox this was built in** (no Chrome/Chromium/Playwright) — the new review UI's DOM structure and class assignment were verified by executing the real committed JS against real API responses via a Node.js DOM stub, but actual visual/CSS rendering was never painted by a real browser. Worth a manual look before merging. 2. **`docs/images/webui.png` was not regenerated** for the same reason. To update it: `pip install -e '.[dev]' && playwright install chromium && python scripts/screenshot_webui.py` (the script now includes a "Landslide" fixture demonstrating dropped lines, a missing span, and low-confidence notes). ## Test plan - [x] Full test suite passes: 253 passed, 1 skipped (`PYTHONPATH=src .venv/bin/python -m pytest tests/ -q`) - [x] Implemented via subagent-driven development: fresh implementer per task, task-scoped review + fix loop after each, and a final whole-branch review with one fix round - [ ] Manual browser check of the new review UI (blocked in this sandbox — see above) - [ ] Regenerate `docs/images/webui.png` locally
Author
Owner

Both residual risks noted in the PR description are now resolved:

  • Manual browser check of the review UI: a headless-Chromium run confirms the piano-roll note strips and the ♩ unmatched singing, 2:10–2:18 missing-span marker render correctly with real CSS.
  • Regenerate docs/images/webui.png locally: done, commit 153c83b (already pushed) — shows the new review panel for the Landslide fixture.

Full test suite still green (253 passed, 1 skipped).

Both residual risks noted in the PR description are now resolved: - **Manual browser check of the review UI**: a headless-Chromium run confirms the piano-roll note strips and the `♩ unmatched singing, 2:10–2:18` missing-span marker render correctly with real CSS. - **Regenerate `docs/images/webui.png` locally**: done, commit 153c83b (already pushed) — shows the new review panel for the Landslide fixture. Full test suite still green (253 passed, 1 skipped).
branderson added 4 commits 2026-07-28 00:48:24 -07:00
branderson force-pushed worktree-webui-lyrics-review from 153c83bd99 to aa21d60d5e 2026-07-28 00:48:24 -07:00 Compare
branderson added 1 commit 2026-07-28 01:21:56 -07:00
The review panel used to show a full line of packed text with one
undifferentiated strip of notes below it, so it was impossible to tell
which notes belonged to which word. The forced-alignment stage already
produces per-word timestamps in alignment.json, but they were never
surfaced past the pipeline.

/api/jobs/{id}/review now includes each line's per-word timing, and the
frontend spaces words out by their real sung timing (karaoke-style)
instead of normal text flow, with the note strip sharing that same time
axis so each note lands directly under its word. Alternating lane
backgrounds make the word/note pairing unambiguous. Dropped lines and
jobs without alignment data keep the old plain-text rendering.
branderson added 1 commit 2026-07-28 01:34:53 -07:00
Replace arbitrary demo pitches with the actual melody transcribed from
Gilbert DeBenedetti's public-domain "Level 4, Flowing" arrangement (E
minor, 6/8), converted to UltraStar semitones, with one note per word
across both demo lines.
branderson added 1 commit 2026-07-28 01:42:08 -07:00
.review-lane spans the full timeline box height (top:0; bottom:0) to
group each word with its note visually, but as a positioned element it
painted after the unpositioned .review-roll SVG, so the lane's
background covered the note bars for every other word. Give .review-roll
position: relative so DOM order (lanes, then notes) governs paint order
instead.
branderson merged commit c2cbbce489 into main 2026-07-28 01:42:57 -07:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: branderson/songtrace#4