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.
 

9.0 KiB

Changelog: 为分镜资源添加命名和描述功能

日期: 2026-02-12
类型: Feature
影响范围: 后端 API、数据库结构


变更概述

为分镜图片(storyboard_images)和分镜视频(storyboard_videos)表添加 namedescription 字段,支持用户自定义命名和描述资源,同时提供 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 资源描述(用户自定义,前期预留)

字段注释

-- 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

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

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

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 层实现:

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 变更

请求参数变更

创建分镜图片/视频

新增可选参数:

{
  "name": "自定义名称",           // 可选,不提供则自动生成
  "description": "资源描述",      // 可选
  "url": "https://...",
  "checksum": "...",
  // ... 其他字段
}

响应数据变更

分镜图片/视频响应

新增字段:

{
  "imageId": "uuid",
  "storyboardId": "uuid",
  "name": "001-开场镜头-方案01",    // 新增
  "description": "用户自定义描述",  // 新增
  "url": "https://...",
  // ... 其他字段
}

使用场景

场景 1:AI 生成分镜图片

# 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:用户自定义命名

# 用户在创建时提供自定义名称
image_data = ImageCreate(
    name="我喜欢的版本",
    description="这个版本的光线效果最好",
    url=url,
    # ... 其他字段
)

场景 3:生成视频时引用

# 用户在生成视频时可以通过名称引用特定图片
prompt = "使用 @001-开场镜头-方案01 作为视频的第一帧"

迁移指南

数据库迁移

# 在 Docker 容器内执行迁移
docker exec jointo-server-app alembic upgrade head

现有数据处理

  • 现有的分镜图片和视频资源的 namedescription 字段将为 NULL
  • 可选:运行数据迁移脚本为现有资源生成默认名称

前端适配

  1. 创建资源时

    • 支持可选的 namedescription 参数
    • 如果用户不提供,后端将自动生成
  2. 显示资源时

    • 在资源列表中显示 name 字段
    • 支持显示和编辑 description 字段
  3. 引用资源时

    • 支持通过 @ 符号引用资源名称
    • 提供资源名称的自动补全功能

后续优化

短期(1-2 周)

  • 在 Service 层实现默认命名生成逻辑
  • 为现有资源生成默认名称(数据迁移脚本)
  • 添加资源名称修改 API

中期(1 个月)

  • 支持资源名称搜索
  • 支持资源名称唯一性校验(可选)
  • 添加资源描述的富文本支持

长期(3 个月)

  • 支持资源标签系统
  • 支持资源分组管理
  • 支持资源版本历史

测试验证

数据库验证

-- 验证字段已添加
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 测试

# 测试创建带名称的图片
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 调用不受影响,namedescription 为可选字段
  2. NULL 值处理:前端需要处理 namedescription 为 NULL 的情况
  3. 命名冲突:当前不强制名称唯一性,允许多个资源使用相同名称
  4. 性能影响:新增字段为 TEXT 类型,不影响查询性能(无索引)

相关文档

变更记录

  • 2026-02-12: 初始版本,完成数据库迁移和 Model/Schema 更新