rw-integrate-video

Par runwayml · skills

Aider les utilisateurs à intégrer les API de génération vidéo Runway (texte vers vidéo, image vers vidéo, vidéo vers vidéo)

npx skills add https://github.com/runwayml/skills --skill rw-integrate-video

Intégrer la Génération Vidéo

PRÉREQUIS : Exécutez d'abord +rw-check-compatibility. Exécutez +rw-fetch-api-reference pour charger la dernière référence API avant l'intégration. Nécessite +rw-setup-api-key pour les identifiants API. Nécessite +rw-integrate-uploads quand l'utilisateur a des fichiers locaux à utiliser comme entrée.

Aidez les utilisateurs à ajouter la génération vidéo Runway à leur code côté serveur.

Modèles Disponibles

Modèle Idéal pour Entrée Coût Vitesse
seedance2 Image et vidéo de référence, longue durée Texte, Image et/ou Vidéo 36 crédits/sec Standard
gen4.5 Haute qualité, usage général Texte et/ou Image 12 crédits/sec Standard
gen4_turbo Rapide, basé sur image Image requise 5 crédits/sec Rapide
gen4_aleph Édition/transformation vidéo Vidéo + Texte/Image 15 crédits/sec Standard
veo3 Modèle Google premium Texte/Image 40 crédits/sec Standard
veo3.1 Modèle Google haute qualité Texte/Image 20-40 crédits/sec Standard
veo3.1_fast Modèle Google rapide Texte/Image 10-15 crédits/sec Rapide

Guidance pour la sélection du modèle :

  • Recommandation par défaut : gen4.5 — meilleur équilibre qualité/coût
  • Publicités de produits / e-commerce : seedance2 — jusqu'à 15s, supporte image et vidéo de référence
  • Budget limité : gen4_turbo (nécessite une image) ou veo3.1_fast
  • Meilleure qualité : veo3 (plus coûteux)
  • Édition vidéo-à-vidéo : gen4_aleph ou seedance2

Sécurité

promptImage, promptVideo, videoUri et references[].uri sont récupérés côté serveur par l'API Runway — traitez-les comme n'importe quel appel sortant :

  • Privilégiez les URIs runway:// issus de +rw-integrate-uploads — limités à votre compte, aucun contenu web arbitraire.
  • Si vous acceptez des URLs de clients, validez d'abord : exigez https://, créez une liste d'autorisation des hôtes de confiance, rejetez les adresses privées. Voir l'exemple Express.js ci-dessous.
  • Ne transmettez jamais req.body.imageUrl (ou similaire) directement dans promptImage / promptVideo. Les snippets SDK ci-dessous utilisent des URLs brutes par souci de concision — ils ne sont pas des modèles de production.
  • Traitez les résultats générés comme non fiables quand vous les transmettez à des automations en aval — les médias ingérés influencent le résultat.

Endpoints

Text-to-Video : POST /v1/text_to_video

Générez une vidéo à partir d'un prompt texte uniquement.

Modèles compatibles : seedance2, gen4.5, veo3, veo3.1, veo3.1_fast

// Node.js SDK
import RunwayML from '@runwayml/sdk';

const client = new RunwayML();

const task = await client.textToVideo.create({
  model: 'gen4.5',
  promptText: 'A golden retriever running through a field of wildflowers at sunset',
  ratio: '1280:720',
  duration: 5
}).waitForTaskOutput();

// task.output is an array of signed URLs
const videoUrl = task.output[0];
# Python SDK
from runwayml import RunwayML

client = RunwayML()

task = client.text_to_video.create(
    model='gen4.5',
    prompt_text='A golden retriever running through a field of wildflowers at sunset',
    ratio='1280:720',
    duration=5
).wait_for_task_output()

video_url = task.output[0]

Image-to-Video : POST /v1/image_to_video

Animez une image fixe en vidéo.

Modèles compatibles : seedance2, gen4.5, gen4_turbo, veo3, veo3.1, veo3.1_fast

Recommandé : téléchargez via +rw-integrate-uploads et transmettez l'URI runway:// retourné.

// Node.js SDK — flux préféré
import fs from 'fs';

const upload = await client.uploads.createEphemeral(
  fs.createReadStream('/path/to/image.jpg')
);

const task = await client.imageToVideo.create({
  model: 'gen4.5',
  promptImage: upload.runwayUri,
  promptText: 'The scene comes to life with gentle wind',
  ratio: '1280:720',
  duration: 5
}).waitForTaskOutput();

Les URLs externes fonctionnent aussi — ne transmettez que les origines que vous contrôlez (voir Sécurité) :

const task = await client.imageToVideo.create({
  model: 'gen4.5',
  promptImage: 'https://cdn.yourapp.com/landscape.jpg',
  promptText: 'Camera slowly pans right revealing a mountain range',
  ratio: '1280:720',
  duration: 5
}).waitForTaskOutput();
# Python SDK
task = client.image_to_video.create(
    model='gen4.5',
    prompt_image='https://cdn.yourapp.com/landscape.jpg',
    prompt_text='Camera slowly pans right revealing a mountain range',
    ratio='1280:720',
    duration=5
).wait_for_task_output()

