"""真实模型集成测试。 复用 testdata/speech_60s.wav(真实语音 WAV,一次性生成、入库,避免每次 测试从视频提取)。使用真实 faster-whisper 模型端到端验证 whisper 节点的 分块转写与 SRT 生成。本地缺少模型或测试资产时自动跳过;具备条件时必须 执行,作为对假模型单元测试的校准。 约定(见 AGENTS.md「测试与覆盖率」):单元测试允许在模型推理这一 I/O 边界使用返回真实结构的薄桩,但必须配套本集成测试验证真实行为。 """ from pathlib import Path import pytest from nodes.whisper import invoke from wov_sdk.models import InvokeRequest # 单体根目录:tests/ 的上一级。 WORKSPACE = Path(__file__).resolve().parent.parent MODEL_DIR = WORKSPACE / "model" / "faster-whisper-large-v3" TEST_AUDIO = WORKSPACE / "testdata" / "speech_60s.wav" @pytest.mark.integration def test_whisper_real_model_chunked_transcription(tmp_path) -> None: """复用 testdata 语音 + 真实模型:分块转写产出真实 SRT,时间不越出素材范围。""" if not (MODEL_DIR / "model.bin").is_file(): pytest.skip("本地无 faster-whisper-large-v3 模型,跳过真实模型集成测试") if not TEST_AUDIO.is_file(): pytest.skip("缺少 testdata/speech_60s.wav 测试资产,跳过真实模型集成测试") response = invoke( InvokeRequest( run_id="integration_1", node_instance_id="", inputs={"audio_uri": str(TEST_AUDIO)}, params={"language": "ja", "chunk_seconds": 60, "vad_filter": False}, output_dir=str(tmp_path / "out"), ) ) assert response.status == "completed", response.error srt_path = Path(response.outputs["srt_uri"]) assert srt_path.is_file() srt = srt_path.read_text(encoding="utf-8") time_lines = [line for line in srt.splitlines() if "-->" in line] # 60s 语音若含可识别内容,则应有字幕,且时间轴不越出素材时长(允许少量超窗)。 if time_lines: last_end = time_lines[-1].split(" --> ")[1].replace(",", ".") hours, minutes, seconds = last_end.split(":") total = int(hours) * 3600 + int(minutes) * 60 + float(seconds) assert total < 90