Spaces:
Sleeping
Sleeping
| {% extends 'base.html' %} | |
| {% block title %}Step 2: Configure Questions - AutoExamGen{% endblock %} | |
| {% block head %} | |
| <style> | |
| body { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| min-height: 100vh; | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| } | |
| .container { | |
| padding-top: 2rem; | |
| } | |
| .card { | |
| border: none; | |
| border-radius: 15px; | |
| box-shadow: 0 10px 30px rgba(0,0,0,0.1); | |
| backdrop-filter: blur(10px); | |
| background: rgba(255, 255, 255, 0.95); | |
| } | |
| .btn-primary { | |
| background: linear-gradient(45deg, #667eea, #764ba2); | |
| border: none; | |
| border-radius: 25px; | |
| padding: 12px 30px; | |
| font-weight: 600; | |
| transition: all 0.3s ease; | |
| } | |
| .btn-primary:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 5px 15px rgba(0,0,0,0.2); | |
| } | |
| .btn-secondary { | |
| border-radius: 25px; | |
| padding: 12px 30px; | |
| font-weight: 600; | |
| } | |
| .form-control, .form-select { | |
| border-radius: 10px; | |
| border: 2px solid #e9ecef; | |
| transition: all 0.3s ease; | |
| } | |
| .form-control:focus, .form-select:focus { | |
| border-color: #667eea; | |
| box-shadow: 0 0 0 0.2rem rgba(102, 126, 234, 0.25); | |
| } | |
| .step-indicator { | |
| display: flex; | |
| justify-content: center; | |
| margin-bottom: 2rem; | |
| } | |
| .step { | |
| width: 40px; | |
| height: 40px; | |
| border-radius: 50%; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| margin: 0 10px; | |
| font-weight: bold; | |
| color: white; | |
| } | |
| .step.active { | |
| background: linear-gradient(45deg, #667eea, #764ba2); | |
| } | |
| .step.completed { | |
| background: #28a745; | |
| } | |
| .step.inactive { | |
| background: #ccc; | |
| } | |
| .question-type-card { | |
| border: 2px solid #e9ecef; | |
| border-radius: 15px; | |
| padding: 1.5rem; | |
| margin-bottom: 1rem; | |
| transition: all 0.3s ease; | |
| } | |
| .question-type-card:hover { | |
| border-color: #667eea; | |
| box-shadow: 0 5px 15px rgba(0,0,0,0.1); | |
| } | |
| .question-type-card.active { | |
| border-color: #667eea; | |
| background-color: #f8f9ff; | |
| } | |
| .marks-preview { | |
| background: linear-gradient(45deg, #667eea, #764ba2); | |
| color: white; | |
| border-radius: 10px; | |
| padding: 1rem; | |
| text-align: center; | |
| } | |
| .alert { | |
| border-radius: 10px; | |
| } | |
| .input-group-text { | |
| border-radius: 10px 0 0 10px; | |
| } | |
| .form-control.rounded-end { | |
| border-radius: 0 10px 10px 0; | |
| } | |
| </style> | |
| {% endblock %} | |
| {% block content %} | |
| <div class="container"> | |
| <div class="row justify-content-center"> | |
| <div class="col-md-10"> | |
| <!-- Progress Indicator --> | |
| <div class="step-indicator"> | |
| <div class="step completed">1</div> | |
| <div class="step active">2</div> | |
| <div class="step inactive">3</div> | |
| </div> | |
| <div class="card"> | |
| <div class="card-header bg-transparent text-center py-4"> | |
| <h2 class="mb-0"> | |
| <i class="fas fa-cogs text-primary me-2"></i> | |
| Step 2: Configure Your Question Paper | |
| </h2> | |
| <p class="text-muted mt-2">Choose the types and number of questions for your exam paper</p> | |
| <div class="badge bg-info"> | |
| <i class="fas fa-file-text me-1"></i> | |
| Syllabus loaded: {{ word_count }} words | |
| </div> | |
| </div> | |
| <div class="card-body p-4"> | |
| {% if error %} | |
| <div class="alert alert-danger" role="alert"> | |
| <i class="fas fa-exclamation-triangle me-2"></i>{{ error }} | |
| </div> | |
| {% endif %} | |
| <form action="{{ url_for('step3_generate') }}" method="POST" id="configForm"> | |
| <!-- Exam Details --> | |
| <div class="row mb-4"> | |
| <div class="col-md-12"> | |
| <div class="question-type-card"> | |
| <div class="row g-3"> | |
| <div class="col-md-4"> | |
| <label class="form-label">Exam Name (optional)</label> | |
| <input type="text" class="form-control" name="exam_name" id="exam_name" placeholder="e.g., Midterm Examination"> | |
| </div> | |
| <div class="col-md-4"> | |
| <label class="form-label">Subject Name (optional)</label> | |
| <input type="text" class="form-control" name="subject_name" id="subject_name" placeholder="e.g., Computer Science"> | |
| </div> | |
| <div class="col-md-4"> | |
| <label class="form-label">Exam Duration (optional)</label> | |
| <input type="text" class="form-control" name="exam_duration" id="exam_duration" placeholder="e.g., 180, 3h, 3 hours, 2h 30m"> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="row"> | |
| <!-- Multiple Choice Questions --> | |
| <div class="col-md-4"> | |
| <div class="question-type-card" id="mcqCard"> | |
| <div class="text-center mb-3"> | |
| <i class="fas fa-list-ul fa-3x text-warning"></i> | |
| <h5 class="mt-2">Multiple Choice Questions</h5> | |
| <p class="text-muted small">Questions with multiple options to choose from</p> | |
| </div> | |
| <div class="mb-3"> | |
| <label class="form-label">Number of Questions</label> | |
| <input type="number" class="form-control" name="mcq_questions" id="mcq_questions" | |
| value="0" min="0" max="30" onchange="updatePreview()"> | |
| </div> | |
| <div class="mb-3"> | |
| <label class="form-label">Marks per Question</label> | |
| <div class="input-group"> | |
| <input type="number" class="form-control rounded-end" value="1" readonly> | |
| <span class="input-group-text">mark</span> | |
| </div> | |
| <div class="form-text">MCQ questions are typically 1 mark each</div> | |
| </div> | |
| <div class="text-center"> | |
| <span class="badge bg-warning" id="mcqTotal">0 marks total</span> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Short Answer Questions --> | |
| <div class="col-md-4"> | |
| <div class="question-type-card" id="shortCard"> | |
| <div class="text-center mb-3"> | |
| <i class="fas fa-edit fa-3x text-primary"></i> | |
| <h5 class="mt-2">Short Answer Questions</h5> | |
| <p class="text-muted small">Brief, focused questions requiring concise answers</p> | |
| </div> | |
| <div class="mb-3"> | |
| <label class="form-label">Number of Questions</label> | |
| <input type="number" class="form-control" name="short_questions" id="short_questions" | |
| value="0" min="0" max="20" onchange="updatePreview()"> | |
| </div> | |
| <div class="mb-3"> | |
| <label class="form-label">Marks per Question</label> | |
| <div class="input-group"> | |
| <input type="number" class="form-control rounded-end" name="short_marks" id="short_marks" | |
| value="3" min="1" max="10" onchange="updatePreview()"> | |
| <span class="input-group-text">marks</span> | |
| </div> | |
| </div> | |
| <div class="form-check mb-3"> | |
| <input class="form-check-input" type="checkbox" value="1" id="short_or" name="short_or" onchange="updatePreview()"> | |
| <label class="form-check-label" for="short_or"> | |
| Provide an 'OR' alternative for each short question | |
| </label> | |
| </div> | |
| <div class="text-center"> | |
| <span class="badge bg-primary" id="shortTotal">0 marks total</span> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Long Answer Questions --> | |
| <div class="col-md-4"> | |
| <div class="question-type-card" id="longCard"> | |
| <div class="text-center mb-3"> | |
| <i class="fas fa-file-alt fa-3x text-success"></i> | |
| <h5 class="mt-2">Long Answer Questions</h5> | |
| <p class="text-muted small">Detailed questions requiring comprehensive answers</p> | |
| </div> | |
| <div class="mb-3"> | |
| <label class="form-label">Number of Questions</label> | |
| <input type="number" class="form-control" name="long_questions" id="long_questions" | |
| value="0" min="0" max="10" onchange="updatePreview()"> | |
| </div> | |
| <div class="mb-3"> | |
| <label class="form-label">Marks per Question</label> | |
| <div class="input-group"> | |
| <input type="number" class="form-control rounded-end" name="long_marks" id="long_marks" | |
| value="10" min="5" max="25" onchange="updatePreview()"> | |
| <span class="input-group-text">marks</span> | |
| </div> | |
| </div> | |
| <div class="mb-3"> | |
| <label class="form-label">Attempt any (optional)</label> | |
| <div class="input-group"> | |
| <input type="number" class="form-control rounded-end" name="long_attempt" id="long_attempt" | |
| value="" min="0" max="10" placeholder="e.g., 3" onchange="updatePreview()"> | |
| <span class="input-group-text">questions</span> | |
| </div> | |
| <div class="form-text">If set, students will be instructed to attempt only this many long questions.</div> | |
| </div> | |
| <div class="text-center"> | |
| <span class="badge bg-success" id="longTotal">0 marks total</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Summary Card --> | |
| <div class="row mt-4"> | |
| <div class="col-md-12"> | |
| <div class="marks-preview"> | |
| <h4 class="mb-3"> | |
| <i class="fas fa-calculator me-2"></i> | |
| Question Paper Summary | |
| </h4> | |
| <div class="row"> | |
| <div class="col-md-3 text-center"> | |
| <h5 id="totalQuestions">0</h5> | |
| <small>Total Questions</small> | |
| </div> | |
| <div class="col-md-3 text-center"> | |
| <h5 id="totalMarks">0</h5> | |
| <small>Total Marks</small> | |
| </div> | |
| <div class="col-md-3 text-center"> | |
| <h5 id="estimatedTime">0</h5> | |
| <small>Estimated Time (min)</small> | |
| </div> | |
| <div class="col-md-3 text-center"> | |
| <h5 id="difficulty">Easy</h5> | |
| <small>Difficulty Level</small> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Action Buttons --> | |
| <div class="row mt-4"> | |
| <div class="col-md-6"> | |
| <a href="/" class="btn btn-secondary btn-lg w-100"> | |
| <i class="fas fa-arrow-left me-2"></i> | |
| Back to Input | |
| </a> | |
| </div> | |
| <div class="col-md-6"> | |
| <button type="submit" class="btn btn-primary btn-lg w-100" id="generateBtn"> | |
| <i class="fas fa-magic me-2"></i> | |
| Generate Question Paper | |
| </button> | |
| </div> | |
| </div> | |
| </form> | |
| </div> | |
| </div> | |
| <!-- Tips Card --> | |
| <div class="card mt-4"> | |
| <div class="card-body"> | |
| <h5 class="card-title"> | |
| <i class="fas fa-lightbulb text-warning me-2"></i> | |
| Configuration Tips | |
| </h5> | |
| <div class="row"> | |
| <div class="col-md-4"> | |
| <h6><i class="fas fa-list-ul text-warning me-2"></i>MCQ Questions</h6> | |
| <small class="text-muted">Great for testing factual knowledge and quick assessment. Usually 1 mark each.</small> | |
| </div> | |
| <div class="col-md-4"> | |
| <h6><i class="fas fa-edit text-primary me-2"></i>Short Questions</h6> | |
| <small class="text-muted">Best for definitions, concepts, and quick explanations. Usually 2-5 marks.</small> | |
| </div> | |
| <div class="col-md-4"> | |
| <h6><i class="fas fa-file-alt text-success me-2"></i>Long Questions</h6> | |
| <small class="text-muted">Perfect for detailed explanations, analysis, and comprehensive answers. Usually 8-15 marks.</small> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| {% endblock %} | |
| {% block scripts %} | |
| <script> | |
| function updatePreview() { | |
| const shortQuestions = parseInt(document.getElementById('short_questions').value) || 0; | |
| const longQuestions = parseInt(document.getElementById('long_questions').value) || 0; | |
| const mcqQuestions = parseInt(document.getElementById('mcq_questions').value) || 0; | |
| const shortMarks = parseInt(document.getElementById('short_marks').value) || 3; | |
| const longMarks = parseInt(document.getElementById('long_marks').value) || 10; | |
| // Calculate totals | |
| const shortTotal = shortQuestions * shortMarks; | |
| const longTotal = longQuestions * longMarks; | |
| const mcqTotal = mcqQuestions * 1; // MCQ is always 1 mark | |
| const totalQuestions = shortQuestions + longQuestions + mcqQuestions; | |
| const totalMarks = shortTotal + longTotal + mcqTotal; | |
| // Update individual totals | |
| document.getElementById('shortTotal').textContent = shortTotal + ' marks total'; | |
| document.getElementById('longTotal').textContent = longTotal + ' marks total'; | |
| document.getElementById('mcqTotal').textContent = mcqTotal + ' marks total'; | |
| // Update summary | |
| document.getElementById('totalQuestions').textContent = totalQuestions; | |
| document.getElementById('totalMarks').textContent = totalMarks; | |
| // Estimate time unless custom duration provided (supports formats like '3 hours', '2h 30m') | |
| const customDurationRaw = document.getElementById('exam_duration').value.trim(); | |
| let customDuration = parseInt(customDurationRaw); | |
| if (customDurationRaw && isNaN(customDuration)) { | |
| const lower = customDurationRaw.toLowerCase(); | |
| // crude parse: extract h and m | |
| let minutesParsed = 0; | |
| const hMatch = lower.match(/(\d+)\s*h/); | |
| const mMatch = lower.match(/(\d+)\s*m/); | |
| if (hMatch) minutesParsed += parseInt(hMatch[1], 10) * 60; | |
| if (mMatch) minutesParsed += parseInt(mMatch[1], 10); | |
| if (minutesParsed > 0) customDuration = minutesParsed; | |
| } | |
| const estimatedTime = Math.round(totalMarks * 1.5); | |
| const timeToShow = (!isNaN(customDuration) && customDuration > 0) ? customDuration : estimatedTime; | |
| document.getElementById('estimatedTime').textContent = timeToShow; | |
| // Determine difficulty | |
| let difficulty = 'Easy'; | |
| if (totalMarks > 50) difficulty = 'Medium'; | |
| if (totalMarks > 100) difficulty = 'Hard'; | |
| document.getElementById('difficulty').textContent = difficulty; | |
| // Update card styles | |
| updateCardStyles(shortQuestions, longQuestions, mcqQuestions); | |
| // Enable/disable generate button | |
| const generateBtn = document.getElementById('generateBtn'); | |
| if (totalQuestions > 0) { | |
| generateBtn.disabled = false; | |
| generateBtn.innerHTML = '<i class="fas fa-magic me-2"></i>Generate Question Paper'; | |
| } else { | |
| generateBtn.disabled = true; | |
| generateBtn.innerHTML = '<i class="fas fa-exclamation-triangle me-2"></i>Select at least one question type'; | |
| } | |
| } | |
| function updateCardStyles(short, long, mcq) { | |
| const shortCard = document.getElementById('shortCard'); | |
| const longCard = document.getElementById('longCard'); | |
| const mcqCard = document.getElementById('mcqCard'); | |
| // Remove active class from all cards | |
| [shortCard, longCard, mcqCard].forEach(card => card.classList.remove('active')); | |
| // Add active class to cards with questions | |
| if (short > 0) shortCard.classList.add('active'); | |
| if (long > 0) longCard.classList.add('active'); | |
| if (mcq > 0) mcqCard.classList.add('active'); | |
| } | |
| // Form validation and loading state | |
| document.getElementById('configForm').addEventListener('submit', function(e) { | |
| const totalQuestions = parseInt(document.getElementById('totalQuestions').textContent); | |
| if (totalQuestions === 0) { | |
| e.preventDefault(); | |
| alert('Please select at least one question type before generating the paper.'); | |
| return; | |
| } | |
| // Show loading state | |
| const generateBtn = document.getElementById('generateBtn'); | |
| const originalText = generateBtn.innerHTML; | |
| generateBtn.disabled = true; | |
| generateBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Generating Questions... Please wait'; | |
| // Show loading message | |
| const loadingDiv = document.createElement('div'); | |
| loadingDiv.id = 'loadingMessage'; | |
| loadingDiv.className = 'alert alert-info mt-3'; | |
| loadingDiv.innerHTML = ` | |
| <div class="d-flex align-items-center"> | |
| <div class="spinner-border spinner-border-sm me-3" role="status"> | |
| <span class="visually-hidden">Loading...</span> | |
| </div> | |
| <div> | |
| <strong>Generating your question paper...</strong><br> | |
| <small>This may take 30-60 seconds. Please don't refresh the page.</small> | |
| </div> | |
| </div> | |
| `; | |
| // Insert loading message after the form | |
| const form = document.getElementById('configForm'); | |
| form.parentNode.insertBefore(loadingDiv, form.nextSibling); | |
| // Timeout fallback - if it takes too long, show error message | |
| setTimeout(function() { | |
| if (document.getElementById('loadingMessage')) { | |
| const errorDiv = document.createElement('div'); | |
| errorDiv.className = 'alert alert-warning mt-2'; | |
| errorDiv.innerHTML = ` | |
| <strong>Taking longer than expected...</strong><br> | |
| The system might be initializing. Please wait a bit more or try refreshing the page if it doesn't respond. | |
| `; | |
| loadingDiv.appendChild(errorDiv); | |
| } | |
| }, 30000); // 30 seconds | |
| }); | |
| // Initialize preview | |
| updatePreview(); | |
| </script> | |
| {% endblock %} | |