| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>SmartLearn - Quiz Generation</title> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <style> |
| @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap'); |
| |
| body { |
| font-family: 'Poppins', sans-serif; |
| margin: 0; |
| padding: 0; |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| min-height: 100vh; |
| background-image: url('../static/quiz.jpg'); |
| background-size: cover; |
| background-position: center; |
| background-attachment: fixed; |
| } |
| |
| .container { |
| border-radius: 20px; |
| padding: 40px; |
| width: 90%; |
| max-width: 500px; |
| text-align: center; |
| position: relative; |
| z-index: 2; |
| background: rgba(255, 255, 255, 0.1); |
| backdrop-filter: blur(10px); |
| box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37); |
| border: 1px solid rgba(255, 255, 255, 0.18); |
| } |
| |
| .quiz-form { |
| padding: 20px; |
| border-radius: 10px; |
| } |
| |
| .form-group { |
| margin-bottom: 20px; |
| text-align: left; |
| } |
| |
| .form-group label { |
| display: block; |
| margin-bottom: 5px; |
| color: #fff; |
| font-weight: 600; |
| } |
| |
| .form-group input, |
| .form-group select { |
| width: 100%; |
| padding: 10px; |
| border: none; |
| border-radius: 5px; |
| background: rgba(255, 255, 255, 0.8); |
| color: #000; |
| font-size: 16px; |
| } |
| |
| .form-group select { |
| appearance: none; |
| background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E"); |
| background-repeat: no-repeat; |
| background-position: right 10px center; |
| background-size: 20px; |
| } |
| |
| .btn { |
| background-color: #3498db; |
| color: white; |
| border: none; |
| padding: 12px 24px; |
| border-radius: 30px; |
| cursor: pointer; |
| font-size: 18px; |
| transition: all 0.3s ease; |
| } |
| |
| .btn:hover { |
| background-color: #2980b9; |
| transform: translateY(-2px); |
| box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); |
| } |
| |
| h1, h2, h3 { |
| color: #fff; |
| text-shadow: 2px 2px 4px rgba(0,0,0,0.5); |
| } |
| |
| .score-circle { |
| width: 150px; |
| height: 150px; |
| background-color: rgba(52, 152, 219, 0.8); |
| border-radius: 50%; |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| margin: 0 auto 30px; |
| font-size: 36px; |
| font-weight: bold; |
| color: white; |
| box-shadow: 0 5px 15px rgba(52, 152, 219, 0.3); |
| } |
| |
| .areas-to-improve { |
| background-color: rgba(248, 249, 250, 0.1); |
| border-radius: 10px; |
| padding: 20px; |
| text-align: left; |
| color: #fff; |
| } |
| |
| .areas-to-improve ol { |
| padding-left: 20px; |
| } |
| |
| .areas-to-improve li { |
| margin-bottom: 10px; |
| } |
| |
| .validation-container { |
| display: none; |
| justify-content: center; |
| align-items: center; |
| flex-direction: column; |
| } |
| |
| .loader { |
| border: 5px solid rgba(255, 255, 255, 0.3); |
| border-top: 5px solid #3498db; |
| border-radius: 50%; |
| width: 50px; |
| height: 50px; |
| animation: spin 1s linear infinite; |
| } |
| |
| @keyframes spin { |
| 0% { transform: rotate(0deg); } |
| 100% { transform: rotate(360deg); } |
| } |
| |
| .validation-text { |
| margin-top: 20px; |
| font-size: 18px; |
| color: #fff; |
| } |
| |
| .correct { color: #2ecc71; } |
| .incorrect { color: #e74c3c; } |
| #areas-to-improve { margin-top: 20px; } |
| |
| .options li { |
| display: flex; |
| align-items: center; |
| margin-bottom: 10px; |
| color: #fff; |
| } |
| |
| .options li input { |
| margin-right: 10px; |
| } |
| |
| .back-button { |
| position: absolute; |
| top: 20px; |
| left: 20px; |
| background-color: #6c757d; |
| color: white; |
| border: none; |
| padding: 10px 20px; |
| border-radius: 30px; |
| cursor: pointer; |
| transition: background-color 0.3s; |
| font-size: 16px; |
| } |
| |
| .back-button:hover { |
| background-color: #5a6268; |
| } |
| |
| .fade-in { |
| animation: fadeIn 0.5s ease-in-out; |
| } |
| |
| @keyframes fadeIn { |
| from { opacity: 0; transform: translateY(20px); } |
| to { opacity: 1; transform: translateY(0); } |
| } |
| |
| .icon { |
| margin-right: 10px; |
| } |
| |
| .loading-animation { |
| display: flex; |
| flex-direction: column; |
| align-items: center; |
| justify-content: center; |
| margin-top: 20px; |
| } |
| |
| .loading-animation p { |
| margin-top: 10px; |
| color: #fff; |
| font-weight: 600; |
| } |
| |
| @keyframes pulse { |
| 0% { transform: scale(1); } |
| 50% { transform: scale(1.1); } |
| 100% { transform: scale(1); } |
| } |
| |
| .loading-icon { |
| font-size: 48px; |
| color: #3498db; |
| animation: pulse 1.5s infinite; |
| } |
| </style> |
| </head> |
| <body> |
| <div class="container fade-in"> |
| <button class="back-button" onclick="goBack()"><i class="fas fa-arrow-left"></i> Back</button> |
| <h1><i class="fas fa-graduation-cap icon"></i>Generate Your Custom Quiz</h1> |
| <form class="quiz-form"> |
| <div class="form-group"> |
| <label for="subject"><i class="fas fa-book icon"></i>Subject:</label> |
| <input type="text" id="subject" name="subject" required> |
| </div> |
| <div class="form-group"> |
| <label for="topic"><i class="fas fa-lightbulb icon"></i>Topic:</label> |
| <input type="text" id="topic" name="topic" required> |
| </div> |
| <div class="form-group"> |
| <label for="num-questions"><i class="fas fa-list-ol icon"></i>Number of Questions:</label> |
| <select id="num-questions" name="num-questions"> |
| <option value="2">2</option> |
| <option value="5">5</option> |
| <option value="10">10</option> |
| <option value="15">15</option> |
| <option value="20">20</option> |
| </select> |
| </div> |
| <div class="form-group"> |
| <label for="difficulty"><i class="fas fa-signal icon"></i>Difficulty Level:</label> |
| <select id="difficulty" name="difficulty"> |
| <option value="easy">Easy</option> |
| <option value="medium">Medium</option> |
| <option value="hard">Hard</option> |
| </select> |
| </div> |
| <button type="submit" class="btn"><i class="fas fa-magic icon"></i>Generate Quiz</button> |
| </form> |
|
|
| <div id="loading-animation" class="loading-animation" style="display: none;"> |
| <i class="fas fa-cog loading-icon"></i> |
| <p id="loading-text">Generating Quiz...</p> |
| </div> |
|
|
| <div id="quiz-result" class="quiz-result" style="display: none;"> |
| |
| </div> |
| <div id="validation-container" class="validation-container"> |
| <div id="loader" class="loader"></div> |
| <div id="validation-text" class="validation-text">Validating...</div> |
| </div> |
| <div id="quiz-score" style="display: none;"></div> |
| <div id="areas-to-improve" class="areas-to-improve" style="display: none;"></div> |
| </div> |
|
|
| <script> |
| let quizData = []; |
| let studentId = 'alice.johnson@stateu.edu'; |
| |
| document.querySelector('.quiz-form').addEventListener('submit', function(e) { |
| e.preventDefault(); |
| const formData = new FormData(this); |
| const data = { |
| subject: formData.get('subject'), |
| topic: formData.get('topic'), |
| 'num-questions': formData.get('num-questions'), |
| difficulty: formData.get('difficulty') |
| }; |
| |
| |
| this.style.display = 'none'; |
| document.getElementById('loading-animation').style.display = 'flex'; |
| |
| let loadingTexts = [ |
| "Crafting challenging questions...", |
| "Digging deep into the subject...", |
| "Polishing the perfect quiz for you...", |
| "Almost there, finalizing details..." |
| ]; |
| let currentTextIndex = 0; |
| |
| |
| const loadingInterval = setInterval(() => { |
| document.getElementById('loading-text').textContent = loadingTexts[currentTextIndex]; |
| currentTextIndex = (currentTextIndex + 1) % loadingTexts.length; |
| }, 3000); |
| |
| fetch('/generate_quiz', { |
| method: 'POST', |
| headers: { |
| 'Content-Type': 'application/json', |
| }, |
| body: JSON.stringify(data) |
| }) |
| .then(response => response.json()) |
| .then(data => { |
| |
| clearInterval(loadingInterval); |
| |
| |
| document.getElementById('loading-animation').style.display = 'none'; |
| |
| quizData = parseQuizData(data.quiz); |
| showQuiz(quizData); |
| }) |
| .catch(error => { |
| console.error('Error:', error); |
| |
| clearInterval(loadingInterval); |
| |
| document.getElementById('loading-animation').style.display = 'none'; |
| alert('An error occurred while generating the quiz. Please try again.'); |
| }); |
| }); |
| |
| function parseQuizData(quizString) { |
| const questions = quizString.split('Question:').filter(q => q.trim() !== ''); |
| return questions.map((question, index) => { |
| const [questionText, ...options] = question.split('\n').filter(line => line.trim() !== ''); |
| const answerLine = options.pop(); |
| const correctAnswer = parseInt(answerLine.split(':')[1].trim()); |
| return { |
| id: index + 1, |
| text: questionText.trim(), |
| options: options.map(opt => opt.replace('<<o>>', '').trim()), |
| correctAnswer: correctAnswer, |
| concept: questionText.match(/\[(.*?)\]/)[1] |
| }; |
| }); |
| } |
| |
| function showQuiz(questions) { |
| const quizResult = document.getElementById('quiz-result'); |
| let quizHtml = '<h2>Your Custom Quiz</h2>'; |
| |
| questions.forEach((question, index) => { |
| quizHtml += ` |
| <div class="question fade-in"> |
| <h3>${question.id}. ${question.text}</h3> |
| <ul class="options"> |
| `; |
| |
| question.options.forEach((option, optionIndex) => { |
| quizHtml += ` |
| <li> |
| <input type="radio" name="q${index}" value="${optionIndex + 1}" id="q${index}o${optionIndex}"> |
| <label for="q${index}o${optionIndex}">${option}</label> |
| </li> |
| `; |
| }); |
| |
| quizHtml += ` |
| </ul> |
| </div> |
| `; |
| }); |
| |
| quizHtml += '<button onclick="submitQuiz()" class="btn">Submit Quiz</button>'; |
| |
| quizResult.innerHTML = quizHtml; |
| quizResult.style.display = 'block'; |
| } |
| |
| function submitQuiz() { |
| const validationContainer = document.getElementById('validation-container'); |
| const quizResult = document.getElementById('quiz-result'); |
| const quizScore = document.getElementById('quiz-score'); |
| const areasToImprove = document.getElementById('areas-to-improve'); |
| |
| quizResult.style.display = 'none'; |
| validationContainer.style.display = 'flex'; |
| |
| setTimeout(() => { |
| validationContainer.style.display = 'none'; |
| const score = calculateScore(); |
| displayResults(score); |
| |
| |
| let improveAreas = []; |
| let incorrectQuestions = quizData.filter((question, index) => { |
| const selectedAnswer = document.querySelector(`input[name="q${index}"]:checked`); |
| return !selectedAnswer || parseInt(selectedAnswer.value) !== question.correctAnswer; |
| }); |
| |
| if (incorrectQuestions.length > 0) { |
| improveAreas = incorrectQuestions.map(question => question.concept); |
| } |
| |
| |
| fetch('/update_student_areas', { |
| method: 'POST', |
| headers: { |
| 'Content-Type': 'application/json', |
| }, |
| body: JSON.stringify({ student_id: studentId, areas_to_improve: improveAreas }) |
| }) |
| .then(response => response.json()) |
| .then(data => { |
| if (data.status === 'success') { |
| console.log('Student areas to improve updated successfully.'); |
| } else { |
| console.error('Failed to update student areas to improve.'); |
| } |
| }) |
| .catch(error => console.error('Error:', error)); |
| |
| }, 2000); |
| } |
| |
| function calculateScore() { |
| let score = 0; |
| quizData.forEach((question, index) => { |
| const selectedAnswer = document.querySelector(`input[name="q${index}"]:checked`); |
| if (selectedAnswer && parseInt(selectedAnswer.value) === question.correctAnswer) { |
| score++; |
| } |
| }); |
| return score; |
| } |
| |
| function displayResults(score) { |
| const quizScore = document.getElementById('quiz-score'); |
| const areasToImprove = document.getElementById('areas-to-improve'); |
| |
| quizScore.innerHTML = ` |
| <div class="score-circle">${score}/${quizData.length}</div> |
| <h3>You have scored</h3> |
| <p>Performance: ${getPerformanceEvaluation(score, quizData.length)}</p> |
| `; |
| quizScore.style.display = 'block'; |
| |
| let incorrectQuestions = quizData.filter((question, index) => { |
| const selectedAnswer = document.querySelector(`input[name="q${index}"]:checked`); |
| return !selectedAnswer || parseInt(selectedAnswer.value) !== question.correctAnswer; |
| }); |
| |
| if (incorrectQuestions.length > 0) { |
| let improveHtml = '<h3>Areas to be improved</h3><ol>'; |
| incorrectQuestions.forEach(question => { |
| improveHtml += `<li>${question.concept}</li>`; |
| }); |
| improveHtml += '</ol>'; |
| areasToImprove.innerHTML = improveHtml; |
| areasToImprove.style.display = 'block'; |
| } |
| } |
| |
| function getPerformanceEvaluation(score, total) { |
| const percentage = (score / total) * 100; |
| if (percentage >= 80) return 'Excellent'; |
| if (percentage >= 60) return 'Good'; |
| if (percentage >= 40) return 'Average'; |
| return 'Needs Improvement'; |
| } |
| |
| function goBack() { |
| window.history.back(); |
| } |
| </script> |
| </body> |
| </html> |