Implement intelligent fallback for AI requests during high demand and rate limiting
This commit is contained in:
+96
-45
@@ -1421,57 +1421,87 @@ async function aiSuggestRoadmapMeta(btn) {
|
||||
if (!firstContent) return;
|
||||
|
||||
const origHtml = btn ? btn.innerHTML : '';
|
||||
if (btn) {
|
||||
btn.innerHTML = '<span class="animate-pulse flex items-center space-x-1"><i data-lucide="loader-2" class="w-3.5 h-3.5 animate-spin"></i><span>Analyseren...</span></span>';
|
||||
btn.disabled = true;
|
||||
if (typeof lucide !== 'undefined') lucide.createIcons();
|
||||
}
|
||||
let attempt = 0;
|
||||
const maxAttempts = 3;
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/ai.php?action=summarize_to_roadmap', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
content: firstContent,
|
||||
session_title: <?= json_encode($session['title']) ?>
|
||||
})
|
||||
});
|
||||
const data = await res.json();
|
||||
if (data.success && data.item) {
|
||||
if (data.item.quarter && document.getElementById('roadmapQuarter')) {
|
||||
document.getElementById('roadmapQuarter').value = data.item.quarter;
|
||||
const executeRequest = async () => {
|
||||
attempt++;
|
||||
if (btn) {
|
||||
btn.innerHTML = `<span class="animate-pulse flex items-center space-x-1"><i data-lucide="loader-2" class="w-3.5 h-3.5 animate-spin"></i><span>${attempt > 1 ? `Wachtrij (${attempt}/${maxAttempts})...` : 'Analyseren...'}</span></span>`;
|
||||
btn.disabled = true;
|
||||
if (typeof lucide !== 'undefined') lucide.createIcons();
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/ai.php?action=summarize_to_roadmap', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
content: firstContent,
|
||||
session_title: <?= json_encode($session['title']) ?>
|
||||
})
|
||||
});
|
||||
const data = await res.json();
|
||||
if (data.success && data.item) {
|
||||
if (data.item.quarter && document.getElementById('roadmapQuarter')) {
|
||||
document.getElementById('roadmapQuarter').value = data.item.quarter;
|
||||
}
|
||||
if (data.item.type && document.getElementById('roadmapType')) {
|
||||
document.getElementById('roadmapType').value = data.item.type;
|
||||
}
|
||||
if (data.item.priority && document.getElementById('roadmapPriority')) {
|
||||
document.getElementById('roadmapPriority').value = data.item.priority;
|
||||
}
|
||||
if (btn) {
|
||||
btn.innerHTML = '<i data-lucide="check" class="w-3.5 h-3.5"></i><span>' + (data.is_fallback ? 'Ingevuld (Standaard)' : 'Ingevuld!') + '</span>';
|
||||
if (typeof lucide !== 'undefined') lucide.createIcons();
|
||||
setTimeout(() => {
|
||||
btn.innerHTML = origHtml;
|
||||
btn.disabled = false;
|
||||
if (typeof lucide !== 'undefined') lucide.createIcons();
|
||||
}, 1800);
|
||||
}
|
||||
} else {
|
||||
const err = (data.error || '').toLowerCase();
|
||||
const isOverloaded = err.includes('demand') || err.includes('druk') || err.includes('spikes') || err.includes('busy') || err.includes('temporarily') || err.includes('quota');
|
||||
|
||||
if (attempt < maxAttempts && isOverloaded) {
|
||||
if (btn) {
|
||||
btn.innerHTML = `<span class="animate-pulse flex items-center space-x-1"><i data-lucide="clock" class="w-3.5 h-3.5"></i><span>Piekdrukte, wachtrij...</span></span>`;
|
||||
if (typeof lucide !== 'undefined') lucide.createIcons();
|
||||
}
|
||||
setTimeout(executeRequest, 2000);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback: vul standaardwaarden in zodat het omzetten altijd kan doorgaan
|
||||
if (document.getElementById('roadmapQuarter') && !document.getElementById('roadmapQuarter').value) {
|
||||
document.getElementById('roadmapQuarter').value = 'Q3';
|
||||
}
|
||||
if (btn) {
|
||||
btn.innerHTML = '<i data-lucide="check" class="w-3.5 h-3.5"></i><span>Ingevuld (Standaard)</span>';
|
||||
if (typeof lucide !== 'undefined') lucide.createIcons();
|
||||
setTimeout(() => {
|
||||
btn.innerHTML = origHtml;
|
||||
btn.disabled = false;
|
||||
if (typeof lucide !== 'undefined') lucide.createIcons();
|
||||
}, 1800);
|
||||
}
|
||||
}
|
||||
if (data.item.type && document.getElementById('roadmapType')) {
|
||||
document.getElementById('roadmapType').value = data.item.type;
|
||||
}
|
||||
if (data.item.priority && document.getElementById('roadmapPriority')) {
|
||||
document.getElementById('roadmapPriority').value = data.item.priority;
|
||||
}
|
||||
if (btn) {
|
||||
btn.innerHTML = '<i data-lucide="check" class="w-3.5 h-3.5"></i><span>Ingevuld!</span>';
|
||||
if (typeof lucide !== 'undefined') lucide.createIcons();
|
||||
setTimeout(() => {
|
||||
} catch(err) {
|
||||
if (attempt < maxAttempts) {
|
||||
setTimeout(executeRequest, 2000);
|
||||
} else {
|
||||
if (btn) {
|
||||
btn.innerHTML = origHtml;
|
||||
btn.disabled = false;
|
||||
if (typeof lucide !== 'undefined') lucide.createIcons();
|
||||
}, 1800);
|
||||
}
|
||||
} else {
|
||||
alert(data.error || 'Kon geen AI advies ophalen');
|
||||
if (btn) {
|
||||
btn.innerHTML = origHtml;
|
||||
btn.disabled = false;
|
||||
if (typeof lucide !== 'undefined') lucide.createIcons();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(err) {
|
||||
alert('Netwerkfout bij aanroepen van AI');
|
||||
if (btn) {
|
||||
btn.innerHTML = origHtml;
|
||||
btn.disabled = false;
|
||||
if (typeof lucide !== 'undefined') lucide.createIcons();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
await executeRequest();
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
@@ -1535,7 +1565,16 @@ async function regenerateBreakdown() {
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchAiBreakdown(content) {
|
||||
async function fetchAiBreakdown(content, attempt = 1, maxAttempts = 3) {
|
||||
const loadingEl = document.getElementById('breakdownLoading');
|
||||
const loadingText = loadingEl ? loadingEl.querySelector('p') : null;
|
||||
|
||||
if (attempt > 1 && loadingText) {
|
||||
loadingText.innerHTML = `<span class="font-bold text-amber-500">⏳ AI Model heeft piekdruk (high demand).</span><br><span class="text-xs text-slate-400">Aanvraag staat in de wachtrij en wordt opnieuw geprobeerd (poging ${attempt}/${maxAttempts})...</span>`;
|
||||
} else if (loadingText) {
|
||||
loadingText.innerHTML = 'AI ontleedt het idee in behapbare taken...';
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/ai.php?action=breakdown_idea', {
|
||||
method: 'POST',
|
||||
@@ -1551,6 +1590,14 @@ async function fetchAiBreakdown(content) {
|
||||
const data = await res.json();
|
||||
|
||||
if (!data.success || !data.items || data.items.length === 0) {
|
||||
const err = (data.error || '').toLowerCase();
|
||||
const isOverloaded = err.includes('demand') || err.includes('druk') || err.includes('spikes') || err.includes('busy') || err.includes('temporarily') || err.includes('quota');
|
||||
|
||||
if (attempt < maxAttempts && isOverloaded) {
|
||||
setTimeout(() => fetchAiBreakdown(content, attempt + 1, maxAttempts), 2500);
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('breakdownLoading').classList.add('hidden');
|
||||
document.getElementById('breakdownError').classList.remove('hidden');
|
||||
document.getElementById('breakdownErrorMsg').innerText = data.error || 'Geen taken gegenereerd door AI.';
|
||||
@@ -1576,6 +1623,10 @@ async function fetchAiBreakdown(content) {
|
||||
document.getElementById('breakdownResult').classList.remove('hidden');
|
||||
if (window.lucide) lucide.createIcons();
|
||||
} catch (err) {
|
||||
if (attempt < maxAttempts) {
|
||||
setTimeout(() => fetchAiBreakdown(content, attempt + 1, maxAttempts), 2500);
|
||||
return;
|
||||
}
|
||||
document.getElementById('breakdownLoading').classList.add('hidden');
|
||||
document.getElementById('breakdownError').classList.remove('hidden');
|
||||
document.getElementById('breakdownErrorMsg').innerText = 'Netwerkfout bij communicatie met AI: ' + err.message;
|
||||
|
||||
Reference in New Issue
Block a user