first
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
import numpy as np
|
||||
|
||||
from speech_to_speech.pipeline.messages import TTSInput
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_TRUE_VALUES = {"1", "true", "yes", "on"}
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class DelayFillerConfig:
|
||||
enabled: bool
|
||||
threshold_s: float
|
||||
short_phrases: list[str]
|
||||
full_phrases: list[str]
|
||||
|
||||
|
||||
def _split_env_list(name: str) -> list[str]:
|
||||
raw = os.environ.get(name, "").strip()
|
||||
return [part.strip() for part in raw.split("|") if part.strip()]
|
||||
|
||||
|
||||
def _env_flag(name: str, *, default: bool) -> bool:
|
||||
raw = os.environ.get(name)
|
||||
if raw is None:
|
||||
return default
|
||||
return raw.strip().lower() in _TRUE_VALUES
|
||||
|
||||
|
||||
def load_delay_filler_config() -> DelayFillerConfig:
|
||||
short_phrases = _split_env_list("TTS_DELAY_FILLERS_SHORT_ES")
|
||||
full_phrases = _split_env_list("TTS_DELAY_FILLERS_FULL_ES")
|
||||
|
||||
# Backward compatibility with the old single-list variable.
|
||||
if not short_phrases and not full_phrases:
|
||||
full_phrases = _split_env_list("TTS_DELAY_FILLERS_ES")
|
||||
|
||||
enabled = _env_flag("TTS_DELAY_FILLERS_ENABLED", default=bool(short_phrases or full_phrases))
|
||||
threshold_ms_raw = os.environ.get("TTS_DELAY_FILLERS_THRESHOLD_MS", "1200").strip() or "1200"
|
||||
try:
|
||||
threshold_ms = max(0, int(threshold_ms_raw))
|
||||
except ValueError:
|
||||
logger.warning("Invalid TTS_DELAY_FILLERS_THRESHOLD_MS=%r; using 1200", threshold_ms_raw)
|
||||
threshold_ms = 1200
|
||||
return DelayFillerConfig(
|
||||
enabled=enabled and bool(short_phrases or full_phrases),
|
||||
threshold_s=threshold_ms / 1000.0,
|
||||
short_phrases=short_phrases,
|
||||
full_phrases=full_phrases,
|
||||
)
|
||||
|
||||
|
||||
def _chunk_to_bytes(chunk: Any) -> bytes:
|
||||
audio = getattr(chunk, "audio", chunk)
|
||||
if isinstance(audio, np.ndarray) or hasattr(audio, "tobytes"):
|
||||
return audio.tobytes()
|
||||
if isinstance(audio, bytes):
|
||||
return audio
|
||||
raise TypeError(f"Unsupported delay filler audio chunk type: {type(audio)!r}")
|
||||
|
||||
|
||||
def pregenerate_delay_filler_clips(tts_handler: Any, phrases: list[str]) -> list[bytes]:
|
||||
clips: list[bytes] = []
|
||||
for phrase in phrases:
|
||||
try:
|
||||
clip = b"".join(
|
||||
_chunk_to_bytes(chunk)
|
||||
for chunk in tts_handler.process(TTSInput(text=phrase, language_code="es"))
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("Failed to pregenerate TTS delay filler for phrase %r", phrase)
|
||||
continue
|
||||
if not clip:
|
||||
logger.warning("Discarding empty TTS delay filler for phrase %r", phrase)
|
||||
continue
|
||||
clips.append(clip)
|
||||
return clips
|
||||
Reference in New Issue
Block a user