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.
 

4.9 KiB

剧本 AI 解析格式兼容性修复

日期: 2026-02-09
类型: Bug Fix
影响范围: 剧本 AI 解析功能

问题描述

🐛 核心问题

剧本 AI 解析功能无法正确处理 AI 返回的数据格式,导致:

  • 0 个角色被创建
  • 0 个场景被创建
  • 0 个道具被创建
  • 0 个分镜被创建

📋 问题根因

AI 实际返回的数据格式与代码期望的格式不匹配:

AI 实际返回格式

{
  "scenes": [  //  使用了 "scenes" 键名
    {
      "scene_number": 1,
      "location": "海边",  //  使用了 "location" 字段而不是 "name"
      "time": "晨",
      "description": "...",
      "characters": ["女孩", "渔民", "老警察", "小警察"],
      "shots": [...]
    }
  ]
}

代码期望格式

{
  "locations": [  //  应该使用 "locations" 键名
    {
      "name": "海边",  //  应该使用 "name" 字段
      "location": "海边",
      "description": "...",
      "meta_data": {
        "time_of_day": "morning",
        "scene_number": 1
      }
    }
  ],
  "characters": [...],
  "props": [...]
}

🔍 日志证据

[2026-02-09 06:44:30] 剧本解析完成: characters=0, locations=6, props=0, storyboards=0
[2026-02-09 06:44:32] WARNING: 场景缺少 name/title 字段,跳过: {'scene_number': 1, 'location': '海边', ...}
[2026-02-09 06:44:32] 剧本元素存储成功: 角色=0, 场景=0, 道具=0, 标签=0, 分镜=0

解决方案

修复内容

修改 server/app/services/screenplay_service.py 中的 _transform_ai_tags_format() 方法,增强格式兼容性:

1. 新增 scenes → locations 转换逻辑

# 步骤1:将 scenes 转换为 locations(如果存在)
if 'scenes' in parsed_data and not parsed_data.get('locations'):
    logger.info("检测到 AI 返回 'scenes' 格式,转换为 'locations'")
    scenes = parsed_data['scenes']
    locations = []
    
    for scene in scenes:
        # 从 scene 对象中提取 location 字段作为 name
        location_name = scene.get('location') or scene.get('name') or scene.get('title')
        
        if not location_name:
            logger.warning("场景缺少 location/name/title 字段,跳过: %s", scene)
            continue
        
        # 构建标准的 location 对象
        location_obj = {
            'name': location_name,  # ✅ 使用 name 字段
            'location': location_name,
            'description': scene.get('description', ''),
            'meta_data': {
                'scene_number': scene.get('scene_number'),
                'time': scene.get('time'),
                'time_of_day': scene.get('time_of_day'),
                'characters': scene.get('characters', []),
                'shots': scene.get('shots', [])
            }
        }
        
        locations.append(location_obj)
    
    result['locations'] = locations

2. 增强字段名兼容性

支持从以下字段提取场景名称:

  • name(标准字段)
  • title(备选字段)
  • location(AI 实际使用的字段)
# 兼容 name/title/location 字段
loc_name = location.get('name') or location.get('title') or location.get('location')

📊 支持的格式

修复后,_transform_ai_tags_format() 方法支持三种格式:

  1. 格式1(顶层格式 - AI Skill Prompt 标准格式)

    • 直接使用,无需转换
    • 包含 character_tagslocation_tagsprop_tags
  2. 格式2(嵌套格式 - 旧版格式)

    • 标签嵌套在元素对象内
    • 需要提取并转换为顶层格式
  3. 格式3(AI 实际返回格式 - 新增支持)

    • 使用 scenes 而不是 locations
    • 场景对象使用 location 字段而不是 name
    • 自动转换为标准格式

测试验证

验证步骤

  1. 重新解析剧本 019c4104-7231-75c0-9420-a7d143465f0e
  2. 检查日志确认格式转换成功
  3. 验证数据库中创建的元素数量

📈 预期结果

  • 成功识别并转换 sceneslocations
  • 正确提取场景名称(从 location 字段)
  • 创建角色、场景、道具、标签、分镜

影响范围

📦 修改文件

  • server/app/services/screenplay_service.py
    • 修改 _transform_ai_tags_format() 方法

🔄 向后兼容性

  • 完全向后兼容
  • 不影响现有格式的处理
  • 仅新增对 AI 实际返回格式的支持

后续优化建议

  1. 统一 AI Prompt:更新 AI Skill Prompt,确保返回标准格式(使用 locations 而不是 scenes
  2. 增强日志:添加更详细的格式检测和转换日志
  3. 单元测试:为 _transform_ai_tags_format() 方法添加单元测试,覆盖三种格式

相关文档

  • AI Skill Prompt: server/app/tasks/ai_tasks.py (parse_screenplay_task)
  • 剧本解析流程: docs/requirements/backend/04-services/project/screenplay-service.md