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