ai-question-generator / index.html
8421bit's picture
Add 2 files
a17ffd5 verified
<!DOCTYPE html>
<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>