ai queue repr

This commit is contained in:
overcuriousity
2025-07-26 14:33:51 +02:00
parent d2fdeccce3
commit 69fc97f7a0
5 changed files with 371 additions and 137 deletions

View File

@@ -81,7 +81,8 @@ const domainAgnosticSoftware = data['domain-agnostic-software'] || [];
</div>
</div>
</div>
<!-- This should be your loading section in AIQueryInterface.astro -->
<!-- Loading State -->
<div id="ai-loading" class="ai-loading" style="display: none; text-align: center; padding: 2rem;">
<div style="display: inline-block; margin-bottom: 1rem;">
@@ -92,6 +93,32 @@ const domainAgnosticSoftware = data['domain-agnostic-software'] || [];
</svg>
</div>
<p id="loading-text" style="color: var(--color-text-secondary);">Analysiere Szenario und generiere Empfehlungen...</p>
<!-- Queue Status Display - THIS SECTION SHOULD BE PRESENT -->
<div id="queue-status" style="margin-top: 1rem; padding: 1rem; background-color: var(--color-bg-secondary); border-radius: 0.5rem; border: 1px solid var(--color-border); display: none;">
<div style="display: flex; align-items: center; justify-content: center; gap: 1rem; margin-bottom: 0.75rem;">
<div style="display: flex; align-items: center; gap: 0.5rem;">
<div id="queue-position-badge" style="width: 24px; height: 24px; background-color: var(--color-primary); color: white; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 0.875rem;">1</div>
<span style="font-weight: 500;">Position in Warteschlange</span>
</div>
</div>
<div style="font-size: 0.875rem; color: var(--color-text-secondary); text-align: center;">
<div id="queue-length-info" style="margin-bottom: 0.5rem;">
<span id="queue-length">0</span> Anfrage(n) in der Warteschlange
</div>
<div id="estimated-time-info">
Geschätzte Wartezeit: <span id="estimated-time">--</span>
</div>
<div id="task-id-info" style="margin-top: 0.5rem; font-family: monospace; font-size: 0.75rem; opacity: 0.7;">
Task-ID: <span id="current-task-id">--</span>
</div>
</div>
<!-- Progress bar -->
<div style="margin-top: 1rem; background-color: var(--color-bg-tertiary); border-radius: 0.25rem; height: 4px; overflow: hidden;">
<div id="queue-progress" style="height: 100%; background-color: var(--color-primary); width: 0%; transition: width 0.3s ease;"></div>
</div>
</div>
</div>
<!-- Error State -->
@@ -240,86 +267,161 @@ document.addEventListener('DOMContentLoaded', () => {
aiInput.addEventListener('input', updateCharacterCount);
updateCharacterCount();
// Submit handler
const handleSubmit = async () => {
const query = aiInput.value.trim();
if (!query) {
alert('Bitte geben Sie eine Beschreibung ein.');
return;
}
if (query.length < 10) {
alert('Bitte geben Sie eine detailliertere Beschreibung ein (mindestens 10 Zeichen).');
return;
}
// Hide previous results and errors
aiResults.style.display = 'none';
aiError.style.display = 'none';
aiLoading.style.display = 'block';
// Disable submit button
aiSubmitBtn.disabled = true;
submitBtnText.textContent = currentMode === 'workflow' ? 'Generiere Empfehlungen...' : 'Suche passende Methode...';
try {
const response = await fetch('/api/ai/query', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query,
mode: currentMode
})
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || `HTTP ${response.status}`);
}
if (!data.success) {
throw new Error(data.error || 'Unknown error');
}
// Store recommendation for restoration
currentRecommendation = data.recommendation;
// Submit handler with enhanced queue feedback
const handleSubmit = async () => {
const query = aiInput.value.trim();
// Display results based on mode
if (currentMode === 'workflow') {
displayWorkflowResults(data.recommendation, query);
} else {
displayToolResults(data.recommendation, query);
if (!query) {
alert('Bitte geben Sie eine Beschreibung ein.');
return;
}
if (query.length < 10) {
alert('Bitte geben Sie eine detailliertere Beschreibung ein (mindestens 10 Zeichen).');
return;
}
// Generate task ID for tracking
const taskId = `ai_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`;
// Hide previous results and errors
aiResults.style.display = 'none';
aiError.style.display = 'none';
aiLoading.style.display = 'block';
// Show queue status section
const queueStatus = document.getElementById('queue-status');
const taskIdDisplay = document.getElementById('current-task-id');
if (queueStatus && taskIdDisplay) {
queueStatus.style.display = 'block';
taskIdDisplay.textContent = taskId;
}
aiLoading.style.display = 'none';
aiResults.style.display = 'block';
// Disable submit button
aiSubmitBtn.disabled = true;
submitBtnText.textContent = currentMode === 'workflow' ? 'Generiere Empfehlungen...' : 'Suche passende Methode...';
} catch (error) {
console.error('AI query failed:', error);
aiLoading.style.display = 'none';
aiError.style.display = 'block';
// Start queue status polling
let statusInterval;
let startTime = Date.now();
// Show user-friendly error messages
if (error.message.includes('429')) {
aiErrorMessage.textContent = 'Zu viele Anfragen. Bitte warten Sie einen Moment und versuchen Sie es erneut.';
} else if (error.message.includes('401')) {
aiErrorMessage.textContent = 'Authentifizierung erforderlich. Bitte melden Sie sich an.';
} else if (error.message.includes('503')) {
aiErrorMessage.textContent = 'KI-Service vorübergehend nicht verfügbar. Bitte versuchen Sie es später erneut.';
} else {
aiErrorMessage.textContent = `Fehler: ${error.message}`;
const updateQueueStatus = async () => {
try {
const response = await fetch(`/api/ai/queue-status?taskId=${taskId}`);
const data = await response.json();
if (data.success) {
const queueLength = document.getElementById('queue-length');
const estimatedTime = document.getElementById('estimated-time');
const positionBadge = document.getElementById('queue-position-badge');
const progressBar = document.getElementById('queue-progress');
if (queueLength) queueLength.textContent = data.queueLength;
if (estimatedTime) {
if (data.estimatedWaitTime > 0) {
estimatedTime.textContent = formatDuration(data.estimatedWaitTime);
} else {
estimatedTime.textContent = 'Verarbeitung läuft...';
}
}
if (positionBadge && data.currentPosition) {
positionBadge.textContent = data.currentPosition;
// Update progress bar (inverse of position)
if (progressBar && data.queueLength > 0) {
const progress = Math.max(0, ((data.queueLength - data.currentPosition + 1) / data.queueLength) * 100);
progressBar.style.width = `${progress}%`;
}
}
// If processing and no position (request is being handled)
if (data.isProcessing && !data.currentPosition) {
if (positionBadge) positionBadge.textContent = '⚡';
if (progressBar) progressBar.style.width = '100%';
if (estimatedTime) estimatedTime.textContent = 'Verarbeitung läuft...';
}
}
} catch (error) {
console.warn('Queue status update failed:', error);
}
};
// Initial status update
updateQueueStatus();
// Poll every 500ms for status updates
statusInterval = setInterval(updateQueueStatus, 500);
try {
const response = await fetch('/api/ai/query', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query,
mode: currentMode,
taskId // Include task ID for backend tracking
})
});
const data = await response.json();
// Clear status polling
if (statusInterval) clearInterval(statusInterval);
if (!response.ok) {
throw new Error(data.error || `HTTP ${response.status}`);
}
if (!data.success) {
throw new Error(data.error || 'Unknown error');
}
// Store recommendation for restoration
currentRecommendation = data.recommendation;
// Display results based on mode
if (currentMode === 'workflow') {
displayWorkflowResults(data.recommendation, query);
} else {
displayToolResults(data.recommendation, query);
}
aiLoading.style.display = 'none';
aiResults.style.display = 'block';
} catch (error) {
console.error('AI query failed:', error);
// Clear status polling
if (statusInterval) clearInterval(statusInterval);
aiLoading.style.display = 'none';
aiError.style.display = 'block';
// Show user-friendly error messages
if (error.message.includes('429')) {
aiErrorMessage.textContent = 'Zu viele Anfragen. Bitte warten Sie einen Moment und versuchen Sie es erneut.';
} else if (error.message.includes('401')) {
aiErrorMessage.textContent = 'Authentifizierung erforderlich. Bitte melden Sie sich an.';
} else if (error.message.includes('503')) {
aiErrorMessage.textContent = 'KI-Service vorübergehend nicht verfügbar. Bitte versuchen Sie es später erneut.';
} else {
aiErrorMessage.textContent = `Fehler: ${error.message}`;
}
} finally {
// Re-enable submit button and hide queue status
aiSubmitBtn.disabled = false;
const config = modeConfig[currentMode];
submitBtnText.textContent = config.submitText;
if (queueStatus) queueStatus.style.display = 'none';
if (statusInterval) clearInterval(statusInterval);
}
} finally {
// Re-enable submit button
aiSubmitBtn.disabled = false;
const config = modeConfig[currentMode];
submitBtnText.textContent = config.submitText;
}
};
};
// Event listeners
aiSubmitBtn.addEventListener('click', handleSubmit);