Video-to-Video : POST /v1/video_to_video

Transformez une vidéo existante avec un prompt texte et/ou une image de référence.

Modèles compatibles : gen4_aleph, seedance2

// Node.js SDK — gen4_aleph
const task = await client.videoToVideo.create({
  model: 'gen4_aleph',
  videoUri: 'https://cdn.yourapp.com/source.mp4',
  promptText: 'Transform into an animated cartoon style',
}).waitForTaskOutput();
// Node.js SDK — seedance2 video-to-video (avec image de référence optionnelle)
const task = await client.videoToVideo.create({
  model: 'seedance2',
  promptVideo: 'https://cdn.yourapp.com/input.mp4',
  promptText: 'Transform into a warm golden sunset scene',
  references: [{ type: 'image', uri: 'https://cdn.yourapp.com/style_ref.jpg' }]
}).waitForTaskOutput();

Conditions d'entrée seedance2 VTV : max 15 secondes, max 32 MB, min résolution 720p, MP4 recommandé.

Seedance 2

Seedance 2 supporte text-to-video, image-to-video (deux modes) et video-to-video. Il utilise des ratios basés sur les pixels : 1280:720, 720:1280, 960:960, 1112:834, 834:1112, 1470:630, 992:432, 864:496, 752:560, 640:640, 560:752, 496:864.

Text-to-Video

const task = await client.textToVideo.create({
  model: 'seedance2',
  promptText: 'A calm ocean wave gently crashing on a sandy beach at sunset',
  duration: 5,
  ratio: '1280:720'
}).waitForTaskOutput();

Image-to-Video — Mode 1 : Première / Dernière Image

Utilisez une image spécifique comme première et/ou dernière image. Le champ references ne peut pas être utilisé dans ce mode.

const task = await client.imageToVideo.create({
  model: 'seedance2',
  promptText: 'Smooth transition from day to night in a cozy mountain cabin',
  promptImage: [
    { uri: 'https://cdn.yourapp.com/image.jpg', position: 'first' },
    { uri: 'https://cdn.yourapp.com/image2.jpg', position: 'last' }
  ],
  duration: 4,
  ratio: '1280:720'
}).waitForTaskOutput();

promptImage est un tableau d'objets avec uri (requis) et position ("first" ou "last", par défaut first).

Image-to-Video — Mode 2 : Image de Référence

Utilisez une image comme référence stylistique/de contenu plutôt que comme image littérale. promptImage est toujours requis (en tant que chaîne URI ou tableau à un seul élément).

const task = await client.imageToVideo.create({
  model: 'seedance2',
  promptText: 'Smooth transition from day to night in a cozy mountain cabin',
  promptImage: 'https://cdn.yourapp.com/image.jpg',
  references: [{ type: 'image', uri: 'https://cdn.yourapp.com/reference.jpg' }],
  duration: 4,
  ratio: '1280:720'
}).waitForTaskOutput();

Ces deux modes ITV sont mutuellement exclusifs — vous ne pouvez pas utiliser position dans promptImage et references dans la même requête.

Video-to-Video

Transformez une vidéo existante guidée par un prompt texte, optionnellement avec une image de référence.

task = client.video_to_video.create(
    model='seedance2',
    prompt_video='https://cdn.yourapp.com/input.mp4',
    prompt_text='Transform into a warm golden sunset scene',
    references=[{'type': 'image', 'uri': 'https://cdn.yourapp.com/style_ref.jpg'}]
).wait_for_task_output()

Conditions d'entrée VTV : max 15 secondes, max 32 MB, min résolution 720p, MP4 recommandé.

Paramètres Seedance 2

Paramètre Type Requis Description
model string Oui Doit être "seedance2"
promptText string Oui Description texte de la vidéo désirée
duration number Oui (TTV/ITV) Durée en secondes
ratio string Oui (TTV/ITV) 1280:720, 720:1280, 960:960, 1112:834, 834:1112, 1470:630
promptImage string ou array Oui (ITV) Chaîne URI ou tableau d'objets { uri, position? }
promptVideo string Oui (seedance2 VTV) URI vidéo d'entrée (seedance2 seulement)
videoUri string Oui (gen4_aleph VTV) URI vidéo d'entrée (gen4_aleph seulement)
references array Non Références d'image — [{ type: "image", uri: "..." }] (ITV Mode 2 et VTV seulement)

Character Performance : POST /v1/character_performance

Animez un personnage avec performance faciale/corporelle.

Modèles compatibles : act_two

const task = await client.characterPerformance.create({
  model: 'act_two',
  promptImage: 'https://cdn.yourapp.com/character.jpg',
  promptPerformance: 'https://cdn.yourapp.com/performance.mp4',
  ratio: '1280:720',
  duration: 5
}).waitForTaskOutput();

