Vite (JavaScript)

Aprende a crear una aplicación web que permita conversaciones por voz con agentes de IA de ElevenLabs

Este tutorial te guiará para crear un cliente web que pueda interactuar con un agente de ElevenLabs. Aprenderás a implementar conversaciones por voz en tiempo real, para que usuarios puedan hablar con un agente de IA capaz de escuchar, comprender y responder de forma natural mediante síntesis de voz.

¿Quieres desarrollar con React/Next.js? Consulta nuestra guía de Next.js

Lo que necesitas

  1. Un agente de ElevenLabs creado siguiendo esta guía
  2. Tener npm instalado en tu sistema local
  3. Conocimientos básicos de JavaScript

Configuración del proyecto

1

Crea un directorio para el proyecto

Abre una terminal y crea un directorio nuevo para tu proyecto:

mkdir elevenlabs-conversational-ai
cd elevenlabs-conversational-ai
2

Inicializa npm e instala las dependencias

Inicializa un proyecto de npm e instala los paquetes necesarios:

npm init -y
npm install vite @elevenlabs/client
3

Configura la estructura básica del proyecto

Añade esto a tu package.json:

package.json
{
"scripts": {
...
"dev:frontend": "vite"
}
}

Crea la siguiente estructura de archivos:

elevenlabs-conversational-ai/
├── index.html
├── script.js
├── package-lock.json
├── package.json
└── node_modules

Implementa la interfaz de chat de voz

1

Crea la interfaz HTML

En index.html, configura una interfaz de usuario sencilla:

index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ElevenLabs Agents</title>
</head>
<body style="font-family: Arial, sans-serif; text-align: center; padding: 50px;">
<h1>ElevenLabs Agents</h1>
<div style="margin-bottom: 20px;">
<button id="startButton" style="padding: 10px 20px; margin: 5px;">Start Conversation</button>
<button id="stopButton" style="padding: 10px 20px; margin: 5px;" disabled>Stop Conversation</button>
</div>
<div style="font-size: 18px;">
<p>Status: <span id="connectionStatus">Disconnected</span></p>
<p>Agent is <span id="agentStatus">listening</span></p>
</div>
<script type="module" src="../images/script.js"></script>
</body>
</html>
2

Implementa la lógica de la conversación

En script.js, implementa la funcionalidad:

script.js
import { Conversation } from '@elevenlabs/client';
const startButton = document.getElementById('startButton');
const stopButton = document.getElementById('stopButton');
const connectionStatus = document.getElementById('connectionStatus');
const agentStatus = document.getElementById('agentStatus');
let conversation;
async function startConversation() {
try {
// Request microphone permission
await navigator.mediaDevices.getUserMedia({ audio: true });
// Start the conversation
conversation = await Conversation.startSession({
agentId: 'YOUR_AGENT_ID', // Replace with your agent ID
onConnect: () => {
connectionStatus.textContent = 'Connected';
startButton.disabled = true;
stopButton.disabled = false;
},
onDisconnect: () => {
connectionStatus.textContent = 'Disconnected';
startButton.disabled = false;
stopButton.disabled = true;
},
onError: (error) => {
console.error('Error:', error);
},
onModeChange: (mode) => {
agentStatus.textContent = mode.mode === 'speaking' ? 'speaking' : 'listening';
},
});
} catch (error) {
console.error('Failed to start conversation:', error);
}
}
async function stopConversation() {
if (conversation) {
await conversation.endSession();
conversation = null;
}
}
startButton.addEventListener('click', startConversation);
stopButton.addEventListener('click', stopConversation);
3

Inicia el servidor de frontend

npm run dev:frontend
Asegúrate de sustituir 'YOUR_AGENT_ID' por el ID real de tu agente de ElevenLabs.

Este paso de autenticación solo es necesario para agentes privados. Si usas un agente público, puedes omitir esta sección y usar directamente agentId en la llamada a startSession.

1

Crea variables de entorno

Crea un archivo .env en la raíz de tu proyecto:

.env
ELEVENLABS_API_KEY=your-api-key-here
AGENT_ID=your-agent-id-here

Asegúrate de añadir .env a tu archivo .gitignore para evitar confirmar accidentalmente credenciales confidenciales.

2

Configura el backend

  1. Instala dependencias adicionales:
npm install express cors dotenv
  1. Crea una carpeta nueva llamada backend:
elevenlabs-conversational-ai/
├── backend
...
3

Crea el servidor

backend/server.js
require("dotenv").config();
const express = require("express");
const cors = require("cors");
const app = express();
app.use(cors());
app.use(express.json());
const PORT = process.env.PORT || 3001;
app.get("/api/get-signed-url", async (req, res) => {
try {
const response = await fetch(
`https://api.elevenlabs.io/v1/convai/conversation/get-signed-url?agent_id=${process.env.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();
res.json({ signedUrl: data.signed_url });
} catch (error) {
console.error("Error:", error);
res.status(500).json({ error: "Failed to generate signed URL" });
}
});
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
4

Actualiza el código del cliente

Modifica tu script.js para obtener y usar la URL firmada:

script.js
// ... existing imports and variables ...
async function getSignedUrl() {
const response = await fetch('http://localhost:3001/api/get-signed-url');
if (!response.ok) {
throw new Error(`Failed to get signed url: ${response.statusText}`);
}
const { signedUrl } = await response.json();
return signedUrl;
}
async function startConversation() {
try {
await navigator.mediaDevices.getUserMedia({ audio: true });
const signedUrl = await getSignedUrl();
conversation = await Conversation.startSession({
signedUrl,
// agentId has been removed...
onConnect: () => {
connectionStatus.textContent = 'Connected';
startButton.disabled = true;
stopButton.disabled = false;
},
onDisconnect: () => {
connectionStatus.textContent = 'Disconnected';
startButton.disabled = false;
stopButton.disabled = true;
},
onError: (error) => {
console.error('Error:', error);
},
onModeChange: (mode) => {
agentStatus.textContent = mode.mode === 'speaking' ? 'speaking' : 'listening';
},
});
} catch (error) {
console.error('Failed to start conversation:', error);
}
}
// ... rest of the code ...

Las URL firmadas caducan tras un breve periodo. Sin embargo, las conversaciones iniciadas antes de que caduquen continuarán sin interrupciones. En un entorno de producción, implementa una gestión de errores adecuada y lógica de renovación de URL para iniciar conversaciones nuevas.

5

Actualiza el package.json

package.json
{
"scripts": {
...
"dev:backend": "node backend/server.js",
"dev": "npm run dev:frontend & npm run dev:backend"
}
}
6

Ejecuta la aplicación

Inicia la aplicación con:

npm run dev

Próximos pasos

Ahora que tienes una implementación básica, puedes:

  1. Añadir comentarios visuales para la actividad de voz
  2. Implementar gestión de errores y lógica de reintentos
  3. Añadir una vista del historial de chat
  4. Personalizar la interfaz de usuario para que encaje con tu marca

Para conocer funciones más avanzadas y opciones de personalización, consulta el paquete @elevenlabs/client.