mirror of
https://github.com/denizsafak/abogen.git
synced 2026-07-18 13:40:27 +02:00
feat: Add debug TTS functionality with EPUB generation, WAV artifact creation, and settings integration
This commit is contained in:
BIN
Binary file not shown.
@@ -0,0 +1,97 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from abogen.debug_tts_samples import DEBUG_TTS_SAMPLES, MARKER_PREFIX, MARKER_SUFFIX, iter_expected_codes
|
||||
from abogen.kokoro_text_normalization import HAS_NUM2WORDS, normalize_for_pipeline
|
||||
from abogen.normalization_settings import build_apostrophe_config
|
||||
from abogen.text_extractor import extract_from_path
|
||||
from abogen.web.app import create_app
|
||||
|
||||
|
||||
def test_debug_epub_contains_all_codes():
|
||||
epub_path = Path("tests/fixtures/abogen_debug_tts_samples.epub")
|
||||
assert epub_path.exists()
|
||||
|
||||
extraction = extract_from_path(epub_path)
|
||||
combined = extraction.combined_text or "\n\n".join((c.text or "") for c in extraction.chapters)
|
||||
|
||||
for code in iter_expected_codes():
|
||||
marker = f"{MARKER_PREFIX}{code}{MARKER_SUFFIX}"
|
||||
assert marker in combined
|
||||
|
||||
|
||||
def test_debug_samples_normalize_smoke():
|
||||
# Use the same defaults as the web UI.
|
||||
from abogen.web.routes.utils.settings import settings_defaults
|
||||
|
||||
settings = settings_defaults()
|
||||
apostrophe = build_apostrophe_config(settings=settings)
|
||||
runtime = dict(settings)
|
||||
|
||||
normalized = {
|
||||
sample.code: normalize_for_pipeline(sample.text, config=apostrophe, settings=runtime)
|
||||
for sample in DEBUG_TTS_SAMPLES
|
||||
}
|
||||
|
||||
# Contractions should expand under defaults.
|
||||
assert "it is" in normalized["APOS_001"].lower()
|
||||
|
||||
# Titles should expand.
|
||||
assert "doctor" in normalized["TITLE_001"].lower()
|
||||
|
||||
# Footnotes should be removed.
|
||||
assert "[1]" not in normalized["FOOT_001"]
|
||||
|
||||
# Terminal punctuation should be added.
|
||||
assert normalized["PUNC_001"].strip()[-1] in {".", "!", "?"}
|
||||
|
||||
if HAS_NUM2WORDS:
|
||||
# Currency and numbers should expand to words when num2words is available.
|
||||
assert "dollar" in normalized["CUR_001"].lower()
|
||||
assert "thousand" in normalized["NUM_001"].lower()
|
||||
|
||||
|
||||
def test_settings_debug_route_writes_manifest(tmp_path, monkeypatch):
|
||||
# Avoid pulling Kokoro models in tests: stub the pipeline.
|
||||
from abogen.web import debug_tts_runner as runner
|
||||
|
||||
class _Seg:
|
||||
def __init__(self, audio):
|
||||
self.audio = audio
|
||||
|
||||
class DummyPipeline:
|
||||
def __call__(self, text, **kwargs):
|
||||
# 100ms of audio per call, deterministic.
|
||||
audio = np.zeros(int(0.1 * runner.SAMPLE_RATE), dtype="float32")
|
||||
audio[::100] = 0.1
|
||||
yield _Seg(audio)
|
||||
|
||||
monkeypatch.setattr(runner, "_load_pipeline", lambda language, use_gpu: DummyPipeline())
|
||||
|
||||
app = create_app(
|
||||
{
|
||||
"TESTING": True,
|
||||
"SECRET_KEY": "test",
|
||||
"OUTPUT_FOLDER": str(tmp_path),
|
||||
"UPLOAD_FOLDER": str(tmp_path / "uploads"),
|
||||
}
|
||||
)
|
||||
|
||||
with app.test_client() as client:
|
||||
resp = client.post("/settings/debug/run")
|
||||
assert resp.status_code in {302, 303}
|
||||
location = resp.headers.get("Location", "")
|
||||
assert "debug_run_id=" in location
|
||||
|
||||
# Extract run id from query string.
|
||||
run_id = location.split("debug_run_id=")[1].split("&")[0].split("#")[0]
|
||||
manifest_path = tmp_path / "debug" / run_id / "manifest.json"
|
||||
assert manifest_path.exists()
|
||||
|
||||
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||||
filenames = {item["filename"] for item in manifest.get("artifacts", [])}
|
||||
assert "overall.wav" in filenames
|
||||
assert any(name.startswith("case_") and name.endswith(".wav") for name in filenames)
|
||||
Reference in New Issue
Block a user