quiz / index.html
UnknownUser0's picture
Add 3 files
e738f7c verified
Raw
History Blame Contribute Delete
27.2 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI Quiz Maker</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>
.file-upload {
border: 2px dashed #cbd5e0;
transition: all 0.3s ease;
}
.file-upload:hover {
border-color: #4f46e5;
}
.file-upload.dragover {
background-color: #f0f9ff;
border-color: #4f46e5;
}
.quiz-card {
transition: transform 0.2s ease;
}
.quiz-card:hover {
transform: translateY(-2px);
}
.progress-bar {
transition: width 0.5s ease;
}
</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 Quiz Maker</h1>
<p class="text-gray-600 max-w-2xl mx-auto">
Upload your study materials and let our AI generate a personalized quiz to test your knowledge.
</p>
</header>
<!-- Main Content -->
<main>
<!-- File Upload Section -->
<section class="bg-white rounded-xl shadow-md p-6 mb-8">
<div class="flex flex-col md:flex-row gap-8">
<!-- Upload Area -->
<div class="w-full md:w-1/2">
<h2 class="text-2xl font-semibold text-gray-800 mb-4">Upload Your Files</h2>
<div
id="dropZone"
class="file-upload rounded-lg p-8 text-center cursor-pointer mb-4"
onclick="document.getElementById('fileInput').click()"
>
<div class="flex flex-col items-center justify-center">
<i class="fas fa-cloud-upload-alt text-5xl text-indigo-500 mb-4"></i>
<p class="text-gray-600 mb-2 font-medium">Drag & drop files here or click to browse</p>
<p class="text-gray-500 text-sm">Supported formats: PDF, DOCX, TXT</p>
</div>
<input
type="file"
id="fileInput"
class="hidden"
multiple
accept=".pdf,.docx,.txt"
onchange="handleFiles(this.files)"
>
</div>
<div class="flex flex-wrap gap-2 mb-4" id="fileList"></div>
</div>
<!-- Settings -->
<div class="w-full md:w-1/2">
<h2 class="text-2xl font-semibold text-gray-800 mb-4">Quiz Settings</h2>
<div class="space-y-4">
<div>
<label class="block text-gray-700 mb-2">Quiz Type</label>
<select id="quizType" class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
<option value="multiple_choice">Multiple Choice</option>
<option value="true_false">True/False</option>
<option value="short_answer">Short Answer</option>
</select>
</div>
<div>
<label class="block text-gray-700 mb-2">Number of Questions</label>
<input
type="range"
id="questionCount"
min="5"
max="20"
value="10"
class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer"
>
<div class="flex justify-between text-sm text-gray-600 mt-1">
<span>5</span>
<span id="questionCountValue">10</span>
<span>20</span>
</div>
</div>
<div>
<label class="block text-gray-700 mb-2">Difficulty</label>
<select id="difficulty" class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
<option value="easy">Easy</option>
<option value="medium" selected>Medium</option>
<option value="hard">Hard</option>
</select>
</div>
<button
id="generateBtn"
class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-3 px-4 rounded-lg transition duration-200 flex items-center justify-center"
onclick="generateQuiz()"
>
<i class="fas fa-magic mr-2"></i> Generate Quiz
</button>
</div>
</div>
</div>
</section>
<!-- Processing Section (Hidden by default) -->
<section id="processingSection" class="hidden bg-white rounded-xl shadow-md p-6 mb-8 text-center">
<div class="max-w-md mx-auto">
<div class="animate-spin rounded-full h-16 w-16 border-t-2 border-b-2 border-indigo-500 mx-auto mb-6"></div>
<h3 class="text-xl font-semibold text-gray-800 mb-2">Analyzing your files...</h3>
<p class="text-gray-600 mb-4">Our AI is reading your documents and generating high-quality questions.</p>
<div class="w-full bg-gray-200 rounded-full h-2.5">
<div id="progressBar" class="progress-bar bg-indigo-600 h-2.5 rounded-full" style="width: 0%"></div>
</div>
<p id="progressText" class="text-sm text-gray-500 mt-2">0% complete</p>
</div>
</section>
<!-- Quiz Results Section (Hidden by default) -->
<section id="quizResults" class="hidden bg-white rounded-xl shadow-md p-6">
<div class="flex justify-between items-center mb-6">
<h2 class="text-2xl font-semibold text-gray-800">Your Generated Quiz</h2>
<button
id="downloadBtn"
class="bg-green-600 hover:bg-green-700 text-white font-medium py-2 px-4 rounded-lg transition duration-200 flex items-center"
>
<i class="fas fa-download mr-2"></i> Download Quiz
</button>
</div>
<div id="quizContainer" class="space-y-6"></div>
<div class="mt-8 pt-6 border-t border-gray-200">
<button
id="submitQuizBtn"
class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-3 px-4 rounded-lg transition duration-200"
>
Submit Quiz
</button>
</div>
</section>
</main>
</div>
<script>
// Global variables
let uploadedFiles = [];
let generatedQuiz = [];
// DOM elements
const dropZone = document.getElementById('dropZone');
const fileInput = document.getElementById('fileInput');
const fileList = document.getElementById('fileList');
const questionCount = document.getElementById('questionCount');
const questionCountValue = document.getElementById('questionCountValue');
const generateBtn = document.getElementById('generateBtn');
const processingSection = document.getElementById('processingSection');
const quizResults = document.getElementById('quizResults');
const quizContainer = document.getElementById('quizContainer');
const progressBar = document.getElementById('progressBar');
const progressText = document.getElementById('progressText');
const downloadBtn = document.getElementById('downloadBtn');
const submitQuizBtn = document.getElementById('submitQuizBtn');
// Event listeners
questionCount.addEventListener('input', () => {
questionCountValue.textContent = questionCount.value;
});
// Drag and drop functionality
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
['dragenter', 'dragover'].forEach(eventName => {
dropZone.addEventListener(eventName, highlight, false);
});
['dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, unhighlight, false);
});
function highlight() {
dropZone.classList.add('dragover');
}
function unhighlight() {
dropZone.classList.remove('dragover');
}
dropZone.addEventListener('drop', handleDrop, false);
function handleDrop(e) {
const dt = e.dataTransfer;
const files = dt.files;
handleFiles(files);
}
// Handle file selection
function handleFiles(files) {
for (let i = 0; i < files.length; i++) {
const file = files[i];
if (isValidFileType(file)) {
if (!isFileAlreadyUploaded(file)) {
uploadedFiles.push(file);
displayFile(file);
}
} else {
alert(`File type not supported: ${file.name}`);
}
}
}
function isValidFileType(file) {
const validTypes = ['application/pdf', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'text/plain'];
return validTypes.includes(file.type);
}
function isFileAlreadyUploaded(file) {
return uploadedFiles.some(uploadedFile =>
uploadedFile.name === file.name &&
uploadedFile.size === file.size
);
}
function displayFile(file) {
const fileElement = document.createElement('div');
fileElement.className = 'flex items-center bg-gray-100 rounded-full px-4 py-2';
const iconClass = file.type === 'application/pdf' ? 'fa-file-pdf text-red-500' :
file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ? 'fa-file-word text-blue-500' :
'fa-file-alt text-gray-500';
fileElement.innerHTML = `
<i class="fas ${iconClass} mr-2"></i>
<span class="text-sm font-medium text-gray-700 mr-3 truncate max-w-xs">${file.name}</span>
<button onclick="removeFile(${uploadedFiles.length - 1})" class="text-gray-400 hover:text-gray-600">
<i class="fas fa-times"></i>
</button>
`;
fileList.appendChild(fileElement);
}
function removeFile(index) {
uploadedFiles.splice(index, 1);
fileList.innerHTML = '';
uploadedFiles.forEach((file, i) => displayFile(file));
}
// Generate quiz function
function generateQuiz() {
if (uploadedFiles.length === 0) {
alert('Please upload at least one file first.');
return;
}
// Show processing section
processingSection.classList.remove('hidden');
generateBtn.disabled = true;
// Simulate processing with progress bar
let progress = 0;
const interval = setInterval(() => {
progress += 5;
progressBar.style.width = `${progress}%`;
progressText.textContent = `${progress}% complete`;
if (progress >= 100) {
clearInterval(interval);
processFilesAndGenerateQuiz();
}
}, 200);
}
function processFilesAndGenerateQuiz() {
// In a real app, this would send files to an AI API
// For this demo, we'll simulate the AI processing
// Read files (simulated)
const quizType = document.getElementById('quizType').value;
const questionCount = parseInt(document.getElementById('questionCount').value);
const difficulty = document.getElementById('difficulty').value;
// Generate sample quiz questions based on file names (simulated AI)
generatedQuiz = [];
for (let i = 0; i < questionCount; i++) {
const fileIndex = i % uploadedFiles.length;
const fileName = uploadedFiles[fileIndex].name;
const fileType = uploadedFiles[fileIndex].type;
let question = {};
if (quizType === 'multiple_choice') {
question = generateMultipleChoiceQuestion(i, fileName, fileType, difficulty);
} else if (quizType === 'true_false') {
question = generateTrueFalseQuestion(i, fileName, fileType, difficulty);
} else {
question = generateShortAnswerQuestion(i, fileName, fileType, difficulty);
}
generatedQuiz.push(question);
}
// Hide processing section and show results
processingSection.classList.add('hidden');
quizResults.classList.remove('hidden');
generateBtn.disabled = false;
// Display the quiz
displayQuiz();
}
function generateMultipleChoiceQuestion(index, fileName, fileType, difficulty) {
const questionTypes = [
`What is the main topic discussed in ${fileName}?`,
`According to ${fileName}, which of the following is correct?`,
`What would be the best summary of ${fileName}?`,
`Which concept is most emphasized in ${fileName}?`
];
const question = questionTypes[index % questionTypes.length];
// Generate plausible options based on file info
const options = [
getOptionBasedOnFile(fileName, fileType, 'correct'),
getOptionBasedOnFile(fileName, fileType, 'plausible'),
getOptionBasedOnFile(fileName, fileType, 'plausible'),
getOptionBasedOnFile(fileName, fileType, 'random')
];
// Shuffle options
for (let i = options.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[options[i], options[j]] = [options[j], options[i]];
}
return {
type: 'multiple_choice',
question: question,
options: options,
correctAnswer: options.findIndex(opt => opt.isCorrect),
userAnswer: null
};
}
function generateTrueFalseQuestion(index, fileName, fileType, difficulty) {
const statements = [
`${fileName} primarily discusses this topic.`,
`This concept is mentioned in ${fileName}.`,
`The author of ${fileName} would agree with this statement.`,
`This is a key finding from ${fileName}.`
];
const statement = statements[index % statements.length];
const isTrue = Math.random() > 0.5;
return {
type: 'true_false',
question: statement,
isTrue: isTrue,
userAnswer: null
};
}
function generateShortAnswerQuestion(index, fileName, fileType, difficulty) {
const questions = [
`What is the main purpose of ${fileName}?`,
`Summarize the key points from ${fileName} in 2-3 sentences.`,
`What problem does ${fileName} aim to solve?`,
`How does ${fileName} contribute to its field?`
];
return {
type: 'short_answer',
question: questions[index % questions.length],
sampleAnswer: getOptionBasedOnFile(fileName, fileType, 'correct').text,
userAnswer: ''
};
}
function getOptionBasedOnFile(fileName, fileType, type) {
const fileBase = fileName.split('.')[0];
if (type === 'correct') {
return {
text: `The ${fileBase} document discusses important concepts in this field`,
isCorrect: true
};
} else if (type === 'plausible') {
const plausibleOptions = [
`The ${fileBase} focuses on historical aspects`,
`This document presents experimental results`,
`A theoretical framework is proposed in ${fileBase}`,
`The ${fileBase} challenges existing paradigms`
];
return {
text: plausibleOptions[Math.floor(Math.random() * plausibleOptions.length)],
isCorrect: false
};
} else {
const randomOptions = [
'None of the above',
'All of the above',
'The data is inconclusive',
'This was not addressed in the document'
];
return {
text: randomOptions[Math.floor(Math.random() * randomOptions.length)],
isCorrect: false
};
}
}
function displayQuiz() {
quizContainer.innerHTML = '';
generatedQuiz.forEach((question, index) => {
const questionElement = document.createElement('div');
questionElement.className = 'quiz-card bg-gray-50 rounded-lg p-6 shadow-sm';
if (question.type === 'multiple_choice') {
questionElement.innerHTML = `
<h3 class="text-lg font-medium text-gray-800 mb-4">${index + 1}. ${question.question}</h3>
<div class="space-y-3">
${question.options.map((option, i) => `
<div class="flex items-center">
<input
type="radio"
id="q${index}_opt${i}"
name="q${index}"
value="${i}"
class="h-4 w-4 text-indigo-600 focus:ring-indigo-500"
onchange="setUserAnswer(${index}, ${i})"
>
<label for="q${index}_opt${i}" class="ml-3 text-gray-700">${option.text}</label>
</div>
`).join('')}
</div>
`;
} else if (question.type === 'true_false') {
questionElement.innerHTML = `
<h3 class="text-lg font-medium text-gray-800 mb-4">${index + 1}. ${question.question}</h3>
<div class="flex space-x-6">
<div class="flex items-center">
<input
type="radio"
id="q${index}_true"
name="q${index}"
value="true"
class="h-4 w-4 text-indigo-600 focus:ring-indigo-500"
onchange="setUserAnswer(${index}, true)"
>
<label for="q${index}_true" class="ml-3 text-gray-700">True</label>
</div>
<div class="flex items-center">
<input
type="radio"
id="q${index}_false"
name="q${index}"
value="false"
class="h-4 w-4 text-indigo-600 focus:ring-indigo-500"
onchange="setUserAnswer(${index}, false)"
>
<label for="q${index}_false" class="ml-3 text-gray-700">False</label>
</div>
</div>
`;
} else {
questionElement.innerHTML = `
<h3 class="text-lg font-medium text-gray-800 mb-4">${index + 1}. ${question.question}</h3>
<textarea
id="q${index}_answer"
class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
rows="3"
placeholder="Type your answer here..."
onchange="setUserAnswer(${index}, this.value)"
></textarea>
`;
}
quizContainer.appendChild(questionElement);
});
}
function setUserAnswer(index, answer) {
generatedQuiz[index].userAnswer = answer;
}
// Download quiz as JSON
downloadBtn.addEventListener('click', () => {
const quizData = {
settings: {
type: document.getElementById('quizType').value,
questionCount: document.getElementById('questionCount').value,
difficulty: document.getElementById('difficulty').value,
files: uploadedFiles.map(file => file.name)
},
questions: generatedQuiz
};
const dataStr = JSON.stringify(quizData, null, 2);
const dataUri = 'data:application/json;charset=utf-8,'+ encodeURIComponent(dataStr);
const exportFileDefaultName = 'quiz.json';
const linkElement = document.createElement('a');
linkElement.setAttribute('href', dataUri);
linkElement.setAttribute('download', exportFileDefaultName);
linkElement.click();
});
// Submit quiz (simulated grading)
submitQuizBtn.addEventListener('click', () => {
let score = 0;
let totalQuestions = generatedQuiz.length;
generatedQuiz.forEach((question, index) => {
if (question.type === 'multiple_choice') {
if (question.userAnswer === question.correctAnswer) {
score++;
}
} else if (question.type === 'true_false') {
if (question.userAnswer === question.isTrue) {
score++;
}
}
// Short answer questions aren't auto-graded in this demo
});
const percentage = Math.round((score / totalQuestions) * 100);
// Show results
quizContainer.innerHTML = `
<div class="bg-white rounded-xl shadow-md p-8 text-center">
<div class="inline-flex items-center justify-center w-24 h-24 bg-green-100 rounded-full mb-6">
<span class="text-3xl font-bold text-green-600">${percentage}%</span>
</div>
<h3 class="text-2xl font-semibold text-gray-800 mb-2">Quiz Completed!</h3>
<p class="text-gray-600 mb-6">
You scored ${score} out of ${totalQuestions} questions.
${percentage >= 70 ? 'Great job!' : 'Keep practicing!'}
</p>
<button
onclick="location.reload()"
class="bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-2 px-6 rounded-lg transition duration-200"
>
Create New Quiz
</button>
</div>
`;
submitQuizBtn.classList.add('hidden');
});
</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=UnknownUser0/quiz" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>