mcpField
I
integrate-characters

integrate-characters

github.com/runwaymlクリエイティブ・メディア7447 回インストール2 日前に更新
リポジトリ

integrate-characters について

integrate-charactersは、GWM-1を使ったRunwayのリアルタイム会話キャラクターを構築するスキルです。サーバー側でアバターとセッションを設定し、ReactコンポーネントでWebRTC通話画面を実装します。

主な機能

  1. 011枚の画像からアバターを作成
  2. 02音声と性格を設定
  3. 03任意のナレッジ文書を追加
  4. 04リアルタイムセッションの作成と管理
  5. 05WebRTCで接続

活用シーン

  1. 01会話型サポートキャラクターの構築
  2. 02ブランドのアニメーションアバター作成
  3. 03アバターに専門分野の知識を提供

インストール

コマンドをコピーしてターミナルで実行します。

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

インストール後、Claude Code で/integrate-charactersを入力して読み込まれたか確認します。

詳細

キャラクターの統合(GWM-1 アバター)

前提条件:

  • +check-compatibility — プロジェクトにサーバー側のコンポーネントが必要です(API キーをクライアントに絶対に公開してはいけません)
  • +fetch-api-reference — 統合する前に、https://docs.dev.runwayml.com/api/ から最新の API リファレンスを読み込みます
  • +setup-api-key — API 認証情報を設定する必要があります

任意の依存関係:

  • +integrate-documents — キャラクターにナレッジベースを追加します
  • +integrate-character-embed — React SDK を使用してアバター通話 UI を埋め込みます

GWM-1 を搭載した、リアルタイムで会話する AI アバター、Runway Characters の作成を支援します。

Characters は1 枚の画像(フォトリアル、アニメーション、非人間など、あらゆるビジュアルスタイルに対応)から生成でき、音声、性格、知識、アクションを細かく制御できます。ファインチューニングやトレーニングは不要です。

主な概念

アバターとセッション
概念説明
アバター外見、音声、性格が定義された永続的なペルソナです。一度作成すれば、何度でも使用できます。
セッションリアルタイムの会話を行うためのライブ WebRTC 接続です。1 人のユーザーと 1 体のアバターを接続します。最大時間:5 分。
セッションのライフサイクル
                    ┌───────────┐
         ┌──────────┤ NOT_READY ├──────────┐
         │          └─────┬─────┘          │
         │                │                │
         ▼                ▼                ▼
     CANCELLED          READY           FAILED
                       ┌──┴──┐
                       │     │
                       ▼     ▼
                    RUNNING FAILED
                    ┌──┴──┐
                    │     │
                    ▼     ▼
                COMPLETED CANCELLED
ステータス説明
NOT_READYセッションを準備中です。準備が整うまでポーリングします。
READYセッションの準備が整いました。sessionKey を使用できます。
RUNNINGWebRTC 接続がアクティブです。会話中です。
COMPLETEDセッションが正常に終了しました。
FAILEDエラーが発生しました。failure フィールドを確認してください。
CANCELLED完了前に明示的にキャンセルされました。

重要: セッション認証情報は一度のみ使用できます。認証情報を使用した後に WebRTC 接続に失敗した場合は、新しいセッションを作成する必要があります。

アーキテクチャ

API キーはサーバー側に保持する必要があります。処理の流れは次のとおりです。

Client (React)  →  Your Server  →  Runway API
                                      ↓
Client (React)  ←─── WebRTC ───← Runway (realtime)
  1. クライアントがお客様のサーバーにセッションをリクエストします
  2. お客様のサーバーが Runway API を呼び出してセッションを作成します(POST /v1/realtime_sessions)
  3. セッションが READY になるまで、お客様のサーバーがポーリングします(GET /v1/realtime_sessions/:id)
  4. お客様のサーバーが認証情報を使用します(POST /v1/realtime_sessions/:id/consume)
  5. お客様のサーバーが認証情報をクライアントに返します
  6. クライアントが Runway との直接 WebRTC 接続を確立します

