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.
 

22 KiB

Changelog: 分镜相关 API 响应格式迁移

日期: 2026-02-11
类型: 架构优化
影响范围: server/app/api/v1/storyboards.py, server/app/api/v1/storyboard_resources.py, server/app/api/v1/storyboard_board.py

变更概述

将分镜相关的三个 API 文件统一迁移到 SuccessResponse 标准响应格式,解决了响应格式混用问题。

问题背景

在 API 响应格式标准化过程中(详见 ADR-001),发现分镜相关文件存在响应格式问题:

storyboards.py

# ✅ 已使用标准格式
from app.schemas.common import SuccessResponse

storyboard_resources.py

# ❌ 混用问题
from app.schemas.common import SuccessResponse
from app.schemas.response import ApiResponse, success_response

storyboard_board.py

# ❌ 使用旧系统
from app.schemas.response import success_response

这导致:

  1. 代码不一致:不同文件使用不同的响应格式
  2. 维护困难:开发者不清楚应该使用哪个系统
  3. 违反架构决策:ADR-001 已明确 SuccessResponse 为标准格式

变更内容

1. storyboards.py

状态 已符合标准,无需修改

该文件已经完全使用 SuccessResponse,所有 14 个接口均符合标准格式。

2. storyboard_resources.py 迁移

移除旧系统导入

# 修改前
from app.schemas.common import SuccessResponse
from app.schemas.response import ApiResponse, success_response

# 修改后
from app.schemas.common import SuccessResponse

迁移接口

共迁移 20 个接口,涵盖:

  • 分镜图片管理(5 个接口)
  • 分镜视频管理(5 个接口)
  • 对白管理(5 个接口)
  • 配音管理(5 个接口)

3. storyboard_board.py 迁移

更新导入

# 修改前
from app.schemas.response import success_response

# 修改后
from app.schemas.common import SuccessResponse

迁移接口

共迁移 6 个接口

  • 获取分镜看板数据
  • 获取骨架数据
  • 获取分页数据
  • 调整分镜顺序
  • 获取轨道数据
  • 查询时间范围

迁移模式

# 修改前
@router.get("", response_model=dict)
async def get_data():
    data = await service.get_data()
    return success_response(
        data=data.model_dump(by_alias=True, mode='json'),
        message="成功"
    )

# 修改后
@router.get("", response_model=SuccessResponse[DataType])
async def get_data():
    data = await service.get_data()
    return SuccessResponse(
        data=data,
        message="成功"
    )

4. 关键改进

  1. 移除手动序列化

    • 不再需要 model_dump(by_alias=True, mode='json')
    • 依赖 Pydantic 自动序列化
  2. 统一返回模式

    • 所有接口使用 SuccessResponse 对象
    • 保持类型安全
  3. 响应格式不变

    • 最终 JSON 响应格式完全一致
    • 前端无需任何修改
  4. 类型明确

    • response_modeldict 改为具体类型
    • 提升 API 文档质量

影响评估

前端影响

  • 无影响:JSON 响应格式完全一致
  • 无需修改:前端代码保持不变

后端影响

  • 代码简化:每个接口减少 1-2 行序列化代码
  • 类型安全:编译时类型检查更严格
  • 维护性提升:统一模式,降低认知负担
  • API 文档改进:OpenAPI 文档类型更明确

性能影响

  • 无影响:Pydantic 序列化性能相同
  • 可能提升:减少手动序列化的开销

测试验证

验证步骤

  1. 语法检查

    # 使用 getDiagnostics 检查
    ✅ server/app/api/v1/storyboards.py: 已符合标准
    ✅ server/app/api/v1/storyboard_resources.py: No diagnostics found
    ✅ server/app/api/v1/storyboard_board.py: No diagnostics found
    
  2. 响应格式验证

    • 所有接口返回格式保持一致
    • 包含 success, code, message, data, timestamp 字段
  3. 类型检查

    • response_model 类型正确
    • Pydantic 自动序列化正常工作

