rw-integrate-uploads

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Integrate Uploads

集成上传功能

PREREQUISITE: Run
+rw-check-compatibility
first. Run
+rw-fetch-api-reference
to load the latest API reference before integrating. Requires
+rw-setup-api-key
for API credentials.
Help users upload local files (images, videos, audio) to Runway's ephemeral storage for use as inputs to generation models.
前提条件: 先运行
+rw-check-compatibility
。在集成前运行
+rw-fetch-api-reference
加载最新的API参考文档。需要通过
+rw-setup-api-key
配置API凭证。
帮助用户将本地文件(图片、视频、音频)上传至Runway的临时存储,用作生成模型的输入。

When to Use Uploads

何时使用上传功能

Use the Uploads API when:
  • The user has a local file (not a public URL) they want to use as input
  • The file exceeds data URI size limits (5 MB for images, 16 MB for video/audio)
  • The file's URL doesn't meet Runway's URL requirements (HTTPS, proper headers, no redirects)
You do NOT need uploads when:
  • The asset is already at a public HTTPS URL with proper headers
  • The asset is small enough for a data URI (< 5 MB image, < 16 MB video)
在以下场景使用Uploads API:
  • 用户拥有想要用作输入的本地文件(而非公共URL)
  • 文件超出Data URI大小限制(图片5MB,视频/音频16MB)
  • 文件URL不符合Runway的URL要求(HTTPS协议、正确的请求头、无重定向)
无需使用上传功能的场景:
  • 资源已存储在符合要求的公共HTTPS URL上
  • 资源体积足够小,可通过Data URI传输(图片<5MB,视频<16MB)

How It Works

工作流程

  1. Request an ephemeral upload slot → get a presigned upload URL and form fields
  2. Upload the file to the presigned URL
  3. Use the returned
    runway://
    URI as input to any generation endpoint
runway://
URIs are valid for 24 hours.
  1. 请求临时上传槽位 → 获取预签名上传URL和表单字段
  2. 将文件上传至预签名URL
  3. 使用返回的
    runway://
    URI作为任意生成接口的输入
runway://
URI的有效期为24小时。

SDK Upload (Recommended)

SDK上传(推荐方式)

Node.js

Node.js

javascript
import RunwayML from '@runwayml/sdk';
import fs from 'fs';

const client = new RunwayML();

// Upload from a file stream
const upload = await client.uploads.createEphemeral(
  fs.createReadStream('/path/to/image.jpg')
);

// Use the runway:// URI in any generation call
const task = await client.imageToVideo.create({
  model: 'gen4.5',
  promptImage: upload.runwayUri,
  promptText: 'The scene comes to life',
  ratio: '1280:720',
  duration: 5
}).waitForTaskOutput();
The Node.js SDK accepts:
  • fs.ReadStream
    — file streams
  • File
    objects — from web APIs
  • Blob
    objects
  • Buffer
    /
    ArrayBuffer
    / typed arrays
  • Response
    objects — from
    fetch()
  • Async iterables
javascript
import RunwayML from '@runwayml/sdk';
import fs from 'fs';

const client = new RunwayML();

// 从文件流上传
const upload = await client.uploads.createEphemeral(
  fs.createReadStream('/path/to/image.jpg')
);

// 在生成调用中使用runway:// URI
const task = await client.imageToVideo.create({
  model: 'gen4.5',
  promptImage: upload.runwayUri,
  promptText: 'The scene comes to life',
  ratio: '1280:720',
  duration: 5
}).waitForTaskOutput();
Node.js SDK支持以下类型:
  • fs.ReadStream
    — 文件流
  • File
    对象 — 来自Web API
  • Blob
    对象
  • Buffer
    /
    ArrayBuffer
    / 类型化数组
  • Response
    对象 — 来自
    fetch()
  • 异步可迭代对象

Python

Python

python
from runwayml import RunwayML
from pathlib import Path

client = RunwayML()
python
from runwayml import RunwayML
from pathlib import Path

client = RunwayML()

Upload from a file path

从文件路径上传

upload = client.uploads.create_ephemeral( Path('/path/to/image.jpg') )
upload = client.uploads.create_ephemeral( Path('/path/to/image.jpg') )

Use the runway:// URI

使用runway:// URI

task = client.image_to_video.create( model='gen4.5', prompt_image=upload.runway_uri, prompt_text='The scene comes to life', ratio='1280:720', duration=5 ).wait_for_task_output()

The Python SDK accepts:
- `pathlib.Path` objects
- `IOBase` objects (file-like objects)
- Two-tuples of `(filename, content)`
task = client.image_to_video.create( model='gen4.5', prompt_image=upload.runway_uri, prompt_text='The scene comes to life', ratio='1280:720', duration=5 ).wait_for_task_output()

