Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Exam Question Generator</title> | |
| <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"> | |
| <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet"> | |
| <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); | |
| } | |
| .btn-primary { | |
| background: linear-gradient(45deg, #667eea, #764ba2); | |
| border: none; | |
| border-radius: 25px; | |
| padding: 12px 30px; | |
| } | |
| .btn-primary:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 5px 15px rgba(0,0,0,0.2); | |
| } | |
| .form-control, .form-select { | |
| border-radius: 10px; | |
| border: 2px solid #e9ecef; | |
| } | |
| .form-control:focus, .form-select:focus { | |
| border-color: #667eea; | |
| box-shadow: 0 0 0 0.2rem rgba(102, 126, 234, 0.25); | |
| } | |
| .question-card { | |
| margin-bottom: 1.5rem; | |
| border-left: 4px solid #667eea; | |
| } | |
| .option { | |
| padding: 8px 15px; | |
| margin: 5px 0; | |
| border-radius: 8px; | |
| background-color: #f8f9fa; | |
| } | |
| .correct-option { | |
| background-color: #d4edda; | |
| border: 1px solid #c3e6cb; | |
| } | |
| .loading { | |
| display: none; | |
| } | |
| .spinner-border { | |
| width: 1.5rem; | |
| height: 1.5rem; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <div class="row justify-content-center"> | |
| <div class="col-md-10"> | |
| <div class="text-center mb-4"> | |
| <h1 class="text-white mb-3"> | |
| <i class="fas fa-brain"></i> Exam Question Generator | |
| </h1> | |
| <p class="text-white-50">Generate intelligent exam questions from any text using AI</p> | |
| </div> | |
| <div class="card"> | |
| <div class="card-body p-4"> | |
| <form id="questionForm"> | |
| <div class="row"> | |
| <div class="col-md-8"> | |
| <div class="mb-3"> | |
| <label for="textInput" class="form-label"> | |
| <i class="fas fa-edit"></i> Enter Text or Upload File | |
| </label> | |
| <textarea class="form-control" id="textInput" name="text_input" rows="8" | |
| placeholder="Paste your text here or upload a file below..."></textarea> | |
| </div> | |
| <div class="mb-3"> | |
| <label for="fileInput" class="form-label"> | |
| <i class="fas fa-upload"></i> Or Upload Text File | |
| </label> | |
| <input class="form-control" type="file" id="fileInput" name="file" accept=".txt,.md"> | |
| </div> | |
| </div> | |
| <div class="col-md-4"> | |
| <div class="mb-3"> | |
| <label for="maxQuestions" class="form-label"> | |
| <i class="fas fa-hashtag"></i> Number of Questions | |
| </label> | |
| <select class="form-select" id="maxQuestions" name="max_questions"> | |
| <option value="3">3 Questions</option> | |
| <option value="5" selected>5 Questions</option> | |
| <option value="8">8 Questions</option> | |
| <option value="10">10 Questions</option> | |
| </select> | |
| </div> | |
| <div class="mb-3"> | |
| <div class="form-check"> | |
| <input class="form-check-input" type="checkbox" id="includeMCQ" name="include_mcq" checked> | |
| <label class="form-check-label" for="includeMCQ"> | |
| <i class="fas fa-list"></i> Generate Multiple Choice Options | |
| </label> | |
| </div> | |
| </div> | |
| <button type="submit" class="btn btn-primary w-100"> | |
| <span class="btn-text"> | |
| <i class="fas fa-magic"></i> Generate Questions | |
| </span> | |
| <span class="loading"> | |
| <span class="spinner-border spinner-border-sm me-2"></span> | |
| Generating... | |
| </span> | |
| </button> | |
| </div> | |
| </div> | |
| </form> | |
| </div> | |
| </div> | |
| <div id="results" class="mt-4" style="display: none;"> | |
| <div class="card"> | |
| <div class="card-header bg-primary text-white"> | |
| <h5 class="mb-0"><i class="fas fa-question-circle"></i> Generated Questions</h5> | |
| </div> | |
| <div class="card-body" id="questionsContainer"> | |
| <!-- Questions will be populated here --> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script> | |
| <script> | |
| document.getElementById('questionForm').addEventListener('submit', async function(e) { | |
| e.preventDefault(); | |
| const btn = document.querySelector('button[type="submit"]'); | |
| const btnText = btn.querySelector('.btn-text'); | |
| const loading = btn.querySelector('.loading'); | |
| const results = document.getElementById('results'); | |
| // Show loading state | |
| btnText.style.display = 'none'; | |
| loading.style.display = 'inline'; | |
| btn.disabled = true; | |
| try { | |
| const formData = new FormData(this); | |
| const response = await fetch('/generate', { | |
| method: 'POST', | |
| body: formData | |
| }); | |
| const data = await response.json(); | |
| if (data.success) { | |
| displayQuestions(data.data); | |
| results.style.display = 'block'; | |
| results.scrollIntoView({ behavior: 'smooth' }); | |
| } else { | |
| alert('Error: ' + (data.error || 'Unknown error occurred')); | |
| } | |
| } catch (error) { | |
| alert('Error: ' + error.message); | |
| } finally { | |
| // Hide loading state | |
| btnText.style.display = 'inline'; | |
| loading.style.display = 'none'; | |
| btn.disabled = false; | |
| } | |
| }); | |
| function displayQuestions(data) { | |
| const container = document.getElementById('questionsContainer'); | |
| let html = ''; | |
| // Display statistics | |
| html += ` | |
| <div class="row mb-4"> | |
| <div class="col-md-3 text-center"> | |
| <div class="bg-light p-3 rounded"> | |
| <h4 class="text-primary">${data.metadata.questions_generated}</h4> | |
| <small>Questions</small> | |
| </div> | |
| </div> | |
| <div class="col-md-3 text-center"> | |
| <div class="bg-light p-3 rounded"> | |
| <h4 class="text-success">${data.metadata.keywords_extracted}</h4> | |
| <small>Keywords</small> | |
| </div> | |
| </div> | |
| <div class="col-md-3 text-center"> | |
| <div class="bg-light p-3 rounded"> | |
| <h4 class="text-info">${data.metadata.input_word_count}</h4> | |
| <small>Words</small> | |
| </div> | |
| </div> | |
| <div class="col-md-3 text-center"> | |
| <div class="bg-light p-3 rounded"> | |
| <h4 class="text-warning">${data.metadata.named_entities}</h4> | |
| <small>Entities</small> | |
| </div> | |
| </div> | |
| </div> | |
| `; | |
| // Display questions | |
| data.questions.forEach((q, index) => { | |
| html += ` | |
| <div class="question-card card mb-3"> | |
| <div class="card-body"> | |
| <h6 class="card-title">Question ${index + 1}</h6> | |
| <p class="card-text fw-bold">${q.question}</p> | |
| `; | |
| if (q.options) { | |
| html += '<div class="options mt-3">'; | |
| q.options.forEach((option, optIndex) => { | |
| const isCorrect = optIndex === q.correct_index; | |
| html += ` | |
| <div class="option ${isCorrect ? 'correct-option' : ''}"> | |
| ${String.fromCharCode(65 + optIndex)}. ${option} | |
| ${isCorrect ? '<i class="fas fa-check text-success float-end"></i>' : ''} | |
| </div> | |
| `; | |
| }); | |
| html += '</div>'; | |
| } | |
| html += ` | |
| <small class="text-muted"> | |
| <strong>Context:</strong> ${q.context.substring(0, 100)}... | |
| </small> | |
| </div> | |
| </div> | |
| `; | |
| }); | |
| container.innerHTML = html; | |
| } | |
| </script> | |
| </body> | |
| </html> | |