Files
BoosAPI/docs/superpowers/plans/2026-06-18-digital-human-comfy-video-entry.md
T
boos 53f99affec docs: 数字人 Comfy 视频入口实现计划(4 任务三层)
前端视频工作流选择器 → 后端转发 api_video_workflow → Pixelle comfy 注入 audio_path
→ 部署联调。视频入口可选、默认不启用、向后兼容。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-18 02:54:26 +08:00

242 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 数字人接入 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` — 加 `apiVideoWorkflow` state + 「视频工作流」选择器 + 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。
---
<!-- TASKS -->
## Task 1: 前端加「视频工作流」选择器 + 提交字段
**Files:**
- Modify: `src/web/pages/DigitalHuman.tsx`
- [ ] **Step 1: `DigitalHumanDraft` type 加字段(~line 34 附近,imageWorkflow 旁)**
找到 `imageWorkflow?: string;`(约 line 34),其后加一行:
```ts
apiVideoWorkflow?: string;
```
- [ ] **Step 2: 加 state(~line 370,imageWorkflow useState 旁)**
找到 `const [imageWorkflow, setImageWorkflow] = useState(draftRef.current.imageWorkflow || '');`(约 line 370),其后加:
```ts
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),其后加:
```ts
api_video_workflow: apiVideoWorkflow || undefined,
```
- [ ] **Step 5: 加「视频工作流」选择器 UI(图片工作流 select 之后,~line 1012)**
找到「图片工作流」那个 `<label className="digital-human-field">...select...</label>` 块结束处
(约 line 1012,`</label>` 后),插入新选择器:
```tsx
<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**
```bash
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>"
```
<!-- T2 -->
## 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):
```rust
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);
}
```
在它**之后**插入:
```rust
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**
```bash
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>"
```
<!-- T3 -->
## 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 精确改写)**
```bash
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: 语法校验 + 重启 + 备份**
```bash
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 非本仓库)。
<!-- T4 -->
## Task 4: 部署 BoosAPI + 端到端联调
**Files:** 无(部署 + 运行时验证)
- [ ] **Step 1: 重新构建并重启 BoosAPI(含前端改动)**
前端改了需重新 build 前端资源,后端改了需重新编译。用项目脚本:
```bash
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)**
```bash
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 执行时长/分辨率等真实生成参数,若出片质量/超时问题属调参,非本计划的接线问题。