ステップ 1:依存関係をインストールする

npm install @runwayml/sdk @runwayml/avatars-react
  • @runwayml/sdk — サーバー側 SDK(セッションの作成、アバターの管理)
  • @runwayml/avatars-react — クライアント側の React コンポーネント(WebRTC、UI)

ステップ 2:アバターを作成する

アバターはDeveloper Portal(UI)またはAPI(プログラムから)で作成できます。

オプション A:Developer Portal(初回におすすめ)
  1. https://dev.runwayml.com/ → Characters タブに移動します
  2. Create a Character をクリックします
  3. 参照画像をアップロードします(ヒントは以下を参照)
  4. 音声プリセットを選択します
  5. 性格の指示を記述します(例:「あなたは Acme Corp の親切なカスタマーサポートエージェントです……」)
  6. 必要に応じて開始スクリプトを追加します(キャラクターが最初に話す内容)
  7. 必要に応じてナレッジドキュメント(.txt ファイル)をアップロードします
  8. Create Character をクリックします
  9. Avatar ID(8be4df61-93ca-11d2-aa0d-00e098032b8c のような UUID)をコピーします
オプション B:API(プログラムから)
// 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)

参照画像がローカルファイルの場合は、まず +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...',
});
参照画像のガイドライン
  • あらゆるビジュアルスタイルに対応します:フォトリアルな人間、アニメーションのマスコット、様式化されたブランドキャラクター
  • 照明が適切で、高品質な画像を使用します
  • 顔がはっきりと見え、中央に配置されている必要があります
  • 複数の人物が写っている画像や、顔が遮られている画像は避けます
  • 推奨アスペクト比:1088×704
音声プリセット
プリセット ID名前スタイル
claraClara柔らかく、親しみやすい
victoriaVictoriaきりっとした、プロフェッショナルな
vincentVincent知識が豊富で、権威のある

Developer Portal ですべての音声をプレビューできます。

ステップ 3:セッションを作成する(サーバー側)

これは、クライアントが呼び出すサーバー側の API ルートです。セッションを作成し、準備が整うまでポーリングして認証情報を取得し、それらを返します。

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"],
    }

ステップ 4:クライアントから接続する

WebRTC 接続とレンダリングを処理する React SDK コンポーネントについては、+integrate-character-embed を参照してください。最も簡単な方法は次のとおりです。

'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)}
    />
  );
}

トラブルシューティング

  • API キーのエラー: キーは key_ の後に 128 個の 16 進数文字が続く形式です。有効なキーであることを確認してください。
  • クレジットがない: 通話を開始する前に、アカウントに前払いクレジットが必要です。
  • セッションのタイムアウト: 60 回のポーリングループは約 60 秒間待機します。セッションが繰り返しタイムアウトする場合は、ご利用のプランの同時実行数の上限を確認してください。
  • 認証情報がすでに消費済み: セッションの認証情報は 1 回限りです。消費後に WebRTC が失敗した場合は、新しいセッションを作成してください。
デバッグログ
<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);
  }}
/>
セッション状態を監視する
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>
  );
}
最小構成でテストする
npx degit runwayml/avatars-sdk-react/examples/nextjs-simple test-app
cd test-app
npm install
# Add your API key to .env.local
npm run dev

ブラウザーのサポート

ブラウザー最低バージョン
Chrome74+
Firefox78+
Safari14.1+
Edge79+

ユーザーはマイクへのアクセスを許可する必要があります。ユーザーの動画を有効にする場合は、カメラへのアクセス許可も必要です。

サポートを受ける

リソース説明
開発者ポータルアバターの管理、ログの表示、ダッシュボードへのアクセス
SDK リポジトリバグの報告、サンプルの表示、リリースの確認

問題を報告する際は、ブラウザーとバージョン、SDK のバージョン(npm list @runwayml/avatars-react)、エラーメッセージ、セッション ID、再現手順を記載してください。

コメント