feat: add AirShelf core implementation
This commit is contained in:
@@ -0,0 +1,702 @@
|
||||
# AirShelf 技术架构方案
|
||||
|
||||
> 版本:v1.0
|
||||
> 日期:2026-05-29
|
||||
> 定位:从原型走向真实可运营产品的顶层技术架构决策文档
|
||||
> 适用范围:Django 后端、前端产品化、火山 ARK AI 接入、额度账本、运营后台、60s 多段视频生产
|
||||
|
||||
---
|
||||
|
||||
## 1. 架构结论
|
||||
|
||||
AirShelf 不应该先横向补齐所有页面,而应该先打穿一条真实生产闭环:
|
||||
|
||||
商品创建 -> 项目创建 -> AI 脚本 -> 基础资产 -> 可选故事板 -> 4 段视频生成 -> FFmpeg 拼接导出 -> 额度确认扣费 -> 资产入库 -> 运营后台可观测
|
||||
|
||||
第一阶段采用“模块化单体 + 异步任务”的架构:
|
||||
|
||||
- 后端:Django + Django REST Framework
|
||||
- 数据库:MySQL
|
||||
- 缓存/队列/锁:Redis
|
||||
- 异步任务:Celery Worker + Celery Beat
|
||||
- 文件存储:火山 TOS
|
||||
- AI 模型:火山 ARK,统一 Provider 抽象
|
||||
- 运营后台:先用 Django Admin + 少量自定义后台页
|
||||
- 前端:React + Vite 单页应用。以 `v1/*.html` 为核心视觉规格,`电商AI平台/*.html` 作为未迁移页面和原版能力补充,重建为真实前端应用
|
||||
- 路由:正式业务入口使用 React History URL,例如 `/products`、`/projects/new`、`/pipeline/:id`。`/exact/*.html` 只作为像素级设计稿镜像和视觉回归基线,不作为产品业务路由
|
||||
|
||||
暂不采用微服务。当前阶段最大风险不是服务边界不够细,而是任务状态、扣费账本、AI 失败恢复、资产流转没有被一套一致的数据模型兜住。模块化单体更容易保证事务一致性,也更适合快速把 PRD 全量能力落地。
|
||||
|
||||
---
|
||||
|
||||
## 2. 核心原则
|
||||
|
||||
### 2.1 账本优先
|
||||
|
||||
额度系统不能后补。所有 AI 任务、导出任务、重跑任务都必须先经过额度预检,并由账本记录冻结、确认扣费、失败释放、人工调整。
|
||||
|
||||
关键原则:
|
||||
|
||||
- 失败不扣费
|
||||
- 用户确认采用后扣费
|
||||
- 预估消耗需要额度预检
|
||||
- 扣费必须幂等
|
||||
- 所有账务变更必须有流水
|
||||
|
||||
### 2.2 任务异步化
|
||||
|
||||
火山生图、生视频、视频拼接都不能放在同步 HTTP 请求里执行。API 只负责创建任务、返回 task_id;Worker 负责执行、轮询、重试、写状态。
|
||||
|
||||
### 2.3 资产对象化
|
||||
|
||||
图片、视频、成片不直接存数据库。数据库只存 TOS object key、元数据、归属、状态、引用关系。所有中间产物都应成为可追踪 Asset。
|
||||
|
||||
### 2.4 状态机先行
|
||||
|
||||
项目、阶段、AI 任务、视频片段、导出任务都必须有清晰状态机。不要只靠布尔字段拼状态,否则 60s 多段生产会很快失控。
|
||||
|
||||
### 2.5 单项目多段并发
|
||||
|
||||
60s 视频按 4 段 x 15s 生产。每段是独立 VideoSegment 和独立 AIJob,可并发、可单段失败、可单段重跑、可回选历史版本。
|
||||
|
||||
---
|
||||
|
||||
## 3. 系统拓扑
|
||||
|
||||
```text
|
||||
Browser
|
||||
|
|
||||
| HTTPS
|
||||
v
|
||||
Frontend Web
|
||||
|
|
||||
| REST / SSE or WebSocket
|
||||
v
|
||||
Django API
|
||||
|
|
||||
| ORM
|
||||
v
|
||||
MySQL
|
||||
|
||||
Django API
|
||||
|
|
||||
| enqueue task
|
||||
v
|
||||
Redis broker
|
||||
|
|
||||
v
|
||||
Celery Workers
|
||||
| | |
|
||||
| | +--> FFmpeg export
|
||||
| +----------> TOS upload/download
|
||||
+------------------> Volcano ARK
|
||||
|
||||
Celery Workers
|
||||
|
|
||||
| status / ledger / asset metadata
|
||||
v
|
||||
MySQL
|
||||
|
||||
Django Admin / Ops
|
||||
|
|
||||
v
|
||||
MySQL + task logs + billing ledger
|
||||
```
|
||||
|
||||
部署形态:
|
||||
|
||||
- `airshelf-web`:前端静态资源或 SSR 前端服务
|
||||
- `airshelf-api`:Django API
|
||||
- `airshelf-worker-default`:通用任务
|
||||
- `airshelf-worker-ai`:AI 文本/图片/视频任务
|
||||
- `airshelf-worker-media`:FFmpeg 拼接、转码、缩略图
|
||||
- `airshelf-beat`:定时任务、超时扫描、TOS 临时文件清理
|
||||
|
||||
---
|
||||
|
||||
## 4. 应用模块划分
|
||||
|
||||
建议 Django apps:
|
||||
|
||||
```text
|
||||
apps/
|
||||
accounts/ 用户、登录、JWT、团队成员
|
||||
teams/ 团队、角色、邀请、权限
|
||||
products/ 商品库、卖点、商品图
|
||||
projects/ 项目、阶段、脚本、分镜
|
||||
assets/ 资产库、TOS 文件、引用关系
|
||||
ai/ 火山 Provider、AIJob、模型配置
|
||||
pipeline/ 5 阶段编排、视频片段、故事板
|
||||
billing/ 额度账户、冻结、扣费、流水、套餐
|
||||
media/ FFmpeg 拼接、字幕、BGM、导出
|
||||
ops/ 运营后台扩展、任务监控、财务对账
|
||||
common/ 审计字段、软删除、幂等、锁、工具
|
||||
```
|
||||
|
||||
模块边界:
|
||||
|
||||
- `ai` 不直接扣费,只上报任务结果和预估成本。
|
||||
- `billing` 不调用火山,只处理额度、冻结、确认扣费和流水。
|
||||
- `assets` 不理解业务阶段,只管理文件、资产类型、引用和权限。
|
||||
- `pipeline` 负责把 PRD 的 5 个 Stage 串起来。
|
||||
- `ops` 只读为主,人工调整必须写审计日志。
|
||||
|
||||
---
|
||||
|
||||
## 5. 关键数据模型
|
||||
|
||||
### 5.1 账户与团队
|
||||
|
||||
- `User`
|
||||
- `Team`
|
||||
- `TeamMember`
|
||||
- `Invitation`
|
||||
- `Role`
|
||||
|
||||
V1 决策:
|
||||
|
||||
- 一个用户默认属于一个团队。
|
||||
- 注册自动创建团队,注册者为超管。
|
||||
- 预留多团队字段,但 V1 不开放切换多团队。
|
||||
|
||||
### 5.2 商品与项目
|
||||
|
||||
- `Product`
|
||||
- `ProductImage`
|
||||
- `ProductSellingPoint`
|
||||
- `Project`
|
||||
- `ProjectStageState`
|
||||
- `Script`
|
||||
- `ScriptShot`
|
||||
|
||||
Project 关键字段:
|
||||
|
||||
- `team_id`
|
||||
- `product_id`
|
||||
- `creator_id`
|
||||
- `target_duration_seconds`:30 / 45 / 60
|
||||
- `segment_count`:2 / 3 / 4
|
||||
- `current_stage`
|
||||
- `status`
|
||||
|
||||
### 5.3 资产
|
||||
|
||||
- `Asset`
|
||||
- `AssetVersion`
|
||||
- `AssetReference`
|
||||
|
||||
资产类型:
|
||||
|
||||
- product_image
|
||||
- product_triptych
|
||||
- character_portrait
|
||||
- character_triptych
|
||||
- scene_image
|
||||
- storyboard
|
||||
- video_clip
|
||||
- final_video
|
||||
- bgm
|
||||
- subtitle
|
||||
|
||||
关键字段:
|
||||
|
||||
- `team_id`
|
||||
- `project_id`
|
||||
- `owner_id`
|
||||
- `tos_key`
|
||||
- `mime_type`
|
||||
- `duration_seconds`
|
||||
- `width`
|
||||
- `height`
|
||||
- `source`
|
||||
- `status`
|
||||
- `is_shared`
|
||||
|
||||
### 5.4 AI 任务
|
||||
|
||||
- `AIJob`
|
||||
- `AIJobAttempt`
|
||||
- `ModelConfig`
|
||||
|
||||
AIJob 关键字段:
|
||||
|
||||
- `job_type`:text / image / video
|
||||
- `provider`:volcengine
|
||||
- `model_name`
|
||||
- `request_payload`
|
||||
- `response_payload`
|
||||
- `external_task_id`
|
||||
- `status`
|
||||
- `progress`
|
||||
- `error_code`
|
||||
- `error_message`
|
||||
- `estimated_cost`
|
||||
- `actual_cost`
|
||||
- `idempotency_key`
|
||||
|
||||
任务状态:
|
||||
|
||||
```text
|
||||
created -> quota_checked -> queued -> submitted -> polling -> succeeded
|
||||
-> failed
|
||||
-> timeout
|
||||
-> cancelled
|
||||
```
|
||||
|
||||
### 5.5 视频片段与导出
|
||||
|
||||
- `VideoSegment`
|
||||
- `VideoSegmentVersion`
|
||||
- `ExportJob`
|
||||
- `TimelineItem`
|
||||
- `SubtitleCue`
|
||||
|
||||
VideoSegment:
|
||||
|
||||
- `project_id`
|
||||
- `segment_index`
|
||||
- `start_second`
|
||||
- `end_second`
|
||||
- `prompt`
|
||||
- `use_storyboard`
|
||||
- `adopted_version_id`
|
||||
- `status`
|
||||
|
||||
60s 项目生成 4 个 VideoSegment:
|
||||
|
||||
- 0-15s
|
||||
- 15-30s
|
||||
- 30-45s
|
||||
- 45-60s
|
||||
|
||||
### 5.6 额度与财务
|
||||
|
||||
- `Wallet`
|
||||
- `QuotaPolicy`
|
||||
- `QuotaUsage`
|
||||
- `BillingTransaction`
|
||||
- `BillingHold`
|
||||
- `PricingRule`
|
||||
- `RechargeOrder`
|
||||
|
||||
四层额度:
|
||||
|
||||
- 用户日额度
|
||||
- 用户月额度
|
||||
- 团队月额度
|
||||
- 团队总额度池
|
||||
|
||||
账务动作:
|
||||
|
||||
- estimate
|
||||
- hold
|
||||
- release
|
||||
- charge
|
||||
- refund
|
||||
- manual_adjust
|
||||
|
||||
所有扣费以 `BillingTransaction` 为准,不从任务表反推财务结果。
|
||||
|
||||
---
|
||||
|
||||
## 6. Redis 设计
|
||||
|
||||
Redis DB index:
|
||||
|
||||
- DB 0:Django cache
|
||||
- DB 1:Celery broker
|
||||
- DB 2:Celery result backend
|
||||
- DB 3:分布式锁、幂等锁、防重复扣费锁
|
||||
- DB 4:限流、验证码计数、短期风控
|
||||
- DB 5:任务进度 pubsub / WebSocket 预留
|
||||
|
||||
锁设计:
|
||||
|
||||
- `lock:billing:confirm:{job_id}`
|
||||
- `lock:project:generate:{project_id}`
|
||||
- `lock:segment:generate:{segment_id}`
|
||||
- `lock:export:{project_id}`
|
||||
|
||||
锁必须有 TTL,且所有关键写入仍要依赖数据库唯一约束保证最终幂等。
|
||||
|
||||
---
|
||||
|
||||
## 7. 火山 ARK Provider 设计
|
||||
|
||||
所有模型通过统一 Provider 调用:
|
||||
|
||||
```text
|
||||
AIProvider
|
||||
generate_text()
|
||||
generate_image()
|
||||
create_video_task()
|
||||
get_video_task()
|
||||
```
|
||||
|
||||
当前模型决策来自 `account.md`,代码只读取环境变量:
|
||||
|
||||
- 文本主模型:DeepSeek-V3-2
|
||||
- 文本备用模型:Doubao Seed 2.0 Pro / Lite
|
||||
- 图片模型:Seedream 5.0 Lite / 5.0 / 4.5
|
||||
- 视频模型:Seedance 2.0 / 2.0 Fast / 1.5 Pro
|
||||
|
||||
接口策略:
|
||||
|
||||
- 文本:OpenAI-compatible chat
|
||||
- 图片:同步或短异步,统一落成 AIJob
|
||||
- 视频:异步任务,提交后轮询
|
||||
- 所有外部响应原文进入 `response_payload`,便于排障
|
||||
|
||||
模型配置不硬编码在业务流程中。业务流程只声明用途:
|
||||
|
||||
- script_generation
|
||||
- asset_prompt_generation
|
||||
- product_image_optimize
|
||||
- storyboard_generation
|
||||
- video_segment_generation
|
||||
|
||||
由 ModelConfig 决定具体模型。
|
||||
|
||||
---
|
||||
|
||||
## 8. 60s 多段生产流程
|
||||
|
||||
### 8.1 Stage 1 脚本
|
||||
|
||||
输入:
|
||||
|
||||
- 商品信息
|
||||
- 卖点
|
||||
- 目标时长
|
||||
- 用户指令
|
||||
|
||||
输出:
|
||||
|
||||
- Script
|
||||
- ScriptShot
|
||||
- 自动切段结果
|
||||
|
||||
60s 输出要求:
|
||||
|
||||
- `segment_count = 4`
|
||||
- 每段约 15s
|
||||
- 每个镜头必须归属 segment_index
|
||||
|
||||
### 8.2 Stage 2 基础资产
|
||||
|
||||
生成:
|
||||
|
||||
- 商品三视图
|
||||
- 人物立绘
|
||||
- 人物三视图
|
||||
- 场景图
|
||||
|
||||
资产候选规则:
|
||||
|
||||
- 创意选择型一次 4 张
|
||||
- 结构转换型一次 1 张
|
||||
- 采用后才进入当前项目引用
|
||||
|
||||
### 8.3 Stage 3 故事板
|
||||
|
||||
故事板是可选项,不是硬前置。
|
||||
|
||||
如果生成:
|
||||
|
||||
- 每段 1 张故事板图
|
||||
- 60s 项目最多 4 张
|
||||
- 每张可独立重跑
|
||||
|
||||
### 8.4 Stage 4 视频片段
|
||||
|
||||
每个 VideoSegment 独立生成:
|
||||
|
||||
- 输入:脚本分段、基础资产、可选故事板、视频提示词
|
||||
- 输出:VideoSegmentVersion
|
||||
- 用户采用某一版后,才进入可拼接素材
|
||||
|
||||
并发策略:
|
||||
|
||||
- 单项目最多 4 段并发
|
||||
- 全局并发由 Worker 数和 Redis 队列控制
|
||||
- 外部配额不足时降级到每项目 2 段并发
|
||||
|
||||
### 8.5 Stage 5 拼接导出
|
||||
|
||||
输入:
|
||||
|
||||
- 已采用的视频片段
|
||||
- 时间线配置
|
||||
- 字幕
|
||||
- BGM
|
||||
- 转场
|
||||
|
||||
输出:
|
||||
|
||||
- final_video Asset
|
||||
- ExportJob
|
||||
|
||||
第一版导出能力:
|
||||
|
||||
- 单主轨
|
||||
- 排序
|
||||
- 裁剪
|
||||
- 字幕烧录
|
||||
- BGM 混音
|
||||
- 9:16
|
||||
- 1080P MP4
|
||||
|
||||
---
|
||||
|
||||
## 9. API 设计原则
|
||||
|
||||
API 应按资源和动作拆分,不把复杂动作塞进一个“大生成接口”。
|
||||
|
||||
示例:
|
||||
|
||||
```text
|
||||
POST /api/products/
|
||||
GET /api/products/
|
||||
POST /api/projects/
|
||||
GET /api/projects/{id}/
|
||||
|
||||
POST /api/projects/{id}/script/generate/
|
||||
POST /api/projects/{id}/script/confirm/
|
||||
|
||||
POST /api/projects/{id}/assets/generate/
|
||||
POST /api/assets/{id}/adopt/
|
||||
|
||||
POST /api/projects/{id}/storyboards/generate/
|
||||
POST /api/storyboards/{id}/adopt/
|
||||
|
||||
POST /api/video-segments/{id}/generate/
|
||||
POST /api/video-segment-versions/{id}/adopt/
|
||||
|
||||
POST /api/projects/{id}/exports/
|
||||
GET /api/exports/{id}/
|
||||
|
||||
GET /api/ai-jobs/{id}/
|
||||
POST /api/billing/estimate/
|
||||
GET /api/billing/transactions/
|
||||
```
|
||||
|
||||
前端轮询策略:
|
||||
|
||||
- AIJob 详情接口提供统一进度。
|
||||
- Stage 页面不直接轮询火山。
|
||||
- 后续可用 SSE/WebSocket 替代轮询。
|
||||
|
||||
---
|
||||
|
||||
## 10. 运营后台
|
||||
|
||||
第一版用 Django Admin 承担运营后台,不另起复杂后台前端。
|
||||
|
||||
必须有:
|
||||
|
||||
- 用户管理
|
||||
- 团队管理
|
||||
- 额度账户
|
||||
- 消费流水
|
||||
- AIJob 任务监控
|
||||
- 视频片段与导出任务
|
||||
- 模型配置
|
||||
- PricingRule
|
||||
- 人工补偿/退款/额度调整
|
||||
|
||||
人工操作要求:
|
||||
|
||||
- 必须写审计日志
|
||||
- 财务调整必须写 BillingTransaction
|
||||
- 禁止直接改余额字段绕过账本
|
||||
|
||||
---
|
||||
|
||||
## 11. 部署与环境
|
||||
|
||||
环境:
|
||||
|
||||
- local
|
||||
- test
|
||||
- production
|
||||
|
||||
敏感配置:
|
||||
|
||||
- 本地测试凭据记录在 `account.md`
|
||||
- 代码与架构文档不保存真实密钥
|
||||
- K8s 使用 Secret 注入环境变量
|
||||
|
||||
K8s 工作负载:
|
||||
|
||||
```text
|
||||
Deployment airshelf-web
|
||||
Deployment airshelf-api
|
||||
Deployment airshelf-worker-default
|
||||
Deployment airshelf-worker-ai
|
||||
Deployment airshelf-worker-media
|
||||
Deployment airshelf-beat
|
||||
Service airshelf-web
|
||||
Service airshelf-api
|
||||
Ingress airshelf
|
||||
Secret airshelf-env
|
||||
ConfigMap airshelf-config
|
||||
```
|
||||
|
||||
CI/CD 需要从当前纯静态部署升级为多镜像构建:
|
||||
|
||||
- web image
|
||||
- api image
|
||||
- worker image 可复用 api image,启动命令不同
|
||||
|
||||
---
|
||||
|
||||
## 12. 可观测性
|
||||
|
||||
日志:
|
||||
|
||||
- API request log
|
||||
- AI provider request/response summary
|
||||
- Celery task log
|
||||
- billing ledger log
|
||||
- export job log
|
||||
|
||||
指标:
|
||||
|
||||
- AI 任务成功率
|
||||
- AI 平均耗时
|
||||
- 视频段失败率
|
||||
- 导出失败率
|
||||
- 队列长度
|
||||
- Worker 并发
|
||||
- TOS 上传失败率
|
||||
- 额度冻结未释放数量
|
||||
|
||||
告警:
|
||||
|
||||
- AI 任务连续失败
|
||||
- 队列堆积
|
||||
- 导出任务超时
|
||||
- Billing hold 超时未释放
|
||||
- Redis / MySQL 不可用
|
||||
|
||||
---
|
||||
|
||||
## 13. 安全与权限
|
||||
|
||||
权限模型:
|
||||
|
||||
- 超管:团队所有权限、充值、额度划拨、财务查看
|
||||
- 团管:成员管理、成员额度分配、团队资产管理
|
||||
- 成员:创建项目、使用额度、管理自己的项目
|
||||
|
||||
安全要求:
|
||||
|
||||
- 所有 API 必须按 team_id 做数据隔离
|
||||
- 资产下载使用签名 URL
|
||||
- 上传文件做类型、大小、时长校验
|
||||
- 后台人工操作写审计
|
||||
- ARK/TOS/Redis/MySQL 密钥只走环境变量
|
||||
- JWT refresh token 需要轮换和黑名单
|
||||
|
||||
---
|
||||
|
||||
## 14. 关键风险与架构应对
|
||||
|
||||
| 风险 | 应对 |
|
||||
| --- | --- |
|
||||
| PRD 60s 与页面流程 15s 口径冲突 | 以 60s 多段为工程目标,页面文案后续统一 |
|
||||
| AI 任务失败或超时 | AIJob 状态机 + Attempt + 重试 + 单段重跑 |
|
||||
| 重复扣费 | BillingHold + 幂等 key + Redis lock + DB 唯一约束 |
|
||||
| 外部模型并发不足 | 队列限流,单项目并发可降级 |
|
||||
| TOS 文件失控增长 | tmp 前缀清理任务,资产软删除,引用检查 |
|
||||
| 视频导出耗时长 | media worker 独立队列,任务进度入库 |
|
||||
| 运营后台需求膨胀 | V1 先 Django Admin,后续再独立后台 |
|
||||
|
||||
---
|
||||
|
||||
## 15. 开发路线
|
||||
|
||||
### Phase 0:工程初始化
|
||||
|
||||
- 创建 Django 项目
|
||||
- 配置 MySQL / Redis / Celery / TOS
|
||||
- Dockerfile 与 K8s 基础部署
|
||||
- 健康检查与环境变量管理
|
||||
|
||||
验收:
|
||||
|
||||
- API 可启动
|
||||
- Worker 可启动
|
||||
- 能连接 MySQL / Redis
|
||||
- 能上传测试文件到 TOS
|
||||
|
||||
### Phase 1:业务地基
|
||||
|
||||
- 用户、团队、角色
|
||||
- 商品库
|
||||
- 项目
|
||||
- 资产模型
|
||||
- AIJob
|
||||
- Billing 账本
|
||||
|
||||
验收:
|
||||
|
||||
- 注册自动建团队
|
||||
- 商品 CRUD
|
||||
- 项目创建
|
||||
- 额度预检、冻结、释放、确认扣费可跑通
|
||||
|
||||
### Phase 2:AI 纵向闭环
|
||||
|
||||
- 脚本生成
|
||||
- 基础资产生成
|
||||
- 故事板生成
|
||||
- 4 段视频生成
|
||||
- 结果入 TOS 和资产库
|
||||
|
||||
验收:
|
||||
|
||||
- 一个 60s 项目可生成 4 个视频片段
|
||||
- 单段失败可重跑
|
||||
- 用户采用后扣费
|
||||
|
||||
### Phase 3:导出与前端联调
|
||||
|
||||
- FFmpeg 拼接
|
||||
- 字幕
|
||||
- BGM
|
||||
- 1080P MP4 导出
|
||||
- 前端接真实 API
|
||||
|
||||
验收:
|
||||
|
||||
- 4 段视频可导出成 60s 成片
|
||||
- 成片入库
|
||||
- 可下载、可预览
|
||||
|
||||
### Phase 4:运营后台与上线硬化
|
||||
|
||||
- Django Admin 增强
|
||||
- 任务监控
|
||||
- 财务对账
|
||||
- 模型配置
|
||||
- 日志告警
|
||||
- 并发压测
|
||||
|
||||
验收:
|
||||
|
||||
- 运营能查任务、查用户、查流水、人工调整额度
|
||||
- 失败任务可定位
|
||||
- 队列堆积可观测
|
||||
|
||||
---
|
||||
|
||||
## 16. 最终判断
|
||||
|
||||
AirShelf 的架构核心不是“页面数量”,而是“AI 生产系统 + 账本系统 + 资产系统”的一致性。
|
||||
|
||||
正确的第一目标是:
|
||||
|
||||
> 用 Django + Celery + TOS + 火山 ARK 打穿真实 60s 多段视频生产闭环,并保证失败恢复和扣费一致性。
|
||||
|
||||
页面可以逐步接入,运营后台可以先用 Django Admin,但账本、任务状态机、资产引用和 AI Provider 必须从第一天按真实产品设计。
|
||||
Reference in New Issue
Block a user