Improving chat functionality significantly throughout the application.

This commit is contained in:
Josako
2024-06-12 11:07:18 +02:00
parent 27b6de8734
commit be311c440b
22 changed files with 604 additions and 127 deletions

View File

@@ -1,6 +1,6 @@
class EveAIChatWidget extends HTMLElement {
static get observedAttributes() {
return ['tenant-id', 'api-key', 'domain'];
return ['tenant-id', 'api-key', 'domain', 'language'];
}
constructor() {
@@ -16,8 +16,14 @@ class EveAIChatWidget extends HTMLElement {
this.innerHTML = this.getTemplate();
this.messagesArea = this.querySelector('.messages-area');
this.questionInput = this.querySelector('.question-area input');
this.statusLine = this.querySelector('.status-line');
this.querySelector('.question-area button').addEventListener('click', () => this.handleSendMessage());
this.questionInput.addEventListener('keydown', (event) => {
if (event.key === 'Enter') {
this.handleSendMessage();
}
});
if (this.areAllAttributesSet() && !this.socket) {
console.log('Attributes already set in connectedCallback, initializing socket');
@@ -31,7 +37,8 @@ class EveAIChatWidget extends HTMLElement {
console.log('Current attributes:', {
tenantId: this.getAttribute('tenant-id'),
apiKey: this.getAttribute('api-key'),
domain: this.getAttribute('domain')
domain: this.getAttribute('domain'),
language: this.getAttribute('language')
});
if (this.areAllAttributesSet() && !this.socket) {
@@ -46,10 +53,12 @@ class EveAIChatWidget extends HTMLElement {
this.tenantId = this.getAttribute('tenant-id');
this.apiKey = this.getAttribute('api-key');
this.domain = this.getAttribute('domain');
this.language = this.getAttribute('language');
console.log('Updated attributes:', {
tenantId: this.tenantId,
apiKey: this.apiKey,
domain: this.domain
domain: this.domain,
language: this.language
});
}
@@ -57,10 +66,12 @@ class EveAIChatWidget extends HTMLElement {
const tenantId = this.getAttribute('tenant-id');
const apiKey = this.getAttribute('api-key');
const domain = this.getAttribute('domain');
const language = this.getAttribute('language');
console.log('Checking if all attributes are set:', {
tenantId,
apiKey,
domain
domain,
language
});
return tenantId && apiKey && domain;
}
@@ -72,6 +83,7 @@ class EveAIChatWidget extends HTMLElement {
}
if (!this.domain || this.domain === 'null') {
console.error('Domain attribute is missing or invalid');
this.setStatusMessage('EveAI Chat Widget needs further configuration by site administrator.')
return;
}
console.log(`Initializing socket connection to ${this.domain}`);
@@ -91,10 +103,12 @@ class EveAIChatWidget extends HTMLElement {
this.socket.on('connect', (data) => {
console.log('Socket connected');
this.setStatusMessage('Connected to EveAI.')
});
this.socket.on('authenticated', (data) => {
console.log('Authenticated event received: ', data);
this.setStatusMessage('Authenticated.')
if (data.token) {
this.jwtToken = data.token; // Store the JWT token received from the server
}
@@ -102,42 +116,64 @@ class EveAIChatWidget extends HTMLElement {
this.socket.on('connect_error', (err) => {
console.error('Socket connection error:', err);
this.setStatusMessage('EveAI Chat Widget needs further configuration by site administrator.')
});
this.socket.on('connect_timeout', () => {
console.error('Socket connection timeout');
this.setStatusMessage('EveAI Chat Widget needs further configuration by site administrator.')
});
this.socket.on('disconnect', () => {
console.log('Socket disconnected');
this.setStatusMessage('Disconnected from EveAI. Please refresh the page for further interaction.')
});
this.socket.on('bot_response', (data) => {
if (data.tenantId === this.tenantId) {
console.log('Bot response received:', data)
console.log('Initial response received:', data)
console.log('Task ID received:', data.taskId)
this.addMessage(data.message, 'bot', data.messageId, data.algorithm);
this.checkTaskStatus(data.taskId)
this.setStatusMessage('Processing...')
}
});
this.socket.on('task_status', (data) => {
console.log('Task status received:', data)
console.log('Task status received:', data.status)
console.log('Task ID received:', data.taskId)
if (data.status === 'SUCCESS') {
this.addMessage(data.result, 'bot');
} else if (data.status === 'FAILURE') {
this.addMessage('Failed to process message.', 'bot');
} else if (data.status === 'pending') {
console.log('Task is pending')
setTimeout(() => this.checkTaskStatus(data.taskId), 1000); // Poll every second
console.log('New check sent')
console.log('Citations type:', typeof data.citations, 'Citations:', data.citations);
if (data.status === 'pending') {
this.updateProgress();
setTimeout(() => this.checkTaskStatus(data.taskId), 1000); // Poll every second
} else if (data.status === 'success') {
this.addBotMessage(data.answer, data.interaction_id, data.algorithm, data.citations);
this.clearProgress(); // Clear progress indicator when done
} else {
this.setStatusMessage('Failed to process message.');
}
});
}
setStatusMessage(message) {
this.statusLine.textContent = message;
}
updateProgress() {
if (!this.statusLine.textContent) {
this.statusLine.textContent = 'Processing...';
} else {
this.statusLine.textContent += '.'; // Append a dot
}
}
clearProgress() {
this.statusLine.textContent = '';
}
checkTaskStatus(taskId) {
this.socket.emit('check_task_status', { task_id: taskId });
this.updateProgress();
this.socket.emit('check_task_status', { task_id: taskId });
}
getTemplate() {
@@ -148,21 +184,39 @@ class EveAIChatWidget extends HTMLElement {
<input type="text" placeholder="Type your message here..." />
<button>Send</button>
</div>
<div class="status-line"></div>
</div>
`;
}
addMessage(text, type = 'user', id = null, algorithm = 'default') {
addUserMessage(text) {
const message = document.createElement('div');
message.classList.add('message', type);
message.classList.add('message', 'user');
message.innerHTML = `<p>${text}</p>`;
this.messagesArea.appendChild(message);
this.messagesArea.scrollTop = this.messagesArea.scrollHeight;
}
addBotMessage(text, interactionId, algorithm = 'default', citations = []) {
const message = document.createElement('div');
message.classList.add('message', 'bot');
let content = marked.parse(text); // Use marked to convert markdown to HTML
// Ensure citations is an array
if (!Array.isArray(citations)) {
console.error('Expected citations to be an array, but got:', citations);
citations = []; // Default to an empty array
}
let citationsHtml = citations.map(url => `<a href="${url}" target="_blank">${url}</a>`).join('<br>');
message.innerHTML = `
<p>${text}</p>
${type === 'bot' ? `
<div class="message-icons">
<span class="algorithm-indicator" style="background-color: var(--algorithm-color-${algorithm});"></span>
<i class="material-icons" onclick="handleFeedback('${id}', 'up')">thumb_up</i>
<i class="material-icons" onclick="handleFeedback('${id}', 'down')">thumb_down</i>
</div>` : ''}
<p>${content}</p>
${citationsHtml ? `<p>Citations: ${citationsHtml}</p>` : ''}
<div class="message-icons">
<span class="algorithm-indicator" style="background-color: var(--algorithm-color-${algorithm});">${algorithm}</span>
<i class="material-icons" onclick="handleFeedback('up', '${interactionId}')">thumb_up</i>
<i class="material-icons" onclick="handleFeedback('down', '${interactionId}')">thumb_down</i>
</div>
`;
this.messagesArea.appendChild(message);
this.messagesArea.scrollTop = this.messagesArea.scrollHeight;
@@ -172,7 +226,7 @@ class EveAIChatWidget extends HTMLElement {
console.log('handleSendMessage called');
const message = this.questionInput.value.trim();
if (message) {
this.addMessage(message, 'user');
this.addUserMessage(message);
this.questionInput.value = '';
this.sendMessageToBackend(message);
}
@@ -189,14 +243,15 @@ class EveAIChatWidget extends HTMLElement {
return;
}
console.log('Sending message to backend');
this.socket.emit('user_message', { tenantId: this.tenantId, token: this.jwtToken, message });
this.socket.emit('user_message', { tenantId: this.tenantId, token: this.jwtToken, message, language: this.language });
this.setStatusMessage('Processing started ...')
}
}
customElements.define('eveai-chat-widget', EveAIChatWidget);
function handleFeedback(messageId, feedback) {
function handleFeedback(feedback, interactionId) {
// Send feedback to the backend
console.log(`Feedback for ${messageId}: ${feedback}`);
// Implement the actual feedback mechanism
console.log(`Feedback for ${interactionId}: ${feedback}`);
this.socket.emit('feedback', { feedback, interaction_id: interactionId });
}