rw-integrate-characters

Par runwayml · skills

Aidez les utilisateurs à créer des Runway Characters (avatars GWM-1) et à intégrer des sessions conversationnelles en temps réel dans leurs applications

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

Intégrer les Caractères (GWM-1 Avatars)

PRÉREQUIS:

  • +rw-check-compatibility — Le projet doit avoir un composant côté serveur (la clé API ne doit JAMAIS être exposée au client)
  • +rw-fetch-api-reference — Charger la dernière référence API depuis https://docs.dev.runwayml.com/api/ avant l'intégration
  • +rw-setup-api-key — Les identifiants API doivent être configurés

DÉPENDANCES OPTIONNELLES:

  • +rw-integrate-documents — Ajouter une base de connaissances à votre caractère
  • +rw-integrate-character-embed — Utiliser le SDK React pour intégrer l'interface d'appel avatar

Aider les utilisateurs à créer des Runway Characters — des avatars d'IA conversationnelle en temps réel alimentés par GWM-1.

À utiliser uniquement lors de la modification de la base de code d'un utilisateur. Pour la gestion directe des avatars ou d'autres actions ponctuelles de compte Runway depuis l'agent, utilisez plutôt +use-runway-api.

Les Characters sont générés à partir d'une image unique (n'importe quel style visuel — photoréaliste, animé, non-humain) avec contrôle total sur la voix, la personnalité, les connaissances et les actions. Aucun fine-tuning ni entraînement requis.

Concepts clés

Avatars vs Sessions

Concept Description
Avatar Une persona persistante avec une apparence, une voix et une personnalité définies. Créée une fois, utilisée plusieurs fois.
Session Une connexion WebRTC en direct pour une conversation en temps réel. Connecte un utilisateur à un avatar. Durée maximale: 5 minutes.

Cycle de vie de la Session

                    ┌───────────┐
         ┌──────────┤ NOT_READY ├──────────┐
         │          └─────┬─────┘          │
         │                │                │
         ▼                ▼                ▼
     CANCELLED          READY           FAILED
                       ┌──┴──┐
                       │     │
                       ▼     ▼
                    RUNNING FAILED
                    ┌──┴──┐
                    │     │
                    ▼     ▼
                COMPLETED CANCELLED
Statut Description
NOT_READY La session est en cours de provisionnement. Interroger jusqu'à ce qu'elle soit prête.
READY La session est prête. La sessionKey est disponible.
RUNNING La connexion WebRTC est active. Conversation en cours.
COMPLETED La session s'est terminée normalement.
FAILED Une erreur s'est produite. Vérifier le champ failure.
CANCELLED Explicitement annulée avant la fin.

Important: Les identifiants de session ne peuvent être consommés qu'une seule fois. Si la connexion WebRTC échoue après la consommation des identifiants, vous devez créer une nouvelle Session.

Architecture

La clé API doit rester côté serveur. Le flux est:

Client (React)  →  Votre Serveur  →  Runway API
                                        ↓
Client (React)  ←─── WebRTC ───← Runway (realtime)
  1. Le client demande une session auprès de votre serveur
  2. Votre serveur appelle l'API Runway pour créer une session (POST /v1/realtime_sessions)
  3. Votre serveur interroge jusqu'à ce que la session soit READY (GET /v1/realtime_sessions/:id)
  4. Votre serveur consomme les identifiants (POST /v1/realtime_sessions/:id/consume)
  5. Votre serveur retourne les identifiants au client
  6. Le client établit une connexion WebRTC directe à Runway

Étape 1: Installer les dépendances

npm install @runwayml/sdk @runwayml/avatars-react
  • @runwayml/sdk — SDK côté serveur (création de session, gestion des avatars)
  • @runwayml/avatars-react — Composants React côté client (WebRTC, UI)

Étape 2: Créer un Avatar

Les avatars peuvent être créés via le Developer Portal (UI) ou l'API (par programmation).

Option A: Developer Portal (Recommandé la première fois)

  1. Aller à https://dev.runwayml.com/ → onglet Characters
  2. Cliquer sur Create a Character
  3. Télécharger une image de référence (conseils ci-dessous)
  4. Choisir un préset de voix
  5. Rédiger les instructions de personnalité (p. ex., "You are a helpful customer support agent for Acme Corp...")
  6. Optionnellement ajouter un script de démarrage (ce que le character dit en premier)
  7. Optionnellement télécharger des documents de connaissances (fichiers .txt)
  8. Cliquer sur Create Character
  9. Copier l'Avatar ID (un UUID comme 8be4df61-93ca-11d2-aa0d-00e098032b8c)

Option B: API (Par programmation)

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

const client = new RunwayML();

