> This page is for 平台, version V4 (default).
> For other versions, use one of these documentation indexes:
> - V4 (default): https://next.developer.frame.io/platform/v4/llms.txt
> - V4 实验版: https://next.developer.frame.io/platform/v4-experimental/llms.txt
> - 旧版: https://next.developer.frame.io/platform/v2/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://next.developer.frame.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://next.developer.frame.io/_mcp/server.

# Frame.io Python SDK — 上传指南

本指南介绍如何使用 **Frame.io Python SDK** (`frameio`) 将文件上传到 Frame.io。 SDK 支持通过预签名 URL 向 S3 上传分片的多分段，具备并行处理、自动重试以及可选的进度追踪功能。 有关常规上传 API 概念（上传 URL、标头、分片），请参阅[本地和远程上传的工作原理](./how-local-remote-uploads-work)。

---

## 先决条件

#### 身份验证

您拥有一个可用的 `Frameio` 客户端。请参阅[身份验证指南](/platform/docs/guides/authentication/python-sdk)以了解设置流程。

#### 安装 SDK

```bash
    pip install frameio
```

#### 目标文件夹

您需要知道文件要上传到的 `account_id` 和 `folder_id`。使用 SDK 来查找它们：

```python
    # List your accounts
    accounts = client.accounts.index()
    account_id = accounts.data[0].id

    # List workspaces in the account
    workspaces = client.workspaces.index(account_id=account_id)
    workspace_id = workspaces.data[0].id

    # List projects in the workspace
    projects = client.projects.index(account_id=account_id, workspace_id=workspace_id)
    project = projects.data[0]

    # The project's root folder is the top-level upload target
    folder_id = project.root_folder_id

    # Or list subfolders to upload into a specific one
    folders = client.folders.list(account_id=account_id, folder_id=folder_id)
```

---

## 快速入门

```python
import os
from frameio import Frameio
from frameio.files import FileCreateLocalUploadParamsData
from frameio.upload import FrameioUploader

client = Frameio(token="YOUR_TOKEN")

file_path = "/path/to/video.mp4"
file_size = os.path.getsize(file_path)

# 1. Create the file resource and get pre-signed upload URLs
response = client.files.create_local_upload(
    account_id="YOUR_ACCOUNT_ID",
    folder_id="YOUR_FOLDER_ID",
    data=FileCreateLocalUploadParamsData(
        name="video.mp4",
        file_size=file_size,
    ),
)

# 2. Upload the file to S3
with open(file_path, "rb") as f:
    FrameioUploader(response.data, f).upload()
```

就是这样。 SDK 根据 API 返回的上传 URL 将文件拆分为几个分片再并行上传，并自动处理重试。

---

## 工作原理

本地上传是一个两步过程：

#### 创建文件资源

使用文件名和大小调用 `client.files.create_local_upload()`。 API 创建占位符文件并返回预签名的 S3 PUT URL（每个分片一个）。 URL 的数量（以及因此的分片数量）取决于具体的文件大小。

#### 上传至 S3

`FrameioUploader` 从响应中读取上传 URL，将您的文件拆分为匹配的分片，并使用线程池将每个分片并行 PUT 到其 URL。 每个请求包含必需的 `x-amz-acl: private` 和 `Content-Type` 标头。

> **Note**
>
> 上传直接从您的应用程序传输到 S3（不通过 Frame.io API 服务器）。 这与 YouTube、Vimeo 和 Dropbox 等服务用于大文件上传的阵列相同。

---

## 用 `FrameioUploader`

`FrameioUploader` 是上传文件的推荐方式。 其中封装了底层分片的上传器并处理所有细节 — 从 API 响应中提取上传 URL、设置所需的标头、对文件分片以及并行上传。

### 进度跟踪

使用 `on_progress` 回调来跟踪上传进度：

```python
def on_progress(bytes_uploaded: int, total_bytes: int) -> None:
    pct = bytes_uploaded / total_bytes * 100
    print(f"\r{pct:.1f}% ({bytes_uploaded:,} / {total_bytes:,} bytes)", end="", flush=True)

with open(file_path, "rb") as f:
    FrameioUploader(response.data, f, on_progress=on_progress).upload()

print("\nUpload complete!")
```

