> ## Documentation Index
> Fetch the complete documentation index at: https://docs.poyo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 文件流上传

> 使用 multipart/form-data 格式将文件直接上传到 PoYo AI

## 使用指南

* 该接口使用标准的 `multipart/form-data` 格式直接上传文件
* 支持直接从本地存储上传文件，并自动识别文件类型
* 最适合从桌面应用、移动应用或网页表单上传本地文件
* 文件可通过返回的 URL 立即访问。图片保留 72 小时；视频存储在 `temp/videos` 生命周期前缀下时保留 24 小时

## 参数详情

* **文件上传要求**：

  * `file` 字段必须包含二进制文件数据

  * 支持的图片格式：**JPEG、PNG、GIF、WebP**

  * 支持的视频格式：**MP4、WebM、MOV/QuickTime、AVI、MKV**

  * 上传数量上限：**每次请求 1 个文件**。视频不超过 **100MB**

  * 系统会根据二进制数据自动识别文件类型

* **参数命名约定**：

  * 该接口同时支持 **snake\_case** 和 **camelCase** 命名

  * `upload_path` 或 `uploadPath`，两者均可

  * `file_name` 或 `fileName`，两者均可

  * 使用与你应用代码风格一致的命名方式即可

* **存储配置**：

  * 所有文件在存储路径中都会自动加上 `temp/` 前缀

  * 如果指定 `upload_path: "photos"`，实际路径为 `temp/photos`

  * 图片在上传 **72 小时**后过期并自动删除

  * 使用默认路径上传的视频存储在 `temp/videos/` 下，在为该前缀配置了 R2 生命周期规则时，**24 小时**后过期

* **文件命名**：

  * 如果未提供 `file_name`，系统会按以下格式生成唯一文件名：`{timestamp}_{random}_{extension}`

  * 自动生成的文件名示例：`20251229130857_a8B9cD2e.png`

## 开发者说明

* 适合使用文件流上传的情况：

  * 从用户本地存储直接上传文件

  * 网页应用中基于表单的文件上传

  * 移动应用文件上传

  * 服务器之间的文件传输

* 对于已经存储在磁盘上的文件，这是效率最高的上传方式

* multipart/form-data 格式是所有编程语言和 HTTP 客户端通用的标准格式

* 如需持久保存，请在过期前将文件下载到本地：图片 72 小时，视频 24 小时

## 速率限制与配额

* **速率限制**：每个已认证用户、每个上传接口，在 60 秒固定窗口内最多 10 次请求

* 超出速率限制时，会收到 `429 Too Many Requests` 错误

* 固定窗口从窗口内第一次请求开始计算，同一用户的 JWT 请求和 API Key 请求共享该窗口

* 使用指数退避重试逻辑处理速率限制错误

## 常见错误场景

* **缺少文件**：请求体中没有提供文件（422 错误）

* **不支持的文件类型**：上传的文件不是支持的图片格式（JPEG、PNG、GIF、WebP）或视频格式（MP4、WebM、MOV/QuickTime、AVI、MKV）

* **视频过大**：上传的视频超过 100MB 限制（413 错误）

* **空文件**：上传的文件为 0 字节或已损坏

* **认证错误**：Authorization 请求头中的 API Key 缺失或无效

## 使用示例

### cURL 示例

```bash theme={"dark"}
curl -X POST "https://api.poyo.ai/api/common/upload/stream" \
  -H "Authorization: Bearer PoYo_API_KEY" \
  -F "file=@/path/to/image.png" \
  -F "file_name=my-image.png"
```

### Python 示例

```python theme={"dark"}
import requests

url = "https://api.poyo.ai/api/common/upload/stream"
headers = {"Authorization": "Bearer PoYo_API_KEY"}

files = {"file": open("/path/to/image.png", "rb")}  # or /path/to/video.mp4
data = {"file_name": "my-image.png"}

response = requests.post(url, headers=headers, files=files, data=data)
print(response.json())
```

### JavaScript 示例（Node.js）

