docs: 注释规范要求精简可读,并清理生产代码中的历史叙事

AGENTS.md 的注释规范新增三节可执行约束:

- 只写代码真实逻辑:注释只回答"做什么"与"为什么必须这么做",禁止写决策/
  修改时间、历史版本对比、实测数据与实验结论、事故与缺陷编号(run_xxxx /
  batch_xxxx / R01 等)——这些属 docs/decisions.md 与审查跟踪文件;当前生效
  的约束可以写,但不附带它何时因何变成这样。
- 精简可读:单段连续注释不超过 3 行;docstring 一句话概括职责,不重复函数名
  已表达的信息;不写逐行翻译代码的废话注释,只在非显然处(业务规则、边界、
  易错点、外部约束)加注。
- 覆盖范围:测试注释只说明验证什么行为,回归用例可保留一句溯源;并明确
  参数说明应写在**参数读取处**附近,而不是把多个参数的解释堆在离使用位置
  很远的注释块里。

按此清理生产代码(注释净减 70 行,18 个文件),典型处理:

- nodes/whisper.py:删掉堆在一起、含"用户 2026-08 决定 / 实测 savr-1054"
  等叙事的参数块,把各参数说明移到各自的读取处与 model.transcribe 调用处;
- nodes/llm_filter.py、nodes/subtitle_cleanup.py:模块 docstring 去掉英文
  背景叙事与条数统计,保留"默认只跑规则层""整条删除而非 '-' 占位"等当前
  行为;
- src/wov_app/{batch,db,scheduler}.py 与 routers:去掉 batch_xxx/run_xxx 事故
  编号与"修复前……"对比,改为一句"否则会出现什么问题";
- nodes/ass.py、frame_extract.py:去掉废弃值对比与日期,保留判据本身。

