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.
7.1 KiB
7.1 KiB
默认形象系统设计
日期:2026-01-21
类型:功能设计
状态:待实施
相关文档:剧本元素标签管理服务
概述
为剧本标签系统添加"默认形象"功能,解决角色、场景、道具有多个标签时的默认显示问题。
业务场景
当元素有多个标签时(如角色的不同年龄段、场景的不同时代),需要设置一个默认形象用于:
- 时间轴拖拽:用户拖入角色时显示默认形象
- 快速预览:在列表中快速显示元素的主要形象
- AI 生成:作为 AI 生成的参考形象
示例
角色"张三"
├── 少年(13-17岁)- 5张素材
├── 青年(18-30岁)✓ 默认标签
│ ├── 素材1.jpg ✓ 默认素材
│ ├── 素材2.jpg
│ └── 素材3.jpg
└── 老年(51岁以上)- 2张素材
用户拖入"张三"时,显示"青年"标签的"素材1.jpg"。
设计方案
两级默认机制
- 元素级别:
default_tag_id- 指定元素的默认标签 - 标签级别:
is_default- 指定标签的默认素材
数据库变更
1. 剧本元素表(3个表)
-- screenplay_characters 表
ALTER TABLE screenplay_characters
ADD COLUMN default_tag_id UUID REFERENCES screenplay_element_tags(tag_id) ON DELETE SET NULL;
CREATE INDEX idx_characters_default_tag ON screenplay_characters(default_tag_id)
WHERE default_tag_id IS NOT NULL;
-- screenplay_scenes 表
ALTER TABLE screenplay_scenes
ADD COLUMN default_tag_id UUID REFERENCES screenplay_element_tags(tag_id) ON DELETE SET NULL;
CREATE INDEX idx_scenes_default_tag ON screenplay_scenes(default_tag_id)
WHERE default_tag_id IS NOT NULL;
-- screenplay_props 表
ALTER TABLE screenplay_props
ADD COLUMN default_tag_id UUID REFERENCES screenplay_element_tags(tag_id) ON DELETE SET NULL;
CREATE INDEX idx_props_default_tag ON screenplay_props(default_tag_id)
WHERE default_tag_id IS NOT NULL;
2. 素材表
-- 添加默认标识字段
ALTER TABLE project_resources
ADD COLUMN is_default BOOLEAN NOT NULL DEFAULT false;
-- 唯一约束:同一标签下只能有一个默认素材
CREATE UNIQUE INDEX idx_resources_default_per_tag
ON project_resources(element_tag_id)
WHERE is_default = true AND element_tag_id IS NOT NULL;
-- 查询优化索引
CREATE INDEX idx_resources_default ON project_resources(element_tag_id, is_default)
WHERE is_default = true;
业务逻辑
自动设置
- 创建第一个标签时,自动设为
default_tag_id - 上传第一个素材时,自动设为
is_default = true
删除处理
- 删除默认标签时,自动切换到下一个标签(按
order_index) - 删除默认素材时,自动切换到下一个素材(按
created_at)
切换默认
- 提供 API 让用户手动设置默认标签
- 提供 API 让用户手动设置默认素材
API 接口
1. 获取默认形象
GET /api/v1/characters/{character_id}/default-image
GET /api/v1/scenes/{scene_id}/default-image
GET /api/v1/props/{prop_id}/default-image
2. 设置默认标签
PUT /api/v1/characters/{character_id}/default-tag
PUT /api/v1/scenes/{scene_id}/default-tag
PUT /api/v1/props/{prop_id}/default-tag
3. 设置默认素材
PUT /api/v1/resources/{resource_id}/set-default
4. 批量获取默认形象
POST /api/v1/elements/default-images
用于时间轴加载时批量获取所有元素的默认形象。
边界情况
| 情况 | 处理方案 |
|---|---|
| 元素没有标签 | default_tag_id = NULL,UI 显示占位图 |
| 元素有标签但未设置默认 | 自动选择第一个标签 |
| 标签没有素材 | 查询返回 NULL,UI 显示占位图 |
| 标签有素材但未设置默认 | 自动选择第一个素材 |
| 删除默认标签 | 自动切换到下一个标签 |
| 删除默认素材 | 自动切换到下一个素材 |
性能优化
1. 单次查询
使用 JOIN 一次性查询元素的默认形象:
SELECT
c.character_id,
c.name,
t.tag_id,
t.tag_label,
r.id AS resource_id,
r.file_url,
r.thumbnail_url
FROM screenplay_characters c
LEFT JOIN screenplay_element_tags t ON c.default_tag_id = t.tag_id
LEFT JOIN project_resources r ON r.element_tag_id = t.tag_id AND r.is_default = true
WHERE c.character_id = ?;
2. 缓存策略
@cache(ttl=300, key="default_image:{element_type}:{element_id}")
async def get_default_image(...):
# 缓存 5 分钟
pass
3. 批量查询
提供批量查询接口,避免 N+1 查询问题。
前端 UI
标签列表
┌─────────────────────────────────────────────┐
│ 角色:张三 │
├─────────────────────────────────────────────┤
│ ⭐ 青年 (默认) [设为默认] │
│ 素材: 3个 │
│ ┌────┬────┬────┐ │
│ │ ✓ │ │ │ ← ✓ 表示默认素材 │
│ └────┴────┴────┘ │
│ │
│ 少年 [设为默认] │
│ 素材: 5个 │
└─────────────────────────────────────────────┘
时间轴
素材库中显示元素的默认形象,拖拽到时间轴后可在属性面板切换标签和素材。
实施清单
- 数据库迁移脚本(
006_default_image_system.py) - Repository 层方法实现
count_element_tags()get_first_tag()count_tag_resources()get_first_resource()clear_default_resources()get_default_image()
- Service 层业务逻辑
- 自动设置默认值
- 删除处理
- 切换默认值
- API 接口实现
GET /default-imagePUT /default-tagPUT /set-defaultPOST /default-images
- 单元测试
- 集成测试
- 前端 UI 实现
- 文档更新
优势
✅ 清晰的两级结构:元素级 + 标签级
✅ 自动化处理:首个标签/素材自动设为默认
✅ 智能降级:删除默认项时自动切换
✅ 统一设计:角色、场景、道具使用相同机制
✅ 性能优化:单次 JOIN 查询 + 缓存策略
✅ 用户友好:提供一键切换默认的 UI