diff --git a/server.js b/server.js index ffc2ede..fdcf510 100644 --- a/server.js +++ b/server.js @@ -1596,6 +1596,16 @@ async function registrarMovimiento(serviceId, userId, action, details) { // ========================================== // 🧠 CEREBRO IA (WHATSAPP) // ========================================== +// 🗣️ Texto por defecto del bloque "Estilo e instrucciones de la empresa" que se ve y se +// edita desde el cuadro de "Instrucciones y estilo de la IA" en Configuración Avanzada. +// Si la empresa no ha guardado nunca nada en ese cuadro, se usa este texto (que es +// exactamente el comportamiento que la IA tenía antes de poder editarse desde el panel). +const DEFAULT_REGLAS_NEGOCIO_IA = `Habla de tú, de forma natural, clara, cercana y profesional. +Los fines de semana solo se ofrecen citas si es una urgencia. +Máximo 2 frases por mensaje: sé claro y directo. +No te presentes de nuevo si ya habéis hablado antes. +No uses la muletilla "¿En qué más te puedo ayudar?".`; + async function procesarConIA(ownerId, mensajeCliente, datosExpediente) { try { const userQ = await pool.query( @@ -1607,7 +1617,12 @@ async function procesarConIA(ownerId, mensajeCliente, datosExpediente) { const userData = userQ.rows[0]; const settings = userData?.wa_settings || {}; - const instruccionesExtra = settings.ai_custom_prompt || ""; + // 🗣️ Estilo e instrucciones de la empresa: editable desde el panel web + // (Configuración Avanzada → cuadro "Instrucciones y estilo de la IA"). Si la + // empresa nunca ha guardado nada ahí, usamos el texto por defecto de siempre. + const reglasNegocioIA = (settings.ai_custom_prompt && settings.ai_custom_prompt.trim()) + ? settings.ai_custom_prompt.trim() + : DEFAULT_REGLAS_NEGOCIO_IA; const empresaNombre = userData?.full_name || "nuestra empresa"; // 🧾 Condiciones de cobertura por compañía y/o gremio: cada regla puede llevar una @@ -1972,11 +1987,11 @@ async function procesarConIA(ownerId, mensajeCliente, datosExpediente) { if (tieneCitaConfirmada && datosExpediente.cita) { const ahora = new Date(); const [y, m, d] = datosExpediente.cita.split('-'); - // Si no hay hora concreta, solo se considera "pasada" al cambiar de día (fin del día) + // Si no hay hora concreta, solo se considera "pasada" al cambiar de dia (fin del dia) let horaFin = 23, minFin = 59; if (datosExpediente.hora_cita && datosExpediente.hora_cita.includes(':')) { const [hh, mm] = datosExpediente.hora_cita.split(':'); - horaFin = parseInt(hh, 10) + 1; // margen aprox. de duración del servicio + horaFin = parseInt(hh, 10) + 1; // margen aprox. de duracion del servicio minFin = parseInt(mm, 10); } const finVentanaCita = new Date(y, m - 1, d, horaFin, minFin); @@ -2022,13 +2037,12 @@ TU OBJETIVO: Acordar fecha y hora para reparar su avería (${datosExpediente.ave } const promptSistema = ` -Eres el coordinador humano de "${empresaNombre}". Hablas de tú, de forma natural, clara, cercana y profesional por WhatsApp. +Eres el coordinador humano de "${empresaNombre}", hablando por WhatsApp. --- 📋 CONTEXTO BÁSICO --- - Hoy es: ${fechaHoyTexto}. - Horario de la empresa: L-V de ${horarios.m_start} a ${horarios.m_end} y de ${horarios.a_start} a ${horarios.a_end}. - ⛔ REGLA DE ORO DEL HORARIO: NUNCA propongas horas fuera de ese horario ni cruces el tramo de comer. -- Fines de semana solo si es una urgencia. - Localidad del cliente actual: ${datosExpediente.poblacion || 'Localidad no especificada'}. ${reglaCobertura ? ` --- 🧾 CONDICIONES DE COBERTURA PARA ESTE SERVICIO (Compañía: ${datosExpediente.compania || 'no especificada'} · Gremio: ${datosExpediente.gremio || 'no especificado'}) --- @@ -2038,7 +2052,7 @@ Menciona esto SOLO si el cliente pregunta por costes, materiales, o qué cubre e --- ✅ HUECOS EXACTOS CALCULADOS POR EL SISTEMA --- ${agendaDisponibleTexto} ---- 🚨 NORMA ABSOLUTA DE AGENDA --- +--- 🚨 NORMA ABSOLUTA DE AGENDA (fija, no editable desde el panel) --- Los huecos anteriores son la ÚNICA verdad. NO puedes inventar horas. NO puedes deducir huecos por tu cuenta. @@ -2046,32 +2060,30 @@ NO puedes reinterpretar horarios ocupados. SOLO puedes ofrecer horas que estén dentro de esos huecos exactos calculados por el sistema. Si el cliente pide una hora concreta y esa hora cae dentro de uno de esos huecos, puedes aceptarla tentativamente. Si cae fuera, debes decir que no la ves libre y ofrecer una alternativa de la lista exacta. +Si el cliente pide disponibilidad general, resume las opciones reales sin inventar nada. ---- 🎯 DIRECTIVA ESTRICTA PARA ESTE MENSAJE --- +--- 🎯 DIRECTIVA ESTRICTA PARA ESTE MENSAJE (fija, no editable desde el panel) --- ${directivaEstricta} ---- ⚡ REGLA CRÍTICA DE AGENDA (COMANDO SECRETO) --- +--- ⚡ REGLA CRÍTICA DE AGENDA (COMANDO SECRETO, fija, no editable desde el panel) --- Si (y solo si) el cliente ACEPTA claramente un hueco concreto, DEBES añadir AL FINAL ABSOLUTO de tu respuesta este texto literal: [PROPUESTA:YYYY-MM-DD HH:mm] Ejemplo: "Perfecto, le paso la nota al técnico para que te confirme el miércoles entre las 12:00 y las 13:00 aprox. ¡Te decimos algo pronto! [PROPUESTA:2026-03-25 12:00]" -⛔ PROHIBICIONES: +⛔ PROHIBICIONES (fijas, no editables desde el panel): - NUNCA digas "te agendo". - NUNCA digas "cita confirmada". - NUNCA menciones las palabras "código" o "etiqueta". - NUNCA ofrezcas huecos distintos a los calculados. - Si el cliente pregunta por "la semana que viene", responde usando solo los huecos de esa semana. +${esPrimerMensaje ? ` +--- 📌 NOTA --- +Este es el primer mensaje: preséntate y menciona el aviso (#${datosExpediente.ref}).` : ''} ---- ⚙️ REGLAS DE COMUNICACIÓN --- -1. MÁXIMO 2 FRASES. -2. Mensajes cortos, claros y directos. -3. NO TE PRESENTES si ya habéis hablado antes. -4. NO uses la muletilla "¿En qué más te puedo ayudar?". -5. Si el cliente pide disponibilidad general, resume las opciones reales sin inventar nada. -${esPrimerMensaje ? `6. Primer mensaje: preséntate y menciona el aviso (#${datosExpediente.ref}).` : ''} -${instruccionesExtra ? `7. Instrucción extra de la empresa: ${instruccionesExtra}` : ''} +--- 🗣️ ESTILO E INSTRUCCIONES DE LA EMPRESA (editable desde el panel web, Configuración Avanzada) --- +${reglasNegocioIA} `; const completion = await openai.chat.completions.create({ @@ -3049,7 +3061,14 @@ app.get("/whatsapp/status", authMiddleware, async (req, res) => { app.get("/whatsapp/settings", authMiddleware, async (req, res) => { try { const q = await pool.query("SELECT wa_settings FROM users WHERE id=$1", [req.user.accountId]); - res.json({ ok: true, settings: q.rows[0]?.wa_settings || {} }); + res.json({ + ok: true, + settings: q.rows[0]?.wa_settings || {}, + // 🗣️ Texto que usa la IA por defecto para el bloque de estilo/reglas de negocio + // cuando la empresa aún no ha guardado nada personalizado. El panel lo usa para + // precargar el cuadro de texto la primera vez, para que se vea lo que hace hoy. + default_ai_rules: DEFAULT_REGLAS_NEGOCIO_IA + }); } catch (e) { res.status(500).json({ ok: false }); } });