Research-Mate / static /js /index.js
kapil14's picture
Upload 11 files
a75e3df verified
document.addEventListener('DOMContentLoaded', function() {
const uploadForm = document.getElementById('upload-form');
const chatForm = document.getElementById('chat-form');
const questionInput = document.getElementById('question');
const chatArea = document.getElementById('chat-area');
const pdfContainer = document.getElementById('pdf-container');
const clearBtn = document.getElementById('clear-chat');
const scholarForm = document.getElementById('scholar-search-form');
const scholarInput = document.getElementById('scholar-query');
const searchResults = document.getElementById('search-results');
// Initialize session data
initializeSessionData();
// Upload form handler
uploadForm.addEventListener('submit', async (e) => {
e.preventDefault();
const submitBtn = uploadForm.querySelector('button[type="submit"]');
submitBtn.disabled = true;
submitBtn.textContent = "Processing...";
document.getElementById("upload-progress").style.display = "block";
document.getElementById("progress-bar-text").style.width = "100%";
const formData = new FormData(uploadForm);
try {
const res = await fetch('/upload', { method: 'POST', body: formData });
// Defensive parsing: check Content-Type before calling res.json()
const contentType = res.headers.get('content-type') || '';
if (!res.ok) {
// Try to read JSON error first, otherwise read text
if (contentType.includes('application/json')) {
const err = await res.json();
throw new Error(err.error || JSON.stringify(err));
} else {
const text = await res.text();
throw new Error(text || `Upload failed with status ${res.status}`);
}
}
if (contentType.includes('application/json')) {
const data = await res.json();
if (data.filenames) {
// Refresh the document list (session_data)
await initializeSessionData();
} else if (data.error) {
throw new Error(data.error);
} else {
// Unexpected shape
throw new Error("Unexpected server response.");
}
} else {
// Not JSON (server returned HTML or something else) — show text
const text = await res.text();
throw new Error(text || "Unexpected non-JSON response from server.");
}
} catch (error) {
console.error("Upload error:", error);
pdfContainer.innerHTML = `<div class="alert alert-danger">❌ Failed to upload or process PDFs: ${error.message}</div>`;
} finally {
document.getElementById("upload-progress").style.display = "none";
submitBtn.disabled = false;
submitBtn.textContent = "Upload & Process PDFs";
}
});
// Render PDF list function
function renderPDFList(files) {
pdfContainer.innerHTML = '';
if (files.length === 0) {
pdfContainer.innerHTML = '<div>No documents uploaded yet.</div>';
return;
}
files.forEach(file => {
const div = document.createElement('div');
div.className = 'pdf-item';
if (file.source === "scholar") div.classList.add('scholarly');
if (file.source === "scholar") {
div.innerHTML = `
<div class="flex-grow-1">
<strong>${file.title || 'Scholar Paper'}</strong>
${file.link ? `<br><small><a href="${file.link}" target="_blank">View Source</a></small>` : ''}
</div>
<span class="delete-pdf" title="Delete PDF">❌</span>
`;
} else {
div.innerHTML = `
<div class="flex-grow-1">${file.filename}</div>
<span class="delete-pdf" title="Delete PDF">❌</span>
`;
}
// Add delete handler
div.querySelector('.delete-pdf').addEventListener('click', async () => {
if (confirm("Are you sure you want to delete this document?")) {
const res = await fetch('/delete_pdf', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `filepath=${encodeURIComponent(file.filename)}`
});
const data = await res.json();
if (data.success) {
await initializeSessionData(); // Refresh the list
} else {
alert("Failed to delete document: " + (data.error || 'Unknown error'));
}
}
});
pdfContainer.appendChild(div);
});
}
// Chat form handler
chatForm.addEventListener('submit', async (e) => {
e.preventDefault();
const question = questionInput.value.trim();
if (!question) return;
// Add user question to chat
chatArea.innerHTML += `<div class='chat-box user'>🧑‍🎓 You: ${question}</div>`;
const tempId = `bot-temp-${Date.now()}`;
chatArea.innerHTML += `<div class='chat-box bot' id='${tempId}'>🤖 Research Mate: Thinking...</div>`;
questionInput.value = '';
questionInput.disabled = true;
try {
const res = await fetch('/ask', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ question })
});
const data = await res.json();
if (data.answer) {
await simulateTyping(document.getElementById(tempId), data.answer);
} else {
document.getElementById(tempId).innerHTML = `🤖 Research Mate: ❌ Error processing the question.`;
}
} catch (error) {
console.error("Ask error:", error);
document.getElementById(tempId).innerHTML = `🤖 Research Mate: ❌ Network error occurred.`;
} finally {
questionInput.disabled = false;
questionInput.focus();
chatArea.scrollTop = chatArea.scrollHeight;
}
});
// Typing simulation
async function simulateTyping(element, text) {
element.innerHTML = "🤖 Research Mate: ";
for (let i = 0; i < text.length; i++) {
element.innerHTML += text.charAt(i);
await new Promise(r => setTimeout(r, 20));
}
chatArea.scrollTop = chatArea.scrollHeight;
}
clearBtn.addEventListener('click', () => {
if (confirm("Are you sure you want to clear the chat history?")) {
chatArea.innerHTML = '';
}
});
// Scholar search handler
scholarForm.addEventListener('submit', async (e) => {
e.preventDefault();
const query = scholarInput.value.trim();
if (!query) return;
searchResults.style.display = "block";
searchResults.innerHTML = "<div class='text-center my-3'>🔎 Searching Google Scholar...</div>";
try {
const res = await fetch('/search_scholar', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query })
});
const data = await res.json();
searchResults.innerHTML = "";
if (!data.papers || data.papers.length === 0) {
searchResults.innerHTML = "<div class='alert alert-warning'>❌ No results found for your query.</div>";
return;
}
const resultsHeader = document.createElement('h5');
resultsHeader.className = "mb-3";
resultsHeader.textContent = "📚 Search Results:";
searchResults.appendChild(resultsHeader);
data.papers.forEach(paper => {
const div = document.createElement('div');
div.className = "border p-3 mb-3 rounded";
div.innerHTML = `
<h5>${paper.title}</h5>
${paper.publication_info ? `<p class="text-info small mb-1">${paper.publication_info}</p>` : ''}
${paper.snippet ? `<p class="mb-2">${paper.snippet}</p>` : ''}
<div class="d-flex gap-2">
<a href="${paper.link}" target="_blank" class="btn btn-sm btn-outline-primary">View Paper</a>
<button class="btn btn-sm btn-success add-paper-btn">Add to Documents</button>
</div>
`;
const addBtn = div.querySelector('.add-paper-btn');
addBtn.addEventListener('click', async () => {
addBtn.disabled = true;
addBtn.textContent = "Adding...";
try {
const addRes = await fetch('/add_scholar_paper', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(paper)
});
const addData = await addRes.json();
if (addData.success) {
addBtn.textContent = "✓ Added";
await initializeSessionData();
} else {
addBtn.textContent = "Failed";
alert(addData.error || "Failed to add paper");
}
} catch (error) {
console.error("Add paper error:", error);
addBtn.textContent = "Error";
} finally {
setTimeout(() => {
addBtn.disabled = false;
addBtn.textContent = "Add to Documents";
}, 2000);
}
});
searchResults.appendChild(div);
});
} catch (error) {
console.error("Scholar search error:", error);
searchResults.innerHTML = `<div class="alert alert-danger">❌ Failed to fetch search results: ${error.message}</div>`;
}
});
// Initialize session data
async function initializeSessionData() {
try {
const res = await fetch('/session_data');
const data = await res.json();
if (data.uploaded_files) {
renderPDFList(data.uploaded_files);
} else {
pdfContainer.innerHTML = '<div class="text-info">No documents uploaded yet.</div>';
}
} catch (error) {
console.error("Session data error:", error);
}
}
});
const chatArea = document.getElementById('chat-area');
function scrollToBottom() {
chatArea.scrollTop = chatArea.scrollHeight;
}
function addMessage(isUser, text) {
const messageDiv = document.createElement('div');
messageDiv.className = `chat-box ${isUser ? 'user' : 'bot'}`;
messageDiv.innerHTML = `${isUser ? '🧑‍🎓 You' : '🤖 Research Mate'}: ${text}`;
chatArea.appendChild(messageDiv);
scrollToBottom();
}
// document.getElementById('delete-all-docs').addEventListener('click', async () => {
// if (confirm("Are you sure you want to delete ALL documents? This cannot be undone.")) {
// try {
// const res = await fetch('/clear_chat', { method: 'POST' });
// const data = await res.json();
// if (data.success) {
// await initializeSessionData(); // Refresh document list
// chatArea.innerHTML = ''; // Also clear chat
// }
// } catch (error) {
// console.error("Delete all error:", error);
// }
// }
// });