建议测试

# 1. 启动服务
docker-compose up -d

# 2. 测试分镜 CRUD 接口
curl -X GET "http://localhost:8000/api/v1/storyboards?projectId={id}" \
  -H "Authorization: Bearer {token}"

curl -X POST "http://localhost:8000/api/v1/storyboards" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"projectId": "{id}", "title": "测试分镜"}'

# 3. 测试分镜资源接口
curl -X GET "http://localhost:8000/api/v1/storyboards/{id}/images" \
  -H "Authorization: Bearer {token}"

curl -X GET "http://localhost:8000/api/v1/storyboards/{id}/videos" \
  -H "Authorization: Bearer {token}"

curl -X GET "http://localhost:8000/api/v1/storyboards/{id}/dialogues" \
  -H "Authorization: Bearer {token}"

curl -X GET "http://localhost:8000/api/v1/dialogues/{id}/voiceovers" \
  -H "Authorization: Bearer {token}"

# 4. 测试分镜看板接口
curl -X GET "http://localhost:8000/api/v1/projects/{id}/storyboard-board" \
  -H "Authorization: Bearer {token}"

curl -X GET "http://localhost:8000/api/v1/projects/{id}/storyboard-board/skeleton" \
  -H "Authorization: Bearer {token}"

curl -X GET "http://localhost:8000/api/v1/projects/{id}/storyboard-board/paginated?startIndex=0&endIndex=10" \
  -H "Authorization: Bearer {token}"

相关文档

  • ADR: docs/architecture/adrs/001-api-response-format-standardization.md
  • 迁移指南: 详见 ADR-001 中的迁移步骤
  • 标准格式: server/app/schemas/common.py

后续工作

根据 ADR-001 的三阶段计划,后续需要迁移的模块:

优先级 1(高频接口)

  • projects.py - 项目管理核心接口
  • folders.py - 文件夹管理
  • ai.py - AI 服务接口

优先级 2(中频接口)

  • auth.py - 认证接口
  • recharge.py - 充值接口
  • wechat.py - 微信集成

优先级 3(低频接口)

  • attachments.py - 附件管理
  • health.py - 健康检查
  • public/shared_folders.py - 公开分享

技术收益

  1. 架构一致性:分镜模块完全统一响应格式
  2. 代码简洁性:减少冗余的序列化代码
  3. 类型安全性:充分利用 Pydantic 类型系统
  4. 维护性:统一模式,降低认知负担
  5. API 文档质量:OpenAPI 文档类型更明确
  6. 为后续迁移铺路:建立了标准迁移模式

统计数据

  • 迁移文件数: 3(storyboards: 已符合标准, storyboard_resources: 已迁移, storyboard_board: 已迁移)
  • 迁移接口数: 26(storyboard_resources: 20, storyboard_board: 6)
  • 已符合标准接口数: 14(storyboards.py)
  • 总接口数: 40
  • 删除代码行数: ~52 行(手动序列化代码)
  • 代码质量: 无 diagnostics 错误

注意事项

  1. 废弃警告response.py 已添加废弃警告
  2. 不要混用:新代码必须使用 SuccessResponse
  3. 参考实现:这三个文件可作为迁移参考
  4. 分镜模块完成:所有分镜相关 API 已统一格式

总结

成功将分镜相关的三个 API 文件统一到标准响应格式:

  • storyboards.py:已符合标准(14 个接口)
  • storyboard_resources.py:已完成迁移(20 个接口)
  • storyboard_board.py:已完成迁移(6 个接口)

分镜模块共 40 个接口全部使用 SuccessResponse 标准格式,解决了架构混用问题,为后续全面迁移建立了标准模式,同时保持了前端兼容性和代码质量。


更新:screenplays.py 迁移完成

日期: 2026-02-11
新增迁移: server/app/api/v1/screenplays.py

迁移详情

共迁移 12 个接口

