From a701b85754222e6dc2b043049579a16c072825d2 Mon Sep 17 00:00:00 2001 From: Rodrigo Bertoldo de Sousa Martins Date: Wed, 1 Apr 2026 09:24:00 -0300 Subject: [PATCH] genieacs: try fix search Signed-off-by: Rodrigo Bertoldo de Sousa Martins --- src/genieacs/api.js | 40 ++++++++++++++++++++++++++++++++++++---- src/nlp/processor.js | 6 +++--- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/genieacs/api.js b/src/genieacs/api.js index f517ccc..20cd53f 100644 --- a/src/genieacs/api.js +++ b/src/genieacs/api.js @@ -8,6 +8,7 @@ const logger = require('../utils/logger'); */ const DEVICE_PROJECTION = [ '_tags', + 'Tags', 'DeviceID.SerialNumber', 'DeviceID.ProductClass', 'DeviceID.Manufacturer', @@ -110,23 +111,45 @@ class GenieACSApi { /** * Busca um dispositivo por serial number. + * Tenta exato primeiro; se não encontrar, tenta uppercase (usuário pode ter digitado minúsculo). * @param {string} serial - Serial number * @param {Object} instance - Instância de GenieACSConfig */ async buscarDispositivo(serial, instance) { logger.info(`[GenieACS] Buscando serial "${serial}" em ${instance.name}`); - return this._buscar({ 'DeviceID.SerialNumber': serial }, instance, 'serial'); + // Tentativa 1: exato como foi informado + const r1 = await this._buscar({ 'DeviceID.SerialNumber': serial }, instance, 'serial'); + if (r1.success) return r1; + // Tentativa 2: uppercase (seriais costumam ser armazenados em maiúsculas) + const upper = serial.toUpperCase(); + if (upper !== serial) { + logger.info(`[GenieACS] Tentando serial em uppercase: "${upper}"`); + return this._buscar({ 'DeviceID.SerialNumber': upper }, instance, 'serial'); + } + return r1; } /** * Busca um dispositivo pela TAG (nome de usuário TopSapp). - * No GenieACS, as tags são armazenadas no campo _tags (array de strings). + * Usa regex case-insensitive para não depender de maiúsculas/minúsculas. * @param {string} tag - Valor da tag (ex.: login PPPoE do cliente) * @param {Object} instance - Instância de GenieACSConfig */ async buscarPorTag(tag, instance) { logger.info(`[GenieACS] Buscando por TAG "${tag}" em ${instance.name}`); - return this._buscar({ '_tags': tag }, instance, 'tag'); + // Escapa caracteres especiais de regex no valor da tag + const tagEscaped = tag.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + + // Tentativa 1: campo _tags com regex case-insensitive (formato array) + const r1 = await this._buscar( + { '_tags': { '$regex': `^${tagEscaped}$`, '$options': 'i' } }, + instance, 'tag' + ); + if (r1.success) return r1; + + // Tentativa 2: campo Tags. = true (formato objeto, como exibido na UI) + logger.info(`[GenieACS] Tentando campo Tags.${tag} em ${instance.name}`); + return this._buscar({ [`Tags.${tag.toLowerCase()}`]: true }, instance, 'tag'); } /** @@ -141,7 +164,16 @@ class GenieACSApi { const autoChannel5 = get('InternetGatewayDevice.LANDevice.1.WLANConfiguration.2.AutoChannelEnable'); // _tags é um array direto na raiz do objeto (não segue o padrão _value) - const tags = Array.isArray(raw._tags) ? raw._tags : []; + // Tags também pode vir como objeto { clickcolmeia2025: { _value: true } } (formato UI do GenieACS) + let tags = []; + if (Array.isArray(raw._tags)) { + tags = raw._tags; + } else if (raw.Tags && typeof raw.Tags === 'object') { + // Extrai as chaves do objeto Tags onde o valor é true + tags = Object.entries(raw.Tags) + .filter(([k, v]) => k !== '_timestamp' && (v === true || (v && v._value === true))) + .map(([k]) => k); + } return { deviceId : raw._id || null, diff --git a/src/nlp/processor.js b/src/nlp/processor.js index b37dd85..db1b55a 100644 --- a/src/nlp/processor.js +++ b/src/nlp/processor.js @@ -171,7 +171,7 @@ class NLPProcessor { const serial = match[match.length - 1] || match[2]; return { action: 'ver_roteador', - target: serial ? serial.trim().toUpperCase() : null, + target: serial ? serial.trim() : null, confidence: 0.95, type: 'genieacs_pattern' }; @@ -754,11 +754,11 @@ class NLPProcessor { // Detectar "ver roteador SERIAL" / "roteador SERIAL" via GenieACS if (/roteador|cpe/i.test(text) && !/onu|ont|sinal|signal/i.test(text)) { - const rrMatch = text.match(/(?:ver|info|status|dados)?\s*(?:roteador|cpe)\s+([A-Z0-9_-]+)/i); + const rrMatch = text.match(/(?:ver|info|status|dados)?\s*(?:roteador|cpe)\s+([A-Z0-9_@.-]+)/i); if (rrMatch && rrMatch[1]) { return { action: 'ver_roteador', - target: rrMatch[1].trim().toUpperCase(), + target: rrMatch[1].trim(), confidence: 0.9, type: 'keyword_roteador' };