feat: NLU routing + audio/image transcription via AI

- NluRouter in AiBot: builds permission-filtered flow catalog, asks AI
  to route user intent to exact flow key or return chat response
- MediaTranscriber: downloads WA media, transcribes audio (Whisper/Gemini),
  extracts image intent (OpenAI/Gemini/Claude vision)
- BotRouter hybrid: text → NormalBot → NLU fallback if no match;
  audio/image → transcribe → NLU route; sends transcript preview first
- Admin IA tab: NLU checkbox with description
- Per-company nlu flag saved in config_json

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-07-04 21:50:01 -05:00
co-authored by Claude Sonnet 4.6
parent 2b859e3dc0
commit 9e36a965c9
5 changed files with 488 additions and 6 deletions
+3 -1
View File
@@ -38,6 +38,7 @@ require_once __DIR__ . '/../services/ErpSync.php';
require_once __DIR__ . '/../services/ConversationContext.php';
require_once __DIR__ . '/../services/NormalBot.php';
require_once __DIR__ . '/../services/AiBot.php';
require_once __DIR__ . '/../services/MediaTranscriber.php';
require_once __DIR__ . '/../services/BotRouter.php';
require_once __DIR__ . '/../services/PendingApproval.php';
require_once __DIR__ . '/../services/ErpMonitor.php';
@@ -534,6 +535,7 @@ $routes = [
$aiProvider = trim($_POST['ai_provider'] ?? '');
if ($aiProvider !== '') $config['ai_provider'] = $aiProvider; else unset($config['ai_provider']);
$config['ai_for_media'] = isset($_POST['ai_for_media']);
$config['nlu'] = isset($_POST['nlu']);
$openaiKey = trim($_POST['openai_api_key'] ?? '');
if ($openaiKey !== '') $config['openai_api_key'] = $openaiKey;
$geminiKey = trim($_POST['gemini_api_key'] ?? '');
@@ -568,7 +570,7 @@ $routes = [
$formManagedKeys = ['commands', 'menus', 'flows', 'ai_prompt', 'ai_model', 'ai_temperature',
'ai_provider', 'openai_api_key', 'gemini_api_key', 'gemini_model',
'claude_api_key', 'claude_model',
'ai_for_media', 'greeting', 'fallback', 'approval_webhook',
'ai_for_media', 'nlu', 'greeting', 'fallback', 'approval_webhook',
'ignore_prefixes', 'welcome_menu', 'per_type'];
foreach ($existingConfig as $k => $v) {
if (!in_array($k, $formManagedKeys, true) && !isset($config[$k])) {