Files
agr-assistent/tests/test_speech_text.py
T
mrleo1nidandClaude Opus 5 fec52dd1c2 Этап 2: озвучка ответов через Silero
- Потоковая озвучка: ответ режется на фразы, синтез и воспроизведение в отдельных потоках
- Подготовка текста: числа словами, без markdown, ссылок и блоков кода
- Модель Silero скачивается в LOCALAPPDATA и прогревается при старте
- Состояние «говорю», переключатель озвучки в трее, «Стоп» прерывает речь
- Тесты нарезки текста и оркестратора озвучки

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 03:20:07 +03:00

51 lines
1.7 KiB
Python

from agr_assistent.tts.text import SpeechTextStream, normalize_for_speech, split_long_text
def _feed_all(chunks: list[str]) -> list[str]:
stream = SpeechTextStream()
result = []
for chunk in chunks:
result.extend(stream.feed(chunk))
return result + stream.flush()
def test_sentences_are_emitted_as_soon_as_complete() -> None:
stream = SpeechTextStream()
assert stream.feed("Привет! Как ") == ["Привет!"]
assert stream.feed("дела? Хоро") == ["Как дела?"]
assert stream.flush() == ["Хоро"]
def test_decimal_numbers_and_list_markers_do_not_split() -> None:
assert _feed_all(["Будет 3.", "5 градуса.\n", "1. Первый пункт"]) == [
"Будет три целых пять десятых градуса.",
"Первый пункт",
]
def test_code_blocks_are_skipped() -> None:
chunks = ["Пример:\n``", "`python\nprint('Привет')\n", "```\nГотово."]
assert _feed_all(chunks) == ["Пример:", "Готово."]
def test_normalize_removes_markdown_links_and_latin() -> None:
text = "**Важно**: смотри [документацию](https://x.io) и https://y.io, Python тоже 😀"
assert normalize_for_speech(text) == "Важно: смотри документацию и ссылка, тоже"
def test_text_without_cyrillic_is_not_spoken() -> None:
assert normalize_for_speech("Hello, world! 👋") == ""
assert _feed_all(["Hello world.\n"]) == []
def test_long_text_is_split_on_commas_and_spaces() -> None:
text = ", ".join(["слово"] * 100)
parts = split_long_text(text, limit=50)
assert all(len(part) <= 50 for part in parts)
assert " ".join(parts).replace(" ,", ",") == text