前端视频工作流选择器 → 后端转发 api_video_workflow → Pixelle comfy 注入 audio_path → 部署联调。视频入口可选、默认不启用、向后兼容。 Co-Authored-By: Claude <noreply@anthropic.com>
10 KiB
数字人接入 Comfy Cloud 视频工作流(完整视频入口)实现计划
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: 给 BoosAPI 数字人加「视频工作流」入口,让用户选 comfy/video_digital_ltx2.json 触发「肖像图+旁白音频→LTX2.3 说话视频」,贯穿前端→BoosAPI 后端→Pixelle 三层。
Architecture: 前端 DigitalHuman.tsx 加可选「视频工作流」选择器(列 video_*),提交 api_video_workflow;BoosAPI digital_human.rs 的 pixelle_request_body 透传该字段;Pixelle asset_based.py 对 comfy/ 视频工作流也注入 audio_path。视频入口默认空=不启用,保持现有「图片+HTML 合成」向后兼容。
Tech Stack: React/TS(BoosAPI 前端)、Rust/axum(BoosAPI 后端)、Python(Pixelle,容器内)。
环境: BoosAPI 仓库
/root/metapi,前端src/web,后端src/routes。Pixelle 在 Docker 容器pixelle-video-api,源码/app/pixelle_video(镜像内置,改后docker compose restart api,备份到/opt/Pixelle-Video/patches/)。构建:前端npm run typecheck:web,后端cargo build -j 2(-j 2 防 OOM)。分支feat/comfy-cloud-adapter。
前置(已完成): comfy-cloud 适配器、
comfy/video_digital_ltx2.json(probe 通过)、media.py 转发 image_path。
文件结构
- Modify
src/web/pages/DigitalHuman.tsx— 加apiVideoWorkflowstate + 「视频工作流」选择器 + payload 字段 + draft 持久化。 - Modify
src/routes/digital_human.rs—pixelle_request_body转发api_video_workflow。 - Modify(容器内)
/app/pixelle_video/pipelines/asset_based.py— comfy 视频工作流注入 audio_path。
Task 1: 前端加「视频工作流」选择器 + 提交字段
Files:
-
Modify:
src/web/pages/DigitalHuman.tsx -
Step 1:
DigitalHumanDrafttype 加字段(~line 34 附近,imageWorkflow 旁)
找到 imageWorkflow?: string;(约 line 34),其后加一行:
apiVideoWorkflow?: string;
- Step 2: 加 state(~line 370,imageWorkflow useState 旁)
找到 const [imageWorkflow, setImageWorkflow] = useState(draftRef.current.imageWorkflow || '');(约 line 370),其后加:
const [apiVideoWorkflow, setApiVideoWorkflow] = useState(draftRef.current.apiVideoWorkflow || '');
- Step 3: draft 持久化加字段(~line 462 写入 + ~line 480 依赖数组)
在 writeDigitalHumanDraft({...}) 对象里(约 line 462),imageWorkflow, 后加 apiVideoWorkflow,;
在该 useEffect 的依赖数组里(约 line 480),imageWorkflow, 后同样加 apiVideoWorkflow,。
- Step 4: 提交 payload 加字段(~line 570 payload 对象)
找到 payload 对象里的 media_workflow: imageWorkflow || undefined,(约 line 575),其后加:
api_video_workflow: apiVideoWorkflow || undefined,
- Step 5: 加「视频工作流」选择器 UI(图片工作流 select 之后,~line 1012)
找到「图片工作流」那个 <label className="digital-human-field">...select...</label> 块结束处
(约 line 1012,</label> 后),插入新选择器:
<label className="digital-human-field">
<span>视频工作流(可选,生成说话视频)</span>
<select value={apiVideoWorkflow} onChange={(event) => setApiVideoWorkflow(event.target.value)}>
<option value="">不生成视频(仅图片合成)</option>
{mediaWorkflows
.filter((wf) => wf.name.toLowerCase().includes('video'))
.map((wf) => (
<option key={workflowValue(wf)} value={workflowValue(wf)}>{pickItemLabel(wf)}{wf.source ? ` · ${wf.source}` : ''}</option>
))}
</select>
</label>
- Step 6: typecheck
Run: cd /root/metapi && npm run typecheck:web 2>&1 | tail -5
Expected: 无 TS 错误。
- Step 7: Commit
cd /root/metapi && git add src/web/pages/DigitalHuman.tsx
git commit -m "feat(digital-human): 前端加视频工作流选择器(api_video_workflow)
Co-Authored-By: Claude <noreply@anthropic.com>"
Task 2: BoosAPI 后端转发 api_video_workflow 给 Pixelle
Files:
-
Modify:
src/routes/digital_human.rs -
Step 1: 在 pixelle_request_body 加转发(~line 2077,tts_workflow 块之后)
找到 pixelle_request_body 里转发 tts_workflow 的块(约 line 2073-2078):
if let Some(value) = optional_string(body, &["ttsWorkflow", "tts_workflow"])
.or_else(|| default_pixelle_tts_workflow(state, backend_provider))
{
request_body["tts_workflow"] = json!(value);
}
在它之后插入:
if let Some(value) = optional_string(body, &["apiVideoWorkflow", "api_video_workflow"]) {
request_body["api_video_workflow"] = json!(value);
}
- Step 2: 构建确认编译
Run: cd /root/metapi && cargo build -j 2 2>&1 | tail -3
Expected: Finished。
- Step 3: 确认 optional_string 接受多 key(它已在文件内大量使用,签名兼容)
Run: cd /root/metapi && rtk proxy grep -n "fn optional_string" src/routes/digital_human.rs | head
Expected: 找到定义,签名为 (body, keys: &[&str])(与 Step 1 用法一致)。若签名不同,按实际调整调用形式。
- Step 4: Commit
cd /root/metapi && git add src/routes/digital_human.rs
git commit -m "feat(digital-human): 后端转发 api_video_workflow 给 Pixelle
Co-Authored-By: Claude <noreply@anthropic.com>"
Task 3: Pixelle 给 comfy 视频工作流注入 audio_path
Files:
-
Modify(容器内):
/app/pixelle_video/pipelines/asset_based.py -
Step 1: 定位音频注入块(~line 703)
Run: rtk proxy docker exec pixelle-video-api sh -lc "grep -n 'audio_driven_i2v' /app/pixelle_video/pipelines/asset_based.py"
Expected: 命中 if "audio_driven_i2v" in adapter_abilities: 那行(约 703)。
- Step 2: 在该判断旁加 comfy 前缀分支(用 python 精确改写)
rtk proxy docker exec pixelle-video-api /app/.venv/bin/python -c "
p='/app/pixelle_video/pipelines/asset_based.py'
src=open(p).read()
anchor=' if \"audio_driven_i2v\" in adapter_abilities:\n api_video_params[\"audio_path\"] = frame.audio_path'
assert anchor in src, 'anchor not found'
add=anchor + '''
elif isinstance(api_video_workflow, str) and api_video_workflow.startswith(\"comfy/\"):
api_video_params[\"audio_path\"] = frame.audio_path'''
if 'api_video_workflow.startswith(\"comfy/\")' in src:
print('already patched')
else:
src=src.replace(anchor, add, 1)
open(p,'w').write(src)
print('patched')
"
Expected: patched(或 already patched)。
- Step 3: 语法校验 + 重启 + 备份
rtk proxy docker exec pixelle-video-api /app/.venv/bin/python -c "import ast; ast.parse(open('/app/pixelle_video/pipelines/asset_based.py').read()); print('syntax OK')"
cd /opt/Pixelle-Video && rtk proxy docker compose restart api && sleep 7 && rtk proxy docker ps --filter name=pixelle --format '{{.Names}} {{.Status}}'
mkdir -p /opt/Pixelle-Video/patches && rtk proxy docker cp pixelle-video-api:/app/pixelle_video/pipelines/asset_based.py /opt/Pixelle-Video/patches/asset_based.py.patched
Expected: syntax OK;容器 healthy;备份文件存在。
- Step 4: 确认改动重启后仍在
Run: rtk proxy docker exec pixelle-video-api sh -lc "grep -c 'api_video_workflow.startswith(\"comfy/\")' /app/pixelle_video/pipelines/asset_based.py"
Expected: 1。无 git commit(Pixelle 非本仓库)。
Task 4: 部署 BoosAPI + 端到端联调
Files: 无(部署 + 运行时验证)
- Step 1: 重新构建并重启 BoosAPI(含前端改动)
前端改了需重新 build 前端资源,后端改了需重新编译。用项目脚本:
cd /root/metapi && ./build-and-run.sh --fast-release 2>&1 | tail -15
若只想快速验证后端逻辑、前端单独 build,可
npm run build:web+./build-and-run.sh --backend-only。 Expected: 构建成功,BoosAPI 起在 :4000。注意这是动线上服务,确认当前无关键流量再重启。
- Step 2: 确认数字人 UI 出现「视频工作流」选择器
打开管理控制台数字人页面,确认新增「视频工作流(可选)」下拉,选项含
video_digital_ltx2(comfy)+ video_wan2.1_fusionx(comfy)等 video_* 工作流。
- Step 3: 发起数字人任务,视频工作流选
comfy/video_digital_ltx2.json
给肖像图 + 文本 + 选 TTS,视频工作流选 comfy/video_digital_ltx2.json,提交。
- Step 4: 监控流转(BoosAPI 日志 + Comfy Cloud job)
cd /root/metapi && rtk proxy sqlite3 boosapi.db "SELECT id, created_at, client_family, http_status, substr(error_message,1,80) FROM proxy_logs ORDER BY id DESC LIMIT 5;"
Expected: 新日志(id 增长),数字人任务推进;Comfy Cloud 出现 LTX2.3 job;最终出说话视频。
-
Step 5: 出错归因
-
LoadImage 仍用默认图 → 查 media.py image_path 转发(Task 已完成,确认
grep image_path /app/pixelle_video/services/media.py)。 -
LoadAudio 无音频 → 查 Task 3 注入(
grep comfy/ /app/pixelle_video/pipelines/asset_based.py)+ workflow 标记$~audio_path!。 -
api_video_workflow没传到 → 查 Task 2 后端转发 + Task 1 前端 payload 字段名(api_video_workflow)。 -
节点/模型错 → 不应发生(probe 已过);若发生看 Comfy Cloud 真实回包。
-
Step 6: 成功标准
数字人任务选 comfy/video_digital_ltx2.json 后,Comfy Cloud 出真实 job,注入了 image_path+audio_path+prompt,返回带音频说话视频,数字人成片。
完成标准
- 前端:数字人页有「视频工作流」可选下拉,列 video_* 工作流,typecheck 干净。
- 后端:
api_video_workflow透传给 Pixelle,cargo build -j 2通过。 - Pixelle:comfy 视频工作流注入 audio_path,重启生效,备份 patches/。
- 端到端:选 comfy/video_digital_ltx2.json 出说话视频。
- 向后兼容:不选视频工作流时,现有「图片+HTML 合成」行为不变。
已知风险 / 备注
- Pixelle asset_based.py 改动在镜像内置层,重建镜像会丢,已备份 patches/,长期应固化 Dockerfile。
- Task 4 动线上服务(重启 BoosAPI),确认时机。
- 单人肖像;多人不在范围。
- LTX2.3 执行时长/分辨率等真实生成参数,若出片质量/超时问题属调参,非本计划的接线问题。