Spaces:
Sleeping
Sleeping
| // Main application logic | |
| class ChatAssistant { | |
| constructor() { | |
| this.pipeline = null; | |
| this.isModelLoaded = false; | |
| this.worker = null; | |
| this.messageHistory = []; | |
| this.initializeElements(); | |
| this.setupEventListeners(); | |
| this.loadModel(); | |
| } | |
| initializeElements() { | |
| this.chatMessages = document.getElementById('chatMessages'); | |
| this.userInput = document.getElementById('userInput'); | |
| this.sendButton = document.getElementById('sendButton'); | |
| this.modelStatus = document.getElementById('modelStatus'); | |
| this.progressFill = document.getElementById('progressFill'); | |
| this.progressText = document.getElementById('progressText'); | |
| } | |
| setupEventListeners() { | |
| this.sendButton.addEventListener('click', () => this.sendMessage()); | |
| this.userInput.addEventListener('keypress', (e) => { | |
| if (e.key === 'Enter' && !e.shiftKey) { | |
| e.preventDefault(); | |
| this.sendMessage(); | |
| } | |
| }); | |
| } | |
| async loadModel() { | |
| try { | |
| this.modelStatus.textContent = 'Loading model...'; | |
| this.updateProgress(0, 'Initializing...'); | |
| // Create a Web Worker for model loading | |
| this.worker = new Worker('worker.js'); | |
| // Listen for messages from the worker | |
| this.worker.onmessage = (event) => { | |
| const { type, data, progress } = event.data; | |
| if (type === 'progress') { | |
| this.updateProgress(progress * 100, `Downloading: ${Math.round(progress * 100)}%`); | |
| } else if (type === 'ready') { | |
| this.pipeline = data; | |
| this.isModelLoaded = true; | |
| this.modelStatus.textContent = 'Ready'; | |
| this.updateProgress(100, 'Model loaded!'); | |
| this.addMessage('assistant', 'Hola! I\'m ready to chat. How can I help you today?'); | |
| } else if (type === 'error') { | |
| this.handleError(data); | |
| } | |
| }; | |
| // Start model loading in worker | |
| this.worker.postMessage({ type: 'loadModel' }); | |
| } catch (error) { | |
| this.handleError(error); | |
| } | |
| } | |
| updateProgress(percentage, text) { | |
| this.progressFill.style.width = `${percentage}%`; | |
| this.progressText.textContent = text; | |
| } | |
| async sendMessage() { | |
| const userInput = this.userInput.value.trim(); | |
| if (!userInput || !this.isModelLoaded) return; | |
| // Add user message to chat | |
| this.addMessage('user', userInput); | |
| this.userInput.value = ''; | |
| this.userInput.disabled = true; | |
| this.sendButton.disabled = true; | |
| try { | |
| // Show typing indicator | |
| const typingIndicator = this.addTypingIndicator(); | |
| // Generate response | |
| const response = await this.generateResponse(userInput); | |
| // Remove typing indicator and add response | |
| typingIndicator.remove(); | |
| this.addMessage('assistant', response); | |
| } catch (error) { | |
| this.handleError(error); | |
| this.userInput.disabled = false; | |
| this.sendButton.disabled = false; | |
| } | |
| this.userInput.disabled = false; | |
| this.sendButton.disabled = false; | |
| this.userInput.focus(); | |
| } | |
| async generateResponse(input) { | |
| if (!this.pipeline) { | |
| throw new Error('Model not loaded'); | |
| } | |
| try { | |
| const result = await this.pipeline(input, { | |
| max_new_tokens: 100, | |
| temperature: 0.7, | |
| top_p: 0.9, | |
| do_sample: true, | |
| return_full_text: false | |
| }); | |
| return result[0].generated_text.trim(); | |
| } catch (error) { | |
| throw new Error('Failed to generate response: ' + error.message); | |
| } | |
| } | |
| addMessage(sender, content) { | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = `message ${sender}`; | |
| const messageContent = document.createElement('div'); | |
| messageContent.className = 'message-content'; | |
| messageContent.textContent = content; | |
| messageDiv.appendChild(messageContent); | |
| this.chatMessages.appendChild(messageDiv); | |
| // Scroll to bottom | |
| this.chatMessages.scrollTop = this.chatMessages.scrollHeight; | |
| this.messageHistory.push({ sender, content }); | |
| } | |
| addTypingIndicator() { | |
| const typingDiv = document.createElement('div'); | |
| typingDiv.className = 'message assistant'; | |
| const typingContent = document.createElement('div'); | |
| typingContent.className = 'message-content typing'; | |
| const dots = document.createElement('span'); | |
| dots.textContent = '...'; | |
| typingContent.appendChild(dots); | |
| typingDiv.appendChild(typingContent); | |
| this.chatMessages.appendChild(typingDiv); | |
| this.chatMessages.scrollTop = this.chatMessages.scrollHeight; | |
| return typingDiv; | |
| } | |
| handleError(error) { | |
| console.error('Error:', error); | |
| this.modelStatus.textContent = 'Error'; | |
| this.addMessage('assistant', 'Sorry, I encountered an error. Please try again later.'); | |
| // Show error message to user | |
| const errorMessage = document.createElement('div'); | |
| errorMessage.className = 'error-message'; | |
| errorMessage.textContent = 'An error occurred: ' + error.message; | |
| this.chatMessages.appendChild(errorMessage); | |
| } | |
| } | |
| // Initialize the application when DOM is loaded | |
| document.addEventListener('DOMContentLoaded', () => { | |
| new ChatAssistant(); | |
| }); |