191 lines
6.8 KiB
Markdown
191 lines
6.8 KiB
Markdown
# AiVideo Architecture Guide
|
||
|
||
## 1. 项目目标与当前定位
|
||
|
||
该项目是一个 AIGC 视频 POC,核心能力是把用户 prompt 转成三分镜短视频,并通过 Node API 流式返回进度与结果。当前实现已经覆盖:
|
||
|
||
- 分镜生成(`script`)
|
||
- 单分镜润色(`refine`)
|
||
- 视频渲染与合成(`render`)
|
||
- `task_id` 级别隔离输出(`outputs/{task_id}/`)
|
||
- Docker 内置 ComfyUI + Node + Python 联动
|
||
- 启动时自检(Comfy 可达性 + workflow/节点约束)
|
||
|
||
整体设计是「Node 作为编排/网关,Python 作为生成引擎」。
|
||
|
||
## 2. 目录与职责
|
||
|
||
- `server/`:Node API + SSE 网关 + 启动自检入口
|
||
- `engine/`:Python 生成引擎(LLM 分镜、TTS、Comfy、MoviePy 合成)
|
||
- `scripts/`:Comfy 连通性和 workflow 约束检查
|
||
- `configs/config.yaml`:运行时配置(Comfy 地址、模型、workflow 映射等)
|
||
- `docker-compose.yml`:`aivideo` + `comfyui` 双服务部署
|
||
- `dev.sh`:本地开发启动/日志/重建封装
|
||
- `outputs/{task_id}/`:任务级产物目录(分镜、润色结果、最终视频)
|
||
|
||
## 3. 运行架构(容器级)
|
||
|
||
- `aivideo` 服务
|
||
- 运行 Node (`server/index.js`)
|
||
- Node 通过 `spawn` 调用 Python(`python -m engine.main`)
|
||
- 对外暴露 `3000`
|
||
- `comfyui` 服务
|
||
- 默认镜像:`jamesbrink/comfyui:latest`
|
||
- 对外暴露 `8188`
|
||
- 挂载 `./ComfyUI/*` 到容器 `/comfyui/*`
|
||
- 服务连接
|
||
- `aivideo` 通过 `http://comfyui:8188` 访问 ComfyUI API(容器内 DNS)
|
||
|
||
## 4. 应用架构(进程级)
|
||
|
||
### 4.1 Node 层(`server/index.js`)
|
||
|
||
职责:
|
||
|
||
- 提供 HTTP/SSE 接口
|
||
- 统一生成 `task_id` 并创建输出目录
|
||
- 把请求参数透传给 Python 引擎
|
||
- 把 Python stdout 协议行转成 SSE 事件
|
||
- 启动前执行自检(`check_comfy.py` + `inspect_comfy_node.py`)
|
||
|
||
主要接口:
|
||
|
||
- `GET /api/health`
|
||
- `GET /api/script`(SSE)
|
||
- `POST /api/refine`(JSON)
|
||
- `POST /api/render`(SSE)
|
||
- `GET /api/static/...`(输出视频静态托管,禁缓存)
|
||
|
||
并发策略(当前):
|
||
|
||
- 渲染接口使用单全局锁 `isBusy`(同一时刻只允许一个渲染)
|
||
|
||
### 4.2 Python 引擎层(`engine/main.py`)
|
||
|
||
职责:
|
||
|
||
- 解析参数并分发 `step`:`script/refine/render`
|
||
- 处理全局风格与角色注入
|
||
- 与 OpenAI、ComfyUI、TTS、MoviePy 协同
|
||
- 按协议输出进度与结构化结果(`SCENE_JSON`、`PROG`、`RENDER_DONE`)
|
||
|
||
子模块职责:
|
||
|
||
- `engine/script_gen.py`:LLM 分镜生成与润色
|
||
- `engine/audio_gen.py`:Edge TTS 合成旁白
|
||
- `engine/comfy_client.py`:提交 workflow、轮询 history、提取产物
|
||
- `engine/video_editor.py`:字幕叠加 + 转场 + 最终拼接
|
||
- `engine/config.py`:YAML 配置读取
|
||
|
||
## 5. 核心流程
|
||
|
||
### 5.1 Script 生成
|
||
|
||
1. Node 收到 `GET /api/script`
|
||
2. 生成 `task_id`,创建 `outputs/{task_id}`
|
||
3. Node spawn Python `--step script`
|
||
4. Python 调 LLM 生成三分镜(无 key 时可 mock fallback)
|
||
5. Python 输出多行 `SCENE_JSON ...`
|
||
6. Node 将其转发为 SSE `scene` 事件
|
||
|
||
### 5.2 Refine 润色
|
||
|
||
1. Node 收到 `POST /api/refine`
|
||
2. 透传当前 scenes/scene 到 Python stdin
|
||
3. Python 调 LLM 润色指定分镜
|
||
4. 返回 `SCENE_JSON`,Node 组装 JSON 响应
|
||
|
||
### 5.3 Render 渲染
|
||
|
||
1. Node 收到 `POST /api/render`(SSE)
|
||
2. 全局 `isBusy` 判定是否可渲染
|
||
3. Python 先做 TTS(并发),再逐分镜调 Comfy
|
||
4. 收集视频 + 音频,MoviePy 合成 `final.mp4`
|
||
5. Python 输出 `PROG` 进度与 `RENDER_DONE`
|
||
6. Node 转发 SSE 完成事件
|
||
|
||
## 6. 关键设计约束
|
||
|
||
- `task_id` 必须贯穿 API 与引擎,保证产物隔离
|
||
- 启动自检失败时,服务不启动(fail fast)
|
||
- workflow 参数注入基于:
|
||
- 明确 node_id,或
|
||
- class_type fallback 自动定位
|
||
- 全局风格/角色必须双重注入:
|
||
- LLM prompt 约束
|
||
- 渲染前 image_prompt 装饰(character + style + scene)
|
||
|
||
## 7. 当前架构优势
|
||
|
||
- **职责拆分清晰**:Node 编排、Python 算法,边界明确
|
||
- **可观测性较好**:SSE 实时进度 + 结构化协议行
|
||
- **生产思路正确**:自检机制避免“半可用”状态
|
||
- **兼容能力强**:mock 路径可脱离 Comfy/LLM 快速调通
|
||
|
||
## 8. 主要架构风险与优化方向
|
||
|
||
### P0(优先处理)
|
||
|
||
1. **作业状态只在内存**
|
||
- 问题:Node 重启后任务状态丢失,前端不可恢复
|
||
- 建议:引入任务元数据存储(SQLite/Redis),记录状态机(queued/running/succeeded/failed)
|
||
|
||
2. **单点渲染锁 `isBusy`**
|
||
- 问题:无法扩展并发;请求高峰体验差
|
||
- 建议:升级为队列模型(本地队列或 Redis/BullMQ),支持排队和取消
|
||
|
||
3. **SSE 协议基于字符串前缀**
|
||
- 问题:协议演进脆弱,难版本化
|
||
- 建议:统一 JSON line 协议(字段:`type`, `task_id`, `ts`, `payload`, `version`)
|
||
|
||
### P1(中期)
|
||
|
||
4. **配置与环境耦合较松散**
|
||
- 建议:增加 config schema 校验(pydantic/JSON schema),启动即检查缺项与类型
|
||
|
||
5. **Comfy 产物识别依赖 history + 文件存在**
|
||
- 建议:扩展更稳定的完成判定(WebSocket event 或更严格 history 状态判断)
|
||
|
||
6. **缺少全链路 trace id**
|
||
- 建议:在 Node/Python/Comfy 请求中统一注入 `task_id` 和 `request_id`
|
||
|
||
### P2(长期)
|
||
|
||
7. **引擎内聚度可再提升**
|
||
- 建议:把 `script/refine/render` 拆成独立 use-case 模块,CLI 仅作参数适配
|
||
|
||
8. **测试体系不足**
|
||
- 建议:
|
||
- 单元测试:config、workflow 注入、scene 解析
|
||
- 集成测试:mock 渲染链路
|
||
- 冒烟测试:Docker 启动 + `/api/health`
|
||
|
||
## 9. 推荐重构路线(4 周)
|
||
|
||
- 第 1 周:任务状态持久化 + API 状态查询接口(`/api/tasks/:id`)
|
||
- 第 2 周:渲染队列化(先单 worker),替换 `isBusy`
|
||
- 第 3 周:统一事件协议(JSON line + version),前后端同时改
|
||
- 第 4 周:补测试与可观测(结构化日志、错误码、性能指标)
|
||
|
||
## 10. 建议新增接口(便于运维和前端)
|
||
|
||
- `GET /api/tasks/:task_id`:任务状态与阶段信息
|
||
- `POST /api/tasks/:task_id/cancel`:取消任务
|
||
- `GET /api/tasks/:task_id/artifacts`:列出产物路径和类型
|
||
- `GET /api/system/checks`:最近一次自检结果
|
||
|
||
## 11. 性能优化清单(先易后难)
|
||
|
||
- TTS 结果按文本 hash 缓存,避免重复合成
|
||
- 分镜视频生成支持失败重试与断点继续
|
||
- MoviePy 合成参数按场景切换(开发 `veryfast`,生产 `medium/slow`)
|
||
- 对 `outputs/` 增加清理策略(TTL + 最大磁盘占用阈值)
|
||
|
||
## 12. 你下一步可以直接做的事
|
||
|
||
1. 先落地任务持久化和状态查询(收益最大、侵入最小)
|
||
2. 再把 `isBusy` 改为队列(并保留单 worker)
|
||
3. 最后统一事件协议,减少前后端耦合与兼容风险
|
||
|
||
这份文档的目的不是重写现有实现,而是在保留当前可用链路的前提下,把系统逐步推进到可扩展的生产形态。
|