// Global state management const state = { isLoading: false, currentPdfUrl: null }; // Add state management for the current paper let currentPaperState = { pdfUrl: null, title: null }; // Add state management for search results let searchState = { lastResults: null, lastQuery: null }; // Utility Functions function getCsrfToken() { return document.querySelector('meta[name="csrf-token"]').getAttribute('content'); } function showLoading() { const overlay = document.getElementById('loadingOverlay'); overlay.classList.remove('hidden'); state.isLoading = true; } function hideLoading() { const overlay = document.getElementById('loadingOverlay'); overlay.classList.add('hidden'); state.isLoading = false; } // Search Functionality async function performSearch() { const searchQuery = document.getElementById('searchInput').value.trim(); const sortBy = document.getElementById('sortBy').value; const maxResults = parseInt(document.getElementById('maxResults').value); if (!searchQuery) { alert('Please enter a search term'); return; } // Show loading overlay document.getElementById('loadingOverlay').classList.remove('hidden'); try { const response = await fetch('/search', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCsrfToken() }, body: JSON.stringify({ paper_name: searchQuery, sort_by: sortBy, max_results: maxResults }) }); const data = await response.json(); // Save the results to the state searchState.lastResults = data; searchState.lastQuery = searchQuery; // Get results section and clear it const resultsSection = document.getElementById('resultsSection'); resultsSection.innerHTML = ''; if (!response.ok) { throw new Error(data.error || 'Search failed'); } // Show results section showResults(); if (data.length === 0) { resultsSection.innerHTML = `

No papers found matching your search.

`; return; } // Create results container const resultsGrid = document.createElement('div'); resultsGrid.className = 'results-grid'; // Add each paper to the grid data.forEach(paper => { const paperCard = document.createElement('div'); paperCard.className = 'paper-card'; paperCard.innerHTML = `

${escapeHtml(paper.title)}

Authors: ${escapeHtml(paper.authors)}

Category: ${escapeHtml(paper.category)}

Published: ${escapeHtml(paper.published)}

${escapeHtml(paper.abstract.substring(0, 200))}...

PDF ARXIV
`; resultsGrid.appendChild(paperCard); }); resultsSection.appendChild(resultsGrid); } catch (error) { console.error('Search error:', error); document.getElementById('resultsSection').innerHTML = `

Failed to search papers: ${error.message}

`; } finally { // Hide loading overlay document.getElementById('loadingOverlay').classList.add('hidden'); } } // Helper function to escape HTML and prevent XSS function escapeHtml(unsafe) { return unsafe .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } // Display Functions function displayResults(results) { const resultsSection = document.getElementById('resultsSection'); resultsSection.innerHTML = ''; const resultsGrid = document.createElement('div'); resultsGrid.className = 'results-grid'; results.forEach((paper, index) => { // Create paper card const paperCard = document.createElement('div'); paperCard.className = 'paper-card'; // Build the card HTML - removed save button paperCard.innerHTML = `
${paper.published}

${paper.title}

${paper.authors}

${paper.abstract}

`; // Add the paper card to the grid resultsGrid.appendChild(paperCard); // Add click handlers for remaining buttons const viewPdfButton = paperCard.querySelector('.view-pdf'); viewPdfButton.addEventListener('click', () => window.open(paper.pdf_link, '_blank')); const arxivButton = paperCard.querySelector('.arxiv'); arxivButton.addEventListener('click', () => window.open(paper.arxiv_link, '_blank')); const analyzeButton = paperCard.querySelector('.analyze'); analyzeButton.addEventListener('click', () => analyzePaper(paper.pdf_link, paper.title)); }); resultsSection.appendChild(resultsGrid); } // Analysis Functions async function analyzePaper(pdfUrl, paperTitle) { // Update current paper state currentPaperState.pdfUrl = pdfUrl; currentPaperState.title = paperTitle; // Show loading overlay showLoading(); try { const response = await fetch('/perform-rag', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCsrfToken() }, body: JSON.stringify({ pdf_url: pdfUrl, paper_title: paperTitle }) }); const data = await response.json(); if (data.error) { throw new Error(data.error); } // Show results section const resultsSection = document.getElementById('resultsSection'); resultsSection.innerHTML = `

${paperTitle}

Research Paper Analysis

