Files
aivideo/docs/AI视频平台开发文档.md

82 KiB
Raw Blame History

AI视频平台开发文档

1. 项目目标

1.1 项目定位

建设一个类似 plotparty.ai 的 AI 视频生成平台,面向普通用户和内容创作者,提供以下能力:

  • 用户注册、登录、充值、查看积分余额
  • 用户通过密钥兑换积分
  • 用户可编辑用户名、头像等个人资料
  • 用户可创建自己的邀请链接或邀请码
  • 用户提交 AI 视频生成任务
  • 用户上传图片、音频、视频等参考素材
  • 用户可查看自己全部视频生成记录,并可自行删除记录
  • 平台根据后台配置调用不同第三方视频模型 API
  • 平台根据后台价格规则按秒对用户进行积分扣费
  • 管理员后台可配置多个视频模型供应商,并为每个前台视频模型绑定一个或多个供应商模型
  • 管理员后台可配置注册赠送积分、邀请奖励积分、邀请码功能是否开启
  • 管理员在后台配置 API、模型、积分价格、充值比例、套餐、公告和风控策略
  • 平台记录完整的任务、计费、充值、回调和操作日志

1.2 首期范围

首版建议聚焦下面 4 个核心闭环:

  1. 用户充值到账
  2. 用户发起视频生成任务
  3. 后端异步调用第三方模型并查询结果
  4. 管理员可动态调整模型、价格和充值配置

1.3 不在首版强制范围内

  • 社区广场、作品公开发布、点赞评论
  • 多租户代理分销
  • 多级分销返佣
  • 自研模型推理集群
  • 视频在线剪辑器
  • 高级工作流编排

这些能力可以在首版稳定后迭代。

2. 技术选型

2.1 最终建议

后端使用 Python,数据库使用 MySQL

2.2 选型理由

对于本项目,真正复杂的地方是:

  • 对接多个第三方 AI 视频 API
  • 长任务异步调度
  • 充值、扣费、退款和幂等控制
  • 后台频繁调整业务规则

这类场景更偏向“业务编排”和“集成开发”,不是 CPU 密集型高性能计算因此优先选择开发效率更高、AI 生态更成熟的 Python。

2.3 推荐技术栈

后端

  • Python 3.12
  • FastAPI
  • SQLAlchemy 2.0
  • Alembic
  • Pydantic v2
  • CeleryDramatiq
  • Redis
  • MySQL 8.0

前端

  • Next.js
  • React
  • TypeScript
  • Tailwind CSS
  • 用户端可用 shadcn/ui
  • 管理端可用 Ant Design

基础设施

  • Nginx
  • Docker / Docker Compose
  • 对象存储:MinIO / S3 / OSS / COS
  • 文件分发:CDN
  • 监控:Prometheus + Grafana
  • 错误追踪:Sentry

2.4 架构决策

服务形态

采用“前后端分离 + 单后端服务 + 异步任务 Worker”的结构。

API 风格

采用 REST API,首版不建议引入 GraphQL。

鉴权策略

用户端采用 JWT Access Token + Refresh Token
后台管理员使用单独的管理员账号体系和 RBAC 权限控制。

实时反馈方式

首版建议以“轮询任务状态”为主,后续可增加 SSE 推送。

项目结构

后端采用“按业务模块划分”的 feature-first 结构,避免 controller/service/repository 全项目散落。

3. 系统总体架构

3.1 逻辑架构

系统分为以下几个部分:

  1. 用户前台
  2. 管理后台
  3. 业务 API 服务
  4. 异步任务服务
  5. MySQL 数据库
  6. Redis 缓存与队列
  7. 对象存储
  8. 第三方支付服务
  9. 第三方 AI 视频模型服务

3.2 推荐部署结构

用户浏览器 / 管理后台
        |
      Nginx
        |
  -------------------------
  |                       |
Next.js Frontend      FastAPI Backend
                          |
          ----------------------------------
          |                |               |
        MySQL            Redis        Object Storage
                          |
                       Celery Worker
                          |
          ----------------------------------
          |                |               |
    OpenAI 官方格式    Seedance 格式      其他扩展格式

3.3 核心原则

  • 业务 API 不直接阻塞等待视频生成完成
  • 所有扣费必须有流水
  • 所有第三方回调必须幂等
  • 所有模型调用必须做抽象适配,不将业务逻辑直接耦合到某一家 API
  • 所有后台配置变更必须保留操作日志

4. 角色与权限

4.1 用户角色

  • 普通用户
  • 管理员
  • 超级管理员

4.2 普通用户能力

  • 注册 / 登录 / 退出
  • 查看个人资料
  • 修改用户名、头像、昵称
  • 兑换积分密钥
  • 创建和管理自己的邀请码 / 邀请链接
  • 查看邀请数据和奖励记录
  • 上传素材
  • 创建视频生成任务
  • 查看任务列表和详情
  • 删除自己的任务记录
  • 下载生成结果
  • 查看积分余额和流水
  • 发起充值

4.3 管理员能力

  • 管理用户
  • 查看充值订单
  • 查看视频任务
  • 配置积分兑换密钥
  • 配置注册赠送积分规则
  • 配置邀请奖励规则
  • 配置多个视频供应商账号
  • 配置供应商模型与平台模型
  • 配置价格规则
  • 配置充值套餐和充值赠送比例
  • 处理失败订单和人工补单
  • 查看回调日志、任务日志、系统日志

4.4 RBAC 权限模块

后台建议最少拆分以下权限:

  • user:view
  • user:edit
  • order:view
  • wallet:view
  • wallet:manual_adjust
  • task:view
  • task:retry
  • provider:view
  • provider:edit
  • pricing:view
  • pricing:edit
  • growth:view
  • growth:edit
  • redeem:view
  • redeem:edit
  • system:view
  • system:edit

5. 核心业务流程

5.1 用户充值流程

用户选择充值套餐
-> 创建充值订单
-> 跳转支付
-> 第三方支付回调
-> 校验签名与订单状态
-> 幂等更新订单为已支付
-> 增加用户积分钱包余额
-> 写入钱包流水
-> 返回支付结果

关键要求

  • 支付回调必须验签
  • 订单状态更新必须幂等
  • 钱包积分增加必须和订单状态更新在同一事务中
  • 同一订单只能入账一次

5.2 视频生成流程

用户提交生成参数
-> 校验模型是否启用
-> 计算预估积分费用
-> 校验积分余额
-> 冻结预扣积分
-> 创建本地任务记录
-> 投递异步任务
-> Worker 调用第三方视频生成 API
-> 保存第三方任务ID
-> 定时轮询任务状态
-> 成功后下载/转存结果
-> 按规则完成最终结算
-> 更新任务状态
-> 用户查看并下载结果

推荐结算策略

为了兼容不同模型与不同供应商格式,建议使用:

  • 提交任务时:冻结预扣积分
  • 任务成功时:正式扣减积分
  • 任务失败时:解冻积分
  • 若平台后续需要按供应商实际成本二次修正:执行补扣或退回积分差额

这样可以同时满足:

  • 用户提交前能看到大致费用
  • 平台可以控制风险
  • 后期支持不同模型差异化积分定价

5.3 后台价格配置流程

管理员配置模型价格规则
-> 配置是否启用
-> 选择平台视频模型
-> 配置每秒积分价格
-> 配置最低积分扣费
-> 配置生效时间和版本
-> 保存版本化价格配置
-> 新任务按最新生效版本计费

5.4 人工补单与钱包调整流程

管理员后台允许人工修正:

  • 充值成功但未到账
  • 任务失败需补偿
  • 手工赠送积分
  • 风控冻结后恢复

所有人工调整都必须:

  • 记录操作人
  • 记录原因
  • 记录前后积分
  • 写入钱包流水
  • 可审计

5.5 密钥兑换积分流程

用户输入兑换密钥
-> 后端校验密钥格式
-> 查询兑换密钥状态
-> 校验是否已使用、是否过期、是否禁用
-> 对兑换密钥记录加锁
-> 增加用户积分
-> 写入钱包流水
-> 标记兑换密钥为已使用
-> 写入兑换记录
-> 返回兑换结果

关键要求

  • 一个兑换密钥默认只能使用一次
  • 必须使用数据库事务 + 行锁防止重复兑换
  • 后台可生成批量兑换密钥或手动导入兑换密钥
  • 所有兑换失败原因必须明确记录

5.6 新用户注册赠送积分流程

用户完成注册
-> 后端读取注册赠送规则
-> 若规则开启,则给用户发放注册奖励积分
-> 写入钱包流水
-> 写入奖励发放记录

关键要求

  • 每个用户只能获得一次注册赠送
  • 注册赠送是否开启、赠送多少积分由后台控制
  • 注册赠送积分应有单独业务类型,不能与充值积分混淆

5.7 邀请奖励流程

推荐将邀请奖励触发条件定义为:

  • 新用户通过邀请码或邀请链接注册成功
  • 该新用户首次发生有效积分消费
  • 邀请人获得一次邀请奖励积分
新用户使用邀请码注册
-> 建立邀请关系
-> 新用户完成首次有效消费
-> 系统检查该邀请关系是否已发奖
-> 若未发奖且邀请奖励功能开启
-> 向邀请人发放积分奖励
-> 写入钱包流水
-> 更新邀请关系奖励状态

关键要求

  • 每个被邀请用户只能触发一次邀请奖励
  • 奖励应在“首次有效消费成功”后发放,而不是注册后立即发放
  • 有效消费建议定义为:首次 final_points > 0 且任务状态为 succeeded
  • 后台可控制是否开启邀请奖励以及奖励多少积分
  • 必须防刷,不能允许同设备批量注册反复薅奖励

5.8 视频记录删除规则

用户删除视频记录时,不建议物理删除数据库记录,建议采用“用户侧软删除”:

用户点击删除任务记录
-> 校验该任务属于当前用户
-> 更新任务记录为用户不可见
-> 保留后台审计信息和财务流水
-> 前台默认不再展示该记录

关键要求

  • 用户删除仅影响前台可见性,不影响后台审计
  • 已生成文件可按延迟清理策略处理,不建议立即物理删除
  • 充值、积分、奖励相关记录不得被用户删除

6. 第三方视频模型接入设计

6.1 基本原则

首版明确只支持两种视频 API 协议格式:

  • openai_official_video
  • seedance_video_generation

同时遵循以下原则:

  • 管理后台可以配置多个供应商账号
  • 一个供应商账号下可以配置多个供应商模型
  • 前台展示的是“平台视频模型”,不是直接暴露供应商模型
  • 一个平台视频模型可以绑定多个供应商模型,用于主备切换或故障回退
  • 业务层只面向统一适配器接口,不直接耦合 OpenAI 或 Seedance 原始协议

6.2 统一适配器接口

推荐抽象接口

class VideoProviderAdapter(Protocol):
    api_format: str

    def submit_task(self, payload: dict) -> SubmitResult: ...
    def query_task(self, external_task_id: str) -> QueryResult: ...
    def download_result(self, external_task_id: str, variant: str = "video") -> bytes: ...
    def cancel_task(self, external_task_id: str) -> CancelResult: ...
    def remix_task(self, external_task_id: str, payload: dict) -> SubmitResult: ...
    def normalize_webhook(self, payload: dict) -> CallbackResult: ...

