AI Teacher Pro
tailwind.config = {
theme: {
extend: {
colors: {
primary: {
50: '#eef2ff',
100: '#e0e7ff',
200: '#c7d2fe',
300: '#a5b4fc',
400: '#818cf8',
500: '#1E90FF', // Main blue
600: '#0284c7',
700: '#0369a1',
800: '#075985',
900: '#0c4a6e',
},
},
animation: {
'bounce-slow': 'bounce 3s infinite',
'pulse-slow': 'pulse 4s cubic-bezier(0.4, 0, 0.6, 1) infinite',
'fade-in': 'fadeIn 0.5s ease-out',
'slide-up': 'slideUp 0.5s ease-out',
'slide-in': 'slideIn 0.5s ease-out',
'expand': 'expand 0.3s ease-out forwards',
},
keyframes: {
fadeIn: {
'0%': { opacity: '0' },
'100%': { opacity: '1' },
},
slideUp: {
'0%': { transform: 'translateY(20px)', opacity: '0' },
'100%': { transform: 'translateY(0)', opacity: '1' },
},
slideIn: {
'0%': { transform: 'translateX(-20px)', opacity: '0' },
'100%': { transform: 'translateX(0)', opacity: '1' },
},
expand: {
'0%': { transform: 'scale(0.8)', opacity: '0' },
'100%': { transform: 'scale(1)', opacity: '1' },
},
},
backdropBlur: {
'xs': '2px',
}
}
}
}
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
:root {
--primary-color: #1E90FF;
--primary-light: #60a5fa;
--primary-dark: #0369a1;
--bg-blur: rgba(255, 255, 255, 0.8);
--card-bg: rgba(255, 255, 255, 0.7);
--card-border: rgba(255, 255, 255, 0.4);
--shadow-color: rgba(0, 0, 0, 0.05);
--text-primary: #1a202c;
--text-secondary: #4a5568;
}
.dark {
--bg-blur: rgba(15, 23, 42, 0.8);
--card-bg: rgba(30, 41, 59, 0.7);
--card-border: rgba(51, 65, 85, 0.4);
--shadow-color: rgba(0, 0, 0, 0.2);
--text-primary: #f8fafc;
--text-secondary: #cbd5e1;
}
body {
font-family: 'Inter', sans-serif;
}
.blur-container {
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
}
.glass-card {
background: var(--card-bg);
border: 1px solid var(--card-border);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
box-shadow: 0 4px 6px var(--shadow-color);
transition: all 0.3s ease;
}
.glass-card:hover {
transform: translateY(-2px);
box-shadow: 0 10px 15px -3px var(--shadow-color);
}
/* Custom scrollbar */
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: #cbd5e1;
border-radius: 3px;
}
.dark ::-webkit-scrollbar-thumb {
background: #475569;
}
/* Message animations */
.user-message {
animation: slideIn 0.3s ease-out;
align-self: flex-end;
background-color: #1E90FF;
color: white;
max-width: 80%;
margin-left: auto;
width: fit-content;
}
.ai-message {
animation: slideIn 0.3s ease-out;
align-self: flex-start;
background-color: var(--card-bg);
color: var(--text-primary);
max-width: 80%;
margin-right: auto;
width: fit-content;
}
/* Typing indicator */
.typing-indicator {
display: flex;
align-items: center;
padding: 0.5rem 1rem;
align-self: flex-start;
margin-right: auto;
}
.typing-indicator span {
height: 8px;
width: 8px;
background-color: var(--primary-color);
border-radius: 50%;
display: inline-block;
margin-right: 3px;
opacity: 0.7;
}
.typing-indicator span:nth-child(1) {
animation: pulse 1s infinite;
}
.typing-indicator span:nth-child(2) {
animation: pulse 1s infinite 0.2s;
}
.typing-indicator span:nth-child(3) {
animation: pulse 1s infinite 0.4s;
}
@keyframes pulse {
0%, 100% {
transform: scale(1);
opacity: 0.7;
}
50% {
transform: scale(1.2);
opacity: 1;
}
}
/* Markdown styles for chat messages */
.message-content {
width: 100%;
overflow-wrap: break-word;
}
.message-content p {
margin-bottom: 0.5rem;
}
.message-content ul, .message-content ol {
margin-left: 1.5rem;
margin-bottom: 0.5rem;
}
.message-content ul {
list-style-type: disc;
}
.message-content ol {
list-style-type: decimal;
}
.message-content code {
font-family: monospace;
background-color: rgba(0, 0, 0, 0.1);
padding: 0.1rem 0.2rem;
border-radius: 3px;
}
.message-content pre {
background-color: rgba(0, 0, 0, 0.1);
padding: 0.5rem;
border-radius: 5px;
margin-bottom: 0.5rem;
overflow-x: auto;
}
.message-content a {
color: #2563eb;
text-decoration: underline;
}
.user-message .message-content a,
.user-message .message-content code,
.user-message .message-content pre {
color: white;
background-color: rgba(255, 255, 255, 0.2);
}
h1,h2,h3,h4,h5,h6 {
margin-bottom: 0px; padding-bottom: 0px;
}
textarea, select {
border: none;
}
textarea:focus {
border-color: #1E90ff;
}
button:hover {
color: none;
}
// App State
const state = {
currentSubject: null,
chatHistory: {},
activeChat: null,
quizState: null,
revisionPlan: null,
isDarkMode: window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches,
isRecording: false,
recognition: null
};
// API Integration
let currentChatId = null;
// DOM Elements
const loadingScreen = document.getElementById('loading-screen');
const appInterface = document.getElementById('app-interface');
const chatContainer = document.getElementById('chat-container');
const messageInput = document.getElementById('message-input');
const sendButton = document.getElementById('send-button');
const statusDiv = document.getElementById('status');
const currentSubjectEl = document.getElementById('current-subject');
const sidebarMenu = document.getElementById('sidebar-menu');
const menuToggleBtn = document.getElementById('menu-toggle');
const quizModal = document.getElementById('quiz-modal');
const revisionModal = document.getElementById('revision-modal');
const historyModal = document.getElementById('history-modal');
const voiceButton = document.getElementById('voice-btn');
// Load chat history from localStorage
function loadChatHistory() {
const savedHistory = localStorage.getItem('eduai-chat-history');
if (savedHistory) {
try {
state.chatHistory = JSON.parse(savedHistory);
} catch (e) {
console.error('Error parsing chat history:', e);
state.chatHistory = {};
}
}
}
// Save chat history to localStorage
function saveChatHistory() {
localStorage.setItem('eduai-chat-history', JSON.stringify(state.chatHistory));
updateHistoryModal();
}
// Initialize theme
function initTheme() {
if (state.isDarkMode) {
document.documentElement.classList.add('dark');
document.getElementById('theme-text').textContent = 'Light Mode';
document.getElementById('theme-icon').classList.remove('fa-moon');
document.getElementById('theme-icon').classList.add('fa-sun');
} else {
document.documentElement.classList.remove('dark');
document.getElementById('theme-text').textContent = 'Dark Mode';
document.getElementById('theme-icon').classList.remove('fa-sun');
document.getElementById('theme-icon').classList.add('fa-moon');
}
}
// Toggle theme
function toggleTheme() {
state.isDarkMode = !state.isDarkMode;
initTheme();
}
// Initialize Speech Recognition
function initSpeechRecognition() {
if ('webkitSpeechRecognition' in window) {
state.recognition = new webkitSpeechRecognition();
state.recognition.continuous = false;
state.recognition.interimResults = true;
state.recognition.onstart = function() {
state.isRecording = true;
voiceButton.classList.add('text-primary-500');
voiceButton.classList.remove('text-gray-500', 'dark:text-gray-400');
voiceButton.innerHTML = '';
messageInput.placeholder = "Listening...";
};
state.recognition.onresult = function(event) {
const transcript = event.results[0][0].transcript;
messageInput.value = transcript;
};
state.recognition.onerror = function(event) {
console.error('Speech recognition error', event.error);
stopRecording();
};
state.recognition.onend = function() {
stopRecording();
};
} else {
voiceButton.disabled = true;
voiceButton.title = "Speech recognition not supported in this browser";
}
}
// Toggle recording
function toggleRecording() {
if (state.isRecording) {
stopRecording();
} else {
startRecording();
}
}
// Start recording
function startRecording() {
if (state.recognition) {
state.recognition.start();
}
}
// Stop recording
function stopRecording() {
if (state.recognition) {
state.recognition.stop();
state.isRecording = false;
voiceButton.classList.remove('text-primary-500');
voiceButton.classList.add('text-gray-500', 'dark:text-gray-400');
voiceButton.innerHTML = '';
messageInput.placeholder = "Ask anything about your subject...";
}
}
// Start a new chat session
async function startNewChat() {
try {
const response = await fetch('https://server-ef04.onrender.com/api/chat/new', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
});
const data = await response.json();
if (data.success) {
currentChatId = data.chatId;
updateStatus('Connected to chat session');
} else {
throw new Error(data.error || 'Failed to start chat session');
}
} catch (error) {
updateStatus('Error: ' + error.message, true);
}
}
// Send a message to the AI
async function sendMessage(message) {
if (!currentChatId) {
updateStatus('No active chat session', true);
return;
}
try {
appendMessage(message, 'user');
// Save to history
if (!state.chatHistory[state.currentSubject]) {
state.chatHistory[state.currentSubject] = [];
}
if (!state.activeChat) {
state.activeChat = {
id: Date.now(),
subject: state.currentSubject,
messages: []
};
state.chatHistory[state.currentSubject].unshift(state.activeChat);
}
state.activeChat.messages.push({
sender: 'user',
text: message,
timestamp: Date.now()
});
saveChatHistory();
// Show typing indicator
const typingIndicator = document.createElement('div');
typingIndicator.classList.add('typing-indicator', 'ai-message', 'p-3', 'rounded-lg');
typingIndicator.innerHTML = '';
chatContainer.appendChild(typingIndicator);
chatContainer.scrollTop = chatContainer.scrollHeight;
disableInput(true);
const response = await fetch('https://server-ef04.onrender.com/api/chat/message', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
chatId: currentChatId,
message: message
})
});
const data = await response.json();
// Remove typing indicator
chatContainer.removeChild(typingIndicator);
if (data.success) {
appendMessage(data.response, 'ai');
// Save AI response to history
state.activeChat.messages.push({
sender: 'ai',
text: data.response,
timestamp: Date.now()
});
saveChatHistory();
} else {
throw new Error(data.error || 'Failed to get response');
}
} catch (error) {
updateStatus('Error: ' + error.message, true);
} finally {
disableInput(false);
}
}
// UI Helper Functions
function appendMessage(message, sender) {
const messageDiv = document.createElement('div');
messageDiv.classList.add('message', `${sender}-message`, 'p-3', 'rounded-lg', 'break-words', 'mb-2', 'w-full');
// Create a container for the content
const contentDiv = document.createElement('div');
contentDiv.classList.add('message-content');
// Format message text with markdown support
if (sender === 'ai') {
contentDiv.innerHTML = marked.parse(message);
} else {
// For user messages, keep as plain text
contentDiv.textContent = message;
}
messageDiv.appendChild(contentDiv);
chatContainer.appendChild(messageDiv);
chatContainer.scrollTop = chatContainer.scrollHeight;
}
function updateStatus(message, isError = false) {
statusDiv.textContent = message;
statusDiv.style.color = isError ? '#dc3545' : 'white';
statusDiv.classList.remove('hidden');
// Hide status after a few seconds
setTimeout(() => {
statusDiv.classList.add('hidden');
}, 3000);
}
function disableInput(disabled) {
messageInput.disabled = disabled;
sendButton.disabled = disabled;
if (disabled) {
sendButton.classList.add('opacity-50');
} else {
sendButton.classList.remove('opacity-50');
}
}
// Change subject
function changeSubject(subject) {
state.currentSubject = subject;
state.activeChat = null;
currentSubjectEl.textContent = getSubjectDisplayName(subject);
// Clear chat container
chatContainer.innerHTML = '';
// Add welcome message
const welcomeMessage = getWelcomeMessage(subject);
appendMessage(welcomeMessage, 'ai');
// Close sidebar if open
toggleSidebar(false);
}
// Get subject display name
function getSubjectDisplayName(subject) {
const subjectMap = {
'biology': 'Biology (Edexcel IAL)',
'chemistry': 'Chemistry (Edexcel IAL)',
'physics': 'Physics (Edexcel IAL)',
'math': 'Mathematics (Edexcel IAL)',
'ielts-speaking': 'IELTS Speaking',
'ielts-writing': 'IELTS Writing',
'ielts-reading': 'IELTS Reading',
'ielts-listening': 'IELTS Listening'
};
return subjectMap[subject] || subject;
}
// Get welcome message for subject
function getWelcomeMessage(subject) {
const welcomeMessages = {
'biology': "๐ Welcome to Biology! I'm your Edexcel IAL Biology tutor. I can help with topics like biological molecules, cells, genetics, ecology, and more. What would you like to learn about today?",
'chemistry': "๐ Welcome to Chemistry! I'm your Edexcel IAL Chemistry tutor. I can help with topics like atomic structure, bonding, energetics, organic chemistry, and more. What would you like to learn about today?",
'physics': "๐ Welcome to Physics! I'm your Edexcel IAL Physics tutor. I can help with topics like mechanics, electricity, waves, fields, nuclear physics, and more. What would you like to learn about today?",
'math': "๐ Welcome to Mathematics! I'm your Edexcel IAL Mathematics tutor. I can help with topics like pure mathematics, statistics, mechanics, and more. What would you like to learn about today?",
'ielts-speaking': "๐ Welcome to IELTS Speaking! I can help you prepare for your speaking test with practice questions, vocabulary, strategies, and feedback. How would you like to practice today?",
'ielts-writing': "๐ Welcome to IELTS Writing! I can help you improve your writing skills for both Task 1 and Task 2, including essay structure, vocabulary, grammar, and more. What aspect of IELTS writing would you like help with?",
'ielts-reading': "๐ Welcome to IELTS Reading! I can help you with reading strategies, practice questions, vocabulary building, and more to improve your reading skills. What aspect of IELTS reading would you like to work on?",
'ielts-listening': "๐ Welcome to IELTS Listening! I can help you with listening strategies, practice questions, note-taking skills, and more. How would you like to improve your listening skills today?"
};
return welcomeMessages[subject] || "๐ Welcome! How can I help you today?";
}
// Toggle sidebar
function toggleSidebar(forceState = null) {
const isOpen = sidebarMenu.classList.contains('-translate-x-0');
const newState = forceState !== null ? forceState : !isOpen;
if (newState) {
sidebarMenu.classList.remove('-translate-x-full');
sidebarMenu.classList.add('translate-x-0');
} else {
sidebarMenu.classList.remove('translate-x-0');
sidebarMenu.classList.add('-translate-x-full');
}
}
// Update history modal
function updateHistoryModal() {
const historyList = document.getElementById('history-list');
const noHistory = document.getElementById('no-history');
historyList.innerHTML = '';
let hasHistory = false;
for (const subject in state.chatHistory) {
if (state.chatHistory[subject].length > 0) {
hasHistory = true;
// Add subject header
const subjectHeader = document.createElement('h3');
subjectHeader.classList.add('text-sm', 'font-semibold', 'text-gray-500', 'dark:text-gray-400', 'uppercase', 'tracking-wider', 'mb-2', 'mt-4');
subjectHeader.textContent = getSubjectDisplayName(subject);
historyList.appendChild(subjectHeader);
// Add chats for this subject
state.chatHistory[subject].forEach(chat => {
const chatItem = document.createElement('div');
chatItem.classList.add('glass-card', 'p-3', 'rounded-lg', 'cursor-pointer', 'hover:bg-gray-100', 'dark:hover:bg-gray-800');
// Get first messages for preview
let preview = 'Empty chat';
if (chat.messages && chat.messages.length > 0) {
const firstUserMsg = chat.messages.find(m => m.sender === 'user');
preview = firstUserMsg ? firstUserMsg.text : chat.messages[0].text;
if (preview.length > 40) {
preview = preview.substring(0, 40) + '...';
}
}
// Format date
const date = new Date(chat.id);
const dateStr = date.toLocaleDateString() + ' ' + date.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
chatItem.innerHTML = `
`;
chatItem.addEventListener('click', () => {
loadChat(subject, chat.id);
historyModal.classList.add('hidden');
});
historyList.appendChild(chatItem);
});
}
}
if (hasHistory) {
noHistory.classList.add('hidden');
historyList.classList.remove('hidden');
} else {
noHistory.classList.remove('hidden');
historyList.classList.add('hidden');
}
}
// Load a specific chat
function loadChat(subject, chatId) {
if (state.currentSubject !== subject) {
changeSubject(subject);
}
const chat = state.chatHistory[subject].find(c => c.id === chatId);
if (chat) {
state.activeChat = chat;
// Clear chat container
chatContainer.innerHTML = '';
// Add messages
chat.messages.forEach(msg => {
appendMessage(msg.text, msg.sender);
});
}
}
// Clear history
function clearHistory() {
if (confirm('Are you sure you want to clear all chat history? This cannot be undone.')) {
state.chatHistory = {};
state.activeChat = null;
saveChatHistory();
updateHistoryModal();
// Clear current chat
chatContainer.innerHTML = '';
// Add welcome message
const welcomeMessage = getWelcomeMessage(state.currentSubject);
appendMessage(welcomeMessage, 'ai');
}
}
// Generate quiz
function generateQuiz() {
const numQuestions = document.getElementById('quiz-num-questions').value;
const difficulty = document.getElementById('quiz-difficulty').value;
const topic = document.getElementById('quiz-topic').value.trim();
const quizContent = document.getElementById('quiz-content');
quizContent.innerHTML = `
`;
// Construct prompt based on subject and parameters
let prompt = `Generate a ${numQuestions}-question ${difficulty} difficulty quiz about ${getSubjectDisplayName(state.currentSubject)}`;
if (topic) {
prompt += ` focusing on ${topic}`;
}
prompt += `. Format: numbered questions with multiple choice options (A, B, C, D) and correct answer marked. Include explanation for each answer.`;
// Send message to API (we're reusing the existing API for simplicity)
fetch('https://server-ef04.onrender.com/api/chat/message', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
chatId: currentChatId,
message: prompt
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Parse quiz response and display
displayQuiz(data.response, numQuestions, difficulty, topic);
} else {
throw new Error(data.error || 'Failed to generate quiz');
}
})
.catch(error => {
quizContent.innerHTML = `
`;
document.getElementById('retry-quiz-btn').addEventListener('click', () => {
document.getElementById('quiz-modal').classList.add('hidden');
setTimeout(() => {
document.getElementById('quiz-btn').click();
}, 300);
});
});
}
// Display quiz
function displayQuiz(quizText, numQuestions, difficulty, topic) {
const quizContent = document.getElementById('quiz-content');
// Simple parsing to show the quiz content with markdown support
quizContent.innerHTML = `
`;
// Add event listeners
document.getElementById('new-quiz-btn').addEventListener('click', () => {
document.getElementById('quiz-modal').classList.add('hidden');
setTimeout(() => {
document.getElementById('quiz-btn').click();
}, 300);
});
document.getElementById('save-quiz-btn').addEventListener('click', () => {
// Save quiz to chat
appendMessage(`Quiz (${difficulty}, ${numQuestions} questions${topic ? ` on ${topic}` : ''})`, 'user');
appendMessage(quizText, 'ai');
// Add to history
if (!state.activeChat) {
state.activeChat = {
id: Date.now(),
subject: state.currentSubject,
messages: []
};
if (!state.chatHistory[state.currentSubject]) {
state.chatHistory[state.currentSubject] = [];
}
state.chatHistory[state.currentSubject].unshift(state.activeChat);
}
state.activeChat.messages.push({
sender: 'user',
text: `Quiz (${difficulty}, ${numQuestions} questions${topic ? ` on ${topic}` : ''})`,
timestamp: Date.now()
});
state.activeChat.messages.push({
sender: 'ai',
text: quizText,
timestamp: Date.now()
});
saveChatHistory();
// Close modal
document.getElementById('quiz-modal').classList.add('hidden');
});
}
// Generate revision plan
function generateRevisionPlan() {
const examDate = document.getElementById('revision-exam-date').value;
const studyHours = document.getElementById('revision-hours').value;
const focusAreas = document.getElementById('revision-focus').value.trim();
// Validate exam date
if (!examDate) {
alert('Please select an exam date');
return;
}
const revisionContent = document.getElementById('revision-content');
revisionContent.innerHTML = `
`;
// Calculate weeks until exam
const today = new Date();
const examDay = new Date(examDate);
const daysUntilExam = Math.ceil((examDay - today) / (1000 * 60 * 60 * 24));
const weeksUntilExam = Math.ceil(daysUntilExam / 7);
// Construct prompt
let prompt = `Create a ${weeksUntilExam}-week revision plan for ${getSubjectDisplayName(state.currentSubject)} with approximately ${studyHours} study hours per week`;
if (focusAreas) {
prompt += `, focusing on these areas: ${focusAreas}`;
}
prompt += `. The exam is on ${examDate}. Include specific topics to study each week, recommended resources, and practice questions. Format as a week-by-week schedule.`;
// Send message to API
fetch('https://server-ef04.onrender.com/api/chat/message', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
chatId: currentChatId,
message: prompt
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Display revision plan
displayRevisionPlan(data.response, examDate, studyHours, focusAreas);
} else {
throw new Error(data.error || 'Failed to generate revision plan');
}
})
.catch(error => {
revisionContent.innerHTML = `
`;
document.getElementById('retry-plan-btn').addEventListener('click', () => {
document.getElementById('revision-modal').classList.add('hidden');
setTimeout(() => {
document.getElementById('revision-btn').click();
}, 300);
});
});
}
// Display revision plan
function displayRevisionPlan(planText, examDate, studyHours, focusAreas) {
const revisionContent = document.getElementById('revision-content');
revisionContent.innerHTML = `
`;
// Add event listeners
document.getElementById('new-plan-btn').addEventListener('click', () => {
document.getElementById('revision-modal').classList.add('hidden');
setTimeout(() => {
document.getElementById('revision-btn').click();
}, 300);
});
document.getElementById('save-plan-btn').addEventListener('click', () => {
// Save plan to chat
const userPrompt = `Revision plan for ${getSubjectDisplayName(state.currentSubject)} (Exam: ${new Date(examDate).toLocaleDateString()}, ${studyHours} hours/week${focusAreas ? `, Focus: ${focusAreas}` : ''})`;
appendMessage(userPrompt, 'user');
appendMessage(planText, 'ai');
// Add to history
if (!state.activeChat) {
state.activeChat = {
id: Date.now(),
subject: state.currentSubject,
messages: []
};
if (!state.chatHistory[state.currentSubject]) {
state.chatHistory[state.currentSubject] = [];
}
state.chatHistory[state.currentSubject].unshift(state.activeChat);
}
state.activeChat.messages.push({
sender: 'user',
text: userPrompt,
timestamp: Date.now()
});
state.activeChat.messages.push({
sender: 'ai',
text: planText,
timestamp: Date.now()
});
saveChatHistory();
// Close modal
document.getElementById('revision-modal').classList.add('hidden');
});
}
// Initialize App
function initApp() {
// Set up color scheme listener
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
state.isDarkMode = event.matches;
initTheme();
});
// Load chat history
loadChatHistory();
// Initialize theme
initTheme();
// Initialize speech recognition
initSpeechRecognition();
// Show app interface directly with default subject
setTimeout(() => {
loadingScreen.classList.add('hidden');
appInterface.classList.remove('hidden');
// Set default subject
const defaultSubject = 'biology';
state.currentSubject = defaultSubject;
// Set subject title
currentSubjectEl.textContent = getSubjectDisplayName(defaultSubject);
// Add welcome message
const welcomeMessage = getWelcomeMessage(defaultSubject);
appendMessage(welcomeMessage, 'ai');
// Start new chat session
startNewChat();
}, 2000);
// Subject buttons in sidebar
document.querySelectorAll('.sidebar-subject-btn').forEach(btn => {
btn.addEventListener('click', () => {
const subject = btn.getAttribute('data-sidebar-subject');
changeSubject(subject);
});
});
// Menu toggle
menuToggleBtn.addEventListener('click', () => {
toggleSidebar();
});
// Send button
sendButton.addEventListener('click', () => {
const message = messageInput.value.trim();
if (message) {
sendMessage(message);
messageInput.value = '';
}
});
// Message input enter key
messageInput.addEventListener('keypress', e => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
const message = messageInput.value.trim();
if (message) {
sendMessage(message);
messageInput.value = '';
}
}
});
// Voice button
voiceButton.addEventListener('click', toggleRecording);
// Quiz button
document.getElementById('quiz-btn').addEventListener('click', () => {
quizModal.classList.remove('hidden');
});
// Close quiz modal
document.getElementById('close-quiz-btn').addEventListener('click', () => {
quizModal.classList.add('hidden');
});
// Start quiz button
document.getElementById('start-quiz-btn').addEventListener('click', generateQuiz);
// Revision plan button
document.getElementById('revision-btn').addEventListener('click', () => {
// Set default exam date (30 days from now)
const defaultDate = new Date();
defaultDate.setDate(defaultDate.getDate() + 30);
document.getElementById('revision-exam-date').valueAsDate = defaultDate;
revisionModal.classList.remove('hidden');
});
// Close revision modal
document.getElementById('close-revision-btn').addEventListener('click', () => {
revisionModal.classList.add('hidden');
});
// Create plan button
document.getElementById('create-plan-btn').addEventListener('click', generateRevisionPlan);
// Chat history button
document.getElementById('chat-history-btn').addEventListener('click', () => {
updateHistoryModal();
historyModal.classList.remove('hidden');
});
// Close history modal
document.getElementById('close-history-btn').addEventListener('click', () => {
historyModal.classList.add('hidden');
});
// Clear history button
document.getElementById('clear-history-btn').addEventListener('click', clearHistory);
// Toggle theme button
document.getElementById('toggle-theme-btn').addEventListener('click', toggleTheme);
// Close sidebar when clicking outside
document.addEventListener('click', e => {
if (sidebarMenu.classList.contains('translate-x-0') &&
!sidebarMenu.contains(e.target) &&
e.target !== menuToggleBtn &&
!menuToggleBtn.contains(e.target)) {
toggleSidebar(false);
}
});
}
// Initialize the app
initApp();
AI Teacher Pro
Loading your educational experience...
Subject
AI Teacher Pro
AI Teacher Pro
Edexcel IAL
IELTS
Quiz Mode
Start a Quiz
Test your knowledge with a subject-specific quiz
5 questions
10 questions
15 questions
20 questions
Easy
Medium
Hard
Revision Plan
Create a Revision Plan
Let AI create a personalized study schedule
~5 hours
~10 hours
~15 hours
~20 hours
~30 hours
Chat History
No chat history yet
${preview}
${dateStr}
Generating Quiz
Please wait while we create your quiz...
Error
${error.message}
Quiz: ${getSubjectDisplayName(state.currentSubject)}
${difficulty} ยท ${numQuestions} questions
${marked.parse(quizText)}
Creating Your Plan
Please wait while we design your personalized revision plan...
Error
${error.message}
Revision Plan: ${getSubjectDisplayName(state.currentSubject)}
Exam date: ${new Date(examDate).toLocaleDateString()}
${marked.parse(planText)}
This is incredible!