Files
sitemente/app/api/site-mente/voice/route.ts
T

101 lines
2.4 KiB
TypeScript

import { NextResponse } from "next/server";
import { runSiteMenteVoiceTurn } from "../../../../lib/ai/siteMenteAgent";
export const runtime = "nodejs";
// Vapi webhook payload types
interface VapiMessage {
type: string;
role?: string;
transcript?: string;
toolCallList?: Array<{
id: string;
function: {
name: string;
arguments: string;
};
}>;
}
interface VapiCall {
id: string;
}
interface VapiWebhookPayload {
message: VapiMessage;
call: VapiCall;
}
export async function POST(request: Request) {
try {
const body = (await request.json()) as VapiWebhookPayload;
const message = body.message;
// Handle tool calls from Vapi
if (message.toolCallList && message.toolCallList.length > 0) {
const toolCall = message.toolCallList[0];
const toolCallId = toolCall.id;
// Get the arguments from the tool call
let args = {};
try {
args = JSON.parse(toolCall.function.arguments || '{}');
} catch (e) {
// If arguments is a string, use it directly
args = { query: toolCall.function.arguments };
}
// Process the voice request
const transcript = args.query || '';
const response = await runSiteMenteVoiceTurn({
transcript: transcript,
});
// Return EXACT Vapi format with toolCallId
return NextResponse.json({
results: [
{
toolCallId: toolCallId,
result: response.reply,
},
],
});
}
// Handle regular transcripts
if (!message || message.type !== "transcript" || !message.transcript) {
return NextResponse.json({ results: [] });
}
const transcript = message.transcript;
const response = await runSiteMenteVoiceTurn({
transcript: transcript,
});
// Return in Vapi's expected format - but we need a toolCallId
// For transcripts without tool calls, we generate one
return NextResponse.json({
results: [
{
toolCallId: `call_${Date.now()}`,
result: response.reply,
},
],
});
} catch (error) {
console.error("[SiteMente][Vapi] Voice route failed", error);
return NextResponse.json(
{
results: [
{
toolCallId: `call_${Date.now()}`,
result: "Lo siento, tuve un problema. ¿Puedes repetir?"
}
]
},
{ status: 200 }
);
}
}