const API_URL = "/ask"; // 1. Generate a random Session ID const sessionId = "session_" + Math.random().toString(36).substr(2, 9); console.log("Your Session ID:", sessionId); // --- VOICE SETUP --- const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; const recognition = new SpeechRecognition(); recognition.lang = 'en-US'; recognition.interimResults = false; let isVoiceActive = false; function startVoice() { const micBtn = document.getElementById("mic-btn"); if (isVoiceActive) { recognition.stop(); return; } try { recognition.start(); micBtn.classList.add("listening"); isVoiceActive = true; } catch (error) { console.error("Speech recognition error:", error); isVoiceActive = false; } } recognition.onend = () => { document.getElementById("mic-btn").classList.remove("listening"); }; recognition.onresult = (event) => { const transcript = event.results[0][0].transcript; document.getElementById("user-input").value = transcript; sendMessage(); }; // 3. Text-to-Speech function speakText(text) { window.speechSynthesis.cancel(); const cleanText = text.replace(/\*/g, "").replace(/<[^>]*>/g, ""); const utterance = new SpeechSynthesisUtterance(cleanText); window.speechSynthesis.speak(utterance); } function appendMessage(text, sender) { const box = document.getElementById("chat-box"); const msg = document.createElement("div"); msg.classList.add("message", sender); // If it's the bot, render Markdown & Math if (sender === "bot") { // 1. Convert Markdown to HTML let htmlContent = marked.parse(text); msg.innerHTML = htmlContent; } else { // User messages stay simple text msg.textContent = text; } box.appendChild(msg); box.scrollTop = box.scrollHeight; // 2. Render Math Formulas (if any) if (sender === "bot" && window.MathJax) { MathJax.typesetPromise([msg]).catch((err) => console.log(err)); } } let currentQuizData = []; let currentQuestionIndex = 0; let score = 0; function renderQuiz(jsonString) { const box = document.getElementById("chat-box"); try { currentQuizData = JSON.parse(jsonString); } catch (e) { appendMessage("⚠️ Error loading quiz.", "bot"); return; } currentQuestionIndex = 0; score = 0; showNextQuestion(); } function showNextQuestion() { const box = document.getElementById("chat-box"); // Check if quiz is finished if (currentQuestionIndex >= currentQuizData.length) { const resultDiv = document.createElement("div"); resultDiv.className = "message bot"; resultDiv.innerHTML = `
🎉 Quiz Complete!
You scored ${score} / ${currentQuizData.length}
`; box.appendChild(resultDiv); box.scrollTop = box.scrollHeight; return; } const qData = currentQuizData[currentQuestionIndex]; // Create Question Container const div = document.createElement("div"); div.className = "message bot"; div.innerHTML = `
Q${currentQuestionIndex + 1}: ${qData.question}
${qData.options.map(opt => `` ).join('')}
`; box.appendChild(div); box.scrollTop = box.scrollHeight; } function checkAnswer(btn, selectedOption) { const qData = currentQuizData[currentQuestionIndex]; const correctOption = qData.correct_answer; const parent = btn.parentElement; // Disable all buttons to prevent double clicking const allBtns = parent.querySelectorAll('.quiz-btn'); allBtns.forEach(b => b.disabled = true); if (selectedOption === correctOption) { btn.classList.add("correct"); score++; } else { btn.classList.add("wrong"); // Highlight the correct one allBtns.forEach(b => { if (b.innerText === correctOption) b.classList.add("correct"); }); } // Wait 1.5 seconds then show next question currentQuestionIndex++; setTimeout(showNextQuestion, 1500); } function appendFlashcards(jsonString) { const box = document.getElementById("chat-box"); // Parse the JSON string from Python let cardsData; try { cardsData = JSON.parse(jsonString); } catch (e) { console.error("JSON Error:", e); appendMessage("⚠️ Error generating cards.", "bot"); return; } // Create Container const container = document.createElement("div"); container.className = "message bot"; container.style.background = "transparent"; container.style.padding = "0"; const scrollBox = document.createElement("div"); scrollBox.className = "flashcard-container"; // Create Cards cardsData.forEach(card => { const cardDiv = document.createElement("div"); cardDiv.className = "flashcard"; // Flip on click cardDiv.onclick = function() { this.classList.toggle('flipped'); }; cardDiv.innerHTML = `
${card.question}
${card.answer}
`; scrollBox.appendChild(cardDiv); }); container.appendChild(scrollBox); box.appendChild(container); box.scrollTop = box.scrollHeight; } function showTyping() { const box = document.getElementById("chat-box"); const typing = document.createElement("div"); typing.classList.add("message", "bot"); typing.id = "typing"; typing.innerHTML = ` Thinking...`; box.appendChild(typing); box.scrollTop = box.scrollHeight; } function removeTyping() { const el = document.getElementById("typing"); if (el) el.remove(); } // --- MIND MAP RENDERER --- async function appendMindMap(mermaidCode) { const box = document.getElementById("chat-box"); const div = document.createElement("div"); div.classList.add("message", "bot"); div.style.background = "white"; div.style.border = "1px solid #ddd"; const id = "mermaid-" + Math.floor(Math.random() * 10000); div.id = id; let cleanCode = mermaidCode.replace(/```mermaid/g, "").replace(/```/g, "").trim(); div.textContent = cleanCode; box.appendChild(div); box.scrollTop = box.scrollHeight; try { await mermaid.init(undefined, div); } catch (error) { div.innerHTML = "⚠️ Could not render diagram."; } } async function sendMessage() { const input = document.getElementById("user-input"); const message = input.value.trim(); if (!message) return; appendMessage(message, "user"); input.value = ""; showTyping(); try { const res = await fetch(API_URL, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ question: message, session_id: sessionId }) }); const data = await res.json(); removeTyping(); appendMessage(data.answer, "bot"); if (isVoiceActive) { speakText(data.answer); isVoiceActive = false; } } catch (error) { removeTyping(); appendMessage("⚠️ Error contacting server.", "bot"); isVoiceActive = false; } } // --- FEATURE REQUESTS --- async function requestFeature(type) { let topic = ""; let endpoint = ""; let body = {}; let method = "POST"; if (type === 'quiz') { topic = prompt("Enter the topic for the quiz:"); if (!topic) return; appendMessage(`📝 Generating quiz for: ${topic}...`, "user"); endpoint = "/quiz"; body = JSON.stringify({ topic: topic }); } else if (type === 'summary') { topic = prompt("Enter topic to summarize:"); if (!topic) return; appendMessage(`📄 Summarizing: ${topic}...`, "user"); endpoint = "/summary"; body = JSON.stringify({ topic: topic }); } else if (type === 'countdown') { appendMessage("⏳ Checking exam schedule...", "user"); endpoint = "/countdown"; method = "GET"; } else if (type === 'plan') { const input = prompt("Enter Subject and Days (e.g., 'Science, 3'):"); if (!input) return; const parts = input.split(","); topic = parts[0].trim(); let days = parts.length > 1 ? parts[1].trim() : "5"; appendMessage(`📅 Creating ${days}-day plan for ${topic}...`, "user"); endpoint = "/study_plan"; body = JSON.stringify({ subject: topic, days: days }); } else if (type === 'mindmap') { topic = prompt("Enter topic for Mind Map:"); if (!topic) return; appendMessage(`🧠 Drawing Mind Map for: ${topic}...`, "user"); endpoint = "/mindmap"; body = JSON.stringify({ topic: topic }); } else if (type === 'flashcards') { topic = prompt("Enter topic for Flashcards:"); if (!topic) return; appendMessage(`🃏 Creating flashcards for: ${topic}...`, "user"); endpoint = "/flashcards"; body = JSON.stringify({ topic: topic }); } else if (type === 'quiz') { renderQuiz(data.answer); } if (!endpoint) return; showTyping(); try { const res = await fetch(`${endpoint}`, { method: method, headers: { "Content-Type": "application/json" }, body: method === "POST" ? body : null }); const data = await res.json(); removeTyping(); if (type === 'mindmap') { appendMindMap(data.answer); } else if (type === 'flashcards') { appendFlashcards(data.answer); } else if (type === 'quiz') { renderQuiz(data.answer); } else { appendMessage(data.answer, "bot"); } } catch (error) { removeTyping(); appendMessage("⚠️ Error fetching data.", "bot"); } }