01 · WHAT IT DOES
给我 audio_url 和 image_url, 我还你一段会说话的数字人 mp4. 如果 audio_url 是视频, 我先抽人声.
不解析自然语言 — agent 已经把意图翻成这 4 个字段了. 不生成主播图 — 形象怎么来不归我管.
重活全在 fal SaaS, 本机不跑视频编解码; 跟 subtitle / pip 走 Rendi 的套路不同.
02 · INPUT CONTRACT
"语气活泼, 用手比划".
03 · ADAPTIVE INPUT
不开 isolate_voice 开关 — ffprobe 看一眼就知道. 视频自动调 ElevenLabs 抽人声, 抽完还校验时长 + 响度.
视频里压根没人声 (纯 BGM) → 隔离后会拿到时长极短或近静音的结果, 走 voice_extraction_failed.
04 · INTERNAL RULES
设计上不让 agent 调; 都是工程默认值, 改要发新 skill 修订.
05 · FAILURE MODES
每条 fail 前先写 outputs/.logs/animate-error.json (reason / fal_request_ids_so_far / created_at), 再 tobatsu-agent fail --summary.
| reason | 触发场景 |
|---|---|
| invalid_payload | audio_url 或 image_url 缺 / payload.json 损坏 / 字段类型错 |
| download_failed | 任一 URL 3 次重试都拉不到 |
| image_unreadable | image_url 内容不是有效图片 (Pillow open 抛错) |
| audio_unreadable | audio_url ffprobe 跑挂 / 文件无音频流 |
| audio_too_long | 隔离后 / 直接用的音频 > 60s (OmniHuman 720p 上限) |
| voice_extraction_failed | 输入是视频, ElevenLabs 成功返回, 但音频时长 < 1s 或 mean_volume < -50 dBFS |
| provider_failed | fal 接口报错 (audio-isolation 或 OmniHuman 任一) |
| upload_failed | tobatsu-agent output upload 3 次重试都挂 |
06 · RUNTIME FLOW
读 payload → 探输入 → (可能抽人声) → 探图 → 跑 OmniHuman → 下载 → 上传 → 写 result.json.
检查 audio_url / image_url 都在, 类型对, JSON 合法. 不合法 → invalid_payload.
拿 streams + duration. 看是有 video 流还是只有 audio.
# 关键判断 streams = ffprobe.streams input_kind = "video" if any(s.codec_type == "video") else "audio"
调 fal ElevenLabs audio-isolation, 下隔离结果, ffprobe 校验时长, ffmpeg volumedetect 校验响度.
fal_call("fal-ai/elevenlabs/audio-isolation", {video_url: audio_url}) # 校验 duration >= 1.0s # else voice_extraction_failed mean_volume > -50 dBFS # else voice_extraction_failed
Pillow open + verify, 不是图片 → image_unreadable.
image_url + 干净 audio_url + prompt + resolution=720p + turbo=false. fal_client.submit() 拿 request_id, get() 等结果. 约 60s 音频 ≈ 13 分钟. 失败 → provider_failed.
3 次重试; 探完拿 width / height / duration.
label = digital-human.mp4. 3 次重试. 拿到 CDN URL.
包含 fal_request_ids (omnihuman / 可能的 audio_isolation), output URL, 尺寸 / 时长, input_audio_kind, audio_isolated. 跑 tobatsu-agent done.
07 · PIPELINE POSITION
这个 skill 是 pipeline 中间一环, 单一职责. 形象怎么来、字幕怎么烧、怎么拼接都不归它. 它只管"图 + 音 → 数字人".
音频去重提醒: 数字人输出永远带 OmniHuman 生成的音轨. 下游做 PIP / concat 时, 如果源视频已经有这段人声 (典型: input_kind=video 那条路, 源视频被原样保留参与拼接), 必须把数字人那一路静音 — 否则同一句话出现两次. PIP 那边 pip_volume=0; concat 那边选主音轨.
08 · KNOWN BOUNDARIES
音频 > 60s — 不切片, 直接 fail. 后续可加切片+拼接逻辑.
1080p 分辨率 — 第一版只开 720p (≤60s). 1080p 卡 30s 不够用, 留作 v1+.
多人物主播图 — 不暴露 mask_url, 默认单人. 多人场景由上游图层处理.
多语种校验 — OmniHuman 自己处理, skill 不预校验.