Actualizar server.js
This commit is contained in:
102
server.js
102
server.js
@@ -448,7 +448,7 @@ async function procesarConIA(ownerId, mensajeCliente, datosExpediente) {
|
||||
const ahora = new Date();
|
||||
const fechaHoyTexto = ahora.toLocaleDateString('es-ES', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
|
||||
|
||||
// 🧠 MEMORIA: Traemos los 8 ÚLTIMOS mensajes
|
||||
// 🧠 MEMORIA: Traemos los últimos 8 mensajes
|
||||
const historyQ = await pool.query(`
|
||||
SELECT sender_role, message
|
||||
FROM service_communications
|
||||
@@ -463,19 +463,14 @@ async function procesarConIA(ownerId, mensajeCliente, datosExpediente) {
|
||||
|
||||
const esPrimerMensaje = historialChat.length === 0;
|
||||
|
||||
// 🗓️ LECTURA DE AGENDA ANTI-SOLAPAMIENTOS
|
||||
let agendaOcupadaTexto = "El técnico tiene la agenda libre. Puedes sugerir cualquier hora dentro del horario laboral.";
|
||||
// 🗓️ LECTURA DE AGENDA (Solo la usamos si realmente necesita agendar)
|
||||
let agendaOcupadaTexto = "El técnico tiene la agenda libre en horario laboral.";
|
||||
if (datosExpediente.worker_id) {
|
||||
const agendaQ = await pool.query(`
|
||||
SELECT raw_data->>'scheduled_date' as date,
|
||||
raw_data->>'scheduled_time' as time,
|
||||
raw_data->>'Población' as pob
|
||||
SELECT raw_data->>'scheduled_date' as date, raw_data->>'scheduled_time' as time, raw_data->>'Población' as pob
|
||||
FROM scraped_services
|
||||
WHERE assigned_to = $1
|
||||
AND raw_data->>'scheduled_date' >= CURRENT_DATE::text
|
||||
AND status != 'archived'
|
||||
AND id != $2
|
||||
ORDER BY date ASC, time ASC
|
||||
WHERE assigned_to = $1 AND raw_data->>'scheduled_date' >= CURRENT_DATE::text
|
||||
AND status != 'archived' AND id != $2 ORDER BY date ASC, time ASC
|
||||
`, [datosExpediente.worker_id, datosExpediente.dbId]);
|
||||
|
||||
if (agendaQ.rowCount > 0) {
|
||||
@@ -486,48 +481,71 @@ async function procesarConIA(ownerId, mensajeCliente, datosExpediente) {
|
||||
ocupaciones[r.date].push(`${r.time} (en ${r.pob || 'otra zona'})`);
|
||||
}
|
||||
});
|
||||
|
||||
const lineas = Object.keys(ocupaciones).map(d => `- Día ${d}: Ocupado a las ${ocupaciones[d].join(", ")}`);
|
||||
if(lineas.length > 0) agendaOcupadaTexto = lineas.join("\n ");
|
||||
}
|
||||
}
|
||||
|
||||
// 🚦 ESTADO PENDIENTE
|
||||
// 🚦 ANÁLISIS DEL ESTADO (LA MAGIA EMPIEZA AQUÍ)
|
||||
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 tieneCitaConfirmada = datosExpediente.cita && datosExpediente.cita !== 'Ninguna';
|
||||
const esUrgencia = datosExpediente.is_urgent;
|
||||
|
||||
// 🎯 INSTRUCCIÓN DINÁMICA: Le ponemos la camisa de fuerza a la IA
|
||||
let directivaEstricta = "";
|
||||
|
||||
if (esUrgencia) {
|
||||
directivaEstricta = `
|
||||
🛑 ESTADO ACTUAL: SERVICIO DE URGENCIA.
|
||||
TU ÚNICO OBJETIVO: Tranquilizar al cliente. Dile que al ser una urgencia, el técnico está avisado y contactará/acudirá lo antes posible.
|
||||
PROHIBICIÓN ABSOLUTA: Bajo ningún concepto intentes dar cita, ni preguntes por fechas, ni propongas horarios.
|
||||
`;
|
||||
} else if (hayCitaPendiente) {
|
||||
directivaEstricta = `
|
||||
🛑 ESTADO ACTUAL: CITA PENDIENTE DE APROBACIÓN POR EL TÉCNICO.
|
||||
Datos de la propuesta actual: Día ${datosExpediente.cita_pendiente_fecha} a las ${datosExpediente.cita_pendiente_hora}.
|
||||
TU ÚNICO OBJETIVO: Informar al cliente que ya le hemos pasado su propuesta al técnico y que estamos esperando a que él la valide en su aplicación.
|
||||
PROHIBICIÓN ABSOLUTA: No agendes de nuevo. No ofrezcas más huecos. Si el cliente dice "vale", despídete amablemente y fin.
|
||||
`;
|
||||
} else if (tieneCitaConfirmada) {
|
||||
directivaEstricta = `
|
||||
🛑 ESTADO ACTUAL: CITA 100% CONFIRMADA.
|
||||
Fecha de la cita: ${datosExpediente.cita}.
|
||||
TU ÚNICO OBJETIVO: Resolver cualquier duda del cliente y recordarle que su cita es el ${datosExpediente.cita}.
|
||||
PROHIBICIÓN ABSOLUTA: No intentes agendar. No menciones huecos libres. El trabajo ya está programado.
|
||||
`;
|
||||
} else {
|
||||
directivaEstricta = `
|
||||
🟢 ESTADO ACTUAL: PENDIENTE DE AGENDAR CITA.
|
||||
TU OBJETIVO: Acordar una fecha y hora con el cliente.
|
||||
|
||||
REGLAS DE AGENDAMIENTO:
|
||||
1. OFRECE HUECOS: Mira la "AGENDA DEL TÉCNICO". Nunca ofrezcas horas ocupadas (deja 1 hora de margen).
|
||||
2. RUTAS INTELIGENTES: El cliente está en ${datosExpediente.poblacion || 'su domicilio'}. Si el técnico ya va a esa población un día concreto, ofrécele ese día para aprovechar el viaje.
|
||||
3. FINES DE SEMANA CERRADO. Ofrece solo de L-V.
|
||||
4. CÓDIGO DE CIERRE (VITAL): Si el cliente ACEPTA una propuesta (ej: tú dices "el lunes a las 10" y él dice "sí, perfecto"), confírmale que le pasas la nota al técnico y AÑADE AL FINAL DE TU MENSAJE: [PROPUESTA:YYYY-MM-DD HH:mm]
|
||||
`;
|
||||
}
|
||||
|
||||
// 🧠 EL PROMPT MAESTRO
|
||||
const promptSistema = `
|
||||
Eres el asistente humano de "${empresaNombre}". Hablas de tú, de forma muy natural, corta y directa por WhatsApp.
|
||||
Eres el coordinador humano de "${empresaNombre}". Hablas de tú, de forma muy natural, empática y al grano por WhatsApp. Eres resolutivo y no suenas como un contestador automático.
|
||||
|
||||
--- 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.
|
||||
--- CONTEXTO BÁSICO ---
|
||||
- Hoy es: ${fechaHoyTexto}. (Año 2026).
|
||||
- Horario de la empresa: Lunes a Viernes de ${horarios.m_start} a ${horarios.m_end} y de ${horarios.a_start} a ${horarios.a_end}.
|
||||
|
||||
--- DATOS DEL AVISO #${datosExpediente.ref} ---
|
||||
- Estado: ${datosExpediente.estado}
|
||||
- Población: ${datosExpediente.poblacion}
|
||||
- Urgencia: ${datosExpediente.is_urgent ? 'SÍ (Prioridad)' : 'No'}
|
||||
- Cita Confirmada: ${datosExpediente.cita || 'Ninguna'}
|
||||
- Cita Solicitada PENDIENTE: ${textoCitaPendiente}
|
||||
|
||||
--- ⚠️ CALENDARIO DEL TÉCNICO Y RUTAS ---
|
||||
--- AGENDA DEL TÉCNICO ASIGNADO ---
|
||||
${agendaOcupadaTexto}
|
||||
- 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.
|
||||
|
||||
--- 🛠️ 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.
|
||||
--- 🎯 DIRECTIVA ESTRICTA PARA ESTE MENSAJE ---
|
||||
${directivaEstricta}
|
||||
|
||||
--- REGLAS DE ORO DE COMUNICACIÓN ---
|
||||
1. Máximo 2 frases. Los mensajes de WhatsApp deben ser cortos.
|
||||
2. Lee el historial de la conversación. Si el cliente solo responde "Ok" o "Gracias", dile "De nada, aquí estamos para lo que necesites" y cierra la charla. No le des la chapa.
|
||||
3. NO TE PRESENTES si ya estáis conversando.
|
||||
${esPrimerMensaje ? '4. Como es el primer mensaje del chat, preséntate brevemente diciendo que eres de ' + empresaNombre + ' y da su número de aviso (#' + datosExpediente.ref + ').' : ''}
|
||||
`;
|
||||
|
||||
const mensajesParaIA = [
|
||||
@@ -539,7 +557,7 @@ async function procesarConIA(ownerId, mensajeCliente, datosExpediente) {
|
||||
const completion = await openai.chat.completions.create({
|
||||
model: "gpt-4o-mini",
|
||||
messages: mensajesParaIA,
|
||||
temperature: 0.2, // Creatividad baja para obedecer reglas y horarios
|
||||
temperature: 0.1, // Congelado. No queremos que invente, queremos que obedezca.
|
||||
});
|
||||
|
||||
return completion.choices[0].message.content;
|
||||
|
||||
Reference in New Issue
Block a user