mcpField
I
integrate-characters

integrate-characters

github.com/runwayml创意与媒体7447 次安装2 天前更新
代码仓库

关于 integrate-characters

integrate-characters 是构建由 GWM-1 驱动的 Runway 实时对话角色的技能,指导服务端创建头像和会话,并使用 React 组件提供客户端 WebRTC 通话界面。

主要功能

  1. 01根据单张图片创建头像
  2. 02配置声音和个性
  3. 03添加可选知识文档
  4. 04创建和管理实时会话
  5. 05通过 WebRTC 连接

适用场景

  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 嵌入虚拟形象通话界面

帮助用户创建 Runway Characters——由 GWM-1 驱动的实时对话式 AI 虚拟形象。

Character 根据单张图片生成(适用于任何视觉风格——照片级写实、动画、非人类),并可全面控制其声音、个性、知识和行动。无需微调或训练。

核心概念

虚拟形象与会话
概念说明
虚拟形象具有指定外观、声音和个性的持久角色。创建一次,可多次使用。
会话用于实时对话的 WebRTC 连接。将一位用户连接到一个虚拟形象。最长时长: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、界面)

步骤 2:创建虚拟形象

可通过 Developer Portal(界面)或 API(编程方式)创建虚拟形象。

选项 A:Developer Portal(推荐初次使用时采用)
  1. 前往 https://dev.runwayml.com/ → Characters 选项卡
  2. 点击 Create a Character
  3. 上传参考图片(请参阅下方提示)
  4. 选择语音预设
  5. 编写个性说明(例如:“你是 Acme Corp 的热心客户支持 Agent……”)
  6. 可选:添加开场脚本(角色首先说的话)
  7. 可选:上传知识文档(.txt 文件)
  8. 点击 Create Character
  9. 复制 Avatar ID(UUID,例如 8be4df61-93ca-11d2-aa0d-00e098032b8c)
选项 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:从客户端连接

请参阅 +integrate-character-embed,了解可处理 WebRTC 连接和渲染的 React SDK 组件。最简单的方法:

'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 个十六进制字符。请确保密钥处于有效状态。
  • 没有额度: 账户必须有预付额度才能开始通话。
  • 会话超时: 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

浏览器支持

浏览器最低版本
Chrome74+
Firefox78+
Safari14.1+
Edge79+

用户必须授予麦克风权限。如果启用了用户视频,还需要摄像头权限。

获取帮助

资源描述
开发者门户管理虚拟形象、查看日志、访问仪表板
SDK 仓库报告错误、查看示例、查看发行版本

报告问题时,请提供:浏览器/版本、SDK 版本(npm list @runwayml/avatars-react)、错误消息、会话 ID,以及重现步骤。

评论

支持 Markdown