From 3d04be14bc71c4047714bd85af82b268b11f6076 Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Sun, 5 Jul 2026 21:57:22 -0500 Subject: [PATCH] =?UTF-8?q?feat:=20auto-selecci=C3=B3n=20en=20dynamic=5Fli?= =?UTF-8?q?st=20cuando=20NLU=20extrae=20el=20grupo/filtro?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - handleDynamicList: si __nlu_entities contiene un valor que coincide con el label de un ítem, lo auto-selecciona y navega al next_node sin mostrar la lista interactiva - AiBot: NLU prompt ahora pide explícitamente grupos y filtros en entities Co-Authored-By: Claude Sonnet 4.6 --- services/AiBot.php | 2 +- services/NormalBot.php | 46 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/services/AiBot.php b/services/AiBot.php index 86016ef..32b79e6 100644 --- a/services/AiBot.php +++ b/services/AiBot.php @@ -446,7 +446,7 @@ PROMPT; . "Analiza el mensaje y determina si se refiere claramente a una opción.\n\n" . "Si sí → responde SOLO este JSON (sin markdown):\n" . "{\"action\":\"route\",\"key\":\"\",\"entities\":{\"campo\":\"valor\",...}}\n\n" - . "En 'entities' incluye los datos que el usuario ya mencionó (nombre de finca, fecha, valor numérico, etc.).\n" + . "En 'entities' incluye los datos que el usuario ya mencionó: nombre de finca, grupo, filtro, fecha, valor numérico, etc. Usa el nombre tal como lo dijo el usuario.\n" . "Si no mencionó datos extra, omite entities o usa {}.\n\n" . "Si no está claro o no hay opción correspondiente → responde SOLO:\n" . "{\"action\":\"chat\",\"text\":\"\"}\n\n" diff --git a/services/NormalBot.php b/services/NormalBot.php index a797e18..c47ec48 100644 --- a/services/NormalBot.php +++ b/services/NormalBot.php @@ -193,10 +193,50 @@ class NormalBot } $valueField = $flow['value_field'] ?? 'id'; + $labelField = $flow['label_field'] ?? 'name'; + $group = $flow['meta_group'] ?? ''; + $key = $flow['meta_key'] ?? ''; + $nextNode = $flow['next_node'] ?? null; + + // Si el NLU extrajo entities, intentar auto-seleccionar sin mostrar lista + $entities = $meta['__nlu_entities'] ?? []; + unset($meta['__nlu_entities']); + if (!empty($entities)) { + $matchedId = null; + foreach ($entities as $ev) { + $evNorm = self::normalize((string)$ev); + foreach ($items as $item) { + if (self::normalize((string)($item[$labelField] ?? '')) === $evNorm) { + $matchedId = (string)($item[$valueField] ?? ''); + break 2; + } + } + } + if ($matchedId !== null) { + $formData = $meta[$group] ?? []; + $formData[$key] = $matchedId; + $meta[$group] = $formData; + ConversationContext::updateMetadata($ctxId, $meta); + if ($nextNode !== null) { + ConversationContext::updateNode($ctxId, $nextNode); + $config = json_decode($company['config_json'] ?? '{}', true); + $flows = $config['flows'] ?? []; + $menus = $config['menus'] ?? []; + if (isset($flows[$nextNode])) { + return self::handleFlow($flows[$nextNode], $context, $company, $ctxId, $menus); + } + } + ConversationContext::updateNode($ctxId, null); + return null; + } + // Sin match: continuar mostrando la lista normal + ConversationContext::updateMetadata($ctxId, $meta); + } + $meta['collecting'] = [ - 'meta_group' => $flow['meta_group'] ?? '', - 'meta_key' => $flow['meta_key'] ?? '', - 'next_node' => $flow['next_node'] ?? null, + 'meta_group' => $group, + 'meta_key' => $key, + 'next_node' => $nextNode, '__valid_ids' => array_column($items, $valueField), ]; ConversationContext::updateMetadata($ctxId, $meta);