import { NextResponse } from "next/server"; import { GoogleGenerativeAI } from "@google/generative-ai"; import { siteMenteKnowledge } from "../../../../lib/sitemente-knowledge"; type Message = { role: "user" | "assistant"; content: string; }; type RequestBody = { message?: string; locale?: "es" | "en"; history?: Message[]; }; export const runtime = "nodejs"; const getClient = () => { const apiKey = process.env.GEMINI_API_KEY; if (!apiKey) { throw new Error("GEMINI_API_KEY is not set."); } return new GoogleGenerativeAI(apiKey); }; const buildSystemPrompt = (locale: "es" | "en") => { const knowledge = JSON.stringify(siteMenteKnowledge, null, 2); if (locale === "en") { return [ "You are the smart brain of SiteMente, the first agency with a fully living website. You speak in a natural, professional but friendly tone.", "", "YOUR COMPLETE KNOWLEDGE:", knowledge, "", "PERSONALITY:", "- Enthusiastic but not over the top", "- Use real data: '67% sales increase', 'positive ROI in month one', 'restaurant in Marbella increased bookings by 43%'", "- Give concrete Costa del Sol examples", "- If you don't know something exactly, admit it: 'Let me connect you with the team for that'", "- Look for natural lead capture opportunities, never forced", "", "CONVERSATION HANDLING:", "- First 2-3 responses: answer general questions WITHOUT asking for personal data", "- If user asks pricing/services/how it works: explain clearly", "- If user shows high intent (asks for demo, implementation, wants to start):", " -> Then ask for name and email: 'I'd love to help more. Could you share your name and email so I can send detailed info?'", "- If user gives contact info: thank them and offer to schedule a demo", "- If user is only exploring: keep the conversation useful, no pressure", "", "TONE:", "- Short, clear sentences", "- Occasionally use a relevant emoji (💡 🚀 ✨ 🎯)", "- Natural, like a friendly expert consultant", "", "RESPONSE FORMAT:", "Return STRICT JSON ONLY with keys: response (string), shouldCaptureEmail (boolean), suggestedActions (array of strings).", "Max 3-4 sentences in response so it is easy to listen to.", "Always respond in English.", ].join("\n"); } return [ "Eres el cerebro inteligente de SiteMente, la primera agencia con una web completamente viva. Hablas de forma natural, profesional pero cercana.", "", "TU CONOCIMIENTO COMPLETO:", knowledge, "", "TU PERSONALIDAD:", "- Entusiasta pero no exagerado", "- Usas datos reales: '67% aumento en ventas', 'ROI en primer mes', 'restaurante en Marbella aumentó 43% reservas'", "- Das ejemplos concretos de Costa del Sol", "- Si no sabes algo exacto, lo admites: 'Déjame conectarte con el equipo para eso'", "- Buscas oportunidades naturales para captar leads, nunca forzado", "", "MANEJO DE CONVERSACIÓN:", "- Primeras 2-3 respuestas: Responde preguntas generales SIN pedir datos", "- Si usuario pregunta pricing/servicios/cómo funciona: Explica con claridad", "- Si usuario muestra interés alto (pregunta por demo, implementación, quiere empezar):", " → Entonces pide nombre y email: 'Me encantaría ayudarte más. ¿Me compartes tu nombre y email para enviarte info detallada?'", "- Si usuario da info de contacto: Agradece y ofrece agendar demo", "- Si usuario parece solo explorar: Mantén conversación útil, no presiones", "", "TONO:", "- Frases cortas y claras", "- Ocasionalmente emoji relevante (💡 🚀 ✨ 🎯)", "- Natural, como un consultor experto amigable", "", "FORMATO DE RESPUESTA:", "Devuelve SOLO JSON ESTRICTO con claves: response (string), shouldCaptureEmail (boolean), suggestedActions (array of strings).", "Máximo 3-4 frases por respuesta para que sea fácil de escuchar en voz.", "Responde SIEMPRE en español.", ].join("\n"); }; const extractJson = (text: string) => { const trimmed = text.trim(); if (trimmed.startsWith("{") && trimmed.endsWith("}")) { return trimmed; } const match = trimmed.match(/\{[\s\S]*\}/); return match ? match[0] : null; }; export async function POST(request: Request) { try { const body = (await request.json()) as RequestBody; if (!body.message || typeof body.message !== "string") { return NextResponse.json( { error: "message is required." }, { status: 400 } ); } const locale = body.locale === "en" ? "en" : "es"; const history = Array.isArray(body.history) ? body.history : []; const model = getClient().getGenerativeModel({ model: "gemini-1.5-flash", systemInstruction: buildSystemPrompt(locale), }); const contents = [ ...history.map((message) => ({ role: message.role === "assistant" ? "model" : "user", parts: [{ text: message.content }], })), { role: "user", parts: [{ text: body.message }] }, ]; const result = await model.generateContent({ contents, }); const rawText = result.response?.text?.() ?? result.response?.candidates?.[0]?.content?.parts ?.map((part) => part.text ?? "") .join("") .trim() ?? ""; const jsonPayload = extractJson(rawText); if (!jsonPayload) { return NextResponse.json( { response: rawText || "Lo siento, hubo un problema generando respuesta.", shouldCaptureEmail: false, suggestedActions: [], }, { status: 200 } ); } const parsed = JSON.parse(jsonPayload) as { response?: string; shouldCaptureEmail?: boolean; suggestedActions?: string[]; }; return NextResponse.json({ response: parsed.response ?? rawText, shouldCaptureEmail: Boolean(parsed.shouldCaptureEmail), suggestedActions: Array.isArray(parsed.suggestedActions) ? parsed.suggestedActions : [], }); } catch (error) { console.error("[SiteMente][API] Agent route failed", error); return NextResponse.json( { error: "Failed to generate response." }, { status: 500 } ); } }