跳到导航

Next.JS

了解如何创建支持与 ElevenLabs AI 智能体进行语音对话的 Web 应用

本教程将指导你创建一个可与 ElevenLabs 智能体交互的 Web 客户端。你将学习如何实现实时语音对话,让用户能够与可聆听、理解并通过语音合成自然回应的 AI 智能体交谈。

所需准备

  1. 按照本指南创建的 ElevenLabs 智能体
  2. 本地系统已安装 npm。
  3. 本教程使用 Typescript,但你也可以使用 Javascript。

需要完整示例?查看我们的 GitHub 上的 Next.js 演示 。

设置

1

创建新的 Next.js 项目

打开终端窗口并运行以下命令:

npm create next-app my-conversational-agent

系统会询问一些有关项目构建方式的问题。本教程将采用默认建议。

2

进入项目目录

cd my-conversational-agent
3

安装 ElevenLabs 依赖项

npm install @elevenlabs/react
4

测试设置

运行以下命令启动开发服务器,然后在浏览器中打开提供的 URL:

npm run dev

实现 ElevenLabs 智能体

1

创建对话组件

创建新文件 app/components/conversation.tsx:

app/components/conversation.tsx
'use client';
import { useConversation } from '@elevenlabs/react';
import { useCallback } from 'react';
export function Conversation() {
const conversation = useConversation({
onConnect: () => console.log('Connected'),
onDisconnect: () => console.log('Disconnected'),
onMessage: (message) => console.log('Message:', message),
onError: (error) => console.error('Error:', error),
});
const startConversation = useCallback(async () => {
try {
// Request microphone permission
await navigator.mediaDevices.getUserMedia({ audio: true });
// Start the conversation with your agent
await conversation.startSession({
agentId: 'YOUR_AGENT_ID', // Replace with your agent ID
userId: 'YOUR_CUSTOMER_USER_ID', // Optional field for tracking your end user IDs
});
} catch (error) {
console.error('Failed to start conversation:', error);
}
}, [conversation]);
const stopConversation = useCallback(async () => {
await conversation.endSession();
}, [conversation]);
return (
<div className="flex flex-col items-center gap-4">
<div className="flex gap-2">
<button
onClick={startConversation}
disabled={conversation.status === 'connected'}
className="px-4 py-2 bg-blue-500 text-white rounded disabled:bg-gray-300"
>
Start Conversation
</button>
<button
onClick={stopConversation}
disabled={conversation.status !== 'connected'}
className="px-4 py-2 bg-red-500 text-white rounded disabled:bg-gray-300"
>
Stop Conversation
</button>
</div>
<div className="flex flex-col items-center">
<p>Status: {conversation.status}</p>
<p>Agent is {conversation.isSpeaking ? 'speaking' : 'listening'}</p>
</div>
</div>
);
}
2

更新主页面

将 app/page.tsx 的内容替换为:

app/page.tsx
'use client';
import { ConversationProvider } from '@elevenlabs/react';
import { Conversation } from './components/conversation';
export default function Home() {
return (
<ConversationProvider>
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm">
<h1 className="text-4xl font-bold mb-8 text-center">
ElevenLabs Agents
</h1>
<Conversation />
</div>
</main>
</ConversationProvider>
);
}

此身份验证步骤仅适用于私有智能体。如果使用公开智能体,可以跳过本节,直接在 startSession 调用中使用 agentId。

如果使用需要身份验证的私有智能体,需要从服务器生成 签名 URL。本节将说明如何进行设置。

所需准备

  1. ElevenLabs 账户和 API 密钥。在此处注册。
1

创建环境变量

在项目根目录创建 .env.local 文件:

.env.local
ELEVENLABS_API_KEY=your-api-key-here
NEXT_PUBLIC_AGENT_ID=your-agent-id-here
  1. 请务必将 .env.local 添加到 .gitignore 文件,防止意外将敏感凭据提交到版本控制系统。
  2. 切勿在客户端代码中暴露 API 密钥。请始终将其安全地保存在服务器上。
2

创建 API 路由

创建新文件 app/api/get-signed-url/route.ts:

app/api/get-signed-url/route.ts
import { NextResponse } from 'next/server';
export async function GET() {
try {
const response = await fetch(
`https://api.elevenlabs.io/v1/convai/conversation/get-signed-url?agent_id=${process.env.NEXT_PUBLIC_AGENT_ID}`,
{
headers: {
'xi-api-key': process.env.ELEVENLABS_API_KEY!,
},
}
);
if (!response.ok) {
throw new Error('Failed to get signed URL');
}
const data = await response.json();
return NextResponse.json({ signedUrl: data.signed_url });
} catch (error) {
return NextResponse.json(
{ error: 'Failed to generate signed URL' },
{ status: 500 }
);
}
}
3

更新 Conversation 组件

修改 conversation.tsx,以获取并使用签名 URL:

app/components/conversation.tsx
// ... existing imports ...
export function Conversation() {
// ... existing conversation setup ...
const getSignedUrl = async (): Promise<string> => {
const response = await fetch("/api/get-signed-url");
if (!response.ok) {
throw new Error(`Failed to get signed url: ${response.statusText}`);
}
const { signedUrl } = await response.json();
return signedUrl;
};
const startConversation = useCallback(async () => {
try {
// Request microphone permission
await navigator.mediaDevices.getUserMedia({ audio: true });
const signedUrl = await getSignedUrl();
// Start the conversation with your signed url
await conversation.startSession({
signedUrl,
});
} catch (error) {
console.error('Failed to start conversation:', error);
}
}, [conversation]);
// ... rest of the component ...
}

签名 URL 会在短时间后过期。不过,在过期前发起的对话不会中断。在生产环境中,应针对发起新对话实现适当的错误处理和 URL 刷新逻辑。

后续步骤

现在已有基本实现,你可以:

  1. 添加语音活动的视觉反馈
  2. 实现错误处理和重试逻辑
  3. 添加聊天记录显示
  4. 自定义 UI 以匹配品牌

如需更多高级功能和自定义选项,请查看 @elevenlabs/react 软件包。