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.
 

12 KiB

Screenplay Services 实现

变更日期:2026-02-03
变更类型:功能实现
影响范围:后端服务层


变更概述

实现了剧本管理服务(ScreenplayService)和剧本标签管理服务(ScreenplayTagService),完善了 Repository 层的 CRUD 方法,为剧本功能提供完整的业务逻辑支持。


变更详情

1. Repository 层完善

1.1 ScreenplayRepository 增强

文件server/app/repositories/screenplay_repository.py

新增方法

  • create() - 创建剧本
  • update() - 更新剧本
  • delete() - 软删除剧本
  • create_character() - 创建角色
  • update_character() - 更新角色
  • delete_character() - 删除角色
  • create_location() - 创建场景
  • update_location() - 更新场景
  • delete_location() - 删除场景
  • create_prop() - 创建道具
  • update_prop() - 更新道具
  • delete_prop() - 删除道具

日志规范

  • 使用 get_logger(__name__) 替代 logging.getLogger()
  • 使用 %-formatting 格式化日志消息
  • 异常日志使用 exc_info=True

1.2 ScreenplayTagRepository 增强

文件server/app/repositories/screenplay_tag_repository.py

新增方法

  • create() - 创建标签
  • update() - 更新标签
  • delete() - 删除标签
  • count_resources_by_tag() - 统计标签关联的资源数量

日志规范

  • 修正 logging 导入为 get_logger(__name__)
  • 统一日志格式

2. Service 层实现

2.1 ScreenplayService

文件server/app/services/screenplay_service.py

