Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>AI Question Generator</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| .question-card { | |
| transition: all 0.3s ease; | |
| } | |
| .question-card:hover { | |
| transform: translateY(-3px); | |
| box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); | |
| } | |
| .loading-dots::after { | |
| content: '.'; | |
| animation: dots 1.5s steps(5, end) infinite; | |
| } | |
| @keyframes dots { | |
| 0%, 20% { content: '.'; } | |
| 40% { content: '..'; } | |
| 60% { content: '...'; } | |
| 80%, 100% { content: ''; } | |
| } | |
| .fade-in { | |
| animation: fadeIn 0.5s ease-in; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-50 min-h-screen"> | |
| <div class="container mx-auto px-4 py-8"> | |
| <!-- Header --> | |
| <header class="text-center mb-12"> | |
| <h1 class="text-4xl font-bold text-indigo-700 mb-2">AI Question Generator</h1> | |
| <p class="text-gray-600 max-w-2xl mx-auto">Enter a topic and let our AI generate insightful questions to explore the subject deeply.</p> | |
| </header> | |
| <!-- Main Content --> | |
| <div class="max-w-4xl mx-auto"> | |
| <!-- Input Section --> | |
| <div class="bg-white rounded-xl shadow-md p-6 mb-8"> | |
| <div class="flex flex-col md:flex-row gap-4"> | |
| <div class="flex-grow"> | |
| <label for="topic" class="block text-sm font-medium text-gray-700 mb-1">Enter your topic</label> | |
| <input | |
| type="text" | |
| id="topic" | |
| placeholder="e.g. Artificial Intelligence, Climate Change, Renaissance Art..." | |
| class="w-full px-4 py-3 rounded-lg border border-gray-300 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition" | |
| > | |
| </div> | |
| <div class="flex items-end"> | |
| <button | |
| id="generateBtn" | |
| class="bg-indigo-600 hover:bg-indigo-700 text-white px-6 py-3 rounded-lg font-medium transition flex items-center justify-center w-full md:w-auto" | |
| > | |
| <i class="fas fa-bolt mr-2"></i> Generate Questions | |
| </button> | |
| </div> | |
| </div> | |
| <div class="mt-4 flex flex-wrap gap-3"> | |
| <div class="flex items-center"> | |
| <input type="checkbox" id="basicQuestions" class="h-4 w-4 text-indigo-600 rounded" checked> | |
| <label for="basicQuestions" class="ml-2 text-sm text-gray-700">Basic</label> | |
| </div> | |
| <div class="flex items-center"> | |
| <input type="checkbox" id="advancedQuestions" class="h-4 w-4 text-indigo-600 rounded" checked> | |
| <label for="advancedQuestions" class="ml-2 text-sm text-gray-700">Advanced</label> | |
| </div> | |
| <div class="flex items-center"> | |
| <input type="checkbox" id="criticalQuestions" class="h-4 w-4 text-indigo-600 rounded" checked> | |
| <label for="criticalQuestions" class="ml-2 text-sm text-gray-700">Critical Thinking</label> | |
| </div> | |
| <div class="flex items-center"> | |
| <input type="number" id="questionCount" min="3" max="20" value="8" class="w-16 px-2 py-1 border border-gray-300 rounded text-sm"> | |
| <label for="questionCount" class="ml-2 text-sm text-gray-700">Questions</label> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Loading State --> | |
| <div id="loadingState" class="hidden text-center py-12"> | |
| <div class="inline-block bg-white p-6 rounded-xl shadow-md"> | |
| <i class="fas fa-cog fa-spin text-indigo-600 text-3xl mb-3"></i> | |
| <p class="text-gray-700 font-medium loading-dots">Generating questions</p> | |
| </div> | |
| </div> | |
| <!-- Results Section --> | |
| <div id="resultsSection" class="hidden"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h2 class="text-xl font-semibold text-gray-800">Generated Questions</h2> | |
| <div class="flex gap-2"> | |
| <button id="exportJsonBtn" class="bg-gray-100 hover:bg-gray-200 text-gray-700 px-4 py-2 rounded-lg text-sm font-medium transition flex items-center"> | |
| <i class="fas fa-file-export mr-2"></i> Export JSON | |
| </button> | |
| <button id="copyAllBtn" class="bg-gray-100 hover:bg-gray-200 text-gray-700 px-4 py-2 rounded-lg text-sm font-medium transition flex items-center"> | |
| <i class="fas fa-copy mr-2"></i> Copy All | |
| </button> | |
| </div> | |
| </div> | |
| <div id="questionsContainer" class="grid gap-4"> | |
| <!-- Questions will be inserted here --> | |
| </div> | |
| </div> | |
| <!-- Empty State --> | |
| <div id="emptyState" class="text-center py-16 bg-white rounded-xl shadow-sm"> | |
| <i class="fas fa-comment-dots text-4xl text-gray-300 mb-4"></i> | |
| <h3 class="text-lg font-medium text-gray-500">No questions generated yet</h3> | |
| <p class="text-gray-400 mt-1">Enter a topic above and click "Generate Questions" to get started</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- JSON Export Modal --> | |
| <div id="jsonModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> | |
| <div class="bg-white rounded-xl shadow-xl w-full max-w-2xl max-h-[80vh] flex flex-col"> | |
| <div class="px-6 py-4 border-b flex justify-between items-center"> | |
| <h3 class="text-lg font-semibold">Export Questions as JSON</h3> | |
| <button id="closeJsonModal" class="text-gray-500 hover:text-gray-700"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <div class="p-6 overflow-auto flex-grow"> | |
| <pre id="jsonOutput" class="bg-gray-50 p-4 rounded text-sm overflow-auto"></pre> | |
| </div> | |
| <div class="px-6 py-4 border-t flex justify-end gap-3"> | |
| <button id="copyJsonBtn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-lg text-sm font-medium transition"> | |
| <i class="fas fa-copy mr-2"></i> Copy JSON | |
| </button> | |
| <button id="downloadJsonBtn" class="bg-gray-100 hover:bg-gray-200 text-gray-700 px-4 py-2 rounded-lg text-sm font-medium transition"> | |
| <i class="fas fa-download mr-2"></i> Download | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // DOM Elements | |
| const topicInput = document.getElementById('topic'); | |
| const generateBtn = document.getElementById('generateBtn'); | |
| const loadingState = document.getElementById('loadingState'); | |
| const resultsSection = document.getElementById('resultsSection'); | |
| const emptyState = document.getElementById('emptyState'); | |
| const questionsContainer = document.getElementById('questionsContainer'); | |
| const exportJsonBtn = document.getElementById('exportJsonBtn'); | |
| const copyAllBtn = document.getElementById('copyAllBtn'); | |
| const jsonModal = document.getElementById('jsonModal'); | |
| const closeJsonModal = document.getElementById('closeJsonModal'); | |
| const jsonOutput = document.getElementById('jsonOutput'); | |
| const copyJsonBtn = document.getElementById('copyJsonBtn'); | |
| const downloadJsonBtn = document.getElementById('downloadJsonBtn'); | |
| // Sample question types for the mock API | |
| const questionTypes = { | |
| basic: [ | |
| "What is {topic}?", | |
| "Why is {topic} important?", | |
| "How does {topic} work?", | |
| "What are the main components of {topic}?", | |
| "When did {topic} first emerge?" | |
| ], | |
| advanced: [ | |
| "What are the current challenges in {topic}?", | |
| "How has {topic} evolved over time?", | |
| "What are the different approaches to {topic}?", | |
| "How does {topic} compare to similar concepts?", | |
| "What are the technical aspects of {topic}?" | |
| ], | |
| critical: [ | |
| "What are the ethical implications of {topic}?", | |
| "How might {topic} impact society in the future?", | |
| "What are the limitations of current {topic} implementations?", | |
| "How could {topic} be improved or innovated upon?", | |
| "What controversies exist surrounding {topic}?" | |
| ] | |
| }; | |
| // Generate questions (mock API call) | |
| function generateQuestions(topic, count) { | |
| const selectedTypes = []; | |
| if (document.getElementById('basicQuestions').checked) selectedTypes.push('basic'); | |
| if (document.getElementById('advancedQuestions').checked) selectedTypes.push('advanced'); | |
| if (document.getElementById('criticalQuestions').checked) selectedTypes.push('critical'); | |
| // Distribute questions evenly among selected types | |
| const questionsPerType = Math.ceil(count / selectedTypes.length); | |
| let questions = []; | |
| selectedTypes.forEach(type => { | |
| const typeQuestions = [...questionTypes[type]]; | |
| // Shuffle and take needed amount | |
| typeQuestions.sort(() => 0.5 - Math.random()); | |
| const selected = typeQuestions.slice(0, questionsPerType); | |
| questions = [...questions, ...selected]; | |
| }); | |
| // Shuffle all questions and trim to exact count | |
| questions.sort(() => 0.5 - Math.random()); | |
| questions = questions.slice(0, count); | |
| // Replace {topic} with actual topic | |
| return questions.map(q => ({ | |
| text: q.replace('{topic}', topic), | |
| type: Object.keys(questionTypes).find(key => questionTypes[key].includes(q)) || 'basic' | |
| })); | |
| } | |
| // Display questions | |
| function displayQuestions(questions) { | |
| questionsContainer.innerHTML = ''; | |
| questions.forEach((question, index) => { | |
| const typeColors = { | |
| basic: 'bg-blue-100 text-blue-800', | |
| advanced: 'bg-purple-100 text-purple-800', | |
| critical: 'bg-orange-100 text-orange-800' | |
| }; | |
| const card = document.createElement('div'); | |
| card.className = `question-card bg-white rounded-xl shadow-sm p-5 border-l-4 border-indigo-500 fade-in`; | |
| card.style.animationDelay = `${index * 0.05}s`; | |
| card.innerHTML = ` | |
| <div class="flex justify-between items-start"> | |
| <div class="flex-grow"> | |
| <div class="flex items-center mb-2"> | |
| <span class="text-xs font-medium px-2 py-1 rounded-full ${typeColors[question.type]} mr-2"> | |
| ${question.type.charAt(0).toUpperCase() + question.type.slice(1)} | |
| </span> | |
| </div> | |
| <p class="text-gray-800 font-medium">${question.text}</p> | |
| </div> | |
| <button class="copy-btn text-gray-400 hover:text-indigo-600 ml-3" data-question="${question.text}"> | |
| <i class="fas fa-copy"></i> | |
| </button> | |
| </div> | |
| `; | |
| questionsContainer.appendChild(card); | |
| }); | |
| // Add event listeners to copy buttons | |
| document.querySelectorAll('.copy-btn').forEach(btn => { | |
| btn.addEventListener('click', function() { | |
| const question = this.getAttribute('data-question'); | |
| navigator.clipboard.writeText(question); | |
| // Show feedback | |
| const icon = this.querySelector('i'); | |
| icon.className = 'fas fa-check'; | |
| setTimeout(() => { | |
| icon.className = 'fas fa-copy'; | |
| }, 1000); | |
| }); | |
| }); | |
| } | |
| // Generate button click handler | |
| generateBtn.addEventListener('click', function() { | |
| const topic = topicInput.value.trim(); | |
| const count = parseInt(document.getElementById('questionCount').value) || 8; | |
| if (!topic) { | |
| alert('Please enter a topic first'); | |
| return; | |
| } | |
| // Show loading state | |
| loadingState.classList.remove('hidden'); | |
| resultsSection.classList.add('hidden'); | |
| emptyState.classList.add('hidden'); | |
| // Simulate API call with timeout | |
| setTimeout(() => { | |
| const questions = generateQuestions(topic, count); | |
| // Hide loading and show results | |
| loadingState.classList.add('hidden'); | |
| resultsSection.classList.remove('hidden'); | |
| displayQuestions(questions); | |
| // Scroll to results | |
| resultsSection.scrollIntoView({ behavior: 'smooth' }); | |
| }, 1500); | |
| }); | |
| // Export JSON functionality | |
| exportJsonBtn.addEventListener('click', function() { | |
| const questions = Array.from(document.querySelectorAll('.question-card')).map(card => { | |
| return { | |
| question: card.querySelector('p').textContent, | |
| type: card.querySelector('span').textContent.toLowerCase() | |
| }; | |
| }); | |
| const jsonData = { | |
| topic: topicInput.value.trim(), | |
| generatedAt: new Date().toISOString(), | |
| questions: questions | |
| }; | |
| jsonOutput.textContent = JSON.stringify(jsonData, null, 2); | |
| jsonModal.classList.remove('hidden'); | |
| }); | |
| // Close JSON modal | |
| closeJsonModal.addEventListener('click', function() { | |
| jsonModal.classList.add('hidden'); | |
| }); | |
| // Copy JSON to clipboard | |
| copyJsonBtn.addEventListener('click', function() { | |
| navigator.clipboard.writeText(jsonOutput.textContent); | |
| const icon = this.querySelector('i'); | |
| const originalText = this.innerHTML; | |
| this.innerHTML = '<i class="fas fa-check mr-2"></i> Copied!'; | |
| setTimeout(() => { | |
| this.innerHTML = originalText; | |
| }, 2000); | |
| }); | |
| // Download JSON file | |
| downloadJsonBtn.addEventListener('click', function() { | |
| const data = jsonOutput.textContent; | |
| const blob = new Blob([data], { type: 'application/json' }); | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = `questions-${topicInput.value.trim().toLowerCase().replace(/\s+/g, '-')}-${new Date().toISOString().slice(0,10)}.json`; | |
| document.body.appendChild(a); | |
| a.click(); | |
| document.body.removeChild(a); | |
| URL.revokeObjectURL(url); | |
| }); | |
| // Copy all questions | |
| copyAllBtn.addEventListener('click', function() { | |
| const questions = Array.from(document.querySelectorAll('.question-card')).map(card => { | |
| return card.querySelector('p').textContent; | |
| }).join('\n\n'); | |
| navigator.clipboard.writeText(questions); | |
| const icon = this.querySelector('i'); | |
| const originalText = this.innerHTML; | |
| this.innerHTML = '<i class="fas fa-check mr-2"></i> Copied all!'; | |
| setTimeout(() => { | |
| this.innerHTML = originalText; | |
| }, 2000); | |
| }); | |
| // Allow Enter key to trigger generation | |
| topicInput.addEventListener('keypress', function(e) { | |
| if (e.key === 'Enter') { | |
| generateBtn.click(); | |
| } | |
| }); | |
| }); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - <a href="https://enzostvs-deepsite.hf.space?remix=8421bit/ai-question-generator" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body> | |
| </html> |