为视频生成 VR 双眼字幕的单体实现:FastAPI 后端、调度器与全部节点 (提音/转写/翻译/ASS/抽帧/OCR/LLM 过滤)在单进程内运行。 - 节点协议(wov_sdk 数据模型)与分布式版保持一致,预留回退桥梁 - 工作流即数据:DAG 存于 workflows/*.json,模型/链路改动只改数据 - 调度器:拓扑顺序执行、断点续跑(产物重建)、任务暂停/继续 - 抽帧按帧间隔(select 按帧号精确取帧),VLM OCR 与 LLM 过滤使用 自适应线程池弹性并发,并打印数据处理速度进度日志 - 100% 行覆盖率(pytest --cov-fail-under=100)
53 lines
2.2 KiB
Python
53 lines
2.2 KiB
Python
"""真实模型集成测试。
|
|
|
|
复用 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
|