From 364fd776c4c694c25f46441d1d12f455f899467a Mon Sep 17 00:00:00 2001 From: Niek Rabelink Date: Sat, 12 Sep 2026 12:51:20 +0200 Subject: [PATCH] Ai fix --- includes/ai.php | 134 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 120 insertions(+), 14 deletions(-) diff --git a/includes/ai.php b/includes/ai.php index e1b6996..3b264f5 100644 --- a/includes/ai.php +++ b/includes/ai.php @@ -138,20 +138,126 @@ function fociz_ai_chat_gemini(array $messages, array $options, array $aiSettings $payload['generationConfig']['responseMimeType'] = 'application/json'; } - // 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); + $cleanModel = preg_replace('#^models/#', '', $model); - $response = fociz_http_request($endpoint, [ - 'method' => 'POST', - 'headers' => [ - 'Content-Type' => 'application/json', - 'x-goog-api-key' => $apiKey, - ], - 'body' => $payload, - 'timeout' => 20, - ]); + // Bepaal fallback volgorde van endpoints/versies voor maximale compatibiliteit met alle Google AI Studio accounts + $candidateUrls = []; + if (str_contains($cleanModel, '1.5-flash')) { + $candidateUrls[] = "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-latest:generateContent"; + $candidateUrls[] = "https://generativelanguage.googleapis.com/v1/models/gemini-1.5-flash:generateContent"; + $candidateUrls[] = "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent"; + $candidateUrls[] = "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-001:generateContent"; + $candidateUrls[] = "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-002:generateContent"; + } elseif (str_contains($cleanModel, '1.5-pro')) { + $candidateUrls[] = "https://generativelanguage.googleapis.com/v1/models/gemini-1.5-pro:generateContent"; + $candidateUrls[] = "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-pro-latest:generateContent"; + $candidateUrls[] = "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-pro:generateContent"; + $candidateUrls[] = "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-pro-001:generateContent"; + } elseif (str_contains($cleanModel, '2.0-flash')) { + $candidateUrls[] = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent"; + $candidateUrls[] = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent"; + $candidateUrls[] = "https://generativelanguage.googleapis.com/v1/models/gemini-2.0-flash:generateContent"; + } else { + $candidateUrls[] = "https://generativelanguage.googleapis.com/v1beta/models/{$cleanModel}:generateContent"; + $candidateUrls[] = "https://generativelanguage.googleapis.com/v1/models/{$cleanModel}:generateContent"; + $candidateUrls[] = "https://generativelanguage.googleapis.com/v1beta/models/{$cleanModel}-latest:generateContent"; + } - if ($response['status'] !== 200 || empty($response['json']['candidates'][0]['content']['parts'][0]['text'])) { + $response = null; + $lastError = null; + $successfulModel = $cleanModel; + + foreach ($candidateUrls as $baseUrl) { + $endpoint = $baseUrl . '?key=' . urlencode($apiKey); + $res = fociz_http_request($endpoint, [ + 'method' => 'POST', + 'headers' => [ + 'Content-Type' => 'application/json', + 'x-goog-api-key' => $apiKey, + ], + 'body' => $payload, + 'timeout' => 20, + ]); + + if ($res['status'] === 200 && !empty($res['json']['candidates'][0]['content']['parts'][0]['text'])) { + $response = $res; + if (preg_match('#/models/([^:]+)#', $baseUrl, $mName)) { + $successfulModel = $mName[1]; + } + break; + } + + // Als het een model-not-found 404 fout is, probeer de volgende kandidaat + $msg = $res['json']['error']['message'] ?? ($res['error'] ?? ''); + $lastError = $msg; + if ($res['status'] === 404 || str_contains($msg, 'not found') || str_contains($msg, 'not supported')) { + continue; + } + + // Bij andere fouten (zoals ongeldige sleutel 400/403) direct stoppen + $response = $res; + break; + } + + // Als alle directe kandidaten een 404 gaven, probeer dynamisch via ListModels een passend gemini model te vinden + if (!$response && ($lastError && (str_contains($lastError, 'not found') || str_contains($lastError, 'not supported')))) { + $listUrl = "https://generativelanguage.googleapis.com/v1beta/models?key=" . urlencode($apiKey); + $listRes = fociz_http_request($listUrl, [ + 'method' => 'GET', + 'headers' => ['x-goog-api-key' => $apiKey], + 'timeout' => 10, + ]); + + if ($listRes['status'] === 200 && !empty($listRes['json']['models'])) { + $availModels = []; + foreach ($listRes['json']['models'] as $mItem) { + $mMethods = $mItem['supportedGenerationMethods'] ?? []; + if (in_array('generateContent', $mMethods, true)) { + $mClean = preg_replace('#^models/#', '', $mItem['name'] ?? ''); + if ($mClean) $availModels[] = $mClean; + } + } + + // Zoek een passend gemini model + $fallbackModel = null; + foreach ($availModels as $am) { + if (str_contains($am, 'flash')) { + $fallbackModel = $am; + break; + } + } + if (!$fallbackModel) { + foreach ($availModels as $am) { + if (str_contains($am, 'gemini')) { + $fallbackModel = $am; + break; + } + } + } + + if ($fallbackModel) { + $dynEndpoint = "https://generativelanguage.googleapis.com/v1beta/models/{$fallbackModel}:generateContent?key=" . urlencode($apiKey); + $dynRes = fociz_http_request($dynEndpoint, [ + 'method' => 'POST', + 'headers' => [ + 'Content-Type' => 'application/json', + 'x-goog-api-key' => $apiKey, + ], + 'body' => $payload, + 'timeout' => 20, + ]); + + if ($dynRes['status'] === 200 && !empty($dynRes['json']['candidates'][0]['content']['parts'][0]['text'])) { + $response = $dynRes; + $successfulModel = $fallbackModel; + } else { + $response = $dynRes; + } + } + } + } + + if (!$response || $response['status'] !== 200 || empty($response['json']['candidates'][0]['content']['parts'][0]['text'])) { $errMsg = null; if (!empty($response['json']['error']['message'])) { $errMsg = $response['json']['error']['message']; @@ -160,7 +266,7 @@ function fociz_ai_chat_gemini(array $messages, array $options, array $aiSettings } 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']})"; + $errMsg = $lastError ?: "Gemini API aanroep mislukt"; } error_log("fociz_ai_chat_gemini fout: {$errMsg}"); return [ @@ -191,7 +297,7 @@ function fociz_ai_chat_gemini(array $messages, array $options, array $aiSettings 'success' => true, 'content' => $cleanContent, 'json' => $parsedJson, - 'model' => $model, + 'model' => $successfulModel, 'provider' => 'gemini', ]; }