133 lines
5.5 KiB
Python
133 lines
5.5 KiB
Python
import pytest
|
|
|
|
from app.normalize import mark_pause_delimiters, normalize_common
|
|
from app.segmentation import prepare_segments
|
|
from app.ssml import PAUSE_DELIM as P, build_ssml, strip_sentinels
|
|
|
|
DELIMS = "([{«“<)]}»>\"'`*_~"
|
|
|
|
|
|
# 5.1/5.2: разделительные символы удаляются, в паузообразующих позициях
|
|
# остаётся sentinel (НЕ запятая). Проверяем инварианты, а не литеральные запятые.
|
|
@pytest.mark.parametrize("text, expected_pauses", [
|
|
("скажи, что именно интересует (мир, техника, курсы валют), и я поищу.", 1),
|
|
('он сказал "сейчас проверю" и ушёл', 2),
|
|
('он сказал: "привет"', 0),
|
|
("мы сходим (надо)", 1),
|
|
('вот текст (важно)"', 1),
|
|
("он сказал **важно** слово", 2),
|
|
("слово *курсив* конец", 2),
|
|
("это _важно_ для дела", 2),
|
|
("список ~зачёркнут~ конец", 2),
|
|
("код `inline` конец", 2),
|
|
("тема «мир» конец", 2),
|
|
("сравнение x < 5 > 3 конец", 2),
|
|
("это {фигурные} и [квадратные] скобки", 4),
|
|
("слово 'вот это' конец", 2),
|
|
])
|
|
def test_delimiters_removed_pause_is_sentinel(text, expected_pauses):
|
|
result = mark_pause_delimiters(text)
|
|
for ch in DELIMS:
|
|
assert ch not in result, f"символ {ch!r} не удалён из {result!r}"
|
|
assert result.count(P) == expected_pauses
|
|
|
|
|
|
@pytest.mark.parametrize("text, expected", [
|
|
("мы сходим (надо)", f"мы сходим {P} надо"),
|
|
('вот текст (важно)"', f"вот текст {P} важно"),
|
|
("он сказал **важно** слово", f"он сказал {P} важно {P} слово"),
|
|
('он сказал: "привет"', "он сказал: привет"),
|
|
("погода в твоём городе?), и я поищу.", "погода в твоём городе?, и я поищу."),
|
|
])
|
|
def test_delimiter_pause_positions(text, expected):
|
|
assert mark_pause_delimiters(text) == expected
|
|
|
|
|
|
@pytest.mark.parametrize("text", [
|
|
"д'Катт и O'Neill пришли",
|
|
])
|
|
def test_apostrophes_inside_words_untouched(text):
|
|
assert mark_pause_delimiters(text) == text
|
|
|
|
|
|
@pytest.mark.parametrize("text", [
|
|
"текст (важно).",
|
|
"текст (важно), конец",
|
|
"текст [важно]!",
|
|
"(важно)",
|
|
])
|
|
def test_no_delimiter_chars_left(text):
|
|
result = mark_pause_delimiters(text)
|
|
for ch in DELIMS:
|
|
assert ch not in result
|
|
|
|
|
|
@pytest.mark.parametrize("text", [
|
|
"текст (важно).",
|
|
"текст (важно), конец",
|
|
"текст (важно)! и ещё (так) конец",
|
|
])
|
|
def test_no_dangling_artifacts(text):
|
|
# Sentinel не добавляет запятых; после удаления артефактов не остаётся.
|
|
result = mark_pause_delimiters(text)
|
|
assert ",," not in result
|
|
assert not result.lstrip().startswith(",")
|
|
assert ",." not in result
|
|
|
|
|
|
def test_line_boundaries():
|
|
text = "(в начале строки) текст\nтекст (в конце строки)\n(снова) конец"
|
|
result = mark_pause_delimiters(text)
|
|
for ch in "()":
|
|
assert ch not in result
|
|
assert P in result
|
|
clean = strip_sentinels(result)
|
|
assert "снова" in clean and "конец" in clean and "текст" in clean
|
|
|
|
|
|
def test_multiline_delimiters_processed_in_every_line():
|
|
text = "первая (строка) тут\nвторая «строка» тут"
|
|
result = mark_pause_delimiters(text)
|
|
assert "(" not in result and "«" not in result and "»" not in result
|
|
clean = strip_sentinels(result)
|
|
assert "строка" in clean and "тут" in clean
|
|
assert P in result
|
|
|
|
|
|
def test_english_text_same_rule():
|
|
segments = prepare_segments("The (parenthetical) works")
|
|
ssml = build_ssml(segments)
|
|
assert "<break" in ssml
|
|
assert "parenthetical" in ssml
|
|
assert "(" not in ssml and ")" not in ssml
|
|
|
|
|
|
def test_bug_example_pauses_before_and_after_parentheses():
|
|
text = ("скажи, что именно интересует (мир, техника, курсы валют, "
|
|
"погода в твоём городе?), и я поищу.")
|
|
segments = prepare_segments(text)
|
|
stripped = strip_sentinels(" ".join(s.text for s in segments))
|
|
assert "(" not in stripped and ")" not in stripped
|
|
assert ",," not in stripped
|
|
assert "интересует" in stripped and "город" in stripped
|
|
# Единственная паузная граница — от открывающей скобки перед «мир»;
|
|
# закрывающая скобка перед запятой границы не создаёт.
|
|
ssml = build_ssml(segments)
|
|
assert ssml.count("<break") == 1
|
|
assert P not in ssml
|
|
|
|
|
|
def test_pause_delim_becomes_break_in_ssml():
|
|
segments = prepare_segments("он сказал **важно** слово")
|
|
ssml = build_ssml(segments)
|
|
assert ssml.count("<break") == 2
|
|
assert P not in ssml
|
|
|
|
|
|
def test_underscore_not_verbalized_before_regional_normalization():
|
|
segments = prepare_segments("это _важно_ для дела")
|
|
joined = strip_sentinels(" ".join(s.text for s in segments))
|
|
assert "_" not in joined
|
|
assert "подчеркивание" not in joined.lower()
|
|
assert "подчёркивание" not in joined.lower()
|