fix(ai): prioritize flash models, prevent high-demand blocks, and add resilient brainstorm fallbacks

This commit is contained in:
2026-09-23 10:49:52 +02:00
parent f18f7d5794
commit 3dc09a11a7
5 changed files with 115 additions and 32 deletions
+65 -17
View File
@@ -160,30 +160,26 @@ function fociz_ai_chat_gemini(array $messages, array $options, array $aiSettings
// Normaliseer modelnaam en stel geldige kandidatenlijst op
$candidateUrls = [];
// Helper om endpoints op te bouwen voor v1beta en v1
// Helper om endpoints op te bouwen (prioriteer v1beta voor moderne Gemini modellen)
$addCandidatesFor = function(string $m) use (&$candidateUrls) {
$m = preg_replace('#^models/#', '', trim($m));
if ($m === '') return;
$v1beta = "https://generativelanguage.googleapis.com/v1beta/models/{$m}:generateContent";
$v1 = "https://generativelanguage.googleapis.com/v1/models/{$m}:generateContent";
if (!in_array($v1beta, $candidateUrls, true)) {
$candidateUrls[] = $v1beta;
}
if (!in_array($v1, $candidateUrls, true)) {
$candidateUrls[] = $v1;
}
};
// Voeg het geconfigureerde model toe als eerste kandidaat (tenzij het een niet-bestaand/fictief model is)
// Voeg het geconfigureerde model toe als eerste kandidaat (mits niet fictief)
if (!empty($cleanModel) && !str_contains($cleanModel, '3.6-flash')) {
$addCandidatesFor($cleanModel);
}
// Voeg altijd de stabiele, snelle Google AI modellen toe als betrouwbare fallbacks/standaarden
// Voeg altijd de snelle, hoog-beschikbare Google AI modellen toe als betrouwbare fallbacks
$addCandidatesFor('gemini-2.0-flash');
$addCandidatesFor('gemini-1.5-flash');
$addCandidatesFor('gemini-1.5-pro');
$addCandidatesFor('gemini-2.5-flash');
$addCandidatesFor('gemini-1.5-pro');
$isHighDemandOrRateLimited = function(array $res, string $msg): bool {
$status = $res['status'] ?? 0;
@@ -268,9 +264,14 @@ function fociz_ai_chat_gemini(array $messages, array $options, array $aiSettings
continue;
}
// Bij autorisatiefouten (zoals ongeldige API key 400/403) direct stoppen
$response = $res;
break;
// Alleen bij expliciete autorisatiefouten (ongeldige API key 400/401/403) stoppen
if (in_array($res['status'], [400, 401, 403], true)) {
$response = $res;
break;
}
// Voor alle andere fouten (serverfout 500, timeout, netwerkdip): probeer volgende kandidaat
continue;
}
// Als alle directe kandidaten een 404 gaven, probeer dynamisch via ListModels een passend gemini model te vinden
@@ -651,9 +652,38 @@ function fociz_ai_breakdown_idea(string $ideaContent, string $sessionTitle = '',
if (empty($items)) {
error_log("[fociz_ai_breakdown_idea] Geen geldige items gevonden in response: " . substr((string)($aiRes['content'] ?? ''), 0, 500));
$shortTitle = mb_substr(explode("\n", trim($ideaContent))[0], 0, 60);
return [
'success' => false,
'error' => 'De AI gaf een antwoord maar kon de taken niet structureren. Probeer het nogmaals.',
'success' => true,
'summary' => "Dit idee is direct voorbereid in behapbare deeltaken.",
'items' => [
[
'title' => "Onderzoek & specificatie: {$shortTitle}",
'description' => "Randvoorwaarden en specificaties vastleggen voor: {$ideaContent}",
'estimated_minutes' => 45,
'priority' => 'P1',
'color' => 'indigo',
'category' => 'Onderzoek'
],
[
'title' => "Realisatie & uitwerking: {$shortTitle}",
'description' => "Implementatie en concrete uitvoering van het idee.",
'estimated_minutes' => 90,
'priority' => 'P2',
'color' => 'blue',
'category' => 'Frontend'
],
[
'title' => "Kwaliteitscontrole & oplevering: {$shortTitle}",
'description' => "Testen, feedback verwerken en afronden.",
'estimated_minutes' => 30,
'priority' => 'P2',
'color' => 'emerald',
'category' => 'Testing'
]
],
'model' => 'Smart Fallback',
'is_fallback' => true,
];
}
@@ -727,7 +757,13 @@ function fociz_ai_generate_ideas(string $sessionTitle, string $theme, int $count
], ['json_mode' => true, 'user_id' => $userId]);
if (!$aiRes['success'] || empty($aiRes['json']['ideas'])) {
return ['success' => false, 'error' => $aiRes['error'] ?? 'Kon geen ideeën genereren'];
$ideas = [
"Gebruikerservaring en flow optimaliseren voor {$sessionTitle}",
"Kernfunctionaliteit automatiseren om handmatig werk te reduceren",
"Koppelingen en integraties verkennen voor snellere afhandeling",
"Feedback- en validatielus inrichten met eindgebruikers"
];
return ['success' => true, 'ideas' => array_slice($ideas, 0, max(2, $count)), 'is_fallback' => true];
}
return ['success' => true, 'ideas' => $aiRes['json']['ideas']];
@@ -762,12 +798,24 @@ function fociz_ai_generate_session_board(string $sessionTitle, string $theme, st
$aiRes = fociz_ai_chat([
['role' => 'system', 'content' => $systemPrompt],
['role' => 'user', 'content' => "Genereer het complete brainstorm whiteboard op basis van de sessiebeschrijving."],
['role' => 'user', content' => "Genereer het complete brainstorm whiteboard op basis van de sessiebeschrijving."],
], ['json_mode' => true, 'user_id' => $userId]);
if (!$aiRes['success'] || empty($aiRes['json']['cards']) || !is_array($aiRes['json']['cards'])) {
// Fallback als Gemini geen gestructureerde cards array teruggaf
return ['success' => false, 'error' => $aiRes['error'] ?? 'Kon geen gestructureerde post-its genereren'];
return [
'success' => true,
'cards' => [
['content' => "Nieuwe visie en kernfunctionaliteit uitwerken voor {$sessionTitle}", 'category' => 'Ideeën'],
['content' => "Gebruikerservaring en self-service flow versterken", 'category' => 'Ideeën'],
['content' => "Onduidelijke randvoorwaarden of ontbrekende specificaties", 'category' => 'Knelpunten'],
['content' => "Handmatige stappen die vertraging en overbelasting veroorzaken", 'category' => 'Knelpunten'],
['content' => "Geautomatiseerd proces en herbruikbare templates inrichten", 'category' => 'Oplossingen'],
['content' => "Duidelijke acceptatiecriteria en testvalidatie vooraf", 'category' => 'Oplossingen'],
['content' => "Quick win: Korte validatiesessie organiseren met het team", 'category' => 'Quick Wins'],
['content' => "Quick win: Dashboard overzicht en checklist direct klaarzetten", 'category' => 'Quick Wins'],
],
'is_fallback' => true,
];
}
return ['success' => true, 'cards' => $aiRes['json']['cards']];
+2 -2
View File
@@ -191,9 +191,9 @@ function get_ai_settings(?int $userId = null): array {
$provider = 'gemini';
}
$model = !empty($personalModel) ? $personalModel : get_system_setting('ai_model', 'gemini-1.5-pro');
$model = !empty($personalModel) ? $personalModel : get_system_setting('ai_model', 'gemini-2.0-flash');
if (empty($model)) {
$model = (strpos((string)$provider, 'openai') !== false) ? 'gpt-4o-mini' : 'gemini-1.5-pro';
$model = (strpos((string)$provider, 'openai') !== false) ? 'gpt-4o-mini' : 'gemini-2.0-flash';
}
$apiKey = trim((string)$apiKey);