关于 integrate-character-embed
面向 React 项目的技能,介绍如何用 `@runwayml/avatars-react` 嵌入 Runway 实时虚拟形象通话,涵盖现成组件和自定义界面;项目需具备服务端会话端点。
主要功能
- 01现成的 `AvatarCall` 组件
- 02通过会话 Hook 自定义界面
- 03虚拟形象与用户视频组件
- 04麦克风控制和会话状态
- 05从服务端获取会话凭据
适用场景
- 01在 React 页面加入虚拟形象通话
- 02构建自定义通话界面
- 03显示用户摄像头画面
- 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 属性
| 属性 | 类型 | 说明 |
|---|---|---|
avatarId | string | Developer Portal 或 API 中的虚拟形象 UUID |
connectUrl | string | 服务端会话端点(例如,/api/avatar/session) |
onEnd | () => void | 通话正常结束时调用 |
onError | (error: Error) => void | 连接或运行时发生错误时调用 |
对于在 Developer Portal 中创建的自定义虚拟形象,请将虚拟形象 UUID 用作 avatarId。
选项 B:完全自定义 — Hooks
如需完全控制 UI,请将 AvatarSession 与 Hooks 搭配使用。
组件和 Hooks
| 导出项 | 类型 | 说明 |
|---|---|---|
AvatarSession | 组件 | 管理 WebRTC 会话的 Provider |
AvatarVideo | 组件 | 渲染虚拟形象的视频流 |
UserVideo | 组件 | 渲染用户的摄像头画面 |
useAvatarSession | Hook | 访问会话状态:state、sessionId、error、end() |
useLocalMedia | Hook | 控制用户的媒体: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>
);
}
浏览器支持
| 浏览器 | 最低版本 |
|---|---|
| Chrome | 74+ |
| Firefox | 78+ |
| Safari | 14.1+ |
| Edge | 79+ |
出现提示时,用户必须授予麦克风权限。启用用户视频时,还需要摄像头权限。
提示
- 始终导入样式:使用
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