```javascript theme={"dark"}
const FormData = require('form-data');
const fs = require('fs');
const axios = require('axios');

const form = new FormData();
form.append('file', fs.createReadStream('/path/to/image.png')); // or /path/to/video.mp4
form.append('file_name', 'my-image.png');

axios.post('https://api.poyo.ai/api/common/upload/stream', form, {
  headers: {
    'Authorization': 'Bearer PoYo_API_KEY',
    ...form.getHeaders()
  }
})
.then(response => console.log(response.data))
.catch(error => console.error(error));
```

### 视频上传示例

```bash theme={"dark"}
curl -X POST "https://api.poyo.ai/api/common/upload/stream"   -H "Authorization: Bearer PoYo_API_KEY"   -F "file=@/path/to/video.mp4"   -F "file_name=my-video.mp4"
```

使用默认路径上传的视频存储在 `temp/videos/` 下。请为该前缀配置 R2 生命周期规则，使对象在 1 天后过期。


## OpenAPI

````yaml zh/api-manual/file-series/upload-stream.json POST /api/common/upload/stream
openapi: 3.0.0
info:
  title: PoYo AI - 文件流上传
  description: 使用 multipart/form-data 格式直接上传文件到 PoYo AI
  version: 1.0.0
servers:
  - url: https://api.poyo.ai
    description: 生产环境
security:
  - BearerAuth: []
paths:
  /api/common/upload/stream:
    post:
      tags:
        - File Upload
      summary: 文件流上传
      description: >-
        使用 multipart/form-data 格式上传文件。支持图片和视频上传。视频默认存储在 temp/videos 前缀下，大小上限
        100MB，24 小时后过期。
      operationId: uploadFileStream
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/UploadStreamRequest'
            examples:
              basic-upload:
                summary: 基础文件上传
                value:
                  file: (binary file data)
              custom-naming-snake-case:
                summary: 使用自定义路径和文件名上传（snake_case）
                value:
                  file: (binary file data)
                  upload_path: photos
                  file_name: vacation-photo.jpg
              custom-naming-camel-case:
                summary: 使用自定义路径和文件名上传（camelCase）
                value:
                  file: (binary file data)
                  uploadPath: documents
                  fileName: profile-image.png
              video-upload:
                summary: 视频上传
                value:
                  file: (binary video data)
                  file_name: input-video.mp4
      responses:
        '200':
          description: 文件上传成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UploadResponse'
        '400':
          description: 请求错误 - 文件类型不支持或文件为空
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                unsupported-type:
                  summary: 文件类型不支持
                  value:
                    detail: 'Unsupported file type: application/pdf'
                empty-file:
                  summary: 文件为空
                  value:
                    detail: File is empty
        '401':
          description: 未授权 - 缺少认证信息或认证无效
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                not-authenticated:
                  summary: 未认证
                  value:
                    detail: Not authenticated
        '413':
          description: 请求体过大 - 视频超过 100MB 上限
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                video-too-large:
                  summary: 视频过大
                  value:
                    detail: Video file too large. Maximum size is 100MB
        '422':
          description: 无法处理的请求 - 缺少必填的 file 字段
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorResponse'
              examples:
                missing-file:
                  summary: 缺少 file 字段
                  value:
                    detail:
                      - loc:
                          - body
                          - file
                        msg: field required
                        type: value_error.missing
        '429':
          description: 超出速率限制 - 每个已认证用户在每个上传接口上，每 60 秒固定窗口内最多 10 次请求
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                rate-limit:
                  summary: 超出速率限制
                  value:
                    detail: Rate limit exceeded
        '500':
          description: 服务器错误 - 存储连接或上传失败
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                server-error:
                  summary: 服务器错误
                  value:
                    detail: 'Upload failed: Failed to write file to storage'
