feat: whisper 节点自动接入自适应 VAD + 方案文档

- nodes/whisper.py:invoke 检测到 vad_filter=true 且未显式传 vad_parameters
  且 WOV_AUTO_VAD=1 时,自动调用 vad_profiler.vad_parameters_for_audio 按
  本音频信号动态确定 VAD 参数并传给 transcribe;分析失败回退默认不中断转写
  (防御性,不影响整段流程)。
- tests/test_nodes.py:新增自动 VAD 异常回退测试(patch profiler 抛错,
  验证 whisper 正常转写 + transcribe 收到 vad_parameters=None)。
- docs/adaptive_vad.md:完整方案文档(背景/可行性/三层架构/参数建议规则/
  评分器/实现落点/取舍/实现状态)。
This commit is contained in:
2026-09-06 08:15:13 +08:00
parent d0d96a8f89
commit 2c3c356348
3 changed files with 151 additions and 1 deletions
+23 -1
View File
@@ -236,6 +236,27 @@ def invoke(request: InvokeRequest) -> InvokeResponse:
# 分块转写:默认每 1 分钟一块(chunk_seconds=60),切块失败自动回退整段。
chunk_seconds = int(request.params.get("chunk_seconds", 60))
chunks = _split_audio(audio_path, output_dir, chunk_seconds, _ffmpeg_bin())
# 每视频自适应 VAD:若开启 vad_filter 且未显式传 vad_parameters,则根据本音频
# 信号分析自动确定 VAD 参数(BGM 覆盖/静音比例/长停顿),改善碎片化与漏识别。
# 门控 WOV_AUTO_VAD=0 可关闭;显式传入 vad_parameters 时跳过。
vad_parameters = request.params.get("vad_parameters")
vad_filter = bool(request.params.get("vad_filter", True))
if vad_filter and not vad_parameters and os.getenv("WOV_AUTO_VAD", "1") == "1":
try:
from nodes.vad_profiler import vad_parameters_for_audio
vad_parameters = vad_parameters_for_audio(
audio_path,
sample_rate=int(request.params.get("sample_rate", 16000)),
whisper_invoke=None, # 片段网格需模型;生产默认仅信号分析(快速)
run_dir=Path(request.output_dir),
chunk_seconds=chunk_seconds,
)
logger.info("自动 VAD 参数: %s", vad_parameters)
except Exception as exc: # noqa: BLE001
# 分析失败不影响转写:回退默认 bentenVAD,仅记录。
logger.warning("自动 VAD 分析失败,回退默认: %s", exc)
vad_parameters = None
# 逐块转写并合并:offset 用每块实际时长累积(WAV 头精确),SRT 序号连续。
logger.info("转写开始: %d 个分块", len(chunks))
lines: list[str] = []
@@ -256,7 +277,8 @@ def invoke(request: InvokeRequest) -> InvokeResponse:
language=str(request.params.get("language", "ja")),
task=str(request.params.get("task", "transcribe")),
beam_size=int(request.params.get("beam_size", 1)),
vad_filter=bool(request.params.get("vad_filter", True)),
vad_filter=vad_filter,
vad_parameters=vad_parameters,
condition_on_previous_text=bool(
request.params.get("condition_on_previous_text", False)
),