let debounceTimer; const DEBOUNCE_DELAY = 300; let isDebugMode = { chat: false, summary: false }; document.addEventListener('DOMContentLoaded', () => { setupTabNavigation(); setupChatPredictions(); setupSummaryPredictions(); setupImageUpload(); initializeChatInterface(); }); function setupTabNavigation() { const navItems = document.querySelectorAll('.nav-item'); navItems.forEach(item => { item.addEventListener('click', (e) => { e.preventDefault(); navItems.forEach(i => i.classList.remove('active')); item.classList.add('active'); const tabId = item.getAttribute('data-tab'); document.querySelectorAll('.tab-content').forEach(tab => { tab.classList.remove('active'); }); document.getElementById(tabId).classList.add('active'); }); }); } function initializeChatInterface() { const chatOutput = document.getElementById('chat-output'); chatOutput.innerHTML = `
`; } function setupChatPredictions() { const chatInput = document.getElementById('chat-input'); const toggleDebug = document.querySelector('#chat .toggle-debug'); const wordPredictions = document.querySelector('#chat .word-predictions'); toggleDebug.addEventListener('click', () => { isDebugMode.chat = !isDebugMode.chat; wordPredictions.style.display = isDebugMode.chat ? 'block' : 'none'; toggleDebug.classList.toggle('active'); }); chatInput.addEventListener('input', () => { clearTimeout(debounceTimer); debounceTimer = setTimeout(() => { if (isDebugMode.chat) { const words = chatInput.value.split(/\s+/); if (words.length > 0) { const lastWord = words[words.length - 1]; getPredictions(lastWord, 'chat'); } } }, DEBOUNCE_DELAY); }); } function setupSummaryPredictions() { const summaryInput = document.getElementById('summary-input'); const toggleDebug = document.querySelector('#summary .toggle-debug'); const wordPredictions = document.querySelector('#summary .word-predictions'); toggleDebug.addEventListener('click', () => { isDebugMode.summary = !isDebugMode.summary; wordPredictions.style.display = isDebugMode.summary ? 'block' : 'none'; toggleDebug.classList.toggle('active'); }); summaryInput.addEventListener('input', () => { clearTimeout(debounceTimer); debounceTimer = setTimeout(() => { if (isDebugMode.summary) { const words = summaryInput.value.split(/\s+/); if (words.length > 0) { const lastWord = words[words.length - 1]; getPredictions(lastWord, 'summary'); } } }, DEBOUNCE_DELAY); }); } async function getPredictions(word, section) { try { const response = await fetch('/predict_words', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ word: word }) }); const predictions = await response.json(); displayPredictions(predictions, section); } catch (error) { console.error('Error getting predictions:', error); } } function displayPredictions(predictions, section) { const predictionsContent = document.querySelector(`#${section} .predictions-content`); predictionsContent.innerHTML = ''; predictions.forEach((pred, index) => { const predictionItem = document.createElement('div'); predictionItem.className = 'prediction-item'; predictionItem.innerHTML = ` ${index + 1}. ${pred.word} ${(pred.probability * 100).toFixed(2)}% `; predictionsContent.appendChild(predictionItem); }); } async function sendMessage() { const input = document.getElementById('chat-input'); const message = input.value.trim(); if (!message) return; // Add user message to chat const chatOutput = document.getElementById('chat-output'); const userMessage = document.createElement('div'); userMessage.className = 'message user'; userMessage.textContent = message; chatOutput.appendChild(userMessage); // Show loading document.getElementById('loading').classList.add('show'); try { const response = await fetch('/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ message: message }) }); const data = await response.json(); const botMessage = document.createElement('div'); botMessage.className = 'message assistant'; // If the server returned per-token info, render tokens individually so we // can show alternative tokens on hover. Otherwise, fall back to plain text. if (data.tokens && Array.isArray(data.tokens) && data.tokens.length > 0) { const frag = document.createDocumentFragment(); const wrapper = document.createElement('div'); wrapper.className = 'generated-text'; data.tokens.forEach((t, idx) => { const span = document.createElement('span'); span.className = 'generated-token'; span.setAttribute('data-token-index', idx); span.textContent = t.token || ''; // store alternatives on the element for quick access span._alternatives = t.alternatives || []; wrapper.appendChild(span); }); frag.appendChild(wrapper); botMessage.appendChild(frag); chatOutput.appendChild(botMessage); // Tooltip element for showing alternatives let tooltip = document.getElementById('alt-tooltip'); if (!tooltip) { tooltip = document.createElement('div'); tooltip.id = 'alt-tooltip'; tooltip.className = 'alt-tooltip'; document.body.appendChild(tooltip); } // Attach hover listeners wrapper.querySelectorAll('.generated-token').forEach(el => { el.addEventListener('mouseenter', (ev) => { const alts = el._alternatives || []; if (!alts.length) return; // build tooltip html tooltip.innerHTML = ''; const title = document.createElement('div'); title.className = 'alt-title'; title.textContent = 'Alternatives'; tooltip.appendChild(title); alts.forEach(a => { const row = document.createElement('div'); row.className = 'alt-row'; const tok = document.createElement('span'); tok.className = 'alt-token'; tok.textContent = a.token || ''; const prob = document.createElement('span'); prob.className = 'alt-prob'; prob.textContent = `${(a.probability * 100).toFixed(2)}%`; row.appendChild(tok); row.appendChild(prob); // click to insert token into input (optional UX) row.addEventListener('click', () => { const chatInput = document.getElementById('chat-input'); insertAtCursor(chatInput, a.token || ''); }); tooltip.appendChild(row); }); // Position tooltip near the hovered token const rect = el.getBoundingClientRect(); tooltip.style.display = 'block'; tooltip.style.left = `${rect.left + window.scrollX}px`; tooltip.style.top = `${rect.bottom + window.scrollY + 6}px`; }); el.addEventListener('mouseleave', () => { const tooltip = document.getElementById('alt-tooltip'); if (tooltip) tooltip.style.display = 'none'; }); }); } else { botMessage.textContent = data.response || 'Sorry, I could not process your request.'; chatOutput.appendChild(botMessage); } // Clear input input.value = ''; chatOutput.scrollTop = chatOutput.scrollHeight; } catch (error) { console.error('Error:', error); const errorMessage = document.createElement('div'); errorMessage.className = 'message error'; errorMessage.textContent = 'Error: Could not send message.'; chatOutput.appendChild(errorMessage); } finally { document.getElementById('loading').classList.remove('show'); } } async function generateSummary() { const input = document.getElementById('summary-input'); const text = input.value.trim(); if (!text) { alert('Please enter some text to summarize'); return; } const outputDiv = document.getElementById('summary-output'); document.getElementById('loading').classList.add('show'); try { const response = await fetch('/api/summarize', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ text: text, max_length: 150, min_length: 30 }) }); const data = await response.json(); if (data.success) { outputDiv.innerHTML = `${result.description}
${results.description}