Improve intent detection: keyword layer + better Gemini prompt

- 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 <noreply@anthropic.com>
This commit is contained in:
Lizandro
2026-07-14 15:25:39 +00:00
co-authored by Claude Sonnet 4.6
parent a21675b12c
commit e43fe4043f
2 changed files with 81 additions and 18 deletions
+56 -6
View File
@@ -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
{