# 视频项目模型

<cite>
**本文引用的文件**
- [video-generator.types.ts](file://server/src/modules/video-generator/video-generator.types.ts)
- [video-generator.service.ts](file://server/src/modules/video-generator/video-generator.service.ts)
- [video-generator.controller.ts](file://server/src/modules/video-generator/video-generator.controller.ts)
- [video-generator.ffmpeg.ts](file://server/src/modules/video-generator/video-generator.ffmpeg.ts)
- [schema.prisma](file://server/prisma/schema.prisma)
- [video-generator.ts](file://my-uniapp-vue3/src/types/video-generator.ts)
- [video-generator-api.ts](file://my-uniapp-vue3/src/utils/video-generator-api.ts)
- [storage.service.ts](file://server/src/services/storage.service.ts)
- [websocket.service.ts](file://server/src/services/websocket.service.ts)
</cite>

## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)

## 简介
本文件面向AI有声书生成平台的“视频项目模型”，系统性阐述VideoProject模型的字段设计、生命周期状态机、与书籍/章节的关联关系、配置管理与参数传递机制，并提供创建、更新、查询、生成等操作的实现要点与最佳实践。同时给出视频文件的存储、压缩与分发策略，帮助开发者在前后端协同下高效构建视频生成能力。

## 项目结构
视频项目相关的核心代码分布在后端模块与前端类型/工具层：
- 后端模块
  - 类型与数据模型：video-generator.types.ts
  - 业务逻辑：video-generator.service.ts
  - 控制器路由：video-generator.controller.ts
  - FFmpeg封装：video-generator.ffmpeg.ts
  - 数据库模型：Prisma schema.prisma
  - 存储与分发：storage.service.ts
  - 实时通知：websocket.service.ts
- 前端类型与API
  - 类型定义：video-generator.ts
  - API封装：video-generator-api.ts

```mermaid
graph TB
subgraph "后端"
Types["类型定义<br/>video-generator.types.ts"]
Service["业务逻辑<br/>video-generator.service.ts"]
Controller["控制器<br/>video-generator.controller.ts"]
FFMPEG["FFmpeg封装<br/>video-generator.ffmpeg.ts"]
Prisma["数据库模型<br/>schema.prisma"]
Storage["存储服务<br/>storage.service.ts"]
WS["WebSocket服务<br/>websocket.service.ts"]
end
subgraph "前端"
FE_Types["类型定义<br/>video-generator.ts"]
FE_API["API封装<br/>video-generator-api.ts"]
end
FE_API --> Controller
Controller --> Service
Service --> FFMPEG
Service --> Prisma
Service --> Storage
Service --> WS
Types --> Service
Types --> Controller
Types --> FFMPEG
FE_Types --> FE_API
```

图表来源
- [video-generator.types.ts:1-308](file://server/src/modules/video-generator/video-generator.types.ts#L1-L308)
- [video-generator.service.ts:1-556](file://server/src/modules/video-generator/video-generator.service.ts#L1-L556)
- [video-generator.controller.ts:1-244](file://server/src/modules/video-generator/video-generator.controller.ts#L1-L244)
- [video-generator.ffmpeg.ts:1-300](file://server/src/modules/video-generator/video-generator.ffmpeg.ts#L1-L300)
- [schema.prisma:194-218](file://server/prisma/schema.prisma#L194-L218)
- [video-generator.ts:1-116](file://my-uniapp-vue3/src/types/video-generator.ts#L1-L116)
- [video-generator-api.ts:1-188](file://my-uniapp-vue3/src/utils/video-generator-api.ts#L1-L188)

章节来源
- [video-generator.types.ts:1-308](file://server/src/modules/video-generator/video-generator.types.ts#L1-L308)
- [video-generator.service.ts:1-556](file://server/src/modules/video-generator/video-generator.service.ts#L1-L556)
- [video-generator.controller.ts:1-244](file://server/src/modules/video-generator/video-generator.controller.ts#L1-L244)
- [video-generator.ffmpeg.ts:1-300](file://server/src/modules/video-generator/video-generator.ffmpeg.ts#L1-L300)
- [schema.prisma:194-218](file://server/prisma/schema.prisma#L194-L218)
- [video-generator.ts:1-116](file://my-uniapp-vue3/src/types/video-generator.ts#L1-L116)
- [video-generator-api.ts:1-188](file://my-uniapp-vue3/src/utils/video-generator-api.ts#L1-L188)

## 核心组件
- VideoProject模型（数据库）
  - 字段与约束：见Prisma模型定义与类型定义
  - 关联关系：与Book、BookChapter的外键关联
- 配置模型
  - VideoConfig：包含图片、音频、背景音乐、字幕、视频参数、全局Ken Burns等
  - 预设配置：portrait/landscape/square三套预设
- 生命周期状态
  - draft、processing、completed、failed
- 生成流程
  - 从章节音频优先获取，支持带/不带BGM两种合成路径
  - 生成完成后回写项目与章节状态并推送WebSocket事件

章节来源
- [schema.prisma:194-218](file://server/prisma/schema.prisma#L194-L218)
- [video-generator.types.ts:75-93](file://server/src/modules/video-generator/video-generator.types.ts#L75-L93)
- [video-generator.types.ts:214-275](file://server/src/modules/video-generator/video-generator.types.ts#L214-L275)
- [video-generator.service.ts:154-312](file://server/src/modules/video-generator/video-generator.service.ts#L154-L312)

## 架构总览
视频项目从“创建—生成—回写—分发”的全链路如下：

```mermaid
sequenceDiagram
participant FE as "前端应用"
participant API as "控制器<br/>video-generator.controller.ts"
participant Svc as "业务逻辑<br/>video-generator.service.ts"
participant DB as "数据库<br/>Prisma schema.prisma"
participant FF as "FFmpeg封装<br/>video-generator.ffmpeg.ts"
participant ST as "存储服务<br/>storage.service.ts"
participant WS as "WebSocket服务<br/>websocket.service.ts"
FE->>API : 创建视频项目
API->>Svc : createVideoProject()
Svc->>DB : 插入VideoProject(draft, progress=0)
DB-->>Svc : 新项目记录
Svc-->>API : 返回项目(含config解析)
API-->>FE : 成功响应
FE->>API : 开始生成
API->>Svc : generateVideoForProject()
Svc->>DB : 更新status=processing, progress=0
Svc->>FF : generateVideo()/generateVideoWithBgm()
FF-->>Svc : 输出视频元数据(duration,size)
Svc->>DB : 更新status=completed, progress=100, outputUrl,duration,fileSize
Svc->>DB : 若有chapterId, 更新章节videoUrl/videoDuration
Svc->>WS : 推送video_generation_complete事件
API-->>FE : 返回outputUrl/duration/fileSize
```

图表来源
- [video-generator.controller.ts:44-129](file://server/src/modules/video-generator/video-generator.controller.ts#L44-L129)
- [video-generator.service.ts:33-57](file://server/src/modules/video-generator/video-generator.service.ts#L33-L57)
- [video-generator.service.ts:157-312](file://server/src/modules/video-generator/video-generator.service.ts#L157-L312)
- [video-generator.ffmpeg.ts:23-118](file://server/src/modules/video-generator/video-generator.ffmpeg.ts#L23-L118)
- [schema.prisma:194-218](file://server/prisma/schema.prisma#L194-L218)
- [websocket.service.ts:81-86](file://server/src/services/websocket.service.ts#L81-L86)

## 详细组件分析

### VideoProject模型字段设计与约束
- 主键与标识
  - id：自增主键
- 用户与归属
  - userId：可空，关联用户
  - bookId/chapterId：可空，直接关联书籍与章节
- 基础信息
  - title、description、coverUrl
- 配置与产物
  - configJson：序列化后的VideoConfig
  - outputUrl：生成视频的访问地址
  - duration、fileSize：生成后回填
- 状态与进度
  - status：枚举值draft/processing/completed/failed
  - progress：百分比
  - errorMsg：失败原因
- 时间戳
  - createdAt、updatedAt

字段约束与校验要点
- configJson必须为合法JSON字符串；解析失败时应降级为空配置
- status默认draft，progress默认0
- outputUrl在生成完成后回填，需确保路径可访问
- 与Book/BookChapter的外键关系允许为NULL，便于独立项目或跨章节生成

章节来源
- [schema.prisma:194-218](file://server/prisma/schema.prisma#L194-L218)
- [video-generator.types.ts:97-115](file://server/src/modules/video-generator/video-generator.types.ts#L97-L115)
- [video-generator.types.ts:279-292](file://server/src/modules/video-generator/video-generator.types.ts#L279-L292)
- [video-generator.service.ts:39-56](file://server/src/modules/video-generator/video-generator.service.ts#L39-L56)

### 生命周期状态机
状态流转
- draft → processing：开始生成
- processing → completed：生成成功
- processing → failed：生成异常
- draft → failed：配置缺失或素材不可用

```mermaid
stateDiagram-v2
[*] --> 草稿
草稿 --> 处理中 : "开始生成"
处理中 --> 完成 : "成功"
处理中 --> 失败 : "异常"
完成 --> [*]
失败 --> [*]
```

图表来源
- [video-generator.types.ts:8-9](file://server/src/modules/video-generator/video-generator.types.ts#L8-L9)
- [video-generator.service.ts:171-173](file://server/src/modules/video-generator/video-generator.service.ts#L171-L173)
- [video-generator.service.ts:293-299](file://server/src/modules/video-generator/video-generator.service.ts#L293-L299)

章节来源
- [video-generator.types.ts:8-9](file://server/src/modules/video-generator/video-generator.types.ts#L8-L9)
- [video-generator.service.ts:157-312](file://server/src/modules/video-generator/video-generator.service.ts#L157-L312)

### 配置模型与参数传递
- VideoConfig组成
  - images：图片数组，每张含URL、显示时长、转场、可选Ken Burns
  - audio：音频URL、起止截取、音量
  - bgm：可选，含URL、音量、循环、淡入淡出
  - subtitle：可选，文本、字号、颜色、背景色、位置、边距、样式
  - video：分辨率、帧率、码率、格式
  - kenburns：全局开关与缩放范围
- 预设配置
  - portrait/landscape/square三套模板，便于快速生成
- 参数传递
  - 前端通过VideoConfig对象提交
  - 后端将VideoConfig序列化为configJson存库
  - 生成时从数据库读取并反序列化为运行时配置

章节来源
- [video-generator.types.ts:75-93](file://server/src/modules/video-generator/video-generator.types.ts#L75-L93)
- [video-generator.types.ts:214-275](file://server/src/modules/video-generator/video-generator.types.ts#L214-L275)
- [video-generator.types.ts:279-292](file://server/src/modules/video-generator/video-generator.types.ts#L279-L292)
- [video-generator-api.ts:10-26](file://my-uniapp-vue3/src/utils/video-generator-api.ts#L10-L26)

### 与书籍/章节的关联关系
- 直接关联
  - VideoProject.bookId → Book
  - VideoProject.chapterId → BookChapter
- 生成时优先策略
  - 若项目包含chapterId，则优先从章节表读取audioUrl与content，作为音频与字幕内容来源
- 回写行为
  - 生成完成后，若存在chapterId，同步更新章节videoUrl与videoDuration

章节来源
- [schema.prisma:211-212](file://server/prisma/schema.prisma#L211-L212)
- [video-generator.service.ts:192-202](file://server/src/modules/video-generator/video-generator.service.ts#L192-L202)
- [video-generator.service.ts:271-283](file://server/src/modules/video-generator/video-generator.service.ts#L271-L283)

### 视频生成流程与实现要点
- 输入准备
  - 校验项目状态与必要素材（图片URL、音频URL）
  - 将URL统一转换为本地文件路径并检查存在性
- 生成执行
  - 无BGM：调用generateVideo
  - 有BGM：先下载BGM至临时目录，再调用generateVideoWithBgm
  - 多图轮播：generateSlideshow
- 输出与回写
  - 生成完成后计算duration与fileSize，回写数据库
  - 若关联章节，同步更新章节视频信息
  - 推送WebSocket事件，通知前端
- 错误处理
  - 捕获异常，回写status=failed与errorMsg
  - 推送失败事件

```mermaid
flowchart TD
Start(["开始生成"]) --> CheckProj["读取项目与状态"]
CheckProj --> StatusOK{"状态为draft/processing?"}
StatusOK --> |processing| ErrBusy["返回已在生成中"]
StatusOK --> |draft| UpdateProc["更新为processing(progress=0)"]
UpdateProc --> LoadCfg["加载配置(configJson)"]
LoadCfg --> HasMedia{"图片/音频可用?"}
HasMedia --> |否| ErrMedia["返回缺少素材"]
HasMedia --> |是| Paths["转换URL为本地路径并校验存在"]
Paths --> GenType{"是否包含BGM?"}
GenType --> |是| GenBGM["下载BGM并生成(带BGM)"]
GenType --> |否| Gen["生成(无BGM)"]
GenBGM --> WriteBack["回写结果: url,duration,size,status=completed,progress=100"]
Gen --> WriteBack
WriteBack --> UpdateChapter{"是否关联章节?"}
UpdateChapter --> |是| UpdChap["更新章节videoUrl/videoDuration"]
UpdateChapter --> |否| SkipChap["跳过"]
UpdChap --> Notify["推送WebSocket事件"]
SkipChap --> Notify
Notify --> End(["完成"])
ErrBusy --> End
ErrMedia --> End
```

图表来源
- [video-generator.service.ts:164-312](file://server/src/modules/video-generator/video-generator.service.ts#L164-L312)
- [video-generator.ffmpeg.ts:23-118](file://server/src/modules/video-generator/video-generator.ffmpeg.ts#L23-L118)
- [video-generator.ffmpeg.ts:123-199](file://server/src/modules/video-generator/video-generator.ffmpeg.ts#L123-L199)

章节来源
- [video-generator.service.ts:154-312](file://server/src/modules/video-generator/video-generator.service.ts#L154-L312)
- [video-generator.ffmpeg.ts:1-300](file://server/src/modules/video-generator/video-generator.ffmpeg.ts#L1-L300)

### FFmpeg参数与压缩策略
- 视频编码
  - 编码器：libx264
  - 预设：fast
  - CRF：18（质量优先）
  - 像素格式：yuv420p（兼容性）
- 音频编码
  - 编码器：aac
  - 码率：192k
- 滤镜链
  - Ken Burns：zoompan（动态缩放）
  - 缩放与填充：scale + pad（保持比例并居中）
  - 字幕：drawtext（按位置渲染）
- 混音
  - amix：将主音频与BGM混合，取最长时长

章节来源
- [video-generator.ffmpeg.ts:38-98](file://server/src/modules/video-generator/video-generator.ffmpeg.ts#L38-L98)
- [video-generator.ffmpeg.ts:169-186](file://server/src/modules/video-generator/video-generator.ffmpeg.ts#L169-L186)

### 存储、压缩与分发策略
- 本地存储
  - 输出视频存放于public/videos，访问路径为/videos/{filename}
  - 素材下载至temp/images或temp/audio临时目录
- OSS存储（可选）
  - 通过storage.service.ts统一抽象，支持OSS与本地无缝切换
  - 提供上传/下载/删除/签名URL等能力
- 压缩与分发
  - 采用H.264+AAC组合，CRF 18兼顾画质与体积
  - 生成完成后回写duration与fileSize，便于前端展示与统计
  - 可结合CDN加速公开视频资源

章节来源
- [video-generator.ffmpeg.ts:11-18](file://server/src/modules/video-generator/video-generator.ffmpeg.ts#L11-L18)
- [video-generator.service.ts:236-237](file://server/src/modules/video-generator/video-generator.service.ts#L236-L237)
- [storage.service.ts:1-278](file://server/src/services/storage.service.ts#L1-L278)

### API与操作示例（路径指引）
- 创建视频项目
  - 后端：POST /api/video/projects
  - 前端：createVideoProject()
- 查询项目列表
  - 后端：GET /api/video/projects
  - 前端：getVideoProjects()
- 获取项目详情
  - 后端：GET /api/video/projects/:id
  - 前端：getVideoProject()
- 更新项目
  - 后端：PUT /api/video/projects/:id
  - 前端：updateVideoProject()
- 删除项目
  - 后端：DELETE /api/video/projects/:id
  - 前端：deleteVideoProject()
- 开始生成
  - 后端：POST /api/video/projects/:id/generate
  - 前端：generateVideo()
- 获取生成进度
  - 后端：GET /api/video/projects/:id/status
  - 前端：getGenerateProgress()
- 从书籍生成项目
  - 后端：POST /api/video/books/:bookId/generate
  - 前端：createVideoProjectFromBook()

章节来源
- [video-generator.controller.ts:28-140](file://server/src/modules/video-generator/video-generator.controller.ts#L28-L140)
- [video-generator-api.ts:78-187](file://my-uniapp-vue3/src/utils/video-generator-api.ts#L78-L187)

## 依赖分析
- 模块耦合
  - controller依赖service；service依赖types、ffmpeg、prisma、storage、websocket
  - ffmpeg封装与配置解耦，便于扩展其他合成引擎
- 外部依赖
  - fluent-ffmpeg：视频合成
  - Prisma：数据库ORM
  - WebSocket：实时事件推送
- 潜在风险
  - 生成流程阻塞IO，建议引入队列异步化
  - FFmpeg命令行依赖系统环境，需容器化部署保证一致性

```mermaid
graph LR
Controller["控制器"] --> Service["业务逻辑"]
Service --> Types["类型定义"]
Service --> FFMPEG["FFmpeg封装"]
Service --> Prisma["Prisma模型"]
Service --> Storage["存储服务"]
Service --> WS["WebSocket服务"]
```

图表来源
- [video-generator.controller.ts:1-244](file://server/src/modules/video-generator/video-generator.controller.ts#L1-L244)
- [video-generator.service.ts:1-556](file://server/src/modules/video-generator/video-generator.service.ts#L1-L556)
- [video-generator.types.ts:1-308](file://server/src/modules/video-generator/video-generator.types.ts#L1-L308)
- [video-generator.ffmpeg.ts:1-300](file://server/src/modules/video-generator/video-generator.ffmpeg.ts#L1-L300)
- [schema.prisma:1-470](file://server/prisma/schema.prisma#L1-L470)
- [storage.service.ts:1-278](file://server/src/services/storage.service.ts#L1-L278)
- [websocket.service.ts:1-136](file://server/src/services/websocket.service.ts#L1-L136)

章节来源
- [video-generator.controller.ts:1-244](file://server/src/modules/video-generator/video-generator.controller.ts#L1-L244)
- [video-generator.service.ts:1-556](file://server/src/modules/video-generator/video-generator.service.ts#L1-L556)

## 性能考虑
- IO与CPU瓶颈
  - FFmpeg合成为CPU密集型任务，建议使用专用GPU或容器资源限制
- 异步化
  - 将生成放入队列，避免阻塞HTTP请求
- 缓存与复用
  - 重复素材可缓存至临时目录，减少网络下载
- 并发控制
  - 限制同一用户的并发生成数量，防止资源争抢
- CDN与分发
  - 使用CDN加速public/videos下的视频资源

## 故障排查指南
常见问题与定位
- 项目不存在或状态异常
  - 检查项目ID与状态；避免重复触发生成
- 缺少必要素材
  - 确认images与audio.url存在且可访问
- FFmpeg命令失败
  - 查看stderr日志；确认系统已安装ffmpeg
- WebSocket未收到事件
  - 检查/upgrade路径与clientId参数；确认wss实例已初始化
- 存储异常
  - 若使用OSS，检查凭证与Bucket权限；本地存储检查目录权限

章节来源
- [video-generator.service.ts:166-173](file://server/src/modules/video-generator/video-generator.service.ts#L166-L173)
- [video-generator.service.ts:204-206](file://server/src/modules/video-generator/video-generator.service.ts#L204-L206)
- [video-generator.service.ts:291-311](file://server/src/modules/video-generator/video-generator.service.ts#L291-L311)
- [websocket.service.ts:102-133](file://server/src/services/websocket.service.ts#L102-L133)
- [storage.service.ts:252-272](file://server/src/services/storage.service.ts#L252-L272)

## 结论
VideoProject模型以清晰的字段设计与严格的生命周期管理为基础，配合灵活的配置体系与稳健的FFmpeg合成流程，实现了从书籍章节到视频的自动化生产。通过Prisma的外键约束与WebSocket的实时通知，系统在数据一致性与用户体验上取得平衡。建议后续引入队列异步化与容器化部署，进一步提升稳定性与可扩展性。

## 附录
- 关键实现路径参考
  - VideoProject创建：[video-generator.service.ts:33-57](file://server/src/modules/video-generator/video-generator.service.ts#L33-L57)
  - 视频生成主流程：[video-generator.service.ts:157-312](file://server/src/modules/video-generator/video-generator.service.ts#L157-L312)
  - FFmpeg合成实现：[video-generator.ffmpeg.ts:23-118](file://server/src/modules/video-generator/video-generator.ffmpeg.ts#L23-L118)
  - WebSocket事件推送：[websocket.service.ts:81-86](file://server/src/services/websocket.service.ts#L81-L86)
  - 前端API封装：[video-generator-api.ts:78-187](file://my-uniapp-vue3/src/utils/video-generator-api.ts#L78-L187)