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.
 

5.9 KiB

Phase 1: 修复 AI Conversation 功能以支持 storyboard_items

日期: 2026-02-10
类型: 重构
影响范围: AI Conversation Service, StoryboardResourceRepository

背景

根据 ADR 04: 移除废弃的 storyboard_resources 表,需要将 AI Conversation 功能从废弃的 storyboard_resources 表迁移到新的 storyboard_items 表。

变更内容

1. StoryboardResourceRepository

文件: server/app/repositories/storyboard_resource_repository.py

1.1 重写 get_by_storyboard() 方法

变更前:

async def get_by_storyboard(self, storyboard_id: UUID) -> List:
    """获取分镜的所有资源(用于 AI Conversation 提及功能)
    
    注意:这是一个简化的实现,返回空列表
    实际应该查询 storyboard_items 表获取关联的资源
    """
    # TODO: 实现完整的分镜资源查询逻辑
    return []

变更后:

async def get_by_storyboard(self, storyboard_id: UUID) -> List[dict]:
    """获取分镜的所有关联资源(基于 storyboard_items)
    
    ⚠️ 注意:这是一个简化实现,仅用于 AI Conversation 资源提及功能。
    
    当前实现:
    - 仅返回直接关联的 ProjectResource(item_type=2)
    - 暂不处理 ElementTag 关联(item_type=1)
    
    原因:
    - AI Conversation Service 的原有逻辑依赖废弃的 storyboard_resources 表结构
    - 新的 storyboard_items 设计与原有逻辑不兼容
    - 需要重构 AI Conversation Service 才能完整支持 ElementTag
    """
    # 查询 storyboard_items 表,仅返回 ItemType.RESOURCE 类型
    # 返回简化的数据结构:project_resource_id, resource_type, file_url, thumbnail_url

实现细节:

  • 查询 storyboard_items 表,过滤 item_type = ItemType.RESOURCE
  • 关联查询 project_resources 表获取资源详情
  • 返回简化的字典列表,包含必要字段

1.2 实现 is_linked() 方法

新增方法:

async def is_linked(
    self,
    storyboard_id: UUID,
    resource_id: UUID
) -> bool:
    """验证资源是否关联到分镜(基于 storyboard_items)
    
    检查两种关联方式:
    1. 直接关联:StoryboardItem.resource_id == resource_id
    2. 间接关联:StoryboardItem.element_tag_id → ProjectElementTag(暂不支持)
    """
    # 检查 storyboard_items 表中是否存在直接关联
    # 返回 True/False

实现细节:

  • 查询 storyboard_items
  • 检查 item_type = ItemType.RESOURCEresource_id 匹配
  • 暂不支持通过 ElementTag 的间接关联

2. AI Conversation Service

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

2.1 简化 _get_storyboard_mentionable_resources() 方法

变更前:

async def _get_storyboard_mentionable_resources(...) -> List[Dict[str, Any]]:
    """获取分镜的可提及资源
    
    查询该分镜关联的所有资源(角色、场景、道具、视频等)
    """
    # 复杂的元素分组逻辑
    # 依赖 element_type, element_id, element_name 等字段
    # 按标签分组资源

变更后:

async def _get_storyboard_mentionable_resources(...) -> List[Dict[str, Any]]:
    """获取分镜的可提及资源
    
    ⚠️ 临时实现:返回空列表
    
    原因:
    - 原有逻辑依赖废弃的 storyboard_resources 表结构
    - 新的 storyboard_items 设计与原有逻辑不兼容
    - 需要完整重构才能支持新的数据结构
    
    TODO: 重构此方法以支持 storyboard_items 表
    """
    logger.warning(
        "分镜资源提及功能暂不可用(需要重构以支持 storyboard_items): storyboard_id=%s",
        storyboard_id
    )
    return []

影响:

  • 分镜对话中的资源提及功能暂时不可用
  • 不影响其他对话类型(角色、场景、道具)
  • 资源关联验证功能正常工作(is_linked() 方法)

测试验证

单元测试

docker exec jointo-server-app pytest tests/unit/services/test_ai_conversation_service.py -v

结果: 全部通过(19 个测试)

功能验证

  • AI Conversation 创建对话正常
  • AI Conversation 发送消息正常
  • AI Conversation 权限验证正常
  • 资源关联验证功能正常(is_linked() 方法)
  • ⚠️ 分镜资源提及功能暂不可用(返回空列表)

技术债务

需要后续重构的功能

  1. 分镜资源提及功能

    • 当前返回空列表
    • 需要重构 _get_storyboard_mentionable_resources() 方法
    • 需要适配 storyboard_items 表的数据结构
  2. ElementTag 关联支持

    • get_by_storyboard() 暂不支持 ElementTag 类型
    • is_linked() 暂不支持通过 ElementTag 的间接关联
    • 需要查询 project_element_tags 表获取完整信息

重构建议

方案 1: 扩展 storyboard_items 表

  • 添加冗余字段:element_type, element_id, element_name
  • 优点:查询性能好,兼容现有逻辑
  • 缺点:数据冗余,维护成本高

方案 2: 重构 AI Conversation Service

  • 修改 _get_storyboard_mentionable_resources() 的返回格式
  • 适配 storyboard_items 的数据结构
  • 优点:数据结构清晰,无冗余
  • 缺点:需要修改前端调用代码

推荐: 方案 2(重构 AI Conversation Service)

下一步

继续执行 ADR 04 的 Phase 2:

  • 删除废弃的 Service 层代码
  • 删除废弃的 API 端点
  • 删除废弃的 Schema
  • 删除废弃的测试文件
  • 删除废弃的模型

参考