Files
talkscore-asr/tests/test_view.py
T
Vladimir BryzgalovandClaude Opus 5 456e86ef9a Страница объясняет, почему нет разбивки на предложения
Результаты, обработанные до 0.14.0, не содержат массива sentences. Пустой
блок разметки выглядел бы поломкой страницы - теперь он говорит, что нужно
отправить запись заново.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-17 14:03:46 +05:00

83 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Страница разбора: по ней смотрят, чья ошибка - распознавания или разметки."""
import json
import re
from app.view import render_job
def job(**over):
base = {
"job_id": "abc12345", "filename": "call.mp3", "duration_sec": 120.0,
"turns": [
{"speaker": 0, "start": 0.0, "end": 4.0, "text": "Первая реплика.",
"acoustics": {"loudness_db": -18.0}},
{"speaker": 0, "start": 30.0, "end": 34.0, "text": "Вторая <реплика>.",
"acoustics": {}, "recovered": True},
],
"sentences": [
{"n": 1, "text": "Первая реплика.", "start": 0.0, "loudness_db": -18.0, "turn": 0},
{"n": 2, "text": "Вторая <реплика>.", "start": 30.0, "loudness_db": None, "turn": 1},
],
"stats": {"turns_count": 2, "speech_sec": 8.0, "diarized": False},
"timing": {"diarization_sec": 1.0, "asr_sec": 2.0},
}
base.update(over)
return base
class TestPage:
def test_is_self_contained(self):
"""Страница открывается локально: внешних файлов и запросов быть не должно."""
page = render_job(job())
assert "<script" in page and "<style" in page
assert "http://" not in page and "https://" not in page
def test_shows_text_of_turns(self):
page = render_job(job())
assert "Первая реплика." in page
def test_escapes_text(self):
"""Расшифровка - это данные, а не разметка."""
page = render_job(job())
assert "Вторая &lt;реплика&gt;." in page
assert "<реплика>" not in page
def test_marks_gap_between_turns(self):
page = render_job(job())
assert "пропуск" in page and "00:04" in page
def test_marks_recovered_turn(self):
assert "второй проход" in render_job(job())
def test_shows_mode(self):
assert "детектор речи" in render_job(job())
assert "диаризация" in render_job(job(stats={"diarized": True, "turns_count": 2}))
def test_sentences_go_into_script(self):
"""По ним страница собирает диалог из вставленной строки ролей."""
page = render_job(job())
payload = re.search(r"const S = (\[.*?\]);", page, re.S).group(1)
assert len(json.loads(payload)) == 2
def test_closing_tag_in_text_cannot_break_out(self):
"""Строка </script> в расшифровке закрыла бы тег и сломала страницу."""
evil = 'а тут </script><img src=x onerror=alert(1)>'
page = render_job(job(
turns=[{"speaker": 0, "start": 0.0, "end": 1.0, "text": evil, "acoustics": {}}],
sentences=[{"n": 1, "text": evil, "start": 0.0, "loudness_db": None, "turn": 0}]))
assert "</script><img" not in page
assert page.count("</script>") == 1
def test_survives_empty_result(self):
page = render_job({"job_id": "x", "turns": [], "sentences": [], "duration_sec": 0})
assert "реплик нет" in page
def test_old_result_explains_missing_sentences(self):
"""Результаты до 0.14.0 не содержат предложений - пустой блок выглядел бы поломкой."""
page = render_job({"job_id": "x", "turns": [], "sentences": [], "duration_sec": 10})
assert "старше 0.14.0" in page
assert "<textarea" not in page
def test_page_with_sentences_has_input(self):
assert "<textarea" in render_job(job())