Download buffalo_rag/frontend/static/js/app.js from TeamSAS/UB_VSA: direct link, hf CLI and curl.
- Browser
- Download file 8.53 kB
-
https://huggingface.co/spaces/TeamSAS/UB_VSA/resolve/main/buffalo_rag/frontend/static/js/app.js
- Command line
-
hf download hf://spaces/TeamSAS/UB_VSA/buffalo_rag/frontend/static/js/app.js
-
curl -L -o app.js https://huggingface.co/spaces/TeamSAS/UB_VSA/resolve/main/buffalo_rag/frontend/static/js/app.js
8.53 kB
| // 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'; | |
| } | |
| } | |