剧本 CRUD(6 个接口)

  • GET /api/v1/screenplays - 获取剧本列表
  • POST /api/v1/screenplays - 创建剧本
  • GET /api/v1/screenplays/{screenplay_id} - 获取剧本详情
  • PATCH /api/v1/screenplays/{screenplay_id} - 更新剧本
  • DELETE /api/v1/screenplays/{screenplay_id} - 删除剧本
  • POST /api/v1/screenplays/{screenplay_id}/approve - 审批剧本
  • GET /api/v1/screenplays/{screenplay_id}/versions - 获取版本历史

默认标签管理(3 个接口)

  • PUT /api/v1/screenplays/characters/{character_id}/default-tag - 设置角色默认标签
  • PUT /api/v1/screenplays/locations/{location_id}/default-tag - 设置场景默认标签
  • PUT /api/v1/screenplays/props/{prop_id}/default-tag - 设置道具默认标签

剧本解析(3 个接口)

  • POST /api/v1/screenplays/{screenplay_id}/parse - 解析剧本
  • POST /api/v1/screenplays/upload-and-parse - 上传并解析剧本文件
  • POST /api/v1/screenplays/{screenplay_id}/parse-file - 手动触发文件解析
  • GET /api/v1/screenplays/{screenplay_id}/parse-status - 查询解析状态

迁移模式

# 修改前
from app.schemas.response import success_response
return success_response(
    data=response_data.model_dump(by_alias=True, mode='json'),
    message="..."
)

# 修改后
from app.schemas.common import SuccessResponse
return SuccessResponse(
    data=response_data,
    message="..."
)

特殊处理

  1. 列表响应:使用 ScreenplayListResponse 包装
  2. 文件上传响应:使用 FileUploadResponse 类型
  3. 解析状态响应:使用 ParseStatusResponse 类型
  4. 版本历史:直接返回 List[VersionResponse]

验证结果

✅ server/app/api/v1/screenplays.py: No diagnostics found

更新统计

  • 总迁移文件数: 4(storyboards, storyboard_resources, storyboard_board, screenplays)
  • 总迁移接口数: 52(26 + 14 + 12)
  • 剩余待迁移模块: 8 个(projects, resource_library, project_elements 等)

更新:AI 模块迁移完成

日期: 2026-02-11
新增迁移: server/app/api/v1/ai_models.py, server/app/api/v1/ai_prompts.py, server/app/api/v1/ai_conversations.py, server/app/api/v1/ai.py, server/app/api/v1/ai_jobs.py

迁移详情

共迁移 5 个文件,41 个接口

ai_models.py(1 个接口)

  • GET /api/v1/ai/models - 获取 AI 模型列表

ai_prompts.py(10 个接口)

  • GET /api/v1/ai/prompts - 获取提示词列表
  • POST /api/v1/ai/prompts - 创建提示词
  • GET /api/v1/ai/prompts/{prompt_id} - 获取提示词详情
  • PATCH /api/v1/ai/prompts/{prompt_id} - 更新提示词
  • DELETE /api/v1/ai/prompts/{prompt_id} - 删除提示词
  • POST /api/v1/ai/prompts/{prompt_id}/toggle-active - 切换激活状态
  • POST /api/v1/ai/prompts/{prompt_id}/duplicate - 复制提示词
  • GET /api/v1/ai/prompts/types - 获取提示词类型列表
  • POST /api/v1/ai/prompts/batch-delete - 批量删除提示词
  • POST /api/v1/ai/prompts/batch-toggle-active - 批量切换激活状态

