Actualizar server.js

This commit is contained in:
2026-03-07 22:17:35 +00:00
parent 49ffa5e315
commit 0ae7fce650

View File

@@ -434,24 +434,29 @@ async function registrarMovimiento(serviceId, userId, action, details) {
async function procesarConIA(ownerId, mensajeCliente, datosExpediente) { async function procesarConIA(ownerId, mensajeCliente, datosExpediente) {
try { try {
const userQ = await pool.query("SELECT wa_settings, full_name FROM users WHERE id=$1", [ownerId]); // 1. Extraemos TODO: nombre, settings y horarios reales de la ruta
const settings = userQ.rows[0]?.wa_settings || {}; const userQ = await pool.query("SELECT wa_settings, full_name, portal_settings FROM users WHERE id=$1", [ownerId]);
const empresaNombre = userQ.rows[0]?.full_name || "nuestra empresa"; const userData = userQ.rows[0];
const settings = userData?.wa_settings || {};
const empresaNombre = userData?.full_name || "nuestra empresa";
// Si no hay horario configurado, usa un estándar lógico
const horarios = userData?.portal_settings || { m_start: "09:00", m_end: "14:00", a_start: "16:00", a_end: "19:00" };
if (!settings.wa_ai_enabled) return null; if (!settings.wa_ai_enabled) return null;
// 🕒 1. Sincronización de Fecha Real
const ahora = new Date(); const ahora = new Date();
const fechaHoyTexto = ahora.toLocaleDateString('es-ES', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }); const opciones = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };
const fechaHoyTexto = ahora.toLocaleDateString('es-ES', opciones);
// 🧠 2. Memoria de Conversación (Evitar saludos repetitivos) // 🧠 MEMORIA: Evita parecer tonto
const chatCheck = await pool.query(` const chatCheck = await pool.query(`
SELECT id FROM service_communications SELECT id FROM service_communications
WHERE scraped_id = $1 AND created_at > NOW() - INTERVAL '60 minutes' LIMIT 1 WHERE scraped_id = $1
AND created_at > NOW() - INTERVAL '60 minutes' LIMIT 1
`, [datosExpediente.dbId]); `, [datosExpediente.dbId]);
const yaSeHaPresentado = chatCheck.rowCount > 0; const yaSeHaPresentado = chatCheck.rowCount > 0;
// 📍 3. Inteligencia de Ruta (Buscar técnicos cerca) // 📍 LOGÍSTICA: Buscar técnicos cerca
const poblacion = datosExpediente.poblacion || ""; const poblacion = datosExpediente.poblacion || "";
let fechasSugeridas = ""; let fechasSugeridas = "";
@@ -459,10 +464,8 @@ async function procesarConIA(ownerId, mensajeCliente, datosExpediente) {
const rutasCercanas = await pool.query(` const rutasCercanas = await pool.query(`
SELECT raw_data->>'scheduled_date' as fecha SELECT raw_data->>'scheduled_date' as fecha
FROM scraped_services FROM scraped_services
WHERE owner_id = $1 WHERE owner_id = $1 AND raw_data->>'Población' ILIKE $2
AND raw_data->>'Población' ILIKE $2 AND raw_data->>'scheduled_date' > CURRENT_DATE::text AND id != $3
AND raw_data->>'scheduled_date' >= CURRENT_DATE::text
AND id != $3
GROUP BY fecha ORDER BY fecha ASC LIMIT 2 GROUP BY fecha ORDER BY fecha ASC LIMIT 2
`, [ownerId, poblacion, datosExpediente.dbId]); `, [ownerId, poblacion, datosExpediente.dbId]);
@@ -475,29 +478,32 @@ async function procesarConIA(ownerId, mensajeCliente, datosExpediente) {
} }
const promptSistema = ` const promptSistema = `
Eres el Asistente IA de "${empresaNombre}". Eres el Asistente Humano de "${empresaNombre}". Tienes que ser MUY natural, cercano y resolutivo. Nada de sonar robótico.
Hoy es ${fechaHoyTexto}. Estamos en el año 2026.
CONTEXTO Y HORARIOS:
- Hoy es: ${fechaHoyTexto}. Año 2026.
- HORARIO DE TRABAJO: Lunes a Viernes. Mañanas de ${horarios.m_start} a ${horarios.m_end}. Tardes de ${horarios.a_start} a ${horarios.a_end}.
- ⛔ LOS FINES DE SEMANA NO SE TRABAJA. Si el cliente pide un Sábado o Domingo, dile amablemente que descansamos el fin de semana y ofrécele un Viernes o Lunes dentro del horario.
DATOS EXPEDIENTE #${datosExpediente.ref}: DATOS EXPEDIENTE #${datosExpediente.ref}:
- Estado: ${datosExpediente.estado} - Estado: ${datosExpediente.estado}
- Población: ${poblacion} - Población: ${poblacion}
- Cita actual: ${datosExpediente.cita || 'Ninguna'}
LÓGICA DE SALUDO: LÓGICA DE SALUDO (MUY IMPORTANTE):
${!yaSeHaPresentado ${!yaSeHaPresentado
? `- Inicio de chat: Preséntate brevemente y menciona el expediente #${datosExpediente.ref}.` ? `- Es el inicio. Preséntate con empatía: "¡Hola! Soy el asistente de ${empresaNombre}. Te escribo sobre tu aviso #${datosExpediente.ref}..."`
: `- Conversación fluida: NO te presentes, NO digas hola, ve directo a la respuesta.` : `- ⛔ YA HABÉIS HABLADO RECIENTEMENTE. PROHIBIDO decir "Hola" o volver a presentarte. Ve DIRECTO a la respuesta como harías en un chat real con un amigo.`
} }
ESTRATEGIA DE RUTA (LOGÍSTICA): ESTRATEGIA DE RUTA:
${fechasSugeridas ${fechasSugeridas
? `- Tenemos otros técnicos en ${poblacion} el ${fechasSugeridas}. SUGIERE estas fechas prioritariamente para optimizar la ruta.` ? `- Casualmente tenemos técnicos yendo a ${poblacion} el ${fechasSugeridas}. Sugiere esas fechas amigablemente para aprovechar el viaje.`
: `- No hay rutas previas en ${poblacion}. Pide al cliente su preferencia de mañana o tarde.` : `- Pregúntale qué día de Lunes a Viernes le viene bien y si prefiere mañana o tarde.`
} }
REGLA DE CITAS: REGLA PARA GUARDAR LA CITA:
- Si el cliente propone algo, di que lo consultas y añade al final: [PROPUESTA:YYYY-MM-DD HH:mm] - Si el cliente confirma un día y hora válidos (L-V), dile que lo dejas anotado para que el técnico lo confirme y añade AL FINAL tu respuesta este código oculto: [PROPUESTA:YYYY-MM-DD HH:mm]
- Máximo 2 frases. Sé muy natural, no parezcas un robot. - Ejemplo: "Perfecto, te dejo anotado para el viernes a las 10:00. El técnico te confirmará en breve. [PROPUESTA:2026-03-13 10:00]"
`; `;
const completion = await openai.chat.completions.create({ const completion = await openai.chat.completions.create({
@@ -506,7 +512,7 @@ async function procesarConIA(ownerId, mensajeCliente, datosExpediente) {
{ role: "system", content: promptSistema }, { role: "system", content: promptSistema },
{ role: "user", content: mensajeCliente } { role: "user", content: mensajeCliente }
], ],
temperature: 0.4, // Más preciso, menos creativo temperature: 0.4, // Controlado para no divagar
}); });
return completion.choices[0].message.content; return completion.choices[0].message.content;