diff options
| author | historia <historiavg@proton.me> | 2026-08-21 00:10:35 -0400 |
|---|---|---|
| committer | historia <historiavg@proton.me> | 2026-08-21 00:10:35 -0400 |
| commit | 0017f6b0421e549e9a2cdfadc104be64433724d3 (patch) | |
| tree | 735065e3f70b9c052eef3dc5741385bc74fd8e99 /converter | |
| parent | 38c8fdcba7ce54ad0ad76be9ef0748df1c55ebc1 (diff) | |
| download | tts-audiobook-generator-0017f6b0421e549e9a2cdfadc104be64433724d3.tar.gz | |
fix: remove unnecessary truncation check
Diffstat (limited to 'converter')
| -rw-r--r-- | converter/tts.py | 62 |
1 files changed, 3 insertions, 59 deletions
diff --git a/converter/tts.py b/converter/tts.py index 0d867a2..0803bb9 100644 --- a/converter/tts.py +++ b/converter/tts.py @@ -29,7 +29,7 @@ from pathlib import Path from typing import Any, Dict, List, Optional, Tuple from . import config -from .audio import concat_audio_files, probe_duration_ms +from .audio import concat_audio_files from .chunking import split_into_chunks logger = logging.getLogger(__name__) @@ -267,56 +267,9 @@ def whisper_backend_available() -> Optional[str]: return None -# Duration sanity check: a response whose audio is far shorter than its -# word count implies is treated as silently truncated, fails the request, -# and goes through the normal retry logic. 150 wpm is a typical spoken -# pace; the ratio is set low (0.5) so only gross truncation trips it. +# 150 wpm is a typical spoken pace; used only to size the HTTP request +# timeout for long audio.cpp generations (not as a correctness check). _ESTIMATED_WORDS_PER_MINUTE = 150 -_MIN_AUDIO_DURATION_RATIO = 0.5 -_MIN_WORDS_FOR_DURATION_CHECK = 10 - - -def check_for_truncation(text: str, actual_seconds: Optional[float], label: str) -> None: - """Raise RuntimeError when audio is far shorter than its text implies. - - Both backends silently truncate audio when a single generation hits an - internal cap (no error is reported to the client), so grossly short - audio must be detected client-side: failing the request lets the retry - logic re-run it, and persistent failures surface as failed chunks - instead of a "successful" run with missing audio. ``actual_seconds`` - is None when the duration could not be determined, in which case the - check is skipped. Requests shorter than - ``_MIN_WORDS_FOR_DURATION_CHECK`` words are not checked (their - duration estimates are too noisy). - """ - words = len(text.split()) - if actual_seconds is None or words < _MIN_WORDS_FOR_DURATION_CHECK: - return - expected_seconds = 60.0 * words / _ESTIMATED_WORDS_PER_MINUTE - if actual_seconds < expected_seconds * _MIN_AUDIO_DURATION_RATIO: - raise RuntimeError( - f"{label}: audio is far shorter than the text implies " - f"({actual_seconds:.1f}s of audio for {words} words, expected at " - f"least {expected_seconds * _MIN_AUDIO_DURATION_RATIO:.0f}s); " - "the TTS server likely truncated the generation silently" - ) - - -def _audio_duration_seconds(path: Path) -> Optional[float]: - """Return an audio file's duration in seconds, or None when unknown.""" - try: - with wave.open(str(path), "rb") as wav_file: - framerate = wav_file.getframerate() - if framerate > 0: - return wav_file.getnframes() / float(framerate) - except (wave.Error, EOFError, OSError): - pass - if shutil.which("ffprobe") is None: - return None - milliseconds = probe_duration_ms(path) - if milliseconds <= 0: - return None - return milliseconds / 1000.0 class _BaseTTSClient: @@ -596,9 +549,6 @@ class QwenTTSClient(_BaseTTSClient): destination = Path(parts_dir) / f"part_{sub_num:02d}{source.suffix or '.wav'}" shutil.copy2(source, destination) - check_for_truncation( - text, _audio_duration_seconds(destination), - f"Chunk {chunk_num} sub-request {sub_num}/{sub_total}") return destination # ------------------------------------------------------------------ @@ -776,9 +726,6 @@ class FasterTTSClient(_BaseTTSClient): for sub_num, sub_text in enumerate(sub_chunks, 1): pcm = self._request_pcm_with_retry( sub_text, chunk_num, sub_num, len(sub_chunks)) - check_for_truncation( - sub_text, len(pcm) / (2 * SAMPLE_RATE), - f"Chunk {chunk_num} sub-chunk {sub_num}/{len(sub_chunks)}") pcm_parts.append(pcm) output_path = self._chunk_path(chunk_num, ".wav") @@ -1185,9 +1132,6 @@ class AudioCppTTSClient(_BaseTTSClient): sub_text, chunk_num, sub_num, len(sub_texts)) destination = Path(parts_dir) / f"part_{sub_num:02d}.wav" destination.write_bytes(wav) - check_for_truncation( - sub_text, _audio_duration_seconds(destination), - f"Chunk {chunk_num} sub-request {sub_num}/{len(sub_texts)}") part_paths.append(destination) if len(part_paths) == 1: output_path = self._chunk_path(chunk_num, ".wav") |
