import numpy as np import torch from app.segmentation import Segment from app.synthesis import SynthesisEngine, ModelEntry class FakeModel: def __init__(self, name, calls): self.name = name self.calls = calls self.speakers = ["spk1", "spk2"] def apply_tts(self, *, text=None, ssml_text=None, speaker, sample_rate, put_accent, put_yo): self.calls.append({ "name": self.name, "speaker": speaker, "text": text, "ssml_text": ssml_text, "put_accent": put_accent, }) return torch.zeros(10) class FakeTts: def __init__(self, name, calls, put_accent=True): self.sample_rate = 24000 self.put_accent = put_accent self.put_yo = True self.tts_model = FakeModel(name, calls) def make_engine(use_ssml=True, put_accent=True): calls: list[dict] = [] engine = SynthesisEngine( models=[ ModelEntry(model_id="ru_model", tts=FakeTts("ru", calls, put_accent), languages=["ru"]), ModelEntry(model_id="en_model", tts=FakeTts("en", calls, put_accent), languages=["en"]), ], sample_rate=24000, use_ssml=use_ssml, ) return engine, calls def test_single_speaker_for_all_segments(): engine, calls = make_engine(use_ssml=False) segments = [Segment(text="Озон", lang="ru"), Segment(text="Пайтон", lang="ru")] pcm = engine.synthesize_segments(segments, "baya", "ru") assert pcm assert len(calls) == 2 assert all(c["name"] == "ru" and c["speaker"] == "baya" for c in calls) def test_en_lang_selects_en_model(): engine, calls = make_engine(use_ssml=False) segments = [Segment(text="hello", lang="en")] engine.synthesize_segments(segments, "en_0", "en") assert calls[0]["name"] == "en" assert calls[0]["text"] == "hello" def test_legacy_path_uses_text_not_ssml(): engine, calls = make_engine(use_ssml=False) engine.synthesize_segments([Segment(text="привет", lang="ru")], "baya", "ru") assert calls[0]["text"] == "привет" assert calls[0]["ssml_text"] is None def test_no_silence_padding_between_segments(): engine, calls = make_engine(use_ssml=False) segments = [Segment(text="а", lang="ru"), Segment(text="б", lang="ru")] pcm = engine.synthesize_segments(segments, "baya", "ru") expected = (np.zeros(10) * 32767).astype(np.int16) assert len(pcm) == 2 * len(expected.tobytes()) # --- ssml_text path (task 3) --- def test_ssml_path_passes_ssml_text(): engine, calls = make_engine() segments = [Segment(text="привет", lang="ru"), Segment(text="мир", lang="ru")] pcm = engine.synthesize_segments(segments, "baya", "ru") assert pcm assert len(calls) == 1 # один чанк на абзац c = calls[0] assert c["text"] is None assert c["ssml_text"].startswith("") assert "привет" in c["ssml_text"] assert "мир" in c["ssml_text"] def test_ssml_path_single_call_per_chunk(): engine, calls = make_engine() # Два разных абзаца -> два

-> (в пределах лимита) один документ/один вызов. segments = [ Segment(text="первый", lang="ru", para=0), Segment(text="второй", lang="ru", para=1), ] engine.synthesize_segments(segments, "baya", "ru") assert len(calls) == 1 assert "

" in calls[0]["ssml_text"] def test_ssml_prosody_rate_and_pitch_passed_to_builder(): engine, calls = make_engine() engine.synthesize_segments( [Segment(text="привет", lang="ru")], "baya", "ru", rate="slow", pitch="high", ) ssml = calls[0]["ssml_text"] assert '