"""长时寒暄幻觉词清洗测试(先红后绿)。 背景(实测 run 20260905115050):修复时间对齐后,字幕仍残留四类问题, 其中"寒暄/收尾幻觉词"最具确定性、可规则化: - 产物里 '晚安 / 感谢观看 / 感谢收看 / 感谢您的观看' 等固定套话出现 36 次; - 其中 **33 条展示时长 = 30s(整块占满)**,明显是 ASR/LLM 对无内容段 的音量幻觉占位,与视频内容毫无关系; - 仅 2 条时长 ~2s(如 720.00-722.00 '晚安')可能是剧情里真的说了"晚安", 属于真实内容,不应误删。 方案(用户确认):日文转译完成后,对**展示时长过长**(≥阈值)且文本匹配 寒暄词表的条目,把文本替换为 '-' 占位,由后续处理(SRT/过滤流程)移除。 这样既清掉幻觉占位,又用"时长阈值"保住可能为真实对话的短时寒暄词。 阈值从本次真实运行实测数据判定:30s 幻觉占位 vs 2s 真实词,分界明显, 本测试选 threshold=15s(>15s 才视为幻觉;≤15s 保留)。 """ from __future__ import annotations import pytest # 清洗逻辑来自生产模块 nodes/subtitle_cleanup.py(纯函数),测试只 import。 from nodes.subtitle_cleanup import ( DEFAULT_THRESHOLD_SECONDS, HALLUCINATION_TOKENS, mask_hallucination_text, ) def _mk(start: float, end: float, text: str) -> dict: """构造一个字幕条目(测试辅助)。""" return {"start": start, "end": end, "text": text} def test_long_hallucination_masked() -> None: """30s 的'晚安/感谢观看'(幻觉占位)必须被替换为 '-'。""" entries = [ _mk(60.0, 90.0, "晚安"), _mk(90.0, 120.0, "感谢您的观看"), _mk(1260.0, 1289.98, "感谢您的观看"), ] out = mask_hallucination_text(entries) assert all(e["text"] == "-" for e in out) def test_short_hallucination_preserved() -> None: """2s 的'晚安'(可能为剧情真实对话)必须保留,不误删。""" entries = [ _mk(720.0, 722.0, "晚安"), _mk(238.0, 240.0, "非常感谢您的观看。"), ] out = mask_hallucination_text(entries) assert out[0]["text"] == "晚安" assert out[1]["text"] == "非常感谢您的观看。" def test_non_hallucination_always_preserved() -> None: """普通内容(即使很长)绝不能被当成寒暄幻觉处理。""" entries = [ _mk(0.0, 30.0, "今天我将为您提供精神调适服务"), _mk(10.0, 40.0, "请尽量放松,无论多少次都能感到舒适愉悦"), ] out = mask_hallucination_text(entries) assert out[0]["text"] == "今天我将为您提供精神调适服务" assert out[1]["text"] == "请尽量放松,无论多少次都能感到舒适愉悦" def test_threshold_boundary() -> None: """阈值边界:刚好 ≥ 阈值才清洗;< 阈值保留。""" entries = [ _mk(0.0, 15.0, "晚安"), # 恰好 15s → 清洗(≥ threshold) _mk(0.0, 14.99, "晚安"), # 14.99s → 保留 ] out = mask_hallucination_text(entries, threshold_seconds=15.0) assert out[0]["text"] == "-" assert out[1]["text"] == "晚安" @pytest.mark.integration def test_mask_does_not_mutate_input() -> None: """清洗不得修改原始条目对象(纯函数约束)。""" entries = [_mk(60.0, 90.0, "晚安")] original_text = entries[0]["text"] mask_hallucination_text(entries) assert entries[0]["text"] == original_text