"""种子数据模块。 启动时把工作区内所有 wov-node-* 子仓库的 manifest 注册为节点,并创建演示 “视频字幕生成”工作流,方便本地直接体验完整链路。 """ from __future__ import annotations from pathlib import Path from wov_sdk.models import NodeManifest, WorkflowDefinition, WorkflowEdge, WorkflowNode from app.db import Database def seed_nodes(db: Database, workspace_root: Path) -> None: """扫描工作区中的节点仓库并注册其 manifest。""" for node_dir in sorted(workspace_root.glob("wov-node-*")): manifest_path = node_dir / "node.manifest.json" # 没有 manifest 的目录不是节点仓库,直接跳过。 if not manifest_path.is_file(): continue manifest = NodeManifest.load(str(manifest_path)) # 以目录名作为 repo_dir,确保 NodeManager 能定位到子仓库。 manifest.repo_dir = node_dir.name db.upsert_node(manifest) def seed_demo_workflow(db: Database) -> None: """创建演示工作流:提音 -> 转写 -> 翻译 -> ASS。""" # 已存在同名工作流时不重复创建,保持幂等。 if db.get_workflow("demo") is not None: return definition = WorkflowDefinition( name="视频字幕生成", version=1, nodes=[ WorkflowNode( id="extract", node_type="ffmpeg-extract", params={"sample_rate": 16000, "channels": 1}, inputs={"video_uri": "input.video_uri"}, ), WorkflowNode( id="asr", node_type="faster-whisper", params={"language": "ja"}, inputs={"audio_uri": "extract.audio_uri"}, ), WorkflowNode( id="translate", node_type="llm-translate", params={"target_language": "zh-CN"}, inputs={"srt_uri": "asr.srt_uri"}, ), WorkflowNode( id="ass", node_type="srt-to-dual-eye-ass", params={"resolution": "3840x1920"}, inputs={"cn_srt_uri": "translate.cn_srt_uri"}, ), ], edges=[ WorkflowEdge(from_node="extract", to_node="asr"), WorkflowEdge(from_node="asr", to_node="translate"), WorkflowEdge(from_node="translate", to_node="ass"), ], entry_inputs={"video_uri": "file"}, final_outputs={ "cn_srt": "translate.cn_srt_uri", "ass": "ass.ass_uri", }, ) db.upsert_workflow( { "id": "demo", "name": definition.name, "description": "上传视频,自动生成中文字幕和 VR 双眼 ASS。", "published": 1, "latest_version": 1, } ) # 保存第一个版本的 DAG 定义,后续发布流程以版本记录为准。 db.create_workflow_version("demo", 1, definition.to_dict())