From b6a85c33f778ff5637b69ee1aad2883f4ce530c2 Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Sun, 28 Jun 2026 13:10:08 -0500 Subject: [PATCH] fix: salir button works, cap at 3 buttons, no AI error on unmatched input MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add 'goodbye' function: resets context + sends farewell with menu hint - Add safety slice to 3 buttons in buildMenuResponse (WhatsApp hard limit) - In hybrid mode: when greeting_menu is configured for the user's category, use it as fallback instead of escalating to AI — prevents "Lo siento, tengo problemas..." from appearing when nothing matches - Expose buildGreetingMenu() as public for BotRouter access - DB: fixed submenu_informes and submenu_ciclos from 4→3 buttons, added salir flow (goodbye function) and salir/exit commands (company 2) Co-Authored-By: Claude Sonnet 4.6 --- services/BotRouter.php | 15 +++++++++++++++ services/NormalBot.php | 11 ++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/services/BotRouter.php b/services/BotRouter.php index e741148..f2cde89 100644 --- a/services/BotRouter.php +++ b/services/BotRouter.php @@ -108,6 +108,21 @@ class BotRouter return $response; } + // Only escalate to AI if bot type truly needs it; avoid AI for menu-driven bots + $config = self::getConfig($company); + $permType = (string)($context['permission_type'] ?? 1); + $perType = $config['per_type'][$permType] ?? []; + + // If a greeting_menu is configured for this category, use it as fallback instead of AI + $greetingMenuKey = $perType['greeting_menu'] ?? null; + if ($greetingMenuKey !== null) { + $menus = array_merge($config['menus'] ?? [], $perType['menus'] ?? []); + if (isset($menus[$greetingMenuKey])) { + self::log("NormalBot no manejó '{$input}' — mostrando menú de categoría en lugar de IA"); + return NormalBot::buildGreetingMenu($menus[$greetingMenuKey], $context['from'], $company); + } + } + self::log("NormalBot no manejó '{$input}', escalando a IA"); return self::runAiBot($company, $context, $input); } diff --git a/services/NormalBot.php b/services/NormalBot.php index ac29eeb..8b9f7cd 100644 --- a/services/NormalBot.php +++ b/services/NormalBot.php @@ -119,6 +119,10 @@ class NormalBot ConversationContext::reset($ctxId); return self::sendText('¿En qué más puedo ayudarte?', $context['from'], $company); })(), + 'goodbye' => (function () use ($ctxId, $context, $company) { + ConversationContext::reset($ctxId); + return self::sendText("Hasta luego 👋\n\nEscribe *menu* cuando quieras volver.", $context['from'], $company); + })(), 'forward_to_ai' => null, 'api_report' => self::executeApiReport($params, $context, $company, $ctxId), default => null, @@ -241,6 +245,11 @@ class NormalBot return self::sendText('✅ Reporte enviado.' . $nav, $context['from'], $company); } + public static function buildGreetingMenu(array $menu, string $to, array $company): ?array + { + return self::buildMenuResponse($menu, $to, $company); + } + private static function buildMenuResponse(array $menu, string $to, array $company): ?array { $menuType = $menu['type'] ?? 'list'; @@ -284,7 +293,7 @@ class NormalBot if ($menuType === 'button') { $buttons = []; - foreach ($menu['buttons'] ?? [] as $btn) { + foreach (array_slice($menu['buttons'] ?? [], 0, 3) as $btn) { $buttons[] = [ 'type' => 'reply', 'reply' => [