banana-video/frontend.md
2025-08-31 18:38:41 +08:00

850 lines
22 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# **AI视频分镜生成器 - 前端API接口文档 (最终版)**
## **基本信息**
* **Base URL:** `/api/v1`
* **Content-Type:** `application/json`
## **重要功能更新 - 自定义提示词模板**
**新增功能:** 现在支持自定义提示词模板!前端可以:
1. 让用户从预设模板中选择
2. 允许用户微调提示词内容
3. 将完整的提示词模板传递给后端
**约定变量格式:**
- 生成剧本:`${script_or_idea}` - 用户的剧本或创意内容
- 生成分镜:`${materials_description}` - 项目素材描述,`${script}` - 用户剧本
**验证机制:** 后端会自动验证提示词模板是否包含必需的变量,缺少时会返回明确的错误提示。
## **新的工作流程说明**
本次更新引入了全新的AI驱动工作流程推荐按以下顺序进行
### **推荐工作流程:**
1. **创建项目**`POST /projects`
2. **生成剧本**`POST /projects/{project_id}/generate-script`
- 输入创意或剧本草稿
- AI自动生成完整剧本和所需素材列表
3. **素材处理** (三选一)
- **选项A** 批量生成所有素材图 → `POST /projects/{project_id}/generate-asset-images`
- **选项B** 单独生成指定素材图 → `POST /assets/{asset_id}/generate-image`
- **选项C** 手动为素材提供图片 → `PUT /assets/{asset_id}/image`
4. **生成分镜**`POST /projects/{project_id}/generate-storyboards`
- 系统会检查所有素材是否都有图片
5. **生成首帧图**`POST /storyboards/{storyboard_id}/generate-frame`
6. **(可选)首帧图指导修改** → `POST /storyboards/{storyboard_id}/guide-frame`
7. **生成分镜视频**`POST /storyboards/{storyboard_id}/generate-video`
8. **合成项目视频**`POST /projects/{project_id}/compose-video`
### **兼容性说明:**
- 旧的"关联素材"接口 (`POST /projects/{project_id}/assets`) 仍然保留,但不推荐使用
- 项目删除现在是软删除,不会真正删除数据
## **模块:公共服务 (Public Services)**
### **1. 获取七牛云上传Token**
获取用于客户端直传文件到七牛云存储的临时Token。
* **Endpoint:** `GET /qiniu/upload-token`
* **请求参数:** 无
* **成功响应 (200 OK):**
* **Type:** `Object`
* **描述:** 返回上传所需的Token以及相关的存储桶信息。Token具有一定的有效期。
<!-- end list -->
```json
{
"token": "qiniu_generated_upload_token_string",
"domain": "https://your-qiniu-domain.com",
"bucket": "your_bucket_name"
}
```
-----
## **模块一:提示词管理 (Prompt Management)**
### **1. 查询所有提示词**
获取系统中存储的所有可用提示词列表。
* **Endpoint:** `GET /prompts`
* **请求参数:** 无
* **成功响应 (200 OK):**
* **Type:** `Array<Object>`
<!-- end list -->
```json
[
{
"step": "create_shots",
"name": "default_v1",
"prompt": "这是一个用于生成分镜的提示词..."
}
]
```
### **2. 根据step查询提示词**
获取指定step阶段的所有提示词。
* **Endpoint:** `GET /prompts/step/{step}`
* **路径参数 (Path):** `step` (String) - 提示词使用的阶段
* **请求参数:** 无
* **成功响应 (200 OK):**
* **Type:** `Array<Object>`
<!-- end list -->
```json
[
{
"id": 1,
"step": "create_shots",
"name": "default_v1",
"prompt": "这是一个用于生成分镜的提示词...",
"created_at": "2025-08-27T10:30:00Z",
"updated_at": "2025-08-27T11:00:00Z"
},
{
"id": 2,
"step": "create_shots",
"name": "custom_v2",
"prompt": "这是另一个用于生成分镜的提示词...",
"created_at": "2025-08-27T10:35:00Z",
"updated_at": "2025-08-27T11:05:00Z"
}
]
```
* **错误响应:**
* **500 Internal Server Error:** 查询失败
```json
{
"detail": "根据step获取提示词失败: 具体错误信息"
}
```
### **3. 新增或修改提示词**
创建一个新的提示词,或者根据 `step` 和 `name` 更新一个已有的提示词。
* **Endpoint:** `POST /prompts`
* **请求体 (Body):**
| 字段名 | 类型 | 必填 | 描述 |
| :--- | :--- | :--- | :--- |
| `step` | String | 是 | 提示词使用的阶段 |
| `name` | String | 是 | 提示词的名称 |
| `prompt` | String | 是 | 提示词的具体内容 |
**示例:**
```json
{
"step": "create_shots",
"name": "default_v1",
"prompt": "请根据以下剧本和素材描述,生成分镜列表..."
}
```
* **成功响应 (200 OK):**
* **Type:** `Object`
<!-- end list -->
```json
{
"id": 1,
"step": "create_shots",
"name": "default_v1",
"prompt": "请根据以下剧本和素材描述,生成分镜列表...",
"created_at": "2025-08-27T10:30:00Z",
"updated_at": "2025-08-27T11:00:00Z"
}
```
### **4. 删除提示词**
删除指定ID的提示词。
* **Endpoint:** `DELETE /prompts/{prompt_id}`
* **路径参数 (Path):** `prompt_id` (Integer) - 要删除的提示词ID
* **请求参数:** 无
* **成功响应 (200 OK):**
* **Type:** `Object`
<!-- end list -->
```json
{
"message": "提示词删除成功"
}
```
* **错误响应:**
* **404 Not Found:** 提示词不存在
```json
{
"detail": "提示词不存在"
}
```
* **500 Internal Server Error:** 删除失败
```json
{
"detail": "删除提示词失败: 具体错误信息"
}
```
-----
## **模块二:项目与视频生成 (Project & Video Generation)**
### **1. 分页获取项目列表**
获取已创建项目的分页列表。
* **Endpoint:** `GET /projects`
* **查询参数 (Query):**
| 参数名 | 类型 | 必填 | 默认值 | 描述 |
| :--- | :--- | :--- | :--- | :--- |
| `page` | Integer | 否 | 1 | 页码 |
| `size` | Integer | 否 | 20 | 每页数量 |
* **成功响应 (200 OK):**
* **Type:** `Object`
<!-- end list -->
```json
{
"items": [
{
"id": 1,
"name": "我的第一个项目",
"created_at": "2025-08-27T10:30:00Z",
"updated_at": "2025-08-27T11:00:00Z"
}
],
"total": 1,
"page": 1,
"size": 20
}
```
### **2. 新建项目**
创建一个新的空项目。
* **Endpoint:** `POST /projects`
* **请求体 (Body):**
| 字段名 | 类型 | 必填 | 描述 |
| :--- | :--- | :--- | :--- |
| `name` | String | 是 | 项目名称 |
**示例:**
```json
{
"name": "我的第一个项目"
}
```
* **成功响应 (201 Created):**
* **Type:** `Object`
<!-- end list -->
```json
{
"id": 1,
"name": "我的第一个项目"
}
```
### **3. 删除项目**
软删除指定的项目(不会真正删除数据,只是标记为已删除)。
* **Endpoint:** `DELETE /projects/{project_id}`
* **路径参数 (Path):** `project_id` (Integer)
* **请求参数:** 无
* **成功响应 (200 OK):**
* **Type:** `Object`
<!-- end list -->
```json
{
"message": "项目 1 删除成功"
}
```
* **错误响应:**
* **404 Not Found:** 项目不存在
```json
{
"detail": "项目 1 不存在"
}
```
* **500 Internal Server Error:** 删除失败
```json
{
"detail": "删除项目失败: 具体错误信息"
}
```
### **4. 生成剧本**
根据创意或剧本生成完整剧本和所需素材信息。这是新的工作流程的第一步。
> **重要更新:** 现在支持自定义提示词模板!前端可以让用户选择并微调提示词模板,然后传递给后端。
* **Endpoint:** `POST /projects/{project_id}/generate-script`
* **路径参数 (Path):** `project_id` (Integer)
* **请求体 (Body):**
| 字段名 | 类型 | 必填 | 描述 |
| :--- | :--- | :--- | :--- |
| `script_or_idea` | String | 是 | 剧本或创意内容 |
| `prompt_template` | String | 是 | 提示词模板,必须包含 `${script_or_idea}` 占位符 |
**示例:**
```json
{
"script_or_idea": "一个关于小猫冒险的故事,小猫在森林里遇到了各种动物朋友",
"prompt_template": "基于以下创意或剧本,生成一个完整的视频剧本和所需的素材列表。\n\n创意/剧本:${script_or_idea}\n\n请返回以下JSON格式的结果\n{\n \"full_script\": \"完整的视频剧本内容,包含详细的场景描述、对话、动作等\",\n \"assets\": [\n {\n \"name\": \"素材名称\",\n \"description\": \"素材的详细描述\",\n \"tags\": [\"标签1\", \"标签2\", \"标签3\"]\n }\n ]\n}\n\n要求\n1. 完整剧本应该包含影视风格和详细的整个完整故事(大概30~90秒)\n2. 素材列表应该包含制作这个视频所需的所有关键元素(人物、场景、道具、动物等视觉相关的元素)\n3. 每个素材都要有清晰的名称、描述和相关标签\n4. 确保所有素材的风格统一\n5. 确保返回的是有效的JSON格式不要包含其他文字"
}
```
* **模板变量说明:**
- `${script_or_idea}`: 会被替换为用户输入的剧本或创意内容
* **成功响应 (200 OK):**
* **Type:** `Object`
<!-- end list -->
```json
{
"full_script": "第一场:森林入口\n小猫咪咪好奇地走进了神秘的森林...",
"assets": [
{
"id": 1,
"name": "小猫咪咪",
"description": "一只橘色的小猫,有着明亮的绿眼睛",
"tags": ["动物", "主角", "小猫"],
"original_url": null,
"created_at": "2025-08-27T10:30:00Z",
"updated_at": "2025-08-27T10:30:00Z"
},
{
"id": 2,
"name": "神秘森林",
"description": "一片茂密的森林,阳光透过树叶洒下",
"tags": ["场景", "森林", "自然"],
"original_url": null,
"created_at": "2025-08-27T10:30:00Z",
"updated_at": "2025-08-27T10:30:00Z"
}
]
}
```
* **错误响应:**
* **400 Bad Request:** 提示词模板缺少必需变量
```json
{
"detail": "提示词模板缺少必需的变量: script_or_idea。请确保模板中包含: ${script_or_idea}"
}
```
### **5. 更新素材图**
为素材更新图片URL。用户可以为生成的素材提供自定义的图片。
* **Endpoint:** `PUT /assets/{asset_id}/image`
* **路径参数 (Path):** `asset_id` (Integer)
* **请求体 (Body):**
| 字段名 | 类型 | 必填 | 描述 |
| :--- | :--- | :--- | :--- |
| `image_url` | String | 是 | 素材图片URL |
**示例:**
```json
{
"image_url": "https://example.com/my-custom-image.jpg"
}
```
* **成功响应 (200 OK):**
* **Type:** `Object`
<!-- end list -->
```json
{
"message": "素材图片更新成功"
}
```
### **6. 生成单个素材图**
为指定的单个素材生成图片。前端提供素材ID后端返回生成图片后的素材信息。
* **Endpoint:** `POST /assets/{asset_id}/generate-image`
* **路径参数 (Path):** `asset_id` (Integer) - 要生成图片的素材ID
* **请求参数:** 无
* **成功响应 (200 OK):**
* **Type:** `Object`
* **描述:** 返回生成图片后的素材信息
<!-- end list -->
```json
{
"asset": {
"id": 1,
"project_id": 1,
"name": "小猫咪咪",
"description": "一只橘色的小猫,有着明亮的绿眼睛",
"tags": ["动物", "主角", "小猫"],
"original_url": "https://your-qiniu-domain.com/generated_cat_123.png",
"created_at": "2025-08-27T10:30:00Z",
"updated_at": "2025-08-27T10:35:00Z"
}
}
```
* **错误响应:**
* **404 Not Found:** 素材不存在
```json
{
"detail": "素材 1 不存在"
}
```
* **500 Internal Server Error:** 生成失败
```json
{
"detail": "生成素材图失败: 具体错误信息"
}
```
### **7. 批量创建素材图**
为项目中所有没有图片的素材自动生成图片。如果所有素材都已有图片,则可以跳过此步骤。
* **Endpoint:** `POST /projects/{project_id}/generate-asset-images`
* **路径参数 (Path):** `project_id` (Integer)
* **请求参数:** 无
* **成功响应 (200 OK):**
* **Type:** `Array<Object>`
* **描述:** 返回项目的所有素材信息(包括新生成图片的素材)
<!-- end list -->
```json
[
{
"id": 1,
"name": "小猫咪咪",
"description": "一只橘色的小猫,有着明亮的绿眼睛",
"tags": ["动物", "主角", "小猫"],
"original_url": "https://your-qiniu-domain.com/generated_cat_123.png",
"created_at": "2025-08-27T10:30:00Z",
"updated_at": "2025-08-27T10:35:00Z"
},
{
"id": 2,
"name": "神秘森林",
"description": "一片茂密的森林,阳光透过树叶洒下",
"tags": ["场景", "森林", "自然"],
"original_url": "https://your-qiniu-domain.com/generated_forest_456.png",
"created_at": "2025-08-27T10:30:00Z",
"updated_at": "2025-08-27T10:35:00Z"
}
]
```
### **8. 关联素材** [已弃用 - 保留兼容性]
> **注意:** 此接口已被新的工作流程替代,但保留用于兼容性。新的推荐流程是:生成剧本 → 更新/生成素材图 → 生成分镜。
* **Endpoint:** `POST /projects/{project_id}/assets`
* **路径参数 (Path):** `project_id` (Integer)
* **请求体 (Body):**
| 字段名 | 类型 | 必填 | 描述 |
| :--- | :--- | :--- | :--- |
| `asset_urls` | Array\<String\> | 是 | **已上传到七牛云的**素材URL数组 |
**示例:**
```json
{
"asset_urls": [
"https://your-qiniu-domain.com/image1.jpg",
"https://your-qiniu-domain.com/image2.png"
]
}
```
* **成功响应 (200 OK):**
* **Type:** `Array<Object>`
* **描述:** 返回分析和入库后的素材信息列表。
<!-- end list -->
```json
[
{
"id": 1,
"name": "海滩上的女孩",
"description": "一个穿着白色连衣裙的女孩在夕阳下的海滩上奔跑。",
"tags": ["海滩", "女孩", "夕阳", "连衣裙"]
}
]
```
### **9. 删除素材**
删除指定ID的素材。
* **Endpoint:** `DELETE /assets/{asset_id}`
* **路径参数 (Path):** `asset_id` (Integer) - 要删除的素材ID
* **请求参数:** 无
* **成功响应 (200 OK):**
* **Type:** `Object`
<!-- end list -->
```json
{
"message": "素材 1 删除成功"
}
```
* **错误响应:**
* **404 Not Found:** 素材不存在
```json
{
"detail": "素材 1 不存在"
}
```
* **500 Internal Server Error:** 删除失败
```json
{
"detail": "删除素材失败: 具体错误信息"
}
```
### **10. 生成分镜**
为指定项目提交剧本和提示词,生成一系列结构化的分镜描述。
> **重要更新:** 现在支持自定义提示词模板!前端可以让用户选择并微调提示词模板,然后传递给后端。
* **Endpoint:** `POST /projects/{project_id}/generate-storyboards`
* **路径参数 (Path):** `project_id` (Integer)
* **请求体 (Body):**
| 字段名 | 类型 | 必填 | 描述 |
| :--- | :--- | :--- | :--- |
| `script` | String | 是 | 用户输入的剧本内容 |
| `prompt_template` | String | 是 | 提示词模板,必须包含 `${materials_description}` 和 `${script}` 占位符 |
**示例:**
```json
{
"script": "清晨,女孩在海边醒来...",
"prompt_template": "请根据以下剧本和素材描述,生成分镜列表。\n\n可用素材描述\n${materials_description}\n\n用户剧本\n${script}\n\n请根据以上信息生成分镜返回JSON数组格式每个分镜包含\n- frame_prompt: 首帧图片生成提示词\n- frame_asset_ids: 用于生成首帧的素材ID数组\n- shot_prompt: 分镜动态内容提示词\n\n请确保返回的是有效的JSON数组格式不要包含其他文字。"
}
```
* **模板变量说明:**
- `${materials_description}`: 会被替换为项目中所有素材的描述信息
- `${script}`: 会被替换为用户输入的剧本内容
* **成功响应 (200 OK):**
* **Type:** `Array<Object>`
<!-- end list -->
```json
[
{
"id": 1,
"frame_prompt": "清晨金色的阳光下...",
"frame_asset_ids": [1],
"shot_prompt": "镜头特写女孩的面部..."
}
]
```
* **错误响应:**
* **400 Bad Request:** 提示词模板缺少必需变量
```json
{
"detail": "提示词模板缺少必需的变量: materials_description, script。请确保模板中包含: ${materials_description}, ${script}"
}
```
### **11. 生成分镜首帧图**
为一个已生成的分镜,生成其首帧静态图。
* **Endpoint:** `POST /storyboards/{storyboard_id}/generate-frame`
* **路径参数 (Path):** `storyboard_id` (Integer)
* **请求体 (Body):**
| 字段名 | 类型 | 必填 | 描述 |
| :--- | :--- | :--- | :--- |
| `frame_prompt` | String | 是 | 用于生成首帧图的提示词(可编辑) |
| `frame_asset_ids` | Array\<Integer\> | 是 | 用于生成首帧图的素材ID数组可编辑 |
**示例:**
```json
{
"frame_prompt": "日出时分,一个女孩在沙滩上醒来...",
"frame_asset_ids": [1]
}
```
* **成功响应 (200 OK):**
* **Type:** `Object`
<!-- end list -->
```json
{
"frame_image_url": "https://your-qiniu-domain.com/generated_image_123.png"
}
```
### **12. 首帧图指导修改**
使用指导图修改分镜的首帧图。用户可以在白板上画草图来指导首帧图的生成。
* **Endpoint:** `POST /storyboards/{storyboard_id}/guide-frame`
* **路径参数 (Path):** `storyboard_id` (Integer)
* **请求体 (Body):**
| 字段名 | 类型 | 必填 | 描述 |
| :--- | :--- | :--- | :--- |
| `guide_image_url` | String | 是 | 指导图URL用户在白板上画的动作或位置指导草图 |
**示例:**
```json
{
"guide_image_url": "https://example.com/my-guide-sketch.jpg"
}
```
* **成功响应 (200 OK):**
* **Type:** `Object`
<!-- end list -->
```json
{
"frame_image_url": "https://your-qiniu-domain.com/guided_frame_789.png"
}
```
### **13. 生成分镜视频**
为一个已生成首帧图的分镜,生成其动态视频。
* **Endpoint:** `POST /storyboards/{storyboard_id}/generate-video`
* **路径参数 (Path):** `storyboard_id` (Integer)
* **请求体 (Body):**
| 字段名 | 类型 | 必填 | 描述 |
| :--- | :--- | :--- | :--- |
| `shot_prompt` | String | 是 | 用于生成分镜视频的动态描述提示词(可编辑) |
**示例:**
```json
{
"shot_prompt": "镜头从女孩的特写平滑地拉远..."
}
```
* **成功响应 (200 OK):**
* **Type:** `Object`
<!-- end list -->
```json
{
"shot_video_url": "https://your-qiniu-domain.com/generated_video_456.mp4"
}
```
### **14. 合成项目视频**
将项目中所有分镜的视频合并成一个完整的项目视频。
* **Endpoint:** `POST /projects/{project_id}/compose-video`
* **路径参数 (Path):** `project_id` (Integer)
* **请求参数:** 无
* **成功响应 (200 OK):**
* **Type:** `Object`
<!-- end list -->
```json
{
"video_url": "https://your-qiniu-domain.com/project_final_video_789.mp4"
}
```
* **错误响应:**
* **400 Bad Request:** 项目不存在或分镜没有视频
```json
{
"detail": "项目 1 的分镜都没有生成视频"
}
```
* **500 Internal Server Error:** 合成失败
```json
{
"detail": "合成项目视频失败: 具体错误信息"
}
```
### **15. 获取项目所有信息**
获取一个项目的完整信息,用于重新打开项目时恢复前端状态。
* **Endpoint:** `GET /projects/{project_id}`
* **路径参数 (Path):** `project_id` (Integer)
* **成功响应 (200 OK):**
* **Type:** `Object`
<!-- end list -->
```json
{
"project": {
"id": 1,
"name": "我的第一个项目",
"script": "清晨,女孩在海边醒来...",
"video_url": "https://your-qiniu-domain.com/project_final_video_789.mp4",
"created_at": "2025-08-27T10:30:00Z",
"updated_at": "2025-08-27T12:00:00Z"
},
"assets": [
{
"id": 1,
"name": "海滩上的女孩",
"description": "一个穿着白色连衣裙的女孩...",
"tags": ["海滩", "女孩"],
"original_url": "https://your-qiniu-domain.com/image1.jpg"
}
],
"storyboards": [
{
"id": 1,
"frame_prompt": "日出时分...",
"frame_asset_ids": [1],
"frame_image_url": "https://your-qiniu-domain.com/generated_image_123.png",
"shot_prompt": "镜头从女孩的特写平滑地拉远...",
"shot_video_url": "https://your-qiniu-domain.com/generated_video_456.mp4"
}
]
}
```