From aef383d7e566319828f3adb59274aa2225adb3ea Mon Sep 17 00:00:00 2001 From: marsalva Date: Sat, 7 Mar 2026 23:32:58 +0000 Subject: [PATCH] Actualizar server.js --- server.js | 57 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/server.js b/server.js index 7ad025a..b812ef9 100644 --- a/server.js +++ b/server.js @@ -460,7 +460,7 @@ async function procesarConIA(ownerId, mensajeCliente, datosExpediente) { const esPrimerMensaje = historialChat.length === 0; - // 🗓️ LECTURA DE AGENDA ANTI-SOLAPAMIENTOS (NUEVO) + // 🗓️ LECTURA DE AGENDA ANTI-SOLAPAMIENTOS let agendaOcupadaTexto = "El técnico tiene la agenda libre. Puedes sugerir cualquier hora dentro del horario laboral."; if (datosExpediente.worker_id) { const agendaQ = await pool.query(` @@ -489,40 +489,42 @@ async function procesarConIA(ownerId, mensajeCliente, datosExpediente) { } } + // 🚦 ESTADO PENDIENTE + const hayCitaPendiente = datosExpediente.appointment_status === 'pending' && datosExpediente.cita_pendiente_fecha; + const textoCitaPendiente = hayCitaPendiente + ? `SÍ. El cliente solicitó cita para el ${datosExpediente.cita_pendiente_fecha} a las ${datosExpediente.cita_pendiente_hora || ''}. Está PENDIENTE de que el técnico la apruebe.` + : `NO.`; + const promptSistema = ` Eres el asistente humano de "${empresaNombre}". Hablas de tú, de forma muy natural, corta y directa por WhatsApp. - CONTEXTO DE TRABAJO: - - Hoy es: ${fechaHoyTexto}. (Año 2026). + --- CONTEXTO Y HORARIOS --- + - Hoy es: ${fechaHoyTexto}. - Horario L-V: Mañanas (${horarios.m_start}-${horarios.m_end}) y Tardes (${horarios.a_start}-${horarios.a_end}). - - ⛔ FIN DE SEMANA CERRADO. Ofrece solo de lunes a viernes. + - ⛔ FIN DE SEMANA CERRADO. Ofrece solo de Lunes a Viernes. - DATOS DEL CLIENTE (Aviso #${datosExpediente.ref}): + --- DATOS DEL AVISO #${datosExpediente.ref} --- - Estado: ${datosExpediente.estado} - Población: ${datosExpediente.poblacion} - - Urgencia: ${datosExpediente.is_urgent ? 'SÍ' : 'No'} - - Cita actual: ${datosExpediente.cita || 'Ninguna'} + - Urgencia: ${datosExpediente.is_urgent ? 'SÍ (Prioridad)' : 'No'} + - Cita Confirmada: ${datosExpediente.cita || 'Ninguna'} + - Cita Solicitada PENDIENTE: ${textoCitaPendiente} - ⚠️ CALENDARIO DEL TÉCNICO ASIGNADO (CRÍTICO): + --- ⚠️ CALENDARIO DEL TÉCNICO Y RUTAS --- ${agendaOcupadaTexto} - REGLA DE CALENDARIO: NUNCA sugieras ni aceptes una hora que ya esté ocupada en la lista anterior. Deja un margen de al menos 1 hora entre citas. Si el cliente pide una hora ocupada, dile que está cogida y ofrece una alternativa libre. + - REGLA 1 (ANTI-SOLAPAMIENTO): NUNCA sugieras ni aceptes una hora que ya esté ocupada en la lista anterior. Deja margen de al menos 1 hora entre citas. + - REGLA 2 (RUTAS): El cliente actual está en ${datosExpediente.poblacion}. Si el técnico ya va a ${datosExpediente.poblacion} un día concreto, PRIORIZA ofrecerle ese mismo día (en una hora libre) para aprovechar el viaje. - INSTRUCCIONES DE ACTUACIÓN: - 1. SI ES URGENCIA: No agendes. Di que el técnico contactará urgente. - 2. PARA AGENDAR: - - Si no hay fecha: Sugiere tú una hora libre basándote en su calendario. - - Si el cliente ACEPTA una hora libre, CIERRA LA CITA confirmándolo y añade OBLIGATORIAMENTE al final el código [PROPUESTA:YYYY-MM-DD HH:mm]. - 3. NUNCA TE PRESENTES si ya estáis conversando. Ve al grano. - ${esPrimerMensaje ? '4. Como es el primer mensaje, preséntate diciendo de qué empresa eres.' : ''} - 5. Sé breve (máximo 1 o 2 frases). - 6. Cuando se confirma la cita, informar al cliente que se le va a informar al operario asignado de la cita elegida, y cuando la vea se le confirmara. - - ⚠️ CALENDARIO DEL TÉCNICO ASIGNADO (CRÍTICO): - ${agendaOcupadaTexto} - - REGLAS DE CALENDARIO Y OPTIMIZACIÓN DE RUTAS: - 1. ANTI-SOLAPAMIENTO: NUNCA sugieras ni aceptes una hora que ya esté ocupada en la lista anterior. - 2. OPTIMIZACIÓN DE RUTA (MUY IMPORTANTE): El cliente actual está en ${datosExpediente.poblacion}. Si ves en el calendario que el técnico ya tiene otra cita en ${datosExpediente.poblacion} un día concreto, tu prioridad absoluta es ofrecerle a este cliente ese mismo día (en una hora libre anterior o posterior) para aprovechar el viaje. + --- 🛠️ MANUAL DE ACTUACIÓN (SIGUE EL ORDEN) --- + 1. 🚨 SI ES URGENCIA: No agendes. Di que al ser urgente, el técnico contactará y acudirá lo antes posible. + 2. ⏳ SI TIENE CITA PENDIENTE: Dile que su propuesta ya ha sido enviada al técnico y que le avisaréis en cuanto él la confirme en su agenda. NO busques otra fecha. + 3. ✅ SI TIENE CITA CONFIRMADA: Recuérdale cuándo es, no agendes otra. + 4. 📅 PARA AGENDAR (Si no aplica lo anterior): + - Sugiere un hueco libre (usando la Regla 2 de Rutas si es posible). + - ⚠️ CIERRE: Si el cliente ACEPTA, dile que la anotas para pasársela al técnico y que cuando él la vea, se confirmará. + - ⚠️ OBLIGATORIO: En el momento del cierre, añade AL FINAL tu respuesta el código oculto: [PROPUESTA:YYYY-MM-DD HH:mm] + 5. SALUDO: ${esPrimerMensaje ? 'Preséntate diciendo que eres de ' + empresaNombre + ' y da el nº de aviso.' : 'NO TE PRESENTES. Ya habéis hablado, ve al grano.'} + 6. FORMATO: Máximo 2 frases. Corto y al pie. `; const mensajesParaIA = [ @@ -534,7 +536,7 @@ async function procesarConIA(ownerId, mensajeCliente, datosExpediente) { const completion = await openai.chat.completions.create({ model: "gpt-4o-mini", messages: mensajesParaIA, - temperature: 0.2, // Mantenemos creatividad baja para que respete el horario estrictamente + temperature: 0.2, // Creatividad baja para obedecer reglas y horarios }); return completion.choices[0].message.content; @@ -3058,6 +3060,9 @@ app.post("/webhook/evolution", async (req, res) => { worker_id: service.assigned_to, poblacion: service.poblacion || "", // 👈 CRÍTICO para buscar rutas en la misma zona is_urgent: service.is_urgent // 👈 CRÍTICO para que no pida cita en urgencias + appointment_status: service.appointment_status, + cita_pendiente_fecha: service.cita_pendiente_fecha, + cita_pendiente_hora: service.cita_pendiente_hora }); if (respuestaIA) {