698 lines
23 KiB
JavaScript
698 lines
23 KiB
JavaScript
class EveAIChatWidget extends HTMLElement {
|
|
static get observedAttributes() {
|
|
return [
|
|
'tenant-id',
|
|
'session-token',
|
|
'language',
|
|
'languages',
|
|
'specialist-id',
|
|
'server-url'
|
|
];
|
|
}
|
|
|
|
constructor() {
|
|
super();
|
|
|
|
// Networking attributes
|
|
this.socket = null; // Initialize socket to null
|
|
this.room = null;
|
|
this.lastRoom = null; // Store last known room
|
|
this.userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone; // Detect user's timezone
|
|
this.heartbeatInterval = null;
|
|
this.idleTime = 0; // in milliseconds
|
|
this.maxConnectionIdleTime = 1 * 60 * 60 * 1000; // 1 hour in milliseconds
|
|
this.reconnectAttempts = 0;
|
|
this.maxReconnectAttempts = 5;
|
|
|
|
// EveAI specific attributes
|
|
this.languages = []
|
|
this.currentLanguage = null;
|
|
this.specialistId = null;
|
|
console.log('EveAIChatWidget constructor called');
|
|
|
|
// Bind methods to ensure correct 'this' context
|
|
this.handleSendMessage = this.handleSendMessage.bind(this);
|
|
this.handleTokenUpdate = this.handleTokenUpdate.bind(this);
|
|
this.updateAttributes = this.updateAttributes.bind(this);
|
|
}
|
|
|
|
connectedCallback() {
|
|
console.log('Chat Widget Connected');
|
|
this.innerHTML = this.getTemplate();
|
|
this.setupElements()
|
|
this.addEventListeners()
|
|
|
|
if (this.areAllAttributesSet()) {
|
|
console.log('All attributes are set, populating language dropdown');
|
|
this.populateLanguageDropdown()
|
|
console.log('All attributes are set, initializing socket');
|
|
this.initializeSocket();
|
|
} else {
|
|
console.warn('Not all required attributes are set yet');
|
|
}
|
|
}
|
|
|
|
setupElements() {
|
|
// Centralizes element querying
|
|
this.messagesArea = this.querySelector('.messages-area');
|
|
this.questionInput = this.querySelector('.question-area textarea');
|
|
this.sendButton = this.querySelector('.send-icon');
|
|
this.languageSelect = this.querySelector('.language-select');
|
|
this.statusLine = this.querySelector('.status-line');
|
|
this.statusMessage = this.querySelector('.status-message');
|
|
this.connectionStatusIcon = this.querySelector('.connection-status-icon');
|
|
}
|
|
|
|
addEventListeners() {
|
|
// Centralized event listener setup
|
|
this.sendButton.addEventListener('click', this.handleSendMessage);
|
|
this.questionInput.addEventListener('keydown', (event) => {
|
|
if (event.key === 'Enter' && !event.shiftKey) {
|
|
event.preventDefault();
|
|
this.handleSendMessage();
|
|
}
|
|
});
|
|
}
|
|
|
|
populateLanguageDropdown() {
|
|
// Clear existing options
|
|
this.languageSelect.innerHTML = '';
|
|
console.log(`languages for options: ${this.languages}`)
|
|
|
|
// Populate with new options
|
|
this.languages.forEach(lang => {
|
|
const option = document.createElement('option');
|
|
option.value = lang;
|
|
option.textContent = lang.toUpperCase();
|
|
if (lang === this.currentLanguage) {
|
|
option.selected = true;
|
|
}
|
|
console.log(`Adding option for language: ${lang}`)
|
|
this.languageSelect.appendChild(option);
|
|
});
|
|
|
|
// Add event listener for language change
|
|
this.languageSelect.addEventListener('change', (e) => {
|
|
this.currentLanguage = e.target.value;
|
|
// You might want to emit an event or update the backend about the language change
|
|
});
|
|
}
|
|
|
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
console.log(`Attribute ${name} changed from ${oldValue} to ${newValue}`);
|
|
|
|
// Handle token updates specially
|
|
if (name === 'session-token' && oldValue !== newValue) {
|
|
this.updateAttributes();
|
|
if (newValue) {
|
|
console.log('Received new session token');
|
|
this.sessionToken = newValue;
|
|
|
|
// If socket exists, reconnect with new token
|
|
if (this.socket) {
|
|
this.socket.disconnect();
|
|
this.initializeSocket();
|
|
} else if (this.areAllAttributesSet()) {
|
|
// Initialize socket if all other attributes are ready
|
|
this.initializeSocket();
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (name === 'languages' || name === 'language') {
|
|
this.updateAttributes();
|
|
this.populateLanguageDropdown();
|
|
return;
|
|
}
|
|
|
|
this.updateAttributes();
|
|
}
|
|
|
|
updateAttributes() {
|
|
this.tenantId = parseInt(this.getAttribute('tenant-id'));
|
|
this.sessionToken = this.getAttribute('session-token');
|
|
this.language = this.getAttribute('language');
|
|
const languageAttr = this.getAttribute('languages');
|
|
this.languages = languageAttr ? languageAttr.split(',') : [];
|
|
this.serverUrl = this.getAttribute('server-url');
|
|
this.currentLanguage = this.language;
|
|
this.specialistId = this.getAttribute('specialist-id');
|
|
console.log('Updated attributes:', {
|
|
tenantId: this.tenantId,
|
|
sessionToken: this.sessionToken,
|
|
language: this.language,
|
|
currentLanguage: this.currentLanguage,
|
|
languages: this.languages,
|
|
serverUrl: this.serverUrl,
|
|
specialistId: this.specialistId
|
|
});
|
|
}
|
|
|
|
areAllAttributesSet() {
|
|
console.log('Checking if all attributes are set:', {
|
|
tenantId: this.tenantId,
|
|
sessionToken: this.sessionToken,
|
|
language: this.language,
|
|
languages: this.languages,
|
|
serverUrl: this.serverUrl,
|
|
specialistId: this.specialistId
|
|
});
|
|
|
|
const requiredAttributes = [
|
|
'tenant-id',
|
|
'session-token',
|
|
'language',
|
|
'languages',
|
|
'specialist-id',
|
|
'server-url'
|
|
];
|
|
|
|
return requiredAttributes.every(attr => this.getAttribute(attr));
|
|
}
|
|
|
|
handleTokenUpdate(newToken) {
|
|
if (this.socket && this.socket.connected) {
|
|
console.log('Updating socket connection with new token');
|
|
// Emit token update event to server
|
|
this.socket.emit('update_token', { token: newToken });
|
|
} else if (newToken && !this.socket) {
|
|
// If we have a new token but no socket, try to initialize
|
|
this.initializeSocket();
|
|
}
|
|
}
|
|
|
|
initializeSocket() {
|
|
console.log(`Initializing socket connection to Evie at ${this.serverUrl}`);
|
|
if (this.socket) {
|
|
console.log('Socket already initialized');
|
|
return;
|
|
}
|
|
|
|
if (!this.sessionToken) {
|
|
console.error('Cannot initialize socket without session token');
|
|
return;
|
|
}
|
|
|
|
this.socket = io(this.serverUrl, {
|
|
path: '/chat/socket.io/',
|
|
transports: ['websocket'],
|
|
query: { // Change from auth to query
|
|
token: this.sessionToken
|
|
},
|
|
reconnectionAttempts: 5, // Infinite reconnection attempts
|
|
reconnectionDelay: 5000, // Delay between reconnections
|
|
timeout: 20000, // Connection timeout
|
|
});
|
|
|
|
if (!this.socket) {
|
|
console.error('Error initializing socket')
|
|
} else {
|
|
console.log('Socket initialized')
|
|
}
|
|
|
|
this.setupSocketEventHandlers();
|
|
}
|
|
|
|
setupSocketEventHandlers() {
|
|
// connect handler --------------------------------------------------------
|
|
this.socket.on('connect', (data) => {
|
|
console.log('Socket connected OK');
|
|
this.setStatusMessage('Connected to EveAI.');
|
|
this.updateConnectionStatus(true);
|
|
this.startHeartbeat();
|
|
|
|
if (data?.room) {
|
|
this.room = data.room;
|
|
this.lastRoom = this.room;
|
|
console.log(`Joined room: ${this.room}`);
|
|
} else {
|
|
console.log('Room information not received on connect');
|
|
}
|
|
});
|
|
|
|
// authenticated handler --------------------------------------------------
|
|
this.socket.on('authenticated', (data) => {
|
|
console.log('Authenticated event received');
|
|
this.setStatusMessage('Authenticated.');
|
|
if (data?.room) {
|
|
this.room = data.room;
|
|
this.lastRoom = this.room;
|
|
console.log(`Confirmed room: ${this.room}`);
|
|
} else {
|
|
console.log('Room information not received on authentication');
|
|
}
|
|
});
|
|
|
|
// Room join handler ------------------------------------------------------
|
|
this.socket.on('room_join', (data) => {
|
|
console.log('Room join event received:', data);
|
|
if (data?.room) {
|
|
this.room = data.room;
|
|
this.lastRoom = this.room;
|
|
console.log(`Joined room: ${this.room}`);
|
|
}
|
|
});
|
|
|
|
// connect-error handler --------------------------------------------------
|
|
this.socket.on('connect_error', (err) => {
|
|
console.error('Socket connection error:', err);
|
|
this.setStatusMessage('Connection Error: EveAI Chat Widget needs further configuration by site administrator.');
|
|
this.updateConnectionStatus(false);
|
|
});
|
|
|
|
// connect-timeout handler ------------------------------------------------
|
|
this.socket.on('connect_timeout', () => {
|
|
console.error('Socket connection timeout');
|
|
this.setStatusMessage('Connection Timeout: EveAI Chat Widget needs further configuration by site administrator.');
|
|
this.updateConnectionStatus(false);
|
|
});
|
|
|
|
// disconnect handler -----------------------------------------------------
|
|
this.socket.on('disconnect', (reason) => {
|
|
console.log('Socket disconnected: ', reason);
|
|
if (reason === 'io server disconnect') {
|
|
// Server disconnected the socket
|
|
this.socket.connect(); // Attempt to reconnect
|
|
}
|
|
this.setStatusMessage('Disconnected from EveAI. Please refresh the page for further interaction.');
|
|
this.updateConnectionStatus(false);
|
|
this.stopHeartbeat();
|
|
this.room = null;
|
|
});
|
|
|
|
// Token related handlers -------------------------------------------------
|
|
this.socket.on('token_expired', () => {
|
|
console.log('Token expired');
|
|
this.setStatusMessage('Session expired. Please refresh the page.');
|
|
this.updateConnectionStatus(false);
|
|
});
|
|
|
|
// reconnect_attempt handler ----------------------------------------------
|
|
this.socket.on('reconnect_attempt', (attemptNumber) => {
|
|
console.log(`Reconnection attempt ${attemptNumber}`);
|
|
this.setStatusMessage(`Reconnecting... (Attempt ${attemptNumber})`);
|
|
this.reconnectAttempts = attemptNumber;
|
|
});
|
|
|
|
// reconnect handler ------------------------------------------------------
|
|
this.socket.on('reconnect', () => {
|
|
console.log('Successfully reconnected to the server');
|
|
this.setStatusMessage('Reconnected to EveAI.');
|
|
this.updateConnectionStatus(true);
|
|
this.startHeartbeat();
|
|
});
|
|
|
|
// reconnect failed -------------------------------------------------------
|
|
this.socket.on('reconnect_failed', () => {
|
|
console.log('Reconnection failed');
|
|
this.setStatusMessage('Unable to reconnect. Please refresh the page.');
|
|
this.handleReconnectFailure();
|
|
});
|
|
|
|
// room rejoin result -----------------------------------------------------
|
|
this.socket.on('room_rejoin_result', (response) => {
|
|
if (response.success) {
|
|
console.log('Successfully rejoined room');
|
|
this.room = response.room;
|
|
this.setStatusMessage('Reconnected successfully.');
|
|
} else {
|
|
console.error('Failed to rejoin room');
|
|
this.handleRoomRejoinFailure();
|
|
}
|
|
});
|
|
|
|
// bot_response handler ---------------------------------------------------
|
|
this.socket.on('bot_response', (data) => {
|
|
console.log('Bot response received: ', data);
|
|
if (data.tenantId === this.tenantId && data?.room === this.room) {
|
|
setTimeout(() => this.startTaskCheck(data.taskId), 1000);
|
|
this.setStatusMessage('Processing...');
|
|
} else {
|
|
console.log('Received message for different room or tenant, ignoring');
|
|
}
|
|
});
|
|
|
|
// task_status handler ----------------------------------------------------
|
|
this.socket.on('task_status', (data) => {
|
|
console.log('Task status received:', data);
|
|
if (!this.room) {
|
|
console.log('No room assigned, cannot process task status');
|
|
return;
|
|
}
|
|
this.handleTaskStatus(data);
|
|
});
|
|
|
|
// Feedback handler -------------------------------------------------------
|
|
this.socket.on('feedback_received', (data) => {
|
|
if (data?.room === this.room) {
|
|
this.setStatusMessage(data.status === 'success' ? 'Feedback recorded.' : 'Failed to record feedback.');
|
|
}
|
|
});
|
|
}
|
|
|
|
attemptRoomRejoin() {
|
|
console.log(`Attempting to rejoin room: ${this.lastRoom}`);
|
|
this.socket.emit('rejoin_room', {
|
|
token: this.sessionToken,
|
|
tenantId: this.tenantId,
|
|
previousRoom: this.lastRoom,
|
|
timestamp: Date.now()
|
|
});
|
|
}
|
|
|
|
handleReconnectFailure() {
|
|
this.room = null;
|
|
this.lastRoom = null;
|
|
this.reconnectAttempts = 0;
|
|
this.updateConnectionStatus(false);
|
|
|
|
// Optionally reload the widget
|
|
if (confirm('Connection lost. Would you like to refresh the chat?')) {
|
|
window.location.reload();
|
|
}
|
|
}
|
|
|
|
handleRoomRejoinFailure() {
|
|
// Clear room state
|
|
this.room = null;
|
|
this.lastRoom = null;
|
|
|
|
// Request new room
|
|
this.socket.emit('request_new_room', {
|
|
token: this.sessionToken,
|
|
tenantId: this.tenantId
|
|
});
|
|
}
|
|
|
|
clearRoomState() {
|
|
// Use when intentionally leaving/clearing a room
|
|
this.room = null;
|
|
this.lastRoom = null;
|
|
this.reconnectAttempts = 0;
|
|
}
|
|
|
|
handleAuthError(error) {
|
|
console.error('Authentication error:', error);
|
|
this.setStatusMessage('Authentication failed. Please refresh the page.');
|
|
this.updateConnectionStatus(false);
|
|
|
|
if (this.socket) {
|
|
this.socket.disconnect();
|
|
}
|
|
}
|
|
|
|
setStatusMessage(message) {
|
|
this.statusMessage.textContent = message;
|
|
}
|
|
|
|
updateConnectionStatus(isConnected) {
|
|
if (isConnected) {
|
|
this.connectionStatusIcon.textContent = 'link';
|
|
this.connectionStatusIcon.classList.remove('status-disconnected');
|
|
this.connectionStatusIcon.classList.add('status-connected');
|
|
} else {
|
|
this.connectionStatusIcon.textContent = 'link_off';
|
|
this.connectionStatusIcon.classList.remove('status-connected');
|
|
this.connectionStatusIcon.classList.add('status-disconnected');
|
|
}
|
|
}
|
|
|
|
startHeartbeat() {
|
|
this.stopHeartbeat(); // Clear any existing interval
|
|
this.heartbeatInterval = setInterval(() => {
|
|
if (this.socket && this.socket.connected) {
|
|
this.socket.emit('heartbeat');
|
|
this.idleTime += 30000;
|
|
if (this.idleTime >= this.maxConnectionIdleTime) {
|
|
this.socket.disconnect();
|
|
this.setStatusMessage('Disconnected due to inactivity.');
|
|
this.updateConnectionStatus(false);
|
|
this.stopHeartbeat();
|
|
}
|
|
}
|
|
}, 30000); // Send a heartbeat every 30 seconds
|
|
}
|
|
|
|
stopHeartbeat() {
|
|
if (this.heartbeatInterval) {
|
|
clearInterval(this.heartbeatInterval);
|
|
this.heartbeatInterval = null;
|
|
}
|
|
}
|
|
|
|
updateProgress() {
|
|
if (!this.statusMessage.textContent) {
|
|
this.statusMessage.textContent = 'Processing...';
|
|
} else {
|
|
this.statusMessage.textContent += '.'; // Append a dot
|
|
}
|
|
}
|
|
|
|
clearProgress() {
|
|
this.statusMessage.textContent = '';
|
|
this.toggleSendButton(false); // Re-enable and revert send button to outlined version
|
|
}
|
|
|
|
checkTaskStatus(taskId) {
|
|
this.updateProgress();
|
|
this.socket.emit('check_task_status', { task_id: taskId });
|
|
}
|
|
|
|
getTemplate() {
|
|
return `
|
|
<div class="chat-container">
|
|
<div class="messages-area"></div>
|
|
<div class="disclaimer">Evie can make mistakes. Please double-check responses.</div>
|
|
<div class="question-area">
|
|
<textarea placeholder="Type your message here..." rows="3"></textarea>
|
|
<div class="right-side">
|
|
<select class="language-select"></select>
|
|
<i class="material-icons send-icon outlined">send</i>
|
|
</div>
|
|
</div>
|
|
<div class="status-line">
|
|
<i class="material-icons connection-status-icon">link_off</i>
|
|
<span class="status-message"></span>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
addUserMessage(text) {
|
|
const message = document.createElement('div');
|
|
message.classList.add('message', 'user');
|
|
message.innerHTML = `<p>${text}</p>`;
|
|
this.messagesArea.appendChild(message);
|
|
this.messagesArea.scrollTop = this.messagesArea.scrollHeight;
|
|
}
|
|
|
|
handleFeedback(feedback, interactionId) {
|
|
// Send feedback to the backend
|
|
console.log('handleFeedback called');
|
|
if (!this.socket) {
|
|
console.error('Socket is not initialized');
|
|
return;
|
|
}
|
|
|
|
if (!this.validateRoom()) {
|
|
console.log("No valid room to handle feedback")
|
|
return;
|
|
}
|
|
|
|
console.log(`Sending feedback for ${interactionId}: ${feedback}`);
|
|
this.socket.emit('feedback', { tenant_id: this.tenantId, token: this.sessionToken, feedback, interactionId, room: this.room });
|
|
this.setStatusMessage('Feedback sent.');
|
|
}
|
|
|
|
addBotMessage(text, interactionId, algorithm = 'default', citations = []) {
|
|
const message = document.createElement('div');
|
|
message.classList.add('message', 'bot');
|
|
|
|
let content = marked.parse(text);
|
|
let citationsHtml = citations.map(url => `<a href="${url}" target="_blank">${url}</a>`).join('<br>');
|
|
|
|
let algorithmClass;
|
|
switch (algorithm) {
|
|
case 'RAG_TENANT':
|
|
algorithmClass = 'fingerprint-rag-tenant';
|
|
break;
|
|
case 'RAG_WIKIPEDIA':
|
|
algorithmClass = 'fingerprint-rag-wikipedia';
|
|
break;
|
|
case 'RAG_GOOGLE':
|
|
algorithmClass = 'fingerprint-rag-google';
|
|
break;
|
|
case 'LLM':
|
|
algorithmClass = 'fingerprint-llm';
|
|
break;
|
|
default:
|
|
algorithmClass = '';
|
|
}
|
|
|
|
message.innerHTML = `
|
|
<p>${content}</p>
|
|
${citationsHtml ? `<p class="citations">${citationsHtml}</p>` : ''}
|
|
<div class="message-icons">
|
|
<i class="material-icons ${algorithmClass}">fingerprint</i>
|
|
<i class="material-icons thumb-icon outlined" data-feedback="up" data-interaction-id="${interactionId}">thumb_up_off_alt</i>
|
|
<i class="material-icons thumb-icon outlined" data-feedback="down" data-interaction-id="${interactionId}">thumb_down_off_alt</i>
|
|
</div>
|
|
`;
|
|
this.messagesArea.appendChild(message);
|
|
|
|
// Add event listeners for feedback buttons
|
|
const thumbsUp = message.querySelector('i[data-feedback="up"]');
|
|
const thumbsDown = message.querySelector('i[data-feedback="down"]');
|
|
thumbsUp.addEventListener('click', () => this.toggleFeedback(thumbsUp, thumbsDown, 'up', interactionId));
|
|
thumbsDown.addEventListener('click', () => this.toggleFeedback(thumbsUp, thumbsDown, 'down', interactionId));
|
|
|
|
this.messagesArea.scrollTop = this.messagesArea.scrollHeight;
|
|
}
|
|
|
|
toggleFeedback(thumbsUp, thumbsDown, feedback, interactionId) {
|
|
console.log('feedback called');
|
|
this.idleTime = 0; // Reset idle time
|
|
if (feedback === 'up') {
|
|
thumbsUp.textContent = 'thumb_up'; // Change to filled icon
|
|
thumbsUp.classList.remove('outlined');
|
|
thumbsUp.classList.add('filled');
|
|
thumbsDown.textContent = 'thumb_down_off_alt'; // Keep the other icon outlined
|
|
thumbsDown.classList.add('outlined');
|
|
thumbsDown.classList.remove('filled');
|
|
} else {
|
|
thumbsDown.textContent = 'thumb_down'; // Change to filled icon
|
|
thumbsDown.classList.remove('outlined');
|
|
thumbsDown.classList.add('filled');
|
|
thumbsUp.textContent = 'thumb_up_off_alt'; // Keep the other icon outlined
|
|
thumbsUp.classList.add('outlined');
|
|
thumbsUp.classList.remove('filled');
|
|
}
|
|
|
|
// Send feedback to the backend
|
|
this.handleFeedback(feedback, interactionId);
|
|
}
|
|
|
|
handleSendMessage() {
|
|
console.log('handleSendMessage called');
|
|
this.idleTime = 0; // Reset idle time
|
|
if (!this.socket?.connected) {
|
|
console.error('Cannot send message: socket not connected');
|
|
this.setStatusMessage('Not connected to server. Please try again.');
|
|
return;
|
|
}
|
|
|
|
if (!this.room) {
|
|
console.error('Cannot send message: no room assigned');
|
|
this.setStatusMessage('Connection not ready. Please wait...');
|
|
// Try to rejoin room if we have a last known room
|
|
if (this.lastRoom) {
|
|
this.attemptRoomRejoin();
|
|
}
|
|
return;
|
|
}
|
|
const message = this.questionInput.value.trim();
|
|
if (message) {
|
|
this.addUserMessage(message);
|
|
this.questionInput.value = '';
|
|
this.sendMessageToBackend(message);
|
|
this.toggleSendButton(true); // Disable and change send button to filled version
|
|
}
|
|
}
|
|
|
|
startTaskCheck(taskId) {
|
|
if (!this.validateRoom()) {
|
|
console.error('Cannot check task status: no room assigned');
|
|
return;
|
|
}
|
|
console.log('Emitting check_task_status for:', taskId);
|
|
this.socket.emit('check_task_status', {
|
|
task_id: taskId,
|
|
token: this.sessionToken,
|
|
tenant_id: this.tenantId,
|
|
room: this.room
|
|
});
|
|
}
|
|
|
|
handleTaskStatus(data) {
|
|
if (data.status === 'pending') {
|
|
this.updateProgress();
|
|
setTimeout(() => this.startTaskCheck(data.taskId), 1000);
|
|
} else if (data.status === 'success') {
|
|
if (data.results) {
|
|
this.addBotMessage(
|
|
data.results.answer,
|
|
data.interaction_id,
|
|
'RAG_TENANT',
|
|
data.results.citations || []
|
|
);
|
|
} else {
|
|
console.error('Missing results in task status response:', data);
|
|
}
|
|
this.clearProgress();
|
|
} else {
|
|
console.error('Task error:', data);
|
|
this.setStatusMessage('Failed to process message.');
|
|
}
|
|
}
|
|
sendMessageToBackend(message) {
|
|
if (!this.socket || !this.room) {
|
|
console.error('Cannot send message: socket or room not available');
|
|
return;
|
|
}
|
|
|
|
if (!this.validateRoom()) {
|
|
return;
|
|
}
|
|
|
|
const selectedLanguage = this.languageSelect.value;
|
|
const messageData = {
|
|
tenant_id: parseInt(this.tenantId),
|
|
token: this.sessionToken,
|
|
specialist_id: parseInt(this.specialistId),
|
|
arguments: {
|
|
language: selectedLanguage,
|
|
query: message
|
|
},
|
|
timezone: this.userTimezone,
|
|
room: this.room
|
|
};
|
|
|
|
console.log('Sending message to backend:', messageData);
|
|
this.socket.emit('user_message', messageData);
|
|
this.setStatusMessage('Processing started ...');
|
|
}
|
|
|
|
toggleSendButton(isProcessing) {
|
|
if (isProcessing) {
|
|
this.sendButton.textContent = 'send'; // Filled send icon
|
|
this.sendButton.classList.remove('outlined');
|
|
this.sendButton.classList.add('filled');
|
|
this.sendButton.classList.add('disabled'); // Add disabled class for styling
|
|
this.sendButton.style.pointerEvents = 'none'; // Disable click events
|
|
} else {
|
|
this.sendButton.textContent = 'send'; // Outlined send icon
|
|
this.sendButton.classList.add('outlined');
|
|
this.sendButton.classList.remove('filled');
|
|
this.sendButton.classList.remove('disabled'); // Remove disabled class
|
|
this.sendButton.style.pointerEvents = 'auto'; // Re-enable click events
|
|
}
|
|
}
|
|
|
|
validateRoom() {
|
|
if (!this.room) {
|
|
console.error('No room assigned');
|
|
this.setStatusMessage('Connection not ready. Please wait...');
|
|
// Try to rejoin room if we have a last known room
|
|
if (this.lastRoom) {
|
|
this.attemptRoomRejoin();
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
customElements.define('eveai-chat-widget', EveAIChatWidget);
|
|
|