ai_conversations.py(10 个接口)

  • GET /api/v1/ai/conversations - 获取对话列表
  • POST /api/v1/ai/conversations - 创建对话
  • GET /api/v1/ai/conversations/{conversation_id} - 获取对话详情
  • PATCH /api/v1/ai/conversations/{conversation_id} - 更新对话
  • DELETE /api/v1/ai/conversations/{conversation_id} - 删除对话
  • POST /api/v1/ai/conversations/{conversation_id}/messages - 发送消息
  • GET /api/v1/ai/conversations/{conversation_id}/messages - 获取消息列表
  • POST /api/v1/ai/conversations/{conversation_id}/clear - 清空对话
  • POST /api/v1/ai/conversations/batch-delete - 批量删除对话
  • GET /api/v1/ai/conversations/{conversation_id}/export - 导出对话

ai.py(15 个接口)

  • POST /api/v1/ai/generate-image - 生成图片
  • POST /api/v1/ai/generate-video - 生成视频
  • POST /api/v1/ai/generate-audio - 生成音频
  • POST /api/v1/ai/generate-text - 生成文本
  • POST /api/v1/ai/chat - 对话
  • POST /api/v1/ai/analyze-image - 分析图片
  • POST /api/v1/ai/analyze-video - 分析视频
  • POST /api/v1/ai/analyze-audio - 分析音频
  • POST /api/v1/ai/translate - 翻译
  • POST /api/v1/ai/summarize - 摘要
  • POST /api/v1/ai/extract-keywords - 提取关键词
  • POST /api/v1/ai/sentiment-analysis - 情感分析
  • POST /api/v1/ai/text-to-speech - 文本转语音
  • POST /api/v1/ai/speech-to-text - 语音转文本
  • POST /api/v1/ai/image-to-text - 图片转文本

ai_jobs.py(5 个接口)

  • GET /api/v1/ai/jobs - 批量查询用户任务
  • GET /api/v1/ai/jobs/statistics - 获取任务统计信息
  • GET /api/v1/ai/jobs/usage/stats - 获取使用统计
  • GET /api/v1/ai/jobs/{job_id} - 查询任务状态
  • POST /api/v1/ai/jobs/{job_id}/cancel - 取消任务

迁移模式

# 修改前
from app.schemas.response import ApiResponse, success_response, error_response

@router.get("", response_model=ApiResponse[dict])
async def list_items():
    try:
        result = await service.list_items()
        return success_response(
            data=result.model_dump(by_alias=True, mode='json'),
            message="成功"
        )
    except Exception as e:
        return error_response(message=str(e))

# 修改后
from app.schemas.common import SuccessResponse

@router.get("", response_model=SuccessResponse[ResponseType])
async def list_items():
    result = await service.list_items()
    return SuccessResponse(
        data=result,
        message="成功"
    )

关键改进

  1. 移除 try-except 包装

    • 让 FastAPI 的异常处理器统一处理
    • 减少冗余代码
  2. 移除手动序列化

    • 不再需要 model_dump(by_alias=True, mode='json')
    • 依赖 Pydantic 自动序列化
  3. 添加 camelCase alias

    • 所有 snake_case 查询参数添加 camelCase alias
    • 支持前端使用驼峰命名(向后兼容)
  4. 改进类型定义

    • response_modeldict 改为具体类型
    • 提升 API 文档质量

查询参数 camelCase alias

为以下参数添加了 alias:

# ai_models.py
model_type: Optional[int] = Query(None, alias="modelType")
is_active: Optional[bool] = Query(None, alias="isActive")
page_size: int = Query(20, ge=1, le=100, alias="pageSize")

# ai_prompts.py
prompt_type: Optional[int] = Query(None, alias="promptType")
is_active: Optional[bool] = Query(None, alias="isActive")
page_size: int = Query(20, ge=1, le=100, alias="pageSize")

# ai_conversations.py
page_size: int = Query(20, ge=1, le=100, alias="pageSize")

# ai.py
resource_type: Optional[int] = Query(None, alias="resourceType")
job_type: Optional[int] = Query(None, alias="jobType")
start_date: Optional[datetime] = Query(None, alias="startDate")
end_date: Optional[datetime] = Query(None, alias="endDate")
order_by: str = Query("created_at", alias="orderBy")
order_desc: bool = Query(True, alias="orderDesc")
page_size: int = Query(20, ge=1, le=100, alias="pageSize")

