feat:优化架构

This commit is contained in:
Daniel
2026-03-25 13:43:00 +08:00
parent 8991f2a2d7
commit a2f224d01f
7 changed files with 509 additions and 5 deletions

190
ARCHITECTURE.md Normal file
View File

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