aboutsummaryrefslogtreecommitdiff
path: root/converter
diff options
context:
space:
mode:
authorhistoria <historiavg@proton.me>2026-08-21 00:10:35 -0400
committerhistoria <historiavg@proton.me>2026-08-21 00:10:35 -0400
commit0017f6b0421e549e9a2cdfadc104be64433724d3 (patch)
tree735065e3f70b9c052eef3dc5741385bc74fd8e99 /converter
parent38c8fdcba7ce54ad0ad76be9ef0748df1c55ebc1 (diff)
downloadtts-audiobook-generator-0017f6b0421e549e9a2cdfadc104be64433724d3.tar.gz
fix: remove unnecessary truncation check
Diffstat (limited to 'converter')
-rw-r--r--converter/tts.py62
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")