# 数字人接入 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。 --- ## 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)** 找到「图片工作流」那个 `` 块结束处 (约 line 1012,`` 后),插入新选择器: ```tsx ``` - [ ] **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 " ``` ## 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 " ``` ## 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 非本仓库)。 ## 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 执行时长/分辨率等真实生成参数,若出片质量/超时问题属调参,非本计划的接线问题。