rw-integrate-characters について
Runway Charactersをコードベースに組み込み、1枚の画像からリアルタイム会話AIアバターを作る開発者向けスキルです。サーバー側のセッション処理を扱い、ナレッジ文書やReact通話画面も追加できます。
主な機能
- 011枚の画像からアバターを作成
- 02音声・性格・知識内容を設定
- 03サーバーAPI経由でリアルタイムセッションを作成
- 04WebRTCで会話接続を確立
- 05文書とReact画面を任意で追加
活用シーン
- 01アプリにリアルタイム会話アバターを追加
- 02指定の音声とブランド性格を持つキャラクターを作成
- 03アバターに文書由来の知識とReact通話画面を追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ runwayml/ skills --skill rw-integrate-charactersインストール後、Claude Code で/rw-integrate-charactersを入力して読み込まれたか確認します。
詳細
キャラクターを統合する(GWM-1 アバター)
前提条件:
+rw-check-compatibility— プロジェクトにサーバーサイドのコンポーネントが必要です(API キーをクライアントに絶対に公開しないでください)+rw-fetch-api-reference— 統合する前に、https://docs.dev.runwayml.com/api/ から最新の API リファレンスを読み込みます+rw-setup-api-key— API 認証情報を設定する必要があります任意の依存関係:
+rw-integrate-documents— キャラクターにナレッジベースを追加します+rw-integrate-character-embed— React SDK を使ってアバターの通話 UI を埋め込みます
GWM-1 を搭載したリアルタイム会話型 AI アバター、Runway Characters の作成を支援します。
これはユーザーのコードベースを変更する場合にのみ使用してください。エージェントからアバターを直接管理する場合や、Runway アカウントに対して単発の操作を行う場合は、代わりに +use-runway-api を使用してください。
キャラクターは、1 枚の画像(写実的、アニメーション、人間以外など、あらゆるビジュアルスタイル)から生成され、音声、性格、知識、アクションを完全に制御できます。ファインチューニングやトレーニングは不要です。
主な概念
アバターとセッション
| 概念 | 説明 |
|---|---|
| アバター | 外見、音声、性格が定義された永続的なペルソナです。一度作成すれば、何度でも使用できます。 |
| セッション | リアルタイム会話のためのライブ WebRTC 接続です。1 人のユーザーを 1 つのアバターに接続します。最大時間:5 分。 |
セッションのライフサイクル
┌───────────┐
┌──────────┤ NOT_READY ├──────────┐
│ └─────┬─────┘ │
│ │ │
▼ ▼ ▼
CANCELLED READY FAILED
┌──┴──┐
│ │
▼ ▼
RUNNING FAILED
┌──┴──┐
│ │
▼ ▼
COMPLETED CANCELLED
| ステータス | 説明 |
|---|---|
NOT_READY | セッションを準備中です。準備ができるまでポーリングします。 |
READY | セッションの準備ができています。sessionKey を使用できます。 |
RUNNING | WebRTC 接続が有効です。会話中です。 |
COMPLETED | セッションが正常に終了しました。 |
FAILED | エラーが発生しました。failure フィールドを確認してください。 |
CANCELLED | 完了前に明示的にキャンセルされました。 |
重要: セッション認証情報は一度だけ使用できます。認証情報を使用した後に WebRTC 接続が失敗した場合は、新しいセッションを作成する必要があります。
アーキテクチャ
API キーはサーバーサイドに保持する必要があります。処理の流れは次のとおりです。
Client (React) → Your Server → Runway API
↓
Client (React) ←─── WebRTC ───← Runway (realtime)
- クライアントがお使いのサーバーにセッションをリクエストします
- サーバーが Runway API を呼び出してセッションを作成します(
POST /v1/realtime_sessions) - サーバーがセッションのステータスが
READYになるまでポーリングします(GET /v1/realtime_sessions/:id) - サーバーが認証情報を使用します(
POST /v1/realtime_sessions/:id/consume) - サーバーが認証情報をクライアントに返します
- クライアントが 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(初回におすすめ)
- https://dev.runwayml.com/ に移動し、Characters タブを開きます
- Create a Character をクリックします
- 参考画像をアップロードします(ヒントは以下を参照)
- 音声プリセットを選択します
- 性格の指示を記述します(例:「Acme Corp の親切なカスタマーサポートエージェントとして振る舞ってください……」)
- 必要に応じて開始スクリプトを追加します(キャラクターが最初に話す内容)
- 必要に応じてナレッジドキュメント(
.txtファイル)をアップロードします - Create Character をクリックします
- 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)
参考画像がローカルファイルの場合は、+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...',
});
参照画像(必須)
アバターを作成する際は、referenceImageが必須です。次の3つの形式を使用できます。
| 形式 | 上限 | 用途 |
|---|---|---|
https://… URL | 2048 chars | 画像がすでに公開されている場合 |
data:image/…;base64,… | 5 MB(文字数) | 小~中サイズのローカルファイル(元ファイルは最大約3.5 MB) |
runway://… URI | 5000 chars | 先に/v1/uploads経由でアップロードした大容量ファイル |
ローカルファイルが約3.5 MBを超える場合は、データURIではなく、アップロードフロー(+rw-integrate-uploads)を使ってrunway:// URIを取得してください。
参照画像のガイドライン
- あらゆるビジュアルスタイルを使用できます:フォトリアリスティックな人物、アニメーションのマスコット、スタイライズされたブランドキャラクター
- 照明が適切な高品質の画像を使用してください
- 顔がはっきりと見え、中央に配置されている必要があります — 識別できる顔がない画像は処理に失敗します
- 複数の人物が写っている画像や、顔が遮られている画像は避けてください
- 推奨アスペクト比:1088×704
音声プリセット
| プリセット ID | 名前 | スタイル |
|---|---|---|
clara | Clara | 柔らかく、親しみやすい |
victoria | Victoria | きりっとした、プロフェッショナル |
vincent | Vincent | 知識豊富で、権威のある |
すべての音声は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 コンポーネントについては、+rw-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秒間待機します。セッションが繰り返しタイムアウトする場合は、ご利用のプランの同時実行数の上限を確認してください。
- 認証情報がすでに使用されています: セッション認証情報は一度しか使用できません。認証情報の取得後に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
ブラウザーのサポート
| ブラウザー | 最小バージョン |
|---|---|
| Chrome | 74+ |
| Firefox | 78+ |
| Safari | 14.1+ |
| Edge | 79+ |
ユーザーはマイクの使用を許可する必要があります。ユーザーのビデオを有効にする場合は、カメラの使用許可も必要です。
ヘルプを利用する
| リソース | 説明 |
|---|---|
| Developer Portal | アバターの管理、ログの表示、ダッシュボードへのアクセス |
| SDK Repository | バグの報告、サンプルの閲覧、リリースの確認 |
問題を報告する際は、ブラウザーとバージョン、SDK のバージョン(npm list @runwayml/avatars-react)、エラーメッセージ、セッション ID、再現手順を含めてください。