document.getElementById('predictionForm').addEventListener('submit', async (e) => { e.preventDefault(); // 1. Collect Course Data const courseRows = document.querySelectorAll('.course-row'); const coursesArray = Array.from(courseRows).map(row => ({ name: row.querySelector('.course-name').value.toUpperCase().trim(), grade: parseFloat(row.querySelector('.course-grade').value) })); // 2. Collect AI Features const studentData = { ssc: parseFloat(document.getElementById('ssc').value), last: parseFloat(document.getElementById('last').value), attendance: parseInt(document.getElementById('attendance').value), preparation: parseInt(document.getElementById('preparation').value), income: 2, hometown: 1, department: 0, gaming: 2, courses: coursesArray }; try { const response = await fetch('http://127.0.0.1:8000/predict', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(studentData) }); const data = await response.json(); const resultArea = document.getElementById('resultArea'); const resultBox = document.getElementById('resultBox'); const resultMessage = document.getElementById('resultMessage'); resultMessage.innerHTML = ""; resultArea.classList.remove('hidden'); // Logic to show "Confidence in Success" vs "Risk of Failure" let displayScore; let scoreLabel; if (data.needs_resources) { // High Risk: Show the risk percentage displayScore = data.confidence_score; scoreLabel = "AI Habit Risk Prediction: " + displayScore + "% chance of falling behind."; } else { // Low Risk: Show the success confidence (100 - risk) displayScore = (100 - data.confidence_score).toFixed(2); scoreLabel = "AI Success Confidence: " + displayScore + "% chance of staying on track."; } // Apply UI Styling let htmlContent = `

${data.message}

`; htmlContent += `

🧠 ${scoreLabel}

`; const styles = { critical: "border-red-300 bg-red-50 text-red-800", subject_alert: "border-yellow-300 bg-yellow-50 text-yellow-800", habit_alert: "border-orange-300 bg-orange-50 text-orange-800", safe: "border-green-300 bg-green-50 text-green-800" }; resultBox.className = `p-4 rounded-md border ${styles[data.alert_level]}`; //generate resource links from Neon if (data.resource_links && data.resource_links.length > 0) { htmlContent += `

Recommended Foundational Resources:

`; htmlContent += `
`; const seenResources = new Set(); data.resource_links.forEach(resource => { if (!seenResources.has(resource.url)) { // 1. Determine Icon and Color Styling based on resource_type let icon, bgStyle, textStyle, label; const type = resource.resource_type.toLowerCase(); if (type === 'video') { icon = '🎥'; bgStyle = 'bg-red-50 border-red-200'; textStyle = 'text-red-700'; label = 'YouTube Video'; } else if (type === 'book') { icon = '📚'; bgStyle = 'bg-blue-50 border-blue-200'; textStyle = 'text-blue-700'; label = 'Textbook / PDF'; } else if (type === 'article') { icon = '📄'; bgStyle = 'bg-gray-50 border-gray-200'; textStyle = 'text-gray-700'; label = 'Web Article'; } else { icon = '🔗'; bgStyle = 'bg-white border-gray-200'; textStyle = 'text-gray-600'; label = 'Resource'; } htmlContent += `
${icon}

${resource.course_code} - ${label}

${resource.title}

${resource.explanation ? `

${resource.explanation}

` : ''}
`; seenResources.add(resource.url); } }); htmlContent += `
`; } else if (data.subjects_to_focus && data.subjects_to_focus.length > 0) { htmlContent += `

Review habits for these codes:

`; } resultMessage.innerHTML = htmlContent; } catch (error) { console.error("Connection Error:", error); alert("Ensure FastAPI is running on port 8000"); } }); function addCourseRow() { const container = document.getElementById('courseContainer'); const newRow = document.createElement('div'); newRow.className = "flex gap-2 course-row"; newRow.innerHTML = ` `; container.appendChild(newRow); } function removeRow(btn) { btn.parentElement.remove(); } let currentFilename= ""; async function handlePDFUpload(event) { if(event) event.preventDefault(); // Extra safety to prevent page reloads const fileInput = document.getElementById('pdfFile'); const urlInput = document.getElementById('pdfUrl'); const statusElement = document.getElementById('uploadStatus'); const pdfFrame = document.getElementById('pdfFrame'); const pdfContainer = document.getElementById('pdfContainer'); const processBtn = document.getElementById('processBtn'); if (fileInput.files.length === 0 && urlInput.value.trim() === "") { alert("Please provide either a PDF file or URL"); return; } statusElement.innerHTML = ' AI is reading and indexing your PDF...'; processBtn.disabled = true; processBtn.classList.add('opacity-50', 'cursor-not-allowed'); if (fileInput.files.length > 0) { const fileURL = URL.createObjectURL(fileInput.files[0]); pdfFrame.src = fileURL; pdfContainer.classList.remove('hidden'); } else if (urlInput.value.trim() !== "") { pdfFrame.src = urlInput.value; pdfContainer.classList.remove('hidden'); } let formData = new FormData(); let response; try { if (fileInput.files.length > 0) { formData.append('file', fileInput.files[0]); response = await fetch('http://127.0.0.1:8000/upload-pdf', { method: 'POST', body: formData }); } else { response = await fetch('http://127.0.0.1:8000/analyze-pdf-url', { method: 'POST', headers : { 'Content-Type': 'application/json' }, body: JSON.stringify({ url: urlInput.value }) }); } if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); if (data.message === "Success") { currentFilename = data.filename; statusElement.innerText = `✅ Loaded: ${data.filename} (${data.chunks_processed || data.chunks} chunks)`; } } catch (error) { console.error("Error processing PDF:", error); statusElement.textContent = 'Error processing PDF: ' + error.message; } finally { processBtn.disabled = false; processBtn.classList.remove('opacity-50', 'cursor-not-allowed'); } } async function askQuestion() { const input = document.getElementById('userQuestion'); const chatMessages = document.getElementById('chatMessages'); const question = input.value.trim(); if (!question) return; // Show User Message chatMessages.innerHTML += `

${question}

`; input.value = ""; const loadingId = "ai-loading-" + Date.now(); chatMessages.innerHTML += `

AI is searching notes...

`; chatMessages.scrollTop = chatMessages.scrollHeight; try { const response = await fetch('http://127.0.0.1:8000/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ question: question, filename: currentFilename }) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); // Remove thinking message and show real answer const loadingElement = document.getElementById(loadingId); if (loadingElement) loadingElement.remove(); const formattedAnswer = marked.parse(data.answer); chatMessages.innerHTML += `
${formattedAnswer}
`; } catch (error) { const loadingElement = document.getElementById(loadingId); if (loadingElement) { if (error.message.includes("429")) { loadingElement.innerHTML = `

⚠️ The AI is thinking too fast! Please wait 30 seconds and try asking again.

`; } else { loadingElement.innerHTML = `

Error: ${error.message}

`; } } } chatMessages.scrollTop = chatMessages.scrollHeight; } //sidebar elements const menuBtn = document.getElementById('menuBtn'); const sidebar = document.getElementById('sidebar'); const overlap = document.getElementById('overlap'); const pdfLibraryList = document.getElementById('pdfLibraryList'); //toggle sidebar logic menuBtn.addEventListener('click', () => { sidebar.classList.toggle('-translate-x-full'); overlay.classList.toggle('opacity-50'); overlay.classList.toggle('pointer-events-auto'); if (!sidebar.classList.contains('-translate-x-full')) { refreshLibrary(); // Fetch list when opening } }); overlay.addEventListener('click', () => { sidebar.classList.add('-translate-x-full'); overlay.classList.remove('opacity-50', 'pointer-events-auto'); }); // 2. Fetch and Display Library async function refreshLibrary() { try { const response = await fetch('http://127.0.0.1:8000/library'); const files = await response.json(); if (files.length === 0) { pdfLibraryList.innerHTML = '

Library is empty.

'; return; } pdfLibraryList.innerHTML = files.map(filename => `
📄 ${filename}
`).join(''); } catch (err) { console.error("Library Error:", err); } } // 3. Select a file from History function selectLibraryFile(filename) { currentFilename = filename; // Update the UI document.getElementById('uploadStatus').innerHTML = `✅ Active Subject: ${filename}`; document.getElementById('pdfViewerContainer').classList.remove('hidden'); // Note:Will need to integrate with Firebase/AWS S3 // Since we don't store the full file URL in the vector DB, // we can't show the PDF in the iframe unless it was just uploaded. // For now, we clear the iframe to show we switched subjects. document.getElementById('pdfFrame').src = ""; // Clear chat and Close sidebar document.getElementById('chatMessages').innerHTML = `

Switched to: ${filename}

`; sidebar.classList.add('-translate-x-full'); overlay.classList.remove('opacity-50', 'pointer-events-auto'); } document.getElementById("userQuestion").addEventListener("keypress", function(event) { if (event.key === "Enter") { event.preventDefault(); // Stops the page reload askQuestion(); } }); async function generateBundle() { const minutes = document.getElementById('time-budget').value; const topic = document.getElementById('topic-select').value; const resultsContainer = document.getElementById("bundle-results"); resultsContainer.innerHTML = "

⏳ Curating your study bundle...

"; try { const response = await fetch("http://127.0.0.1:8000/bundler/create", { method : "POST", headers : { "Content-Type" : "application/json" }, body: JSON.stringify({ minutes_available: parseInt(minutes), topic : "" }) }); if (!response.ok) throw new Error("Could not generate bundle."); const data = await response.json(); //clear laading text resultsContainer.innerHTML = ""; //loop through the retuned resources and display data.forEach(item => { resultsContainer.innerHTML += `

${item.type.toUpperCase()} (${item.duration_min} mins)

${item.content}

`; }); } catch (error) { resultsContainer.innerHTML = `

Error: ${error.message}

`; } }