fix(tts): ban commas in LLM patter — the prosody stumble at its source (gh-#303) - #318
Merged
Merged
Conversation
…e (gh-#303) Commas were the single biggest source of unnatural pauses on air. A small model writes grammatically correct clause-heavy copy, and both engines honor every one of those commas with a stumble the ear reads as hesitation. gh-#292's comma-before-vocative ("hats, folks") is the same fault at its most audible. The rule ships with two deliberately different escape hatches: a real clause break becomes a SENTENCE, which gh-#116 then renders as true 0.6s silence on the Kokoro path; a run-together phrase simply loses the comma. Collapsing both into "always split" would trade a 0.2s stumble for a 0.6s gap and read worse for exactly the vocative case. Stated without commas on purpose — prompt text is style the model imitates. The issue's second half (have the model emit [pause:0.6s] itself) is deliberately NOT taken: CleanCopy already strips every bracketed run (\[[^\]]*\]) as a stage direction, and piper-tts speaks any tag that reaches it aloud. Sentence boundaries plus gh-#116 give the same explicit silence with the placement decided by us rather than a 3B model. 6 new specs; full suite green (2,547 passed).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #303. Relieves #292.
🎧 The fault
Commas are the single biggest source of unnatural pauses on air. A small model writes grammatically correct clause-heavy copy, and both engines honor every comma with a stumble the ear reads as hesitation. #292's comma-before-vocative (
hats, folks) is the same fault at its most audible.Overnight sample from the demo box — every one of these is comma-led:
🛠️ The fix
Four sentences added to the shared scaffold body in
LlmPromptBuilder.BuildSystemPrompt, so persona-voiced and persona-less copy are held to it equally.Two escape hatches, deliberately different:
[pause:0.6s]at sentence ends on the Kokoro pathhats folks)Collapsing both into "always split" would trade a 0.2s stumble for a 0.6s gap and read worse for exactly the vocative case. That's why the rule is two rules.
The rule states itself without commas, because prompt text is style the model imitates. A spec locks that in — it's the kind of intent a well-meaning future edit quietly undoes.
🚫 What this deliberately does NOT take
The issue's second half — "we should be using
[pause:0.6s]explicitly instead of relying on a side effect":CleanCopyalready strips every bracketed run (\[[^\]]*\]) as a stage direction, so a model-emitted tag never reaches an engine today. Taking this would need a deliberate carve-out in that filter.piper-ttsspeaks any tag aloud (TtsOptions.cs:29) — and the Piper hop is exactly what runs when Kokoro dies (tts: kokoro dies silently mid-render (likely OOM) — Piper fallback voice airs on demo #276). A carve-out would put "bracket pause zero point six s" on air on the fallback path.Sentence boundaries + #116 deliver the same explicit silence, with the placement decided by us instead of by a 3B model. Happy to revisit if you want author-controlled pauses in human-written copy (persona cards, templates) — that's a different, safer surface.
✅ Verification
dotnet buildclean, 0 warningsdotnet test GenWave.sln— 2,547 passed, 0 failed (Tts specs 329 → 335)Prosody itself is an ear check — worth listening to a few breaks after this ships.