- Refinement of the chat client to have better visible clues for user vs chatbot messages

- Introduction of interview_phase and normal phase in TRAICIE_SELECTION_SPECIALIST to make interaction with bot more human.
- More and random humanised messages to TRAICIE_SELECTION_SPECIALIST
This commit is contained in:
Josako
2025-08-02 16:36:41 +02:00
parent 998ddf4c03
commit 9a88582fff
50 changed files with 2064 additions and 384 deletions

View File

@@ -7,32 +7,35 @@
<slot name="loading"></slot>
</div>
<!-- Empty state -->
<div v-if="normalMessages.length === 0" class="empty-state">
<div class="empty-icon">💬</div>
<div class="empty-text">Nog geen berichten</div>
<div class="empty-subtext">Start een gesprek door een bericht te typen!</div>
</div>
<!-- Normal message list (excluding temporarily positioned AI messages) -->
<template v-if="normalMessages.length > 0">
<!-- Messages -->
<template v-for="(message, index) in normalMessages" :key="message.id">
<!-- The actual message -->
<chat-message
:message="message"
:is-submitting-form="isSubmittingForm"
:api-prefix="apiPrefix"
:is-latest-ai-message="isLatestAiMessage(message)"
@image-loaded="handleImageLoaded"
@specialist-complete="$emit('specialist-complete', $event)"
@specialist-error="$emit('specialist-error', $event)"
></chat-message>
<!-- Messages wrapper for bottom alignment -->
<div class="messages-wrapper">
<!-- Empty state (only show when no messages) -->
<div v-if="normalMessages.length === 0" class="empty-state">
<div class="empty-icon">💬</div>
<div class="empty-text">Nog geen berichten</div>
<div class="empty-subtext">Start een gesprek door een bericht te typen!</div>
</div>
<!-- Normal message list (excluding temporarily positioned AI messages) -->
<template v-if="normalMessages.length > 0">
<!-- Messages -->
<template v-for="(message, index) in normalMessages" :key="message.id">
<!-- The actual message -->
<chat-message
:message="message"
:is-submitting-form="isSubmittingForm"
:api-prefix="apiPrefix"
:is-latest-ai-message="isLatestAiMessage(message)"
@image-loaded="handleImageLoaded"
@specialist-complete="$emit('specialist-complete', $event)"
@specialist-error="$emit('specialist-error', $event)"
></chat-message>
</template>
</template>
</template>
<!-- Typing indicator -->
<typing-indicator v-if="isTyping"></typing-indicator>
<!-- Typing indicator -->
<typing-indicator v-if="isTyping"></typing-indicator>
</div>
</div>
</div>
@@ -96,14 +99,20 @@ export default {
watch: {
messages: {
handler(newMessages, oldMessages) {
// Auto-scroll when new messages are added
if (this.autoScroll && newMessages.length > (oldMessages?.length || 0)) {
const hasNewMessages = newMessages.length > (oldMessages?.length || 0);
// Always auto-scroll when new messages are added (regardless of current scroll position)
if (this.autoScroll && hasNewMessages) {
// Double $nextTick for better DOM update synchronization
this.$nextTick(() => {
this.scrollToBottom();
this.$nextTick(() => {
this.scrollToBottom(true);
});
});
}
},
deep: true
deep: true,
immediate: false
},
isTyping(newVal) {
if (newVal && this.autoScroll) {
@@ -188,13 +197,16 @@ export default {
}
},
scrollToBottom() {
scrollToBottom(force = false) {
const container = this.$refs.messagesContainer;
if (container) {
container.scrollTop = container.scrollHeight;
this.isAtBottom = true;
this.showScrollButton = false;
this.unreadCount = 0;
// Use requestAnimationFrame for better timing
requestAnimationFrame(() => {
container.scrollTop = container.scrollHeight;
this.isAtBottom = true;
this.showScrollButton = false;
this.unreadCount = 0;
});
}
},
@@ -209,7 +221,7 @@ export default {
const container = this.$refs.messagesContainer;
if (!container) return;
const threshold = 100; // pixels from bottom
const threshold = 50; // Reduced threshold for better detection
const isNearBottom = container.scrollHeight - container.scrollTop - container.clientHeight < threshold;
this.isAtBottom = isNearBottom;
@@ -221,7 +233,7 @@ export default {
},
handleImageLoaded() {
// Auto-scroll when images load to maintain position
// Auto-scroll when img load to maintain position
if (this.isAtBottom) {
this.$nextTick(() => this.scrollToBottom());
}
@@ -273,8 +285,19 @@ export default {
overflow-y: auto;
padding: 10px;
scroll-behavior: smooth;
/* Bottom-aligned messages implementation */
display: flex;
flex-direction: column;
justify-content: flex-end;
min-height: 100%;
}
.messages-wrapper {
display: flex;
flex-direction: column;
gap: 10px; /* Space between messages */
}
.load-more-indicator {
text-align: center;