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");
}
}