const avatar = await client.avatars.create({
  name: 'Support Agent',
  referenceImage: 'https://example.com/avatar.png',
  voice: {
    type: 'runway-live-preset',
    presetId: 'clara',
  },
  personality: 'You are a helpful customer support agent for Acme Corp. You help users with billing questions and technical issues.',
});

console.log('Avatar ID:', avatar.id);
# Python
from runwayml import RunwayML

client = RunwayML()

avatar = client.avatars.create(
    name='Support Agent',
    reference_image='https://example.com/avatar.png',
    voice={
        'type': 'runway-live-preset',
        'preset_id': 'clara',
    },
    personality='You are a helpful customer support agent for Acme Corp.',
)

print('Avatar ID:', avatar.id)

Si l'image de référence est un fichier local, téléchargez-la d'abord avec +rw-integrate-uploads:

import fs from 'fs';

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

const avatar = await client.avatars.create({
  name: 'Support Agent',
  referenceImage: upload.runwayUri,
  voice: { type: 'runway-live-preset', presetId: 'clara' },
  personality: 'You are a helpful customer support agent...',
});

Image de référence (Obligatoire)

referenceImage est obligatoire lors de la création d'un avatar. Elle accepte trois formats:

Format Limite Quand l'utiliser
https://… URL 2048 caractères Image déjà hébergée publiquement
data:image/…;base64,… 5 MB (caractères) Fichiers locaux petits à moyens (~3,5 MB brut max)
runway://… URI 5000 caractères Fichiers volumineux téléchargés d'abord via /v1/uploads

Pour les fichiers locaux de plus de ~3,5 MB, utiliser le flux de téléchargement (+rw-integrate-uploads) pour obtenir un URI runway:// au lieu d'un URI de données.

Directives pour l'image de référence

  • N'importe quel style visuel fonctionne: humains photoréalistes, mascotes animées, caractères de marque stylisés
  • Utiliser des images de haute qualité avec un bon éclairage
  • Le visage doit être clairement visible et centré — les images sans visage reconnaissable échoueront le traitement
  • Éviter les images avec plusieurs personnes ou obstructions
  • Rapport d'aspect recommandé: 1088×704

Présets de voix

ID de préset Nom Style
clara Clara Doux, accessible
victoria Victoria Ferme, professionnel
vincent Vincent Instruit, autoritaire

Prévisualiser toutes les voix dans le Developer Portal.

Étape 3: Créer une Session (Côté serveur)

C'est la route API côté serveur que votre client appellera. Elle crée une session, interroge jusqu'à ce qu'elle soit prête, consomme les identifiants et les retourne.

Next.js App Router

// app/api/avatar/session/route.ts
import RunwayML from '@runwayml/sdk';

const client = new RunwayML();

export async function POST(request: Request) {
  const { avatarId } = await request.json();

  // 1. Create session
  const { id: sessionId } = await client.realtimeSessions.create({
    model: 'gwm1_avatars',
    avatar: { type: 'custom', avatarId },
  });

  // 2. Poll until ready
  let sessionKey: string | undefined;
  for (let i = 0; i < 60; i++) {
    const session = await client.realtimeSessions.retrieve(sessionId);

    if (session.status === 'READY') {
      sessionKey = session.sessionKey;
      break;
    }
    if (session.status === 'FAILED') {
      return Response.json({ error: session.failure }, { status: 500 });
    }

    await new Promise(r => setTimeout(r, 1000));
  }

  if (!sessionKey) {
    return Response.json({ error: 'Session timed out' }, { status: 504 });
  }

  // 3. Consume session to get WebRTC credentials
  const consumeResponse = await fetch(
    `${client.baseURL}/v1/realtime_sessions/${sessionId}/consume`,
    {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${sessionKey}`,
        'X-Runway-Version': '2024-11-06',
      },
    }
  );
  const credentials = await consumeResponse.json();

  return Response.json({
    sessionId,
    serverUrl: credentials.url,
    token: credentials.token,
    roomName: credentials.roomName,
  });
}

Express.js

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

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

app.post('/api/avatar/session', async (req, res) => {
  const { avatarId } = req.body;

  try {
    // 1. Create session
    const { id: sessionId } = await client.realtimeSessions.create({
      model: 'gwm1_avatars',
      avatar: { type: 'custom', avatarId },
    });

    // 2. Poll until ready
    let sessionKey: string | undefined;
    for (let i = 0; i < 60; i++) {
      const session = await client.realtimeSessions.retrieve(sessionId);

      if (session.status === 'READY') {
        sessionKey = session.sessionKey;
        break;
      }
      if (session.status === 'FAILED') {
        return res.status(500).json({ error: session.failure });
      }

      await new Promise(r => setTimeout(r, 1000));
    }

    if (!sessionKey) {
      return res.status(504).json({ error: 'Session timed out' });
    }

    // 3. Consume credentials
    const consumeResponse = await fetch(
      `${client.baseURL}/v1/realtime_sessions/${sessionId}/consume`,
      {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${sessionKey}`,
          'X-Runway-Version': '2024-11-06',
        },
      }
    );
    const credentials = await consumeResponse.json();

    res.json({
      sessionId,
      serverUrl: credentials.url,
      token: credentials.token,
      roomName: credentials.roomName,
    });
  } catch (error) {
    console.error('Session creation failed:', error);
    res.status(500).json({ error: error instanceof Error ? error.message : 'Unknown error' });
  }
});

