fix: match fuzzy de label en dynamic_list y collecting mid-flow
- handleDynamicList: usa str_contains bilateral para que "mantenimiento plateo" coincida con label "Plateo" (el NLU suele incluir palabras extra) - handleCollectingInput: si el texto transcrito no es un ID válido, intenta match fuzzy contra __label_map guardado en el estado collecting - handleDynamicList: guarda __label_map en el estado collecting para que mid-flow audio pueda auto-seleccionar sin ID exacto Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
3d04be14bc
commit
976f61b682
+32
-9
@@ -139,16 +139,31 @@ class NormalBot
|
||||
$key = $col['meta_key'] ?? '';
|
||||
$nextNode = $col['next_node'] ?? null;
|
||||
$validIds = $col['__valid_ids'] ?? null;
|
||||
$labelMap = $col['__label_map'] ?? [];
|
||||
|
||||
if ($validIds !== null && !in_array(trim($input), $validIds, true)) {
|
||||
return self::sendText(
|
||||
'⚠️ Por favor selecciona una opción válida de la lista.',
|
||||
$context['from'], $company
|
||||
);
|
||||
$resolved = trim($input);
|
||||
if ($validIds !== null && !in_array($resolved, $validIds, true)) {
|
||||
// Intento de match por label (útil cuando viene texto transcrito de audio)
|
||||
$inputNorm = self::normalize($resolved);
|
||||
$matched = null;
|
||||
foreach ($labelMap as $label => $id) {
|
||||
$lNorm = self::normalize((string)$label);
|
||||
if ($lNorm === $inputNorm || str_contains($inputNorm, $lNorm) || str_contains($lNorm, $inputNorm)) {
|
||||
$matched = (string)$id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($matched === null) {
|
||||
return self::sendText(
|
||||
'⚠️ Por favor selecciona una opción válida de la lista.',
|
||||
$context['from'], $company
|
||||
);
|
||||
}
|
||||
$resolved = $matched;
|
||||
}
|
||||
|
||||
$formData = $meta[$group] ?? [];
|
||||
$formData[$key] = trim($input);
|
||||
$formData[$key] = $resolved;
|
||||
$meta[$group] = $formData;
|
||||
unset($meta['collecting']);
|
||||
ConversationContext::updateMetadata($ctxId, $meta);
|
||||
@@ -198,6 +213,12 @@ class NormalBot
|
||||
$key = $flow['meta_key'] ?? '';
|
||||
$nextNode = $flow['next_node'] ?? null;
|
||||
|
||||
// Mapa label → id para match fuzzy (usado tanto en auto-select como en collecting)
|
||||
$labelMap = [];
|
||||
foreach ($items as $item) {
|
||||
$labelMap[(string)($item[$labelField] ?? '')] = (string)($item[$valueField] ?? '');
|
||||
}
|
||||
|
||||
// Si el NLU extrajo entities, intentar auto-seleccionar sin mostrar lista
|
||||
$entities = $meta['__nlu_entities'] ?? [];
|
||||
unset($meta['__nlu_entities']);
|
||||
@@ -205,9 +226,10 @@ class NormalBot
|
||||
$matchedId = null;
|
||||
foreach ($entities as $ev) {
|
||||
$evNorm = self::normalize((string)$ev);
|
||||
foreach ($items as $item) {
|
||||
if (self::normalize((string)($item[$labelField] ?? '')) === $evNorm) {
|
||||
$matchedId = (string)($item[$valueField] ?? '');
|
||||
foreach ($labelMap as $label => $id) {
|
||||
$lNorm = self::normalize($label);
|
||||
if ($lNorm === $evNorm || str_contains($evNorm, $lNorm) || str_contains($lNorm, $evNorm)) {
|
||||
$matchedId = $id;
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
@@ -238,6 +260,7 @@ class NormalBot
|
||||
'meta_key' => $key,
|
||||
'next_node' => $nextNode,
|
||||
'__valid_ids' => array_column($items, $valueField),
|
||||
'__label_map' => $labelMap,
|
||||
];
|
||||
ConversationContext::updateMetadata($ctxId, $meta);
|
||||
ConversationContext::updateNode($ctxId, 'collecting');
|
||||
|
||||
Reference in New Issue
Block a user