本文件是
skill-mv能力边界的唯一事实来源,与lib/providers.mjs保持同步。 所有结论均为 2026-10-13 在网关https://api.fmode.cn/v1实测得到。 状态随时可能变化 —— 复测命令:> fmode-mv providers # 轻量探活(查模型清单 + 路由真实性,不产生费用) > fmode-mv providers --deep # 深度探活(会真实提交任务,可能计费) > ``` --- ## 一、总览 | 环节 | 端点 | 现状 | 证据 | |---|---|---|---| | 作曲填词 / 分镜 / 口播稿 | `POST /v1/chat/completions` | ✅ **可用** | 实测产出完整歌词与分镜 JSON | | 场景 / 人物关键帧 | `POST /v1/images/generations` | ✅ **可用** | 实测 `gpt-image-2.5-sunburst` 返回 b64_json,1792×1024 / 3MB | | 剪辑 / 合成 | 本地 ffmpeg | ✅ **可用** | 实测出片 25.2s / 1280×720 / 4.6MB,含烧字幕与响度归一化 | | AI 音乐 | `POST /suno/submit/music` + `POST /suno/fetch` | ⚠️ **端点存在,渠道未开通** | `POST` 返回 `503 {"code":"server_error","message":"Task request failed"}` | | 图生视频 | `POST /v1/video/generations` | ⚠️ **无可用渠道** | `503 {"code":"model_not_found","message":"No available channel for model doubao-seedance-1-0-pro ..."}` | | 唇形驱动 | — | ⚠️ **平台无此路由** | 网关返回前端兜底页(`HTTP 200` + `text/html`) | | TTS 口播配音 | `/v1/audio/speech` | ⚠️ **平台无此路由** | 同上;本地 edge-tts 在**部分云环境被 403 拦截**(本容器实测),需备外部接口 | | 音轨分离 | 本地 | ◐ **ffmpeg 近似 / demucs 可选** | 单声道素材无法分离;立体声可做相位近似 | **汇总:2 条平台通道可用(chat / image)+ 本地剪辑可用。** --- ## 二、⚠️ 一个必须知道的探测陷阱 网关**根域对未知路径返回 SPA 的前端 `index.html`**,状态码是 **`200`**,`Content-Type: text/html`。 这意味着:**只看 HTTP 状态码会把不存在的端点误判为"可用"**。 早期版本的探活就踩了这个坑(`/lipsync/generations`、`/audio/speech` 都显示 `HTTP 200` → 误报可用)。 现已修正,`probeEndpoint()` 会做三重判断:js // 1. Content-Type / 响应体是 HTML → 端点不存在 if (ct.includes('text/html') || /^\s*<(doctype html|html)/i.test(text)) → 不存在 // 2. 405 → 路由存在(方法不对) if (status === 405) → 存在 // 3. 明确的渠道错误 → 端点存在但渠道未开通 if (/no available channel|model_not_found|task request failed/i.test(msg)) → 存在但不可用
**如果你自己写探活脚本,务必带上这个判断**,否则会得出「TTS 可用」的错误结论。 --- ## 三、逐项替代方案 ### AI 音乐 ⚠️ **症状**:`POST https://api.fmode.cn/suno/submit/music` → `503 {"code":"server_error","message":"Task request failed"}` (端点路由存在 —— `GET` 该路径返回 `405 Method Not Allowed`) | 方案 | 操作 | 适用 | |---|---|---| | A. 等平台开通 | 无 | 通道开通后 `fmode-mv music --from work/song.json` **无需改代码**即可用 | | B. 自备音乐 | `fmode-mv song "主题" --music your-song.mp3` | **当前最实际**。用自己的编曲/购买的音乐 | | C. 对接外部 | `export FEME_MUSIC_ENDPOINT=https://your-host/suno/submit/music` | 自建或采购了 Suno 兼容服务 | **设计保证**:`lib/providers.mjs` 的 `music` provider 端点与模型名**不在代码里写死**, 全部可被 `FEME_MUSIC_ENDPOINT` / `FEME_MUSIC_MODEL` 覆盖。 平台开通或换服务商,**只需改环境变量**。 --- ### 图生视频 ⚠️ **症状**:`POST /v1/video/generations` → `503 {"code":"model_not_found","message":"No available channel for model doubao-seedance-1-0-pro under group default (distributor)"}` 模型名**在**网关 `/v1/models` 清单里,但**没有可用渠道**(这是"模型在列 ≠ 能调用"的典型)。 | 方案 | 操作 | 适用 | |---|---|---| | A. 平台开通 | 无 | 开通后 `fmode-mv video --from work/storyboard.json --mode provider --force` 一键替换 | | B. 换已开通模型 | `export FEME_VIDEO_MODEL=<可用模型名>` | 若网关接入其它视频模型 | | C. **静帧 + Ken Burns 兜底** | 默认 `--mode auto` 自动启用 | **当前默认行为** | **兜底实现**(`lib/ffmpeg.mjs` 的 `kenBurns()`): 在 2 倍画布上做 `zoompan` 缓慢推拉,按镜头序号交替推近/拉远,输出 1280×720 @30fps。 **兜底产物的诚实标记**(这是本技能的设计底线): - 文件名带 **`.fallback`**:`shot-01.fallback.mp4` - `work/clips/clips.json` 里 `mode: "still"`、`fallback: true` - 命令输出明确打印:! 注意:本次所有片段都是「静帧 + 运镜」兜底产物,不是 AI 图生视频结果。
!提示:N 段为兜底运镜(非真 AI 图生视频)- `out/manifest.json` 记录 `fallbackCount`,成片报告里再提示一次 **绝不把兜底产物说成 AI 生成视频。** --- ### 唇形驱动 ⚠️ **症状**:网关**没有** `/lipsync/generations` 路由 —— 返回 SPA 兜底页(`HTTP 200` + `text/html`)。 | 方案 | 操作 | 观感 | |---|---|---| | C. 纯空镜 + 字幕 | 分镜里不标 `lipSync` | 纯音乐 MV 最常见做法,零风险 ✅ | | B. 表情微动镜头 | 演唱镜头走图生视频(表情/头部微动),不严格对口型 | 可接受 | | **A. 自建服务** | 部 Wav2Lip / SadTalker / LatentSync → `export FEME_LIPSYNC_ENDPOINT=https://your-host/lipsync` | 最好 | **自建服务的接口约定**(技能按此调用):http POST Content-Type: application/json Authorization: Bearer
{ "image": "<人脸图片 URL 或 data:image/png;base64,...>", "audio": "<音频 URL>", "model": "" }
期望响应:任何包含视频 URL 的结构(技能会递归扫描 `video_url` / `url` 等字段),例如:json { "data": { "video_url": "https://cdn.example.com/out.mp4" } }
**降低依赖的建议**: - 分镜里 `lipSync: true` 的镜头**全片 ≤ 4 个**(产线 B ≤ 2 个)。 - `talking`/`perf` 镜头用中景而非正脸特写,口型不匹配不易察觉。 --- ### TTS 口播配音 ⚠️ **症状**:网关**没有** `/v1/audio/speech` 路由 —— 同样返回 SPA 兜底页。 | 方案 | 操作 | 说明 | |---|---|---| | **A. 本地 edge-tts** | `pip install edge-tts` | **免费**,中文音色多,技能**自动探测**。⚠️ 但**部分云环境会失败**:调用 `wss://speech.platform.bing.com` 返回 **403 HandshakeError**(本容器 2026-10-13 实测 edge-tts 7.2.8 最新版亦被拦)—— 命中则该方案不可用,改走 B | | B. 对接外部 | `export FEME_TTS_ENDPOINT=https://your-host/v1/audio/speech` | OpenAI 兼容接口。**云环境推荐**;DashScope/百炼 `cosyvoice`、火山、MiniMax 均可自建转发 | | C. 自备配音 | `--voice my.mp3` | 真人录音也行 | **探测优先级**(`tts.probe()`):**本地 edge-tts 优先**,其次才探网关。 安装后 `fmode-mv tts --probe` 返回:状态 可用 提供方 edge-tts(local)
**常用中文音色**: | 音色 | 特征 | |---|---| | `zh-CN-XiaoxiaoNeural` | 女声,自然亲和(默认) | | `zh-CN-YunxiNeural` | 男声,年轻 | | `zh-CN-YunjianNeural` | 男声,沉稳 | | `zh-CN-XiaoyiNeural` | 女声,活泼 | --- ### 音轨分离 ◐ **不是"未开通",是"精度分级"**: | 级别 | 依赖 | 效果 | 命令 | |---|---|---|---| | 高质量 | `demucs`(`pip install demucs`) | 真·分离,人声/伴奏/鼓/贝斯分轨 | `fmode-mv separate x.mp3 --method demucs` | | **兜底** | 仅 ffmpeg | **近似**:侧信号取伴奏、中置取人声 | `fmode-mv separate x.mp3`(默认) | **兜底的物理限制(必须如实告知用户)**: 1. **仅对立体声有效** —— 单声道素材脚本会**直接报错**,不会给你假结果。 2. **是相位近似,不是分离** —— 只对「人声居中、乐器分列左右」的老式混音有效; 现代宽混音基本无效,人声/伴奏都会残留串扰。 3. 脚本会明确打印:`! 未检测到 demucs,使用 ffmpeg 相位兜底方案(近似分离,非真·分离)`, 并在返回结构里带 `note` 字段。 --- ## 四、provider 覆盖机制(不改代码换通道) `lib/providers.mjs` 是唯一的通道注册表。任何 provider 的模型名/端点都可被覆盖: ### 方式 1:环境变量bash export FEME_MUSIC_MODEL=chirp-v4-0 export FEME_MUSIC_ENDPOINT=https://your-host/suno/submit/music export FEME_VIDEO_MODEL=kling-v1 export FEME_VIDEO_ENDPOINT=https://your-host/v1/video/generations export FEME_LIPSYNC_ENDPOINT=https://your-host/lipsync export FEME_TTS_ENDPOINT=https://your-host/v1/audio/speech export FEME_TTS_VOICE=zh-CN-YunxiNeural export FEME_CHAT_MODEL=doubao-seed-2-1-pro export FEME_IMAGE_MODEL=gpt-image-2.5-sunburst
### 方式 2:身份文件的 `providers` 段jsonc // /opt/data/fmode-identity.json { "newapi_token": "...", "providers": {
"music": { "model": "chirp-v4-0", "endpoint": "/suno/submit/music" }, "video": { "model": "kling-v1" }, "tts": { "voice": "zh-CN-YunxiNeural" }} }
> ⚠️ 身份文件含凭据,**不要提交进 Git**(`.gitignore` 已排除 `*identity*.json`)。 **覆盖优先级**:环境变量 > 身份文件 `providers` 段 > provider 内置默认值。 --- ## 五、复测脚本 通道状态会变。建议每次开工前跑一次:bash fmode-mv providers # 轻量:查 /v1/models + 路由真实性 + SPA 兜底判断,零费用 fmode-mv doctor # 全量自检:node/ffmpeg/凭据/demucs/各通道 fmode-mv providers --deep # 深度:真实提交任务(music 会消耗额度,image 不做 deep)
**预期输出(2026-10-13 基线)**:chat ✅ 可用 大语言模型(作曲填词 / 分镜 / 口播稿) image ✅ 可用 文生图(场景 & 人物关键帧) music ◐ 未知 AI 音乐生成(Suno 兼容通道) video ⚠️ 未开通 图生视频(B-roll 空镜 / 人物演唱镜头) lipsync ⚠️ 未开通 唇形驱动(口型对齐人声) tts ⚠️ 未开通 语音合成(口播配音) 汇总: 2/6 通道可用
--- ## 六、本技能的诚实性承诺 针对"未开通通道"这一现实,本技能遵守三条硬规则: 1. **不静默失败** —— 调用未开通通道必抛 `ProviderUnavailableError`, 携带 `hint` 字段,打印**可操作方案**(换通道 / 对接外部 / 用现成素材)。 2. **不伪造产物** —— 绝不写入空的或占位的音频/视频文件冒充生成结果。 兜底产物一律带 `.fallback` 后缀与 `fallback: true` 标记。 3. **不隐藏降级** —— 端到端编排的最终报告里,每一步的状态 (`ok` / `fallback` / `unavailable` / `skipped` / `failed`)逐条列出, 未完成项单独成段列出原因。════════════════════════════════════════════════════════════════ 产线A · AI 单曲 MV · 执行报告 ════════════════════════════════════════════════════════════════ ✅ 作曲填词 《末班车还亮着》 ✅ 分镜脚本 6 镜 / 36s ⚠️ AI 音乐 通道未开通 ⏭️ 音轨分离 无音乐文件 ✅ 关键帧 成功 6 / 失败 0 ◐ 图生视频 Ken Burns 兜底:6 段 ⚠️ 唇形驱动 2 个待处理镜头未处理 ✅ 剪辑合成 36.0s / 4.6MB ──────────────────────────────────────────────────────────────── 成片: out/mv.mp4 未完成项: · AI 音乐: 通道未开通 · 唇形驱动: 2 个待处理镜头未处理 ════════════════════════════════════════════════════════════════ ```
这就是本技能对"诚实"的落地方式:让用户一眼看清哪些是真 AI 生成、哪些是降级替代。