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.7 KiB

ResourceLibraryService 实现

日期: 2026-02-03
类型: 新功能
影响范围: 后端服务层、API 层、数据模型

概述

实现了 ResourceLibraryService 服务,用于整合剧本元素(角色、场景、道具)、标签和项目资源的数据,为前端提供统一的资源库接口。

变更内容

1. 新增服务层

文件: server/app/services/resource_library_service.py

实现了以下核心方法:

  • get_characters() - 获取所有角色列表(包含标签和资源)
  • get_locations() - 获取所有场景列表(包含标签和资源)
  • get_props() - 获取所有道具列表(包含标签和资源)
  • get_footage_resources() - 获取实拍资源列表
  • get_element_with_tags() - 获取元素的所有标签和资源

关键特性

  • 支持父子项目资源聚合(include_subprojects 参数)
  • 返回所有元素(包含有资源和无资源的)
  • 使用 selectinload 预加载关联数据,避免 N+1 查询
  • 不感知 storyboard_items 表(职责分离)
  • 完整的权限检查和日志记录

2. 新增 Schema 定义

文件: server/app/schemas/resource_library.py

定义了以下 Pydantic 模型:

  • ResourceInTag - 标签中的资源
  • ElementTag - 元素标签
  • CharacterWithResources - 角色(包含标签和资源)
  • LocationWithResources - 场景(包含标签和资源)
  • PropWithResources - 道具(包含标签和资源)
  • FootageResource - 实拍资源
  • ElementWithTags - 元素详情(包含所有标签和资源)

3. 新增 API 路由

文件: server/app/api/v1/resource_library.py

实现了 5 个 API 端点:

GET /api/v1/projects/{project_id}/resource-library/characters
GET /api/v1/projects/{project_id}/resource-library/locations
GET /api/v1/projects/{project_id}/resource-library/props
GET /api/v1/projects/{project_id}/resource-library/footage-resources
GET /api/v1/projects/{project_id}/resource-library/elements/{element_type}/{element_id}/tags-with-resources

所有端点支持 include_subprojects 查询参数。

4. 新增数据模型

创建了以下 SQLModel 模型:

  • server/app/models/screenplay.py - 剧本主表模型
  • server/app/models/screenplay_character.py - 剧本角色模型
  • server/app/models/screenplay_location.py - 剧本场景模型
  • server/app/models/screenplay_prop.py - 剧本道具模型
  • server/app/models/screenplay_element_tag.py - 剧本元素标签模型

关键设计

  • 使用 UUID v7 主键
  • 使用 SMALLINT + IntEnum 替代 PostgreSQL ENUM
  • 使用 selectinload 配置关系预加载
  • 提供 *_str 属性方法用于枚举值转字符串

5. 路由注册

文件: server/app/api/v1/__init__.py

注册了 resource_library 路由到 API v1 路由器。

技术规范遵循

UUID v7: 所有主键使用 UUID v7(应用层生成)
无物理外键: 仅在模型层定义关系,数据库层无 FOREIGN KEY 约束
SMALLINT 枚举: 使用 SMALLINT + IntEnum 替代 PostgreSQL ENUM
日志格式: 使用 %-formatting 格式化日志
异常日志: 异常日志添加 exc_info=True
API 响应: 使用 success_response() 统一响应格式
日志系统: 使用 app.core.logging.get_logger 获取 logger
权限检查: 所有方法都进行项目权限验证

数据流程

获取角色列表流程

  1. 检查用户对项目的访问权限
  2. 获取项目ID列表(包含子项目,如果 include_subprojects=true
  3. 查询项目的所有剧本ID
  4. 查询剧本的所有角色(预加载标签)
  5. 查询标签关联的项目资源
  6. 组装返回数据(角色 → 标签 → 资源)

父子项目资源聚合

include_subprojects=true 时:

  1. 查询父项目的所有子项目ID
  2. 将父项目ID和子项目ID合并为项目ID列表
  3. 查询所有项目的剧本和资源
  4. 返回聚合后的数据

API 使用示例

获取角色列表

GET /api/v1/projects/{project_id}/resource-library/characters?include_subprojects=false

响应:

{
  "success": true,
  "code": 200,
  "message": "success",
  "data": [
    {
      "character_id": "uuid",
      "screenplay_id": "uuid",
      "name": "张三",
      "description": "主角",
      "role_type": "main",
      "is_offscreen": false,
      "has_tags": true,
      "tags": [
        {
          "tag_id": "uuid",
          "tag_label": "少年",
          "description": "15岁",
          "display_order": 0,
          "resources": [
            {
              "project_resource_id": "uuid",
              "name": "张三-少年形象",
              "type": "character",
              "file_url": "https://...",
              "thumbnail_url": "https://..."
            }
          ]
        }
      ]
    }
  ],
  "timestamp": "2026-02-03T10:00:00Z"
}

获取元素详情

GET /api/v1/projects/{project_id}/resource-library/elements/character/{character_id}/tags-with-resources

依赖关系

依赖的服务

  • ProjectRepository - 项目权限检查

依赖的模型

  • Screenplay - 剧本主表
  • ScreenplayCharacter - 剧本角色
  • ScreenplayLocation - 剧本场景
  • ScreenplayProp - 剧本道具
  • ScreenplayElementTag - 剧本元素标签
  • ProjectResource - 项目资源
  • Project - 项目表

性能优化

  1. 预加载关联数据: 使用 selectinload() 预加载标签,避免 N+1 查询
  2. 批量查询资源: 收集所有标签ID后批量查询资源,而非逐个查询
  3. 索引优化: 依赖数据库迁移中创建的索引(screenplay_id, element_id, element_tag_id

测试建议

单元测试

  • 测试权限检查逻辑
  • 测试父子项目资源聚合
  • 测试空数据情况(无剧本、无标签、无资源)

集成测试

  • 测试完整的数据查询流程
  • 测试 include_subprojects 参数
  • 测试不同元素类型的查询

性能测试

  • 测试大量角色/标签/资源的查询性能
  • 测试预加载是否生效(检查 SQL 查询数量)

后续优化

  1. 缓存: 考虑对资源库数据添加 Redis 缓存
  2. 分页: 如果角色/场景/道具数量很大,考虑添加分页支持
  3. 搜索: 添加按名称搜索角色/场景/道具的功能
  4. 排序: 支持自定义排序(按名称、创建时间等)

相关文档

  • 设计文档: docs/requirements/backend/04-services/project/resource-library-service.md
  • 技术栈规范: docs/architecture/tech-stack.md
  • 数据库迁移: server/alembic/versions/20260203_1300_create_screenplay_tables.py

作者

Kiro AI Assistant

审核状态

  • 代码审核
  • 测试验证
  • 文档审核