Actualizar server.js

This commit is contained in:
2026-03-07 19:53:25 +00:00
parent 7764dd84c0
commit b01d30bf48

View File

@@ -4,6 +4,7 @@ import bcrypt from "bcryptjs";
import jwt from "jsonwebtoken"; import jwt from "jsonwebtoken";
import pg from "pg"; import pg from "pg";
import crypto from "crypto"; import crypto from "crypto";
import OpenAI from "openai";
const { Pool } = pg; const { Pool } = pg;
const app = express(); const app = express();
@@ -401,6 +402,43 @@ async function registrarMovimiento(serviceId, userId, action, details) {
} catch (e) { console.error("Error Robot Notario:", e); } } catch (e) { console.error("Error Robot Notario:", e); }
} }
// HELPER: Procesar mensaje con IA (ChatGPT)
async function procesarConIA(ownerId, mensajeCliente, datosExpediente) {
try {
const userQ = await pool.query("SELECT wa_settings FROM users WHERE id=$1", [ownerId]);
const settings = userQ.rows[0]?.wa_settings || {};
if (!settings.wa_ai_enabled) return null;
const promptSistema = `
Eres el asistente de IntegraRepara. Responde al cliente de forma profesional y corta.
DATOS DEL EXPEDIENTE #${datosExpediente.ref}:
- Estado: ${datosExpediente.estado}
- Operario: ${datosExpediente.operario || 'Pendiente de asignar'}
- Fecha Cita: ${datosExpediente.cita || 'Pendiente de agendar'}
REGLAS:
- Si el cliente pregunta cuándo van, dale la fecha si existe.
- Si no hay operario, di que estamos buscando al mejor técnico.
- NO inventes datos. Si no sabes algo, pide que espere a que un humano le atienda.
- Máximo 2 frases.
`;
const completion = await openai.chat.completions.create({
model: "gpt-4o-mini",
messages: [
{ role: "system", content: promptSistema },
{ role: "user", content: mensajeCliente }
],
temperature: 0.7,
});
return completion.choices[0].message.content;
} catch (e) {
console.error("❌ Error OpenAI:", e.message);
return null;
}
}
// 🛡️ MIDDLEWARE DE PLANES // 🛡️ MIDDLEWARE DE PLANES
async function requirePlan(req, res, next, feature) { async function requirePlan(req, res, next, feature) {
try { try {
@@ -2901,6 +2939,66 @@ app.post("/services/:id/chat", authMiddleware, async (req, res) => {
} }
}); });
// 🤖 WEBHOOK PARA RECIBIR MENSAJES DE WHATSAPP Y RESPONDER CON IA
app.post("/webhook/evolution", async (req, res) => {
try {
const data = req.body;
// Solo procesamos si es un mensaje de texto entrante
if (data.event !== "messages.upsert" || data.data.key.fromMe) return res.sendStatus(200);
const telefonoCliente = data.data.key.remoteJid.split("@")[0];
const mensajeTexto = data.data.message?.conversation || data.data.message?.extendedTextMessage?.text;
const instanceName = data.instance; // ej: cliente_1
if (!mensajeTexto) return res.sendStatus(200);
// 1. Identificar al dueño de la instancia (owner_id)
const ownerId = instanceName.split("_")[1];
// 2. Buscar si este teléfono tiene un servicio activo
const svcQ = await pool.query(`
SELECT s.id, s.service_ref, s.assigned_to, u.full_name as worker_name,
st.name as status_name, s.raw_data->>'scheduled_date' as cita
FROM scraped_services s
LEFT JOIN users u ON s.assigned_to = u.id
LEFT JOIN service_statuses st ON (s.raw_data->>'status_operativo')::text = st.id::text
WHERE s.owner_id = $1 AND s.raw_data->>'Teléfono' ILIKE $2
ORDER BY s.created_at DESC LIMIT 1
`, [ownerId, `%${telefonoCliente.slice(-9)}%`]);
if (svcQ.rowCount > 0) {
const service = svcQ.rows[0];
// 3. Llamar a la IA
const respuestaIA = await procesarConIA(ownerId, mensajeTexto, {
ref: service.service_ref,
estado: service.status_name,
operario: service.worker_name,
cita: service.cita
});
if (respuestaIA) {
// 4. Enviar respuesta por WhatsApp
await sendWhatsAppAuto(telefonoCliente, respuestaIA, instanceName, true);
// 5. Registrar en el chat para que la oficina lo vea
await pool.query(`
INSERT INTO service_communications (scraped_id, owner_id, sender_name, sender_role, message)
VALUES ($1, $2, $3, $4, $5)
`, [service.id, ownerId, "Asistente IA", "ia", respuestaIA]);
// 6. Registrar en el historial
await registrarMovimiento(service.id, null, "Respuesta IA", `ChatGPT respondió: ${respuestaIA}`);
}
}
res.sendStatus(200);
} catch (e) {
console.error("Error Webhook IA:", e.message);
res.sendStatus(500);
}
});
// ========================================== // ==========================================
// 🕒 EL RELOJ DEL SISTEMA (Ejecutar cada minuto) // 🕒 EL RELOJ DEL SISTEMA (Ejecutar cada minuto)
// ========================================== // ==========================================