diff --git a/admin/DashboardController.php b/admin/DashboardController.php index 13a9455..33245c2 100644 --- a/admin/DashboardController.php +++ b/admin/DashboardController.php @@ -1750,8 +1750,42 @@ HTML; + +
+
Probar conexión IA
+
+
+ + +
+ Guarda primero la configuración, luego prueba la conexión. Se enviará un mensaje de prueba al proveedor activo. +
+
+
Los cambios se aplican inmediatamente. Los valores se almacenan en la base de datos.
+ HTML; diff --git a/public/index.php b/public/index.php index f330e6b..1e17a4c 100644 --- a/public/index.php +++ b/public/index.php @@ -415,7 +415,7 @@ $routes = [ $allowed = [ 'whatsapp_access_token', 'whatsapp_app_secret', 'whatsapp_verify_token', 'whatsapp_business_account_id', 'whatsapp_default_phone_number_id', - 'ai_provider', 'openai_api_key', 'openai_model', 'ai_max_tokens', 'ai_default_prompt', + 'ai_provider', 'openai_api_key', 'openai_model', 'gemini_api_key', 'gemini_model', 'ai_max_tokens', 'ai_default_prompt', 'verify_hmac_signature', ]; // Checkbox: si no está presente, desactivar @@ -443,6 +443,37 @@ $routes = [ exit; })()], + ['POST', '/admin/settings/test-ai', fn() => (function () { + SessionAuth::require(); + $provider = Settings::get('ai_provider', 'mock'); + if ($provider === 'gemini') { + $apiKey = Settings::get('gemini_api_key', ''); + $model = Settings::get('gemini_model', 'gemini-2.0-flash'); + if ($apiKey === '') { jsonResponse(200, ['ok' => false, 'provider' => 'gemini', 'error' => 'API Key no configurada. Guarda primero.']); return; } + $url = "https://generativelanguage.googleapis.com/v1beta/models/{$model}:generateContent?key={$apiKey}"; + $payload = json_encode(['contents' => [['role' => 'user', 'parts' => [['text' => 'Responde solo: OK']]]]]); + $ch = curl_init($url); + curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_POSTFIELDS => $payload, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 15]); + $resp = curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $err = curl_error($ch); curl_close($ch); + if ($code !== 200) { $msg = $err ?: (json_decode($resp, true)['error']['message'] ?? "HTTP {$code}"); jsonResponse(200, ['ok' => false, 'provider' => 'gemini', 'error' => $msg]); return; } + $text = json_decode($resp, true)['candidates'][0]['content']['parts'][0]['text'] ?? '(sin respuesta)'; + jsonResponse(200, ['ok' => true, 'provider' => 'gemini', 'response' => trim($text)]); + } elseif ($provider === 'openai') { + $apiKey = Settings::get('openai_api_key', ''); + $model = Settings::get('openai_model', 'gpt-4o-mini'); + if ($apiKey === '') { jsonResponse(200, ['ok' => false, 'provider' => 'openai', 'error' => 'API Key no configurada. Guarda primero.']); return; } + $payload = json_encode(['model' => $model, 'messages' => [['role' => 'user', 'content' => 'Responde solo: OK']], 'max_tokens' => 5]); + $ch = curl_init('https://api.openai.com/v1/chat/completions'); + curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_POSTFIELDS => $payload, CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Authorization: Bearer ' . $apiKey], CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 15]); + $resp = curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $err = curl_error($ch); curl_close($ch); + if ($code !== 200) { $msg = $err ?: (json_decode($resp, true)['error']['message'] ?? "HTTP {$code}"); jsonResponse(200, ['ok' => false, 'provider' => 'openai', 'error' => $msg]); return; } + $text = json_decode($resp, true)['choices'][0]['message']['content'] ?? '(sin respuesta)'; + jsonResponse(200, ['ok' => true, 'provider' => 'openai', 'response' => trim($text)]); + } else { + jsonResponse(200, ['ok' => true, 'provider' => 'mock', 'response' => 'Mock activo — no hay proveedor real configurado.']); + } + })()], + // ─── Debug: captura cruda de webhooks (loguea todo sin validar) ─────── ['GET', '/admin/v1/wp-webhook-debug', fn() => (function () { $log = '[' . date('Y-m-d H:i:s') . "] GET " . ($_SERVER['QUERY_STRING'] ?? '') . "\n";