mcpField
R
rw-integrate-character-embed

rw-integrate-character-embed

github.com/runwayml开发74211 次安装2 天前更新
代码仓库

关于 rw-integrate-character-embed

面向 React 应用的 Runway 虚拟形象视频通话集成技能,使用 `@runwayml/avatars-react`。提供开箱即用的通话组件和基于 Hook 的自定义界面方案,前提是已创建虚拟形象并配置服务端会话端点。

主要功能

  1. 01在 React 中嵌入虚拟形象视频通话
  2. 02使用 AvatarCall 预置组件
  3. 03通过会话 Hook 构建自定义界面
  4. 04显示虚拟形象和用户视频
  5. 05控制麦克风并查看会话状态

适用场景

  1. 01在 React 页面添加虚拟形象通话
  2. 02创建自定义通话界面
  3. 03按条件显示或隐藏通话

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/runwayml/skills --skill rw-integrate-character-embed

安装后在 Claude Code 中输入/rw-integrate-character-embed确认已加载。

详细介绍

在 React 中嵌入角色(Avatars React SDK)

前置条件:

  • +rw-check-compatibility — 项目必须具备服务端能力(绝不能将 API 密钥暴露给客户端)
  • +rw-fetch-api-reference — 集成前,请从 https://docs.dev.runwayml.com/api/ 加载最新的 API 参考
  • +rw-integrate-characters — 必须已创建角色(Avatar),并且会话端点已存在
  • 项目必须使用 React(Next.js、Vite+React、Remix 等)

可选:

  • +rw-integrate-documents — 嵌入前添加知识库

使用 @runwayml/avatars-react SDK,在 React 应用中嵌入实时 Avatar 视频通话。

安装

npm install @runwayml/avatars-react

这是一个客户端软件包。服务端的 @runwayml/sdk 应已通过 +rw-integrate-characters 安装。

选项 A:简单方案 — AvatarCall 组件

嵌入角色最快捷的方式。它会自动处理 WebRTC 连接并呈现默认 UI。

'use client';

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

export default function CharacterPage() {
  return (
    <AvatarCall
      avatarId="your-avatar-id-here"
      connectUrl="/api/avatar/session"
      onEnd={() => console.log('Call ended')}
      onError={(error) => console.error('Error:', error)}
    />
  );
}
AvatarCall 属性
属性类型说明
avatarIdstringDeveloper Portal 或 API 中的 Avatar UUID
connectUrlstring服务端会话端点(例如 /api/avatar/session)
onEnd() => void通话正常结束时调用
onError(error: Error) => void连接或运行时发生错误时调用

对于在 Developer Portal 中创建的自定义 Avatar,请将 Avatar UUID 用作 avatarId。

选项 B:完全自定义 — Hooks

如需完全控制 UI,请使用带 Hooks 的 AvatarSession。

组件与 Hooks
导出项类型说明
AvatarSession组件管理 WebRTC 会话的 Provider
AvatarVideo组件呈现 Avatar 的视频流
UserVideo组件呈现用户的摄像头画面
useAvatarSessionHook访问会话状态:state、sessionId、error、end()
useLocalMediaHook控制用户的媒体:isMicEnabled、toggleMic()
自定义 UI 示例
'use client';

import {
  AvatarSession,
  AvatarVideo,
  UserVideo,
  useAvatarSession,
  useLocalMedia,
} from '@runwayml/avatars-react';
import type { SessionCredentials } from '@runwayml/avatars-react';

function CallUI() {
  const { state, end } = useAvatarSession();
  const { isMicEnabled, toggleMic } = useLocalMedia();

  return (
    <div className="relative w-full h-screen">
      {/* Avatar video takes full screen */}
      <AvatarVideo className="w-full h-full object-cover" />

      {/* User's camera in a small overlay */}
      <UserVideo className="absolute bottom-4 right-4 w-48 rounded-lg" />

      {/* Controls */}
      <div className="absolute bottom-4 left-4 flex gap-2">
        <button onClick={toggleMic}>
          {isMicEnabled ? 'Mute' : 'Unmute'}
        </button>
        <button onClick={end}>End Call</button>
      </div>

      {/* Connection state */}
      {state === 'connecting' && (
        <div className="absolute inset-0 flex items-center justify-center bg-black/50">
          Connecting...
        </div>
      )}
    </div>
  );
}

