# 小虾 SaaS API 参考文档

**版本**: v0.1.88  
**更新日期**: 2026-06-29  
**基础 URL**: `/api/v1`

---

## 目录

1. [认证 (Auth)](#1-认证-auth)
2. [项目 (Project)](#2-项目-project)
3. [任务中心 (TaskCenter)](#3-任务中心-taskcenter)
4. [素材诊断 (AssetDiagnosis)](#4-素材诊断-assetdiagnosis)
5. [素材库 (AssetLibrary)](#5-素材库-assetlibrary)
6. [素材 (Asset)](#6-素材-asset)
7. [导入任务 (IngestJob)](#7-导入任务-ingestjob)
8. [分类任务 (ClassificationJob)](#8-分类任务-classificationjob)
9. [上传 (Upload)](#9-上传-upload)
10. [分片上传 (ChunkedUpload)](#10-分片上传-chunkedupload)
11. [生成任务 (Generation)](#11-生成任务-generation)
12. [生成视频 (GeneratedVideo)](#12-生成视频-generatedvideo)
13. [标题库 (TitleLibrary)](#13-标题库-titlelibrary)
14. [配音库 (VoiceLibrary)](#14-配音库-voicelibrary)
15. [查重 (Duplication)](#15-查重-duplication)
16. [订阅 (Subscription)](#16-订阅-subscription)

---

## 通用说明

### 认证方式

除特别说明外，所有 API 端点均需要认证。认证通过以下方式：

**请求头**:
```
Authorization: Bearer <access_token>
```

获取 access_token 请参见 [登录接口](#post-apiv1autologin)。

### 错误响应格式

```json
{
  "detail": "错误描述信息"
}
```

### HTTP 状态码

| 状态码 | 说明 |
|--------|------|
| 200 | 请求成功 |
| 201 | 资源创建成功 |
| 204 | 请求成功（无返回内容） |
| 400 | 请求参数错误 |
| 401 | 未认证或 token 无效 |
| 403 | 无权限访问 |
| 404 | 资源不存在 |
| 409 | 资源冲突 |
| 413 | 文件过大 |
| 415 | 不支持的文件类型 |
| 422 | 请求格式正确但无法处理 |
| 429 | 配额超限 |
| 500 | 服务器内部错误 |
| 503 | 服务暂不可用 |

---

## 1. 认证 (Auth)

**基础路径**: `/api/v1/auth`

### POST /register

用户注册。

**认证**: 否

**请求 Body**:
```json
{
  "email": "user@example.com",
  "password": "your_password",
  "username": "username",
  "display_name": "显示名称"
}
```

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| email | string | 是 | 邮箱地址 |
| password | string | 是 | 密码（建议至少 8 位） |
| username | string | 是 | 用户名（唯一） |
| display_name | string | 否 | 显示名称，默认同 username |

**响应** `201 Created`:
```json
{
  "user_id": "用户ID",
  "email": "user@example.com",
  "username": "username",
  "display_name": "显示名称",
  "message": "注册成功！"
}
```

---

### POST /login

用户登录。

**认证**: 否

**请求 Body**:
```json
{
  "email": "user@example.com",
  "password": "your_password"
}
```

**响应** `200 OK`:
```json
{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIs...",
  "token_type": "bearer",
  "user_id": "用户ID",
  "email": "user@example.com",
  "username": "username",
  "display_name": "显示名称",
  "expires_in": 3600
}
```

---

### POST /refresh

刷新访问令牌。

**认证**: 否

**请求 Body**:
```json
{
  "refresh_token": "eyJhbGciOiJIUzI1NiIs..."
}
```

**响应** `200 OK`: 同登录响应

---

### GET /verify-email

验证邮箱（通过链接点击）。

**认证**: 否

**查询参数**:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| token | string | 是 | 邮箱验证 token |

**响应** `200 OK`:
```json
{
  "message": "邮箱验证成功"
}
```

---

### POST /verify-email

验证邮箱（通过 API）。

**认证**: 否

**请求 Body**:
```json
{
  "token": "邮箱验证 token"
}
```

**响应** `200 OK`:
```json
{
  "message": "邮箱验证成功"
}
```

---

### POST /password/forgot

请求密码重置。

**认证**: 否

**请求 Body**:
```json
{
  "email": "user@example.com"
}
```

**响应** `202 Accepted`:
```json
{
  "message": "如果账户存在，密码重置邮件已发送"
}
```

---

### POST /password/reset

重置密码。

**认证**: 否

**请求 Body**:
```json
{
  "token": "密码重置 token",
  "new_password": "new_password123"
}
```

**响应** `200 OK`:
```json
{
  "message": "密码重置成功"
}
```

---

### GET /me

获取当前登录用户信息。

**认证**: 是

**响应** `200 OK`:
```json
{
  "user_id": "用户ID",
  "email": "user@example.com",
  "username": "username",
  "display_name": "显示名称",
  "email_verified": true
}
```

---

## 2. 项目 (Project)

**基础路径**: `/api/v1/projects`

### GET /

获取用户的所有项目列表。

**认证**: 是

**响应** `200 OK`:
```json
{
  "items": [
    {
      "id": "项目ID",
      "owner_user_id": "拥有者ID",
      "name": "项目名称",
      "description": "项目描述",
      "shared_users": []
    }
  ]
}
```

---

### POST /

创建新项目。

**认证**: 是

**请求 Body**:
```json
{
  "name": "项目名称",
  "description": "项目描述（可选）"
}
```

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| name | string | 是 | 项目名称（1-100字符） |
| description | string | 否 | 项目描述（最多500字符） |

**响应** `200 OK`:
```json
{
  "id": "项目ID",
  "owner_user_id": "拥有者ID",
  "name": "项目名称",
  "description": "项目描述",
  "shared_users": []
}
```

---

### GET /{project_id}

获取指定项目详情。

**认证**: 是

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| project_id | string | 项目 ID |

**响应** `200 OK`:
```json
{
  "id": "项目ID",
  "owner_user_id": "拥有者ID",
  "name": "项目名称",
  "description": "项目描述",
  "shared_users": []
}
```

---

## 3. 任务中心 (TaskCenter)

**基础路径**: `/api/v1`

### GET /projects/{project_id}/tasks

获取项目的所有任务（导入任务 + 生成任务）。

**认证**: 是

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| project_id | string | 项目 ID |

**响应** `200 OK`:
```json
{
  "items": [
    {
      "id": "task:任务ID",
      "task_type": "ingest 或 generation",
      "project_id": "项目ID",
      "status": "pending | processing | completed | failed",
      "progress": 0.0,
      "current_step": "当前步骤描述",
      "error_message": "",
      "user_message": "",
      "retryable": false,
      "source_id": "原始任务ID",
      "created_at": "2024-01-01T00:00:00Z",
      "updated_at": "2024-01-01T00:00:00Z"
    }
  ]
}
```

---

### POST /tasks/{task_type}/{source_id}/retry

重试失败的任务。

**认证**: 是

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| task_type | string | 任务类型：`ingest` 或 `generation` |
| source_id | string | 原始任务 ID |

**响应** `200 OK`: 返回重试后的任务信息（同上）

---

## 4. 素材诊断 (AssetDiagnosis)

**基础路径**: `/api/v1`

### GET /projects/{project_id}/asset-diagnosis

获取项目的素材健康度诊断。

**认证**: 是

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| project_id | string | 项目 ID |

**响应** `200 OK`:
```json
{
  "project_id": "项目ID",
  "readiness_score": 75,
  "readiness_label": "素材充足",
  "total_assets": 10,
  "ready_assets": 8,
  "video_assets": 5,
  "image_assets": 2,
  "voice_assets": 1,
  "total_duration_seconds": 120.5,
  "estimated_video_count": 3,
  "used_assets": 2,
  "unused_assets": 6,
  "pending_review_assets": 0,
  "smart_views": [
    {
      "key": "recommended",
      "label": "推荐素材",
      "count": 5,
      "description": "已导入完成、可参与生成的视频素材"
    }
  ],
  "gaps": [
    {
      "key": "missing_voice",
      "severity": "info",
      "message": "暂未配置配音素材",
      "recommendation": "如果本项目需要口播/旁白，请上传配音素材"
    }
  ]
}
```

---

## 5. 素材库 (AssetLibrary)

**基础路径**: `/api/v1/asset-libraries`

### GET /

获取素材库列表。

**认证**: 是

**查询参数**:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| project_id | string | 否 | 按项目 ID 筛选 |

**响应** `200 OK`:
```json
{
  "items": [
    {
      "id": "素材库ID",
      "project_id": "项目ID",
      "name": "素材库名称",
      "kind": "video | voice | image",
      "asset_count": 10,
      "total_size": 104857600
    }
  ]
}
```

---

### POST /

创建素材库。

**认证**: 是

**请求 Body**:
```json
{
  "project_id": "项目ID",
  "name": "素材库名称",
  "kind": "video"
}
```

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| project_id | string | 是 | 所属项目 ID |
| name | string | 是 | 素材库名称（1-100字符） |
| kind | string | 是 | 类型：`video`、`voice` 或 `image` |

**响应** `200 OK`:
```json
{
  "id": "素材库ID",
  "project_id": "项目ID",
  "name": "素材库名称",
  "kind": "video",
  "asset_count": 0,
  "total_size": 0
}
```

---

## 6. 素材 (Asset)

**基础路径**: `/api/v1/assets`

### GET /

获取素材列表。

**认证**: 是

**查询参数**:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| library_id | string | 是 | 素材库 ID |

**响应** `200 OK`:
```json
{
  "items": [
    {
      "id": "素材ID",
      "project_id": "项目ID",
      "library_id": "素材库ID",
      "name": "素材名称.mp4",
      "storage_key": "uploads/xxx/素材名称.mp4",
      "mime_type": "video/mp4",
      "metadata": {},
      "file_size": 10485760,
      "thumbnail_url": "https://...",
      "duration": 120.5,
      "width": 1920,
      "height": 1080,
      "fps": 30.0,
      "codec": "h264",
      "status": "ready",
      "classification_status": "completed",
      "quality_score": 85.0,
      "uploaded_by_user_id": "用户ID"
    }
  ]
}
```

---

### POST /

创建素材记录（通常由上传流程自动调用）。

**认证**: 是

**请求 Body**:
```json
{
  "project_id": "项目ID",
  "library_id": "素材库ID",
  "name": "素材名称.mp4",
  "storage_key": "uploads/xxx/素材名称.mp4",
  "mime_type": "video/mp4",
  "metadata": {},
  "file_size": 10485760,
  "thumbnail_url": "https://...",
  "duration": 120.5,
  "width": 1920,
  "height": 1080,
  "fps": 30.0,
  "codec": "h264",
  "status": "uploading",
  "classification_status": "pending",
  "quality_score": 85.0
}
```

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| project_id | string | 是 | 项目 ID |
| library_id | string | 是 | 素材库 ID |
| name | string | 是 | 素材名称（1-100字符） |
| storage_key | string | 是 | 存储路径 |
| mime_type | string | 是 | MIME 类型 |
| metadata | object | 否 | 元数据 |
| file_size | integer | 否 | 文件大小（字节） |
| thumbnail_url | string | 否 | 缩略图 URL |
| duration | float | 否 | 时长（秒） |
| width | integer | 否 | 宽度 |
| height | integer | 否 | 高度 |
| fps | float | 否 | 帧率 |
| codec | string | 否 | 编码格式 |
| status | string | 否 | 状态（默认 uploading） |
| classification_status | string | 否 | 分类状态（默认 pending） |
| quality_score | float | 否 | 质量分数（0-100） |

**响应** `200 OK`: 返回创建的素材对象

---

### PATCH /{asset_id}/review

更新素材审核状态。

**认证**: 是

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| asset_id | string | 素材 ID |

**请求 Body**:
```json
{
  "review_status": "pending_review | approved | rejected"
}
```

**响应** `200 OK`: 返回更新的素材对象

---

## 7. 导入任务 (IngestJob)

**基础路径**: `/api/v1/ingest-jobs`

### GET /{job_id}

获取导入任务详情。

**认证**: 否（内部 API）

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| job_id | string | 任务 ID |

**响应** `200 OK`:
```json
{
  "id": "任务ID",
  "project_id": "项目ID",
  "library_id": "素材库ID",
  "storage_key": "uploads/xxx/file.mp4",
  "status": "completed",
  "error_message": "",
  "result_asset_id": "素材ID"
}
```

---

### POST /

提交新的导入任务。

**认证**: 否（内部 API）

**请求 Body**:
```json
{
  "project_id": "项目ID",
  "library_id": "素材库ID",
  "storage_key": "uploads/xxx/file.mp4"
}
```

**响应** `200 OK`: 返回创建的任务对象

---

## 8. 分类任务 (ClassificationJob)

**基础路径**: `/api/v1/classification-jobs`

### GET /{job_id}

获取分类任务详情。

**认证**: 否（内部 API）

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| job_id | string | 任务 ID |

**响应** `200 OK`:
```json
{
  "id": "任务ID",
  "project_id": "项目ID",
  "asset_id": "素材ID",
  "status": "completed",
  "classification": "video",
  "confidence": 0.95,
  "error_message": ""
}
```

---

### POST /

提交新的分类任务。

**认证**: 否（内部 API）

**请求 Body**:
```json
{
  "project_id": "项目ID",
  "asset_id": "素材ID"
}
```

**响应** `200 OK`: 返回创建的任务对象

---

## 9. 上传 (Upload)

**基础路径**: `/api/v1/upload`

### POST /direct/prepare

准备直传 OSS（获取表单签名）。

**认证**: 是

**请求 Body**:
```json
{
  "project_id": "项目ID",
  "library_id": "素材库ID",
  "filename": "video.mp4",
  "content_type": "video/mp4",
  "file_size": 104857600
}
```

**响应** `200 OK`:
```json
{
  "upload_url": "https://oss.example.com/...",
  "method": "POST",
  "storage_key": "uploads/xxx/video.mp4",
  "expires_at": "2024-01-01T12:00:00Z",
  "fields": {
    "OSSAccessKeyId": "...",
    "policy": "...",
    "signature": "...",
    "key": "uploads/xxx/video.mp4"
  },
  "max_size_bytes": 104857600
}
```

---

### POST /direct/complete

确认直传完成并创建导入任务。

**认证**: 是

**请求 Body**:
```json
{
  "project_id": "项目ID",
  "library_id": "素材库ID",
  "storage_key": "uploads/xxx/video.mp4"
}
```

**响应** `200 OK`:
```json
{
  "storage_key": "uploads/xxx/video.mp4",
  "ingest_job_id": "导入任务ID"
}
```

---

### POST /

上传素材文件（multipart/form-data）。

**认证**: 是

**表单字段**:
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| project_id | string | 是 | 项目 ID |
| library_id | string | 是 | 素材库 ID |
| file | file | 是 | 上传的文件 |

**响应** `200 OK`:
```json
{
  "storage_key": "uploads/xxx/video.mp4",
  "ingest_job_id": "导入任务ID",
  "url": "https://oss.example.com/uploads/xxx/video.mp4"
}
```

**支持的文件类型**:
- 视频: `video/mp4`, `video/mpeg`, `video/quicktime`, `video/x-msvideo`, `video/webm`, `video/x-matroska`, `video/3gpp`
- 音频: `audio/mpeg`, `audio/wav`, `audio/ogg`, `audio/flac`, `audio/aac`, `audio/mp3`, `audio/x-m4a`
- 图片: `image/jpeg`, `image/png`, `image/gif`, `image/webp`, `image/bmp`, `image/svg+xml`, `image/tiff`

---

## 10. 分片上传 (ChunkedUpload)

**基础路径**: `/api/v1/upload/chunk`

适用于大文件上传（最大 2GB）。

### POST /init

初始化分片上传。

**认证**: 是

**请求 Body**:
```json
{
  "filename": "large_video.mp4",
  "file_size": 1073741824,
  "total_chunks": 200,
  "content_type": "video/mp4",
  "project_id": "项目ID",
  "library_id": "素材库ID"
}
```

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| filename | string | 是 | 文件名（1-255字符） |
| file_size | integer | 是 | 文件大小（最大 2GB） |
| total_chunks | integer | 是 | 分片总数 |
| content_type | string | 否 | 文件 MIME 类型 |
| project_id | string | 是 | 项目 ID |
| library_id | string | 是 | 素材库 ID |

**响应** `200 OK`:
```json
{
  "upload_id": "上传ID",
  "chunk_size": 5242880,
  "total_chunks": 200,
  "filename": "large_video.mp4",
  "expires_at": "2024-01-02T00:00:00Z"
}
```

---

### POST /{upload_id}/{chunk_index}

上传单个分片。

**认证**: 是

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| upload_id | string | 上传 ID |
| chunk_index | integer | 分片索引（从 0 开始） |

**请求体**: 二进制文件数据

**响应** `200 OK`:
```json
{
  "message": "Chunk uploaded successfully",
  "chunk_index": 0,
  "uploaded_chunks": 1,
  "total_chunks": 200
}
```

---

### GET /{upload_id}/status

获取上传状态（支持断点续传）。

**认证**: 是

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| upload_id | string | 上传 ID |

**响应** `200 OK`:
```json
{
  "upload_id": "上传ID",
  "filename": "large_video.mp4",
  "file_size": 1073741824,
  "total_chunks": 200,
  "uploaded_chunks": [0, 1, 2, 3],
  "status": "uploading",
  "created_at": "2024-01-01T00:00:00Z",
  "expires_at": "2024-01-02T00:00:00Z"
}
```

---

### POST /{upload_id}/complete

完成分片上传，合并文件并创建导入任务。

**认证**: 是

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| upload_id | string | 上传 ID |

**请求 Body**:
```json
{
  "project_id": "项目ID",
  "library_id": "素材库ID"
}
```

**响应** `200 OK`:
```json
{
  "storage_key": "uploads/xxx/large_video.mp4",
  "ingest_job_id": "导入任务ID",
  "url": "https://oss.example.com/uploads/xxx/large_video.mp4"
}
```

---

## 11. 生成任务 (Generation)

**基础路径**: `/api/v1/generation`

### POST /tasks

创建视频生成任务。

**认证**: 是

**请求 Body**:
```json
{
  "project_id": "项目ID",
  "asset_library_id": "素材库ID",
  "strategy_id": "",
  "voice_library_id": ""
}
```

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| project_id | string | 是 | 项目 ID |
| asset_library_id | string | 是 | 素材库 ID |
| strategy_id | string | 否 | 生成策略 ID |
| voice_library_id | string | 否 | 配音库 ID |

**响应** `200 OK`:
```json
{
  "id": "任务ID",
  "project_id": "项目ID",
  "asset_library_id": "素材库ID",
  "strategy_id": "",
  "voice_library_id": "",
  "status": "pending",
  "progress": 0.0,
  "result_count": 0,
  "error_message": ""
}
```

---

### GET /tasks/{task_id}

获取生成任务详情。

**认证**: 是

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| task_id | string | 任务 ID |

**响应** `200 OK`: 返回任务详情（同上）

---

### GET /tasks/{task_id}/results

获取生成任务的成片列表。

**认证**: 是

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| task_id | string | 任务 ID |

**响应** `200 OK`:
```json
{
  "items": [
    {
      "id": "成片ID",
      "project_id": "项目ID",
      "generation_task_id": "任务ID",
      "name": "成片名称.mp4",
      "file_url": "uploads/xxx/output.mp4",
      "file_size": 5242880,
      "duration": 30.0,
      "thumbnail_url": "https://...",
      "width": 1920,
      "height": 1080,
      "fps": 30.0,
      "status": "completed",
      "review_status": "pending_review",
      "generation_params": {},
      "download_url": "https://..."
    }
  ]
}
```

---

## 12. 生成视频 (GeneratedVideo)

**基础路径**: `/api/v1/generated-videos`

### GET /

获取成片列表。

**认证**: 是

**查询参数**:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| project_id | string | 否 | 按项目 ID 筛选 |

**响应** `200 OK`:
```json
{
  "items": [
    {
      "id": "成片ID",
      "project_id": "项目ID",
      "generation_task_id": "任务ID",
      "name": "成片名称.mp4",
      "file_url": "uploads/xxx/output.mp4",
      "file_size": 5242880,
      "duration": 30.0,
      "thumbnail_url": "https://...",
      "width": 1920,
      "height": 1080,
      "fps": 30.0,
      "status": "completed",
      "review_status": "pending_review",
      "generation_params": {},
      "download_url": "https://..."
    }
  ]
}
```

---

### GET /{video_id}

获取成片详情。

**认证**: 是

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| video_id | string | 成片 ID |

**响应** `200 OK`: 返回成片详情

---

### PATCH /{video_id}/review

更新成片审核状态。

**认证**: 是

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| video_id | string | 成片 ID |

**请求 Body**:
```json
{
  "review_status": "pending_review | approved | rejected"
}
```

**响应** `200 OK`: 返回更新后的成片对象

---

### GET /{video_id}/download-url

获取成片下载链接。

**认证**: 是

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| video_id | string | 成片 ID |

**响应** `200 OK`:
```json
{
  "video_id": "成片ID",
  "download_url": "https://oss.example.com/..."
}
```

---

## 13. 标题库 (TitleLibrary)

**基础路径**: `/api/v1/titles`

### GET /

获取标题列表。

**认证**: 是

**查询参数**:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| category | string | 否 | 按分类筛选 |
| skip | integer | 否 | 跳过数量（默认 0） |
| limit | integer | 否 | 返回数量（默认 50，最大 200） |

**响应** `200 OK`:
```json
{
  "items": [
    {
      "id": "标题ID",
      "user_id": "用户ID",
      "name": "标题名称",
      "text": "标题文本内容",
      "category": "default",
      "description": "描述",
      "tags": ["标签1", "标签2"],
      "usage_count": 5,
      "is_active": true,
      "created_at": "2024-01-01T00:00:00Z",
      "updated_at": "2024-01-01T00:00:00Z"
    }
  ],
  "total": 100
}
```

---

### GET /{title_id}

获取标题详情。

**认证**: 是

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| title_id | string | 标题 ID |

**响应** `200 OK`: 返回标题详情

---

### POST /

创建标题。

**认证**: 是

**请求 Body**:
```json
{
  "name": "标题名称",
  "text": "标题文本内容",
  "category": "default",
  "description": "描述",
  "tags": ["标签1", "标签2"]
}
```

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| name | string | 是 | 标题名称（1-255字符） |
| text | string | 是 | 标题文本（1-500字符） |
| category | string | 否 | 分类（默认 default） |
| description | string | 否 | 描述 |
| tags | array | 否 | 标签列表 |

**响应** `201 Created`: 返回创建的标题对象

**配额限制**:
- free: 10 条
- standard: 50 条
- pro: 200 条
- enterprise: 无限制

---

### PUT /{title_id}

更新标题。

**认证**: 是

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| title_id | string | 标题 ID |

**请求 Body**:
```json
{
  "name": "新标题名称",
  "text": "新标题文本",
  "category": "new_category",
  "description": "新描述",
  "tags": ["新标签"]
}
```

**响应** `200 OK`: 返回更新后的标题对象

---

### DELETE /{title_id}

删除标题。

**认证**: 是

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| title_id | string | 标题 ID |

**响应** `204 No Content`

---

## 14. 配音库 (VoiceLibrary)

**基础路径**: `/api/v1/voices`

### GET /

获取配音列表。

**认证**: 是

**查询参数**:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| status | string | 否 | 按状态筛选 |
| skip | integer | 否 | 跳过数量（默认 0） |
| limit | integer | 否 | 返回数量（默认 50，最大 200） |

**响应** `200 OK`:
```json
{
  "items": [
    {
      "id": "配音ID",
      "user_id": "用户ID",
      "name": "配音名称",
      "text": "配音文本",
      "voice_provider": "elevenlabs",
      "voice_id": "voice_xxx",
      "voice_name": "中文男声",
      "audio_url": "https://...",
      "duration": 10.5,
      "file_size": 102400,
      "status": "completed",
      "project_id": null,
      "tags": ["旁白"],
      "created_at": "2024-01-01T00:00:00Z",
      "updated_at": "2024-01-01T00:00:00Z"
    }
  ],
  "total": 20
}
```

---

### GET /{voice_id}

获取配音详情。

**认证**: 是

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| voice_id | string | 配音 ID |

**响应** `200 OK`: 返回配音详情

---

### POST /

创建配音。

**认证**: 是

**请求 Body**:
```json
{
  "name": "配音名称",
  "text": "配音文本内容",
  "voice_provider": "elevenlabs",
  "voice_id": "voice_xxx",
  "voice_name": "中文男声",
  "audio_url": "https://...",
  "duration": 10.5,
  "file_size": 102400,
  "status": "completed",
  "project_id": null,
  "tags": ["旁白"]
}
```

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| name | string | 是 | 配音名称（1-255字符） |
| text | string | 否 | 配音文本 |
| voice_provider | string | 否 | 语音服务商 |
| voice_id | string | 否 | 语音 ID |
| voice_name | string | 否 | 语音名称 |
| audio_url | string | 否 | 音频 URL |
| duration | float | 否 | 时长（秒） |
| file_size | integer | 否 | 文件大小 |
| status | string | 否 | 状态（默认 completed） |
| project_id | string | 否 | 关联项目 ID |
| tags | array | 否 | 标签列表 |

**响应** `201 Created`: 返回创建的配音对象

---

### PUT /{voice_id}

更新配音。

**认证**: 是

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| voice_id | string | 配音 ID |

**请求 Body**: 同创建（所有字段可选）

**响应** `200 OK`: 返回更新后的配音对象

---

### DELETE /{voice_id}

删除配音。

**认证**: 是

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| voice_id | string | 配音 ID |

**响应** `204 No Content`

---

## 15. 查重 (Duplication)

**基础路径**: `/api/v1/duplication`

### POST /upload

上传视频进行查重检测。

**认证**: 是

**请求**: multipart/form-data

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| file | file | 是 | 视频文件 |

**响应** `200 OK`:
```json
{
  "id": "查重记录ID",
  "status": "pending",
  "message": "文件 \"video.mp4\" 已上传，正在查重中..."
}
```

**限制**:
- 仅支持视频文件: `mp4`, `mpeg`, `mov`, `avi`, `webm`, `mkv`, `3gp`
- 最大文件大小: 100MB

---

### GET /records

获取查重记录列表。

**认证**: 是

**响应** `200 OK`:
```json
[
  {
    "id": "记录ID",
    "filename": "video.mp4",
    "file_size": 5242880,
    "duration_seconds": 30.0,
    "status": "completed",
    "duplicate_rate": 0.15,
    "duplicate_count": 2,
    "created_at": "2024-01-01T00:00:00Z",
    "updated_at": "2024-01-01T00:01:00Z"
  }
]
```

---

### GET /records/{record_id}

获取查重记录详情（含重复片段）。

**认证**: 是

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| record_id | string | 查重记录 ID |

**响应** `200 OK`:
```json
{
  "id": "记录ID",
  "filename": "video.mp4",
  "file_size": 5242880,
  "duration_seconds": 30.0,
  "status": "completed",
  "duplicate_rate": 0.15,
  "duplicate_count": 2,
  "created_at": "2024-01-01T00:00:00Z",
  "updated_at": "2024-01-01T00:01:00Z",
  "segments": [
    {
      "id": "片段ID",
      "source_start": 5.0,
      "source_end": 10.5,
      "matched_video_id": "视频ID",
      "matched_video_name": "匹配视频名称",
      "matched_start": 0.0,
      "matched_end": 5.5,
      "similarity": 0.95
    }
  ]
}
```

---

### DELETE /records/{record_id}

删除查重记录。

**认证**: 是

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| record_id | string | 查重记录 ID |

**响应** `204 No Content`

---

### POST /records/{record_id}/retry

重新提交查重。

**认证**: 是

**路径参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| record_id | string | 查重记录 ID |

**响应** `200 OK`:
```json
{
  "id": "记录ID",
  "status": "pending",
  "message": "已重新提交查重"
}
```

---

## 16. 订阅 (Subscription)

**基础路径**: `/api/v1/subscription`

### GET /current

获取当前订阅信息。

**认证**: 是

**响应** `200 OK`:
```json
{
  "id": "sub-xxx",
  "plan_id": "pro",
  "plan_name": "专业版",
  "status": "active",
  "billing_cycle": "monthly",
  "current_period_start": "2024-01-01T00:00:00Z",
  "current_period_end": "2024-02-01T00:00:00Z",
  "amount": 299.0,
  "auto_renew": true,
  "created_at": "2024-01-01T00:00:00Z"
}
```

---

### GET /billing-records

获取账单记录列表。

**认证**: 是

**响应** `200 OK`:
```json
[]
```

---

### POST /change-plan

变更订阅套餐（升级/降级）。

**认证**: 是

**请求 Body**:
```json
{
  "target_plan_id": "pro",
  "billing_cycle": "monthly"
}
```

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| target_plan_id | string | 是 | 目标套餐: `free`, `standard`, `pro`, `enterprise` |
| billing_cycle | string | 是 | 计费周期: `monthly`, `yearly` |

**响应** `200 OK`:
```json
{
  "success": true,
  "message": "套餐已成功变更为 专业版",
  "new_subscription": { ... }
}
```

---

### POST /cancel

取消订阅。

**认证**: 是

**响应** `200 OK`:
```json
{
  "success": true,
  "message": "订阅已取消，当前周期结束后停止服务"
}
```

---

### POST /toggle-auto-renew

切换自动续费。

**认证**: 是

**请求 Body**:
```json
{
  "enabled": false
}
```

**响应** `200 OK`:
```json
{
  "success": true,
  "message": "已关闭自动续费"
}
```

---

## 附录 A: 套餐配额

| 套餐 | 最大项目数 | 存储空间 | 标题库配额 | 配音库配额 |
|------|-----------|----------|-----------|-----------|
| free | 3 | 10 GB | 10 条 | 5 条 |
| standard | 10 | 50 GB | 50 条 | 20 条 |
| pro | 无限制 | 100 GB | 200 条 | 100 条 |
| enterprise | 无限制 | 1000 GB | 无限制 | 无限制 |

---

## 附录 B: 套餐价格

| 套餐 | 月付 | 年付 |
|------|------|------|
| free | ¥0 | ¥0 |
| standard | ¥99 | ¥999 |
| pro | ¥299 | ¥2999 |
| enterprise | ¥999 | ¥9999 |

---

*文档版本: v0.1.88 | 更新于: 2026-06-29*
