mcpField
I
integrate-character-embed

integrate-character-embed

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

关于 integrate-character-embed

面向 React 项目的技能,介绍如何用 `@runwayml/avatars-react` 嵌入 Runway 实时虚拟形象通话,涵盖现成组件和自定义界面;项目需具备服务端会话端点。

主要功能

  1. 01现成的 `AvatarCall` 组件
  2. 02通过会话 Hook 自定义界面
  3. 03虚拟形象与用户视频组件
  4. 04麦克风控制和会话状态
  5. 05从服务端获取会话凭据

适用场景

  1. 01在 React 页面加入虚拟形象通话
  2. 02构建自定义通话界面
  3. 03显示用户摄像头画面
  4. 04处理通话错误和结束事件

安装

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

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

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

详细介绍

在 React 中嵌入虚拟形象(Avatars React SDK)

前置条件:

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

可选:

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

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

安装

npm install @runwayml/avatars-react

这是一个客户端软件包。服务端的 @runwayml/sdk 应已通过 +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 中的虚拟形象 UUID
connectUrlstring服务端会话端点(例如,/api/avatar/session)
onEnd() => void通话正常结束时调用
onError(error: Error) => void连接或运行时发生错误时调用

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

选项 B:完全自定义 — Hooks

如需完全控制 UI,请将 AvatarSession 与 Hooks 搭配使用。

组件和 Hooks
导出项类型说明
AvatarSession组件管理 WebRTC 会话的 Provider
AvatarVideo组件渲染虚拟形象的视频流
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): 完整的服务端会话创建代码,请参阅 +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