${marked.parse(data.analysis.executive_summary)}
AI
Hello! I'm here to help you understand this research paper better. Feel free to ask any questions about the paper's content, methodology, findings, or implications.
`; } catch (error) { console.error('Analysis error:', error); document.getElementById('resultsSection').innerHTML = `
Failed to analyze paper: ${error.message}
`; } finally { hideLoading(); } } // Function to switch between paper analysis and chat tabs function switchPaperTab(tab) { const analysisBtnTab = document.getElementById('paperAnalysisTab'); const chatBtnTab = document.getElementById('chatWithPaperTab'); const analysisContent = document.getElementById('analysisContent'); const chatContent = document.getElementById('chatContent'); if (tab === 'analysis') { analysisBtnTab.classList.add('active'); chatBtnTab.classList.remove('active'); analysisContent.classList.add('active'); chatContent.classList.remove('active'); } else { chatBtnTab.classList.add('active'); analysisBtnTab.classList.remove('active'); chatContent.classList.add('active'); analysisContent.classList.remove('active'); } } // Function to handle chat messages async function sendMessage() { const chatInput = document.getElementById('chatInput'); const question = chatInput.value.trim(); if (!question || !currentPaperState.pdfUrl) return; const chatMessages = document.getElementById('chatMessages'); // Add user message addMessage(question, true); // Add AI thinking message with loading animation const thinkingMessageId = 'ai-thinking-' + Date.now(); addMessage(`${thinkingMessageId} AI is thinking...`, false); chatInput.value = ''; chatMessages.scrollTop = chatMessages.scrollHeight; try { const response = await fetch('/chat-with-paper', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCsrfToken() }, body: JSON.stringify({ pdf_url: currentPaperState.pdfUrl, question: question }) }); const data = await response.json(); if (data.error) { throw new Error(data.error); } // Remove thinking message const thinkingMessage = document.getElementById(thinkingMessageId); if (thinkingMessage) { thinkingMessage.remove(); } // Add AI response addMessage(data.response, false); chatMessages.scrollTop = chatMessages.scrollHeight; } catch (error) { console.error('Chat error:', error); // Remove thinking message const thinkingMessage = document.getElementById(thinkingMessageId); if (thinkingMessage) { thinkingMessage.remove(); } addMessage(`Error: ${error.message}`, false); } } // Navigation Functions function showHome() { hideAllSections(); document.getElementById('homeSection').classList.add('active'); document.getElementById('backButton').style.display = 'none'; } function showResults() { hideAllSections(); document.getElementById('resultsSection').classList.add('active'); document.getElementById('currentSection').textContent = 'Search Results'; document.getElementById('backButton').style.display = 'block'; } function hideAllSections() { const sections = ['homeSection', 'historySection', 'savedSection', 'resultsSection']; sections.forEach(section => { document.getElementById(section).classList.remove('active'); }); } function goBack() { showHome(); } // Load search history function loadSearchHistory() { const historyGrid = document.getElementById('searchHistory'); try { const history = JSON.parse(localStorage.getItem('searchHistory') || '[]'); if (history.length === 0) { historyGrid.innerHTML = '

No search history yet

'; return; } historyGrid.innerHTML = ''; history.forEach(item => { const historyCard = document.createElement('div'); historyCard.className = 'history-card'; historyCard.innerHTML = `

${item.query}

${new Date(item.timestamp).toLocaleDateString()}

`; historyGrid.appendChild(historyCard); }); } catch (error) { console.error('Error loading history:', error); historyGrid.innerHTML = '

Error loading history

'; } } // Add notification system function showNotification(message, type = 'info') { const notification = document.createElement('div'); notification.className = `notification ${type}`; notification.textContent = message; document.body.appendChild(notification); setTimeout(() => { notification.classList.add('show'); setTimeout(() => { notification.classList.remove('show'); setTimeout(() => notification.remove(), 300); }, 2000); }, 100); } // Add history functionality function saveToHistory(query, results) { try { const history = JSON.parse(localStorage.getItem('searchHistory') || '[]'); history.unshift({ query, timestamp: new Date().toISOString(), results: results.slice(0, 3) // Save only first 3 results to save space }); // Keep only last 10 searches localStorage.setItem('searchHistory', JSON.stringify(history.slice(0, 10))); } catch (error) { console.error('Error saving to history:', error); } } // Add function to repeat search from history function repeatSearch(query) { const searchInput = document.getElementById('searchInput'); searchInput.value = query; showHome(); performSearch(); } // Add tab switching functionality function switchTab(tabName) { // Update tab buttons document.querySelectorAll('.tab-button').forEach(button => { button.classList.remove('active'); if (button.textContent.toLowerCase().includes(tabName)) { button.classList.add('active'); } }); // Update tab content document.querySelectorAll('.tab-content').forEach(content => { content.classList.remove('active'); }); document.getElementById(`${tabName}Tab`).classList.add('active'); } // Add function to return to search results function showSearchResults() { if (lastSearchResults) { displayResults(lastSearchResults); // Update navigation state document.getElementById('currentSection').textContent = 'Search Results'; } else { showHome(); } } // Add function to handle back to search function backToSearchResults() { if (searchState.lastResults) { const resultsSection = document.getElementById('resultsSection'); resultsSection.innerHTML = ''; // Create results container const resultsGrid = document.createElement('div'); resultsGrid.className = 'results-grid'; // Recreate the results from the saved state searchState.lastResults.forEach(paper => { const paperCard = document.createElement('div'); paperCard.className = 'paper-card'; paperCard.innerHTML = `