export function CustomAvatar({ credentials }: { credentials: SessionCredentials }) {
  return (
    <AvatarSession credentials={credentials} audio video>
      <CallUI />
    </AvatarSession>
  );
}
为自定义 UI 获取凭据

使用 Hooks 方案时,需要从服务器端点获取凭据,并将其传递给 AvatarSession:

'use client';

import { useState, useCallback } from 'react';
import type { SessionCredentials } from '@runwayml/avatars-react';
import { CustomAvatar } from './CustomAvatar';

export default function CharacterPage() {
  const [credentials, setCredentials] = useState<SessionCredentials | null>(null);
  const [loading, setLoading] = useState(false);

  const startCall = useCallback(async () => {
    setLoading(true);
    try {
      const res = await fetch('/api/avatar/session', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ avatarId: 'your-avatar-id-here' }),
      });
      const data = await res.json();
      setCredentials(data);
    } catch (error) {
      console.error('Failed to connect:', error);
    } finally {
      setLoading(false);
    }
  }, []);

  if (credentials) {
    return <CustomAvatar credentials={credentials} />;
  }

  return (
    <button onClick={startCall} disabled={loading}>
      {loading ? 'Connecting...' : 'Start Conversation'}
    </button>
  );
}

集成模式

Next.js App Router(完整示例)

服务端路由(app/api/avatar/session/route.ts): 完整的服务端会话创建代码请参阅 +rw-integrate-characters。

客户端页面(app/character/page.tsx):

'use client';

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

const AVATAR_ID = process.env.NEXT_PUBLIC_AVATAR_ID || 'your-avatar-id';

export default function CharacterPage() {
  return (
    <div className="flex items-center justify-center min-h-screen">
      <AvatarCall
        avatarId={AVATAR_ID}
        connectUrl="/api/avatar/session"
        onEnd={() => window.location.reload()}
        onError={(error) => {
          console.error('Avatar error:', error);
          alert('Connection failed. Please try again.');
        }}
      />
    </div>
  );
}
条件渲染(显示/隐藏)
'use client';

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

export default function SupportPage() {
  const [showAvatar, setShowAvatar] = useState(false);

  return (
    <div>
      <h1>Customer Support</h1>

      {!showAvatar ? (
        <button onClick={() => setShowAvatar(true)}>
          Talk to an Agent
        </button>
      ) : (
        <AvatarCall
          avatarId="support-agent-id"
          connectUrl="/api/avatar/session"
          onEnd={() => setShowAvatar(false)}
          onError={(error) => {
            console.error(error);
            setShowAvatar(false);
          }}
        />
      )}
    </div>
  );
}

错误处理

详细错误日志
<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 DebugPanel() {
  const { state, sessionId, error } = useAvatarSession();

  return (
    <pre style={{ fontSize: 12, position: 'fixed', top: 0, right: 0 }}>
      {JSON.stringify({ state, sessionId, error: error?.message }, null, 2)}
    </pre>
  );
}

浏览器支持

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

用户必须在提示时授予麦克风权限。启用用户视频时,还需要摄像头权限。

提示

  • 务必导入样式:使用 AvatarCall 时,请导入 import '@runwayml/avatars-react/styles.css'
  • Next.js App Router 中,所有使用 React SDK 的组件都必须添加 'use client' 指令
  • 会话最长持续时间为 5 分钟——处理 onEnd 回调,以显示重新连接选项
  • 凭据只能使用一次——如果连接失败,请获取新凭据(创建新会话)
  • 完整 SDK 源码、示例和问题跟踪请参阅:github.com/runwayml/avatars-sdk-react

评论

支持 Markdown