ai queue repr
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user