// ======================================== // State // ======================================== const conversationHistory = []; let isStreaming = false; // ======================================== // DOM Elements // ======================================== const chatForm = document.getElementById('chatForm'); const userInput = document.getElementById('userInput'); const sendBtn = document.getElementById('sendBtn'); const chatArea = document.getElementById('chatArea'); const messagesDiv = document.getElementById('messages'); const welcome = document.getElementById('welcome'); const clearBtn = document.getElementById('clearBtn'); const suggestions = document.querySelectorAll('.suggestion'); // ======================================== // Auto-resize textarea // ======================================== userInput.addEventListener('input', () => { userInput.style.height = 'auto'; userInput.style.height = Math.min(userInput.scrollHeight, 150) + 'px'; sendBtn.disabled = !userInput.value.trim() || isStreaming; }); // Enter to send (Shift+Enter for newline) userInput.addEventListener('keydown', (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); if (userInput.value.trim() && !isStreaming) { chatForm.dispatchEvent(new Event('submit')); } } }); // ======================================== // Suggestion Buttons // ======================================== suggestions.forEach(btn => { btn.addEventListener('click', () => { userInput.value = btn.dataset.prompt; userInput.dispatchEvent(new Event('input')); chatForm.dispatchEvent(new Event('submit')); }); }); // ======================================== // Clear Chat // ======================================== clearBtn.addEventListener('click', () => { conversationHistory.length = 0; messagesDiv.innerHTML = ''; welcome.classList.remove('hidden'); userInput.value = ''; userInput.style.height = 'auto'; sendBtn.disabled = true; }); // ======================================== // Create message element // ======================================== function createMessageEl(role, content = '') { const msg = document.createElement('div'); msg.className = `message ${role}`; const avatar = document.createElement('div'); avatar.className = 'message-avatar'; avatar.textContent = role === 'user' ? 'Y' : 'AI'; const body = document.createElement('div'); body.className = 'message-body'; const roleLabel = document.createElement('div'); roleLabel.className = 'message-role'; roleLabel.textContent = role === 'user' ? 'You' : 'Assistant'; const contentDiv = document.createElement('div'); contentDiv.className = 'message-content'; contentDiv.textContent = content; body.appendChild(roleLabel); body.appendChild(contentDiv); msg.appendChild(avatar); msg.appendChild(body); return { msg, contentDiv }; } // ======================================== // Scroll to bottom // ======================================== function scrollToBottom() { chatArea.scrollTo({ top: chatArea.scrollHeight, behavior: 'smooth' }); } // ======================================== // Format text with basic markdown // ======================================== function formatContent(text) { // Escape HTML let html = text .replace(/&/g, '&') .replace(//g, '>'); // Code blocks html = html.replace(/```(\w*)\n([\s\S]*?)```/g, '
$2');
// Inline code
html = html.replace(/`([^`]+)`/g, '$1');
// Bold
html = html.replace(/\*\*(.+?)\*\*/g, '$1');
// Italic
html = html.replace(/\*(.+?)\*/g, '$1');
// Line breaks → paragraphs
html = html
.split(/\n\n+/)
.map(p => `${p.replace(/\n/g, '
')}
${fullResponse}
`; } // Finalize assistantMsg.classList.remove('streaming'); conversationHistory.push({ role: 'assistant', content: fullResponse }); isStreaming = false; sendBtn.disabled = !userInput.value.trim(); scrollToBottom(); });