speaker_helper.chunking module
Long-text chunking: cut a text into synthesis-sized pieces, LLM-assisted.
Module summary
Every neural TTS engine has a comfort zone, and a long text read in one call leaves it: Chatterbox audibly degrades past roughly half a minute of speech, and autoregressive models drift. The fix is old and simple — synthesise sentence groups and concatenate — and the only interesting question is where to cut. A cut between two sentences of the same thought is audible; a cut at a paragraph or topic boundary is not.
That placement is what the local LLM contributes here, under one invariant
that makes the feature safe: the model never touches the text. Sentences
are split locally (split_sentences(),
deterministic); the LLM is only asked how many consecutive sentences go in
each chunk, its answer is validated structurally (positive integers, summing
to the sentence count), and anything else — a chatty answer, a wrong sum, no
LLM at all — falls back to a deterministic greedy packer. Chunks always
concatenate back to exactly the sentences the splitter produced.
The model is resolved through best-engine-ai-helper (the suite rule) and
served by Ollama at temperature 0, like the pronunciation lexicon’s
respelling tier (speaker_helper.lexicon).
Usage example
>>> from speaker_helper.chunking import greedy_group_sizes
>>> greedy_group_sizes(["aa.", "bb.", "cc."], max_chars=7)
[2, 1]
- speaker_helper.chunking.DEFAULT_MAX_CHARS: int = 500
Default per-chunk budget, in characters. ~500 characters is ~30 seconds of speech — inside every backend’s comfort zone (Chatterbox degrades past that; Kyutai and Kokoro are comfortable well below it).
- speaker_helper.chunking.chunk_long_text(text, language, settings)[source]
Cut
textinto synthesis-sized chunks at the best boundaries known.Short texts pass through untouched (one chunk); long ones are split into sentence groups — grouped by the local LLM when available, greedily otherwise. Either way the chunks are exactly the local splitter’s sentences, in order: the LLM chooses boundaries, never words.
- Parameters:
text (str) – The text to synthesise (already respelled, when a lexicon applies).
language (str) – Language of the text — context for the LLM prompt only.
settings (Settings) – Its
chunkingmapping drives this:enabled(default True),llm(default True),max_chars(defaultDEFAULT_MAX_CHARS).
- Returns:
Chunks in reading order;
[text]when no split is needed (the common case, costing one length check).- Return type:
- speaker_helper.chunking.greedy_group_sizes(sentences, max_chars)[source]
Pack consecutive sentences into groups under
max_charseach.The deterministic fallback: no model, no surprise. A single sentence longer than the budget forms its own group — splitting inside a sentence is never an option.
- Parameters:
- Returns:
Group sizes, positive, summing to
len(sentences).- Return type:
Examples
>>> greedy_group_sizes(["aa.", "bb.", "cc."], max_chars=7) [2, 1]