${escapeHtml(paper.title)}

Authors: ${escapeHtml(paper.authors)}

Category: ${escapeHtml(paper.category)}

Published: ${escapeHtml(paper.published)}

${escapeHtml(paper.abstract.substring(0, 200))}...

PDF ARXIV
`; resultsGrid.appendChild(paperCard); }); resultsSection.appendChild(resultsGrid); } else { // If no previous results, redirect to home showHome(); } } // Add function to handle search history function updateSearchHistory(searchTerm) { try { let searches = JSON.parse(localStorage.getItem('recentSearches') || '[]'); // Add new search with timestamp searches.unshift({ term: searchTerm, date: new Date().toISOString() }); // Keep only the most recent 9 searches searches = searches.slice(0, 9); localStorage.setItem('recentSearches', JSON.stringify(searches)); displaySearchHistory(); } catch (error) { console.error('Error updating search history:', error); } } // Add function to display search history function displaySearchHistory() { const historyContainer = document.getElementById('searchHistory'); if (!historyContainer) return; try { const searches = JSON.parse(localStorage.getItem('recentSearches') || '[]'); historyContainer.innerHTML = `

Recent Searches

${searches.map(search => `

${search.term}

${new Date(search.date).toLocaleDateString('en-GB')}
`).join('')}
`; } catch (error) { console.error('Error displaying search history:', error); } } // Add function to handle search again function searchAgain(term) { document.getElementById('searchInput').value = term; handleSearch(term); } // Update the search container HTML in your JavaScript function initializeSearchInterface() { const searchSection = document.querySelector('.search-section'); if (searchSection) { searchSection.innerHTML = `
`; // Add event listeners const searchInput = document.getElementById('searchInput'); const searchButton = document.getElementById('searchButton'); searchInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { performSearch(); } }); searchButton.addEventListener('click', performSearch); } } function createChatInterface() { return `
AI
Hello! I'm here to help you understand this research paper better. Feel free to ask any questions about the paper's content, methodology, findings, or implications.
`; } function addMessage(message, isUser = false) { const chatMessages = document.getElementById('chatMessages'); const messageWrapper = document.createElement('div'); messageWrapper.className = 'message-wrapper'; const avatar = document.createElement('div'); avatar.className = `message-avatar ${isUser ? 'user-avatar' : 'ai-avatar'}`; avatar.textContent = isUser ? 'You' : 'AI'; const messageDiv = document.createElement('div'); messageDiv.className = `message ${isUser ? 'user-message' : 'ai-message'}`; // Convert markdown to HTML if it's an AI message if (!isUser) { messageDiv.innerHTML = marked.parse(message); } else { messageDiv.textContent = message; } messageWrapper.appendChild(avatar); messageWrapper.appendChild(messageDiv); chatMessages.appendChild(messageWrapper); // Scroll to bottom chatMessages.scrollTop = chatMessages.scrollHeight; } // Add this new function to handle quick questions async function handleQuickQuestion(question) { // Add user's question to chat addMessage(question, true); // Show thinking indicator const thinkingDiv = addThinkingMessage(); try { const response = await fetch('/chat-with-paper', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCsrfToken() }, body: JSON.stringify({ pdf_url: currentPaperState.pdfUrl, question: question }) }); const data = await response.json(); // Remove thinking indicator thinkingDiv.remove(); if (data.error) { addMessage(`Error: ${data.error}`, false); return; } // Add AI's response to chat addMessage(data.response, false); } catch (error) { // Remove thinking indicator thinkingDiv.remove(); addMessage(`Error: ${error.message}`, false); } } // Event Listeners document.addEventListener('DOMContentLoaded', () => { // Navigation initialization showHome(); initializeSearchInterface(); // Search button click const searchButton = document.getElementById('searchButton'); searchButton.addEventListener('click', performSearch); // Search input enter key const searchInput = document.getElementById('searchInput'); searchInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { performSearch(); } }); }); function addThinkingMessage() { const chatMessages = document.getElementById('chatMessages'); const thinkingDiv = document.createElement('div'); thinkingDiv.className = 'ai-thinking'; thinkingDiv.innerHTML = `
`; chatMessages.appendChild(thinkingDiv); chatMessages.scrollTop = chatMessages.scrollHeight; return thinkingDiv; }