mirror of
https://github.com/denizsafak/abogen.git
synced 2026-07-22 07:10:28 +02:00
refactor(webui): rename preview.py to synthesize.py and remove dead code
- Rename abogen/webui/routes/utils/preview.py → synthesize.py The file contains the core TTS synthesis pipeline (generate_preview_audio, synthesize_preview), not just preview logic. Name now matches responsibility. - Remove dead code from voice.py: get_preview_pipeline(), synthesize_audio_from_normalized(), _preview_pipeline_lock, _preview_pipelines, and unused imports (threading, numpy, create_pipeline, get_new_voice, _select_device, _to_float32, SAMPLE_RATE, SPLIT_PATTERN). These were never called — identical logic lives in synthesize.py. - Update imports in api.py, voices.py, and test_preview_applies_manual_overrides.py - 7 new tests in test_synthesize_module.py enforce file naming and import rules - 7 tests in test_domain_imports.py updated for renamed module
This commit is contained in:
@@ -25,7 +25,7 @@ from abogen.voice_profiles import (
|
||||
normalize_profile_entry,
|
||||
)
|
||||
from abogen.webui.routes.utils.common import split_profile_spec
|
||||
from abogen.webui.routes.utils.preview import synthesize_preview, generate_preview_audio
|
||||
from abogen.webui.routes.utils.synthesize import synthesize_preview, generate_preview_audio
|
||||
from abogen.webui.routes.utils.voice import formula_from_profile
|
||||
from abogen.normalization_settings import (
|
||||
build_llm_configuration,
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import threading
|
||||
from typing import Any, Dict, Iterable, List, Mapping, Optional, Tuple, cast
|
||||
import numpy as np
|
||||
|
||||
from abogen.speaker_configs import slugify_label
|
||||
from abogen.speaker_analysis import analyze_speakers
|
||||
@@ -10,7 +8,7 @@ from abogen.voice_profiles import (
|
||||
load_profiles,
|
||||
serialize_profiles,
|
||||
)
|
||||
from abogen.voice_formulas import get_new_voice, parse_formula_terms
|
||||
from abogen.voice_formulas import parse_formula_terms
|
||||
from abogen.constants import (
|
||||
LANGUAGE_DESCRIPTIONS,
|
||||
SUBTITLE_FORMATS,
|
||||
@@ -20,14 +18,7 @@ from abogen.constants import (
|
||||
)
|
||||
from abogen.tts_plugin.utils import get_voices
|
||||
from abogen.speaker_configs import list_configs
|
||||
from abogen.tts_plugin.utils import create_pipeline
|
||||
from abogen.domain.device import select_device as _select_device
|
||||
from abogen.domain.audio_helpers import to_float32 as _to_float32, SAMPLE_RATE
|
||||
|
||||
SPLIT_PATTERN = r"\n+"
|
||||
|
||||
_preview_pipeline_lock = threading.RLock()
|
||||
_preview_pipelines: Dict[Tuple[str, str], Any] = {}
|
||||
|
||||
def build_narrator_roster(
|
||||
voice: str,
|
||||
@@ -736,76 +727,3 @@ def pairs_to_formula(pairs: Iterable[Tuple[str, float]]) -> Optional[str]:
|
||||
|
||||
def profiles_payload() -> Dict[str, Any]:
|
||||
return {"profiles": serialize_profiles()}
|
||||
|
||||
|
||||
def get_preview_pipeline(language: str, device: str):
|
||||
key = (language, device)
|
||||
with _preview_pipeline_lock:
|
||||
pipeline = _preview_pipelines.get(key)
|
||||
if pipeline is not None:
|
||||
return pipeline
|
||||
pipeline = create_pipeline("kokoro", lang_code=language, device=device)
|
||||
_preview_pipelines[key] = pipeline
|
||||
return pipeline
|
||||
|
||||
|
||||
def synthesize_audio_from_normalized(
|
||||
*,
|
||||
normalized_text: str,
|
||||
voice_spec: str,
|
||||
language: str,
|
||||
speed: float,
|
||||
use_gpu: bool,
|
||||
max_seconds: float,
|
||||
) -> np.ndarray:
|
||||
if not normalized_text.strip():
|
||||
raise ValueError("Preview text is required")
|
||||
|
||||
device = "cpu"
|
||||
if use_gpu:
|
||||
try:
|
||||
device = _select_device()
|
||||
except Exception:
|
||||
device = "cpu"
|
||||
use_gpu = False
|
||||
|
||||
pipeline = get_preview_pipeline(language, device)
|
||||
if pipeline is None:
|
||||
raise RuntimeError("Preview pipeline is unavailable")
|
||||
|
||||
voice_choice: Any = voice_spec
|
||||
if voice_spec and "*" in voice_spec:
|
||||
voice_choice = get_new_voice(pipeline, voice_spec, use_gpu)
|
||||
|
||||
segments = pipeline(
|
||||
normalized_text,
|
||||
voice=voice_choice,
|
||||
speed=speed,
|
||||
split_pattern=SPLIT_PATTERN,
|
||||
)
|
||||
|
||||
audio_chunks: List[np.ndarray] = []
|
||||
accumulated = 0
|
||||
max_samples = int(max(1.0, max_seconds) * SAMPLE_RATE)
|
||||
|
||||
for segment in segments:
|
||||
graphemes = getattr(segment, "graphemes", "").strip()
|
||||
if not graphemes:
|
||||
continue
|
||||
audio = _to_float32(getattr(segment, "audio", None))
|
||||
if audio.size == 0:
|
||||
continue
|
||||
remaining = max_samples - accumulated
|
||||
if remaining <= 0:
|
||||
break
|
||||
if audio.shape[0] > remaining:
|
||||
audio = audio[:remaining]
|
||||
audio_chunks.append(audio)
|
||||
accumulated += audio.shape[0]
|
||||
if accumulated >= max_samples:
|
||||
break
|
||||
|
||||
if not audio_chunks:
|
||||
raise RuntimeError("Preview could not be generated")
|
||||
|
||||
return np.concatenate(audio_chunks)
|
||||
|
||||
@@ -9,7 +9,7 @@ from abogen.webui.routes.utils.voice import (
|
||||
parse_voice_formula,
|
||||
)
|
||||
from abogen.webui.routes.utils.settings import load_settings, coerce_bool
|
||||
from abogen.webui.routes.utils.preview import synthesize_preview
|
||||
from abogen.webui.routes.utils.synthesize import synthesize_preview
|
||||
from abogen.speaker_configs import (
|
||||
list_configs,
|
||||
get_config,
|
||||
|
||||
Reference in New Issue
Block a user