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