核心功能

  • 剧本查询(按 ID)
  • 角色管理(创建)
  • 场景管理(创建)
  • 道具管理(创建)
  • AI 解析数据存储(store_parsed_elements()
  • 权限检查(_check_project_permission()

关键方法

async def store_parsed_elements(
    self,
    screenplay_id: UUID,
    parsed_data: Dict[str, Any]
) -> Dict[str, Any]:
    """
    存储 AI 解析的剧本元素(供 Celery Worker 调用)
    
    流程:
    1. 存储角色 → character_id_map
    2. 存储场景 → location_id_map
    3. 存储道具 → prop_id_map
    4. 调用 ScreenplayTagService.store_tags() 存储标签
    5. 更新剧本统计(character_count, location_count)
    6. 提交事务
    
    返回:
    - character_id_map: {角色名: UUID}
    - location_id_map: {场景名: UUID}
    - prop_id_map: {道具名: UUID}
    - tag_id_maps: {element_type: {元素名-标签名: UUID}}
    """

技术栈符合性

  • 使用 async/await 异步编程
  • 使用 get_logger(__name__) 获取 logger
  • 使用 %-formatting 格式化日志
  • 异常日志使用 exc_info=True
  • 时间戳使用 datetime.now(timezone.utc)
  • 枚举类型使用 IntEnum(RoleType.from_string()

2.2 ScreenplayTagService

文件server/app/services/screenplay_tag_service.py

核心功能

  • 标签 CRUD(创建、查询、更新、删除)
  • 按元素查询标签(get_tags_by_element()
  • 按剧本查询标签(get_tags_by_screenplay()
  • AI 解析标签存储(store_tags()
  • has_tags 字段维护(_update_element_has_tags()
  • 权限检查

关键方法

async def store_tags(
    self,
    screenplay_id: UUID,
    parsed_data: Dict[str, Any],
    character_id_map: Dict[str, UUID],
    location_id_map: Dict[str, UUID],
    prop_id_map: Dict[str, UUID]
) -> Dict[str, Dict[str, UUID]]:
    """
    存储 AI 解析的标签(供 ScreenplayService 调用)
    
    流程:
    1. 遍历 character_tags,创建角色标签
    2. 遍历 location_tags,创建场景标签
    3. 遍历 prop_tags,创建道具标签
    4. 更新元素的 has_tags 标志
    
    返回:
    - character_tags: {角色名-标签名: tag_id}
    - location_tags: {场景名-标签名: tag_id}
    - prop_tags: {道具名-标签名: tag_id}
    """

has_tags 字段维护逻辑

  • 创建标签时:自动设置 has_tags = true
  • 删除标签时:检查是否还有其他标签,如果没有则设置 has_tags = false
  • AI 解析时:批量设置 has_tags = true

技术栈符合性

  • 使用 async/await 异步编程
  • 使用 get_logger(__name__) 获取 logger
  • 使用 %-formatting 格式化日志
  • 异常日志使用 exc_info=True
  • 枚举类型使用 IntEnum(ElementType.from_string()

3. 数据流程

3.1 AI 解析剧本流程

AI Service (Celery Worker)
    ↓
ScreenplayService.store_parsed_elements()
    ├─ 创建角色 (ScreenplayRepository.create_character)
    ├─ 创建场景 (ScreenplayRepository.create_location)
    ├─ 创建道具 (ScreenplayRepository.create_prop)
    ↓
ScreenplayTagService.store_tags()
    ├─ 创建角色标签 (ScreenplayTagRepository.create)
    ├─ 创建场景标签 (ScreenplayTagRepository.create)
    ├─ 创建道具标签 (ScreenplayTagRepository.create)
    └─ 更新 has_tags 标志 (ScreenplayRepository.update_*)
    ↓
返回 ID 映射 (用于后续分镜关联)

3.2 标签 ID 映射结构

{
    'character_id_map': {
        '孙悟空': UUID('019d1234-5678-7abc-def0-111111111111')
    },
    'location_id_map': {
        '花果山': UUID('019d1234-5678-7abc-def0-222222222222')
    },
    'prop_id_map': {
        '金箍棒': UUID('019d1234-5678-7abc-def0-333333333333')
    },
    'tag_id_maps': {
        'character_tags': {
            '孙悟空-少年': UUID('019d1234-5678-7abc-def0-444444444444'),
            '孙悟空-成年': UUID('019d1234-5678-7abc-def0-555555555555')
        },
        'location_tags': {
            '花果山-白天': UUID('019d1234-5678-7abc-def0-666666666666'),
            '花果山-夜晚': UUID('019d1234-5678-7abc-def0-777777777777')
        },
        'prop_tags': {
            '金箍棒-崭新': UUID('019d1234-5678-7abc-def0-888888888888')
        }
    }
}

技术栈符合性检查

异步编程

  • 所有数据库操作使用 async/await
  • Repository 方法全部异步
  • Service 方法全部异步

日志规范

  • 使用 get_logger(__name__) 获取模块级 logger
  • 使用 %-formatting 格式化日志消息
  • 异常日志使用 exc_info=True
  • 日志级别:info(正常操作)、warning(异常情况)、error(错误)、debug(调试信息)

时间戳

  • 使用 datetime.now(timezone.utc) 生成 UTC 时间
  • 数据库字段使用 TIMESTAMPTZ 类型

枚举类型

  • 使用 IntEnum 定义枚举(RoleType, ElementType
  • 提供 from_string() 方法进行字符串转换
  • 数据库存储 SMALLINT 类型

异常处理

  • 使用自定义异常(NotFoundError, ValidationError, PermissionError
  • 异常日志包含上下文信息
  • 事务失败时回滚(await self.db.rollback()

已实现功能(第二阶段)

3. Schema 层实现

3.1 剧本 Schema

文件server/app/schemas/screenplay.py

定义的模型

  • ScreenplayBase - 剧本基础模型
  • ScreenplayCreate - 创建剧本请求
  • ScreenplayUpdate - 更新剧本请求
  • ScreenplayResponse - 剧本响应
  • CharacterBase - 角色基础模型
  • CharacterCreate - 创建角色请求
  • CharacterUpdate - 更新角色请求
  • CharacterResponse - 角色响应
  • LocationBase - 场景基础模型
  • LocationCreate - 创建场景请求
  • LocationUpdate - 更新场景请求
  • LocationResponse - 场景响应
  • PropBase - 道具基础模型
  • PropCreate - 创建道具请求
  • PropUpdate - 更新道具请求
  • PropResponse - 道具响应
  • PaginatedResponse - 分页响应

特点

  • 使用 Pydantic v2 语法(model_config = ConfigDict(from_attributes=True)
  • 完整的字段描述和类型注解
  • 支持 ORM 模型转换

3.2 标签 Schema

文件server/app/schemas/screenplay_tag.py

定义的模型

  • TagBase - 标签基础模型
  • TagCreate - 创建标签请求
  • TagUpdate - 更新标签请求
  • TagResponse - 标签响应
  • SetDefaultTagRequest - 设置默认标签请求
  • SetDefaultTagResponse - 设置默认标签响应

4. API 路由层实现

4.1 剧本 API

文件server/app/api/v1/screenplays.py

实现的端点

方法 路径 功能 状态码
POST /{screenplay_id}/characters 创建角色 201
GET /{screenplay_id}/characters 获取角色列表 200
POST /{screenplay_id}/locations 创建场景 201
GET /{screenplay_id}/locations 获取场景列表 200
POST /{screenplay_id}/props 创建道具 201
GET /{screenplay_id}/props 获取道具列表 200

特点

  • 完整的权限检查(通过 get_current_user 依赖)
  • 分页支持(page, page_size)
  • 搜索过滤(search 参数)
  • 标签过滤(has_tags 参数)
  • 统一的错误处理
  • 详细的 API 文档(summary, description)

4.2 标签 API

文件server/app/api/v1/screenplay_tags.py

实现的端点

方法 路径 功能 状态码
POST `` 创建标签 201
GET /element/{element_type}/{element_id} 获取元素的所有标签 200
GET /screenplay/{screenplay_id} 获取剧本的所有标签 200
PATCH /{tag_id} 更新标签 200
DELETE /{tag_id} 删除标签 204

特点

  • RESTful 设计
  • 支持按元素类型过滤
  • 删除前检查资源关联
  • 自动维护 has_tags 字段

未实现功能

以下功能在需求文档中定义,但本次未实现(留待后续迭代):

1. ScreenplayService 缺失功能

  • 剧本列表查询(get_screenplays()
  • 创建文本剧本(create_screenplay()
  • 创建文件剧本(create_screenplay_from_file()
  • 更新剧本(update_screenplay()
  • 审批剧本(approve_screenplay()
  • 版本管理(get_screenplay_versions(), _create_version()
  • 设置默认标签(set_character_default_tag(), set_location_default_tag(), set_prop_default_tag()
  • 获取默认缩略图(_get_default_thumbnail()

2. API 路由缺失功能

  • 剧本 CRUD API(创建、查询、更新、删除剧本)
  • 版本管理 API
  • 审批 API
  • 设置默认标签 API

3. 模型更新

  • server/app/models/screenplay_element_tag.py - 添加 element_name 字段(冗余存储)

后续任务

  1. 完善 ScreenplayService

    • 实现剧本 CRUD 完整功能
    • 实现版本管理
    • 实现审批流程
    • 实现默认标签设置
  2. 创建 Schema 层

    • 定义请求/响应模型
    • 数据验证规则
  3. 创建 API 路由层

    • 实现所有 API 端点
    • 集成 FastAPI 依赖注入
    • 添加 API 文档
  4. 集成测试

    • 编写单元测试
    • 编写集成测试
    • 测试 AI 解析流程

相关文档


变更影响

新增文件

第一阶段

  • server/app/services/screenplay_service.py - 剧本服务
  • server/app/services/screenplay_tag_service.py - 标签服务
  • docs/server/changelogs/2026-02-03-screenplay-services-implementation.md - 变更日志

第二阶段

  • server/app/schemas/screenplay.py - 剧本相关 Schema
  • server/app/schemas/screenplay_tag.py - 标签相关 Schema
  • server/app/api/v1/screenplays.py - 剧本 API 路由
  • server/app/api/v1/screenplay_tags.py - 标签 API 路由

修改文件

  • server/app/repositories/screenplay_repository.py - 新增 CRUD 方法
  • server/app/repositories/screenplay_tag_repository.py - 新增 CRUD 方法,修正日志导入
  • docs/server/changelogs/2026-02-03-screenplay-services-implementation.md - 更新变更记录

依赖关系

  • ScreenplayService 依赖 ScreenplayRepository
  • ScreenplayTagService 依赖 ScreenplayTagRepository、ScreenplayRepository
  • ScreenplayService.store_parsed_elements() 调用 ScreenplayTagService.store_tags()

变更日期:2026-02-03
变更作者:System
审核状态:待审核