diff options
| author | historia <historiavg@proton.me> | 2026-08-20 18:06:22 -0400 |
|---|---|---|
| committer | historia <historiavg@proton.me> | 2026-08-20 18:06:22 -0400 |
| commit | 5ca77f86b70718b4ef1a07299efbd6431268d546 (patch) | |
| tree | e50a439ea7a92bd628f78240fdbc2d4093df6928 /converter/converter.py | |
| parent | b873844f7eb681119542661ef588c5b452f88763 (diff) | |
| download | tts-audiobook-generator-5ca77f86b70718b4ef1a07299efbd6431268d546.tar.gz | |
fix: do not chunk with audio.cpp backend (double chunking)
Diffstat (limited to 'converter/converter.py')
| -rw-r--r-- | converter/converter.py | 40 |
1 files changed, 36 insertions, 4 deletions
diff --git a/converter/converter.py b/converter/converter.py index 6994a31..f1064f1 100644 --- a/converter/converter.py +++ b/converter/converter.py @@ -134,7 +134,8 @@ class AudiobookConverter: voice_clone_ref_text: Optional[str] = None, skip_transcription: bool = False, speed: float = 1.0, single_file: bool = False, output_format: str = config.AUDIO_FORMAT, language: Optional[str] = None, backend: str = BACKEND_GRADIO, - voice: Optional[str] = None, debug: bool = False): + voice: Optional[str] = None, debug: bool = False, + chunk: bool = False): if speed <= 0: raise ValueError(f"Speed must be a positive number, got {speed}") if output_format not in AUDIO_FORMATS: @@ -154,6 +155,12 @@ class AudiobookConverter: self.backend = backend self.voice = voice self.debug = bool(debug) + # Client-side chunking: the gradio and faster backends always chunk + # (their servers do one generation per request and silently truncate + # long text). The audio.cpp server chunks long text itself, so it + # defaults to one request per chapter; --chunk forces client-side + # chunking on top (possible needless double-chunking). + self.client_chunks = bool(chunk) or backend != BACKEND_AUDIOCPP self._validate_configuration() if backend == BACKEND_FASTER: # The faster backend always voice-clones using a reference voice @@ -162,7 +169,8 @@ class AudiobookConverter: elif backend == BACKEND_AUDIOCPP: # Speaker mode (no voice) uses a built-in CustomVoice speaker; # an explicit voice selects a server-side preset (cloning). - self.tts = AudioCppTTSClient(voice=voice, language=self.language) + self.tts = AudioCppTTSClient(voice=voice, language=self.language, + chunk_text=self.client_chunks) else: self.tts = QwenTTSClient( voice_mode=voice_mode, @@ -426,6 +434,18 @@ class AudiobookConverter: logger.info("Chunk processing completed: %d/%d chunks", successful_chunks, total_chunks) return results + def _chapter_chunks(self, text: str) -> List[str]: + """Split chapter text into TTS requests. + + Client-side chunking splits into CHUNK_SIZE-word chunks (gradio and + faster always; audio.cpp only with --chunk). Otherwise (audio.cpp + default) the whole text is one request and the server does its own + long-form chunking. + """ + if self.client_chunks: + return chunking.split_into_chunks(text) + return [text] if text.strip() else [] + def _convert_text(self, text: str, output_path: Path, start_time: float, speed: Optional[float] = None, output_format: Optional[str] = None, @@ -452,7 +472,7 @@ class AudiobookConverter: logger.info("Extracted %d characters (%d words)", len(text), len(text.split())) - chunks = chunking.split_into_chunks(text) + chunks = self._chapter_chunks(text) total_chunks = len(chunks) if total_chunks == 0: logger.error("No chunks created") @@ -460,7 +480,13 @@ class AudiobookConverter: chunk_sizes = [len(chunk.split()) for chunk in chunks] avg_chunk_size = sum(chunk_sizes) / len(chunk_sizes) - logger.info("Split into %d chunks (avg %.0f words per chunk)", total_chunks, avg_chunk_size) + if len(chunks) == 1: + logger.info("Sending the whole text as one request (%d words; " + "the server chunks long text itself)", + chunk_sizes[0]) + else: + logger.info("Split into %d chunks (avg %.0f words per chunk)", + total_chunks, avg_chunk_size) backend_labels = { BACKEND_FASTER: "faster TTS API", BACKEND_AUDIOCPP: "audio.cpp server", @@ -526,6 +552,12 @@ class AudiobookConverter: else: print("Backend: audio.cpp (custom voice, built-in speaker)") print(f"Speaker: {config.SPEAKER}") + if self.client_chunks: + print("Chunking: client-side (--chunk; the server also chunks " + "long text itself, so this may double-chunk)") + else: + print("Chunking: server-side (one request per chapter; " + "--chunk forces client-side chunking)") print(f"Language: {self.language}") else: api_url = (config.CLONE_API_URL if self.voice_mode == VOICE_MODE_CLONE |
