# ADR 003: 剧本拆解与素材关联架构设计 > **状态**:已接受 > **日期**:2025-01-27 > **决策者**:架构团队 --- ## 背景 在视频创作工作流中,用户上传剧本后,需要通过 AI 拆解剧本,提取角色、场景、道具等信息,并生成对应的可视化素材。这些数据需要合理的存储架构来支持: 1. 剧本文本信息的结构化存储 2. AI 生成的可视化素材管理 3. 剧本元素与素材的关联追踪 4. 素材在分镜中的使用情况查询 ## 决策 采用**双层数据架构**,将"文字描述"和"可视化素材"分离存储,并建立清晰的关联关系。 ### 架构设计 ``` 剧本层(文字描述) ├─ 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/real - `file_url`、`thumbnail_url`:文件 URL - `screenplay_character_id`:来源角色(可选) - `screenplay_scene_id`:来源场景(可选) - `screenplay_prop_id`:来源道具(可选) - `checksum`:文件去重 **设计理由**: - 素材是项目级别的,可以被多个剧本、多个分镜复用 - 一个剧本角色可以生成多个素材(不同风格、不同角度) - 素材记录来源信息,便于追溯和管理 - 支持用户直接上传素材(不关联剧本元素) #### 3. 分镜素材关联表(storyboard_resources) **职责**:记录分镜使用了哪些素材 **关键字段**: - `storyboard_id`:分镜 ID - `project_resource_id`:素材 ID - `resource_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" } ``` ### 查询路径 **查询"角色张三在哪些分镜中出现"**: ```sql 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 = ?; ``` **查询"剧本角色张三对应哪些素材"**: ```sql 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 表,不区分剧本层和素材层 **优点**: - 结构简单,无需新增表 - 查询路径短 **缺点**: - 无法区分"剧本描述"和"实际素材" - 一个项目有多个剧本时,角色信息混乱 - 无法支持"剧本角色 → 多个素材"的场景 - 不符合业务逻辑(剧本拆解产生的是文字,不是文件) **拒绝理由**:不符合业务逻辑,扩展性差 ## 影响 ### 正面影响 1. **清晰的数据分层**:文字描述和可视化素材分离,职责明确 2. **灵活的关联关系**:一个剧本角色可以对应多个素材 3. **素材复用**:项目级别的素材可以被多个剧本、多个分镜使用 4. **完整的追溯链路**:可以查询素材来源、使用情况 5. **支持多剧本**:一个项目可以有多个剧本,每个剧本有独立的角色列表 ### 负面影响 1. **查询复杂度**:需要 3-4 层 JOIN 查询 2. **数据冗余**:resource_type 在 storyboard_resources 中冗余存储 3. **维护成本**:需要维护多个表的关联关系 ### 缓解措施 1. **索引优化**:为所有外键和查询字段创建索引 2. **查询优化**:使用 Repository 层封装复杂查询 3. **缓存策略**:对高频查询结果进行缓存 ## 实现计划 ### Phase 1:数据库迁移 - [x] 创建 screenplay_props 表 - [x] 在 project_resources 表增加来源字段 - screenplay_character_id - screenplay_scene_id - screenplay_prop_id - [x] 创建索引和约束 ### 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 素材生成服务 - [ ] 自动关联剧本元素与素材 ## 相关文档 - [剧本管理服务](../../requirements/backend/04-services/project/screenplay-service.md) - [项目素材管理服务](../../requirements/backend/04-services/resource/project-resource-service.md) - [数据库设计文档](../../requirements/database-design.md) ## 变更记录 **v1.0 (2025-01-27)** - 初始版本 - 确定双层架构设计 - 定义剧本元素表和素材表的关联关系 --- **状态**:已接受 **决策日期**:2025-01-27