feat: 完成 ffmpeg 音频提取节点
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user