Next.js 로 시작하기
Next.js 애플리케이션에 vox.ai 에이전트와 음성 챗 기능을 통합하여 AI 에이전트와 자연스러운 대화를 가능하게 하는 방법을 소개합니다.
필요한 것
- vox.ai 대시보드에서 생성된 vox.ai 에이전트
- vox.ai 대시보드에서 발급받은 에이전트 ID와 API 키
- Next.js 프로젝트 (13.0.0 이상 권장)
- React 훅에 대한 기본 지식
기본 사용법 (Next.js)
Next.js 프로젝트에서 vox.ai를 사용하는 방법을 단계별로 알아보겠습니다.
1. 프로젝트 설정
새 Next.js 프로젝트를 생성하거나 기존 프로젝트를 사용할 수 있습니다:
# 새 프로젝트 생성
npx create-next-app my-vox-ai-app
cd my-vox-ai-app
# vox.ai SDK 설치
npm install @vox-ai/react
# 또는
yarn add @vox-ai/react
# 또는
pnpm install @vox-ai/react
2. 대화 컴포넌트 생성
app/components
디렉토리를 생성하고 VoxConversation.tsx
파일을 만듭니다:
"use client";
import { useVoxAI } from "@vox-ai/react";
import { useCallback } from "react";
export function VoxConversation() {
// vox.ai 훅 초기화
const {
connect,
disconnect,
state,
messages,
send,
audioWaveform,
toggleMic,
setVolume,
} = useVoxAI({
onConnect: () => console.log("연결됨"),
onDisconnect: () => console.log("연결 해제됨"),
onMessage: (message) => console.log("메시지:", message),
onError: (error) => console.error("오류:", error),
});
// 대화 시작 함수
const startConversation = useCallback(async () => {
try {
// 마이크 권한 요청
await navigator.mediaDevices.getUserMedia({ audio: true });
// vox.ai 에이전트에 연결
await connect({
agentId: "YOUR_AGENT_ID", // 에이전트 ID로 교체하세요
apiKey: "YOUR_API_KEY", // API 키로 교체하세요
dynamicVariables: {
// 대화 커스터마이징을 위한 동적 변수
userName: "홍길동",
context: "고객-지원",
},
metadata: {
// 통화에 대한 메타데이터
callerId: "customer-123",
departmentId: "support",
},
});
} catch (error) {
console.error("대화 시작 실패:", error);
}
}, [connect]);
// 대화 종료 함수
const stopConversation = useCallback(async () => {
await disconnect();
}, [disconnect]);
// UI 렌더링
return (
<div className="flex flex-col items-center gap-4">
{/* 컨트롤 버튼 */}
<div className="flex gap-2">
<button
onClick={startConversation}
disabled={state !== "disconnected"}
className="px-4 py-2 bg-blue-500 text-white rounded disabled:bg-gray-300"
>
대화 시작
</button>
<button
onClick={stopConversation}
disabled={state === "disconnected"}
className="px-4 py-2 bg-red-500 text-white rounded disabled:bg-gray-300"
>
대화 종료
</button>
{/* 상태 표시 */}
<div className="flex flex-col items-center">
<p>상태: {state}</p>
<p>에이전트가 {state === "speaking" ? "말하는 중" : "듣는 중"}</p>
</div>
{/* 대화 기록 */}
<div className="w-full max-w-md mt-4">
<h2 className="text-xl font-bold mb-2">대화 내용</h2>
<ul className="rounded p-4 max-h-60 overflow-y-auto">
{messages.map((msg, index) => (
<li key={msg.id || index} className="mb-2 p-2 rounded">
<strong>{msg.name === "agent" ? "에이전트" : "사용자"}:</strong>{" "}
{msg.message}
</li>
))}
</ul>
</div>
</div>
);
}
3. 메인 페이지에 컴포넌트 추가
app/page.tsx
파일을 다음과 같이 수정합니다:
import { VoxConversation } from "./components/VoxConversation";
export default function Home() {
return (
<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">
vox.ai 음성 대화
</h1>
<VoxConversation />
</div>
</main>
);
}
4. 개발 서버 실행
다음 명령어로 개발 서버를 실행하고 브라우저에서 확인합니다:
고급 사용법
useVoxAI 훅
useVoxAI
훅은 다음과 같은 기능과 값을 제공합니다:
메서드
- connect: Vox.ai 서비스에 연결을 설정합니다.
- disconnect: 음성 AI 세션을 수동으로 종료합니다.
- send: 텍스트 메시지나 DTMF 톤을 에이전트에 전송합니다.
- audioWaveform: 에이전트나 사용자의 오디오 웨이브폼 데이터를 반환합니다.
- toggleMic: 사용자의 마이크를 활성화/비활성화합니다.
- setVolume: 에이전트의 볼륨을 설정합니다(0-1 범위).
상태 및 데이터
- state: 현재 통화 상태를 나타냅니다(“disconnected”, “connecting”, “initializing”, “listening”, “thinking”, “speaking”).
- messages: 대화 기록을 포함합니다.
메시지 구조
각 메시지는 다음 구조를 가집니다:
type VoxMessage = {
id?: string;
name: "agent" | "user" | "tool";
message?: string;
timestamp: number;
isFinal?: boolean;
tool?: FunctionToolsExecuted; // 에이전트가 실행한 함수 도구
};
동적 변수 및 메타데이터 추가하기
대화를 커스터마이징하거나 통화 데이터를 추적하기 위해 dynamicVariables
와 metadata
를 전달할 수 있습니다:
connect({
agentId: "your-agent-id", // 에이전트 ID 입력
apiKey: "your-api-key", // API 키 입력
dynamicVariables: {
userName: "홍길동",
context: "고객-지원",
// 기타 관련 정보 추가
},
metadata: {
userId: "1234567890",
// 기타 식별자 추가
},
});
dynamicVariables
와 metadata
는 통화 기록에서도 확인할 수 있습니다.
메시지 전송하기
텍스트 메시지 또는 DTMF 톤을 에이전트에게 보낼 수 있습니다:
// 텍스트 메시지 전송
send({ message: "안녕하세요, 도움이 필요합니다." });
// DTMF 톤 전송 (0-9, *, #)
send({ digit: 1 });
대화 상태 모니터링
훅에서 제공하는 state
값은 대화 상태에 대한 실시간 정보를 제공합니다:
disconnected
- vox.ai에 연결되지 않음
connecting
- 연결 설정 중
initializing
- 연결 설정됨, 음성 인터페이스 초기화 중
listening
- 사용자 입력 대기 중
thinking
- 사용자 입력 처리 중
speaking
- AI 에이전트가 말하는 중
이 상태를 사용하여 사용자에게 시각적 피드백을 제공할 수 있습니다:
function getStatusIndicator(state) {
switch (state) {
case "listening":
return <div className="status-indicator listening">듣는 중...</div>;
case "thinking":
return <div className="status-indicator thinking">생각하는 중...</div>;
case "speaking":
return <div className="status-indicator speaking">말하는 중...</div>;
default:
return null;
}
}
// 렌더 함수 내에서
{
getStatusIndicator(state);
}
오디오 웨이브폼 시각화
audioWaveform
메서드를 사용하여 오디오 활동을 시각화할 수 있습니다:
import React, { useState, useEffect } from "react";
import { useVoxAI } from "@vox-ai/react";
function WaveformVisualizer() {
const { audioWaveform, state } = useVoxAI();
const [waveformData, setWaveformData] = useState([]);
// 웨이브폼 데이터를 정기적으로 업데이트
useEffect(() => {
if (state === "disconnected") return;
const intervalId = setInterval(() => {
// 에이전트 오디오 웨이브폼 데이터 가져오기
const data = audioWaveform({
speaker: "agent", // "agent" 또는 "user"
barCount: 30, // 반환할 웨이브폼 바의 수
updateInterval: 50, // 업데이트 간격 (ms)
});
setWaveformData(data);
}, 50);
return () => clearInterval(intervalId);
}, [audioWaveform, state]);
return (
<div className="waveform-container">
{waveformData.map((value, index) => (
<div
key={index}
className="waveform-bar"
style={{
height: `${value * 100}%`,
width: "10px",
backgroundColor: "#3498db",
margin: "0 2px",
}}
/>
))}
</div>
);
}
마이크 및 볼륨 제어
toggleMic
와 setVolume
메서드를 사용하여 오디오 입출력을 제어할 수 있습니다:
// 마이크 켜기/끄기
toggleMic(true); // 마이크 활성화
toggleMic(false); // 마이크 비활성화
// 에이전트 볼륨 조절 (0: 음소거, 1: 최대 볼륨)
setVolume(0.5); // 볼륨 50%로 설정
메시지 처리하기
messages
배열은 대화 기록을 포함합니다. 각 메시지는 다음 구조를 가집니다. onMessage
콜백을 사용하여 새 메시지가 수신될 때 작업을 수행할 수 있습니다:
const { connect, disconnect, state, messages } = useVoxAI({
onMessage: (message) => {
// 에이전트의 최종 메시지만 처리
if (message.name === "agent" && message.isFinal) {
// 에이전트 응답에 따른 작업 수행
console.log("에이전트 응답:", message.message);
}
},
});
문제 해결
마이크 접근 문제
사용자가 마이크 접근에 문제가 있는 경우:
- 사이트가 HTTPS로 제공되는지 확인 (마이크 접근에 필요)
- 브라우저 권한 설정 확인
- 권한 거부에 대한 적절한 오류 처리 구현:
try {
await navigator.mediaDevices.getUserMedia({ audio: true });
} catch (error) {
if (error.name === "NotAllowedError") {
alert("음성 대화를 위해 마이크 접근 권한이 필요합니다");
} else {
console.error("마이크 오류:", error);
}
}