Initial commit: Pixel AI comic/video creation platform
- FastAPI backend with SQLModel, Alembic migrations, AgentScope agents - Next.js 15 frontend with React 19, Tailwind, Zustand, React Flow - Multi-provider AI system (DashScope, Kling, MiniMax, Volcengine, OpenAI, etc.) - All HTTP clients migrated from sync requests to async httpx - Admin-managed API keys via environment variables - SSRF vulnerability fixed in ensure_url()
This commit is contained in:
608
docs/API.md
Normal file
608
docs/API.md
Normal file
@@ -0,0 +1,608 @@
|
||||
# Pixel API 文档
|
||||
|
||||
## 概述
|
||||
|
||||
本文档描述了 Pixel 后端 API 的核心端点,重点介绍模型配置和生成 API。
|
||||
|
||||
**基础 URL**: `http://localhost:8000/api/v1`
|
||||
|
||||
**认证**: 目前不需要认证(开发环境)
|
||||
|
||||
---
|
||||
|
||||
## 模型 ID 格式
|
||||
|
||||
所有 API 使用**复合 ID 格式**来标识模型:
|
||||
|
||||
```
|
||||
provider/model_key
|
||||
```
|
||||
|
||||
**示例**:
|
||||
- `dashscope/qwen-image` - DashScope 的 Qwen 图片生成模型
|
||||
- `dashscope/wan2.6-video` - DashScope 的 Wan 2.6 视频生成模型
|
||||
- `volcengine/doubao-tts` - 火山引擎的豆包 TTS 模型
|
||||
- `modelscope/qwen-image` - ModelScope 的 Qwen 图片生成模型
|
||||
|
||||
**格式规则**:
|
||||
- 必须包含一个 `/` 分隔符
|
||||
- `provider` 和 `model_key` 都不能为空
|
||||
- 不支持多个 `/` 分隔符
|
||||
|
||||
---
|
||||
|
||||
## 模型配置 API
|
||||
|
||||
### 获取所有模型配置
|
||||
|
||||
获取系统中所有可用的模型配置,按类型分组。
|
||||
|
||||
**端点**: `GET /api/v1/models`
|
||||
|
||||
**响应格式**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "200",
|
||||
"message": "success",
|
||||
"data": {
|
||||
"image": {
|
||||
"dashscope/qwen-image": {
|
||||
"id": "dashscope/qwen-image",
|
||||
"name": "Qwen Image",
|
||||
"type": "image",
|
||||
"provider": "dashscope",
|
||||
"model_key": "qwen-image",
|
||||
"is_default": true,
|
||||
"enabled": true,
|
||||
"capabilities": {
|
||||
"supportsLora": true,
|
||||
"supportsRefImage": true
|
||||
},
|
||||
"resolutions": {
|
||||
"1K": {
|
||||
"16:9": "1280*720",
|
||||
"1:1": "1024*1024"
|
||||
},
|
||||
"2K": {
|
||||
"16:9": "2560*1440",
|
||||
"1:1": "2048*2048"
|
||||
}
|
||||
}
|
||||
},
|
||||
"modelscope/qwen-image": {
|
||||
"id": "modelscope/qwen-image",
|
||||
"name": "ModelScope Qwen Image",
|
||||
"type": "image",
|
||||
"provider": "modelscope",
|
||||
"model_key": "qwen-image",
|
||||
"is_default": false,
|
||||
"enabled": true,
|
||||
"capabilities": {
|
||||
"supportsLora": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"video": {
|
||||
"dashscope/wan2.6-video": {
|
||||
"id": "dashscope/wan2.6-video",
|
||||
"name": "Wan 2.6 Video",
|
||||
"type": "video",
|
||||
"provider": "dashscope",
|
||||
"model_key": "wan2.6-video",
|
||||
"is_default": true,
|
||||
"enabled": true,
|
||||
"durations": {
|
||||
"5s": "5秒",
|
||||
"10s": "10秒"
|
||||
}
|
||||
}
|
||||
},
|
||||
"audio": {
|
||||
"volcengine/doubao-tts": {
|
||||
"id": "volcengine/doubao-tts",
|
||||
"name": "豆包 TTS",
|
||||
"type": "audio",
|
||||
"provider": "volcengine",
|
||||
"model_key": "doubao-tts",
|
||||
"is_default": true,
|
||||
"enabled": true,
|
||||
"voices": [
|
||||
{
|
||||
"id": "zh_female_qingxin",
|
||||
"name": "清新女声",
|
||||
"language": "zh"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"llm": {
|
||||
"dashscope/qwen-plus": {
|
||||
"id": "dashscope/qwen-plus",
|
||||
"name": "Qwen Plus",
|
||||
"type": "llm",
|
||||
"provider": "dashscope",
|
||||
"model_key": "qwen-plus",
|
||||
"is_default": true,
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**字段说明**:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `id` | string | 复合 ID,格式为 `provider/model_key` |
|
||||
| `name` | string | 模型显示名称 |
|
||||
| `type` | string | 模型类型:`image`、`video`、`audio`、`llm` |
|
||||
| `provider` | string | 提供商名称 |
|
||||
| `model_key` | string | 模型键名 |
|
||||
| `is_default` | boolean | 是否为该类型的默认模型 |
|
||||
| `enabled` | boolean | 是否启用 |
|
||||
| `capabilities` | object | 模型能力(可选) |
|
||||
| `resolutions` | object | 支持的分辨率(图片模型) |
|
||||
| `durations` | object | 支持的时长(视频模型) |
|
||||
| `voices` | array | 支持的音色(音频模型) |
|
||||
|
||||
---
|
||||
|
||||
## 图片生成 API
|
||||
|
||||
### 生成图片
|
||||
|
||||
创建图片生成任务。
|
||||
|
||||
**端点**: `POST /api/v1/generations/image`
|
||||
|
||||
**请求体**:
|
||||
|
||||
```json
|
||||
{
|
||||
"prompt": "a beautiful sunset over mountains",
|
||||
"model": "dashscope/qwen-image",
|
||||
"negativePrompt": "blurry, low quality",
|
||||
"resolution": "2K",
|
||||
"aspectRatio": "16:9",
|
||||
"n": 1,
|
||||
"imageInputs": ["https://example.com/ref-image.jpg"],
|
||||
"extraParams": {
|
||||
"loras": [
|
||||
{
|
||||
"model": "dashscope/anime-style",
|
||||
"weight": 0.8
|
||||
}
|
||||
]
|
||||
},
|
||||
"projectId": "proj_123",
|
||||
"source": "canvas",
|
||||
"sourceId": "canvas_456"
|
||||
}
|
||||
```
|
||||
|
||||
**参数说明**:
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `prompt` | string | ✅ | 生成提示词 |
|
||||
| `model` | string | ✅ | 模型复合 ID,格式:`provider/model_key` |
|
||||
| `negativePrompt` | string | ❌ | 负面提示词 |
|
||||
| `resolution` | string | ❌ | 分辨率级别(如 `1K`、`2K`),默认 `1K` |
|
||||
| `aspectRatio` | string | ❌ | 宽高比(如 `16:9`、`1:1`) |
|
||||
| `n` | integer | ❌ | 生成数量,默认 1 |
|
||||
| `imageInputs` | array | ❌ | 参考图片 URL 列表 |
|
||||
| `extraParams` | object | ❌ | 额外参数(如 LoRA 配置) |
|
||||
| `projectId` | string | ❌ | 项目 ID |
|
||||
| `source` | string | ❌ | 来源标识 |
|
||||
| `sourceId` | string | ❌ | 来源对象 ID |
|
||||
|
||||
**响应**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "200",
|
||||
"message": "success",
|
||||
"data": {
|
||||
"task_id": "task_abc123"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**错误响应**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "400",
|
||||
"message": "Model must be in format 'provider/model_key', got: 'qwen-image'. Example: 'dashscope/qwen-image'"
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "404",
|
||||
"message": "Model 'invalid/model' not found. Available models can be fetched from /api/v1/models"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 视频生成 API
|
||||
|
||||
### 生成视频
|
||||
|
||||
创建视频生成任务。
|
||||
|
||||
**端点**: `POST /api/v1/generations/video`
|
||||
|
||||
**请求体**:
|
||||
|
||||
```json
|
||||
{
|
||||
"prompt": "a cat playing with a ball",
|
||||
"model": "dashscope/wan2.6-video",
|
||||
"negativePrompt": "static, blurry",
|
||||
"duration": "5s",
|
||||
"resolution": "720p",
|
||||
"n": 1,
|
||||
"imageInputs": ["https://example.com/first-frame.jpg"],
|
||||
"projectId": "proj_123"
|
||||
}
|
||||
```
|
||||
|
||||
**参数说明**:
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `prompt` | string | ✅ | 生成提示词 |
|
||||
| `model` | string | ✅ | 模型复合 ID,格式:`provider/model_key` |
|
||||
| `negativePrompt` | string | ❌ | 负面提示词 |
|
||||
| `duration` | string | ❌ | 视频时长(如 `5s`、`10s`) |
|
||||
| `resolution` | string | ❌ | 分辨率(如 `720p`、`1080p`) |
|
||||
| `n` | integer | ❌ | 生成数量,默认 1 |
|
||||
| `imageInputs` | array | ❌ | 参考图片 URL 列表(首帧) |
|
||||
| `projectId` | string | ❌ | 项目 ID |
|
||||
|
||||
**响应**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "200",
|
||||
"message": "success",
|
||||
"data": {
|
||||
"task_id": "task_xyz789"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 音频生成 API
|
||||
|
||||
### 生成音频
|
||||
|
||||
创建音频生成任务(TTS)。
|
||||
|
||||
**端点**: `POST /api/v1/generations/audio`
|
||||
|
||||
**请求体**:
|
||||
|
||||
```json
|
||||
{
|
||||
"prompt": "Hello, welcome to Pixel AI!",
|
||||
"model": "volcengine/doubao-tts",
|
||||
"voice": "zh_female_qingxin",
|
||||
"speed": 1.0,
|
||||
"projectId": "proj_123"
|
||||
}
|
||||
```
|
||||
|
||||
**参数说明**:
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `prompt` | string | ✅ | 要转换的文本 |
|
||||
| `model` | string | ✅ | 模型复合 ID,格式:`provider/model_key` |
|
||||
| `voice` | string | ❌ | 音色 ID |
|
||||
| `speed` | float | ❌ | 语速,默认 1.0 |
|
||||
| `projectId` | string | ❌ | 项目 ID |
|
||||
|
||||
**响应**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "200",
|
||||
"message": "success",
|
||||
"data": {
|
||||
"task_id": "task_audio123"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 任务查询 API
|
||||
|
||||
### 获取任务状态
|
||||
|
||||
查询生成任务的状态和结果。
|
||||
|
||||
**端点**: `GET /api/v1/tasks/{task_id}`
|
||||
|
||||
**响应**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "200",
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": "task_abc123",
|
||||
"type": "image",
|
||||
"status": "completed",
|
||||
"model": "dashscope/qwen-image",
|
||||
"params": {
|
||||
"prompt": "a beautiful sunset over mountains",
|
||||
"resolution": "2K",
|
||||
"aspectRatio": "16:9"
|
||||
},
|
||||
"result": {
|
||||
"images": [
|
||||
{
|
||||
"url": "https://example.com/generated-image.jpg",
|
||||
"width": 2560,
|
||||
"height": 1440
|
||||
}
|
||||
]
|
||||
},
|
||||
"created_at": "2026-02-11T10:00:00Z",
|
||||
"updated_at": "2026-02-11T10:00:30Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**任务状态**:
|
||||
- `pending` - 等待处理
|
||||
- `processing` - 处理中
|
||||
- `completed` - 已完成
|
||||
- `failed` - 失败
|
||||
|
||||
---
|
||||
|
||||
## 错误处理
|
||||
|
||||
### 错误响应格式
|
||||
|
||||
所有错误响应遵循统一格式:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "400",
|
||||
"message": "详细的错误描述",
|
||||
"request_id": "req_123456"
|
||||
}
|
||||
```
|
||||
|
||||
### 常见错误码
|
||||
|
||||
| 错误码 | 说明 |
|
||||
|--------|------|
|
||||
| `400` | 请求参数错误(如模型 ID 格式不正确) |
|
||||
| `404` | 资源不存在(如模型不存在) |
|
||||
| `500` | 服务器内部错误 |
|
||||
| `503` | 服务暂时不可用 |
|
||||
|
||||
### 模型 ID 格式错误
|
||||
|
||||
**错误请求**:
|
||||
```json
|
||||
{
|
||||
"prompt": "a cat",
|
||||
"model": "qwen-image"
|
||||
}
|
||||
```
|
||||
|
||||
**错误响应**:
|
||||
```json
|
||||
{
|
||||
"code": "400",
|
||||
"message": "Model must be in format 'provider/model_key', got: 'qwen-image'. Example: 'dashscope/qwen-image'"
|
||||
}
|
||||
```
|
||||
|
||||
### 模型不存在
|
||||
|
||||
**错误请求**:
|
||||
```json
|
||||
{
|
||||
"prompt": "a cat",
|
||||
"model": "invalid/model"
|
||||
}
|
||||
```
|
||||
|
||||
**错误响应**:
|
||||
```json
|
||||
{
|
||||
"code": "404",
|
||||
"message": "Model 'invalid/model' not found. Available models can be fetched from /api/v1/models"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 使用复合 ID
|
||||
|
||||
始终使用完整的复合 ID 格式:
|
||||
|
||||
✅ **正确**:
|
||||
```json
|
||||
{
|
||||
"model": "dashscope/qwen-image"
|
||||
}
|
||||
```
|
||||
|
||||
❌ **错误**:
|
||||
```json
|
||||
{
|
||||
"model": "qwen-image"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 获取可用模型
|
||||
|
||||
在调用生成 API 之前,先获取可用模型列表:
|
||||
|
||||
```javascript
|
||||
// 1. 获取模型配置
|
||||
const response = await fetch('/api/v1/models');
|
||||
const { data } = await response.json();
|
||||
|
||||
// 2. 使用模型 ID
|
||||
const imageModels = data.image;
|
||||
const modelId = Object.keys(imageModels)[0]; // "dashscope/qwen-image"
|
||||
|
||||
// 3. 调用生成 API
|
||||
await fetch('/api/v1/generations/image', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
prompt: "a cat",
|
||||
model: modelId
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
### 3. 错误处理
|
||||
|
||||
始终处理可能的错误:
|
||||
|
||||
```javascript
|
||||
try {
|
||||
const response = await fetch('/api/v1/generations/image', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
prompt: "a cat",
|
||||
model: "dashscope/qwen-image"
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
console.error('API Error:', error.message);
|
||||
return;
|
||||
}
|
||||
|
||||
const { data } = await response.json();
|
||||
console.log('Task ID:', data.task_id);
|
||||
} catch (error) {
|
||||
console.error('Network Error:', error);
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 轮询任务状态
|
||||
|
||||
生成任务是异步的,需要轮询状态:
|
||||
|
||||
```javascript
|
||||
async function waitForTask(taskId) {
|
||||
while (true) {
|
||||
const response = await fetch(`/api/v1/tasks/${taskId}`);
|
||||
const { data } = await response.json();
|
||||
|
||||
if (data.status === 'completed') {
|
||||
return data.result;
|
||||
}
|
||||
|
||||
if (data.status === 'failed') {
|
||||
throw new Error('Task failed');
|
||||
}
|
||||
|
||||
// 等待 2 秒后重试
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 迁移指南
|
||||
|
||||
### 从旧格式迁移
|
||||
|
||||
如果你的代码使用了旧的 `provider` 参数,需要进行以下修改:
|
||||
|
||||
**旧代码**:
|
||||
```javascript
|
||||
await fetch('/api/v1/generations/image', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
prompt: "a cat",
|
||||
model: "qwen-image",
|
||||
provider: "dashscope" // ❌ 不再支持
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
**新代码**:
|
||||
```javascript
|
||||
await fetch('/api/v1/generations/image', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
prompt: "a cat",
|
||||
model: "dashscope/qwen-image" // ✅ 使用复合 ID
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
### 前端辅助函数
|
||||
|
||||
如果你的前端代码有 `getProviderForModel` 函数,可以直接删除:
|
||||
|
||||
**旧代码**:
|
||||
```typescript
|
||||
const provider = getProviderForModel(model, 'image'); // ❌ 删除
|
||||
await ImageGenerationService.generate({
|
||||
model,
|
||||
provider, // ❌ 删除
|
||||
prompt
|
||||
});
|
||||
```
|
||||
|
||||
**新代码**:
|
||||
```typescript
|
||||
await ImageGenerationService.generate({
|
||||
model, // ✅ 直接使用复合 ID
|
||||
prompt
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 交互式文档
|
||||
|
||||
访问 FastAPI 自动生成的交互式文档:
|
||||
|
||||
- **Swagger UI**: http://localhost:8000/docs
|
||||
- **ReDoc**: http://localhost:8000/redoc
|
||||
- **OpenAPI JSON**: http://localhost:8000/openapi.json
|
||||
|
||||
---
|
||||
|
||||
## 更新日志
|
||||
|
||||
### v2.0.0 (2026-02-11)
|
||||
|
||||
- ✅ 统一使用复合 ID 格式(`provider/model_key`)
|
||||
- ✅ 移除冗余的 `provider` 参数
|
||||
- ✅ 模型配置 API 返回按类型分组的 HashMap
|
||||
- ✅ 改进错误消息,提供清晰的格式说明
|
||||
- ✅ 简化前端 API 调用
|
||||
|
||||
---
|
||||
|
||||
## 支持
|
||||
|
||||
如有问题,请联系开发团队或查看:
|
||||
- [GitHub Issues](https://github.com/pixel-ai/pixel/issues)
|
||||
- [开发文档](../README.md)
|
||||
Reference in New Issue
Block a user