feat: NLU routing + fix greeting para cat2/cat3 + nlu_descriptions
- Cat 2 y cat 3: greeting '' (no null) para que greeting_flow: ask_finca se dispare en el primer mensaje y el usuario seleccione su finca - nlu_enabled: true en config root activa el routing inteligente - NormalBot: step 6 llama AiBot::routeOrChat() antes del fallback_flow; si retorna 'route' ejecuta el flow; si 'chat' responde en texto libre - reset_finca: nuevo flow+función que limpia el meta de finca y relanza ask_finca; el NLU puede enrutar "quiero cambiar de finca" aquí - nlu_description en todos los flows consultables por el NLU; nlu_skip en menus de navegación interna para no exponerlos al modelo - AiBot::buildFlowCatalog: agrega upload_ciclo a isUpload para que cat 2 no vea flujos de subida en el catálogo del NLU Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
7fc36f1ebf
commit
0ddab6adcf
+51
-3
@@ -103,20 +103,54 @@ class NormalBot
|
||||
return $response;
|
||||
}
|
||||
|
||||
// 6. Fallback flow
|
||||
// 6. NLU routing — si está habilitado, intenta mapear texto libre a un flow antes del fallback
|
||||
if (!$suppressFallback && ($config['nlu_enabled'] ?? false)) {
|
||||
$context['permission_type'] ??= (int)$permType;
|
||||
$route = AiBot::routeOrChat($company, $context, $input);
|
||||
if ($route['action'] === 'route' && isset($route['key'])) {
|
||||
$key = $route['key'];
|
||||
// reset_finca: limpiar finca del meta y relanzar ask_finca
|
||||
if ($key === 'reset_finca') {
|
||||
$m = ConversationContext::getMetadata($ctxId);
|
||||
unset($m['finca']);
|
||||
ConversationContext::updateMetadata($ctxId, $m);
|
||||
$key = 'ask_finca';
|
||||
}
|
||||
// Inyectar entities para auto-select en dynamic_list
|
||||
if (!empty($route['entities'])) {
|
||||
$m = ConversationContext::getMetadata($ctxId);
|
||||
$m['__nlu_entities'] = array_values($route['entities']);
|
||||
ConversationContext::updateMetadata($ctxId, $m);
|
||||
}
|
||||
if (isset($flows[$key])) {
|
||||
ConversationContext::updateNode($ctxId, $key);
|
||||
return self::handleFlow($flows[$key], $context, $company, $ctxId, $menus);
|
||||
}
|
||||
if (isset($menus[$key])) {
|
||||
ConversationContext::updateNode($ctxId, $key);
|
||||
return self::buildMenuResponse($menus[$key], $context['from'], $company);
|
||||
}
|
||||
}
|
||||
if ($route['action'] === 'chat' && ($route['text'] ?? '') !== '') {
|
||||
ConversationContext::updateNode($ctxId, null);
|
||||
return self::sendText($route['text'], $context['from'], $company);
|
||||
}
|
||||
}
|
||||
|
||||
// 7. Fallback flow
|
||||
$fallbackFlowId = $perType['fallback_flow'] ?? $config['fallback_flow'] ?? null;
|
||||
if ($fallbackFlowId !== null && isset($flows[$fallbackFlowId])) {
|
||||
ConversationContext::updateNode($ctxId, $fallbackFlowId);
|
||||
return self::handleFlow($flows[$fallbackFlowId], $context, $company, $ctxId, $menus);
|
||||
}
|
||||
|
||||
// 7. Greeting menu as fallback (texto no reconocido después de estar en __greeted)
|
||||
// 8. Greeting menu as fallback (texto no reconocido después de estar en __greeted)
|
||||
if (!$suppressFallback && $greetingMenuKey !== null && isset($menus[$greetingMenuKey])) {
|
||||
ConversationContext::updateNode($ctxId, '__greeted');
|
||||
return self::buildMenuResponse($menus[$greetingMenuKey], $context['from'], $company);
|
||||
}
|
||||
|
||||
// 8. Static fallback text
|
||||
// 9. Static fallback text
|
||||
if (!$suppressFallback) {
|
||||
$fallback = $perType['fallback'] ?? $config['fallback'] ?? null;
|
||||
if ($fallback !== null) {
|
||||
@@ -1081,6 +1115,20 @@ class NormalBot
|
||||
ConversationContext::reset($ctxId);
|
||||
return self::sendText("Hasta luego 👋\n\nEscribe *menu* cuando quieras volver.", $context['from'], $company);
|
||||
})(),
|
||||
'reset_finca' => (function () use ($ctxId, $context, $company) {
|
||||
$m = ConversationContext::getMetadata($ctxId);
|
||||
unset($m['finca']);
|
||||
ConversationContext::updateMetadata($ctxId, $m);
|
||||
$cfg = self::getConfig($company);
|
||||
$permType = (string)($company['_permission_type'] ?? 1);
|
||||
$pt = $cfg['per_type'][$permType] ?? [];
|
||||
$allFlows = array_merge($cfg['flows'] ?? [], $pt['flows'] ?? []);
|
||||
$allMenus = array_merge($cfg['menus'] ?? [], $pt['menus'] ?? []);
|
||||
ConversationContext::updateNode($ctxId, 'ask_finca');
|
||||
return isset($allFlows['ask_finca'])
|
||||
? self::handleFlow($allFlows['ask_finca'], $context, $company, $ctxId, $allMenus)
|
||||
: self::sendText('¿En qué finca trabajas?', $context['from'], $company);
|
||||
})(),
|
||||
'forward_to_ai' => null,
|
||||
'api_report' => self::executeApiReport($params, $context, $company, $ctxId),
|
||||
default => null,
|
||||
|
||||
Reference in New Issue
Block a user