FastAPI (Python)

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

app = FastAPI()
client = RunwayML()

class SessionRequest(BaseModel):
    avatar_id: str

@app.post("/api/avatar/session")
async def create_session(req: SessionRequest):
    # 1. Create session
    result = client.realtime_sessions.create(
        model='gwm1_avatars',
        avatar={'type': 'custom', 'avatar_id': req.avatar_id},
    )
    session_id = result.id

    # 2. Poll until ready
    session_key = None
    for _ in range(60):
        session = client.realtime_sessions.retrieve(session_id)

        if session.status == 'READY':
            session_key = session.session_key
            break
        if session.status == 'FAILED':
            raise HTTPException(status_code=500, detail=str(session.failure))

        time.sleep(1)

    if not session_key:
        raise HTTPException(status_code=504, detail='Session timed out')

    # 3. Consume credentials
    async with httpx.AsyncClient() as http:
        resp = await http.post(
            f"{client.base_url}/v1/realtime_sessions/{session_id}/consume",
            headers={
                "Authorization": f"Bearer {session_key}",
                "X-Runway-Version": "2024-11-06",
            },
        )
    credentials = resp.json()

    return {
        "session_id": session_id,
        "server_url": credentials["url"],
        "token": credentials["token"],
        "room_name": credentials["roomName"],
    }

Étape 4: Se connecter depuis le Client

Voir +rw-integrate-character-embed pour les composants SDK React qui gèrent la connexion WebRTC et le rendu. L'approche la plus simple:

'use client';
import { AvatarCall } from '@runwayml/avatars-react';
import '@runwayml/avatars-react/styles.css';

export default function CharacterPage() {
  return (
    <AvatarCall
      avatarId="your-avatar-id"
      connectUrl="/api/avatar/session"
      onEnd={() => console.log('Call ended')}
      onError={(error) => console.error('Error:', error)}
    />
  );
}

Dépannage

  • Erreurs de clé API: La clé commence par key_ suivi de 128 caractères hexadécimaux. S'assurer qu'elle est active.
  • Pas de crédits: Le compte doit disposer de crédits prépayés avant de démarrer un appel.
  • Expiration de session: La boucle de polling de 60 itérations attend ~60 secondes. Si les sessions expirent régulièrement, vérifier les limites de concurrence de votre tier.
  • Identifiants déjà consommés: Les identifiants de session s'utilisent une seule fois. Si WebRTC échoue après la consommation, créer une nouvelle session.

Journalisation de débogage

<AvatarCall
  avatarId="your-avatar-id"
  connectUrl="/api/avatar/session"
  onError={(error) => {
    console.error('Avatar error:', error);
    console.error('Error name:', error.name);
    console.error('Error message:', error.message);
    if (error.cause) console.error('Cause:', error.cause);
  }}
/>

Surveiller l'état de la session

import { useAvatarSession } from '@runwayml/avatars-react';

function DebugInfo() {
  const { state, sessionId, error } = useAvatarSession();
  return (
    <pre>
      {JSON.stringify({ state, sessionId, error: error?.message }, null, 2)}
    </pre>
  );
}

Tester avec une configuration minimale

npx degit runwayml/avatars-sdk-react/examples/nextjs-simple test-app
cd test-app
npm install
# Ajouter votre clé API à .env.local
npm run dev

Support des navigateurs

Navigateur Version minimale
Chrome 74+
Firefox 78+
Safari 14.1+
Edge 79+

Les utilisateurs doivent accorder les permissions de microphone. Les permissions de caméra sont nécessaires si la vidéo utilisateur est activée.

Obtenir de l'aide

Ressource Description
Developer Portal Gérer les avatars, consulter les journaux, accéder au tableau de bord
SDK Repository Signaler des bugs, consulter des exemples, vérifier les versions

En signalant des problèmes, inclure: navigateur/version, version du SDK (npm list @runwayml/avatars-react), messages d'erreur, ID de session et étapes à reproduire.

Skills similaires