310 lines
11 KiB
JavaScript
310 lines
11 KiB
JavaScript
export const ProgressTracker = {
|
|
name: 'ProgressTracker',
|
|
props: {
|
|
taskId: {
|
|
type: String,
|
|
required: true
|
|
},
|
|
apiPrefix: {
|
|
type: String,
|
|
default: ''
|
|
}
|
|
},
|
|
emits: ['specialist-complete', 'progress-update', 'specialist-error'],
|
|
data() {
|
|
return {
|
|
isExpanded: false,
|
|
progressLines: [],
|
|
eventSource: null,
|
|
isCompleted: false,
|
|
lastLine: '',
|
|
error: null,
|
|
connecting: true,
|
|
finalAnswer: null,
|
|
hasError: false
|
|
};
|
|
},
|
|
computed: {
|
|
progressEndpoint() {
|
|
return `${this.apiPrefix}/chat/api/task_progress/${this.taskId}`;
|
|
},
|
|
displayLines() {
|
|
return this.isExpanded ? this.progressLines : [
|
|
this.lastLine || 'Verbinden met taak...'
|
|
];
|
|
}
|
|
},
|
|
mounted() {
|
|
this.connectToEventSource();
|
|
},
|
|
beforeUnmount() {
|
|
this.disconnectEventSource();
|
|
},
|
|
methods: {
|
|
connectToEventSource() {
|
|
try {
|
|
this.connecting = true;
|
|
this.error = null;
|
|
|
|
// Sluit eventuele bestaande verbinding
|
|
this.disconnectEventSource();
|
|
|
|
// Maak nieuwe SSE verbinding
|
|
this.eventSource = new EventSource(this.progressEndpoint);
|
|
|
|
// Algemene event handler
|
|
this.eventSource.onmessage = (event) => {
|
|
this.handleProgressUpdate(event);
|
|
};
|
|
|
|
// Specifieke event handlers per type
|
|
this.eventSource.addEventListener('progress', (event) => {
|
|
this.handleProgressUpdate(event, 'progress');
|
|
});
|
|
|
|
this.eventSource.addEventListener('EveAI Specialist Complete', (event) => {
|
|
console.log('Received EveAI Specialist Complete event');
|
|
this.handleProgressUpdate(event, 'EveAI Specialist Complete');
|
|
});
|
|
|
|
this.eventSource.addEventListener('error', (event) => {
|
|
this.handleError(event);
|
|
});
|
|
|
|
// Status handlers
|
|
this.eventSource.onopen = () => {
|
|
this.connecting = false;
|
|
};
|
|
|
|
this.eventSource.onerror = (error) => {
|
|
console.error('SSE Connection error:', error);
|
|
this.error = 'Verbindingsfout. Probeer het later opnieuw.';
|
|
this.connecting = false;
|
|
|
|
// Probeer opnieuw te verbinden na 3 seconden
|
|
setTimeout(() => {
|
|
if (!this.isCompleted && this.progressLines.length === 0) {
|
|
this.connectToEventSource();
|
|
}
|
|
}, 3000);
|
|
};
|
|
} catch (err) {
|
|
console.error('Error setting up event source:', err);
|
|
this.error = 'Kan geen verbinding maken met de voortgangsupdates.';
|
|
this.connecting = false;
|
|
}
|
|
},
|
|
|
|
disconnectEventSource() {
|
|
if (this.eventSource) {
|
|
this.eventSource.close();
|
|
this.eventSource = null;
|
|
}
|
|
},
|
|
|
|
handleProgressUpdate(event, eventType = null) {
|
|
try {
|
|
const update = JSON.parse(event.data);
|
|
|
|
// Controleer op verschillende typen updates
|
|
const processingType = update.processing_type;
|
|
const data = update.data || {};
|
|
|
|
// Process based on processing type
|
|
let message = this.formatProgressMessage(processingType, data);
|
|
|
|
// Alleen bericht toevoegen als er daadwerkelijk een bericht is
|
|
if (message) {
|
|
this.progressLines.push(message);
|
|
this.lastLine = message;
|
|
}
|
|
|
|
// Emit progress update voor parent component
|
|
this.$emit('progress-update', {
|
|
processingType,
|
|
data,
|
|
message
|
|
});
|
|
|
|
// Handle completion and errors
|
|
if (processingType === 'EveAI Specialist Complete') {
|
|
console.log('Processing EveAI Specialist Complete:', data);
|
|
this.handleSpecialistComplete(data);
|
|
} else if (processingType === 'EveAI Specialist Error') {
|
|
this.handleSpecialistError(data);
|
|
} else if (processingType === 'Task Complete' || processingType === 'Task Error') {
|
|
this.isCompleted = true;
|
|
this.disconnectEventSource();
|
|
}
|
|
|
|
// Scroll automatisch naar beneden als uitgevouwen
|
|
if (this.isExpanded) {
|
|
this.$nextTick(() => {
|
|
const container = this.$refs.progressContainer;
|
|
if (container) {
|
|
container.scrollTop = container.scrollHeight;
|
|
}
|
|
});
|
|
}
|
|
} catch (err) {
|
|
console.error('Error parsing progress update:', err, event.data);
|
|
}
|
|
},
|
|
|
|
formatProgressMessage(processingType, data) {
|
|
// Lege data dictionary - toon enkel processing type
|
|
if (!data || Object.keys(data).length === 0) {
|
|
return processingType;
|
|
}
|
|
|
|
// Specifiek bericht als er een message field is
|
|
if (data.message) {
|
|
return data.message;
|
|
}
|
|
|
|
// Processing type met name veld als dat bestaat
|
|
if (data.name) {
|
|
return `${processingType}: ${data.name}`;
|
|
}
|
|
|
|
// Stap informatie
|
|
if (data.step) {
|
|
return `Stap ${data.step}: ${data.description || ''}`;
|
|
}
|
|
|
|
// Voor EveAI Specialist Complete - geen progress message
|
|
if (processingType === 'EveAI Specialist Complete') {
|
|
return null;
|
|
}
|
|
|
|
// Default: processing type + eventueel data als string
|
|
return processingType;
|
|
},
|
|
|
|
handleSpecialistComplete(data) {
|
|
this.isCompleted = true;
|
|
this.disconnectEventSource();
|
|
|
|
// Debug logging
|
|
console.log('Specialist Complete Data:', data);
|
|
|
|
// Extract answer from data.result.answer
|
|
if (data.result && data.result.answer) {
|
|
this.finalAnswer = data.result.answer;
|
|
|
|
console.log('Final Answer:', this.finalAnswer);
|
|
|
|
// Direct update van de parent message als noodoplossing
|
|
try {
|
|
if (this.$parent && this.$parent.message) {
|
|
console.log('Direct update parent message');
|
|
this.$parent.message.content = data.result.answer;
|
|
}
|
|
} catch(err) {
|
|
console.error('Error updating parent message:', err);
|
|
}
|
|
|
|
// Emit event to parent met alle relevante data inclusief form_request
|
|
this.$emit('specialist-complete', {
|
|
answer: data.result.answer,
|
|
form_request: data.result.form_request, // Voeg form_request toe
|
|
result: data.result,
|
|
interactionId: data.interaction_id,
|
|
taskId: this.taskId
|
|
});
|
|
} else {
|
|
console.error('Missing result.answer in specialist complete data:', data);
|
|
}
|
|
},
|
|
|
|
handleSpecialistError(data) {
|
|
this.isCompleted = true;
|
|
this.hasError = true;
|
|
this.disconnectEventSource();
|
|
|
|
// Zet gebruiksvriendelijke foutmelding
|
|
const errorMessage = "We could not process your request. Please try again later.";
|
|
this.error = errorMessage;
|
|
|
|
// Log de werkelijke fout voor debug doeleinden
|
|
if (data.Error) {
|
|
console.error('Specialist Error:', data.Error);
|
|
}
|
|
|
|
// Emit error event naar parent
|
|
this.$emit('specialist-error', {
|
|
message: errorMessage,
|
|
originalError: data.Error,
|
|
taskId: this.taskId
|
|
});
|
|
},
|
|
|
|
handleError(event) {
|
|
console.error('SSE Error event:', event);
|
|
this.error = 'Er is een fout opgetreden bij het verwerken van updates.';
|
|
|
|
// Probeer parse van foutgegevens
|
|
try {
|
|
const errorData = JSON.parse(event.data);
|
|
if (errorData && errorData.message) {
|
|
this.error = errorData.message;
|
|
}
|
|
} catch (err) {
|
|
// Blijf bij algemene foutmelding als parsing mislukt
|
|
}
|
|
},
|
|
|
|
toggleExpand() {
|
|
this.isExpanded = !this.isExpanded;
|
|
|
|
if (this.isExpanded) {
|
|
this.$nextTick(() => {
|
|
const container = this.$refs.progressContainer;
|
|
if (container) {
|
|
container.scrollTop = container.scrollHeight;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
},
|
|
template: `
|
|
<div class="progress-tracker" :class="{ 'expanded': isExpanded, 'completed': isCompleted && !hasError, 'error': error || hasError }">
|
|
<div
|
|
class="progress-header"
|
|
@click="toggleExpand"
|
|
:title="isExpanded ? 'Inklappen' : 'Uitklappen voor volledige voortgang'"
|
|
>
|
|
<div class="progress-title">
|
|
<span v-if="connecting" class="spinner"></span>
|
|
<span v-else-if="error" class="status-icon error">✗</span>
|
|
<span v-else-if="isCompleted" class="status-icon completed">✓</span>
|
|
<span v-else class="status-icon in-progress"></span>
|
|
<span v-if="error">Fout bij verwerking</span>
|
|
<span v-else-if="isCompleted">Verwerking voltooid</span>
|
|
<span v-else>Bezig met redeneren...</span>
|
|
</div>
|
|
<div class="progress-toggle">
|
|
{{ isExpanded ? '▲' : '▼' }}
|
|
</div>
|
|
</div>
|
|
|
|
<div v-if="error" class="progress-error">
|
|
{{ error }}
|
|
</div>
|
|
|
|
<div
|
|
ref="progressContainer"
|
|
class="progress-content"
|
|
:class="{ 'single-line': !isExpanded }"
|
|
>
|
|
<div
|
|
v-for="(line, index) in displayLines"
|
|
:key="index"
|
|
class="progress-line"
|
|
>
|
|
{{ line }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`
|
|
}; |