docs: 为全部代码补充中文注释并加入 AGENTS 注释规范
This commit is contained in:
@@ -1,3 +1,9 @@
|
||||
"""FFmpeg 提音节点入口。
|
||||
|
||||
通过标准节点 HTTP 服务对外提供音频提取能力。ffmpeg 解析顺序为:
|
||||
FFMPEG_BIN 环境变量 > PATH 中的 ffmpeg > imageio-ffmpeg 内置二进制。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
@@ -11,29 +17,37 @@ from wov_sdk.server import run_node
|
||||
|
||||
|
||||
def _bundled_ffmpeg() -> str | None:
|
||||
"""尝试获取 imageio-ffmpeg 内置的 ffmpeg 可执行文件路径。"""
|
||||
try:
|
||||
import imageio_ffmpeg
|
||||
|
||||
return imageio_ffmpeg.get_ffmpeg_exe()
|
||||
except Exception: # noqa: BLE001
|
||||
# 未安装 imageio-ffmpeg 或获取失败时返回 None,交由上层回退。
|
||||
return None
|
||||
|
||||
|
||||
def _ffmpeg_bin() -> str:
|
||||
"""按优先级解析 ffmpeg 可执行文件,返回最终命令路径。"""
|
||||
# 显式配置优先,便于部署环境指定自定义二进制。
|
||||
configured = os.getenv("FFMPEG_BIN")
|
||||
if configured:
|
||||
return configured
|
||||
# 其次查找 PATH 中的系统 ffmpeg。
|
||||
found = shutil.which("ffmpeg")
|
||||
if found:
|
||||
return found
|
||||
# 最后回退到 imageio-ffmpeg 内置二进制;都没有时保留 "ffmpeg" 交给调用失败处理。
|
||||
return _bundled_ffmpeg() or "ffmpeg"
|
||||
|
||||
|
||||
def invoke(request: InvokeRequest) -> InvokeResponse:
|
||||
"""提取输入视频/音频的标准化音频,产物为 audio.wav。"""
|
||||
video_uri = request.inputs.get("video_uri")
|
||||
if not video_uri:
|
||||
return InvokeResponse(status="failed", error="video_uri is required")
|
||||
|
||||
# 找不到可用 ffmpeg 时直接返回失败,避免子进程报晦涩错误。
|
||||
ffmpeg = _ffmpeg_bin()
|
||||
if shutil.which(ffmpeg) is None and not Path(ffmpeg).is_file():
|
||||
return InvokeResponse(status="failed", error="ffmpeg not found")
|
||||
@@ -41,14 +55,15 @@ def invoke(request: InvokeRequest) -> InvokeResponse:
|
||||
output_dir = Path(request.output_dir)
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
output_path = output_dir / "audio.wav"
|
||||
# ASR 节点默认期望 16kHz 单声道;参数可覆盖。
|
||||
channels = str(request.params.get("channels", 1))
|
||||
sample_rate = str(request.params.get("sample_rate", 16000))
|
||||
command = [
|
||||
ffmpeg,
|
||||
"-y",
|
||||
"-y", # 覆盖可能存在的同名输出文件。
|
||||
"-i",
|
||||
str(video_uri),
|
||||
"-vn",
|
||||
"-vn", # 丢弃视频流,只保留音频。
|
||||
"-ac",
|
||||
channels,
|
||||
"-ar",
|
||||
@@ -57,6 +72,7 @@ def invoke(request: InvokeRequest) -> InvokeResponse:
|
||||
]
|
||||
result = subprocess.run(command, capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
# 返回 stderr 尾部,保留最有诊断价值的错误信息。
|
||||
return InvokeResponse(
|
||||
status="failed",
|
||||
error=result.stderr[-2000:] or "ffmpeg failed",
|
||||
@@ -65,6 +81,7 @@ def invoke(request: InvokeRequest) -> InvokeResponse:
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""加载节点清单并以本模块的 invoke 处理器启动服务。"""
|
||||
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))
|
||||
|
||||
Reference in New Issue
Block a user