Fix NLU flow: media_id, upload perm, catalog filter, nlu_description field

- WpWebhook: inject media_id into context before calling BotRouter so
  MediaTranscriber can download audio/image (was passing caption='')
- BotRouter: use context['media_id'] for transcription (non-breaking fallback)
- AiBot::processMedia: fix canUpload to include permType 1 (solo reporta)
- AiBot::buildFlowCatalog: include text flows that have nlu_description set
- DashboardController + index.php: add nlu_description field per flow card

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-07-05 08:51:13 -05:00
co-authored by Claude Sonnet 4.6
parent bb4b5dab10
commit 1d9484a1e0
5 changed files with 18 additions and 5 deletions
+5
View File
@@ -3383,6 +3383,7 @@ HTML;
$flowIdx = 0;
foreach ($flows as $fk => $flow) {
$ft = $flow['type'] ?? 'text';
$fNluDesc = self::h($flow['nlu_description'] ?? '');
$fMsg = self::h($flow['message'] ?? '');
$fFn = $flow['function'] ?? 'forward_to_ai';
$fMenu = $flow['menu'] ?? '';
@@ -3498,6 +3499,8 @@ HTML;
<div class=\"item-card\" id=\"flow-card-{$flowIdx}\">
<div class=\"item-head\">
<span>ID: <input type=\"text\" name=\"flow_key[]\" value=\"" . self::h($fk) . "\" style=\"border:none;background:transparent;font-weight:700;color:#0b3d91;width:180px;font-size:13px\"></span>
<span style=\"font-size:11px;color:#7a8291;font-weight:400;margin-left:8px\">🧠 NLU:</span>
<input type=\"text\" name=\"flow_nlu_desc[]\" value=\"{$fNluDesc}\" placeholder=\"Descripción para IA (ej: Registrar pluviometría)\" style=\"border:none;background:#f0f4ff;border-radius:4px;padding:2px 8px;font-size:11px;color:#374151;flex:1;min-width:0\">
<button type=\"button\" class=\"del\" onclick=\"this.closest('.item-card').remove()\">✕</button>
</div>
<div class=\"form-row\" style=\"align-items:flex-start;gap:10px\">
@@ -4028,6 +4031,8 @@ function addFlowCard() {
'<div class="item-card" id="' + cardId + '">' +
' <div class="item-head">' +
' <span>ID: <input type="text" name="flow_key[]" value="" style="border:none;background:transparent;font-weight:700;color:#0b3d91;width:180px;font-size:13px" placeholder="nuevo_flujo"></span>' +
' <span style="font-size:11px;color:#7a8291;font-weight:400;margin-left:8px">🧠 NLU:</span>' +
' <input type="text" name="flow_nlu_desc[]" value="" placeholder="Descripción para IA (ej: Registrar pluviometría)" style="border:none;background:#f0f4ff;border-radius:4px;padding:2px 8px;font-size:11px;color:#374151;flex:1;min-width:0">' +
' <button type="button" class="del" onclick="this.closest(\'.item-card\').remove()">✕</button>' +
' </div>' +
' <div class="form-row" style="align-items:flex-start;gap:10px">' +
+2
View File
@@ -480,6 +480,8 @@ class WpWebhook
$isNew = self::saveConversation($ctx, $preview, $mediaId);
self::forwardToCompany($ctx, $preview, $mediaId);
if ($isNew && self::$currentCompany !== null) {
// media_id in context so BotRouter/MediaTranscriber can download the file
$ctx['media_id'] = $mediaId;
BotRouter::route(self::$currentCompany, $ctx, $caption, $type);
}
}
+4
View File
@@ -395,6 +395,7 @@ $routes = [
// Flows
$flowKeys = $_POST['flow_key'] ?? [];
$flowNluDescs = $_POST['flow_nlu_desc'] ?? [];
$flowTypes = $_POST['flow_type'] ?? [];
$flowMessages = $_POST['flow_message'] ?? [];
$flowFunctions = $_POST['flow_function'] ?? [];
@@ -443,6 +444,9 @@ $routes = [
$f = ['type' => $ftype];
$nluDesc = trim($flowNluDescs[$i] ?? '');
if ($nluDesc !== '') $f['nlu_description'] = $nluDesc;
if ($ftype === 'text') {
$f['message'] = trim($flowMessages[$i] ?? '');
+4 -3
View File
@@ -17,7 +17,7 @@ class AiBot
default => 'un archivo',
};
$canUpload = $permType === 3;
$canUpload = in_array($permType, [1, 3], true); // 1=solo reporta, 3=ambos
$permDesc = $canUpload
? 'El usuario tiene permisos para subir información y reportes.'
: 'El usuario solo puede recibir información o descargar informes, NO puede subir archivos.';
@@ -382,8 +382,9 @@ PROMPT;
if ($isUpload && !in_array($permType, [1, 3], true)) continue;
if ($isDownload && !in_array($permType, [2, 3], true)) continue;
// Skip purely internal/navigation flows
if (in_array($type, ['text', 'image'], true) && !$isUpload && !$isDownload) continue;
// Skip internal/navigation flows unless they have an explicit NLU description
$hasNluDesc = isset($flow['nlu_description']) && $flow['nlu_description'] !== '';
if (in_array($type, ['text', 'image'], true) && !$isUpload && !$isDownload && !$hasNluDesc) continue;
$label = $flow['nlu_description'] ?? $labels[$key] ?? $key;
$dir = $isUpload ? 'subida' : ($isDownload ? 'descarga' : '');
+3 -2
View File
@@ -118,9 +118,10 @@ class BotRouter
}
if ($nluEnabled && in_array($inputType, ['audio', 'image'], true)) {
$mediaId = $context['media_id'] ?? $input; // injected by WpWebhook::handleMedia
$text = $inputType === 'audio'
? MediaTranscriber::transcribeAudio($input, $company)
: MediaTranscriber::extractFromImage($input, $company);
? MediaTranscriber::transcribeAudio($mediaId, $company)
: MediaTranscriber::extractFromImage($mediaId, $company);
if ($text !== null && trim($text) !== '') {
self::log("NLU media [{$inputType}]: texto extraído → \"{$text}\"");