SakshamLak's picture
Update buffalo_rag/frontend/static/js/app.js
a0505b5 verified
// DOM Elements
const messagesContainer = document.getElementById('messages');
const messageInput = document.getElementById('message-input');
const sendButton = document.getElementById('send-button');
const emptyChat = document.getElementById('empty-chat');
const chatContainer = document.getElementById('chat-container');
const sourcesContainer = document.getElementById('sources-container');
const noSources = document.getElementById('no-sources');
const scrapeBtn = document.getElementById('scrape-btn');
const refreshBtn = document.getElementById('refresh-btn');
// State
let messages = [];
let sources = [];
// Initialize
document.addEventListener('DOMContentLoaded', () => {
// Enable/disable send button based on input
messageInput.addEventListener('input', () => {
sendButton.disabled = !messageInput.value.trim();
});
// Send message on button click
sendButton.addEventListener('click', sendMessage);
// Send message on Enter key
messageInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
sendMessage();
}
});
// Admin buttons
scrapeBtn.addEventListener('click', triggerScrape);
refreshBtn.addEventListener('click', triggerRefreshIndex);
});
// Format date
function formatDate() {
return new Date().toLocaleString();
}
// Create message element
function createMessageElement(message) {
const messageEl = document.createElement('div');
messageEl.className = `message ${message.role}`;
const bubble = document.createElement('div');
bubble.className = 'bubble';
bubble.innerHTML = marked.parse(message.content); // parse Markdown to HTML
const meta = document.createElement('div');
meta.className = 'meta';
meta.textContent = formatDate();
messageEl.appendChild(bubble);
messageEl.appendChild(meta);
return messageEl;
}
// Update sources panel
function updateSources(sources) {
sourcesContainer.innerHTML = '';
// Filter sources with score > -8
const filteredSources = sources.filter(source => source.score > -8);
if (filteredSources.length === 0) {
sourcesContainer.appendChild(noSources);
return;
}
filteredSources.forEach(source => {
const card = document.createElement('div');
card.className = 'source-card';
const title = document.createElement('h4');
title.textContent = source.title;
const link = document.createElement('a');
link.className = 'link';
link.href = source.url;
link.target = '_blank';
link.innerHTML = `View source <i class="fas fa-external-link-alt"></i>`;
const score = document.createElement('div');
score.className = 'score';
score.textContent = `Relevance: ${source.score.toFixed(2)}`;
card.appendChild(title);
card.appendChild(link);
card.appendChild(score);
sourcesContainer.appendChild(card);
});
}
// Send message
async function sendMessage() {
const content = messageInput.value.trim();
if (!content) return;
// Hide empty chat if visible
if (emptyChat.style.display !== 'none') {
emptyChat.style.display = 'none';
}
// Add user message
const userMessage = { role: 'user', content };
messages.push(userMessage);
messagesContainer.appendChild(createMessageElement(userMessage));
// Clear input
messageInput.value = '';
sendButton.disabled = true;
// Show thinking message
const thinkingEl = document.createElement('div');
thinkingEl.className = 'message assistant';
const thinkingBubble = document.createElement('div');
thinkingBubble.className = 'bubble';
thinkingBubble.textContent = 'Thinking...';
thinkingEl.appendChild(thinkingBubble);
messagesContainer.appendChild(thinkingEl);
// Scroll to bottom
chatContainer.scrollTop = chatContainer.scrollHeight;
try {
// Call API
const response = await fetch('/api/ask', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: content,
k: 5
}),
});
if (!response.ok) {
throw new Error('API request failed');
}
const data = await response.json();
// Remove thinking message
messagesContainer.removeChild(thinkingEl);
// Add assistant message
const assistantMessage = { role: 'assistant', content: data.response };
messages.push(assistantMessage);
messagesContainer.appendChild(createMessageElement(assistantMessage));
// Update sources
sources = data.sources;
updateSources(sources);
// Scroll to bottom
chatContainer.scrollTop = chatContainer.scrollHeight;
} catch (error) {
console.error('Error:', error);
// Remove thinking message
messagesContainer.removeChild(thinkingEl);
// Add error message
const errorMessage = {
role: 'assistant',
content: "I'm sorry, I encountered an error. Please try again later or contact UB International Student Services directly."
};
messages.push(errorMessage);
messagesContainer.appendChild(createMessageElement(errorMessage));
// Scroll to bottom
chatContainer.scrollTop = chatContainer.scrollHeight;
}
}
// Quick questions
async function askQuickQuestion(question) {
// Set the question in the input field
messageInput.value = question;
// Send the message
await sendMessage();
}
// Admin functions
async function triggerScrape() {
scrapeBtn.disabled = true;
scrapeBtn.textContent = 'Scraping...';
try {
const response = await fetch('/api/scrape', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
seed_url: 'https://www.buffalo.edu/international-student-services.html',
max_pages: 100
}),
});
if (!response.ok) {
throw new Error('API request failed');
}
const data = await response.json();
alert(`${data.message}`);
} catch (error) {
console.error('Error:', error);
alert('Error starting scraper. Please check console for details.');
} finally {
scrapeBtn.disabled = false;
scrapeBtn.textContent = 'Scrape New Content';
}
}
async function triggerRefreshIndex() {
refreshBtn.disabled = true;
refreshBtn.textContent = 'Refreshing...';
try {
const response = await fetch('/api/refresh-index', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
});
if (!response.ok) {
throw new Error('API request failed');
}
const data = await response.json();
alert(`${data.message}`);
} catch (error) {
console.error('Error:', error);
alert('Error refreshing index. Please check console for details.');
} finally {
refreshBtn.disabled = false;
refreshBtn.textContent = 'Refresh Index';
}
}