You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
6.8 KiB
6.8 KiB
ADR 003: 剧本拆解与素材关联架构设计
状态:已接受
日期:2025-01-27
决策者:架构团队
背景
在视频创作工作流中,用户上传剧本后,需要通过 AI 拆解剧本,提取角色、场景、道具等信息,并生成对应的可视化素材。这些数据需要合理的存储架构来支持:
- 剧本文本信息的结构化存储
- AI 生成的可视化素材管理
- 剧本元素与素材的关联追踪
- 素材在分镜中的使用情况查询
决策
采用双层数据架构,将"文字描述"和"可视化素材"分离存储,并建立清晰的关联关系。
架构设计
剧本层(文字描述)
├─ screenplays(剧本表)
│ ├─ screenplay_characters(剧本角色表)
│ ├─ screenplay_scenes(剧本场景表)
│ └─ screenplay_props(剧本道具表)
│
素材层(可视化文件)
├─ project_resources(项目素材表)
│ ├─ screenplay_character_id(来源角色)
│ ├─ screenplay_scene_id(来源场景)
│ └─ screenplay_prop_id(来源道具)
│
分镜层(素材使用)
└─ storyboard_resources(分镜素材关联表)
核心表设计
1. 剧本元素表(screenplay_characters/scenes/props)
职责:存储剧本文本中提取的角色、场景、道具的文字描述信息
关键字段:
name:名称description:描述metadata:JSONB 扩展字段- 角色:gender、age、nationality、species、biography、personality、appearance
- 场景:location、time_of_day、atmosphere
- 道具:category、importance、material、size、color、function
设计理由:
- 剧本拆解产生的是文字信息,不是可视化文件
- 一个项目可能有多个剧本(不同版本、不同集数)
- 每个剧本有独立的角色、场景、道具列表
2. 项目素材表(project_resources)
职责:存储项目的可视化素材文件(图片、视频)
关键字段:
type:character/scene/prop/realfile_url、thumbnail_url:文件 URLscreenplay_character_id:来源角色(可选)screenplay_scene_id:来源场景(可选)screenplay_prop_id:来源道具(可选)checksum:文件去重
设计理由:
- 素材是项目级别的,可以被多个剧本、多个分镜复用
- 一个剧本角色可以生成多个素材(不同风格、不同角度)
- 素材记录来源信息,便于追溯和管理
- 支持用户直接上传素材(不关联剧本元素)
3. 分镜素材关联表(storyboard_resources)
职责:记录分镜使用了哪些素材
关键字段:
storyboard_id:分镜 IDproject_resource_id:素材 IDresource_type:素材类型(冗余字段,优化查询)
设计理由:
- 多对多关系,一个分镜可以使用多个素材
- 一个素材可以被多个分镜使用
数据流
1. 用户上传剧本
↓
2. AI 拆解剧本
↓
3. 存储到剧本元素表
screenplay_characters: {name: "张三", gender: "male", age: 30, ...}
screenplay_scenes: {title: "咖啡厅", location: "室内", ...}
screenplay_props: {name: "古剑", category: "武器", ...}
↓
4. AI 生成素材(可选)
↓
5. 存储到项目素材表
project_resources: {
type: "character",
file_url: "...",
screenplay_character_id: "xxx"
}
↓
6. 用户在分镜中选择素材
↓
7. 创建分镜素材关联
storyboard_resources: {
storyboard_id: "yyy",
project_resource_id: "zzz"
}
查询路径
查询"角色张三在哪些分镜中出现":
SELECT s.storyboard_id, s.title
FROM screenplay_characters sc
JOIN project_resources pr ON pr.screenplay_character_id = sc.character_id
JOIN storyboard_resources sr ON sr.project_resource_id = pr.id
JOIN storyboards s ON s.storyboard_id = sr.storyboard_id
WHERE sc.name = '张三' AND sc.screenplay_id = ?;
查询"剧本角色张三对应哪些素材":
SELECT pr.*
FROM screenplay_characters sc
JOIN project_resources pr ON pr.screenplay_character_id = sc.character_id
WHERE sc.name = '张三' AND sc.screenplay_id = ?;
备选方案
方案 B:单层架构(已拒绝)
设计:只使用 project_resources 表,不区分剧本层和素材层
优点:
- 结构简单,无需新增表
- 查询路径短
缺点:
- 无法区分"剧本描述"和"实际素材"
- 一个项目有多个剧本时,角色信息混乱
- 无法支持"剧本角色 → 多个素材"的场景
- 不符合业务逻辑(剧本拆解产生的是文字,不是文件)
拒绝理由:不符合业务逻辑,扩展性差
影响
正面影响
- 清晰的数据分层:文字描述和可视化素材分离,职责明确
- 灵活的关联关系:一个剧本角色可以对应多个素材
- 素材复用:项目级别的素材可以被多个剧本、多个分镜使用
- 完整的追溯链路:可以查询素材来源、使用情况
- 支持多剧本:一个项目可以有多个剧本,每个剧本有独立的角色列表
负面影响
- 查询复杂度:需要 3-4 层 JOIN 查询
- 数据冗余:resource_type 在 storyboard_resources 中冗余存储
- 维护成本:需要维护多个表的关联关系
缓解措施
- 索引优化:为所有外键和查询字段创建索引
- 查询优化:使用 Repository 层封装复杂查询
- 缓存策略:对高频查询结果进行缓存
实现计划
Phase 1:数据库迁移
- 创建 screenplay_props 表
- 在 project_resources 表增加来源字段
- screenplay_character_id
- screenplay_scene_id
- screenplay_prop_id
- 创建索引和约束
Phase 2:服务层实现
- 更新 ScreenplayService
- add_prop() 方法
- 更新 ProjectResourceService
- create_project_resource() 支持来源字段
- get_resources_by_screenplay_element() 方法
- 更新 Repository 层
Phase 3:API 接口
- POST /api/v1/screenplays/{screenplay_id}/props
- POST /api/v1/projects/{project_id}/resources(支持来源参数)
- GET /api/v1/projects/{project_id}/resources/by-screenplay-element
Phase 4:AI 集成
- AI 剧本拆解服务
- AI 素材生成服务
- 自动关联剧本元素与素材
相关文档
变更记录
v1.0 (2025-01-27)
- 初始版本
- 确定双层架构设计
- 定义剧本元素表和素材表的关联关系
状态:已接受
决策日期:2025-01-27