Attaque2 / templates /index.html
Docfile's picture
Upload index.html
1d80589 verified
raw
history blame
10.2 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 IA</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
line-height: 1.6;
padding: 20px;
max-width: 800px;
margin: 40px auto;
background-color: #f4f4f4;
color: #333;
}
.container {
background-color: #fff;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
h1 {
text-align: center;
color: #2c3e50;
margin-bottom: 30px;
}
label {
display: block;
margin-bottom: 8px;
font-weight: bold;
color: #555;
}
input[type="text"] {
width: calc(100% - 120px); /* Adjust width considering button size */
padding: 12px;
margin-bottom: 20px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 1rem;
box-sizing: border-box; /* Include padding in width */
}
button {
padding: 12px 20px;
background-color: #3498db;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 1rem;
transition: background-color 0.3s ease;
vertical-align: top; /* Align with input field */
}
button:hover {
background-color: #2980b9;
}
button:disabled {
background-color: #bdc3c7;
cursor: not-allowed;
}
#statusMessage {
margin-top: 20px;
padding: 10px;
border-radius: 4px;
text-align: center;
font-weight: bold;
}
#statusMessage.loading {
background-color: #eaf2f8;
color: #3498db;
}
#statusMessage.error {
background-color: #fbeae5;
color: #c0392b;
}
#statusMessage.success {
background-color: #e8f6f3;
color: #1abc9c;
}
#flashcardsContainer {
margin-top: 30px;
border-top: 1px solid #eee;
padding-top: 20px;
}
.flashcard {
background-color: #f9f9f9;
border: 1px solid #ddd;
border-radius: 5px;
padding: 15px 20px;
margin-bottom: 15px;
cursor: pointer;
transition: box-shadow 0.2s ease-in-out;
}
.flashcard:hover {
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.flashcard .question {
font-weight: bold;
margin-bottom: 10px;
color: #34495e;
}
.flashcard .answer {
display: none; /* Hidden by default */
color: #555;
margin-top: 10px;
padding-top: 10px;
border-top: 1px dashed #ccc;
}
.flashcard.flipped .answer {
display: block; /* Shown when .flipped class is added */
}
@media (max-width: 600px) {
input[type="text"] {
width: 100%;
margin-bottom: 10px;
}
button {
width: 100%;
}
}
</style>
</head>
<body>
<div class="container">
<h1>Générateur de Flashcards IA</h1>
<div>
<label for="topicInput">Entrez un sujet :</label>
<input type="text" id="topicInput" placeholder="Ex: Histoire de l'intelligence artificielle">
<button id="generateButton">Générer</button>
</div>
<div id="statusMessage"></div>
<div id="flashcardsContainer">
<!-- Les flashcards générées apparaîtront ici -->
</div>
</div>
<script>
const topicInput = document.getElementById('topicInput');
const generateButton = document.getElementById('generateButton');
const statusMessage = document.getElementById('statusMessage');
const flashcardsContainer = document.getElementById('flashcardsContainer');
generateButton.addEventListener('click', handleGenerateClick);
// Optionnel : Permettre de lancer la génération avec la touche Entrée dans le champ de texte
topicInput.addEventListener('keypress', function(event) {
if (event.key === 'Enter') {
event.preventDefault(); // Empêche la soumission de formulaire par défaut si enveloppé dans un <form>
handleGenerateClick();
}
});
async function handleGenerateClick() {
const topic = topicInput.value.trim();
if (!topic) {
displayMessage('Veuillez entrer un sujet.', 'error');
return;
}
// Désactiver le bouton et afficher le message de chargement
generateButton.disabled = true;
flashcardsContainer.innerHTML = ''; // Vider les anciennes flashcards
displayMessage('Génération des flashcards en cours... Cela peut prendre un moment.', 'loading');
try {
const response = await fetch('/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ topic: topic }),
});
// Essayer de parser la réponse JSON même si le statut n'est pas OK (pour les messages d'erreur du backend)
const data = await response.json();
clearMessage(); // Effacer le message de chargement
if (!response.ok) {
// Gérer les erreurs HTTP (4xx, 5xx) et les erreurs applicatives renvoyées dans le JSON
const errorMsg = data?.error || `Erreur ${response.status}: ${response.statusText}`;
throw new Error(errorMsg); // Provoque l'entrée dans le bloc catch
}
if (data.success && data.flashcards && Array.isArray(data.flashcards)) {
if(data.flashcards.length > 0) {
displayFlashcards(data.flashcards);
displayMessage(`Flashcards générées pour "${topic}"! Cliquez sur une carte pour voir la réponse.`, 'success');
} else {
displayMessage("Aucune flashcard n'a pu être générée pour ce sujet. Essayez d'être plus spécifique ou de reformuler.", 'info'); // Utiliser 'info' ou une classe dédiée
statusMessage.style.backgroundColor = '#eaf2f8'; // Style pour info
statusMessage.style.color = '#3498db';
}
} else if (data.error) {
// Gérer les erreurs applicatives spécifiques renvoyées dans data.error
displayMessage(`Erreur: ${data.error}`, 'error');
}
else {
// Cas où la réponse est 200 OK mais le format n'est pas celui attendu
displayMessage('Réponse inattendue reçue du serveur.', 'error');
}
} catch (error) {
// Gérer les erreurs réseau ou les erreurs levées lors du traitement de la réponse
console.error('Erreur lors de la requête de génération:', error);
clearMessage(); // Assurez-vous que le message de chargement est parti
displayMessage(`Erreur de communication: ${error.message}`, 'error');
} finally {
// Réactiver le bouton dans tous les cas (succès ou échec)
generateButton.disabled = false;
}
}
function displayMessage(message, type = 'info') { // type peut être 'info', 'error', 'loading', 'success'
statusMessage.textContent = message;
statusMessage.className = type; // Appliquer la classe pour le style CSS
statusMessage.style.display = 'block'; // S'assurer que le message est visible
}
function clearMessage() {
statusMessage.textContent = '';
statusMessage.className = '';
statusMessage.style.display = 'none'; // Cacher la zone de message
}
function displayFlashcards(flashcards) {
flashcardsContainer.innerHTML = ''; // Assurer que c'est vide avant d'ajouter
flashcards.forEach((card) => {
// Vérification simple de la structure attendue
if (typeof card.question !== 'string' || typeof card.answer !== 'string') {
console.warn('Format de flashcard inattendu ignoré:', card);
return; // Ignorer cette carte si elle n'a pas le bon format
}
const cardElement = document.createElement('div');
cardElement.classList.add('flashcard');
const questionElement = document.createElement('div');
questionElement.classList.add('question');
questionElement.textContent = `Q: ${card.question}`;
const answerElement = document.createElement('div');
answerElement.classList.add('answer');
answerElement.textContent = `R: ${card.answer}`;
cardElement.appendChild(questionElement);
cardElement.appendChild(answerElement);
// Ajouter l'interactivité: cliquer pour afficher/masquer la réponse
cardElement.addEventListener('click', () => {
cardElement.classList.toggle('flipped');
});
flashcardsContainer.appendChild(cardElement);
});
}
</script>
</body>
</html>