Python SDK支持以下类型:
- `pathlib.Path`对象
- `IOBase`对象(类文件对象)
- `(filename, content)`二元组

REST API Upload (Manual)

REST API上传(手动方式)

If not using the SDK, the upload flow has three steps:
如果不使用SDK,上传流程分为三步:

Step 1: Create an upload slot

步骤1:创建上传槽位

javascript
const response = await fetch('https://api.dev.runwayml.com/v1/uploads', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.RUNWAYML_API_SECRET}`,
    'X-Runway-Version': '2024-11-06',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    filename: 'image.jpg',
    type: 'ephemeral'
  })
});

const { uploadUrl, fields, runwayUri } = await response.json();
javascript
const response = await fetch('https://api.dev.runwayml.com/v1/uploads', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.RUNWAYML_API_SECRET}`,
    'X-Runway-Version': '2024-11-06',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    filename: 'image.jpg',
    type: 'ephemeral'
  })
});

const { uploadUrl, fields, runwayUri } = await response.json();

Step 2: Upload the file using the presigned URL

步骤2:使用预签名URL上传文件

javascript
const formData = new FormData();

// Add all presigned form fields first
for (const [key, value] of Object.entries(fields)) {
  formData.append(key, value);
}

// Add the file last
formData.append('file', fileBuffer, 'image.jpg');

await fetch(uploadUrl, {
  method: 'POST',
  body: formData
});
javascript
const formData = new FormData();

// 先添加所有预签名表单字段
for (const [key, value] of Object.entries(fields)) {
  formData.append(key, value);
}

// 最后添加文件
formData.append('file', fileBuffer, 'image.jpg');

await fetch(uploadUrl, {
  method: 'POST',
  body: formData
});

Step 3: Use the
runway://
URI

步骤3:使用
runway://
URI

javascript
const task = await fetch('https://api.dev.runwayml.com/v1/image_to_video', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.RUNWAYML_API_SECRET}`,
    'X-Runway-Version': '2024-11-06',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    model: 'gen4.5',
    promptImage: runwayUri,
    promptText: 'Animate this scene',
    ratio: '1280:720',
    duration: 5
  })
});
javascript
const task = await fetch('https://api.dev.runwayml.com/v1/image_to_video', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.RUNWAYML_API_SECRET}`,
    'X-Runway-Version': '2024-11-06',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    model: 'gen4.5',
    promptImage: runwayUri,
    promptText: 'Animate this scene',
    ratio: '1280:720',
    duration: 5
  })
});

Upload Constraints

上传限制

ConstraintValue
Minimum file size512 bytes
Maximum file size200 MB
URI validity24 hours
Requires creditsYes (must have purchased credits)
限制项数值
最小文件体积512字节
最大文件体积200MB
URI有效期24小时
是否需要 credits是(必须已购买credits)

Integration Pattern

集成示例

Express.js — Upload Endpoint with File Generation

Express.js — 带文件生成功能的上传接口

javascript
import RunwayML from '@runwayml/sdk';
import express from 'express';
import multer from 'multer';

const client = new RunwayML();
const app = express();
const upload = multer({ storage: multer.memoryStorage() });

app.post('/api/image-to-video', upload.single('image'), async (req, res) => {
  try {
    // Upload the user's file to Runway
    const runwayUpload = await client.uploads.createEphemeral(req.file.buffer);

    // Use the uploaded file for video generation
    const task = await client.imageToVideo.create({
      model: 'gen4.5',
      promptImage: runwayUpload.runwayUri,
      promptText: req.body.prompt || 'Animate this image',
      ratio: '1280:720',
      duration: 5
    }).waitForTaskOutput();

    res.json({ videoUrl: task.output[0] });
  } catch (error) {
    console.error('Generation failed:', error);
    res.status(500).json({ error: error.message });
  }
});
javascript
import RunwayML from '@runwayml/sdk';
import express from 'express';
import multer from 'multer';

const client = new RunwayML();
const app = express();
const upload = multer({ storage: multer.memoryStorage() });

app.post('/api/image-to-video', upload.single('image'), async (req, res) => {
  try {
    // 将用户文件上传至Runway
    const runwayUpload = await client.uploads.createEphemeral(req.file.buffer);

    // 使用上传的文件生成视频
    const task = await client.imageToVideo.create({
      model: 'gen4.5',
      promptImage: runwayUpload.runwayUri,
      promptText: req.body.prompt || 'Animate this image',
      ratio: '1280:720',
      duration: 5
    }).waitForTaskOutput();

    res.json({ videoUrl: task.output[0] });
  } catch (error) {
    console.error('Generation failed:', error);
    res.status(500).json({ error: error.message });
  }
});