components:
  schemas:
    UploadStreamRequest:
      type: object
      required:
        - file
      properties:
        file:
          type: string
          format: binary
          description: |-
            要上传的文件二进制数据。

            **支持的图片格式**：JPEG、PNG、GIF、WebP

            **支持的视频格式**：MP4、WebM、QuickTime/MOV、AVI、MKV

            **上限**：每次请求 1 个文件。视频最大 100MB。

            **保留时长**：图片 72 小时后过期。存储在 temp/videos 生命周期前缀下的视频 24 小时后过期。

            **注意**：系统会自动识别文件类型并分类。
        upload_path:
          type: string
          description: |-
            自定义存储目录路径。

            支持两种命名方式：
            - **snake_case**：`upload_path`
            - **camelCase**：`uploadPath`

            未指定时，系统使用 `temp`。使用默认 `temp` 路径的视频会存储为 `temp/videos`。

            **注意**：API 路由会把自定义路径统一归到 `temp/` 前缀下。
          example: photos
        file_name:
          type: string
          description: |-
            上传文件的自定义文件名。

            支持两种命名方式：
            - **snake_case**：`file_name`
            - **camelCase**：`fileName`

            未指定时，系统会按以下格式生成唯一文件名：`{timestamp}_{random}_{extension}`

            **自动生成的文件名示例**：`20251229130857_a8B9cD2e.png`
          example: photo.png
    UploadResponse:
      type: object
      required:
        - success
        - code
        - msg
        - data
      properties:
        success:
          type: boolean
          example: true
          description: 上传是否成功
        code:
          type: integer
          example: 200
          description: >-
            业务状态码。`200` 表示成功，其他值都表示请求失败。请务必检查这个字段：部分参数校验错误会以 HTTP 200 返回，响应体里的
            `code` 为 `400`。


            - `200`：成功

            - `400`：请求参数无效

            - `401`：API Key 缺失或无效

            - `402`：积分不足

            - `403`：没有权限

            - `404`：资源不存在

            - `408`：请求超时

            - `429`：请求频率超限

            - `500`：服务器内部错误

            - `502`：上游服务错误

            - `503`：服务暂不可用


            详见[错误码](/zh/api-manual/error-codes)。
          enum:
            - 200
            - 400
            - 401
            - 402
            - 403
            - 404
            - 408
            - 429
            - 500
            - 502
            - 503
        msg:
          type: string
          example: File uploaded successfully
          description: 响应消息
        data:
          type: object
          required:
            - file_id
            - file_name
            - file_size
            - mime_type
            - file_url
            - download_url
            - expires_at
          properties:
            file_id:
              type: string
              example: 872defd8180ee9c6d32265ef4e8d255b
              description: 文件唯一标识（MD5 哈希）
            file_name:
              type: string
              example: test-stream.png
              description: 存储后的文件名
            original_name:
              type: string
              example: uploaded-file.png
              description: 上传文件的原始文件名
            file_size:
              type: integer
              example: 3242
              description: 文件大小（字节）
            mime_type:
              type: string
              example: image/png
              description: 上传文件的 MIME 类型，例如 image/png 或 video/mp4
            upload_path:
              type: string
              example: temp/videos
              description: 存储路径。默认情况下视频上传使用 temp/videos，图片上传使用 temp。
            file_url:
              type: string
              format: uri
              example: https://storage.poyo.ai/temp/videos/input-video.mp4
              description: 上传文件的直接访问 URL
            download_url:
              type: string
              format: uri
              example: https://storage.poyo.ai/temp/videos/input-video.mp4
              description: 下载 URL（与 file_url 相同）
            upload_time:
              type: string
              format: date-time
              example: '2025-12-29T13:09:04.731057'
              description: 上传时间戳，ISO 8601 格式
            expires_at:
              type: string
              format: date-time
              example: '2026-01-01T13:09:04.731057'
              description: 过期时间戳，ISO 8601 格式。图片 72 小时后过期；视频 24 小时后过期。
    ErrorResponse:
      type: object
      required:
        - detail
      properties:
        detail:
          type: string
          description: 描述错误原因的错误信息
          example: Not authenticated
    ValidationErrorResponse:
      type: object
      required:
        - detail
      properties:
        detail:
          type: array
          description: 校验错误列表
          items:
            type: object
            properties:
              loc:
                type: array
                items:
                  type: string
                description: 校验错误的位置
              msg:
                type: string
                description: 错误信息
              type:
                type: string
                description: 错误类型
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API Key
      description: >-
        所有 API 接口都需要 Bearer Token 认证。


        创建 API Key：登录 PoYo，进入 **仪表盘 → API
        密钥**（[poyo.ai/zh/dashboard/api-key](https://poyo.ai/zh/dashboard/api-key)），点击创建
        Key。


        在请求头中添加：


        ```

        Authorization: Bearer YOUR_API_KEY

        ```

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.