安全验证:用 AST 对比(剥离 docstring 后比较语法树)确认 18 个文件**零逻辑
变更**;`nodes/proper_nouns.py` 的规则表 reason 字段会注入 LLM 提示词,属于
数据而非注释,已恢复原值。全量测试 476 passed。
This commit is contained in:
2026-09-13 16:37:49 +08:00
parent 8f6083f8cf
commit 7a7212f70c
18 changed files with 192 additions and 262 deletions
+19 -39
View File
@@ -1,28 +1,18 @@
"""Subtitle cleanup: remove long-duration closing/greeting hallucinations.
"""字幕清洗:删除寒暄幻觉与纯呻吟碎片。
Background (real run 20260905115050): after fixing the timing alignment,
subtitles still contain "closing/greeting hallucination words" - fixed
phrases like 'wan an / gan xie guan kan / gan xie nin de guan kan'
(good night / thanks for watching) that the ASR/LLM repeatedly emits on
empty segments, filling a full 30s block, unrelated to video content.
Some 2s 'good night' might be real dialogue, so it must be kept.
处理策略(2026-09 用户确认改为"整条剔除"):
幻觉识别出后(展示时长 ≥ 阈值 且 文本命中套话词表),应**连带时间戳把整条
字幕 cue 删除**(剩余条目重新编号),而不是把文本替换成 '-' 占位留给下游——
占位会一路流到 ASS 渲染成可见的"减号"、在翻译/过滤阶段都要额外特殊处理,
处理位置绕且不彻底。因此清洗统一为:**在幻觉产生处(whisper 转录后 / LLM
翻译后)整条删除**,时间轴随之消失,字幕序号重新连续编号。
ASRwhisper 无 VAD 解码)与 LLM 翻译在无语音段会输出固定套话(如“晚安/
感谢观看”/“おやすみなさい”),且在翻译产物里反复出现。处理方式为**连带
时间戳整条删除** cue 并重新编号:不能改成 '-' 占位,否则会一路渲染成可见
减号,并在翻译/过滤阶段需要额外特判。
两类词表:
- HALLUCINATION_TOKENS:中文(LLM 翻译产物中的寒暄,如"晚安/感谢观看");
- JAPANESE_HALLUCINATION_TOKENS:日文(whisper decode_full 无 VAD 解码在
无语音段直接输出的套话,如"おやすみなさい/ご視聴ありがとうございました")。
- HALLUCINATION_TOKENS:中文(LLM 翻译产物中的寒暄);
- JAPANESE_HALLUCINATION_TOKENS:日文(whisper 无 VAD 解码直接输出的套话)。
阈值从真实运行实测数据判定:30s 幻觉占位 vs 2s 真实词,分界明显,
默认 threshold=15s(≥15s 才删除;<15s 的相同词可能是剧情真实道晚安,保留)。
删除只针对展示时长 ≥ 阈值的长条目:短时相同词可能是剧情真实台词(如真实
互道晚安),必须保留。另外删除纯呻吟/喘息碎片(判据见 _is_pure_moan)。
Pure functions, unit-testable (tests/test_hallucination_mask.py).
纯函数,不修改输入。
"""
from __future__ import annotations
@@ -39,11 +29,8 @@ HALLUCINATION_TOKENS = (
# Display-duration threshold (seconds): only remove entries longer than this.
DEFAULT_THRESHOLD_SECONDS = 15.0
# 日文 ASR 直出(whisper 节点 decode_full 无 VAD 整段解码)的收尾/寒暄幻觉词。
# 无 VAD 解码会把无语音/音乐/呻吟段当语音,whisper 常在这些段重复输出套话
# (实测 savr-1054 全片 119-149s/600-630s 等出现 30s 长"おやすみなさい"
# "ご視聴ありがとうございました")。短时(≤阈值)的相同词可能是剧情里真实
# 互道晚安,须保留;仅删除展示时长 ≥ 阈值的条目(与中文表同一机制)。
# 日文套话词表:whisper 无 VAD 解码会把无语音/音乐段当语音,从而重复输出
# 这些寒暄;短时相同词可能是剧情真实台词,靠时长阈值区分(同中文表机制)。
JAPANESE_HALLUCINATION_TOKENS = (
"おやすみなさい", # 晚安
"ご視聴ありがとうございました", # 感谢观看
@@ -58,14 +45,10 @@ JAPANESE_HALLUCINATION_TOKENS = (
"Thank you for watching",
)
# 纯呻吟/喘息字符集合decode_full 救回弱语音后的去噪,2026-09 用户决策)。
#
# 背景(实测 savr-1054-2 前 600s):decode_full 无 VAD 解码会把呻吟/BGM 混叠
# 的弱语音也整段救回,但其中混有大量**纯语气词碎片**(あ…/ん?/はぁ…/あ!あ!
# /んふふ 等),这类内容放进字幕是噪声。判据:文本(去空白/标点)**全部由本
# 集合字符组成**且有效假名数 ≤ 阈值才删除。集合**刻意排除** そ/こ/ね/や/ば/だ
# /く/へ 等假名——真实短对话(そこ/やばい/ねえ/やだ/えへへ)都含这些字符,
# 含任意非集合字符的条目天然不命中,从根上避免误删真实短句。
# 纯呻吟/喘息字符集合:文本(去空白/标点)全部由本集合字符组成、且有效假名数
# ≤ 阈值时才判为噪声删除。集合**刻意排除** そ/こ/ね/や/ば/だ/く/へ 等假名——
# 真实短对话(そこ/やばい/ねえ/やだ/えへへ)都含这些字符,因此天然不命中,从
# 判据根源上避免误删真实短句。
MOAN_CHARS = frozenset(
# 平假名元音与ん/ふ/は(呻吟与喘息气流音的主干)
"あいうえおんふはっ"
@@ -144,12 +127,9 @@ def remove_short_moan_entries(
) -> str:
"""删除 SRT 中'纯呻吟/喘息碎片'的**整条 cue**whisper decode_full 去噪)。
decode_full 无 VAD 解码会把呻吟也整段救回,字幕混入大量纯语气词碎片
(あ…/ん?/はぁ…)。判据:文本全部由 MOAN_CHARS 组成且有效假名数 ≤
max_chars(默认 3)才删除(见 _is_pure_moan),真实短对话(そこ/やばい/
ねえ/やだ/えへへ/行く行く行く)天然不命中。max_chars=0 时关闭过滤(原
样返回)。仅在 whisper 节点 decode_full=true 时调用(用户 2026-09 决策,
不作用于 learn-translate 等 VAD 链路)。纯函数,不修改输入。
无 VAD 解码会把呻吟也整段救回,字幕因此混入纯语气词碎片(あ…/ん?)。
判据见 _is_pure_moan:文本全部由 MOAN_CHARS 组成且有效假名数 ≤ max_chars
才删除;max_chars=0 时关闭过滤。纯函数,不修改输入。
"""
if max_chars <= 0:
return srt_text