Next.js — Upload + Generate

Next.js — 上传+生成

typescript
// app/api/image-to-video/route.ts
import RunwayML from '@runwayml/sdk';
import { NextRequest, NextResponse } from 'next/server';

const client = new RunwayML();

export async function POST(request: NextRequest) {
  const formData = await request.formData();
  const imageFile = formData.get('image') as File;
  const prompt = formData.get('prompt') as string;

  try {
    // Upload file to Runway
    const upload = await client.uploads.createEphemeral(imageFile);

    // Generate video from the uploaded image
    const task = await client.imageToVideo.create({
      model: 'gen4.5',
      promptImage: upload.runwayUri,
      promptText: prompt || 'Animate this image',
      ratio: '1280:720',
      duration: 5
    }).waitForTaskOutput();

    return NextResponse.json({ videoUrl: task.output[0] });
  } catch (error) {
    return NextResponse.json(
      { error: error instanceof Error ? error.message : 'Failed' },
      { status: 500 }
    );
  }
}
typescript
// app/api/image-to-video/route.ts
import RunwayML from '@runwayml/sdk';
import { NextRequest, NextResponse } from 'next/server';

const client = new RunwayML();

export async function POST(request: NextRequest) {
  const formData = await request.formData();
  const imageFile = formData.get('image') as File;
  const prompt = formData.get('prompt') as string;

  try {
    // 将文件上传至Runway
    const upload = await client.uploads.createEphemeral(imageFile);

    // 从上传的图片生成视频
    const task = await client.imageToVideo.create({
      model: 'gen4.5',
      promptImage: upload.runwayUri,
      promptText: prompt || 'Animate this image',
      ratio: '1280:720',
      duration: 5
    }).waitForTaskOutput();

    return NextResponse.json({ videoUrl: task.output[0] });
  } catch (error) {
    return NextResponse.json(
      { error: error instanceof Error ? error.message : 'Failed' },
      { status: 500 }
    );
  }
}

FastAPI — Upload + Generate

FastAPI — 上传+生成

python
from fastapi import FastAPI, UploadFile, Form, HTTPException
from runwayml import RunwayML

app = FastAPI()
client = RunwayML()

@app.post("/api/image-to-video")
async def image_to_video(image: UploadFile, prompt: str = Form("Animate this image")):
    try:
        # Upload to Runway
        content = await image.read()
        upload = client.uploads.create_ephemeral((image.filename, content))

        # Generate video
        task = client.image_to_video.create(
            model="gen4.5",
            prompt_image=upload.runway_uri,
            prompt_text=prompt,
            ratio="1280:720",
            duration=5
        ).wait_for_task_output()

        return {"video_url": task.output[0]}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
python
from fastapi import FastAPI, UploadFile, Form, HTTPException
from runwayml import RunwayML

app = FastAPI()
client = RunwayML()

@app.post("/api/image-to-video")
async def image_to_video(image: UploadFile, prompt: str = Form("Animate this image")):
    try:
        # 上传至Runway
        content = await image.read()
        upload = client.uploads.create_ephemeral((image.filename, content))

        # 生成视频
        task = client.image_to_video.create(
            model="gen4.5",
            prompt_image=upload.runway_uri,
            prompt_text=prompt,
            ratio="1280:720",
            duration=5
        ).wait_for_task_output()

        return {"video_url": task.output[0]}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

Tips

提示

  • Always upload local files before passing them to generation endpoints. Don't try to pass local file paths — they won't work.
  • runway://
    URIs expire after 24 hours.
    If you need to re-use an asset, upload it again.
  • The SDK handles the presigned URL flow automatically — prefer the SDK over manual REST calls.
  • For models requiring image/video input (image-to-video, video-to-video, character performance), upload the asset first, then pass the
    runway://
    URI.
  • Maximum 200 MB per file via uploads — larger than URL (16 MB) or data URI (5 MB) limits.
  • 始终先上传本地文件,再将其传入生成接口。不要尝试直接传入本地文件路径——这无法生效。
  • runway://
    URI会在24小时后过期
    。如果需要重复使用资源,请重新上传。
  • SDK会自动处理预签名URL流程——优先使用SDK而非手动REST调用。
  • 对于需要图片/视频输入的模型(图生视频、视频生视频、角色动作生成),先上传资源,再传入
    runway://
    URI。
  • 单次上传最大支持200MB文件——大于URL(16MB)或Data URI(5MB)的限制。