From eb436638fbdbd9758d78b335ff293bdfe3d290a7 Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Sat, 4 Jul 2026 22:04:52 -0500 Subject: [PATCH] =?UTF-8?q?fix:=20AI=20tab=20settings=20not=20saving=20?= =?UTF-8?q?=E2=80=94=20read=20from=20DOM=20in=20bot-config=20save=20JS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The JS FormData was built from the CONFIG object (DB state), missing all AI inputs the user types: api_key, models, checkboxes (nlu, ai_for_media). Now reads them directly from DOM before the fetch. Co-Authored-By: Claude Sonnet 4.6 --- admin/DashboardController.php | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/admin/DashboardController.php b/admin/DashboardController.php index 82a5618..73bc226 100644 --- a/admin/DashboardController.php +++ b/admin/DashboardController.php @@ -5135,12 +5135,21 @@ function saveConfig() { // General fd.append('greeting', fullConfig.greeting || ''); fd.append('fallback', fullConfig.fallback || ''); - fd.append('ai_prompt', fullConfig.ai_prompt || ''); - fd.append('ai_model', fullConfig.ai_model || 'gpt-4o-mini'); - fd.append('ai_temperature', String(fullConfig.ai_temperature || 0.7)); - fd.append('ai_provider', fullConfig.ai_provider || ''); - fd.append('approval_webhook', fullConfig.approval_webhook || ''); - fd.append('ignore_prefixes', (fullConfig.ignore_prefixes || []).join('\\n')); + // AI fields — leer del DOM porque el usuario puede editarlos sin tocar el CONFIG JS + const _qs = sel => document.querySelector(sel); + fd.set('ai_provider', _qs('select[name="ai_provider"]')?.value || fullConfig.ai_provider || ''); + fd.set('ai_prompt', _qs('textarea[name="ai_prompt"]')?.value || fullConfig.ai_prompt || ''); + fd.set('ai_model', _qs('select[name="ai_model"]')?.value || fullConfig.ai_model || 'gpt-4o-mini'); + fd.set('ai_temperature', _qs('input[name="ai_temperature"]')?.value || String(fullConfig.ai_temperature || 0.7)); + fd.set('openai_api_key', _qs('input[name="openai_api_key"]')?.value || ''); + fd.set('gemini_api_key', _qs('input[name="gemini_api_key"]')?.value || ''); + fd.set('gemini_model', _qs('select[name="gemini_model"]')?.value || ''); + fd.set('claude_api_key', _qs('input[name="claude_api_key"]')?.value || ''); + fd.set('claude_model', _qs('select[name="claude_model"]')?.value || ''); + if (_qs('input[name="ai_for_media"]')?.checked) fd.set('ai_for_media', '1'); + if (_qs('input[name="nlu"]')?.checked) fd.set('nlu', '1'); + fd.set('approval_webhook', fullConfig.approval_webhook || ''); + fd.set('ignore_prefixes', (fullConfig.ignore_prefixes || []).join('\\n')); // Per-category menus — read from DOM so they're preserved on every AJAX save [1, 2, 3].forEach(cat => {