diff options
| author | historia <historiavg@proton.me> | 2026-08-17 18:32:14 -0400 |
|---|---|---|
| committer | historia <historiavg@proton.me> | 2026-08-17 18:32:14 -0400 |
| commit | a30bd534151f757dad38763ae479fcd465d2ba0d (patch) | |
| tree | d2185a9e12abb13b76944c6d39b1bd64f5f70e24 /converter/chunking.py | |
| parent | 2bb8f721092fe2f4d6ae6e425181094c1f0da57a (diff) | |
| download | tts-audiobook-generator-a30bd534151f757dad38763ae479fcd465d2ba0d.tar.gz | |
refactor(converter): extract logic into package
Diffstat (limited to 'converter/chunking.py')
| -rw-r--r-- | converter/chunking.py | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/converter/chunking.py b/converter/chunking.py new file mode 100644 index 0000000..f649310 --- /dev/null +++ b/converter/chunking.py @@ -0,0 +1,59 @@ +"""Split extracted book text into TTS-sized chunks.""" + +import re +from typing import List + +from . import config + + +def split_into_chunks(text: str, max_words: int = config.CHUNK_SIZE_WORDS) -> List[str]: + """Split text into chunks of at most ``max_words`` words. + + Splits on sentence boundaries. Sentences longer than the limit are split + further at clause punctuation (which is kept attached for TTS prosody). + A single sentence with no clause punctuation longer than the limit is + kept intact as one oversized chunk. + """ + if not text.strip(): + return [] + + sentences = re.split(r"(?<=[.!?])\s+", text) + chunks = [] + current_chunk = "" + current_words = 0 + + for sentence in sentences: + sentence_words = len(sentence.split()) + + if sentence_words > max_words: + if current_chunk: + chunks.append(current_chunk.strip()) + current_chunk = "" + current_words = 0 + + # Split long sentences at clause boundaries, keeping punctuation. + parts = re.split(r"(?<=[,;:])\s*", sentence) + for part in parts: + part_words = len(part.split()) + if current_words + part_words <= max_words: + current_chunk += part + " " + current_words += part_words + else: + if current_chunk: + chunks.append(current_chunk.strip()) + current_chunk = part + " " + current_words = part_words + else: + if current_words + sentence_words <= max_words: + current_chunk += sentence + " " + current_words += sentence_words + else: + if current_chunk: + chunks.append(current_chunk.strip()) + current_chunk = sentence + " " + current_words = sentence_words + + if current_chunk.strip(): + chunks.append(current_chunk.strip()) + + return [chunk for chunk in chunks if chunk.strip()] |
