integrate-uploads
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseIntegrate Uploads
集成上传功能
PREREQUISITE: Runfirst. Run+check-compatibilityto load the latest API reference before integrating. Requires+fetch-api-referencefor API credentials.+setup-api-key
Help users upload local files (images, videos, audio) to Runway's ephemeral storage for use as inputs to generation models.
前置要求: 先运行。集成前请运行+check-compatibility加载最新的API参考。需要运行+fetch-api-reference配置API凭证。+setup-api-key
帮助用户将本地文件(图片、视频、音频)上传到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)
满足以下条件时请使用上传API:
- 用户有本地文件(非公共URL)需要作为输入使用
- 文件超过数据URI大小限制(图片5MB,视频/音频16MB)
- 文件的URL不符合Runway的URL要求(HTTPS、正确的请求头、无重定向)
满足以下条件时无需使用上传功能:
- 资源已经存放在符合请求头要求的公共HTTPS URL中
- 资源足够小,可以使用数据URI(图片<5MB,视频<16MB)
How It Works
工作原理
- Request an ephemeral upload slot → get a presigned upload URL and form fields
- Upload the file to the presigned URL
- Use the returned URI as input to any generation endpoint
runway://
runway://- 请求临时上传槽 → 获取预签名上传URL和表单字段
- 将文件上传到预签名URL
- 使用返回的URI作为任意生成端点的输入
runway://
runway://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:
- — file streams
fs.ReadStream - objects — from web APIs
File - objects
Blob - /
Buffer/ typed arraysArrayBuffer - objects — from
Responsefetch() - Async iterables
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();Node.js SDK支持的输入类型:
- — 文件流
fs.ReadStream - 对象 — 来自Web API
File - 对象
Blob - /
Buffer/ 类型化数组ArrayBuffer - 对象 — 来自
Responsefetch() - 异步可迭代对象
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 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
Use the 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` 对象(类文件对象)
- 二元组 `(文件名, 内容)`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();
// 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
});Step 3: Use the runway://
URI
runway://步骤3:使用runway://
URI
runway://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
上传限制
| Constraint | Value |
|---|---|
| Minimum file size | 512 bytes |
| Maximum file size | 200 MB |
| URI validity | 24 hours |
| Requires credits | Yes (must have purchased credits) |
| 限制项 | 取值 |
|---|---|
| 最小文件大小 | 512 字节 |
| 最大文件大小 | 200 MB |
| URI有效期 | 24 小时 |
| 是否需要积分 | 是(必须已购买积分) |
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 {
// 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 });
}
});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 {
// 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 }
);
}
}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:
# 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))Tips
注意事项
- Always upload local files before passing them to generation endpoints. Don't try to pass local file paths — they won't work.
- URIs expire after 24 hours. If you need to re-use an asset, upload it again.
runway:// - 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 URI.
runway:// - Maximum 200 MB per file via uploads — larger than URL (16 MB) or data URI (5 MB) limits.
- 传递给生成端点前务必先上传本地文件,不要尝试传递本地文件路径——它们无法被识别。
- URI 24小时后过期,如果需要重复使用资源,请重新上传。
runway:// - SDK会自动处理预签名URL流程——优先使用SDK而非手动调用REST接口。
- 对于需要图片/视频输入的模型(图生视频、视频生视频、角色表演),先上传资源,再传递URI。
runway:// - 单个上传文件最大支持200MB——比URL(16MB)和数据URI(5MB)的限制更高。