Attaque2 / templates /index.html
Docfile's picture
Update templates/index.html
13ae48e verified
raw
history blame
12.7 kB
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Générateur de Flashcards et Quiz</title>
<!-- Inclusion de Tailwind CSS via CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<style>
/* Styles personnalisés additionnels si nécessaire */
.flashcard-transform {
transition: transform 0.3s ease-in-out, box-shadow 0.3s ease-in-out;
}
.flashcard-transform:hover {
transform: translateY(-5px);
}
</style>
</head>
<body class="bg-gray-100 font-sans">
<div class="container mx-auto mt-8 px-4">
<h1 class="text-3xl font-bold text-center text-gray-800 mb-6">Générateur de Flashcards et Quiz</h1>
<!-- Section de configuration -->
<div class="max-w-2xl mx-auto mb-8">
<div class="bg-white rounded-lg shadow-md p-6">
<div class="mb-4">
<label for="topic" class="block text-sm font-medium text-gray-700 mb-1">Sujet</label>
<input type="text" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" id="topic" placeholder="Entrez un sujet...">
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-2">Type de contenu</label>
<div class="flex items-center space-x-4">
<div class="flex items-center">
<input id="typeFlashcards" name="contentType" type="radio" value="flashcards" checked class="h-4 w-4 text-indigo-600 border-gray-300 focus:ring-indigo-500">
<label for="typeFlashcards" class="ml-2 block text-sm text-gray-900">
Flashcards
</label>
</div>
<div class="flex items-center">
<input id="typeQuiz" name="contentType" type="radio" value="quiz" class="h-4 w-4 text-indigo-600 border-gray-300 focus:ring-indigo-500">
<label for="typeQuiz" class="ml-2 block text-sm text-gray-900">
Quiz
</label>
</div>
</div>
</div>
<button id="generateBtn" class="w-full py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 transition duration-150 ease-in-out">
Générer
</button>
</div>
</div>
<!-- Indicateur de chargement -->
<div id="loading" class="hidden text-center my-10 flex flex-col items-center justify-center">
<svg class="animate-spin h-8 w-8 text-indigo-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
<p class="mt-2 text-gray-600">Génération en cours... Cela peut prendre plusieurs minutes.</p>
</div>
<!-- Conteneur pour les Flashcards -->
<div id="flashcardsContainer" class="mt-6">
<!-- Les flashcards seront injectées ici -->
</div>
<!-- Conteneur pour le Quiz -->
<div id="quizContainer" class="mt-6 max-w-3xl mx-auto">
<!-- Les questions du quiz seront injectées ici -->
</div>
</div>
<script>
const generateBtn = document.getElementById('generateBtn');
const loadingIndicator = document.getElementById('loading');
const flashcardsContainer = document.getElementById('flashcardsContainer');
const quizContainer = document.getElementById('quizContainer');
const topicInput = document.getElementById('topic');
generateBtn.addEventListener('click', function() {
const topic = topicInput.value.trim();
if (!topic) {
alert('Veuillez entrer un sujet.');
return;
}
const contentType = document.querySelector('input[name="contentType"]:checked').value;
// Afficher le chargement et cacher les anciens résultats
loadingIndicator.classList.remove('hidden');
flashcardsContainer.innerHTML = '';
quizContainer.innerHTML = '';
flashcardsContainer.classList.add('hidden');
quizContainer.classList.add('hidden');
// Envoi de la requête
fetch('/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ topic, type: contentType }),
})
.then(response => {
if (!response.ok) {
throw new Error(`Erreur HTTP: ${response.status}`);
}
return response.json();
})
.then(data => {
loadingIndicator.classList.add('hidden');
if (data.error) {
alert('Erreur: ' + data.error);
return;
}
if (contentType === 'flashcards' && data.flashcards) {
flashcardsContainer.classList.remove('hidden');
displayFlashcards(data.flashcards);
} else if (contentType === 'quiz' && data.quiz) {
quizContainer.classList.remove('hidden');
displayQuiz(data.quiz);
} else {
alert('Aucune donnée reçue ou format incorrect.');
}
})
.catch(error => {
loadingIndicator.classList.add('hidden');
console.error('Erreur lors de la génération:', error);
alert('Erreur lors de la génération: ' + error.message + '. Vérifiez la console pour plus de détails.');
});
});
function displayFlashcards(flashcards) {
flashcardsContainer.innerHTML = `
<div class="mb-4">
<h2 class="text-2xl font-semibold text-center text-gray-700 mb-1">Flashcards générées (${flashcards.length})</h2>
<p class="text-center text-gray-500 text-sm">Cliquez sur une carte pour voir la réponse</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<!-- Flashcards ici -->
</div>
`;
const gridContainer = flashcardsContainer.querySelector('.grid');
flashcards.forEach((card, index) => {
const cardElement = document.createElement('div');
cardElement.className = 'bg-white rounded-lg shadow p-4 cursor-pointer flashcard-transform hover:shadow-lg';
cardElement.setAttribute('onclick', `toggleAnswer(${index})`);
cardElement.innerHTML = `
<div class="font-semibold text-gray-800">${card.question}</div>
<div id="answer-${index}" class="hidden mt-3 pt-3 border-t border-dashed border-gray-300 text-sm text-gray-700">
<strong class="font-bold text-gray-900">Réponse:</strong> ${card.answer}
</div>
`;
gridContainer.appendChild(cardElement);
});
}
function toggleAnswer(index) {
const answerElement = document.getElementById(`answer-${index}`);
answerElement.classList.toggle('hidden');
}
function displayQuiz(quizQuestions) {
quizContainer.innerHTML = `
<div class="mb-4">
<h2 class="text-2xl font-semibold text-center text-gray-700 mb-1">Quiz généré (${quizQuestions.length} questions)</h2>
<p class="text-center text-gray-500 text-sm">Sélectionnez une réponse pour chaque question</p>
</div>
`;
quizQuestions.forEach((question, qIndex) => {
const questionElement = document.createElement('div');
questionElement.className = 'bg-white rounded-lg shadow p-5 mb-5';
let optionsHtml = '';
const safeCorrectAnswer = question.correctAnswer.replace(/"/g, '&quot;');
question.options.forEach((option, oIndex) => {
optionsHtml += `
<div class="option block p-3 my-2 border border-gray-200 rounded-md cursor-pointer transition duration-150 ease-in-out hover:bg-gray-100 text-gray-800"
id="q${qIndex}-o${oIndex}"
data-correct="${safeCorrectAnswer}"
onclick="selectOption(this, ${qIndex}, ${oIndex})">
${option}
</div>
`;
});
questionElement.innerHTML = `
<h5 class="font-semibold text-lg mb-3 text-gray-800">${qIndex + 1}. ${question.question}</h5>
<div class="options mt-3">
${optionsHtml}
</div>
<div class="explanation hidden mt-4 p-3 rounded-md bg-blue-50 border border-blue-200 text-sm text-blue-700" id="explanation-${qIndex}">
<strong class="font-bold">Explication:</strong> ${question.explanation}
</div>
`;
quizContainer.appendChild(questionElement);
});
}
function selectOption(element, questionIndex, optionIndex) {
const correctAnswer = element.dataset.correct;
const questionOptions = quizContainer.querySelectorAll(`#q${questionIndex}-o0`)[0].parentElement.querySelectorAll('.option');
const explanationElement = document.getElementById(`explanation-${questionIndex}`);
// Vérifier si la question a déjà été répondue
let alreadyAnswered = false;
questionOptions.forEach(opt => {
if (opt.classList.contains('bg-green-100') || opt.classList.contains('bg-red-100')) {
alreadyAnswered = true;
}
});
if (alreadyAnswered) return;
// Réinitialiser les styles des options
questionOptions.forEach(option => {
option.classList.remove('bg-indigo-100', 'border-indigo-300', 'bg-green-100', 'border-green-300', 'text-green-800', 'bg-red-100', 'border-red-300', 'text-red-800');
option.classList.add('hover:bg-gray-100');
});
// Marquer l'option cliquée
element.classList.add('bg-indigo-100', 'border-indigo-300');
element.classList.remove('hover:bg-gray-100');
const selectedText = element.textContent.trim();
if (selectedText === correctAnswer) {
element.classList.remove('bg-indigo-100', 'border-indigo-300');
element.classList.add('bg-green-100', 'border-green-300', 'text-green-800');
} else {
element.classList.remove('bg-indigo-100', 'border-indigo-300');
element.classList.add('bg-red-100', 'border-red-300', 'text-red-800');
// Mettre en évidence la bonne réponse
questionOptions.forEach(option => {
if (option.textContent.trim() === correctAnswer) {
option.classList.add('bg-green-100', 'border-green-300', 'text-green-800');
option.classList.remove('hover:bg-gray-100');
}
});
}
// Désactiver les clics pour toutes les options de cette question
questionOptions.forEach(option => {
option.onclick = null;
option.classList.remove('cursor-pointer', 'hover:bg-gray-100');
option.style.cursor = 'default';
});
// Afficher l'explication
explanationElement.classList.remove('hidden');
}
</script>
</body>
</html>