From e43fe4043fe8e01820d0047399d565f1bbc4db74 Mon Sep 17 00:00:00 2001 From: Lizandro Date: Tue, 14 Jul 2026 15:25:39 +0000 Subject: [PATCH] Improve intent detection: keyword layer + better Gemini prompt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add detectarIntencionKeyword() with regex patterns in Colombian Spanish that runs before Gemini (instant, no API cost) - Gemini is now only called for ambiguous text - Improve Gemini prompt with real examples and informal Spanish - Replace generic "no entendí" with actionable buttons Co-Authored-By: Claude Sonnet 4.6 --- app/Http/Livewire/Chat/PublicChat.php | 62 ++++++++++++++++++++++++--- app/Services/GeminiIntentService.php | 37 ++++++++++------ 2 files changed, 81 insertions(+), 18 deletions(-) diff --git a/app/Http/Livewire/Chat/PublicChat.php b/app/Http/Livewire/Chat/PublicChat.php index aaef869..1d46b95 100644 --- a/app/Http/Livewire/Chat/PublicChat.php +++ b/app/Http/Livewire/Chat/PublicChat.php @@ -352,13 +352,24 @@ class PublicChat extends Component return; } - $accionIA = $this->detectarIntencionIA($texto); + $accion = $this->detectarIntencion($texto); - if ($accionIA) { - $this->clickBoton($accionIA['action'], $accionIA['data'] ?? []); + if ($accion) { + $this->clickBoton($accion['action'], $accion['data'] ?? []); } else { - $this->guardarMensajeBot($this->convId, "No entendi tu mensaje. Usa los botones o escribe lo que deseas:"); - $this->mostrarMenuPrincipal($this->convId); + ChatMessage::create([ + 'conversation_id' => $this->convId, + 'tipo' => 'bot', + 'tipo_ui' => 'buttons', + 'contenido' => "No entendí bien tu mensaje. Puedes escribir cosas como:\n\"ver planes\", \"hacer recarga\", \"mis credenciales\", \"ver promociones\" o usar los botones:", + 'payload' => ['botones' => [ + ['label' => 'Ver planes', 'action' => 'servicios.listar', 'data' => []], + ['label' => 'Recargar saldo', 'action' => 'recarga.iniciar', 'data' => []], + ['label' => 'Mis credenciales','action' => 'credenciales.listar','data' => []], + ['label' => 'Menú principal', 'action' => 'menu.principal', 'data' => []], + ]], + 'leido' => true, + ]); } $this->cargarMensajes(); @@ -1252,8 +1263,47 @@ class PublicChat extends Component } // ───────────────────────────────────────────────────────── - // IA: detectar intencion // ───────────────────────────────────────────────────────── + // Detección de intención: keywords primero, Gemini como fallback + // ───────────────────────────────────────────────────────── + + private function detectarIntencion(string $texto): ?array + { + return $this->detectarIntencionKeyword($texto) + ?? $this->detectarIntencionIA($texto); + } + + private function detectarIntencionKeyword(string $texto): ?array + { + $t = mb_strtolower(trim($texto)); + + $patrones = [ + // Recarga de saldo + 'recarga.iniciar' => '/recarg|recargar|cargar\s*(saldo|cuenta|dinero|plata)|abonar|depositar|agregar\s*(saldo|dinero|plata)|quiero\s*poner\s*saldo/', + // Ver servicios / planes + 'servicios.listar' => '/servicio|plan(es)?|cat[aá]logo|qu[eé]\s*(hay|tienen|tienes)|ver\s*plan|netflix|disney|hbo|prime|spotify|crunchyroll|paramount|streaming|aplicacion|aplicaci[oó]n/', + // Promociones + 'promo.listar' => '/promo(ci[oó]n)?|oferta|descuento|especial/', + // Credenciales / acceso + 'credenciales.listar' => '/credencial|contrase[ñn]a|clave|password|acceso|usuario|mi\s*cuenta|mis\s*datos\s*de\s*acceso|c[oó]mo\s*(entro|accedo|me\s*conecto)/', + // Historial de compras + 'historial.ver' => '/historial|compra(s)?|pedido(s)?|lo\s*que\s*(compr[eé]|he\s*comprado)|mis\s*compras/', + // Perfil + 'perfil.ver' => '/perfil|mis\s*datos|mi\s*informaci[oó]n|mis\s*datos\s*personales/', + // Asesor humano + 'asesor.solicitar' => '/asesor|agente|persona|humano|soporte|ayuda\s*(de\s*una\s*persona)?|hablar\s*con\s*(alguien|una\s*persona|un\s*asesor)/', + // Menú / saludo + 'menu.principal' => '/^(hola|buenas?|buenos?|hey|men[uú]|inicio|principal|volver|regresar|empezar|comenzar|start)[\s!.]*$/', + ]; + + foreach ($patrones as $action => $pattern) { + if (preg_match($pattern, $t)) { + return ['action' => $action, 'data' => []]; + } + } + + return null; + } private function detectarIntencionIA(string $texto): ?array { diff --git a/app/Services/GeminiIntentService.php b/app/Services/GeminiIntentService.php index f72ad72..36dfa04 100644 --- a/app/Services/GeminiIntentService.php +++ b/app/Services/GeminiIntentService.php @@ -58,25 +58,38 @@ class GeminiIntentService $promptExtra = ChatConfig::get('gemini_prompt_extra', ''); return <<