This commit is contained in:
valenti
2026-10-16 12:33:56 +01:00
parent 236fd509ca
commit 430997bd2e
11 changed files with 291 additions and 24 deletions
+122
View File
@@ -5,6 +5,126 @@ Entries are written in English and ordered newest-first.
---
## 2026-10-16 — Mivocero: karaoke word highlighting on the assistant reply
### Changed
- **The `/mivocero` client now reveals the assistant reply in karaoke style**
([`src/web/mivocero.html`](src/web/mivocero.html)) instead of appending plain
text. Each word is a `<span>`; words light up as they are *spoken*. The
highlight is driven by the **audio playhead**: the playback AudioWorklet now
counts the samples it has actually emitted and reports them (`played`) on its
existing per-block message. The client maps that count onto a character offset
with an estimated speaking rate (`KARAOKE_CPS`, ~15 chars/s) and marks each
word `done` / `now` / pending.
- The old blinking-caret "pending" style was removed; the whole reply is shown at
once (dim) and progressively illuminated.
- A safety net finishes the highlight: once `assistant_end` has been received and
playback has been idle for 600 ms *after it had actually started*, any word
still pending is marked done, so a reply always ends fully lit. New turns and
interrupts cancel the loop.
### Notes
- The mapping from audio to text is inherently approximate (the server streams
text and PCM on the same socket without per-word timing), so `KARAOKE_CPS` is a
tunable estimate for the visual effect only — it never touches the audio.
- `played` counts only real samples, so the playback jitter buffer's silence and
any underrun pauses do not advance the highlight.
---
## 2026-10-16 — End-to-end validation → `TTS_PREBUFFER_MS` 700 → 450 ms; Drama-3 startup documented
### Changed
- **`TTS_PREBUFFER_MS` lowered `700` → `450`** (`.env`, `.env.example`,
[`src/config.rs`](src/config.rs)). With the vocoder ramp `"[10,12,16]"` the
*first* window is 10 codec frames = 0.464 s, so `450 ms` sits just below it and
playback now starts on that **first** window instead of waiting for the second
one that `700 ms` required.
- **README:** new *"Starting the Drama 3 backend (SGLang-Omni)"* subsection under
the `fish` plugin, with the exact `sgl-omni serve` command, the **pm2** workflow,
the meaning of the two `--vocoder.factory.*` flags and the two CLI gotchas (no
`stages.` prefix; the ramp tuple passed as a JSON string).
### Why
- An end-to-end browser test (`RUST_LOG=…,audio_agent_engine::tts=debug,…`) on the
live engine confirmed the narrower windows: bursts of 10/12/16 frames
(0.464 / 0.557 / 0.743 s) instead of a single 2.97 s block, `prebuffer=30870`
samples (= 700 ms) and time-to-first-audio ≈ 1.1 s from dispatch (~0.64 s of
which is the server's TTFB). Barge-in fired correctly on three interrupts.
- Three **tail underruns** were still observed at the end of short replies: e.g.
2.46 s of audio produced in ~2.6 s (≈1.07× real time including the fixed
~0.64 s TTFB), so the queue drained just before the last words. The mixer
recovered via resilient resume, but the gap is audible. `450 ms` targets the
first 0.464 s window and trades a little more tail risk for a markedly earlier
start.
### Notes
- The residual deficit is dominated by the server's **fixed ~0.64 s
time-to-first-byte**, which no pre-buffer value can remove. Going lower would
need a faster first token (model / preprocessing), not a smaller stride.
---
## 2026-10-16 — Finer TTS delivery granularity (Drama-3 vocoder window) → `TTS_PREBUFFER_MS` 700 ms
### Changed
- **The SGLang Drama-3 server now emits audio in ~0.74 s windows instead of
~2.97 s bursts.** Two flags were added to the server launcher
(`/root/drama3/start-drama3.sh`, managed by `pm2` as `start-drama3`):
`--vocoder.factory.stream_followup_stride 16` and
`--vocoder.factory.stream_followup_stride_ramp "[10,12,16]"` — upstream
defaults were `64` and `(10,12,32)`.
- **`TTS_PREBUFFER_MS` default lowered `900` → `700`** (`.env`, `.env.example`,
[`src/config.rs`](src/config.rs)). 700 ms is deliberately just under one 0.743 s
window, so playback starts on the *first* burst rather than waiting for a
second one.
### Why
- Drama-3's streaming granularity is a **vocoder** setting, not an engine one:
[`Drama3VocoderFactoryArgs`](../drama3/sglang-omni/sglang_omni/models/fishaudio_drama3/config.py)
buffers `stream_followup_stride` codec frames before decoding and emitting, and
`frame_length = hop_length * 4 = 2048` samples (46.4 ms at 44.1 kHz). The
upstream `64` therefore means a 131 072-sample burst every ~2.7 s.
- Measured against the live endpoint (single, uncontended request, PCM stream):
| | burst | period | ratio | first audio |
|---|---|---|---|---|
| before (`stride` 64) | 131 072 samples / 2.97 s | 2.70–2.78 s | 1.08× | 0.96 s |
| after (`stride` 16) | 32 768 samples / 0.743 s | 0.69 s (σ ≈ 0.01 s) | 1.04× | 1.34 s |
- The finer window is what makes the small pre-buffer viable: the producer still
runs slightly faster than real time (1.04×), but it now tops the queue up every
0.69 s instead of every ~2.7 s, so arrival jitter is bounded by one window and
no longer forces a multi-second buffer.
- Prefix caching (RadixAttention) was evaluated and **rejected**: the client
already sends a constant prefix (`model` / `voice` / `references`), yet an A/B
on the endpoint showed no TTFB difference (ref 0.62–0.64 s, no-ref 0.52 s) —
that start-up is decode/vocoder, not prompt prefill.
### Notes
- Each window re-decodes `stream_overlap_tokens` (32) frames of context, so a
smaller stride costs more vocoder compute: 96 frames decoded per 64 emitted
becomes 48 per 16. The measured ratio moved 1.08× → 1.04×, still above real
time; `stride` 8 (0.371 s windows, 40 frames decoded per 8 emitted) is the next
step down and should only be tried with the ratio re-measured.
- The window lengths feed the vocoder's CUDA-graph capture set, so changing them
requires a server restart.
- `stream_stride` (first window) and `stream_followup_stride_ramp` (the windows
after it) were left near their defaults — only the steady-state value drives
the granularity of a long reply.
- (Superseded: the `TTS_PREBUFFER_MS` default is now `450`, targeting the ramp's
0.464 s *first* window — see the entry above.)
---
## 2026-10-16 — Resilient mixer resume + `TTS_PREBUFFER_MS` default 900 ms
### Changed
@@ -42,6 +162,8 @@ Entries are written in English and ordered newest-first.
- Default `900` is a deliberate latency-first choice: it keeps time-to-first-audio
low (~1.8 s) and accepts a rare short drop-out on very long replies. Raising
`TTS_PREBUFFER_MS` towards ~3000 trades that latency back for gaplessness.
(Superseded: the default is now `700`, once the server's vocoder window was
narrowed to ~0.74 s — see the entry above.)
### Notes