Spaces:
Runtime error
Runtime error
| // 1. Elements Selection | |
| const box = document.getElementById('chat-box'); | |
| const input = document.getElementById('user-input'); | |
| const btn = document.getElementById('send-btn'); | |
| const statusBadge = document.getElementById('status-badge'); | |
| const statusText = document.getElementById('status-text'); | |
| const themeToggle = document.getElementById('theme-toggle'); | |
| // 2. Professional SVG Icons | |
| const sunIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>`; | |
| const moonIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>`; | |
| // 3. Theme Toggle Logic | |
| function updateToggleIcon(isDark) { | |
| themeToggle.innerHTML = isDark ? moonIcon : sunIcon; | |
| } | |
| themeToggle.onclick = () => { | |
| document.body.classList.toggle('dark-mode'); | |
| updateToggleIcon(document.body.classList.contains('dark-mode')); | |
| }; | |
| // 4. Input Auto-Resize Logic | |
| input.addEventListener('input', function() { | |
| this.style.height = 'auto'; | |
| this.style.height = (this.scrollHeight) + 'px'; | |
| }); | |
| // 5. Messaging Logic | |
| async function sendMessage() { | |
| const msg = input.value.trim(); | |
| if (!msg) return; | |
| // UI Reset | |
| input.value = ''; | |
| input.style.height = 'auto'; | |
| addMessage(msg, 'user'); | |
| // Show "Typing..." Status | |
| statusBadge.className = 'status-badge typing'; | |
| statusText.innerText = 'Typing...'; | |
| // Add Loading Animation Row | |
| const loaderId = 'loader-' + Date.now(); | |
| const loaderRow = document.createElement('div'); | |
| loaderRow.className = 'message-row bot'; | |
| loaderRow.id = loaderId; | |
| loaderRow.innerHTML = `<div class="bubble"><div class="loader"><div class="dot"></div><div class="dot"></div><div class="dot"></div></div></div>`; | |
| box.appendChild(loaderRow); | |
| box.scrollTo({ top: box.scrollHeight, behavior: 'smooth' }); | |
| try { | |
| const res = await fetch('/chat', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ message: msg }) | |
| }); | |
| const data = await res.json(); | |
| // Remove loader and display bot response | |
| document.getElementById(loaderId).remove(); | |
| addMessage(data.response, 'bot'); | |
| } catch (e) { | |
| if (document.getElementById(loaderId)) document.getElementById(loaderId).remove(); | |
| addMessage("Sorry, I'm having trouble connecting to the server.", 'bot'); | |
| } finally { | |
| // Restore "Online" status | |
| statusBadge.className = 'status-badge online'; | |
| statusText.innerText = 'Online'; | |
| } | |
| } | |
| function addMessage(content, role) { | |
| const div = document.createElement('div'); | |
| div.className = `message-row ${role}`; | |
| // Use marked.js for professional Markdown rendering in bot responses | |
| const html = role === 'bot' ? marked.parse(content) : content; | |
| div.innerHTML = `<div class="bubble">${html}</div>`; | |
| box.appendChild(div); | |
| box.scrollTo({ top: box.scrollHeight, behavior: 'smooth' }); | |
| } | |
| // 6. Event Listeners | |
| btn.onclick = sendMessage; | |
| input.onkeydown = (e) => { | |
| // Enter sends message, Shift+Enter adds new line | |
| if (e.key === 'Enter' && !e.shiftKey) { | |
| e.preventDefault(); | |
| sendMessage(); | |
| } | |
| }; | |
| // 7. Initial State | |
| updateToggleIcon(false); | |
| // Pre-parse the initial welcome message | |
| const initialBotMsg = box.querySelector('.bot .bubble'); | |
| if (initialBotMsg) initialBotMsg.innerHTML = marked.parse(initialBotMsg.innerHTML); |