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:
co-authored by
Claude Sonnet 4.6
parent
a21675b12c
commit
e43fe4043f
@@ -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
|
||||
{
|
||||
|
||||
@@ -58,25 +58,38 @@ class GeminiIntentService
|
||||
$promptExtra = ChatConfig::get('gemini_prompt_extra', '');
|
||||
|
||||
return <<<PROMPT
|
||||
Eres un clasificador de intenciones para una tienda de streaming (peliculas, series).
|
||||
Eres un clasificador de intenciones para SirPremium, una tienda colombiana de streaming (Netflix, Disney+, HBO, Spotify, etc.).
|
||||
Los usuarios escriben en español latinoamericano informal, con jerga colombiana y errores ortográficos.
|
||||
{$promptExtra}
|
||||
|
||||
Acciones validas (devuelve EXACTAMENTE una de estas en el campo "action"):
|
||||
- menu.principal (usuario quiere ver el menu, inicio, ayuda general)
|
||||
- servicios.listar (quiere ver servicios, planes, catalogo, que hay disponible)
|
||||
- promo.listar (quiere ver promociones, ofertas, descuentos)
|
||||
- recarga.iniciar (quiere recargar saldo, agregar dinero, cargar cuenta)
|
||||
- credenciales.listar (quiere ver sus credenciales, usuario, contrasena, cuenta, acceso)
|
||||
- historial.ver (quiere ver historial, compras anteriores, que ha comprado)
|
||||
- perfil.ver (quiere ver su perfil, sus datos, su informacion)
|
||||
- asesor.solicitar (quiere hablar con una persona, agente, asesor, humano, soporte)
|
||||
Acciones válidas — devuelve EXACTAMENTE una de estas:
|
||||
- menu.principal → saludo, "hola", "inicio", "volver", "menú", pedir ayuda general
|
||||
- servicios.listar → ver planes, catálogo, qué servicios hay, "quiero Netflix", "qué tienen", "cuánto vale", preguntar por precios
|
||||
- promo.listar → ver promociones, ofertas, combos, descuentos, "hay algo especial"
|
||||
- recarga.iniciar → recargar saldo, cargar dinero, "quiero poner saldo", "cómo recargo", "agregar plata", "depositar"
|
||||
- credenciales.listar → ver contraseña, cómo entrar, "no puedo acceder", "dame el usuario", "mis datos de Netflix", "cómo me conecto"
|
||||
- historial.ver → historial de compras, "qué he comprado", "mis pedidos", "mis servicios activos"
|
||||
- perfil.ver → ver perfil, mis datos personales, cambiar información
|
||||
- asesor.solicitar → hablar con persona, "quiero un asesor", "necesito ayuda de alguien", "soporte humano"
|
||||
|
||||
Ejemplos de clasificación:
|
||||
"hacer recarga" → recarga.iniciar
|
||||
"quiero recargar" → recarga.iniciar
|
||||
"cargar saldo" → recarga.iniciar
|
||||
"poner plata" → recarga.iniciar
|
||||
"ver planes" → servicios.listar
|
||||
"qué tienen de Netflix" → servicios.listar
|
||||
"hay promociones" → promo.listar
|
||||
"mis contraseñas" → credenciales.listar
|
||||
"no puedo entrar a mi cuenta" → credenciales.listar
|
||||
"hablar con alguien" → asesor.solicitar
|
||||
|
||||
Texto del usuario: "{$texto}"
|
||||
|
||||
Responde UNICAMENTE con un JSON valido, sin markdown, sin explicacion:
|
||||
Responde ÚNICAMENTE con JSON válido, sin markdown, sin explicación:
|
||||
{"action": "la_accion", "data": {}}
|
||||
|
||||
Si no puedes determinar la intencion con certeza, usa: {"action": "menu.principal", "data": {}}
|
||||
Si el texto es completamente ambiguo o irrelevante, usa: {"action": "menu.principal", "data": {}}
|
||||
PROMPT;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user