from __future__ import annotations import json import os import shutil import subprocess from pathlib import Path from wov_sdk.models import InvokeRequest, InvokeResponse, NodeManifest from wov_sdk.server import run_node def _bundled_ffmpeg() -> str | None: try: import imageio_ffmpeg return imageio_ffmpeg.get_ffmpeg_exe() except Exception: # noqa: BLE001 return None def _ffmpeg_bin() -> str: configured = os.getenv("FFMPEG_BIN") if configured: return configured found = shutil.which("ffmpeg") if found: return found return _bundled_ffmpeg() or "ffmpeg" def invoke(request: InvokeRequest) -> InvokeResponse: video_uri = request.inputs.get("video_uri") if not video_uri: return InvokeResponse(status="failed", error="video_uri is required") ffmpeg = _ffmpeg_bin() if shutil.which(ffmpeg) is None and not Path(ffmpeg).is_file(): return InvokeResponse(status="failed", error="ffmpeg not found") output_dir = Path(request.output_dir) output_dir.mkdir(parents=True, exist_ok=True) output_path = output_dir / "audio.wav" channels = str(request.params.get("channels", 1)) sample_rate = str(request.params.get("sample_rate", 16000)) command = [ ffmpeg, "-y", "-i", str(video_uri), "-vn", "-ac", channels, "-ar", sample_rate, str(output_path), ] result = subprocess.run(command, capture_output=True, text=True) if result.returncode != 0: return InvokeResponse( status="failed", error=result.stderr[-2000:] or "ffmpeg failed", ) return InvokeResponse(status="completed", outputs={"audio_uri": str(output_path)}) def main() -> None: manifest_path = Path(__file__).resolve().parent.parent / "node.manifest.json" with open(manifest_path, "r", encoding="utf-8") as f: manifest = NodeManifest.from_dict(json.load(f)) run_node(manifest, invoke) if __name__ == "__main__": main()