From bb0bf658ed1016f2b4a237a6770cd6b82e1cf4ef Mon Sep 17 00:00:00 2001 From: Niek Rabelink Date: Sat, 12 Sep 2026 11:12:31 +0200 Subject: [PATCH] Fix --- admin.php | 66 +++++++++++++------- api/ai.php | 137 ++++++++++++++++++++++++------------------ config/database.php | 7 ++- includes/ai.php | 51 +++++++++++++--- includes/auth.php | 4 +- includes/settings.php | 50 +++++++++++---- 6 files changed, 208 insertions(+), 107 deletions(-) diff --git a/admin.php b/admin.php index a9fc39e..8c61a42 100644 --- a/admin.php +++ b/admin.php @@ -210,24 +210,36 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { // 4. AI Co-Pilot instellingen opslaan (Release v1.5) elseif ($action === 'save_ai_settings') { - $aiEnabled = isset($_POST['ai_enabled']) ? 1 : 0; - $aiProvider = trim($_POST['ai_provider'] ?? 'openai'); - $aiModel = trim($_POST['ai_model'] ?? 'gpt-4o-mini'); - $apiKeyIn = trim($_POST['ai_api_key'] ?? ''); + try { + $aiEnabled = isset($_POST['ai_enabled']) ? 1 : 0; + $aiModel = trim((string)($_POST['ai_model'] ?? 'gemini-1.5-pro')); + $aiProvider = trim((string)($_POST['ai_provider'] ?? '')); + if (empty($aiProvider)) { + $aiProvider = str_contains($aiModel, 'gpt') ? 'openai' : 'gemini'; + } + $apiKeyIn = trim((string)($_POST['ai_api_key'] ?? '')); - $currentAi = get_ai_settings(); - if ($apiKeyIn !== '' && $apiKeyIn !== '••••••••••••••••') { - set_system_setting('ai_api_key', fociz_encrypt($apiKeyIn)); + if ($apiKeyIn !== '' && $apiKeyIn !== '••••••••••••••••') { + set_system_setting('ai_api_key', fociz_encrypt($apiKeyIn)); + } + + set_system_setting('ai_enabled', $aiEnabled); + set_system_setting('ai_provider', $aiProvider); + set_system_setting('ai_model', $aiModel); + + fociz_log_audit($userId, 'SETTINGS_UPDATED', 'ai_settings', null, [ + 'ai_enabled' => $aiEnabled, + 'ai_provider' => $aiProvider, + 'ai_model' => $aiModel + ], 'SUCCESS', $adminUser['email'] ?? null); + + $message = "AI Co-Pilot instellingen zijn succesvol opgeslagen."; + $messageType = 'success'; + } catch (Throwable $e) { + error_log("Fout bij opslaan AI instellingen: " . $e->getMessage()); + $message = "Fout bij opslaan van AI instellingen: " . htmlspecialchars($e->getMessage()); + $messageType = 'error'; } - - set_system_setting('ai_enabled', $aiEnabled); - set_system_setting('ai_provider', $aiProvider); - set_system_setting('ai_model', $aiModel); - - fociz_log_audit($userId, 'SETTINGS_UPDATED', 'ai_settings', null, ['ai_enabled' => $aiEnabled, 'ai_provider' => $aiProvider, 'ai_model' => $aiModel], 'SUCCESS', $adminUser['email']); - - $message = "AI Co-Pilot instellingen zijn succesvol opgeslagen."; - $messageType = 'success'; } // 5. Test e-mail versturen via SMTP (Release v1.6) @@ -1098,7 +1110,7 @@ require_once __DIR__ . '/includes/header.php'; - + @@ -1141,7 +1153,7 @@ require_once __DIR__ . '/includes/header.php'; - +
@@ -1651,7 +1663,10 @@ async function testAdminAiConnection() { const resultDiv = document.getElementById('adminAiTestResult'); const apiKey = document.getElementById('admin_ai_api_key').value.trim(); const model = document.getElementById('admin_ai_model').value; - const provider = document.getElementById('admin_ai_provider').value; + let provider = document.getElementById('admin_ai_provider').value; + if (!provider) { + provider = (model && model.indexOf('gpt') !== -1) ? 'openai' : 'gemini'; + } resultDiv.classList.add('hidden'); resultDiv.className = 'hidden p-3 rounded-xl text-xs'; @@ -1673,12 +1688,19 @@ async function testAdminAiConnection() { headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); - const data = await res.json(); + + const rawText = await res.text(); + let data; + try { + data = JSON.parse(rawText); + } catch (parseErr) { + throw new Error(`Ongeldig serverantwoord (HTTP ${res.status}): ${rawText.slice(0, 200)}`); + } resultDiv.classList.remove('hidden'); - if (data.success) { + if (data && data.success) { resultDiv.className = 'p-3 rounded-xl text-xs bg-emerald-50 dark:bg-emerald-950/30 border border-emerald-200 dark:border-emerald-800 text-emerald-800 dark:text-emerald-200 flex items-center space-x-2'; - resultDiv.innerHTML = `Verbinding Geslaagd! ${data.message}`; + resultDiv.innerHTML = `Verbinding Geslaagd! ${data.message || 'API verbinding is geverifieerd.'}`; } else { resultDiv.className = 'p-3 rounded-xl text-xs bg-rose-50 dark:bg-rose-950/30 border border-rose-200 dark:border-rose-800 text-rose-800 dark:text-rose-200 flex items-center space-x-2'; resultDiv.innerHTML = `Verbinding Mislukt: ${data.error || 'Onbekende fout opgetreden'}`; diff --git a/api/ai.php b/api/ai.php index df6fa1a..264dd83 100644 --- a/api/ai.php +++ b/api/ai.php @@ -351,71 +351,86 @@ try { // 3d. Test AI Verbinding (Gemini Pro / OpenAI) if ($action === 'test_connection') { - $data = json_decode(file_get_contents('php://input'), true) ?: $_POST; - - $tempProvider = !empty($data['provider']) ? trim($data['provider']) : null; - $tempKey = !empty($data['api_key']) ? trim($data['api_key']) : null; - $tempModel = !empty($data['model']) ? trim($data['model']) : null; + try { + $rawInput = file_get_contents('php://input'); + $data = !empty($rawInput) ? (json_decode($rawInput, true) ?: []) : $_POST; + + $tempProvider = !empty($data['provider']) ? trim((string)$data['provider']) : null; + $tempKey = !empty($data['api_key']) ? trim((string)$data['api_key']) : null; + $tempModel = !empty($data['model']) ? trim((string)$data['model']) : null; - // Als er test credentials zijn meegegeven, test direct met die credentials - if (!empty($tempKey)) { - $testSettings = [ - 'ai_provider' => $tempProvider ?: 'gemini', - 'ai_api_key' => $tempKey, - 'ai_model' => $tempModel ?: ($tempProvider === 'openai' ? 'gpt-4o-mini' : 'gemini-1.5-pro'), + // Als er test credentials zijn meegegeven, test direct met die credentials + if (!empty($tempKey) && $tempKey !== '••••••••••••••••') { + $testSettings = [ + 'ai_provider' => $tempProvider ?: 'gemini', + 'ai_api_key' => $tempKey, + 'ai_model' => $tempModel ?: ($tempProvider === 'openai' ? 'gpt-4o-mini' : 'gemini-1.5-pro'), + ]; + } else { + // Anders haal de geconfigureerde instellingen op van user of org + $testSettings = get_ai_settings($user['id']); + if (!empty($tempModel)) { + $testSettings['ai_model'] = $tempModel; + } + if (!empty($tempProvider)) { + $testSettings['ai_provider'] = $tempProvider; + } + } + + if (empty($testSettings['ai_api_key'])) { + echo json_encode([ + 'success' => false, + 'error' => 'Geen API-sleutel ingevuld of geconfigureerd om te testen.', + ]); + exit; + } + + $provider = strtolower($testSettings['ai_provider'] ?? 'gemini'); + $model = $testSettings['ai_model'] ?? ($provider === 'openai' ? 'gpt-4o-mini' : 'gemini-1.5-pro'); + + $t0 = microtime(true); + + $testMessages = [ + ['role' => 'user', 'content' => 'Fociz connectiviteitstest. Reageer enkel met het woord OK.'], ]; - } else { - // Anders haal de geconfigureerde instellingen op van user of org - $testSettings = get_ai_settings($user['id']); - } - if (empty($testSettings['ai_api_key'])) { + if ($provider === 'gemini' || strpos(strtolower($model), 'gemini') !== false) { + $aiRes = fociz_ai_chat_gemini($testMessages, ['max_tokens' => 20, 'temperature' => 0.1], $testSettings); + } else { + $aiRes = fociz_ai_chat_openai($testMessages, ['max_tokens' => 20, 'temperature' => 0.1], $testSettings); + } + + $latency = round((microtime(true) - $t0) * 1000); + + if (!$aiRes['success']) { + echo json_encode([ + 'success' => false, + 'error' => $aiRes['error'] ?? 'Verbindingstest mislukt.', + 'latency_ms' => $latency, + 'provider' => $provider, + 'model' => $model, + ]); + exit; + } + + $providerName = ($provider === 'gemini' || strpos(strtolower($model), 'gemini') !== false) ? 'Google Gemini Pro' : 'OpenAI'; + + echo json_encode([ + 'success' => true, + 'message' => "Verbinding met {$providerName} is succesvol tot stand gebracht! (Response tijd: {$latency}ms)", + 'latency_ms' => $latency, + 'provider' => $provider, + 'model' => $aiRes['model'] ?? $model, + 'zero_leak' => true, + ]); + exit; + } catch (Throwable $testEx) { echo json_encode([ 'success' => false, - 'error' => 'Geen API-sleutel ingevuld of geconfigureerd om te testen.', + 'error' => 'Fout tijdens verbindingstest: ' . $testEx->getMessage(), ]); exit; } - - $provider = strtolower($testSettings['ai_provider'] ?? 'gemini'); - $model = $testSettings['ai_model'] ?? ($provider === 'openai' ? 'gpt-4o-mini' : 'gemini-1.5-pro'); - - $t0 = microtime(true); - - $testMessages = [ - ['role' => 'user', 'content' => 'Fociz connectiviteitstest. Reageer enkel met het woord OK.'], - ]; - - if ($provider === 'gemini' || strpos(strtolower($model), 'gemini') !== false) { - $aiRes = fociz_ai_chat_gemini($testMessages, ['max_tokens' => 20, 'temperature' => 0.1], $testSettings); - } else { - $aiRes = fociz_ai_chat_openai($testMessages, ['max_tokens' => 20, 'temperature' => 0.1], $testSettings); - } - - $latency = round((microtime(true) - $t0) * 1000); - - if (!$aiRes['success']) { - echo json_encode([ - 'success' => false, - 'error' => $aiRes['error'] ?? 'Verbindingstest mislukt.', - 'latency_ms' => $latency, - 'provider' => $provider, - 'model' => $model, - ]); - exit; - } - - $providerName = ($provider === 'gemini' || strpos(strtolower($model), 'gemini') !== false) ? 'Google Gemini Pro' : 'OpenAI'; - - echo json_encode([ - 'success' => true, - 'message' => "Verbinding met {$providerName} is succesvol tot stand gebracht! (Response tijd: {$latency}ms)", - 'latency_ms' => $latency, - 'provider' => $provider, - 'model' => $aiRes['model'] ?? $model, - 'zero_leak' => true, - ]); - exit; } // 4. Slimme dagindeling berekenen voor taken rondom bezette tijdblokken @@ -599,7 +614,11 @@ try { } echo json_encode(['error' => 'Onbekende actie']); -} catch (Exception $e) { +} catch (Throwable $e) { + error_log("api/ai.php Throwable: " . $e->getMessage() . " in " . $e->getFile() . ":" . $e->getLine()); http_response_code(500); - echo json_encode(['error' => $e->getMessage()]); + echo json_encode([ + 'success' => false, + 'error' => 'Serverfout bij AI verwerking: ' . $e->getMessage() + ]); } diff --git a/config/database.php b/config/database.php index 85208ad..e979292 100644 --- a/config/database.php +++ b/config/database.php @@ -172,6 +172,9 @@ function ensure_tables_exist(PDO $pdo): void { "CREATE TABLE IF NOT EXISTS `audit_logs` (`id` INT AUTO_INCREMENT PRIMARY KEY, `user_id` INT NULL, `user_email` VARCHAR(191) NULL, `action` VARCHAR(64) NOT NULL, `resource_type` VARCHAR(64) NULL, `resource_id` INT NULL, `details` TEXT NULL, `ip_address` VARCHAR(45) NOT NULL, `user_agent` VARCHAR(255) NULL, `status` ENUM('SUCCESS', 'FAILED', 'WARNING', 'PENDING') NOT NULL DEFAULT 'SUCCESS', `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, INDEX (`user_id`), INDEX (`action`), INDEX (`created_at`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", // Agenda & Verlof: Hele of meerdere dagen blokkeren (Vakantie, Vrije dag, Ziekte) "CREATE TABLE IF NOT EXISTS `calendar_blocks` (`id` INT AUTO_INCREMENT PRIMARY KEY, `user_id` INT NOT NULL, `start_date` DATE NOT NULL, `end_date` DATE NOT NULL, `title` VARCHAR(255) NOT NULL, `block_type` VARCHAR(50) NOT NULL DEFAULT 'VACATION', `notes` TEXT NULL, `outlook_event_id` VARCHAR(255) NULL, `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX (`user_id`, `start_date`, `end_date`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + // Centrale Systeeminstellingen (AI, Werkdagen, Sessiebeveiliging) + "CREATE TABLE IF NOT EXISTS `system_settings` (`setting_key` VARCHAR(64) PRIMARY KEY, `setting_value` LONGTEXT NULL, `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", + "ALTER TABLE `system_settings` MODIFY COLUMN `setting_value` LONGTEXT NULL", ]; foreach ($colUpgrades as $sql) { try { @@ -245,8 +248,8 @@ function ensure_tables_exist(PDO $pdo): void { // Pas bestaande audit logs eenmalig aan zodat de weergave klopt met de lokale tijd $pdo->exec("UPDATE audit_logs SET created_at = DATE_ADD(created_at, INTERVAL 2 HOUR)"); $pdo->prepare(" - INSERT INTO system_settings (setting_key, setting_value, created_at, updated_at) - VALUES ('audit_logs_tz_fixed', '1', NOW(), NOW()) + INSERT INTO system_settings (setting_key, setting_value, updated_at) + VALUES ('audit_logs_tz_fixed', '1', NOW()) ON DUPLICATE KEY UPDATE setting_value = '1', updated_at = NOW() ")->execute(); } diff --git a/includes/ai.php b/includes/ai.php index dd6ab1b..e1b6996 100644 --- a/includes/ai.php +++ b/includes/ai.php @@ -82,12 +82,19 @@ function fociz_ai_enforce_privacy_firewall(array &$messages): array { * @return array */ function fociz_ai_chat_gemini(array $messages, array $options, array $aiSettings): array { - $apiKey = $aiSettings['ai_api_key']; - $model = !empty($aiSettings['ai_model']) ? $aiSettings['ai_model'] : 'gemini-1.5-pro'; + $apiKey = trim((string)($aiSettings['ai_api_key'] ?? '')); + $model = !empty($aiSettings['ai_model']) ? trim((string)$aiSettings['ai_model']) : 'gemini-1.5-pro'; $temperature = $options['temperature'] ?? 0.3; $maxTokens = $options['max_tokens'] ?? 2048; $jsonMode = !empty($options['json_mode']); + if (empty($apiKey)) { + return [ + 'success' => false, + 'error' => 'Geen Google Gemini API-sleutel ingevuld of geconfigureerd.', + ]; + } + // Google Generative Language API structuur opbouwen $systemInstructions = []; $contents = []; @@ -131,7 +138,8 @@ function fociz_ai_chat_gemini(array $messages, array $options, array $aiSettings $payload['generationConfig']['responseMimeType'] = 'application/json'; } - $endpoint = "https://generativelanguage.googleapis.com/v1beta/models/{$model}:generateContent"; + // Geef de sleutel zowel in de URL (?key=) als in de x-goog-api-key header mee voor proxy-ondersteuning + $endpoint = "https://generativelanguage.googleapis.com/v1beta/models/{$model}:generateContent?key=" . urlencode($apiKey); $response = fociz_http_request($endpoint, [ 'method' => 'POST', @@ -140,11 +148,20 @@ function fociz_ai_chat_gemini(array $messages, array $options, array $aiSettings 'x-goog-api-key' => $apiKey, ], 'body' => $payload, - 'timeout' => 45, + 'timeout' => 20, ]); if ($response['status'] !== 200 || empty($response['json']['candidates'][0]['content']['parts'][0]['text'])) { - $errMsg = $response['json']['error']['message'] ?? ($response['error'] ?? "Gemini API aanroep mislukt (HTTP {$response['status']})"); + $errMsg = null; + if (!empty($response['json']['error']['message'])) { + $errMsg = $response['json']['error']['message']; + } elseif (!empty($response['error'])) { + $errMsg = $response['error']; + } elseif (!empty($response['body'])) { + $errMsg = "Gemini fout (HTTP {$response['status']}): " . strip_tags(substr((string)$response['body'], 0, 200)); + } else { + $errMsg = "Gemini API aanroep mislukt (HTTP {$response['status']})"; + } error_log("fociz_ai_chat_gemini fout: {$errMsg}"); return [ 'success' => false, @@ -188,12 +205,19 @@ function fociz_ai_chat_gemini(array $messages, array $options, array $aiSettings * @return array */ function fociz_ai_chat_openai(array $messages, array $options, array $aiSettings): array { - $apiKey = $aiSettings['ai_api_key']; - $model = !empty($aiSettings['ai_model']) ? $aiSettings['ai_model'] : 'gpt-4o-mini'; + $apiKey = trim((string)($aiSettings['ai_api_key'] ?? '')); + $model = !empty($aiSettings['ai_model']) ? trim((string)$aiSettings['ai_model']) : 'gpt-4o-mini'; $temperature = $options['temperature'] ?? 0.3; $maxTokens = $options['max_tokens'] ?? 1500; $jsonMode = !empty($options['json_mode']); + if (empty($apiKey)) { + return [ + 'success' => false, + 'error' => 'Geen OpenAI API-sleutel ingevuld of geconfigureerd.', + ]; + } + $payload = [ 'model' => $model, 'messages' => $messages, @@ -212,11 +236,20 @@ function fociz_ai_chat_openai(array $messages, array $options, array $aiSettings 'Content-Type' => 'application/json', ], 'body' => $payload, - 'timeout' => 35, + 'timeout' => 20, ]); if ($response['status'] !== 200 || empty($response['json']['choices'][0]['message']['content'])) { - $errMsg = $response['json']['error']['message'] ?? ($response['error'] ?? "OpenAI aanroep mislukt (HTTP {$response['status']})"); + $errMsg = null; + if (!empty($response['json']['error']['message'])) { + $errMsg = $response['json']['error']['message']; + } elseif (!empty($response['error'])) { + $errMsg = $response['error']; + } elseif (!empty($response['body'])) { + $errMsg = "OpenAI fout (HTTP {$response['status']}): " . strip_tags(substr((string)$response['body'], 0, 200)); + } else { + $errMsg = "OpenAI API aanroep mislukt (HTTP {$response['status']})"; + } error_log("fociz_ai_chat_openai fout: {$errMsg}"); return [ 'success' => false, diff --git a/includes/auth.php b/includes/auth.php index f80565a..04f9297 100644 --- a/includes/auth.php +++ b/includes/auth.php @@ -34,7 +34,7 @@ function is_https_request(): bool { /** * AES-256-GCM / AES-256-CBC encryptie helper voor gevoelige tokens (OAuth, API keys) */ -function fociz_encrypt(string $plaintext): string { +function fociz_encrypt(?string $plaintext): string { if (empty($plaintext)) return ''; $key = hash('sha256', defined('APP_SECRET') ? APP_SECRET : 'fociz-maria-db-super-secret-key-998877', true); $iv = random_bytes(16); @@ -46,7 +46,7 @@ function fociz_encrypt(string $plaintext): string { /** * AES-256-CBC decryptie helper; decodeert indien versleuteld, laat legacy plaintext ongemoeid */ -function fociz_decrypt(string $ciphertext): string { +function fociz_decrypt(?string $ciphertext): string { if (empty($ciphertext)) return ''; if (!str_starts_with($ciphertext, 'ENC:')) { return $ciphertext; // Plaintext legacy waarde diff --git a/includes/settings.php b/includes/settings.php index 7c6fc23..96284f8 100644 --- a/includes/settings.php +++ b/includes/settings.php @@ -45,8 +45,17 @@ function get_all_system_settings(bool $forceRefresh = false): array { $stmt = $db->query("SELECT setting_key, setting_value FROM system_settings"); while ($row = $stmt->fetch()) { $val = $row['setting_value']; - $decoded = json_decode($val, true); - $settingsCache[$row['setting_key']] = (json_last_error() === JSON_ERROR_NONE) ? $decoded : $val; + if ($val === null) { + $settingsCache[$row['setting_key']] = null; + continue; + } + $trimmed = trim((string)$val); + if (str_starts_with($trimmed, '{') || str_starts_with($trimmed, '[')) { + $decoded = json_decode($val, true); + $settingsCache[$row['setting_key']] = (json_last_error() === JSON_ERROR_NONE) ? $decoded : $val; + } else { + $settingsCache[$row['setting_key']] = $val; + } } } catch (Throwable $e) { error_log("get_all_system_settings error: " . $e->getMessage()); @@ -60,7 +69,10 @@ function get_all_system_settings(bool $forceRefresh = false): array { */ function get_system_setting(string $key, $default = null) { $all = get_all_system_settings(); - return array_key_exists($key, $all) ? $all[$key] : $default; + if (array_key_exists($key, $all) && $all[$key] !== null && $all[$key] !== '') { + return $all[$key]; + } + return $default; } /** @@ -123,6 +135,8 @@ function get_ai_settings(?int $userId = null): array { $apiKey = ''; $isPersonal = false; + $personalProvider = null; + $personalModel = null; // 1. Controleer persoonlijke sleutel van de ingelogde gebruiker if ($userId !== null && $userId > 0) { @@ -134,12 +148,12 @@ function get_ai_settings(?int $userId = null): array { if ($row) { // Sleutel kan in access_token staan of in settings['api_key'] if (!empty($row['access_token'])) { - $apiKey = fociz_decrypt($row['access_token']); + $apiKey = fociz_decrypt((string)$row['access_token']); $isPersonal = true; } elseif (!empty($row['settings'])) { $userSettings = json_decode($row['settings'], true) ?: []; if (!empty($userSettings['api_key'])) { - $apiKey = fociz_decrypt($userSettings['api_key']); + $apiKey = fociz_decrypt((string)$userSettings['api_key']); $isPersonal = true; } } @@ -147,10 +161,10 @@ function get_ai_settings(?int $userId = null): array { if (!empty($row['settings'])) { $userSettings = json_decode($row['settings'], true) ?: []; if (!empty($userSettings['provider'])) { - $personalProvider = $userSettings['provider']; + $personalProvider = (string)$userSettings['provider']; } if (!empty($userSettings['model'])) { - $personalModel = $userSettings['model']; + $personalModel = (string)$userSettings['model']; } } } @@ -163,24 +177,34 @@ function get_ai_settings(?int $userId = null): array { if (empty($apiKey)) { $savedKeyRaw = get_system_setting('ai_api_key', ''); if (!empty($savedKeyRaw)) { - $apiKey = fociz_decrypt($savedKeyRaw); + $apiKey = fociz_decrypt((string)$savedKeyRaw); } } // 3. Fallback naar .env variabelen (GEMINI_API_KEY of OPENAI_API_KEY) if (empty($apiKey)) { - $apiKey = fociz_env('GEMINI_API_KEY', '') ?: fociz_env('OPENAI_API_KEY', ''); + $apiKey = (string)(fociz_env('GEMINI_API_KEY', '') ?: fociz_env('OPENAI_API_KEY', '')); } $provider = !empty($personalProvider) ? $personalProvider : get_system_setting('ai_provider', 'gemini'); + if (empty($provider)) { + $provider = 'gemini'; + } + $model = !empty($personalModel) ? $personalModel : get_system_setting('ai_model', 'gemini-1.5-pro'); + if (empty($model)) { + $model = (strpos((string)$provider, 'openai') !== false) ? 'gpt-4o-mini' : 'gemini-1.5-pro'; + } + + $apiKey = trim((string)$apiKey); + $hasKey = ($apiKey !== ''); return [ - 'ai_enabled' => (bool)get_system_setting('ai_enabled', !empty($apiKey)), - 'ai_provider' => $provider, + 'ai_enabled' => (bool)get_system_setting('ai_enabled', $hasKey), + 'ai_provider' => (string)$provider, 'ai_api_key' => $apiKey, - 'ai_model' => $model, - 'has_key' => !empty($apiKey), + 'ai_model' => (string)$model, + 'has_key' => $hasKey, 'is_personal_key'=> $isPersonal, ]; }