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

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_urlthumbnail_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"
   }

查询路径

查询"角色张三在哪些分镜中出现"

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 表,不区分剧本层和素材层

优点

  • 结构简单,无需新增表
  • 查询路径短

缺点

  • 无法区分"剧本描述"和"实际素材"
  • 一个项目有多个剧本时,角色信息混乱
  • 无法支持"剧本角色 → 多个素材"的场景
  • 不符合业务逻辑(剧本拆解产生的是文字,不是文件)

拒绝理由:不符合业务逻辑,扩展性差

影响

正面影响

  1. 清晰的数据分层:文字描述和可视化素材分离,职责明确
  2. 灵活的关联关系:一个剧本角色可以对应多个素材
  3. 素材复用:项目级别的素材可以被多个剧本、多个分镜使用
  4. 完整的追溯链路:可以查询素材来源、使用情况
  5. 支持多剧本:一个项目可以有多个剧本,每个剧本有独立的角色列表

负面影响

  1. 查询复杂度:需要 3-4 层 JOIN 查询
  2. 数据冗余:resource_type 在 storyboard_resources 中冗余存储
  3. 维护成本:需要维护多个表的关联关系

缓解措施

  1. 索引优化:为所有外键和查询字段创建索引
  2. 查询优化:使用 Repository 层封装复杂查询
  3. 缓存策略:对高频查询结果进行缓存

实现计划

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