6.3 OpenAI 官方视频格式适配说明

根据 OpenAI 官方文档,当前视频 API 的核心接口格式如下:

  • POST /v1/videos 创建视频生成任务
  • GET /v1/videos/{video_id} 查询任务状态
  • GET /v1/videos/{video_id}/content 下载最终视频内容
  • POST /v1/videos/{video_id}/remix 基于已有视频生成 remix
  • 支持 webhook 事件:video.completedvideo.failed

OpenAI 官方格式的关键特点:

  • 创建接口使用 multipart/form-data
  • 核心参数包括:promptmodelsecondssize
  • 可选 input_reference 图片作为首帧参考
  • 当前官方文档公开的模型包括 sora-2sora-2-pro
  • 任务状态主要包括 queuedin_progresscompletedfailed
  • 视频完成后通过 /content 下载,下载资产可能存在 expires_at
  • 支持 variant 下载派生资源,例如缩略图或 spritesheet

平台接入 OpenAI 官方格式时,后端需要注意:

  • 请求体不是 JSON而是 multipart/form-data
  • 参数校验要按 OpenAI 允许值做白名单校验
  • 完成后立即下载并转存到自己的对象存储
  • webhook 验签必须按 OpenAI 官方 webhook secret 做校验
  • 前台不要直接暴露 OpenAI 原始模型名和下载地址

OpenAI 官方格式示例

curl -X POST "https://api.openai.com/v1/videos" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: multipart/form-data" \
  -F 'prompt=A cinematic shot of a paper airplane flying through a neon city at night' \
  -F 'model=sora-2' \
  -F 'seconds=8' \
  -F 'size=1280x720' \
  -F 'input_reference=@frame.png;type=image/png'

典型返回结构:

{
  "id": "video_123",
  "object": "video",
  "model": "sora-2",
  "status": "queued",
  "progress": 0,
  "seconds": "8",
  "size": "1280x720"
}

6.4 Seedance 格式适配说明

根据你项目目录中的 Seedance_2.0_客户使用手册.docx,可确认其核心特点:

  • 通过 POST /v1/video/generations 创建异步生成任务
  • 通过 GET /v1/video/generations/{id} 查询状态
  • 支持 seedanceseedance-fast
  • 支持文本、图片、视频、音频组合输入
  • 支持 generate_audioratioduration
  • 生成结果需要尽快下载,文档里提到结果链接存在有效期

因此平台内部要统一做以下事情:

  • 提交任务后保存第三方任务 ID
  • 定时查询第三方任务状态
  • 成功后将结果文件转存到自己的对象存储
  • 不依赖第三方临时链接作为最终下载地址

Seedance 格式示例

{
  "model": "seedance",
  "content": [
    {
      "type": "text",
      "text": "夜晚的城市高架桥上,一辆银色跑车高速穿行,镜头跟拍,霓虹反光强烈。"
    },
    {
      "type": "image_url",
      "image_url": {
        "url": "https://example.com/reference.png"
      },
      "role": "reference_image"
    }
  ],
  "generate_audio": true,
  "ratio": "16:9",
  "duration": 8
}

典型查询接口:

GET /v1/video/generations/{task_id}

6.5 平台模型与供应商绑定设计

为了支持“多个供应商 + 每个前台视频单独定价”,数据结构上必须区分三层:

  1. 供应商账号:如 OpenAI 主账号、Seedance 主账号
  2. 供应商模型:如 sora-2sora-2-proseedanceseedance-fast
  3. 平台视频模型:用户前台看到的产品模型,如“标准视频”“高速视频”“高清视频”

推荐后台工作流:

  1. 先新增多个供应商账号
  2. 为每个供应商账号录入一个协议格式:openai_official_videoseedance_video_generation
  3. 在供应商账号下录入供应商模型
  4. 创建平台视频模型
  5. 将一个平台视频模型绑定一个或多个供应商模型
  6. 设置主供应商、优先级和故障切换顺序

首版建议使用最简单可控的优先级策略:

  • 同一个平台视频模型可以绑定多个供应商模型
  • 默认按优先级从高到低依次尝试
  • 主供应商失败、限流或超时后切换到下一个供应商
  • 前台价格不因供应商切换而变化,价格只绑定平台视频模型

6.6 模型差异抽象字段

后台配置中建议统一维护以下模型能力字段:

  • 是否支持文生视频
  • 是否支持图生视频
  • 是否支持首尾帧
  • 是否支持视频参考
  • 是否支持音频参考
  • 是否支持生成音频
  • 支持的分辨率
  • 支持的宽高比
  • 支持的时长范围
  • 默认时长
  • 单次最大文件数
  • 是否支持联网搜索

这样用户前台就能根据模型能力动态渲染表单。

7. 功能模块拆解

7.1 用户端

账户系统

  • 手机号 / 邮箱注册登录
  • 验证码登录
  • 密码登录
  • 忘记密码
  • 绑定手机号 / 邮箱
  • 设置用户名
  • 设置头像
  • 设置昵称

钱包系统

  • 当前积分余额
  • 冻结积分
  • 可用积分
  • 充值入口
  • 兑换码入口
  • 充值记录
  • 消费记录
  • 退款记录
  • 奖励记录

素材系统

  • 上传图片
  • 上传音频
  • 上传视频
  • 删除素材
  • 查看素材列表

视频任务系统

  • 创建任务
  • 查看任务进度
  • 查看失败原因
  • 查看结果视频
  • 再次生成
  • 复制参数重建任务
  • 删除自己的任务记录

邀请系统

  • 生成邀请码
  • 生成邀请链接
  • 查看邀请人数
  • 查看邀请奖励记录
  • 查看待奖励邀请用户

7.2 管理后台

控制台

  • 今日充值金额
  • 今日订单数
  • 今日任务数
  • 成功率
  • 用户增长
  • 模型调用分布

用户管理

  • 用户列表
  • 用户详情
  • 积分余额查看
  • 冻结/解冻用户
  • 人工调整积分
  • 查看邀请关系
  • 查看邀请码

充值管理

  • 充值订单列表
  • 订单状态筛选
  • 回调日志
  • 异常订单补偿

兑换密钥管理

  • 批量生成兑换密钥
  • 手动导入兑换密钥
  • 设置兑换积分数量
  • 设置有效期
  • 查看兑换记录
  • 禁用兑换密钥

视频任务管理

  • 任务列表
  • 任务状态筛选
  • 按模型筛选
  • 查看原始请求参数
  • 查看第三方返回
  • 重试任务
  • 标记补偿

供应商管理

  • 可配置多个供应商账号
  • 第三方平台名称
  • 协议格式类型
  • Base URL
  • API Key
  • Secret
  • Webhook Secret
  • 默认超时时间
  • 重试策略
  • 是否启用

供应商模型管理

  • 供应商模型名称
  • 供应商模型编码
  • 所属平台
  • 是否上架
  • 能力标签
  • 默认参数

平台视频模型管理

  • 平台模型名称
  • 前台展示名称
  • 绑定多个供应商模型
  • 默认路由供应商
  • 默认参数
  • 是否上架

价格配置管理

  • 按平台视频模型定价
  • 每秒积分价格
  • 最低积分扣费
  • 生效时间
  • 版本管理

增长奖励配置管理

  • 是否开启新用户注册送积分
  • 注册赠送积分数量
  • 是否开启邀请奖励
  • 邀请奖励积分数量
  • 邀请奖励触发条件说明

充值配置管理

  • 固定充值套餐
  • 赠送比例
  • 实付与到账换算比例
  • 活动时间范围
  • 是否启用

系统配置管理

  • 网站标题
  • 首页公告
  • 用户协议
  • 隐私政策
  • 上传大小限制
  • 允许的文件类型

8. 数据库设计

8.1 设计原则

  • 使用 MySQL 8.0
  • 人民币字段使用 DECIMAL(10,2),禁止使用浮点
  • 积分字段使用 BIGINT UNSIGNED
  • 主键使用 BIGINT UNSIGNED
  • 对外展示 ID 使用字符串型 public_id
  • 所有表保留 created_atupdated_at
  • 关键业务表加 deleted_at 实现软删除时要谨慎,钱包流水表不建议软删除

8.2 核心表清单

首版建议至少包含以下表:

  1. users
  2. user_auths
  3. admin_users
  4. roles
  5. permissions
  6. admin_user_roles
  7. wallets
  8. wallet_transactions
  9. growth_reward_rules
  10. redeem_codes
  11. invite_codes
  12. invite_relations
  13. recharge_plans
  14. recharge_orders
  15. payment_channels
  16. provider_accounts
  17. provider_models
  18. video_models
  19. video_model_supplier_bindings
  20. pricing_rules
  21. media_assets
  22. video_generation_tasks
  23. video_task_events
  24. callback_logs
  25. system_configs
  26. operation_logs

8.3 关键表设计

users

