# Changelog: 为分镜资源添加命名和描述功能 **日期**: 2026-02-12 **类型**: Feature **影响范围**: 后端 API、数据库结构 --- ## 变更概述 为分镜图片(storyboard_images)和分镜视频(storyboard_videos)表添加 `name` 和 `description` 字段,支持用户自定义命名和描述资源,同时提供 AI 默认命名规则。 ## 业务价值 1. **资源命名**:用户可以为生成的分镜图片和视频命名,便于在生成视频时通过 @ 引用特定资源 2. **资源描述**:用户可以添加描述信息,记录资源的用途、特点等 3. **默认命名**:AI 生成资源时自动使用规范化命名(镜号-分镜名称-方案编号) 4. **灵活性**:用户可以随时修改资源名称和描述 ## 数据库变更 ### 迁移文件 `server/alembic/versions/20260212_1900_add_name_description_to_resources.py` ### 新增字段 #### storyboard_images 表 | 字段 | 类型 | 约束 | 默认值 | 说明 | |------|------|------|--------|------| | `name` | TEXT | nullable | NULL | 资源名称(用户可自定义,AI 生成时默认为:镜号-分镜名称-方案编号) | | `description` | TEXT | nullable | NULL | 资源描述(用户自定义) | #### storyboard_videos 表 | 字段 | 类型 | 约束 | 默认值 | 说明 | |------|------|------|--------|------| | `name` | TEXT | nullable | NULL | 资源名称(默认为:镜号-分镜名称-方案编号) | | `description` | TEXT | nullable | NULL | 资源描述(用户自定义,前期预留) | ### 字段注释 ```sql -- storyboard_images COMMENT ON COLUMN storyboard_images.name IS '资源名称(用户可自定义,AI 生成时默认为:镜号-分镜名称-方案编号)'; COMMENT ON COLUMN storyboard_images.description IS '资源描述(用户自定义)'; -- storyboard_videos COMMENT ON COLUMN storyboard_videos.name IS '资源名称(默认为:镜号-分镜名称-方案编号)'; COMMENT ON COLUMN storyboard_videos.description IS '资源描述(用户自定义,前期预留)'; ``` ## 代码变更 ### Model 层 **文件**: `server/app/models/storyboard_resource.py` ```python class StoryboardImage(SQLModel, table=True): # ... 其他字段 # 资源命名 name: Optional[str] = Field(default=None, nullable=True) description: Optional[str] = Field(default=None, nullable=True) # ... 其他字段 class StoryboardVideo(SQLModel, table=True): # ... 其他字段 # 资源命名 name: Optional[str] = Field(default=None, nullable=True) description: Optional[str] = Field(default=None, nullable=True) # ... 其他字段 ``` ### Schema 层 **文件**: `server/app/schemas/storyboard_resource.py` #### 创建请求 Schema ```python class ImageCreate(BaseModel): """创建分镜图片请求""" name: Optional[str] = Field(None, description="资源名称(可选,不提供则自动生成)") description: Optional[str] = Field(None, description="资源描述") # ... 其他字段 class VideoCreate(BaseModel): """创建分镜视频请求""" name: Optional[str] = Field(None, description="资源名称(可选,不提供则自动生成)") description: Optional[str] = Field(None, description="资源描述") # ... 其他字段 ``` #### 响应 Schema ```python class ImageResponse(BaseModel): """分镜图片响应""" image_id: str = Field(..., serialization_alias="imageId") storyboard_id: str = Field(..., serialization_alias="storyboardId") name: Optional[str] = Field(None, description="资源名称") description: Optional[str] = Field(None, description="资源描述") # ... 其他字段 class VideoResponse(BaseModel): """分镜视频响应""" video_id: str = Field(..., serialization_alias="videoId") storyboard_id: str = Field(..., serialization_alias="storyboardId") name: Optional[str] = Field(None, description="资源名称") description: Optional[str] = Field(None, description="资源描述") # ... 其他字段 ``` ## 默认命名规则 ### 命名格式 ``` {镜号:03d}-{分镜名称}-方案{版本:02d} ``` ### 示例 - 分镜 1,标题"开场镜头",版本 1:`001-开场镜头-方案01` - 分镜 5,标题"角色特写",版本 2:`005-角色特写-方案02` - 分镜 12,标题"场景切换",版本 1:`012-场景切换-方案01` ### 实现位置 默认命名逻辑将在 Service 层实现: ```python def generate_default_resource_name( order_index: int, storyboard_title: str, version: int ) -> str: """生成默认资源名称 Args: order_index: 分镜序号(从 storyboards.order_index 获取) storyboard_title: 分镜标题(从 storyboards.title 获取) version: 资源版本号(从 storyboard_images/videos.version 获取) Returns: 格式化的资源名称,如:001-开场镜头-方案01 """ shot_number = f"{order_index:03d}" version_label = f"方案{version:02d}" return f"{shot_number}-{storyboard_title}-{version_label}" ``` ## API 变更 ### 请求参数变更 #### 创建分镜图片/视频 新增可选参数: ```json { "name": "自定义名称", // 可选,不提供则自动生成 "description": "资源描述", // 可选 "url": "https://...", "checksum": "...", // ... 其他字段 } ``` ### 响应数据变更 #### 分镜图片/视频响应 新增字段: ```json { "imageId": "uuid", "storyboardId": "uuid", "name": "001-开场镜头-方案01", // 新增 "description": "用户自定义描述", // 新增 "url": "https://...", // ... 其他字段 } ``` ## 使用场景 ### 场景 1:AI 生成分镜图片 ```python # Service 层自动生成名称 storyboard = await storyboard_repo.get_by_id(storyboard_id) default_name = generate_default_resource_name( order_index=storyboard.order_index, storyboard_title=storyboard.title, version=1 ) image = StoryboardImage( storyboard_id=storyboard_id, name=default_name, # 自动生成:001-开场镜头-方案01 url=generated_url, # ... 其他字段 ) ``` ### 场景 2:用户自定义命名 ```python # 用户在创建时提供自定义名称 image_data = ImageCreate( name="我喜欢的版本", description="这个版本的光线效果最好", url=url, # ... 其他字段 ) ``` ### 场景 3:生成视频时引用 ```python # 用户在生成视频时可以通过名称引用特定图片 prompt = "使用 @001-开场镜头-方案01 作为视频的第一帧" ``` ## 迁移指南 ### 数据库迁移 ```bash # 在 Docker 容器内执行迁移 docker exec jointo-server-app alembic upgrade head ``` ### 现有数据处理 - 现有的分镜图片和视频资源的 `name` 和 `description` 字段将为 NULL - 可选:运行数据迁移脚本为现有资源生成默认名称 ### 前端适配 1. **创建资源时**: - 支持可选的 `name` 和 `description` 参数 - 如果用户不提供,后端将自动生成 2. **显示资源时**: - 在资源列表中显示 `name` 字段 - 支持显示和编辑 `description` 字段 3. **引用资源时**: - 支持通过 @ 符号引用资源名称 - 提供资源名称的自动补全功能 ## 后续优化 ### 短期(1-2 周) - [ ] 在 Service 层实现默认命名生成逻辑 - [ ] 为现有资源生成默认名称(数据迁移脚本) - [ ] 添加资源名称修改 API ### 中期(1 个月) - [ ] 支持资源名称搜索 - [ ] 支持资源名称唯一性校验(可选) - [ ] 添加资源描述的富文本支持 ### 长期(3 个月) - [ ] 支持资源标签系统 - [ ] 支持资源分组管理 - [ ] 支持资源版本历史 ## 测试验证 ### 数据库验证 ```sql -- 验证字段已添加 SELECT column_name, data_type, is_nullable FROM information_schema.columns WHERE table_name = 'storyboard_images' AND column_name IN ('name', 'description'); SELECT column_name, data_type, is_nullable FROM information_schema.columns WHERE table_name = 'storyboard_videos' AND column_name IN ('name', 'description'); ``` ### API 测试 ```bash # 测试创建带名称的图片 curl -X POST http://localhost:8000/api/v1/storyboards/{id}/images \ -H "Content-Type: application/json" \ -d '{ "name": "测试图片", "description": "这是一个测试", "url": "https://example.com/image.jpg", "checksum": "...", "storagePath": "..." }' ``` ## 注意事项 1. **向后兼容**:现有 API 调用不受影响,`name` 和 `description` 为可选字段 2. **NULL 值处理**:前端需要处理 `name` 和 `description` 为 NULL 的情况 3. **命名冲突**:当前不强制名称唯一性,允许多个资源使用相同名称 4. **性能影响**:新增字段为 TEXT 类型,不影响查询性能(无索引) ## 相关文档 - [迁移脚本](../../alembic/versions/20260212_1900_add_name_description_to_resources.py) - [Model 定义](../../app/models/storyboard_resource.py) - [Schema 定义](../../app/schemas/storyboard_resource.py) ## 变更记录 - 2026-02-12: 初始版本,完成数据库迁移和 Model/Schema 更新