From 875033ff00e9132d0fcbaebe114e5cea0deb5d6c Mon Sep 17 00:00:00 2001 From: Vuong Hoang Date: Tue, 2 Jun 2026 00:58:57 -0700 Subject: [PATCH] feat(chatterbox-fast): add seed for reproducible one-shot output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TTSRequest gains `seed` (0=random); seeded once per request under the lock via torch.manual_seed + cuda.manual_seed_all. One-shot output is then byte-reproducible for a fixed seed+params (verified: seed=42 -> identical sha256 across runs). Streaming stays non-reproducible by design — adaptive-chunk boundaries depend on live-measured RTF. Needed for the asset-engine catalog reproducibility contract (parity with the chatterbox sibling, which exposes seed). --- stacks/chatterbox-fast/app.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/stacks/chatterbox-fast/app.py b/stacks/chatterbox-fast/app.py index 758456b..7b4e476 100644 --- a/stacks/chatterbox-fast/app.py +++ b/stacks/chatterbox-fast/app.py @@ -206,6 +206,7 @@ class TTSRequest(BaseModel): top_p: float = 0.95 top_k: int = 1000 repetition_penalty: float = 1.2 + seed: int = 0 # 0 ⇒ random; a fixed seed repeats a one-shot take (see note below) # Scheduler overrides (None ⇒ ChunkConfig defaults). margin: float | None = Field(default=None) margin_first: float | None = Field(default=None) @@ -279,6 +280,13 @@ def tts(req: TTSRequest) -> StreamingResponse: # workload); concurrent callers queue rather than corrupt conditionals. with engine.lock: engine._prepare(voice_path, exaggeration=req.exaggeration) + # Seed once per request (under the lock). One-shot is then reproducible + # for a fixed seed + params; streaming is NOT — adaptive-chunk boundaries + # depend on live-measured RTF (wall-clock), so chunk splits vary run to run. + if req.seed: + torch.manual_seed(req.seed) + if DEVICE.startswith("cuda"): + torch.cuda.manual_seed_all(req.seed) t_req = time.perf_counter() first_audio_ms: float | None = None