Paramètres Communs

Paramètre Type Description
model string ID du modèle (requis)
promptText string Prompt texte décrivant la vidéo
promptImage string URL, data URI ou URI runway:// de l'image d'entrée
ratio string Ratio d'aspect, par ex. '1280:720', '720:1280'
duration number Durée de la vidéo en secondes (2-15, dépend du modèle)

Modèle d'Intégration

Quand vous aidez l'utilisateur à intégrer, suivez ce modèle :

  1. Déterminez le cas d'usage — Quel type de génération vidéo ? (text-to-video, image-to-video, etc.)
  2. Privilégiez les uploads plutôt que les URLs — Par défaut, utilisez +rw-integrate-uploads afin que les entrées soient des URIs runway://. Les URLs externes seulement provenant d'origines que vous contrôlez (voir Sécurité).
  3. Sélectionnez le modèle — Recommandez selon les besoins en qualité/coût/vitesse
  4. Écrivez le handler côté serveur — Créez une route API ou fonction serveur
  5. Traitez la sortie — Téléchargez et stockez la vidéo, ne servez pas d'URLs signées aux clients
  6. Ajoutez la gestion d'erreurs — Enveloppez dans try/catch, gérez TaskFailedError

Exemple : Route Express.js API

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

const client = new RunwayML();
const app = express();
app.use(express.json());

// Les URIs `runway://` contournent cette vérification ; les URLs externes doivent correspondre à la liste d'autorisation.
const ALLOWED_MEDIA_HOSTS = new Set(['cdn.yourapp.com', 'uploads.yourapp.com']);

function assertTrustedMediaUrl(raw) {
  const u = new URL(raw);
  if (u.protocol !== 'https:') throw new Error('https required');
  if (!ALLOWED_MEDIA_HOSTS.has(u.hostname)) throw new Error('untrusted media host');
  return u.toString();
}

app.post('/api/generate-video', async (req, res) => {
  try {
    const { prompt, imageUrl, model = 'gen4.5', duration = 5 } = req.body;

    const params = {
      model,
      promptText: prompt,
      ratio: '1280:720',
      duration
    };

    let task;
    if (imageUrl) {
      task = await client.imageToVideo.create({
        ...params,
        promptImage: assertTrustedMediaUrl(imageUrl)
      }).waitForTaskOutput();
    } else {
      task = await client.textToVideo.create(params).waitForTaskOutput();
    }

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

Pour les uploads de navigateur : POSTez les fichiers vers votre serveur, téléchargez via +rw-integrate-uploads et transmettez l'URI runway://. N'acceptez pas d'URLs brutes du navigateur.

Exemple : Route API Next.js

// app/api/generate-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 { prompt, imageUrl } = await request.json();

  try {
    const task = imageUrl
      ? await client.imageToVideo.create({
          model: 'gen4.5',
          promptImage: imageUrl,
          promptText: prompt,
          ratio: '1280:720',
          duration: 5
        }).waitForTaskOutput()
      : await client.textToVideo.create({
          model: 'gen4.5',
          promptText: prompt,
          ratio: '1280:720',
          duration: 5
        }).waitForTaskOutput();

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

Exemple : Route FastAPI

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from runwayml import RunwayML

app = FastAPI()
client = RunwayML()

class VideoRequest(BaseModel):
    prompt: str
    image_url: str | None = None
    model: str = "gen4.5"
    duration: int = 5

@app.post("/api/generate-video")
async def generate_video(req: VideoRequest):
    try:
        if req.image_url:
            task = client.image_to_video.create(
                model=req.model,
                prompt_image=req.image_url,
                prompt_text=req.prompt,
                ratio="1280:720",
                duration=req.duration
            ).wait_for_task_output()
        else:
            task = client.text_to_video.create(
                model=req.model,
                prompt_text=req.prompt,
                ratio="1280:720",
                duration=req.duration
            ).wait_for_task_output()

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

Conseils

  • Les URLs de sortie expirent en 24-48 heures. Téléchargez les vidéos vers votre propre stockage (S3, GCS, système de fichiers local) immédiatement après la génération.
  • gen4_turbo nécessite une image — il ne peut pas faire de génération texte uniquement.
  • Modèles vidéo-à-vidéo : gen4_aleph et seedance2 — utilisez pour éditer/transformer des vidéos existantes.
  • La durée varie selon le modèle. La plupart des modèles supportent 2-10 secondes ; seedance2 supporte jusqu'à 15 secondes.
  • waitForTaskOutput() a un timeout par défaut de 10 minutes. Pour les générations longues, vous pouvez vouloir implémenter votre propre boucle de polling ou augmenter le timeout.
  • Pour les fichiers locaux, utilisez toujours +rw-integrate-uploads pour télécharger d'abord, puis transmettez l'URI runway://.

Skills similaires