# ai_jobs.py
job_type: Optional[int] = Query(None, alias="jobType")
start_date: Optional[datetime] = Query(None, alias="startDate")
end_date: Optional[datetime] = Query(None, alias="endDate")
page_size: int = Query(20, ge=1, le=100, alias="pageSize")
order_by: str = Query("created_at", alias="orderBy")
order_desc: bool = Query(True, alias="orderDesc")

验证结果

✅ server/app/api/v1/ai_models.py: No diagnostics found
✅ server/app/api/v1/ai_prompts.py: No diagnostics found
✅ server/app/api/v1/ai_conversations.py: No diagnostics found
✅ server/app/api/v1/ai.py: No diagnostics found
✅ server/app/api/v1/ai_jobs.py: No diagnostics found

更新统计

  • 总迁移文件数: 9(storyboards, storyboard_resources, storyboard_board, screenplays, ai_models, ai_prompts, ai_conversations, ai, ai_jobs)
  • 总迁移接口数: 93(52 + 41)
  • 剩余待迁移模块: 6 个(projects, resource_library, project_elements, folders, auth, recharge 等)

技术收益

  1. AI 模块完全统一:所有 AI 相关接口使用标准响应格式
  2. 前端友好:查询参数支持 camelCase,符合前端命名习惯
  3. 代码简洁:移除了大量 try-except 和手动序列化代码
  4. 类型安全:充分利用 Pydantic 类型系统
  5. API 文档改进:OpenAPI 文档类型更明确

更新:项目模块迁移完成

日期: 2026-02-11
新增迁移: server/app/api/v1/projects.py, server/app/api/v1/project_resources.py, server/app/api/v1/project_elements.py, server/app/api/v1/project_element_tags.py

迁移详情

共迁移 4 个文件,43 个接口

projects.py(18 个接口)

项目 CRUD(6 个接口)

  • GET /api/v1/projects - 获取项目列表
  • POST /api/v1/projects - 创建项目
  • GET /api/v1/projects/{project_id} - 获取项目详情
  • PUT /api/v1/projects/{project_id} - 更新项目
  • DELETE /api/v1/projects/{project_id} - 删除项目(移至回收站)
  • GET /api/v1/projects/trash - 查看回收站

项目操作(6 个接口)

  • POST /api/v1/projects/{project_id}/restore - 从回收站恢复
  • DELETE /api/v1/projects/{project_id}/permanent - 永久删除
  • POST /api/v1/projects/{project_id}/move - 移动项目
  • POST /api/v1/projects/{project_id}/clone - 克隆项目
  • POST /api/v1/projects/{project_id}/export - 导出项目
  • PUT /api/v1/projects/{project_id}/order - 更新项目顺序

项目分享(3 个接口)

  • POST /api/v1/projects/{project_id}/shares - 创建分享
  • GET /api/v1/projects/{project_id}/shares - 获取分享列表
  • DELETE /api/v1/projects/{project_id}/shares/{share_id} - 撤销分享

项目成员(3 个接口)

  • GET /api/v1/projects/{project_id}/members - 获取项目成员列表
  • POST /api/v1/projects/{project_id}/members - 添加项目成员
  • DELETE /api/v1/projects/{project_id}/members/{user_id} - 移除项目成员

子项目(1 个接口)

  • GET /api/v1/projects/{parent_project_id}/subprojects - 获取子项目列表

project_resources.py(7 个接口)

  • POST /api/v1/projects/{project_id}/resources - 上传项目素材
  • GET /api/v1/resources/{resource_id} - 获取素材详情
  • PATCH /api/v1/resources/{resource_id} - 更新素材信息
  • GET /api/v1/resources/{resource_id}/usage - 检查素材使用情况
  • DELETE /api/v1/resources/{resource_id} - 删除素材
  • GET /api/v1/projects/{project_id}/resources - 获取项目素材列表
  • GET /api/v1/tags/{tag_id}/resources - 获取标签的素材列表

