- MediaTranscriber: if whisper_url set, POSTs to own server with
Basic auth (audio_file field); falls back to OpenAI cloud Whisper
- Admin AI tab: new section for whisper_url / whisper_user / whisper_pass
- save-ai endpoint: saves the three whisper fields to config_json
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- AiLogger.php: new service, inserts into ai_logs on every AI call
- ai_logs table: added to migrate.php (provider, model, call_type, tokens, duration_ms)
- AiBot: logs chat, media_response, nlu calls with timing and token counts
- MediaTranscriber: logs whisper, geminiAudio, openaiVision, geminiVision, claudeVision
- /admin/ai-logs: paginated table with provider/company filter
- Layout.php: added IA Logs nav link
- index.php: require AiLogger before AiBot; added GET /admin/ai-logs route
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>