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.
16 KiB
16 KiB
AI 剧本解析字段映射对照表
文档版本:v1.0
最后更新:2026-02-06
用途:说明AI输出的JSON字段如何映射到数据库表字段
目录
阶段1:元素提取字段映射
1.1 角色字段映射
| AI输出字段 | 数据库表 | 数据库字段 | 类型 | 必填 | 说明 |
|---|---|---|---|---|---|
| name | screenplay_characters | name | TEXT | ✅ | 角色名称 |
| description | screenplay_characters | description | TEXT | ✅ | 角色描述 |
| role_type | screenplay_characters | role_type | SMALLINT | ✅ | 角色类型:1=main, 2=supporting, 3=extra |
| is_offscreen | screenplay_characters | is_offscreen | BOOLEAN | ✅ | 是否为画外音角色 |
| meta_data | screenplay_characters | meta_data | JSONB | ✅ | 额外元数据(性别、物种、性格等) |
枚举值映射:
role_type: "main" → 1, "supporting" → 2, "extra" → 3
1.2 角色标签字段映射
| AI输出字段 | 数据库表 | 数据库字段 | 类型 | 必填 | 说明 |
|---|---|---|---|---|---|
| tag_key | screenplay_element_tags | tag_key | TEXT | ✅ | 标签键(如youth/adult/old) |
| tag_label | screenplay_element_tags | tag_label | TEXT | ✅ | 标签显示名称(如"少年"/"青年"/"老年") |
| description | screenplay_element_tags | description | TEXT | ✅ | 标签详细描述 |
| meta_data | screenplay_element_tags | meta_data | JSONB | ✅ | 额外元数据(age/clothing/mood等) |
后端自动填充字段:
element_type: 1 (角色)element_id: 从character_id_map获取element_name: 从AI输出的角色名称获取screenplay_id: 从上下文获取
1.3 场景字段映射
| AI输出字段 | 数据库表 | 数据库字段 | 类型 | 必填 | 说明 |
|---|---|---|---|---|---|
| name | screenplay_locations | name | TEXT | ✅ | 场景名称 |
| location | screenplay_locations | location | TEXT | ⚪ | 场景地点 |
| description | screenplay_locations | description | TEXT | ✅ | 场景描述 |
| meta_data | screenplay_locations | meta_data | JSONB | ✅ | 额外元数据 |
1.4 场景标签字段映射
| AI输出字段 | 数据库表 | 数据库字段 | 类型 | 必填 | 说明 |
|---|---|---|---|---|---|
| tag_key | screenplay_element_tags | tag_key | TEXT | ✅ | 标签键(如daytime/night) |
| tag_label | screenplay_element_tags | tag_label | TEXT | ✅ | 标签显示名称(如"白天"/"夜晚") |
| description | screenplay_element_tags | description | TEXT | ✅ | 标签详细描述 |
| meta_data | screenplay_element_tags | meta_data | JSONB | ✅ | 额外元数据(lighting/weather/season等) |
后端自动填充字段:
element_type: 2 (场景)element_id: 从location_id_map获取element_name: 从AI输出的场景名称获取
1.5 道具字段映射
| AI输出字段 | 数据库表 | 数据库字段 | 类型 | 必填 | 说明 |
|---|---|---|---|---|---|
| name | screenplay_props | name | TEXT | ✅ | 道具名称 |
| description | screenplay_props | description | TEXT | ✅ | 道具描述 |
| meta_data | screenplay_props | meta_data | JSONB | ✅ | 额外元数据(material/size/color等) |
⚠️ 字段缺失问题:
- AI输出包含
prop_type,owner_character,owner_location字段 - 数据库表
screenplay_props不包含这些字段 - 建议:将这些信息存储在
meta_data中
meta_data 建议结构:
{
"material": "金属",
"size": "可变",
"prop_type": "interactive",
"owner_character": "孙悟空",
"owner_location": null
}
1.6 道具标签字段映射
| AI输出字段 | 数据库表 | 数据库字段 | 类型 | 必填 | 说明 |
|---|---|---|---|---|---|
| tag_key | screenplay_element_tags | tag_key | TEXT | ✅ | 标签键(如new/old/damaged) |
| tag_label | screenplay_element_tags | tag_label | TEXT | ✅ | 标签显示名称(如"崭新"/"陈旧"/"破损") |
| description | screenplay_element_tags | description | TEXT | ✅ | 标签详细描述 |
| meta_data | screenplay_element_tags | meta_data | JSONB | ✅ | 额外元数据(condition/appearance等) |
后端自动填充字段:
element_type: 3 (道具)element_id: 从prop_id_map获取element_name: 从AI输出的道具名称获取
阶段2:分镜拆解字段映射
2.1 分镜基本字段映射
| AI输出字段 | 数据库表 | 数据库字段 | 类型 | 必填 | 说明 |
|---|---|---|---|---|---|
| title | storyboards | title | TEXT | ✅ | 分镜标题 |
| description | storyboards | description | TEXT | ✅ | 画面描述 |
| shooting_description | storyboards | shooting_description | TEXT | ⚪ | 拍摄描述 |
| shot_size | storyboards | shot_size | SMALLINT | ⚪ | 景别(1-8) |
| camera_movement | storyboards | camera_movement | SMALLINT | ⚪ | 运镜(1-9) |
| estimated_duration | storyboards | estimated_duration | NUMERIC(10,3) | ⚪ | 预估时长(秒) |
| order_index | storyboards | order_index | INTEGER | ✅ | 顺序索引 |
| start_time | storyboards | start_time | NUMERIC(10,3) | ✅ | 开始时间(秒) |
| end_time | storyboards | end_time | NUMERIC(10,3) | ✅ | 结束时间(秒) |
| meta_data | storyboards | meta_data | JSONB | ✅ | 额外元数据 |
后端自动填充字段:
project_id: 从上下文获取screenplay_id: 从上下文获取(可选)storyboard_id: 应用层生成 UUID v7
2.2 分镜角色关联字段映射
| AI输出字段 | 数据库表 | 数据库字段 | 类型 | 必填 | 说明 |
|---|---|---|---|---|---|
| name | storyboard_items | element_name | TEXT | ✅ | 角色名称(冗余) |
| tag_label | storyboard_items | tag_label | TEXT | ✅ | 标签名称(冗余) |
| action | storyboard_items | action_description | TEXT | ⚪ | 动作描述 |
| position | storyboard_items | spatial_position | TEXT | ⚪ | 画面位置 |
| is_visible | storyboard_items | is_visible | BOOLEAN | ✅ | 是否可见 |
| order | storyboard_items | display_order | INTEGER | ✅ | 显示顺序 |
⚠️ 字段名称不匹配:
- AI输出:
action→ 数据库:action_description - AI输出:
position→ 数据库:spatial_position - AI输出:
order→ 数据库:display_order
后端自动填充字段:
item_type: 1 (ElementTag)element_tag_id: 从tag_id_maps['character_tags']获取cover_url: 从标签关联的资源获取(可选)z_index: 默认 0
2.3 分镜场景关联字段映射
| AI输出字段 | 数据库表 | 数据库字段 | 类型 | 必填 | 说明 |
|---|---|---|---|---|---|
| name | storyboard_items | element_name | TEXT | ✅ | 场景名称(冗余) |
| tag_label | storyboard_items | tag_label | TEXT | ✅ | 标签名称(冗余) |
| order | storyboard_items | display_order | INTEGER | ✅ | 显示顺序 |
后端自动填充字段:
item_type: 1 (ElementTag)element_tag_id: 从tag_id_maps['location_tags']获取cover_url: 从标签关联的资源获取(可选)
2.4 分镜道具关联字段映射
| AI输出字段 | 数据库表 | 数据库字段 | 类型 | 必填 | 说明 |
|---|---|---|---|---|---|
| name | storyboard_items | element_name | TEXT | ✅ | 道具名称(冗余) |
| tag_label | storyboard_items | tag_label | TEXT | ✅ | 标签名称(冗余) |
| action | storyboard_items | action_description | TEXT | ⚪ | 动作描述 |
| position | storyboard_items | spatial_position | TEXT | ⚪ | 画面位置 |
| order | storyboard_items | display_order | INTEGER | ✅ | 显示顺序 |
后端自动填充字段:
item_type: 1 (ElementTag)element_tag_id: 从tag_id_maps['prop_tags']获取cover_url: 从标签关联的资源获取(可选)
2.5 对白字段映射
| AI输出字段 | 数据库表 | 数据库字段 | 类型 | 必填 | 说明 |
|---|---|---|---|---|---|
| character_name | storyboard_dialogues | character_name | TEXT | ✅ | 说话的角色名称 |
| content | storyboard_dialogues | content | TEXT | ✅ | 对白内容 |
| dialogue_type | storyboard_dialogues | dialogue_type | SMALLINT | ✅ | 对白类型(1/2/3) |
| sequence_order | storyboard_dialogues | sequence_order | INTEGER | ✅ | 顺序(从0开始) |
| emotion | storyboard_dialogues | emotion | TEXT | ⚪ | 情绪标记 |
后端自动填充字段:
storyboard_id: 从上下文获取character_id: 从character_id_map获取(可选)dialogue_id: 应用层生成 UUID v7
枚举值映射:
dialogue_type: 1=normal, 2=inner_monologue, 3=narration
字段不匹配问题
问题1:分镜关联字段名称不一致
AI输出:
{
"action": "大笑",
"position": "center",
"order": 0
}
数据库字段:
action_description TEXT,
spatial_position TEXT,
display_order INTEGER
解决方案:后端在存储时进行字段名称映射
# 后端映射逻辑
storyboard_item = StoryboardItem(
action_description=char_data.get('action'), # action → action_description
spatial_position=char_data.get('position'), # position → spatial_position
display_order=char_data.get('order', 0) # order → display_order
)
问题2:道具分类字段缺失
AI输出:
{
"name": "金箍棒",
"prop_type": "interactive",
"owner_character": "孙悟空",
"owner_location": null
}
数据库表:screenplay_props 表不包含 prop_type, owner_character, owner_location 字段
解决方案:将这些信息存储在 meta_data 中
# 后端存储逻辑
prop = ScreenplayProp(
name=prop_data['name'],
description=prop_data['description'],
meta_data={
**prop_data.get('meta_data', {}),
'prop_type': prop_data.get('prop_type'),
'owner_character': prop_data.get('owner_character'),
'owner_location': prop_data.get('owner_location')
}
)
问题3:缺少 tag_key 字段
AI输出:
{
"tag_key": "youth",
"tag_label": "少年"
}
数据库表:screenplay_element_tags 表包含 tag_key 字段
✅ 结论:无问题,AI输出已包含该字段
后端处理逻辑
阶段1:存储元素
async def store_parsed_elements(
self,
screenplay_id: UUID,
parsed_data: Dict[str, Any]
) -> Dict[str, Any]:
"""存储 AI 解析的剧本元素"""
# 1. 存储角色
character_id_map = {}
for char_data in parsed_data.get('characters', []):
# 枚举值映射
role_type_map = {'main': 1, 'supporting': 2, 'extra': 3}
role_type = role_type_map.get(char_data['role_type'], 2)
character = await self.repository.add_character(
screenplay_id,
{
'name': char_data['name'],
'description': char_data['description'],
'role_type': role_type,
'is_offscreen': char_data.get('is_offscreen', False),
'meta_data': char_data.get('meta_data', {})
}
)
character_id_map[char_data['name']] = character.character_id
# 2. 存储道具(处理缺失字段)
prop_id_map = {}
for prop_data in parsed_data.get('props', []):
# 将 prop_type, owner_character, owner_location 存入 meta_data
meta_data = prop_data.get('meta_data', {})
if 'prop_type' in prop_data:
meta_data['prop_type'] = prop_data['prop_type']
if 'owner_character' in prop_data:
meta_data['owner_character'] = prop_data['owner_character']
if 'owner_location' in prop_data:
meta_data['owner_location'] = prop_data['owner_location']
prop = await self.repository.add_prop(
screenplay_id,
{
'name': prop_data['name'],
'description': prop_data['description'],
'meta_data': meta_data
}
)
prop_id_map[prop_data['name']] = prop.prop_id
# 3. 存储标签(包含 tag_key)
tag_id_maps = await tag_service.store_tags(
screenplay_id,
parsed_data,
character_id_map,
location_id_map,
prop_id_map
)
return {
'character_id_map': character_id_map,
'location_id_map': location_id_map,
'prop_id_map': prop_id_map,
'tag_id_maps': tag_id_maps
}
阶段2:存储分镜
async def create_storyboards_from_ai(
self,
screenplay_id: UUID,
storyboards_data: List[Dict],
tag_id_maps: Dict
) -> List[UUID]:
"""从 AI 解析结果创建分镜"""
for storyboard_data in storyboards_data:
# 1. 创建分镜记录
storyboard = Storyboard(
screenplay_id=screenplay_id,
title=storyboard_data['title'],
description=storyboard_data['description'],
# ... 其他字段
)
created_storyboard = await self.repository.create(storyboard)
# 2. 创建角色关联(字段名称映射)
for char_data in storyboard_data.get('characters', []):
map_key = f"{char_data['name']}-{char_data['tag_label']}"
element_tag_id = tag_id_maps['character_tags'].get(map_key)
if element_tag_id:
await self.repository.create_item(StoryboardItem(
storyboard_id=created_storyboard.storyboard_id,
item_type=1, # ElementTag
element_tag_id=element_tag_id,
element_name=char_data['name'],
tag_label=char_data['tag_label'],
action_description=char_data.get('action'), # action → action_description
spatial_position=char_data.get('position'), # position → spatial_position
is_visible=char_data.get('is_visible', True),
display_order=char_data.get('order', 0) # order → display_order
))
# 3. 创建对白
for dialogue_data in storyboard_data.get('dialogues', []):
await self.repository.create_dialogue(StoryboardDialogue(
storyboard_id=created_storyboard.storyboard_id,
character_name=dialogue_data['character_name'],
content=dialogue_data['content'],
dialogue_type=dialogue_data['dialogue_type'],
sequence_order=dialogue_data['sequence_order'],
emotion=dialogue_data.get('emotion')
))
总结
✅ 完全匹配的字段
- 角色基本字段(name, description, role_type, is_offscreen, meta_data)
- 场景基本字段(name, location, description, meta_data)
- 标签字段(tag_key, tag_label, description, meta_data)
- 分镜基本字段(title, description, shot_size, camera_movement等)
- 对白字段(character_name, content, dialogue_type, sequence_order, emotion)
⚠️ 需要映射的字段
| AI输出字段 | 数据库字段 | 处理方式 |
|---|---|---|
| action | action_description | 后端映射 |
| position | spatial_position | 后端映射 |
| order | display_order | 后端映射 |
❌ 缺失的字段
| AI输出字段 | 数据库表 | 解决方案 |
|---|---|---|
| prop_type | screenplay_props | 存入 meta_data |
| owner_character | screenplay_props | 存入 meta_data |
| owner_location | screenplay_props | 存入 meta_data |
建议
- 更新AI提示词:将
action,position,order改为action_description,spatial_position,display_order,与数据库字段名称保持一致 - 更新数据库表:为
screenplay_props表添加prop_type,owner_character,owner_location字段(可选) - 保持现状:后端在存储时进行字段名称映射和数据转换(推荐,无需修改AI提示词)
文档版本:v1.0
最后更新:2026-02-06