good
This commit is contained in:
+122
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user