CREATE TABLE users (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  public_id VARCHAR(64) NOT NULL UNIQUE,
  username VARCHAR(64) NULL DEFAULT NULL,
  nickname VARCHAR(100) NOT NULL DEFAULT '',
  avatar_url VARCHAR(500) NOT NULL DEFAULT '',
  email VARCHAR(191) NOT NULL DEFAULT '',
  mobile VARCHAR(32) NOT NULL DEFAULT '',
  password_hash VARCHAR(255) NOT NULL DEFAULT '',
  status TINYINT NOT NULL DEFAULT 1 COMMENT '1正常 2禁用 3冻结',
  last_login_at DATETIME NULL,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  UNIQUE KEY uk_users_username (username),
  KEY idx_users_email (email),
  KEY idx_users_mobile (mobile),
  KEY idx_users_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

wallets

CREATE TABLE wallets (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  user_id BIGINT UNSIGNED NOT NULL,
  balance_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
  frozen_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
  total_recharged_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
  total_consumed_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
  total_refunded_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  UNIQUE KEY uk_wallets_user_id (user_id),
  CONSTRAINT fk_wallets_user_id FOREIGN KEY (user_id) REFERENCES users(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

wallet_transactions

CREATE TABLE wallet_transactions (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  transaction_no VARCHAR(64) NOT NULL UNIQUE,
  user_id BIGINT UNSIGNED NOT NULL,
  wallet_id BIGINT UNSIGNED NOT NULL,
  biz_type VARCHAR(32) NOT NULL COMMENT 'recharge/redeem_code/signup_reward/invite_reward/freeze/consume/refund/unfreeze/manual_adjust',
  direction VARCHAR(16) NOT NULL COMMENT 'in/out/freeze/unfreeze',
  amount_points BIGINT UNSIGNED NOT NULL,
  balance_before_points BIGINT UNSIGNED NOT NULL,
  balance_after_points BIGINT UNSIGNED NOT NULL,
  frozen_before_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
  frozen_after_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
  related_type VARCHAR(32) NOT NULL DEFAULT '',
  related_id BIGINT UNSIGNED NULL,
  remark VARCHAR(255) NOT NULL DEFAULT '',
  operator_type VARCHAR(16) NOT NULL DEFAULT 'system' COMMENT 'system/admin/user',
  operator_id BIGINT UNSIGNED NULL,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  KEY idx_wallet_tx_user_id (user_id),
  KEY idx_wallet_tx_biz_type (biz_type),
  KEY idx_wallet_tx_related (related_type, related_id),
  CONSTRAINT fk_wallet_tx_user_id FOREIGN KEY (user_id) REFERENCES users(id),
  CONSTRAINT fk_wallet_tx_wallet_id FOREIGN KEY (wallet_id) REFERENCES wallets(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

growth_reward_rules

CREATE TABLE growth_reward_rules (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  rule_type VARCHAR(32) NOT NULL COMMENT 'signup_reward/invite_reward',
  enabled TINYINT NOT NULL DEFAULT 0,
  reward_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
  trigger_condition VARCHAR(64) NOT NULL DEFAULT '' COMMENT 'on_register/on_first_consume',
  remark VARCHAR(255) NOT NULL DEFAULT '',
  updated_by_admin_id BIGINT UNSIGNED NULL,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  UNIQUE KEY uk_growth_reward_rules_type (rule_type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

redeem_codes

CREATE TABLE redeem_codes (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  batch_no VARCHAR(64) NOT NULL,
  redeem_code VARCHAR(64) NOT NULL UNIQUE,
  points BIGINT UNSIGNED NOT NULL,
  status VARCHAR(32) NOT NULL DEFAULT 'unused' COMMENT 'unused/used/expired/disabled',
  used_by_user_id BIGINT UNSIGNED NULL,
  wallet_transaction_id BIGINT UNSIGNED NULL,
  expired_at DATETIME NULL,
  used_at DATETIME NULL,
  created_by_admin_id BIGINT UNSIGNED NULL,
  remark VARCHAR(255) NOT NULL DEFAULT '',
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  KEY idx_redeem_codes_batch_no (batch_no),
  KEY idx_redeem_codes_status (status),
  KEY idx_redeem_codes_used_by_user_id (used_by_user_id),
  CONSTRAINT fk_redeem_codes_used_by_user_id FOREIGN KEY (used_by_user_id) REFERENCES users(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

invite_codes

CREATE TABLE invite_codes (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  user_id BIGINT UNSIGNED NOT NULL,
  invite_code VARCHAR(32) NOT NULL UNIQUE,
  invite_link VARCHAR(255) NOT NULL DEFAULT '',
  status TINYINT NOT NULL DEFAULT 1 COMMENT '1启用 0停用',
  is_default TINYINT NOT NULL DEFAULT 0,
  max_use_count INT UNSIGNED NULL,
  used_count INT UNSIGNED NOT NULL DEFAULT 0,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  KEY idx_invite_codes_user_id (user_id),
  KEY idx_invite_codes_status (status),
  CONSTRAINT fk_invite_codes_user_id FOREIGN KEY (user_id) REFERENCES users(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

invite_relations

CREATE TABLE invite_relations (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  inviter_user_id BIGINT UNSIGNED NOT NULL,
  invitee_user_id BIGINT UNSIGNED NOT NULL,
  invite_code_id BIGINT UNSIGNED NOT NULL,
  reward_status VARCHAR(32) NOT NULL DEFAULT 'pending' COMMENT 'pending/eligible/rewarded/invalid',
  reward_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
  first_consumed_task_id BIGINT UNSIGNED NULL,
  first_consumed_at DATETIME NULL,
  rewarded_at DATETIME NULL,
  reward_wallet_transaction_id BIGINT UNSIGNED NULL,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  UNIQUE KEY uk_invite_relations_invitee_user_id (invitee_user_id),
  KEY idx_invite_relations_inviter_user_id (inviter_user_id),
  KEY idx_invite_relations_reward_status (reward_status),
  CONSTRAINT fk_invite_relations_inviter_user_id FOREIGN KEY (inviter_user_id) REFERENCES users(id),
  CONSTRAINT fk_invite_relations_invitee_user_id FOREIGN KEY (invitee_user_id) REFERENCES users(id),
  CONSTRAINT fk_invite_relations_invite_code_id FOREIGN KEY (invite_code_id) REFERENCES invite_codes(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

recharge_plans

CREATE TABLE recharge_plans (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(100) NOT NULL,
  pay_amount DECIMAL(10,2) NOT NULL,
  point_ratio INT UNSIGNED NOT NULL DEFAULT 10 COMMENT '1元兑换多少积分',
  give_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
  bonus_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
  sort_order INT NOT NULL DEFAULT 0,
  status TINYINT NOT NULL DEFAULT 1,
  start_at DATETIME NULL,
  end_at DATETIME NULL,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  KEY idx_recharge_plans_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

recharge_orders

CREATE TABLE recharge_orders (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  order_no VARCHAR(64) NOT NULL UNIQUE,
  user_id BIGINT UNSIGNED NOT NULL,
  recharge_plan_id BIGINT UNSIGNED NULL,
  payment_channel_code VARCHAR(32) NOT NULL,
  pay_amount DECIMAL(10,2) NOT NULL,
  point_ratio_snapshot INT UNSIGNED NOT NULL,
  give_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
  bonus_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
  arrival_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
  currency VARCHAR(16) NOT NULL DEFAULT 'CNY',
  status VARCHAR(32) NOT NULL COMMENT 'pending/paid/failed/cancelled/refunded',
  third_party_order_no VARCHAR(100) NOT NULL DEFAULT '',
  paid_at DATETIME NULL,
  expired_at DATETIME NULL,
  callback_payload JSON NULL,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  KEY idx_recharge_orders_user_id (user_id),
  KEY idx_recharge_orders_status (status),
  KEY idx_recharge_orders_paid_at (paid_at),
  CONSTRAINT fk_recharge_orders_user_id FOREIGN KEY (user_id) REFERENCES users(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

provider_accounts

CREATE TABLE provider_accounts (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  provider_code VARCHAR(32) NOT NULL UNIQUE,
  provider_name VARCHAR(100) NOT NULL,
  api_format VARCHAR(64) NOT NULL COMMENT 'openai_official_video/seedance_video_generation',
  base_url VARCHAR(255) NOT NULL,
  api_key_encrypted TEXT NOT NULL,
  api_secret_encrypted TEXT NULL,
  webhook_secret_encrypted TEXT NULL,
  timeout_seconds INT NOT NULL DEFAULT 60,
  max_retries INT NOT NULL DEFAULT 3,
  status TINYINT NOT NULL DEFAULT 1,
  remark VARCHAR(255) NOT NULL DEFAULT '',
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  KEY idx_provider_accounts_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

provider_models

CREATE TABLE provider_models (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  provider_account_id BIGINT UNSIGNED NOT NULL,
  model_code VARCHAR(64) NOT NULL,
  model_name VARCHAR(100) NOT NULL,
  request_content_type VARCHAR(64) NOT NULL DEFAULT 'application/json',
  scene_type VARCHAR(32) NOT NULL DEFAULT 'video_generation',
  supports_text_to_video TINYINT NOT NULL DEFAULT 1,
  supports_image_to_video TINYINT NOT NULL DEFAULT 0,
  supports_video_reference TINYINT NOT NULL DEFAULT 0,
  supports_audio_reference TINYINT NOT NULL DEFAULT 0,
  supports_generate_audio TINYINT NOT NULL DEFAULT 0,
  supports_remix TINYINT NOT NULL DEFAULT 0,
  supports_webhook TINYINT NOT NULL DEFAULT 0,
  min_duration INT NOT NULL DEFAULT 4,
  max_duration INT NOT NULL DEFAULT 15,
  status TINYINT NOT NULL DEFAULT 1,
  default_ratio VARCHAR(20) NOT NULL DEFAULT '16:9',
  default_resolution VARCHAR(20) NOT NULL DEFAULT '720p',
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  UNIQUE KEY uk_provider_model (provider_account_id, model_code),
  KEY idx_provider_models_status (status),
  CONSTRAINT fk_provider_models_provider_account_id FOREIGN KEY (provider_account_id) REFERENCES provider_accounts(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

video_models

CREATE TABLE video_models (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  model_key VARCHAR(64) NOT NULL UNIQUE,
  model_name VARCHAR(100) NOT NULL,
  frontend_title VARCHAR(100) NOT NULL,
  frontend_description VARCHAR(255) NOT NULL DEFAULT '',
  default_duration_seconds INT NOT NULL DEFAULT 8,
  default_ratio VARCHAR(20) NOT NULL DEFAULT '16:9',
  default_resolution VARCHAR(20) NOT NULL DEFAULT '720p',
  status TINYINT NOT NULL DEFAULT 1,
  sort_order INT NOT NULL DEFAULT 0,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  KEY idx_video_models_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

video_model_supplier_bindings

CREATE TABLE video_model_supplier_bindings (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  video_model_id BIGINT UNSIGNED NOT NULL,
  provider_model_id BIGINT UNSIGNED NOT NULL,
  routing_priority INT NOT NULL DEFAULT 100,
  is_primary TINYINT NOT NULL DEFAULT 0,
  status TINYINT NOT NULL DEFAULT 1,
  timeout_seconds_override INT NULL,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  UNIQUE KEY uk_video_model_provider_model (video_model_id, provider_model_id),
  KEY idx_video_model_bindings_priority (video_model_id, routing_priority),
  CONSTRAINT fk_video_model_bindings_video_model_id FOREIGN KEY (video_model_id) REFERENCES video_models(id),
  CONSTRAINT fk_video_model_bindings_provider_model_id FOREIGN KEY (provider_model_id) REFERENCES provider_models(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

pricing_rules

CREATE TABLE pricing_rules (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  rule_name VARCHAR(100) NOT NULL,
  video_model_id BIGINT UNSIGNED NOT NULL,
  billing_mode VARCHAR(32) NOT NULL DEFAULT 'per_second',
  points_per_second INT UNSIGNED NOT NULL,
  minimum_points INT UNSIGNED NOT NULL DEFAULT 0,
  status TINYINT NOT NULL DEFAULT 1,
  effective_at DATETIME NOT NULL,
  expired_at DATETIME NULL,
  version_no INT NOT NULL DEFAULT 1,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  KEY idx_pricing_rules_model_id (video_model_id),
  KEY idx_pricing_rules_status (status),
  KEY idx_pricing_rules_effective_at (effective_at),
  CONSTRAINT fk_pricing_rules_video_model_id FOREIGN KEY (video_model_id) REFERENCES video_models(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

media_assets

CREATE TABLE media_assets (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  asset_no VARCHAR(64) NOT NULL UNIQUE,
  user_id BIGINT UNSIGNED NOT NULL,
  media_type VARCHAR(16) NOT NULL COMMENT 'image/video/audio',
  source_type VARCHAR(16) NOT NULL DEFAULT 'upload' COMMENT 'upload/generated/imported',
  original_filename VARCHAR(255) NOT NULL,
  mime_type VARCHAR(100) NOT NULL DEFAULT '',
  file_size BIGINT UNSIGNED NOT NULL DEFAULT 0,
  storage_bucket VARCHAR(100) NOT NULL,
  storage_key VARCHAR(255) NOT NULL,
  public_url VARCHAR(500) NOT NULL DEFAULT '',
  status VARCHAR(32) NOT NULL DEFAULT 'active',
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  KEY idx_media_assets_user_id (user_id),
  KEY idx_media_assets_media_type (media_type),
  CONSTRAINT fk_media_assets_user_id FOREIGN KEY (user_id) REFERENCES users(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

video_generation_tasks

CREATE TABLE video_generation_tasks (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  task_no VARCHAR(64) NOT NULL UNIQUE,
  user_id BIGINT UNSIGNED NOT NULL,
  video_model_id BIGINT UNSIGNED NOT NULL,
  provider_account_id BIGINT UNSIGNED NOT NULL,
  provider_model_id BIGINT UNSIGNED NOT NULL,
  provider_binding_id BIGINT UNSIGNED NULL,
  pricing_rule_id BIGINT UNSIGNED NOT NULL,
  external_task_id VARCHAR(100) NOT NULL DEFAULT '',
  submit_mode VARCHAR(32) NOT NULL DEFAULT 'async',
  task_status VARCHAR(32) NOT NULL COMMENT 'created/queued/running/succeeded/failed/cancelled',
  generation_mode VARCHAR(32) NOT NULL COMMENT 'text_to_video/image_to_video/multimodal',
  prompt_text TEXT NULL,
  request_payload JSON NOT NULL,
  response_payload JSON NULL,
  duration_seconds INT NOT NULL DEFAULT 5,
  ratio VARCHAR(20) NOT NULL DEFAULT '16:9',
  resolution VARCHAR(20) NOT NULL DEFAULT '720p',
  generate_audio TINYINT NOT NULL DEFAULT 0,
  estimated_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
  frozen_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
  final_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
  supplier_cost_amount DECIMAL(10,4) NOT NULL DEFAULT 0.0000,
  supplier_cost_currency VARCHAR(16) NOT NULL DEFAULT '',
  result_asset_id BIGINT UNSIGNED NULL,
  fail_reason VARCHAR(500) NOT NULL DEFAULT '',
  submitted_at DATETIME NULL,
  started_at DATETIME NULL,
  finished_at DATETIME NULL,
  next_poll_at DATETIME NULL,
  poll_count INT NOT NULL DEFAULT 0,
  user_visible TINYINT NOT NULL DEFAULT 1,
  user_deleted_at DATETIME NULL,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  KEY idx_video_tasks_user_id (user_id),
  KEY idx_video_tasks_status (task_status),
  KEY idx_video_tasks_external_task_id (external_task_id),
  KEY idx_video_tasks_next_poll_at (next_poll_at),
  KEY idx_video_tasks_user_visible (user_id, user_visible),
  CONSTRAINT fk_video_tasks_user_id FOREIGN KEY (user_id) REFERENCES users(id),
  CONSTRAINT fk_video_tasks_video_model_id FOREIGN KEY (video_model_id) REFERENCES video_models(id),
  CONSTRAINT fk_video_tasks_provider_account_id FOREIGN KEY (provider_account_id) REFERENCES provider_accounts(id),
  CONSTRAINT fk_video_tasks_provider_model_id FOREIGN KEY (provider_model_id) REFERENCES provider_models(id),
  CONSTRAINT fk_video_tasks_provider_binding_id FOREIGN KEY (provider_binding_id) REFERENCES video_model_supplier_bindings(id),
  CONSTRAINT fk_video_tasks_pricing_rule_id FOREIGN KEY (pricing_rule_id) REFERENCES pricing_rules(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

video_task_events

CREATE TABLE video_task_events (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  video_task_id BIGINT UNSIGNED NOT NULL,
  event_type VARCHAR(32) NOT NULL,
  event_message VARCHAR(255) NOT NULL DEFAULT '',
  payload JSON NULL,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  KEY idx_video_task_events_task_id (video_task_id),
  KEY idx_video_task_events_event_type (event_type),
  CONSTRAINT fk_video_task_events_video_task_id FOREIGN KEY (video_task_id) REFERENCES video_generation_tasks(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

callback_logs

CREATE TABLE callback_logs (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  source_type VARCHAR(32) NOT NULL COMMENT 'payment/provider',
  source_code VARCHAR(32) NOT NULL,
  related_no VARCHAR(64) NOT NULL DEFAULT '',
  request_headers JSON NULL,
  request_body JSON NULL,
  verify_status VARCHAR(32) NOT NULL DEFAULT 'pending',
  process_status VARCHAR(32) NOT NULL DEFAULT 'pending',
  response_body TEXT NULL,
  error_message VARCHAR(500) NOT NULL DEFAULT '',
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  KEY idx_callback_logs_source (source_type, source_code),
  KEY idx_callback_logs_related_no (related_no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

8.4 索引建议

以下字段必须建立索引:

  • 用户登录查询:emailmobile
  • 用户名查询:username
  • 钱包流水列表:user_idcreated_at
  • 充值订单查询:order_nouser_idstatus
  • 兑换密钥查询:redeem_codestatus
  • 邀请码查询:invite_codeuser_id
  • 邀请关系查询:invitee_user_idinviter_user_idreward_status
  • 任务轮询:task_statusnext_poll_at
  • 第三方回调:external_task_id
  • 用户任务列表:user_iduser_visiblecreated_at
  • 管理后台筛选:video_model_idprovider_model_idcreated_at

8.5 金额与积分字段规范

金额与积分相关统一规定:

  • 用户钱包单位:积分
  • 积分字段统一使用 BIGINT UNSIGNED
  • 支付金额单位:元
  • 人民币字段统一使用 DECIMAL(10,2)
  • 积分建议为整数,不使用小数积分
  • 建议后台配置基础兑换比例,例如 1 元 = 100 积分
  • 业务内部结算不允许使用 float

8.6 数据一致性要求

  • 钱包积分更新必须使用事务
  • 钱包积分扣减必须带版本控制或 select ... for update
  • 充值回调必须通过唯一订单号防重
  • 视频任务成功结算必须保证“状态更新 + 钱包流水”一致
  • 兑换密钥兑换必须通过行锁保证只成功一次
  • 注册赠送必须通过唯一用户校验只发放一次
  • 邀请奖励必须通过唯一 invitee 校验只发放一次
  • 供应商故障切换时不得重复提交同一任务到多个供应商,除非显式进入补偿重试流程

9. 后端模块设计

9.1 推荐目录结构

backend/
  app/
    common/
      config/
      db/
      errors/
      middleware/
      security/
      utils/
    modules/
      auth/
      users/
      invites/
      redeem_codes/
      growth_rules/
      wallets/
      payments/
      providers/
      pricing/
      assets/
      video_tasks/
      admins/
      system/
    workers/
    scripts/
  tests/
  alembic/

9.2 模块职责

auth

  • 注册登录
  • JWT 签发与刷新
  • 权限校验

users

  • 个人资料查询
  • 用户名与头像修改
  • 用户状态校验

invites

  • 邀请码生成
  • 邀请关系建立
  • 邀请奖励发放
  • 邀请统计查询

redeem_codes

  • 兑换密钥校验
  • 兑换事务处理
  • 兑换记录查询

growth_rules

  • 注册赠送规则读取
  • 邀请奖励规则读取
  • 后台增长规则维护

wallets

  • 钱包积分查询
  • 冻结和解冻
  • 积分扣减和退款
  • 人工调账

payments

  • 创建充值订单
  • 调起支付
  • 回调验签
  • 到账处理

providers

  • 多供应商账号配置
  • OpenAI 官方格式适配器
  • Seedance 格式适配器
  • API 调用封装
  • 回调标准化
  • 供应商故障切换

pricing

  • 价格规则查询
  • 积分价格计算器
  • 活动和赠送策略

assets

  • 上传凭证
  • 文件转存
  • 文件元数据记录

video_tasks

  • 创建任务
  • 调度 worker
  • 状态查询
  • 结果保存
  • 最终结算

10. API 设计

10.1 设计规范

  • 路径使用复数资源名
  • 响应统一包装
  • 错误响应统一结构
  • 列表接口统一分页
  • 异步任务创建返回 202 Accepted200 + taskId

10.2 推荐响应格式

成功

{
  "code": 0,
  "message": "ok",
  "data": {}
}

失败

{
  "code": 40001,
  "message": "insufficient balance",
  "requestId": "req_xxx",
  "errors": [
    {
      "field": "balance",
      "reason": "not enough"
    }
  ]
}

10.3 用户端接口

认证

  • POST /api/v1/auth/register
  • POST /api/v1/auth/login
  • POST /api/v1/auth/refresh
  • POST /api/v1/auth/logout
  • GET /api/v1/auth/me

个人资料

  • GET /api/v1/profile
  • PUT /api/v1/profile

钱包

  • GET /api/v1/wallet
  • GET /api/v1/wallet/transactions
  • POST /api/v1/wallet/recharge-orders
  • GET /api/v1/wallet/recharge-orders
  • POST /api/v1/wallet/redeem-codes/exchange
  • GET /api/v1/wallet/redeem-records

邀请

  • GET /api/v1/invite
  • POST /api/v1/invite/codes
  • GET /api/v1/invite/relations
  • GET /api/v1/invite/rewards

素材

  • POST /api/v1/assets/upload-token
  • POST /api/v1/assets
  • GET /api/v1/assets
  • DELETE /api/v1/assets/{assetId}

视频任务

  • GET /api/v1/video-models
  • POST /api/v1/video-tasks
  • GET /api/v1/video-tasks
  • GET /api/v1/video-tasks/{taskId}
  • POST /api/v1/video-tasks/{taskId}/retry
  • POST /api/v1/video-tasks/{taskId}/cancel
  • DELETE /api/v1/video-tasks/{taskId}

10.4 管理后台接口

用户与钱包

  • GET /api/v1/admin/users
  • GET /api/v1/admin/users/{userId}
  • POST /api/v1/admin/users/{userId}/wallet-adjust
  • GET /api/v1/admin/users/{userId}/invite-relations

充值管理

  • GET /api/v1/admin/recharge-orders
  • GET /api/v1/admin/recharge-orders/{orderId}
  • POST /api/v1/admin/recharge-orders/{orderId}/repair

兑换密钥与增长奖励管理

  • GET /api/v1/admin/redeem-codes
  • POST /api/v1/admin/redeem-codes/batch-create
  • POST /api/v1/admin/redeem-codes/import
  • PUT /api/v1/admin/redeem-codes/{id}/disable
  • GET /api/v1/admin/growth-rules
  • PUT /api/v1/admin/growth-rules/signup
  • PUT /api/v1/admin/growth-rules/invite
  • GET /api/v1/admin/invite-relations

平台和模型管理

  • GET /api/v1/admin/provider-accounts
  • POST /api/v1/admin/provider-accounts
  • PUT /api/v1/admin/provider-accounts/{id}
  • GET /api/v1/admin/provider-models
  • POST /api/v1/admin/provider-models
  • PUT /api/v1/admin/provider-models/{id}
  • GET /api/v1/admin/video-models
  • POST /api/v1/admin/video-models
  • PUT /api/v1/admin/video-models/{id}
  • GET /api/v1/admin/video-model-bindings
  • POST /api/v1/admin/video-model-bindings
  • PUT /api/v1/admin/video-model-bindings/{id}

价格管理

  • GET /api/v1/admin/pricing-rules
  • POST /api/v1/admin/pricing-rules
  • PUT /api/v1/admin/pricing-rules/{id}
  • POST /api/v1/admin/pricing-rules/{id}/publish

任务管理

  • GET /api/v1/admin/video-tasks
  • GET /api/v1/admin/video-tasks/{id}
  • POST /api/v1/admin/video-tasks/{id}/retry
  • POST /api/v1/admin/video-tasks/{id}/refund

11. 价格与充值设计

11.1 积分充值体系

首版建议采用“人民币充值 -> 积分到账”的积分钱包制。

例如:

  • 用户支付 100 元
  • 后台基础兑换比例配置为 1 元 = 100 积分
  • 则基础到账 10000 积分
  • 若活动赠送 1000 积分,则最终到账 11000 积分

因此要区分:

  • pay_amount:用户实付金额
  • give_points:基础到账积分
  • bonus_points:赠送积分
  • arrival_points:最终到账积分

11.2 价格规则设计

价格中心必须按“平台视频模型”单独配置价格。

首版统一采用:

  • 按秒计费
  • 单位为积分
  • 每个平台视频模型单独设置 points_per_second

例如:

  • 标准视频:120 积分/秒
  • 高速视频:80 积分/秒
  • 高清视频:200 积分/秒

注意:

  • 前台用户选择的是平台视频模型
  • 后台真正路由到哪个供应商模型,不影响前台价格展示
  • 这样可以在不中断用户体验的情况下切换供应商

11.3 推荐计费公式

最终扣费积分 =
max(
  最低积分扣费,
  请求时长秒数 * 每秒积分价格
)

例如:

  • 某平台视频模型价格为 120 积分/秒
  • 用户提交 8 秒
  • 最低扣费为 500 积分
  • 最终扣费 = max(500, 8 * 120) = 960 积分

11.4 计费秒数标准

首版建议统一按“用户提交的请求时长”计费,而不是按供应商最终生成时长回写计费。

原因:

  • 用户在提交前就能明确看到积分消耗
  • OpenAI 与 Seedance 的返回格式不完全一致
  • 避免因供应商返回的时长轻微偏差产生争议

11.5 供应商格式差异下的参数校验

首版在前台选择平台视频模型后,后端仍需依据实际命中的供应商模型做二次参数校验:

  • OpenAI 官方格式:
    • seconds 只允许官方支持的档位
    • size 必须是官方允许的分辨率
    • 有图参考时需使用 multipart/form-data
  • Seedance 格式:
    • duration 允许整数秒
    • content 为多模态数组
    • generate_audioratiotools 等走 JSON 提交

11.6 首版建议

首版不要引入过于复杂的倍率系统,定价中心只保留:

  • 平台视频模型
  • 每秒积分价格
  • 最低积分扣费
  • 生效时间
  • 版本号

11.7 积分来源与优先级

平台首版建议明确区分积分来源:

  • 充值积分
  • 兑换密钥积分
  • 注册赠送积分
  • 邀请奖励积分
  • 人工补偿积分

建议所有积分都进入同一个钱包余额,但在流水中区分业务类型。

11.8 注册赠送与邀请奖励的发放规则

推荐规则如下:

  • 注册赠送:
    • 注册成功后立即发放
    • 每个用户仅一次
  • 邀请奖励:
    • 仅当被邀请用户首次成功消费后发放
    • 每个被邀请用户仅触发一次
    • 若邀请关系被判定异常,则不发放奖励

11.9 密钥兑换规则

推荐规则如下:

  • 默认一密一用
  • 支持设置过期时间
  • 支持后台批量生成
  • 支持后台单个禁用
  • 兑换后不可撤销,若需回收,应通过人工调账处理

12. 异步任务与调度设计

12.1 队列任务分类

  • submit_video_task
  • poll_video_task_status
  • finalize_video_task
  • download_result_asset
  • retry_failed_task
  • grant_signup_reward
  • grant_invite_reward

12.2 轮询策略

推荐指数退避轮询:

  • 第 1 次10 秒后
  • 第 2 次20 秒后
  • 第 3 次30 秒后
  • 第 4 次后60 秒固定
  • 最大轮询时间:根据模型 SLA 配置,例如 30 分钟

12.3 超时处理

若任务超时:

  • 标记任务为失败或超时
  • 释放冻结积分
  • 记录第三方超时原因
  • 可由管理员手动重试

13. 文件与对象存储设计

13.1 存储对象分类

  • 用户上传原始图片
  • 用户上传音频
  • 用户上传视频参考
  • 生成结果视频
  • 缩略图和封面

13.2 推荐策略

  • 浏览器直接上传对象存储,后端签发上传凭证
  • 上传完成后由后端写入 media_assets
  • 生成结果统一转存到自有桶
  • 文件路径按日期和用户 ID 分层

示例:

uploads/user/10001/images/2026/04/17/xxx.png
uploads/user/10001/videos/2026/04/17/xxx.mp4
generated/video/2026/04/17/task_xxx/result.mp4

13.3 下载控制

  • 用户自己的文件可查看
  • 生成结果可设置临时签名 URL
  • 管理员可查看所有文件

14. 安全设计

14.1 必须实现

  • HTTPS
  • JWT 鉴权
  • 管理后台 RBAC
  • 管理后台强密码策略
  • 管理后台建议开启二次验证
  • 支付回调验签
  • API Key 加密存储
  • 限流
  • 上传文件类型校验
  • 敏感操作审计日志
  • 密码使用 Argon2idbcrypt 哈希存储
  • 下载地址使用签名 URL
  • 所有关键写操作支持幂等控制

14.2 风控建议

  • 单用户分钟级任务创建频率限制
  • 单用户每日消费上限
  • 可疑账号风控标签
  • 支付失败次数限制
  • 超大文件拒绝上传
  • 兑换密钥尝试次数限制
  • 邀请码尝试次数限制
  • 同 IP / 同设备注册频率限制
  • 同设备多账号邀请奖励限制

14.3 数据安全

  • API Key 使用应用层加密后保存
  • 不在日志中输出完整秘钥
  • 对回调报文脱敏存储
  • 定期备份 MySQL 和对象存储元数据
  • 用户密码、Token、支付报文中的敏感字段必须脱敏
  • 生成视频原始供应商下载地址不直接暴露给前端

14.4 必须落实的安全基线

这部分不是建议,而是上线前必须落实:

  1. 注册、登录、兑换密钥、创建任务、支付回调全部记录 request id
  2. 所有创建类接口都校验登录态和用户状态
  3. 所有查询类接口都校验资源归属,禁止越权查看他人任务
  4. DELETE /video-tasks/{id} 只能删除自己的记录,且为软删除
  5. 兑换密钥必须通过数据库事务加锁,防止并发重复兑换
  6. 邀请奖励发放必须检查是否已奖励过,不能重复发奖
  7. 后台接口必须进行角色权限校验,不能只依赖前端菜单隐藏
  8. 对象存储桶不得设置公开读写
  9. 上传文件必须做 MIME、扩展名、大小三重校验
  10. 生产环境必须关闭调试模式和详细堆栈输出

14.5 邀请与兑换的防刷要求

邀请奖励和兑换密钥是最容易被攻击的两个模块,必须重点处理:

兑换密钥防刷

  • 单用户单位时间兑换失败次数限制
  • 单 IP 单位时间兑换失败次数限制
  • 兑换密钥使用后立即失效
  • 后台支持一键禁用批次
  • 对异常批量尝试行为进行告警

邀请奖励防刷

  • 同一被邀请用户只允许绑定一次邀请关系
  • 同设备、同 IP、同支付标识可作为风控参考
  • 邀请奖励必须延迟到首次有效消费后发放
  • 可配置最小有效消费积分阈值,例如消费满 100 积分才触发奖励
  • 若命中风控规则,可将奖励状态置为 invalid

14.6 用户删除记录的安全要求

用户删除视频记录时必须满足:

  • 仅影响用户前台可见性
  • 不删除任务日志、积分流水、邀请奖励触发依据
  • 不删除后台审计记录
  • 管理后台仍可检索该记录

14.7 推荐安全中间件

后端建议至少接入:

  • 请求 ID 中间件
  • 统一异常处理中间件
  • JWT 鉴权中间件
  • RBAC 权限中间件
  • 频率限制中间件
  • 管理后台操作审计中间件

15. 监控与日志

15.1 必备日志

  • 请求日志
  • 错误日志
  • 支付回调日志
  • 第三方 API 调用日志
  • 视频任务事件日志
  • 管理员操作日志

15.2 核心监控指标

  • 注册用户数
  • 充值转化率
  • 任务提交成功率
  • 第三方接口成功率
  • 任务平均完成时长
  • 模型调用成本
  • 钱包积分扣费失败次数

15.3 告警建议

  • 第三方接口连续失败
  • 支付回调异常激增
  • 队列积压
  • MySQL 连接数过高
  • Redis 内存过高

16. 开发阶段划分

16.1 Phase 1MVP

目标:打通最小商业闭环。

包含:

  • 用户登录注册
  • 钱包与充值
  • 兑换密钥
  • 注册赠送积分
  • 邀请码与邀请奖励
  • 两种供应商协议接入:OpenAI 官方格式 + Seedance 格式
  • 文生视频和图生视频
  • 任务列表和详情
  • 管理后台配置模型和价格

16.2 Phase 2增强版

包含:

  • 多模型接入
  • 音频参考和视频参考
  • 优惠活动和充值赠送
  • 管理台统计报表
  • 失败任务补偿
  • SSE 任务状态推送

16.3 Phase 3平台化

包含:

  • 社区作品广场
  • API 对外开放
  • 渠道商体系
  • 团队工作区
  • 自动化风控与推荐

17. 建议开发排期

第 1 周

  • 项目初始化
  • 用户认证
  • MySQL 基础表
  • 钱包系统

第 2 周

  • 充值订单
  • 支付回调
  • 素材上传
  • 管理后台基础框架

第 3 周

  • 视频任务创建
  • 第三方模型接入
  • Celery 轮询任务
  • 结果转存

第 4 周

  • 价格配置
  • 后台模型管理
  • 任务管理
  • 错误处理与监控

第 5 周

  • 联调测试
  • 压测
  • 修复异常流程
  • 预发布上线

18. 测试方案

18.1 单元测试

  • 价格计算器
  • 钱包扣费逻辑
  • 充值入账逻辑
  • 兑换密钥兑换逻辑
  • 注册赠送逻辑
  • 邀请奖励发放逻辑
  • 第三方适配器

18.2 集成测试

  • 登录注册
  • 充值下单
  • 密钥兑换
  • 邀请码注册
  • 支付回调
  • 任务创建到完成
  • 失败退回积分

18.3 关键用例

  • 重复支付回调只入账一次
  • 任务失败后积分正确返还
  • 同一个兑换密钥不能重复兑换
  • 同一个被邀请用户不能重复触发邀请奖励
  • 第三方返回慢时任务不会重复提交
  • 多供应商绑定时主供应商失败可自动切换到备用供应商
  • OpenAI 官方格式和 Seedance 格式都能正确映射到统一任务模型
  • 管理员停用模型后前台不可选

19. 上线建议

19.1 生产环境组件

  • 1 x Nginx
  • 1 x Next.js
  • 2 x FastAPI
  • 2 x Celery Worker
  • 1 x MySQL 主库
  • 1 x Redis
  • 1 x MinIO/OSS

19.2 备份策略

  • MySQL 每日全量备份
  • 二进制日志保留至少 7 天
  • 对象存储开启版本控制或跨区域备份

19.3 上线前检查

  • 环境变量是否完整
  • 支付回调域名是否正确
  • CORS 白名单是否正确
  • JWT 密钥是否已替换
  • API Key 是否加密保存
  • 监控和告警是否生效

20. 首版最终建议

20.1 技术结论

本项目首版推荐方案如下:

  • 后端:Python + FastAPI
  • 数据库:MySQL 8
  • 缓存与队列:Redis
  • 异步任务:Celery
  • 前端:Next.js + React
  • 管理后台:Next.js Admin 或独立 React + Ant Design

20.2 业务结论

首版优先实现:

  1. 钱包充值
  2. 视频生成
  3. 后台配置多供应商、平台视频模型与积分价格
  4. OpenAI 官方格式与 Seedance 格式双适配
  5. 日志与回调幂等

20.3 架构结论

一定要从第一天就做好这 5 件事:

  1. 第三方模型适配层
  2. 钱包流水审计
  3. 平台模型与供应商绑定层
  4. 任务异步化
  5. 后台动态积分价格配置

这五项决定后续能不能稳定扩展成真正的平台。

21. 开发落地规范

21.1 文档使用方式

这份文档应同时承担以下三个角色:

  • 产品需求说明书
  • 技术设计说明书
  • 开发实施说明书

开发时建议按下面顺序阅读:

  1. 先读 1-6 章,理解业务目标、供应商设计和计费方式
  2. 再读 8-12 章,确定数据库、接口、积分规则和任务调度
  3. 最后读 21-31 章,按页面、接口、状态机和验收标准落地开发

21.2 MVP 开发完成标准

满足以下条件,才可认为首版可上线测试:

  1. 用户可注册、登录、退出,并正常刷新登录态
  2. 用户可查看积分余额、充值套餐、充值记录、积分流水
  3. 用户支付成功后,积分能准确到账且回调幂等
  4. 用户可上传图片素材并发起视频任务
  5. 前台可展示平台视频模型列表,并显示每秒积分价格
  6. 用户可创建视频任务并看到预估扣费积分
  7. 后端可根据平台视频模型路由到供应商模型
  8. 平台至少支持 OpenAI 官方格式Seedance 格式
  9. 任务完成后能转存结果并在前台查看
  10. 任务失败后能退回冻结积分
  11. 用户可通过兑换密钥成功兑换积分
  12. 用户可修改用户名、头像等资料
  13. 邀请码注册、首次消费、邀请奖励链路可用
  14. 用户可查看并软删除自己的视频记录
  15. 管理后台可配置供应商账号、供应商模型、平台视频模型、模型绑定关系、价格规则、增长奖励规则、兑换密钥
  16. 所有关键业务有日志、操作记录和错误追踪

21.3 项目分仓建议

建议首版使用单仓库,结构如下:

AIVideo/
  backend/
  frontend-web/
  frontend-admin/
  docs/
  deploy/
  scripts/
  sql/

如果团队规模较小,也可以采用:

AIVideo/
  apps/
    api/
    web/
    admin/
  packages/
    shared-types/
  deploy/
  docs/

21.4 后端推荐文件清单

后端建议至少包含以下文件:

backend/
  app/
    main.py
    common/
      config/settings.py
      db/session.py
      db/base.py
      middleware/request_id.py
      middleware/auth.py
      errors/app_error.py
      responses/api_response.py
      security/jwt.py
      security/encryptor.py
      utils/time.py
      utils/id_gen.py
    modules/
      auth/
        router.py
        service.py
        schema.py
        repository.py
      users/
        router.py
        service.py
        schema.py
        repository.py
      invites/
        router.py
        service.py
        schema.py
        repository.py
      redeem_codes/
        router.py
        service.py
        schema.py
        repository.py
      growth_rules/
        router.py
        service.py
        schema.py
        repository.py
      wallets/
        router.py
        service.py
        schema.py
        repository.py
      payments/
        router.py
        service.py
        schema.py
        repository.py
        channels/
          alipay.py
          wechat.py
      assets/
        router.py
        service.py
        schema.py
        repository.py
        storage.py
      providers/
        router.py
        service.py
        schema.py
        repository.py
        adapters/
          base.py
          openai_video.py
          seedance_video.py
        mapper.py
      video_models/
        router.py
        service.py
        schema.py
        repository.py
      pricing/
        router.py
        service.py
        schema.py
        repository.py
        calculator.py
      video_tasks/
        router.py
        service.py
        schema.py
        repository.py
        orchestrator.py
      admins/
        router.py
        service.py
        schema.py
        repository.py
      system/
        router.py
        service.py
        schema.py
        repository.py
    workers/
      celery_app.py
      tasks_video_submit.py
      tasks_video_poll.py
      tasks_video_finalize.py
      tasks_recharge_repair.py
      tasks_signup_reward.py
      tasks_invite_reward.py
    models/
      user.py
      wallet.py
      growth_reward_rule.py
      redeem_code.py
      invite_code.py
      invite_relation.py
      recharge_order.py
      provider_account.py
      provider_model.py
      video_model.py
      pricing_rule.py
      media_asset.py
      video_generation_task.py
      callback_log.py
    tests/
      unit/
      integration/
  alembic/
  requirements.txt

21.5 前台与后台推荐文件清单

前台建议至少包含以下页面和模块:

frontend-web/
  src/
    app/
      login/page.tsx
      register/page.tsx
      workspace/create/page.tsx
      workspace/tasks/page.tsx
      workspace/tasks/[taskNo]/page.tsx
      workspace/assets/page.tsx
      wallet/page.tsx
      wallet/recharge/page.tsx
      wallet/redeem/page.tsx
      invite/page.tsx
      profile/page.tsx
    components/
      video-model-select.tsx
      create-task-form.tsx
      asset-uploader.tsx
      task-status-badge.tsx
      points-balance-card.tsx
      redeem-code-form.tsx
      invite-summary-card.tsx
    lib/
      api.ts
      auth.ts
      types.ts

后台建议至少包含以下页面和模块:

frontend-admin/
  src/
    app/
      admin/login/page.tsx
      admin/dashboard/page.tsx
      admin/users/page.tsx
      admin/recharge-orders/page.tsx
      admin/redeem-codes/page.tsx
      admin/growth-rules/page.tsx
      admin/invite-relations/page.tsx
      admin/provider-accounts/page.tsx
      admin/provider-models/page.tsx
      admin/video-models/page.tsx
      admin/video-model-bindings/page.tsx
      admin/pricing-rules/page.tsx
      admin/video-tasks/page.tsx
      admin/callback-logs/page.tsx
      admin/system-config/page.tsx
    components/
      provider-account-form.tsx
      provider-model-form.tsx
      video-model-form.tsx
      pricing-rule-form.tsx
      redeem-code-batch-form.tsx
      growth-rule-form.tsx
      task-detail-drawer.tsx
    lib/
      api.ts
      auth.ts
      table-columns.ts

22. 页面与路由详细清单

22.1 用户前台页面路由

建议前台路由如下:

/
/login
/register
/forgot-password
/workspace/create
/workspace/tasks
/workspace/tasks/[taskNo]
/workspace/assets
/wallet
/wallet/recharge
/wallet/redeem
/wallet/orders
/wallet/transactions
/invite
/profile

22.2 用户前台页面说明

首页 /

页面目标:

  • 展示平台主卖点
  • 引导登录和充值
  • 引导进入创建页

页面模块:

  • 顶部导航
  • Banner
  • 平台视频模型展示卡片
  • 常见问题
  • 页脚

登录页 /login

表单字段:

  • account:邮箱或手机号,必填
  • password:密码,必填

交互要求:

  • 登录成功跳转到 /workspace/create
  • 登录失败显示统一错误提示

注册页 /register

表单字段:

  • emailmobile
  • password
  • confirmPassword
  • verificationCode

校验规则:

  • 密码长度至少 8 位
  • 两次密码必须一致
  • 邮箱或手机号必须未注册

创建页 /workspace/create

页面目标:

  • 选择平台视频模型
  • 输入提示词
  • 上传参考素材
  • 预估积分
  • 创建任务

页面字段:

  • videoModelId:平台视频模型 ID必选
  • prompt:提示词,必填
  • durationSeconds:时长秒数,必填
  • resolution:分辨率,必选
  • ratio:宽高比,必选
  • generateAudio:是否生成音频
  • referenceImageAssetIds:参考图片列表
  • referenceVideoAssetIds:参考视频列表
  • referenceAudioAssetIds:参考音频列表

页面行为:

  • 选择平台视频模型后请求模型详情和价格规则
  • 输入时长后实时计算预估积分
  • 提交前再次向后端确认价格
  • 若积分不足,提示去充值

任务列表页 /workspace/tasks

表格字段:

  • 任务编号
  • 平台视频模型名称
  • 任务状态
  • 时长秒数
  • 预估积分
  • 最终积分
  • 创建时间
  • 操作

操作按钮:

  • 查看详情
  • 复制参数重建
  • 失败后重试
  • 删除记录

任务详情页 /workspace/tasks/[taskNo]

页面模块:

  • 任务基础信息
  • 原始请求参数
  • 任务时间线
  • 最终结果视频
  • 失败原因
  • 积分结算信息

素材页 /workspace/assets

页面功能:

  • 上传素材
  • 筛选图片/视频/音频
  • 删除素材
  • 复制素材 URL

钱包页 /wallet

页面功能:

  • 当前积分
  • 冻结积分
  • 可用积分
  • 充值入口
  • 兑换入口
  • 最近流水

充值页 /wallet/recharge

页面功能:

  • 展示充值套餐
  • 展示每个套餐对应到账积分
  • 创建充值订单
  • 跳转支付

兑换页 /wallet/redeem

页面功能:

  • 输入兑换密钥
  • 查看兑换说明
  • 查看最近兑换记录

表单字段:

  • redeemCode

邀请页 /invite

页面功能:

  • 展示自己的邀请码
  • 展示邀请链接
  • 一键复制邀请码
  • 一键复制邀请链接
  • 手动生成新邀请码
  • 查看邀请人数
  • 查看已奖励积分
  • 查看待奖励邀请关系

个人中心 /profile

页面功能:

  • 修改用户名
  • 修改昵称
  • 上传头像
  • 查看绑定信息
  • 查看账号状态

22.3 管理后台页面路由

建议后台路由如下:

/admin/login
/admin/dashboard
/admin/users
/admin/users/[id]
/admin/recharge-orders
/admin/recharge-orders/[id]
/admin/redeem-codes
/admin/growth-rules
/admin/invite-relations
/admin/provider-accounts
/admin/provider-accounts/create
/admin/provider-models
/admin/video-models
/admin/video-model-bindings
/admin/pricing-rules
/admin/video-tasks
/admin/video-tasks/[id]
/admin/callback-logs
/admin/system-config
/admin/operation-logs

22.4 管理后台页面说明

仪表盘 /admin/dashboard

指标卡片:

  • 今日充值金额
  • 今日充值订单数
  • 今日任务创建数
  • 今日任务成功率
  • 今日积分消耗
  • 供应商失败率

图表:

  • 最近 7 天充值趋势
  • 最近 7 天任务趋势
  • 各平台视频模型调用分布
  • 各供应商调用分布

供应商账号页 /admin/provider-accounts

列表字段:

  • 供应商名称
  • 协议格式
  • Base URL
  • 状态
  • 超时秒数
  • 重试次数
  • 更新时间

创建/编辑字段:

  • providerCode
  • providerName
  • apiFormat
  • baseUrl
  • apiKey
  • apiSecret
  • webhookSecret
  • timeoutSeconds
  • maxRetries
  • status
  • remark

供应商模型页 /admin/provider-models

列表字段:

  • 供应商
  • 模型编码
  • 模型名称
  • 是否支持图生视频
  • 是否支持音频参考
  • 是否支持 webhook
  • 状态

创建/编辑字段:

  • providerAccountId
  • modelCode
  • modelName
  • requestContentType
  • supportsTextToVideo
  • supportsImageToVideo
  • supportsVideoReference
  • supportsAudioReference
  • supportsGenerateAudio
  • supportsRemix
  • supportsWebhook
  • minDuration
  • maxDuration
  • defaultRatio
  • defaultResolution
  • status

平台视频模型页 /admin/video-models

列表字段:

  • 平台模型名称
  • 前台展示名称
  • 默认时长
  • 默认分辨率
  • 状态
  • 排序

创建/编辑字段:

  • modelKey
  • modelName
  • frontendTitle
  • frontendDescription
  • defaultDurationSeconds
  • defaultRatio
  • defaultResolution
  • status
  • sortOrder

平台模型绑定页 /admin/video-model-bindings

列表字段:

  • 平台视频模型
  • 供应商
  • 供应商模型
  • 是否主路由
  • 路由优先级
  • 状态

创建/编辑字段:

  • videoModelId
  • providerModelId
  • routingPriority
  • isPrimary
  • status
  • timeoutSecondsOverride

价格规则页 /admin/pricing-rules

列表字段:

  • 平台视频模型
  • 每秒积分价格
  • 最低积分
  • 生效时间
  • 失效时间
  • 版本号
  • 状态

创建/编辑字段:

  • ruleName
  • videoModelId
  • pointsPerSecond
  • minimumPoints
  • effectiveAt
  • expiredAt
  • versionNo
  • status

兑换密钥页 /admin/redeem-codes

列表字段:

  • 批次号
  • 兑换密钥
  • 对应积分
  • 状态
  • 使用人
  • 使用时间
  • 过期时间

创建/编辑字段:

  • batchNo
  • points
  • quantity
  • expiredAt
  • remark

增长奖励规则页 /admin/growth-rules

字段:

  • signupRewardEnabled
  • signupRewardPoints
  • inviteRewardEnabled
  • inviteRewardPoints
  • inviteRewardTrigger

邀请关系页 /admin/invite-relations

列表字段:

  • 邀请人
  • 被邀请用户
  • 邀请码
  • 注册时间
  • 首次消费时间
  • 奖励状态
  • 奖励积分
  • 奖励时间

视频任务页 /admin/video-tasks

列表字段:

  • 任务编号
  • 用户 ID
  • 平台视频模型
  • 供应商
  • 供应商模型
  • 任务状态
  • 请求时长
  • 预估积分
  • 最终积分
  • 创建时间

详情页字段:

  • 原始提交参数
  • 标准化参数
  • 供应商提交报文
  • 供应商返回报文
  • 时间线
  • 回调日志
  • 结算记录

23. 统一 DTO 与接口字段规范

23.1 创建视频任务请求 DTO

后端对外统一接收如下结构:

{
  "videoModelId": 1,
  "prompt": "夜晚的未来城市上空,一架银色飞行器低空掠过,镜头跟拍。",
  "durationSeconds": 8,
  "resolution": "1280x720",
  "ratio": "16:9",
  "generateAudio": true,
  "referenceImageAssetIds": [1001],
  "referenceVideoAssetIds": [],
  "referenceAudioAssetIds": []
}

字段说明:

  • videoModelId:平台视频模型 ID必填
  • prompt:提示词,必填,建议长度 1 到 4000
  • durationSeconds:请求时长,必填
  • resolution:分辨率,必填
  • ratio:宽高比,必填
  • generateAudio:是否生成音频,必填
  • referenceImageAssetIds:参考图片素材 ID 列表
  • referenceVideoAssetIds:参考视频素材 ID 列表
  • referenceAudioAssetIds:参考音频素材 ID 列表

23.2 创建视频任务响应 DTO

{
  "code": 0,
  "message": "ok",
  "data": {
    "taskNo": "vt_202604170001",
    "taskStatus": "queued",
    "estimatedPoints": 960,
    "frozenPoints": 960
  }
}

23.3 任务详情响应 DTO

{
  "code": 0,
  "message": "ok",
  "data": {
    "taskNo": "vt_202604170001",
    "taskStatus": "succeeded",
    "videoModel": {
      "id": 1,
      "name": "标准视频"
    },
    "provider": {
      "providerCode": "openai-main",
      "modelCode": "sora-2"
    },
    "durationSeconds": 8,
    "estimatedPoints": 960,
    "finalPoints": 960,
    "resultVideoUrl": "https://cdn.example.com/generated/xxx.mp4",
    "failReason": "",
    "createdAt": "2026-04-17T18:00:00+08:00",
    "finishedAt": "2026-04-17T18:03:12+08:00"
  }
}

23.4 创建充值订单请求 DTO

{
  "rechargePlanId": 1,
  "paymentChannelCode": "alipay"
}

23.5 创建充值订单响应 DTO

{
  "code": 0,
  "message": "ok",
  "data": {
    "orderNo": "rc_202604170001",
    "payAmount": "100.00",
    "arrivalPoints": 11000,
    "payUrl": "https://payment.example.com/pay/xxx"
  }
}

23.6 管理后台供应商账号请求 DTO

{
  "providerCode": "openai-main",
  "providerName": "OpenAI 主账号",
  "apiFormat": "openai_official_video",
  "baseUrl": "https://api.openai.com",
  "apiKey": "sk-xxx",
  "apiSecret": "",
  "webhookSecret": "whsec_xxx",
  "timeoutSeconds": 120,
  "maxRetries": 3,
  "status": 1,
  "remark": "生产主账号"
}

23.7 管理后台价格规则请求 DTO

{
  "ruleName": "标准视频默认价格",
  "videoModelId": 1,
  "pointsPerSecond": 120,
  "minimumPoints": 500,
  "effectiveAt": "2026-04-18 00:00:00",
  "expiredAt": null,
  "versionNo": 1,
  "status": 1
}

23.8 个人资料更新请求 DTO

{
  "username": "neo_director",
  "nickname": "Neo",
  "avatarUrl": "https://cdn.example.com/avatar/1001.png"
}

23.9 兑换密钥请求 DTO

{
  "redeemCode": "SPRING-2026-ABCD-1234"
}

23.10 邀请码创建响应 DTO

{
  "code": 0,
  "message": "ok",
  "data": {
    "inviteCode": "NEO88",
    "inviteLink": "https://example.com/register?inviteCode=NEO88"
  }
}

23.11 注册请求 DTO 补充字段

若用户通过邀请码或邀请链接注册,注册请求体建议增加:

{
  "account": "user@example.com",
  "password": "12345678",
  "verificationCode": "123456",
  "inviteCode": "NEO88"
}

24. 状态机与枚举规范

24.1 充值订单状态

推荐枚举:

  • pending
  • paid
  • failed
  • cancelled
  • refunded

状态流转:

pending -> paid
pending -> failed
pending -> cancelled
paid -> refunded

24.2 视频任务状态

推荐枚举:

  • created
  • queued
  • submitting
  • submitted
  • running
  • succeeded
  • failed
  • cancelled
  • timed_out

状态流转:

created -> queued
queued -> submitting
submitting -> submitted
submitted -> running
running -> succeeded
running -> failed
running -> timed_out
queued -> cancelled
running -> cancelled

24.3 钱包流水业务类型

推荐枚举:

  • recharge
  • redeem_code
  • signup_reward
  • invite_reward
  • freeze
  • consume
  • unfreeze
  • refund
  • manual_adjust

24.4 供应商协议枚举

推荐枚举:

  • openai_official_video
  • seedance_video_generation

24.5 兑换密钥状态

推荐枚举:

  • unused
  • used
  • expired
  • disabled

24.6 邀请奖励状态

推荐枚举:

  • pending
  • eligible
  • rewarded
  • invalid

25. 供应商适配器实现细则

25.1 标准化内部请求结构

所有业务层进入适配器之前,统一整理成如下内部结构:

{
  "taskNo": "vt_202604170001",
  "videoModelId": 1,
  "providerAccountId": 10,
  "providerModelId": 21,
  "prompt": "夜晚的未来城市上空,一架银色飞行器低空掠过,镜头跟拍。",
  "durationSeconds": 8,
  "resolution": "1280x720",
  "ratio": "16:9",
  "generateAudio": true,
  "referenceImages": [
    {
      "assetId": 1001,
      "url": "https://storage.example.com/uploads/1001.png"
    }
  ],
  "referenceVideos": [],
  "referenceAudios": []
}

25.2 OpenAI 适配器映射规则

映射建议:

  • prompt -> prompt
  • providerModel.modelCode -> model
  • durationSeconds -> seconds
  • resolution -> size
  • referenceImages[0].url -> input_reference

请求格式:

  • 使用 multipart/form-data
  • 由适配器自行构造 multipart 边界和文件流

查询规则:

  • 使用 GET /v1/videos/{video_id}
  • 当状态为 completed 时,再调用 /content 下载

25.3 Seedance 适配器映射规则

映射建议:

  • providerModel.modelCode -> model
  • prompt -> content[].text
  • referenceImages -> content[].image_url
  • referenceVideos -> content[].video_url
  • referenceAudios -> content[].audio_url
  • durationSeconds -> duration
  • ratio -> ratio
  • generateAudio -> generate_audio

请求格式:

  • 使用 application/json

查询规则:

  • 使用 GET /v1/video/generations/{id}
  • 当返回成功状态时读取视频 URL 并下载转存

25.4 标准化查询结果结构

适配器对外统一返回如下结构:

{
  "externalTaskId": "video_123",
  "normalizedStatus": "running",
  "progress": 50,
  "resultUrl": "",
  "resultExpiresAt": null,
  "rawResponse": {}
}

25.5 供应商切换策略

首版建议按以下策略执行:

  1. 根据 videoModelId 查出绑定的供应商模型列表
  2. routingPriority 升序排序
  3. 优先使用 isPrimary = 1 的供应商模型
  4. 若提交失败且属于可重试错误,则切到下一个供应商
  5. 若已经拿到外部任务 ID则后续只轮询该供应商不再切换

25.6 不允许切换的场景

以下场景不能自动切换供应商:

  • 已经成功提交到供应商并拿到任务 ID
  • 供应商已进入 running
  • 供应商已返回部分结果

25.7 建议保留的原始日志

建议新增供应商请求日志表或至少落文件日志,记录:

  • 任务编号
  • 供应商账号
  • 供应商模型
  • 请求 URL
  • 请求方法
  • 请求头脱敏版本
  • 请求体脱敏版本
  • 响应体
  • HTTP 状态码
  • 请求耗时

26. 任务执行链路详细说明

26.1 创建任务事务

用户提交任务时,后端需在一个事务内完成:

  1. 校验用户状态
  2. 校验平台视频模型状态
  3. 查找当前生效的价格规则
  4. 计算预估积分
  5. 校验钱包可用积分
  6. 创建视频任务记录
  7. 冻结积分
  8. 写入钱包流水
  9. 提交事务

事务提交后再投递异步任务。

26.2 提交任务 Worker

Worker 执行顺序:

  1. 根据 taskNo 读取任务
  2. 判断状态是否允许提交
  3. 根据 videoModelId 解析可用供应商绑定
  4. 构建标准化请求 DTO
  5. 调用供应商适配器提交任务
  6. 保存 externalTaskId
  7. 更新任务状态为 submitted
  8. 写入任务事件
  9. 投递轮询任务

26.3 轮询任务 Worker

Worker 执行顺序:

  1. 读取本地任务
  2. 若任务已结束,直接退出
  3. 调用对应适配器查询状态
  4. 写入原始响应
  5. 若状态仍在处理中,更新 nextPollAt
  6. 若状态成功,投递结果下载任务
  7. 若状态失败,执行解冻与失败收尾

26.4 结果下载 Worker

Worker 执行顺序:

  1. 使用适配器下载结果文件
  2. 上传到对象存储
  3. 创建 media_assets 记录
  4. 回写 resultAssetId
  5. 触发最终结算

26.5 最终结算 Worker

成功任务:

  1. 将冻结积分转为实际消费
  2. 写入消费流水
  3. 更新任务为 succeeded

失败任务:

  1. 解冻积分
  2. 写入退回流水
  3. 更新任务为 failed

26.6 注册赠送与邀请奖励触发

注册成功后:

  1. 检查注册赠送规则是否开启
  2. 检查用户是否已发放过注册赠送
  3. 发放注册奖励积分
  4. 写入钱包流水

任务消费成功后:

  1. 检查用户是否存在邀请关系
  2. 检查该邀请关系是否尚未奖励
  3. 检查是否满足首次有效消费条件
  4. 检查邀请奖励规则是否开启
  5. 给邀请人发放积分奖励
  6. 更新邀请关系状态为 rewarded

26.7 幂等要求

以下操作必须具备幂等性:

  • 支付回调
  • 任务冻结积分
  • 任务最终扣费
  • 任务失败退回积分
  • 注册赠送发放
  • 邀请奖励发放
  • 兑换密钥使用
  • 结果转存写库
  • 供应商 webhook 处理

27. 环境变量与配置清单

27.1 后端环境变量

APP_NAME=AIVideo
APP_ENV=development
APP_HOST=0.0.0.0
APP_PORT=8000
APP_DEBUG=true

MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
MYSQL_USER=root
MYSQL_PASSWORD=123456
MYSQL_DATABASE=aivideo

REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_DB=0

JWT_SECRET=replace_me
JWT_REFRESH_SECRET=replace_me_too
JWT_ACCESS_EXPIRE_MINUTES=120
JWT_REFRESH_EXPIRE_DAYS=30

STORAGE_PROVIDER=minio
STORAGE_ENDPOINT=127.0.0.1:9000
STORAGE_BUCKET=ai-video
STORAGE_ACCESS_KEY=minioadmin
STORAGE_SECRET_KEY=minioadmin
STORAGE_PUBLIC_BASE_URL=https://cdn.example.com

POINT_EXCHANGE_RATIO=100
REDEEM_CODE_FAIL_LIMIT_PER_HOUR=20
INVITE_REWARD_MIN_CONSUME_POINTS=100

PAYMENT_NOTIFY_BASE_URL=https://api.example.com
VIDEO_NOTIFY_BASE_URL=https://api.example.com

DATA_ENCRYPTION_KEY=replace_32_length_key
SENTRY_DSN=

27.2 前端环境变量

前台:

NEXT_PUBLIC_API_BASE_URL=https://api.example.com
NEXT_PUBLIC_APP_NAME=AIVideo

后台:

NEXT_PUBLIC_ADMIN_API_BASE_URL=https://api.example.com
NEXT_PUBLIC_ADMIN_APP_NAME=AIVideo Admin

27.3 系统配置表建议维护的键

建议把以下配置放入 system_configs

  • site.title
  • site.notice
  • wallet.point_exchange_ratio
  • reward.signup.enabled
  • reward.signup.points
  • reward.invite.enabled
  • reward.invite.points
  • reward.invite.trigger
  • reward.invite.min_consume_points
  • invite.code.enabled
  • upload.max_image_size_mb
  • upload.max_video_size_mb
  • upload.max_audio_size_mb
  • task.default_poll_interval_seconds
  • task.max_poll_minutes
  • task.daily_create_limit

28. 本地开发流程

28.1 后端初始化步骤

1. 创建 Python 虚拟环境
2. 安装依赖
3. 准备 .env
4. 初始化 MySQL 数据库
5. 执行 Alembic migrate
6. 启动 FastAPI
7. 启动 Celery Worker
8. 启动 Celery Beat 或定时轮询服务

28.2 前台初始化步骤

1. 安装 Node.js 依赖
2. 配置 .env.local
3. 启动 Next.js dev server
4. 连接后端调试登录、充值、创建任务

28.3 后台初始化步骤

1. 安装 Node.js 依赖
2. 配置 .env.local
3. 创建管理员种子账号
4. 启动后台项目
5. 先录入增长奖励规则
6. 再录入兑换密钥批次
7. 再录入供应商账号
8. 再录入供应商模型
9. 再创建平台视频模型
10. 再创建绑定关系和价格规则

28.4 数据初始化顺序

建议种子数据按以下顺序初始化:

  1. 管理员角色与权限
  2. 管理员账号
  3. 增长奖励规则
  4. 支付渠道
  5. 兑换密钥批次
  6. 供应商账号
  7. 供应商模型
  8. 平台视频模型
  9. 平台模型绑定关系
  10. 价格规则
  11. 系统配置

29. 错误码规范

29.1 错误码分段

建议按模块划分错误码:

  • 10000-19999:认证与用户
  • 20000-29999:钱包与积分
  • 30000-39999:充值与支付
  • 40000-49999:素材与上传
  • 50000-59999:视频任务
  • 60000-69999:供应商与模型
  • 70000-74999:邀请、兑换与增长奖励
  • 75000-79999:后台权限与系统配置

29.2 常用错误码示例

10001 未登录
10002 Token 无效
10003 用户被禁用

20001 积分不足
20002 钱包不存在
20003 冻结积分失败
20004 兑换密钥不存在
20005 兑换密钥已使用
20006 兑换密钥已过期

30001 充值订单不存在
30002 支付回调验签失败
30003 订单已处理

40001 上传文件类型不支持
40002 文件大小超限
40003 素材不存在

50001 平台视频模型不存在
50002 平台视频模型已下架
50003 没有可用供应商
50004 任务状态不允许当前操作
50005 任务创建失败
50006 任务记录不存在或无权限访问

60001 供应商账号不可用
60002 供应商模型不可用
60003 供应商接口超时
60004 供应商接口限流
60005 供应商返回格式异常

70001 邀请码不存在
70002 邀请码不可用
70003 邀请关系已绑定
70004 邀请奖励已发放

30. 开发任务拆分建议

30.1 后端任务拆分

后端至少拆成以下开发任务:

  1. 认证模块
  2. 用户与钱包模块
  3. 兑换密钥模块
  4. 邀请与奖励模块
  5. 充值订单与支付回调模块
  6. 素材上传模块
  7. 供应商账号与模型管理模块
  8. 平台视频模型与绑定模块
  9. 价格规则模块
  10. 视频任务模块
  11. OpenAI 适配器
  12. Seedance 适配器
  13. 异步任务模块
  14. 日志与监控模块

30.2 前台任务拆分

前台至少拆成以下开发任务:

  1. 登录注册
  2. 钱包与充值
  3. 兑换密钥
  4. 邀请中心
  5. 素材管理
  6. 创建视频任务
  7. 任务列表
  8. 任务详情
  9. 个人中心

30.3 后台任务拆分

后台至少拆成以下开发任务:

  1. 管理员登录
  2. 仪表盘
  3. 用户管理
  4. 充值订单管理
  5. 兑换密钥管理
  6. 增长奖励规则管理
  7. 邀请关系管理
  8. 供应商账号管理
  9. 供应商模型管理
  10. 平台视频模型管理
  11. 绑定关系管理
  12. 价格规则管理
  13. 视频任务管理
  14. 回调日志和操作日志

31. 开发验收清单

31.1 用户端验收

  • 用户可正常登录退出
  • 用户可看到平台视频模型与价格
  • 用户可修改用户名和头像
  • 用户可上传素材
  • 用户可通过兑换密钥获得积分
  • 用户可看到邀请码和邀请链接
  • 用户可创建任务
  • 用户可轮询看到任务变化
  • 用户可看到结果视频
  • 用户可删除自己的任务记录
  • 用户可查看积分流水

31.2 后台验收

  • 可新增多个供应商账号
  • 可新增多个供应商模型
  • 可新增平台视频模型
  • 可绑定多个供应商模型到同一个平台视频模型
  • 可配置每秒积分价格
  • 可配置注册赠送积分是否开启及积分数
  • 可配置邀请奖励是否开启及积分数
  • 可批量生成或导入兑换密钥
  • 可查看任务命中的实际供应商
  • 可查看邀请关系与奖励状态
  • 可查看回调日志与操作日志

31.3 技术验收

  • OpenAI 官方格式能成功提交、查询和下载结果
  • Seedance 格式能成功提交、查询和下载结果
  • 支付回调幂等
  • 任务积分冻结与扣减幂等
  • 任务失败积分退回正确
  • 兑换密钥并发兑换时只成功一次
  • 注册赠送积分只发放一次
  • 邀请奖励只发放一次
  • 供应商切换策略符合预期
  • 日志、监控、错误追踪已接入

31.4 上线前人工回归项

  • 创建 1 个 OpenAI 平台模型并完成生成
  • 创建 1 个 Seedance 平台模型并完成生成
  • 构造供应商主路由失败并验证自动切换
  • 构造支付重复回调并验证只到账一次
  • 构造任务失败并验证积分退回
  • 构造同一个兑换密钥重复兑换并验证只成功一次
  • 构造邀请注册和首次消费并验证奖励只发放一次