diff options
Diffstat (limited to 'app/converter/tts.py')
| -rw-r--r-- | app/converter/tts.py | 61 |
1 files changed, 13 insertions, 48 deletions
diff --git a/app/converter/tts.py b/app/converter/tts.py index 6ccef56..842cc0c 100644 --- a/app/converter/tts.py +++ b/app/converter/tts.py @@ -278,11 +278,6 @@ def whisper_backend_available() -> Optional[str]: return None -# 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 - - class _BaseTTSClient: """Shared chunk retry logic, heartbeat, and chunk file bookkeeping.""" @@ -327,15 +322,10 @@ class _BaseTTSClient: return None @contextlib.contextmanager - def _chunk_heartbeat(self, chunk_num: int, label: Optional[str] = None): - """Print a periodic "still working" message while a request generates. - - ``label`` overrides the default "Chunk {chunk_num}" subject, for - backends that send one request per chapter without client-side - chunking (the audio.cpp default) where "chunk" would be misleading. - """ + def _chunk_heartbeat(self, chunk_num: int): + """Print a periodic "still working" message while a request generates.""" stop = threading.Event() - subject = label if label is not None else f"Chunk {chunk_num}" + subject = f"Chunk {chunk_num}" def _beat(): start = time.time() @@ -796,20 +786,14 @@ class AudioCppTTSClient(_BaseTTSClient): the request's "options" object, which is the server's generic pass-through for per-model controls. - Chunking: the server does its own long-form text chunking for every - family (its ``text_chunk_size`` option, with a per-family default), so - by default each chapter is sent as a single request and the audio - comes back already stitched. With ``chunk_text=True`` (the --chunk CLI - flag), text is instead split client-side into CHUNK_SIZE-word - sub-requests, which may needlessly double-chunk — the warning is - printed by the CLI. - - Each response is a complete WAV file, so sub-request audio is - concatenated with the same lossless path used for the Qwen client. + Chunking: text is split client-side into sub-requests of at most + config.CHUNK_SIZE words each; each sub-request returns a complete + WAV file and the parts are concatenated with the same lossless path + used for the Qwen client. """ def __init__(self, voice: Optional[str] = None, language: Optional[str] = None, - api_url: Optional[str] = None, chunk_text: bool = False, + api_url: Optional[str] = None, model_id: Optional[str] = None, instructions: Optional[str] = None, request_options: Optional[Dict[str, str]] = None): @@ -844,10 +828,6 @@ class AudioCppTTSClient(_BaseTTSClient): # speakers gets its voice from the instruction alone (no voice field). self.design_mode = False self.instruction_voice = False - # When False (default), each chapter is sent as one request and the - # server does its own long-form chunking (text_chunk_size); when True, - # text is split client-side into CHUNK_SIZE-word sub-requests first. - self.chunk_text = bool(chunk_text) # Family and task of the selected model entry and the family's request # profile; all are resolved from GET /v1/models during _connect. self.family = "" @@ -1217,11 +1197,6 @@ class AudioCppTTSClient(_BaseTTSClient): url, data=json.dumps(payload).encode("utf-8"), headers={"Content-Type": "application/json"}, method="POST") timeout = config.API_TIMEOUT - if not self.chunk_text: - # Estimated audio duration at 150 wpm, doubled plus a minute of - # slack, bounded below by the configured per-request timeout. - estimated_seconds = 60.0 * len(text.split()) / _ESTIMATED_WORDS_PER_MINUTE - timeout = max(timeout, int(estimated_seconds * 2) + 60) try: with urllib.request.urlopen(request, timeout=timeout) as response: wav = response.read() @@ -1259,28 +1234,18 @@ class AudioCppTTSClient(_BaseTTSClient): def generate_chunk(self, text: str, chunk_num: int) -> Optional[str]: """Generate one audio chunk; returns its path in the chunks folder. - By default the whole text goes out as a single request and the - server does its own long-form chunking (see the class docstring). - With ``chunk_text=True`` (--chunk), the text is split into - sub-requests of at most ``config.CHUNK_SIZE`` words each; each - sub-request returns a complete WAV file and the parts are - concatenated into one chunk file. + The text is split into sub-requests of at most ``config.CHUNK_SIZE`` + words each; each sub-request returns a complete WAV file and the + parts are concatenated into one chunk file. """ try: - if self.chunk_text: - sub_texts = split_into_chunks(text, max_words=config.CHUNK_SIZE) - elif text.strip(): - sub_texts = [text] - else: - sub_texts = [] + sub_texts = split_into_chunks(text, max_words=config.CHUNK_SIZE) if not sub_texts: raise RuntimeError("No text to synthesize") output_path: Optional[Path] = None with tempfile.TemporaryDirectory(prefix="tts_parts_") as parts_dir, \ - self._chunk_heartbeat( - chunk_num, - label=None if self.chunk_text else "Request"): + self._chunk_heartbeat(chunk_num): part_paths = [] for sub_num, sub_text in enumerate(sub_texts, 1): wav = self._request_wav_with_retry( |
