This commit is contained in:
2026-07-24 13:05:57 +08:00
parent fc1e880fcc
commit 23c8a4c1ba
77 changed files with 1987 additions and 1408 deletions
+485
View File
@@ -0,0 +1,485 @@
# Video Factory 项目文档
## 概述
Video Factory 是一个 AI 驱动的短视频自动生成平台。用户创建短剧项目,配置演员/场景/道具等素材,通过 AI 生成剧集脚本并调用视频生成 API 自动产出视频。
---
## 技术栈
| 层 | 技术 |
|---|------|
| 语言 | Go 1.22+ |
| Web 框架 | GoFrame v2 (github.com/gogf/gf/v2) |
| 数据库 | SQLite(通过 GoFrame ORM |
| 认证 | JWT (golang-jwt/jwt/v5) |
| 密码 | bcrypt (golang.org/x/crypto/bcrypt) |
| AI 模型 | OpenAI 兼容 API(可对接 DeepSeek/Kimi/Qwen 等) |
| 前端 | Vue 3 + Vitevideo-factory-ui |
---
## 项目结构
```
video-factory/
├── main.go # 入口:路由注册、静态文件、启动轮询
├── common/
│ └── http/
│ └── http.go # RouteRegister — 自动注册路由
├── shortdrama/
│ ├── controller/ # HTTP 控制器层(17 个)
│ │ ├── drama_controller.go # 短剧 CRUD
│ │ ├── scene_controller.go # 场景 CRUD
│ │ ├── character_controller.go # 演员 CRUD
│ │ ├── prop_controller.go # 道具 CRUD
│ │ ├── bgm_controller.go # 背景音 CRUD
│ │ ├── episode_controller.go # 剧集 CRUD + 脚本生成
│ │ ├── generation_controller.go # 视频生成/轮询/分段
│ │ ├── user_controller.go # 用户登录/改密
│ │ ├── agent_controller.go # 代理商管理
│ │ ├── customer_controller.go # 客户管理
│ │ ├── transaction_controller.go # 交易记录
│ │ ├── payment_order_controller.go # 支付订单
│ │ ├── payment_channel_trade_controller.go # 支付渠道流水
│ │ ├── payment_config_controller.go # 支付配置
│ │ ├── model_config_controller.go # 模型配置
│ │ ├── user_model_config_controller.go # 用户模型配置
│ │ └── region_pricing_controller.go # 区域定价
│ ├── service/ # 业务逻辑层(17 个)
│ │ ├── drama_service.go # 短剧 CRUD + 工作空间管理
│ │ ├── scene_service.go # 场景
│ │ ├── character_service.go # 演员(含文件保存)
│ │ ├── prop_service.go # 道具
│ │ ├── background_music_service.go # 背景音
│ │ ├── episode_service.go # 剧集 + AI 脚本生成
│ │ ├── generation_service.go # 视频生成核心流水线
│ │ ├── user_service.go # 登录/JWT
│ │ ├── agent_service.go # 代理商
│ │ ├── customer_service.go # 客户
│ │ ├── transaction_service.go # 交易
│ │ ├── payment_order_service.go # 支付(微信/支付宝/线下)
│ │ ├── payment_channel_trade_service.go # 渠道流水
│ │ ├── payment_config_service.go # 支付配置
│ │ ├── model_config_service.go # 模型配置(缓存)
│ │ ├── user_model_config_service.go # 用户模型配置(合并系统+用户)
│ │ └── region_pricing_service.go # 区域定价(缓存)
│ ├── dao/ # 数据访问层(17 个,每表一个)
│ │ ├── drama_dao.go
│ │ ├── scene_dao.go
│ │ ├── character_dao.go
│ │ ├── episode_dao.go
│ │ ├── prop_dao.go
│ │ ├── background_music_dao.go
│ │ ├── generation_task_dao.go
│ │ ├── user_dao.go
│ │ ├── agent_profile_dao.go
│ │ ├── customer_profile_dao.go
│ │ ├── account_transaction_dao.go
│ │ ├── payment_order_dao.go
│ │ ├── payment_channel_trade_dao.go
│ │ ├── payment_config_dao.go
│ │ ├── model_config_dao.go
│ │ ├── user_model_config_dao.go
│ │ └── region_pricing_dao.go
│ ├── model/
│ │ ├── entity/ # 数据库实体(每表一个)
│ │ ├── dto/ # 请求/响应结构体(含 g.Meta 路由信息)
│ │ ├── domain/ # 领域模型
│ │ │ └── shot.go # 镜头模型 + 镜头转文本方法
│ │ ├── agent_output.go # AI Agent 输出解析
│ │ └── segment_output.go # 分段生成输出类型
│ ├── agent/ # AI Agent 模块
│ │ ├── types.go # 类型定义
│ │ ├── chat_model.go # LLM API 调用(OpenAI 兼容)
│ │ ├── react_agent.go # ReAct 智能体引擎
│ │ ├── tools.go # Agent 工具集
│ │ └── context.go # Agent 上下文
│ ├── middleware/
│ │ └── auth_middleware.go # JWT 鉴权中间件
│ ├── config/
│ │ └── shot_duration.go # 镜头时长提示词
│ └── consts/
│ ├── public/
│ │ ├── table_name.go # 数据库表名常量
│ │ └── content_type.go # 内容类型/字段定义
│ └── status.go # 剧集/任务状态常量
└── workspace/ # 上传文件存储目录
```
---
## 架构模式
分层结构:**Controller → Service → DAO → SQLite**
```
HTTP 请求
Controller(接收请求、参数校验、返回响应)
Service(业务逻辑、事务管理、AI 调用)
DAO(数据访问、ORM 操作)
SQLite
```
- 每一层都是独立的包,通过包级变量暴露单例(如 `var DramaService = new(dramaService)`
- 每张数据库表对应一个 DAO、一个 Service、一个 Controller17×17 一对一映射)
### 路由注册机制
`RouteRegister``common/http/http.go`)通过反射获取结构体名,转为 kebab-case 作为 URL 前缀:
```go
type scene struct{} // → 前缀 /scene
type modelConfig struct{} // → 前缀 /model-config
```
GoFrame v2 将 Controller 方法名转为 kebab-case 拼接到前缀后:
```go
// scene_controller.go
func (c *scene) List(ctx, req) GET /scene/list
func (c *scene) Add(ctx, req) POST /scene/add
```
完整路由表(详见下方 API 章节)。
---
## 数据库
使用 SQLite`init()` 函数自动建表,支持旧表迁移(ALTER TABLE ADD COLUMN 兼容)。
### 短剧相关表(6 张)
| 表名 | 实体 | 说明 |
|------|------|------|
| `short_drama` | Drama | 短剧项目(标题/类型/时长/分辨率/配置) |
| `short_drama_episode` | Episode | 剧集(序号/标题/脚本/状态/视频URL) |
| `short_drama_character` | Character | 演员(名称/描述/声音文件/形象文件) |
| `short_drama_scene` | Scene | 场景(名称/描述/图片) |
| `short_drama_prop` | Prop | 道具(名称/描述/图片) |
| `short_drama_background_music` | BackgroundMusic | 背景音乐(名称/文件) |
### 生成任务表(1 张)
| 表名 | 说明 |
|------|------|
| `short_drama_generation_task` | 视频生成任务(剧集/分段/状态/任务ID/脚本/模型名) |
### 用户/代理商/客户表(3 张)
| 表名 | 说明 |
|------|------|
| `user` | 用户(角色:admin/agent/customer |
| `agent_profile` | 代理商资料(最大客户数/到期时间/区域保护) |
| `customer_profile` | 客户资料(关联代理商/余额) |
### 支付相关表(3 张)
| 表名 | 说明 |
|------|------|
| `payment_order` | 支付订单(用户/金额/渠道/状态/类型) |
| `payment_channel_trade` | 渠道流水(支付单号/渠道单号/状态) |
| `payment_config` | 支付配置(渠道/商户ID/密钥) |
### 其他表(4 张)
| 表名 | 说明 |
|------|------|
| `short_drama_model_config` | 模型配置(系统级,模型列表/参数) |
| `user_model_config` | 用户模型配置(用户自定义 API Key/模型选择) |
| `account_transaction` | 账户交易流水(充值/扣费) |
| `region_pricing` | 区域定价(省份/地区/套餐/价格) |
---
## API 路由表
所有请求均需 JWT 鉴权(除 `/user/login`),统一 JSON 响应格式 `{"code":0,"message":"OK","data":...}`
### 短剧管理
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/drama/list` | 短剧列表(分页) |
| POST | `/drama/create` | 创建短剧 |
| GET | `/drama/get` | 短剧详情(含关联演员/场景/道具/背景音) |
| POST | `/drama/update` | 更新短剧 |
| POST | `/drama/delete` | 删除短剧(级联删除关联数据) |
| GET | `/drama/field-definitions` | 获取内容类型字段定义 |
### 场景
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/scene/list` | 场景列表 |
| POST | `/scene/add` | 添加场景(支持上传图片) |
| POST | `/scene/update` | 更新场景 |
| POST | `/scene/delete` | 删除场景 |
### 演员
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/character/list` | 演员列表 |
| POST | `/character/add` | 添加演员(支持上传声音/形象) |
| POST | `/character/update` | 更新演员 |
| POST | `/character/delete` | 删除演员 |
### 道具
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/prop/list` | 道具列表 |
| POST | `/prop/add` | 添加道具 |
| POST | `/prop/update` | 更新道具 |
| POST | `/prop/delete` | 删除道具 |
### 背景音乐
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/bgm/list` | 背景音乐列表 |
| POST | `/bgm/add` | 添加背景音乐 |
| POST | `/bgm/update` | 更新背景音乐 |
| POST | `/bgm/delete` | 删除背景音乐 |
### 剧集
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/episode/list` | 剧集列表(分页) |
| POST | `/episode/add` | 添加剧集 |
| POST | `/episode/update` | 更新剧集 |
| POST | `/episode/delete` | 删除剧集 |
| POST | `/episode/generate-script` | AI 生成脚本 |
### 视频生成
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | `/generation/generate` | 提交一集视频生成任务 |
| GET | `/generation/poll` | 轮询生成状态 |
| GET | `/generation/episode/task` | 获取剧集所有生成任务 |
| POST | `/generation/segment/continue` | 继续分段生成(含反馈) |
| POST | `/generation/segment/feedback` | 分段反馈 |
### 用户
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | `/user/login` | 登录(公开路径) |
| POST | `/user/change-password` | 修改密码 |
### 模型配置
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/model-config/get-model-list` | 模型列表 |
| POST | `/model-config/save-model-config` | 保存模型配置 |
| GET | `/user-model-config/get-user-config` | 获取用户模型配置 |
| POST | `/user-model-config/save-user-config` | 保存用户模型配置 |
| GET | `/user-model-config/get-user-model-list` | 用户可用模型列表 |
### 支付
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | `/payment-order/prepay` | 创建支付订单 |
| GET | `/payment-order/status` | 查询支付状态 |
| POST | `/payment-order/confirm-offline` | 线下确认 |
| ALL | `/payment-order/notify-wechat` | 微信回调 |
| ALL | `/payment-order/notify-alipay` | 支付宝回调 |
| GET | `/payment-channel-trade/list-by-order` | 订单渠道流水 |
| GET | `/payment-config/get` | 支付配置 |
| POST | `/payment-config/save` | 保存支付配置 |
### 代理商/客户/交易
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/agent/list` | 代理商列表 |
| POST | `/agent/create` | 创建代理商 |
| POST | `/agent/update` | 更新代理商 |
| ALL | `/agent/get` | 代理商详情 |
| POST | `/agent/create-renew-order` | 创建续费订单 |
| GET | `/agent/list-renewals` | 续费记录 |
| GET | `/customer/list` | 客户列表 |
| POST | `/customer/create` | 创建客户 |
| POST | `/customer/update` | 更新客户 |
| ALL | `/customer/detail` | 客户详情 |
| GET | `/transaction/list` | 交易流水 |
| POST | `/transaction/recharge` | 充值 |
### 区域定价
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/region-pricing/list` | 定价列表 |
| POST | `/region-pricing/save` | 保存定价 |
| ALL | `/region-pricing/delete` | 删除定价 |
| ALL | `/region-pricing/regions` | 区域列表 |
| ALL | `/region-pricing/cascades` | 级联数据 |
---
## 核心业务流程
### 1. 创建短剧
```
用户创建短剧 → 填写标题/类型/时长 → 添加演员/场景/道具/背景音 → 添加剧集
```
- 短剧内容类型:短剧、漫剧、广告视频
- 创建时自动创建 workspace 目录结构
### 2. 生成脚本
```
用户选择剧集 → 点击"生成脚本"
→ 系统加载短剧上下文(演员/场景/道具列表)
→ 调用 LLM chat completion(简单对话,非 ReAct
→ 模型返回 JSON 格式的镜头数组(Shot[]
→ 解析验证,失败则重试修正
```
每个镜头包含:时间起止、画面描述、台词、旁白、运镜、景别、出演人物、场景、道具。
### 3. 生成视频(核心流程)
```
用户选择剧集 → 点击"生成视频"
┌─ 1. 余额检查(客户角色)并预扣费
├─ 2. 按视频模型约束将剧集时长拆分为多段(15-60s/段)
├─ 3. 并行或串行生成每段:
│ ├─ a. 如果脚本是 JSON 镜头格式 → 直接按时间提取段内容
│ ├─ b. 否则 → ReAct Agent 循环(最多 15 步):
│ │ 思考 → 工具调用 → 观察结果 → 最终输出
│ │ 工具:parse_script / analyze_script_for_episode / generate_scene_image
│ ├─ c. 解析 Agent 输出为 SegmentOutput
│ ├─ d. 提取角色/场景参考图片
│ ├─ e. 构建视频 API 请求体并提交
│ └─ f. 保存 video_task_id
├─ 4. 串行模式下等待前段完成(用于首帧参考)
└─ 5. 后台轮询(每 15s)检查视频生成状态
```
#### 分段策略(`calcSegDurs`
根据视频模型的最大时长限制,将整集拆分为若干段:
- 短剧(默认):每段 15-60 秒
- 漫剧:每段 15-30 秒
- 广告视频:整段 15-60 秒
#### ReAct Agent 工具
| 工具 | 功能 |
|------|------|
| `parse_script` | 将原始剧本按 `---` 拆分为多集,提取标题和内容 |
| `analyze_script_for_episode` | 分析单集剧本,按空行拆分为场景,识别出场演员 |
| `generate_scene_image` | 从场景库中匹配图片返回 base64 |
### 4. 视频模型对接
项目通过 OpenAI 兼容 API 对接视频生成模型。流程:
1. 构建请求体(含角色参考图URL、场景图片、脚本描述)
2. POST 提交视频生成任务
3. 轮询任务状态(pending → generating → completed/failed
4. 完成后拼接各段视频为最终输出
---
## 权限与角色
| 角色 | 说明 |
|------|------|
| `admin` | 管理员,查看所有数据 |
| `agent` | 代理商,管理名下客户,查看区域客户数据 |
| `customer` | 客户,仅查看自己的数据,生成视频扣费 |
登录默认账号:
- admin / Tongli686^*^(管理员)
- test1 / Tongli686^*^(代理商)
---
## AI Agent 模块
### 架构
```
agent/
├── types.go # ChatMessage/ToolInfo/ToolCall 类型定义
├── chat_model.go # OpenAI 兼容 API 调用(含重试/限流处理)
├── react_agent.go # ReAct 循环引擎(思考→行动→观察→重复)
├── tools.go # 工具注册与实现
└── context.go # 上下文(DramaID 注入)
```
### 调用模式
**简单 Chat Completion**(脚本生成用):
```
System Prompt + User Input → LLM → JSON 输出
```
**ReAct Agent**(视频生成用):
```
System Prompt + User Input
→ LLM 思考 → 工具调用(parse_script → 观察结果
→ LLM 思考 → 工具调用(analyze_script_for_episode → 观察结果
→ LLM 思考 → 工具调用(generate_scene_image → 观察结果
→ LLM 最终回答 → 输出 JSON
```
最大 15 步循环,支持指数退避重试。
---
## JWT 认证
- Token 在 `/user/login` 获取
- 所有请求(除 `/user/login`)需在 Header 携带 `Authorization: Bearer <token>`
- 中间件从 token 解析 `userId``role``agentId` 注入请求上下文
- 过期时间默认 7 天
---
## 文件存储
上传文件统一存储在 `workspace/{短剧标题}/` 目录下:
```
workspace/{短剧标题}/
├── 产出视频/
├── 演员形象/
├── 演员声音/
├── 场景/
├── 道具/
└── 背景音乐/
```
---
## 配置
- `config.yml`:镜头时长规则(按内容类型)、画风约束
- `.env`:开发环境代理目标(前端项目)
- 用户模型配置存数据库 `short_drama_model_config``user_model_config`
### 模型配置继承
```
系统模型配置(short_drama_model_config
└── 用户模型配置(user_model_config,可选覆盖 API Key/模型选择)
└── GetMergedConfig() 合并两者,用户配置优先
```
系统配置 + 用户配置 → `MergedModelConfig`(运行时最终配置)
+251
View File
@@ -0,0 +1,251 @@
# Video Factory 后端项目缺陷与优化说明
> 基于当前代码实际扫描(2026-07-24 最新)。已在此会话中修复的项不重复列出。
---
## 一、安全缺陷
### 1.1 JWT 密钥硬编码
**文件**: `shortdrama/service/user_service.go:15`
```go
const jwtSecret = "video-factory-jwt-secret-2024"
```
密钥硬编码源码中,所有部署共用同一密钥。泄露后可用任意用户 Token 伪造身份。
**修复**: 从环境变量 `JWT_SECRET` 读取。
**严重程度**: 🔴 严重
---
### 1.2 支付签名使用 MD5
**文件**: `shortdrama/service/payment_order_service.go:362,447`
- 微信支付使用 MD5 签名(微信推荐 HMAC-SHA256
- 支付宝使用 `md5.Sum([]byte(raw + privateKey))` 而非标准 RSA2
**严重程度**: 🔴 严重
---
### 1.3 支付通知 URL 为空
**文件**: `shortdrama/service/payment_order_service.go:309,384`
```go
"notify_url": "", // 需要实际外网可访问地址
```
微信和支付宝通知地址均为空,支付渠道无法回调通知订单状态变更。
**严重程度**: 🔴 严重
---
### 1.4 支付回调错误被静默忽略
**文件**: `shortdrama/controller/payment_order_controller.go:67,76`
```go
_ = service.PaymentService.HandleNotify(ctx, "wechat", body)
```
`HandleNotify` 返回值被忽略,即使处理失败也返回 `SUCCESS`,支付渠道不会重试,可能导致资金损失。
**严重程度**: 🔴 严重
---
### 1.5 微信支付 IP 写死
**文件**: `shortdrama/service/payment_order_service.go:308`
```go
"spbill_create_ip": "127.0.0.1",
```
全部走 localhost 可能触发微信风控。
**严重程度**: 🟠 重要
---
### 1.6 API Key 明文写入日志
**文件**: `shortdrama/service/episode_service.go:216`
```go
g.Log().Warningf(ctx, "... ApiKey=%q ...", modelCfg.ApiKey)
```
模型 API Key 在日志中明文输出。
**严重程度**: 🟠 重要
---
### 1.7 订单号随机性弱
**文件**: `shortdrama/service/payment_order_service.go:290`
```go
r := rand.Intn(10000) // 仅 10000 种
return fmt.Sprintf("PAY%s%04d", now.Format("20060102150405"), r)
```
使用 `math/rand`(非加密安全),同一秒内仅 10000 种订单号,高并发可重复。
**严重程度**: 🟠 重要
---
### 1.8 支付 nonce 使用 math/rand
**文件**: `shortdrama/service/payment_order_service.go:457`
```go
b[i] = letters[rand.Intn(len(letters))]
```
nonce 可被预测。
**严重程度**: 🟠 重要
---
### 1.9 CORS 未限制来源
**文件**: `common/http/http.go:28`
```go
r.Response.CORS(r.Response.DefaultCORSOptions())
```
允许所有来源跨域访问。
**严重程度**: 🟠 重要
---
### 1.10 客户默认密码为手机号后 6 位
**文件**: `shortdrama/service/customer_service.go:57-61`
默认密码 = 手机号后 6 位,且 `bcryptGenerate` 错误被忽略(失败时密码为空)。
**严重程度**: 🟠 重要
---
### 1.11 API Key 明文存储
**文件**: `shortdrama/dao/payment_config_dao.go:25`, `dao/user_model_config_dao.go:34,71`
支付 API Key、AppSecret、PrivateKey 及用户模型 API Key 在 SQLite 中明文存储。
**严重程度**: 🟠 重要
---
## 二、严重逻辑缺陷
### 2.1 并行模式永久死代码
**文件**: `shortdrama/service/generation_service.go:95`
```go
// 注释说"默认使用并行生成模式"
mode = "serial"
```
`mode` 参数被无条件覆盖为 `"serial"`,下方完整的并行 goroutine 代码行(约 30 行)完全不可达。注释与行为矛盾。
**严重程度**: 🔴 严重
---
## 三、代码质量问题
### 3.1 generation_service.go 文件过大
**文件**: `shortdrama/service/generation_service.go`2688 行,60+ 个函数)
职责涵盖:Agent 调用、视频提交/合并、ffmpeg 操作、轮询引擎、缓存、prompt 构建、上下文构建、文件操作等。
**建议**: 拆分为 `generation.go``poller.go``prompt.go``fileops.go``ffmpeg.go`
**严重程度**: 🟡 中等
---
## 四、架构与设计问题
### 4.1 DAO 用 init() 执行 DDL 迁移
**文件**: `shortdrama/dao/*dao.go`17 个文件)
DDL 散落在 `init()` 中,执行顺序依赖包导入顺序,SQLite `DROP COLUMN` 被静默忽略,无回滚,无超时,不可测试。
**建议**: 使用 migrate/sqlite 等迁移工具统一管理。
**严重程度**: 🟠 重要
---
### 4.2 缺少审计日志
所有 CRUD 操作(短剧、演员、场景、代理商、充值等)均无审计记录。充值无操作人身份记录。
**建议**: 关键操作记录 `(actor_id, action, target_type, target_id, detail)`
**严重程度**: 🟡 中等
---
### 4.3 视频轮询器无指数退避
**文件**: `shortdrama/service/generation_service.go:1630`
```go
ticker := time.NewTicker(15 * time.Second)
```
恒定 15s 轮询,任务长时间 RUNNING 时无谓消耗 DB。
**建议**: 实现指数退避(15s → 30s → 60s → 120s)。
**严重程度**: 🟡 中等
---
## 五、测试覆盖
### 5.1 无单元测试
约 100+ `.go` 文件,`_test.go` 数量为 **0**。Agent 调用、分段算法、支付签名、权限校验、DAO 操作等核心逻辑均无覆盖。
**严重程度**: 🟠 重要
---
### 5.2 无集成测试
API 端点无集成测试,无法验证路由、参数解析、响应格式。DDL 迁移完全不可测试。
**严重程度**: 🟡 中等
---
## 严重程度汇总
| 级别 | 含义 | 数量 |
|------|------|------|
| 🔴 严重 | 安全性/功能性问题 | 5 |
| 🟠 重要 | 有实际风险 | 12 |
| 🟡 中等 | 代码质量/架构 | 4 |
| 🟢 轻微 | 代码整洁性 | 0 |