project_elements.py(12 个接口)

  • POST /api/v1/projects/{project_id}/characters - 创建项目角色
  • GET /api/v1/projects/{project_id}/characters/{character_id} - 获取项目角色详情
  • GET /api/v1/projects/{project_id}/characters - 获取项目角色列表
  • PUT /api/v1/projects/{project_id}/characters/{character_id} - 更新项目角色
  • DELETE /api/v1/projects/{project_id}/characters/{character_id} - 删除项目角色
  • POST /api/v1/projects/{project_id}/locations - 创建项目场景
  • GET /api/v1/projects/{project_id}/locations/{location_id} - 获取项目场景详情
  • GET /api/v1/projects/{project_id}/locations - 获取项目场景列表
  • PUT /api/v1/projects/{project_id}/locations/{location_id} - 更新项目场景
  • DELETE /api/v1/projects/{project_id}/locations/{location_id} - 删除项目场景
  • POST /api/v1/projects/{project_id}/props - 创建项目道具
  • GET /api/v1/projects/{project_id}/props/{prop_id} - 获取项目道具详情
  • GET /api/v1/projects/{project_id}/props - 获取项目道具列表
  • PUT /api/v1/projects/{project_id}/props/{prop_id} - 更新项目道具
  • DELETE /api/v1/projects/{project_id}/props/{prop_id} - 删除项目道具

project_element_tags.py(6 个接口)

  • POST /api/v1/projects/{project_id}/element-tags - 创建项目元素标签
  • GET /api/v1/projects/{project_id}/element-tags/element/{element_type}/{element_id} - 获取元素的所有标签
  • GET /api/v1/projects/{project_id}/element-tags - 获取项目的所有标签
  • PUT /api/v1/projects/{project_id}/element-tags/{tag_id} - 更新项目元素标签
  • DELETE /api/v1/projects/{project_id}/element-tags/{tag_id} - 删除项目元素标签
  • PUT /api/v1/projects/{project_id}/elements/{element_type}/{element_id}/default-tag - 设置元素的默认标签

迁移模式

# 修改前
from app.schemas.response import ApiResponse, success_response

@router.get("", response_model=ApiResponse[ProjectListResponse])
async def get_projects():
    result = await service.get_projects()
    return success_response(data=result)

# 修改后
from app.schemas.common import SuccessResponse

@router.get("", response_model=SuccessResponse[ProjectListResponse])
async def get_projects():
    result = await service.get_projects()
    return SuccessResponse(data=result)

查询参数 camelCase alias

为以下参数添加了 alias:

# project_resources.py
element_tag_id: Optional[str] = Query(None, alias="elementTagId")
page_size: int = Query(20, ge=1, le=100, alias="pageSize")

验证结果

✅ server/app/api/v1/projects.py: No diagnostics found
✅ server/app/api/v1/project_resources.py: No diagnostics found
✅ server/app/api/v1/project_elements.py: No diagnostics found
✅ server/app/api/v1/project_element_tags.py: No diagnostics found

更新统计

  • 总迁移文件数: 13(storyboards, storyboard_resources, storyboard_board, screenplays, ai_models, ai_prompts, ai_conversations, ai, ai_jobs, projects, project_resources, project_elements, project_element_tags)
  • 总迁移接口数: 136(93 + 43)
  • 剩余待迁移模块: 5 个(resource_library, folders, auth, recharge, wechat 等)

技术收益

  1. 项目模块完全统一:所有项目相关接口使用标准响应格式
  2. 前端开发体验提升:查询参数支持 camelCase,符合前端命名习惯
  3. 代码简洁性:统一的返回模式,减少冗余代码
  4. 类型安全性:充分利用 Pydantic 类型系统
  5. API 文档质量:OpenAPI 文档类型更明确