Files
AiVideo/ARCHITECTURE.md
2026-03-25 13:43:00 +08:00

191 lines
6.8 KiB
Markdown
Raw Permalink 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.
# 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. 最后统一事件协议,减少前后端耦合与兼容风险
这份文档的目的不是重写现有实现,而是在保留当前可用链路的前提下,把系统逐步推进到可扩展的生产形态。