diff --git a/robot.js b/robot.js index aa92dcc..da5f2dd 100644 --- a/robot.js +++ b/robot.js @@ -7,33 +7,115 @@ if (!DATABASE_URL) { console.error("❌ Error: No hay DATABASE_URL."); process.e const pool = new pg.Pool({ connectionString: DATABASE_URL, ssl: false }); const HEADLESS = true; +// ========================================== +// 🧠 MOTOR DE CLASIFICACIÓN DE GREMIOS PRO +// ========================================== +const REGLAS_GREMIOS = [ + // 1. LOS MANITAS ESPECÍFICOS PRIMERO (Prioridad Alta) + { + nombres_db: ["MANITAS ELECTRICISTA", "MANITAS ELECTRICO", "MANITAS ELECTRICIDAD"], + keywords: ["manitas electric", "cambiar bombilla", "colgar lampara", "instalar foco", "fluorescente", "casquillo", "lampara del dormitorio", "cambiar enchufe", "embellecedor"] + }, + { + nombres_db: ["MANITAS FONTANERIA", "MANITAS FONTANERO"], + keywords: ["manitas fontaner", "cambiar grifo", "sellar bañera", "silicona", "latiguillo", "alcachofa", "tapon", "cambiar cisterna", "descargador"] + }, + { + nombres_db: ["MANITAS PERSIANAS", "MANITAS PERSIANISTA"], + keywords: ["manitas persian", "cambiar cinta", "cuerda persiana", "recogedor", "atasco persiana", "lamas rotas", "persiana descolgada"] + }, + // 2. GREMIOS OFICIALES (Prioridad Media) + { + nombres_db: ["ELECTRICISTA", "ELECTRICIDAD"], + keywords: ["electric", "cortocircuito", "cuadro electrico", "salto de plomos", "apagon", "diferencial", "icp", "magnetotermico", "chispazo", "sin luz", "cableado", "derivacion"] + }, + { + nombres_db: ["FONTANERO", "FONTANERIA"], + keywords: ["fontaner", "fuga de agua", "tuberia", "atasco", "desatasco", "bote sifonico", "llave de paso", "calentador", "termo", "radiador", "caldera", "gotera", "inundacion", "filtracion", "bajante", "humedad"] + }, + { + nombres_db: ["CRISTALERO", "CRISTALERIA"], + keywords: ["cristal", "vidrio", "ventana rota", "escaparate", "luna", "espejo", "climalit", "doble acristalamiento", "velux", "rotura"] + }, + { + nombres_db: ["PERSIANISTA", "PERSIANERO", "PERSIANAS"], + keywords: ["motor persiana", "eje persiana", "persianista", "persiana atascada", "rotura de persiana", "domotica persiana"] + }, + { + nombres_db: ["CARPINTERO", "CARPINTERIA", "MADERA"], + keywords: ["carpinter", "puerta de madera", "bisagra", "marco", "rodapie", "tarima", "armario", "cepillar puerta", "cajon", "encimera", "madera hinchada"] + }, + // 3. EL COMODÍN (Prioridad Baja) + { + nombres_db: ["MANITAS GENERAL", "MANITAS", "BRICOLAJE"], + keywords: ["manitas general", "colgar cuadro", "soporte tv", "estanteria", "montar mueble", "ikea", "cortina", "riel", "estor", "agujero", "taladro", "picaporte", "colgar espejo"] + } +]; + +function normalizarTexto(texto) { + if (!texto) return ""; + return texto.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, ""); +} + +function clasificarGremio(descripcion, gremiosActivosDB) { + if (!descripcion || gremiosActivosDB.length === 0) return null; + + const descNormalizada = normalizarTexto(descripcion); + + for (const regla of REGLAS_GREMIOS) { + const coincide = regla.keywords.some(kw => descNormalizada.includes(normalizarTexto(kw))); + + if (coincide) { + const gremioEncontrado = gremiosActivosDB.find(gDB => { + const nombreDBNorm = normalizarTexto(gDB.name); + return regla.nombres_db.some(nRegla => nombreDBNorm.includes(normalizarTexto(nRegla))); + }); + + if (gremioEncontrado) { + console.log(` 🧠 Gremio detectado automáticamente: ${gremioEncontrado.name} (ID: ${gremioEncontrado.id})`); + return gremioEncontrado.id; + } + } + } + return null; +} + + async function main() { - console.log("🤖 ROBOT MODO: CIRUJANO + ASPIRADORA INTELIGENTE"); + console.log("🤖 ROBOT MODO: CIRUJANO + ASPIRADORA + CLASIFICADOR PRO"); while (true) { const client = await pool.connect(); try { + // 1. CARGAMOS LOS GREMIOS ACTUALES DE LA BASE DE DATOS + const gremiosRes = await client.query("SELECT id, name FROM guilds"); + const gremiosDB = gremiosRes.rows; + const res = await client.query("SELECT * FROM provider_credentials WHERE status = 'active'"); for (const cred of res.rows) { let password = Buffer.from(cred.password_hash, 'base64').toString('utf-8'); console.log(`\n🔄 Procesando ${cred.provider.toUpperCase()}...`); + + // 2. PASAMOS LOS GREMIOS AL SCRAPER if (cred.provider === 'multiasistencia') { - await runMultiasistencia(cred.owner_id, cred.username, password); + await runMultiasistencia(cred.owner_id, cred.username, password, gremiosDB); } else if (cred.provider === 'homeserve') { - await runHomeserve(cred.owner_id, cred.username, password); + await runHomeserve(cred.owner_id, cred.username, password, gremiosDB); } + await client.query("UPDATE provider_credentials SET last_sync = NOW() WHERE id = $1", [cred.id]); } } catch (e) { console.error("❌ Error ciclo:", e.message); } finally { client.release(); } + console.log("\n💤 Durmiendo 15 minutos..."); await new Promise(r => setTimeout(r, 15 * 60 * 1000)); } } // ========================================== -// 🏥 MULTIASISTENCIA (FUNCIONANDO) +// 🏥 MULTIASISTENCIA (CON INTELIGENCIA) // ========================================== -async function runMultiasistencia(ownerId, user, pass) { +async function runMultiasistencia(ownerId, user, pass, gremiosDB) { const browser = await chromium.launch({ headless: HEADLESS, args: ['--no-sandbox'] }); const context = await browser.newContext(); const page = await context.newPage(); @@ -97,15 +179,22 @@ async function runMultiasistencia(ownerId, user, pass) { if (scrapData && scrapData['Nombre Cliente']) break; } catch (e) { continue; } } - if (scrapData && scrapData['Nombre Cliente']) await saveServiceToDB(ownerId, 'multiasistencia', ref, scrapData); + if (scrapData && scrapData['Nombre Cliente']) { + // 🪄 MAGIA: Clasificamos el gremio basándonos en la descripción leída de la web + const idGremioDetectado = clasificarGremio(scrapData['Descripción'], gremiosDB); + if (idGremioDetectado) { + scrapData['guild_id'] = idGremioDetectado; + } + await saveServiceToDB(ownerId, 'multiasistencia', ref, scrapData); + } } } catch (e) { console.error("❌ Error Multi:", e.message); } finally { await browser.close(); } } // ========================================== -// 🧹 HOMESERVE (CORREGIDO) +// 🧹 HOMESERVE (CON INTELIGENCIA) // ========================================== -async function runHomeserve(ownerId, user, pass) { +async function runHomeserve(ownerId, user, pass, gremiosDB) { const browser = await chromium.launch({ headless: HEADLESS, args: ['--no-sandbox'] }); const page = await browser.newPage(); try { @@ -174,6 +263,11 @@ async function runHomeserve(ownerId, user, pass) { }); if (scrapData && scrapData['Nombre Cliente']) { + // 🪄 MAGIA: Clasificamos el gremio basándonos en la descripción leída de la web + const idGremioDetectado = clasificarGremio(scrapData['Descripción'], gremiosDB); + if (idGremioDetectado) { + scrapData['guild_id'] = idGremioDetectado; + } await saveServiceToDB(ownerId, 'homeserve', ref, scrapData); } }