每个分片上传完成后，回调函数会被调用一次，返回到目前为止已上传的累计字节数和文件总大小。

#### 丰富的进度条

为获得流畅的终端体验，请使用 [Rich](https://github.com/Textualize/rich)：

```python
from rich.progress import Progress, BarColumn, DownloadColumn, TransferSpeedColumn, TimeRemainingColumn

with Progress(
    "[progress.description]{task.description}",
    BarColumn(),
    DownloadColumn(),
    TransferSpeedColumn(),
    TimeRemainingColumn(),
) as progress:
    task = progress.add_task("Uploading...", total=file_size)

    with open(file_path, "rb") as f:
        FrameioUploader(
            response.data, f,
            on_progress=lambda done, total: progress.update(task, completed=done),
        ).upload()
```

### 配置

`FrameioUploader` 接受多个可选参数：

| 参数            | 默认                                             | 描述                                         |
| ------------- | ---------------------------------------------- | ------------------------------------------ |
| `max_workers` | `5`                                            | 并发上传线程数                                    |
| `标头`          | `{&quot;x-amz-acl&quot;: &quot;private&quot;}` | 随每个 S3 PUT 请求发送的标头。 自定义标头与默认标头合并。          |
| `max_retries` | `3`                                            | 每个分片的重试次数（指数退避：1 秒、2 秒、4 秒……）              |
| `on_progress` | `无`                                            | 在每个分片后触发回调 `(bytes_uploaded, total_bytes)` |

```python
with open(file_path, "rb") as f:
    FrameioUploader(
        response.data,
        f,
        max_workers=10,       # more parallelism for high-bandwidth connections
        max_retries=5,        # more resilient on flaky networks
        on_progress=on_progress,
    ).upload()
```

### 完整示例

包含身份验证、上传和进度跟踪的完整示例：

```python
import os
from frameio import Frameio
from frameio.auth import ServerToServerAuth
from frameio.files import FileCreateLocalUploadParamsData
from frameio.upload import FrameioUploader

# Authenticate
auth = ServerToServerAuth(
    client_id="YOUR_CLIENT_ID",
    client_secret="YOUR_CLIENT_SECRET",
)
client = Frameio(token=auth.get_token)

# Prepare the file
file_path = "/path/to/video.mp4"
file_name = os.path.basename(file_path)
file_size = os.path.getsize(file_path)

# Create the file resource
response = client.files.create_local_upload(
    account_id="YOUR_ACCOUNT_ID",
    folder_id="YOUR_FOLDER_ID",
    data=FileCreateLocalUploadParamsData(
        name=file_name,
        file_size=file_size,
    ),
)

print(f"Uploading {file_name} ({file_size:,} bytes) in {len(response.data.upload_urls)} chunks...")

# Upload with progress
def on_progress(uploaded: int, total: int) -> None:
    print(f"\r{uploaded / total:.0%}", end="", flush=True)

with open(file_path, "rb") as f:
    FrameioUploader(response.data, f, on_progress=on_progress).upload()

print(f"\nDone! View at: {response.data.view_url}")
```

---

> **Tip**
>
> 如果您需要完全控制上传过程（例如，手动处理分片、集成异步管道或自定义重试逻辑），请参阅[本地和远程上传的工作原理](./how-local-remote-uploads-work)，了解原始 API 流程和独立 Python 脚本示例。

---

## 远程上传

如果您的文件已可通过公共 URL 访问，请改用远程上传。 无需分片，Frame.io 会直接获取文件：

```python
from frameio.files import FileCreateRemoteUploadParamsData

response = client.files.create_remote_upload(
    account_id="YOUR_ACCOUNT_ID",
    folder_id="YOUR_FOLDER_ID",
    data=FileCreateRemoteUploadParamsData(
        name="video.mp4",
        source_url="https://example.com/video.mp4",
    ),
)
print(f"File created: {response.data.id}")
```

> **Warning**
>
> 远程上传目前有 **50 GB 的文件大小限制**。 对于超过 50 GB 的文件，请改用[本地上传](#quick-start)。

---

## 检查上传状态

上传后，您可以验证文件是否已接收：

```python
status = client.files.show_file_upload_status(
    account_id="YOUR_ACCOUNT_ID",
    file_id=response.data.id,
)
print(f"Upload complete: {status.data.upload_complete}")
```