Spaces:
Sleeping
Sleeping
| class ChatInterface { | |
| constructor() { | |
| this.messagesContainer = document.getElementById('chatMessages'); | |
| this.messageInput = document.getElementById('messageInput'); | |
| this.sendButton = document.getElementById('sendButton'); | |
| this.typingIndicator = document.getElementById('typingIndicator'); | |
| this.quickReplies = document.getElementById('quickReplies'); | |
| this.isTyping = false; | |
| this.conversationStarted = false; | |
| this.init(); | |
| } | |
| init() { | |
| this.setupEventListeners(); | |
| this.startConversation(); | |
| this.adjustTextareaHeight(); | |
| } | |
| setupEventListeners() { | |
| // Send button click | |
| this.sendButton.addEventListener('click', () => this.sendMessage()); | |
| // Enter key to send (Shift+Enter for new line) | |
| this.messageInput.addEventListener('keydown', (e) => { | |
| if (e.key === 'Enter' && !e.shiftKey) { | |
| e.preventDefault(); | |
| this.sendMessage(); | |
| } | |
| }); | |
| // Auto-resize textarea | |
| this.messageInput.addEventListener('input', () => this.adjustTextareaHeight()); | |
| // Quick reply clicks | |
| this.quickReplies.addEventListener('click', (e) => { | |
| if (e.target.classList.contains('quick-reply')) { | |
| this.sendQuickReply(e.target.textContent); | |
| } | |
| }); | |
| } | |
| adjustTextareaHeight() { | |
| this.messageInput.style.height = 'auto'; | |
| this.messageInput.style.height = Math.min(this.messageInput.scrollHeight, 100) + 'px'; | |
| } | |
| async startConversation() { | |
| await this.delay(2000); | |
| const welcomeMessage = "Hello! 👋 I'm your AI assistant calling on behalf of a client who is interested in making a reservation to visit your apartment. Could you please tell me which apartment you'd like to schedule a viewing for?"; | |
| await this.addBotMessage(welcomeMessage); | |
| await this.delay(2000); | |
| this.showQuickReplies([ | |
| "Apartment A - 2BR/1BA", | |
| "Apartment B - 3BR/2BA", | |
| "Apartment C - 1BR/1BA", | |
| "I have multiple units" | |
| ]); | |
| this.conversationStarted = true; | |
| } | |
| async sendMessage() { | |
| const message = this.messageInput.value.trim(); | |
| if (!message || this.isTyping) return; | |
| this.addUserMessage(message); | |
| this.messageInput.value = ''; | |
| this.adjustTextareaHeight(); | |
| this.hideQuickReplies(); | |
| // Simulate AI processing | |
| await this.showTyping(); | |
| const response = await this.generateResponse(message); | |
| await this.addBotMessage(response.message); | |
| await this.delay(2000); | |
| if (response.quickReplies) { | |
| this.showQuickReplies(response.quickReplies); | |
| } | |
| } | |
| async sendQuickReply(reply) { | |
| this.addUserMessage(reply); | |
| this.hideQuickReplies(); | |
| await this.showTyping(); | |
| const response = await this.generateResponse(reply); | |
| await this.addBotMessage(response.message); | |
| await this.delay(2000); | |
| if (response.quickReplies) { | |
| this.showQuickReplies(response.quickReplies); | |
| } | |
| } | |
| async generateResponse(userMessage) { | |
| try { | |
| const response = await fetch('/chat', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify({ | |
| message: userMessage, | |
| conversation_history: this.getConversationHistory() | |
| }) | |
| }); | |
| if (!response.ok) { | |
| throw new Error(`HTTP error! status: ${response.status}`); | |
| } | |
| const data = await response.json(); | |
| return { | |
| message: data.message, | |
| quickReplies: data.quick_replies || [] | |
| }; | |
| } catch (error) { | |
| console.error('Error calling chat API:', error); | |
| // Fallback response if API fails | |
| return { | |
| message: "I apologize, but I'm having trouble connecting right now. Could you please try again in a moment?", | |
| quickReplies: ["Try again", "Contact support"] | |
| }; | |
| } | |
| } | |
| getConversationHistory() { | |
| const messages = this.messagesContainer.querySelectorAll('.message'); | |
| const history = []; | |
| messages.forEach(messageEl => { | |
| const isBot = messageEl.classList.contains('message-bot'); | |
| const content = messageEl.querySelector('.message-content').textContent; | |
| history.push({ | |
| role: isBot ? 'assistant' : 'user', | |
| content: content | |
| }); | |
| }); | |
| return history; | |
| } | |
| addUserMessage(message) { | |
| const messageElement = this.createMessageElement('user', message); | |
| this.messagesContainer.appendChild(messageElement); | |
| this.scrollToBottom(); | |
| } | |
| async addBotMessage(message) { | |
| const messageElement = this.createMessageElement('bot', message); | |
| this.messagesContainer.appendChild(messageElement); | |
| this.scrollToBottom(); | |
| this.hideTyping(); | |
| } | |
| createMessageElement(sender, content) { | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = `message message-${sender}`; | |
| const avatar = document.createElement('div'); | |
| avatar.className = `avatar avatar-${sender}`; | |
| avatar.innerHTML = sender === 'bot' ? '<i class="fas fa-robot"></i>' : '<i class="fas fa-user"></i>'; | |
| const contentDiv = document.createElement('div'); | |
| contentDiv.className = 'message-content'; | |
| contentDiv.textContent = content; | |
| messageDiv.appendChild(avatar); | |
| messageDiv.appendChild(contentDiv); | |
| return messageDiv; | |
| } | |
| async showTyping() { | |
| this.isTyping = true; | |
| this.sendButton.disabled = true; | |
| this.typingIndicator.style.display = 'flex'; | |
| this.scrollToBottom(); | |
| } | |
| hideTyping() { | |
| this.isTyping = false; | |
| this.sendButton.disabled = false; | |
| this.typingIndicator.style.display = 'none'; | |
| } | |
| showQuickReplies(replies) { | |
| this.quickReplies.innerHTML = ''; | |
| replies.forEach(reply => { | |
| const button = document.createElement('button'); | |
| button.className = 'quick-reply'; | |
| button.textContent = reply; | |
| this.quickReplies.appendChild(button); | |
| }); | |
| this.quickReplies.style.display = 'flex'; | |
| } | |
| hideQuickReplies() { | |
| this.quickReplies.style.display = 'none'; | |
| } | |
| scrollToBottom() { | |
| setTimeout(() => { | |
| this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight; | |
| }, 100); | |
| } | |
| delay(ms) { | |
| return new Promise(resolve => setTimeout(resolve, ms)); | |
| } | |
| } | |
| // Initialize the chat interface when the page loads | |
| document.addEventListener('DOMContentLoaded', () => { | |
| new ChatInterface(); | |
| }); | |
| // Add some smooth animations and interactions | |
| document.addEventListener('DOMContentLoaded', () => { | |
| // Add hover effects to messages | |
| document.addEventListener('mouseover', (e) => { | |
| if (e.target.closest('.message')) { | |
| e.target.closest('.message').style.transform = 'translateY(-1px)'; | |
| } | |
| }); | |
| document.addEventListener('mouseout', (e) => { | |
| if (e.target.closest('.message')) { | |
| e.target.closest('.message').style.transform = 'translateY(0)'; | |
| } | |
| }); | |
| // Add some visual feedback for the send button | |
| const sendButton = document.getElementById('sendButton'); | |
| sendButton.addEventListener('mousedown', () => { | |
| sendButton.style.transform = 'scale(0.95)'; | |
| }); | |
| sendButton.addEventListener('mouseup', () => { | |
| sendButton.style.transform = 'scale(1)'; | |
| }); | |
| }); |