Docfile commited on
Commit
671f070
·
verified ·
1 Parent(s): d9ee204

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +217 -223
templates/index.html CHANGED
@@ -3,264 +3,258 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Générateur de Flashcards IA</title>
 
7
  <style>
8
- body {
9
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
10
- line-height: 1.6;
11
- padding: 20px;
12
- max-width: 800px;
13
- margin: 40px auto;
14
- background-color: #f4f4f4;
15
- color: #333;
16
- }
17
- .container {
18
- background-color: #fff;
19
- padding: 30px;
20
  border-radius: 8px;
21
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
 
 
 
 
22
  }
23
- h1 {
24
- text-align: center;
25
- color: #2c3e50;
26
- margin-bottom: 30px;
27
  }
28
- label {
29
- display: block;
30
- margin-bottom: 8px;
31
- font-weight: bold;
32
- color: #555;
33
  }
34
- input[type="text"] {
35
- width: calc(100% - 120px); /* Adjust width considering button size */
36
- padding: 12px;
37
  margin-bottom: 20px;
38
- border: 1px solid #ccc;
39
- border-radius: 4px;
40
- font-size: 1rem;
41
- box-sizing: border-box; /* Include padding in width */
42
  }
43
- button {
44
- padding: 12px 20px;
45
- background-color: #3498db;
46
- color: white;
47
- border: none;
48
  border-radius: 4px;
49
  cursor: pointer;
50
- font-size: 1rem;
51
- transition: background-color 0.3s ease;
52
- vertical-align: top; /* Align with input field */
53
- }
54
- button:hover {
55
- background-color: #2980b9;
56
- }
57
- button:disabled {
58
- background-color: #bdc3c7;
59
- cursor: not-allowed;
60
- }
61
- #statusMessage {
62
- margin-top: 20px;
63
- padding: 10px;
64
- border-radius: 4px;
65
- text-align: center;
66
- font-weight: bold;
67
- }
68
- #statusMessage.loading {
69
- background-color: #eaf2f8;
70
- color: #3498db;
71
- }
72
- #statusMessage.error {
73
- background-color: #fbeae5;
74
- color: #c0392b;
75
- }
76
- #statusMessage.success {
77
- background-color: #e8f6f3;
78
- color: #1abc9c;
79
  }
80
- #flashcardsContainer {
81
- margin-top: 30px;
82
- border-top: 1px solid #eee;
83
- padding-top: 20px;
84
  }
85
- .flashcard {
86
- background-color: #f9f9f9;
87
- border: 1px solid #ddd;
88
- border-radius: 5px;
89
- padding: 15px 20px;
90
- margin-bottom: 15px;
91
- cursor: pointer;
92
- transition: box-shadow 0.2s ease-in-out;
93
- }
94
- .flashcard:hover {
95
- box-shadow: 0 2px 5px rgba(0,0,0,0.1);
96
  }
97
- .flashcard .question {
98
- font-weight: bold;
99
- margin-bottom: 10px;
100
- color: #34495e;
101
  }
102
- .flashcard .answer {
103
- display: none; /* Hidden by default */
104
- color: #555;
105
- margin-top: 10px;
106
- padding-top: 10px;
107
- border-top: 1px dashed #ccc;
108
  }
109
- .flashcard.flipped .answer {
110
- display: block; /* Shown when .flipped class is added */
 
 
 
 
111
  }
112
-
113
- @media (max-width: 600px) {
114
- input[type="text"] {
115
- width: 100%;
116
- margin-bottom: 10px;
117
- }
118
- button {
119
- width: 100%;
120
- }
121
  }
122
-
123
  </style>
124
  </head>
125
  <body>
126
- <div class="container">
127
- <h1>Générateur de Flashcards IA</h1>
128
-
129
- <div>
130
- <label for="topicInput">Entrez un sujet :</label>
131
- <input type="text" id="topicInput" placeholder="Ex: Histoire de l'intelligence artificielle">
132
- <button id="generateButton">Générer</button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  </div>
134
-
135
- <div id="statusMessage"></div>
136
-
137
- <div id="flashcardsContainer">
138
- <!-- Les flashcards générées apparaîtront ici -->
 
139
  </div>
 
 
 
140
  </div>
141
 
142
  <script>
143
- const topicInput = document.getElementById('topicInput');
144
- const generateButton = document.getElementById('generateButton');
145
- const statusMessage = document.getElementById('statusMessage');
146
- const flashcardsContainer = document.getElementById('flashcardsContainer');
147
-
148
- generateButton.addEventListener('click', handleGenerateClick);
149
- // Optionnel : Permettre de lancer la génération avec la touche Entrée dans le champ de texte
150
- topicInput.addEventListener('keypress', function(event) {
151
- if (event.key === 'Enter') {
152
- event.preventDefault(); // Empêche la soumission de formulaire par défaut si enveloppé dans un <form>
153
- handleGenerateClick();
154
- }
155
- });
156
-
157
-
158
- async function handleGenerateClick() {
159
- const topic = topicInput.value.trim();
160
-
161
  if (!topic) {
162
- displayMessage('Veuillez entrer un sujet.', 'error');
163
  return;
164
  }
165
-
166
- // Désactiver le bouton et afficher le message de chargement
167
- generateButton.disabled = true;
168
- flashcardsContainer.innerHTML = ''; // Vider les anciennes flashcards
169
- displayMessage('Génération des flashcards en cours... Cela peut prendre un moment.', 'loading');
170
-
171
- try {
172
- const response = await fetch('/generate', {
173
- method: 'POST',
174
- headers: {
175
- 'Content-Type': 'application/json',
176
- },
177
- body: JSON.stringify({ topic: topic }),
178
- });
179
-
180
- // Essayer de parser la réponse JSON même si le statut n'est pas OK (pour les messages d'erreur du backend)
181
- const data = await response.json();
182
-
183
- clearMessage(); // Effacer le message de chargement
184
-
185
- if (!response.ok) {
186
- // Gérer les erreurs HTTP (4xx, 5xx) et les erreurs applicatives renvoyées dans le JSON
187
- const errorMsg = data?.error || `Erreur ${response.status}: ${response.statusText}`;
188
- throw new Error(errorMsg); // Provoque l'entrée dans le bloc catch
189
  }
190
-
191
- if (data.success && data.flashcards && Array.isArray(data.flashcards)) {
192
- if(data.flashcards.length > 0) {
193
- displayFlashcards(data.flashcards);
194
- displayMessage(`Flashcards générées pour "${topic}"! Cliquez sur une carte pour voir la réponse.`, 'success');
195
- } else {
196
- 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
197
- statusMessage.style.backgroundColor = '#eaf2f8'; // Style pour info
198
- statusMessage.style.color = '#3498db';
199
- }
200
- } else if (data.error) {
201
- // Gérer les erreurs applicatives spécifiques renvoyées dans data.error
202
- displayMessage(`Erreur: ${data.error}`, 'error');
203
- }
204
- else {
205
- // Cas où la réponse est 200 OK mais le format n'est pas celui attendu
206
- displayMessage('Réponse inattendue reçue du serveur.', 'error');
207
  }
208
-
209
- } catch (error) {
210
- // Gérer les erreurs réseau ou les erreurs levées lors du traitement de la réponse
211
- console.error('Erreur lors de la requête de génération:', error);
212
- clearMessage(); // Assurez-vous que le message de chargement est parti
213
- displayMessage(`Erreur de communication: ${error.message}`, 'error');
214
- } finally {
215
- // Réactiver le bouton dans tous les cas (succès ou échec)
216
- generateButton.disabled = false;
217
- }
218
- }
219
-
220
- function displayMessage(message, type = 'info') { // type peut être 'info', 'error', 'loading', 'success'
221
- statusMessage.textContent = message;
222
- statusMessage.className = type; // Appliquer la classe pour le style CSS
223
- statusMessage.style.display = 'block'; // S'assurer que le message est visible
224
- }
225
-
226
- function clearMessage() {
227
- statusMessage.textContent = '';
228
- statusMessage.className = '';
229
- statusMessage.style.display = 'none'; // Cacher la zone de message
230
- }
231
-
232
  function displayFlashcards(flashcards) {
233
- flashcardsContainer.innerHTML = ''; // Assurer que c'est vide avant d'ajouter
234
-
235
- flashcards.forEach((card) => {
236
- // Vérification simple de la structure attendue
237
- if (typeof card.question !== 'string' || typeof card.answer !== 'string') {
238
- console.warn('Format de flashcard inattendu ignoré:', card);
239
- return; // Ignorer cette carte si elle n'a pas le bon format
240
- }
241
-
242
  const cardElement = document.createElement('div');
243
- cardElement.classList.add('flashcard');
244
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
  const questionElement = document.createElement('div');
246
- questionElement.classList.add('question');
247
- questionElement.textContent = `Q: ${card.question}`;
248
-
249
- const answerElement = document.createElement('div');
250
- answerElement.classList.add('answer');
251
- answerElement.textContent = `R: ${card.answer}`;
252
-
253
- cardElement.appendChild(questionElement);
254
- cardElement.appendChild(answerElement);
255
-
256
- // Ajouter l'interactivité: cliquer pour afficher/masquer la réponse
257
- cardElement.addEventListener('click', () => {
258
- cardElement.classList.toggle('flipped');
259
  });
260
-
261
- flashcardsContainer.appendChild(cardElement);
 
 
 
 
 
 
 
 
 
 
 
262
  });
263
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
264
  </script>
265
  </body>
266
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Générateur de Flashcards et Quiz</title>
7
+ <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
8
  <style>
9
+ .flashcard {
10
+ border: 1px solid #ddd;
 
 
 
 
 
 
 
 
 
 
11
  border-radius: 8px;
12
+ margin-bottom: 15px;
13
+ padding: 15px;
14
+ cursor: pointer;
15
+ background-color: #f8f9fa;
16
+ transition: transform 0.3s;
17
  }
18
+ .flashcard:hover {
19
+ transform: translateY(-5px);
20
+ box-shadow: 0 5px 15px rgba(0,0,0,0.1);
 
21
  }
22
+ .answer {
23
+ display: none;
24
+ margin-top: 10px;
25
+ padding-top: 10px;
26
+ border-top: 1px dashed #ccc;
27
  }
28
+ .quiz-question {
29
+ border: 1px solid #ddd;
30
+ border-radius: 8px;
31
  margin-bottom: 20px;
32
+ padding: 15px;
33
+ background-color: #f8f9fa;
 
 
34
  }
35
+ .option {
36
+ padding: 8px 15px;
37
+ margin: 5px 0;
 
 
38
  border-radius: 4px;
39
  cursor: pointer;
40
+ transition: background-color 0.2s;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  }
42
+ .option:hover {
43
+ background-color: #e9ecef;
 
 
44
  }
45
+ .selected {
46
+ background-color: #d1e7dd;
 
 
 
 
 
 
 
 
 
47
  }
48
+ .correct {
49
+ background-color: #d4edda;
50
+ border-color: #c3e6cb;
 
51
  }
52
+ .incorrect {
53
+ background-color: #f8d7da;
54
+ border-color: #f5c6cb;
 
 
 
55
  }
56
+ .explanation {
57
+ display: none;
58
+ margin-top: 15px;
59
+ padding: 10px;
60
+ border-radius: 4px;
61
+ background-color: #e2f3fc;
62
  }
63
+ #loading {
64
+ display: none;
 
 
 
 
 
 
 
65
  }
 
66
  </style>
67
  </head>
68
  <body>
69
+ <div class="container mt-5">
70
+ <h1 class="text-center mb-4">Générateur de Flashcards et Quiz</h1>
71
+
72
+ <div class="row mb-4">
73
+ <div class="col-md-8 offset-md-2">
74
+ <div class="card">
75
+ <div class="card-body">
76
+ <div class="mb-3">
77
+ <label for="topic" class="form-label">Sujet</label>
78
+ <input type="text" class="form-control" id="topic" placeholder="Entrez un sujet...">
79
+ </div>
80
+ <div class="mb-3">
81
+ <label class="form-label">Type de contenu</label>
82
+ <div class="form-check">
83
+ <input class="form-check-input" type="radio" name="contentType" id="typeFlashcards" value="flashcards" checked>
84
+ <label class="form-check-label" for="typeFlashcards">
85
+ Flashcards
86
+ </label>
87
+ </div>
88
+ <div class="form-check">
89
+ <input class="form-check-input" type="radio" name="contentType" id="typeQuiz" value="quiz">
90
+ <label class="form-check-label" for="typeQuiz">
91
+ Quiz
92
+ </label>
93
+ </div>
94
+ </div>
95
+ <button id="generateBtn" class="btn btn-primary w-100">Générer</button>
96
+ </div>
97
+ </div>
98
+ </div>
99
  </div>
100
+
101
+ <div id="loading" class="text-center my-5">
102
+ <div class="spinner-border text-primary" role="status">
103
+ <span class="visually-hidden">Chargement...</span>
104
+ </div>
105
+ <p class="mt-2">Génération en cours... Cela peut prendre plusieurs minutes.</p>
106
  </div>
107
+
108
+ <div id="flashcardsContainer" class="row mt-4"></div>
109
+ <div id="quizContainer" class="row mt-4"></div>
110
  </div>
111
 
112
  <script>
113
+ document.getElementById('generateBtn').addEventListener('click', function() {
114
+ const topic = document.getElementById('topic').value;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  if (!topic) {
116
+ alert('Veuillez entrer un sujet.');
117
  return;
118
  }
119
+
120
+ const contentType = document.querySelector('input[name="contentType"]:checked').value;
121
+
122
+ // Afficher le chargement
123
+ document.getElementById('loading').style.display = 'block';
124
+ document.getElementById('flashcardsContainer').innerHTML = '';
125
+ document.getElementById('quizContainer').innerHTML = '';
126
+
127
+ // Envoi de la requête
128
+ fetch('/generate', {
129
+ method: 'POST',
130
+ headers: {
131
+ 'Content-Type': 'application/json',
132
+ },
133
+ body: JSON.stringify({ topic, type: contentType }),
134
+ })
135
+ .then(response => response.json())
136
+ .then(data => {
137
+ // Masquer le chargement
138
+ document.getElementById('loading').style.display = 'none';
139
+
140
+ if (data.error) {
141
+ alert('Erreur: ' + data.error);
142
+ return;
143
  }
144
+
145
+ if (contentType === 'flashcards' && data.flashcards) {
146
+ displayFlashcards(data.flashcards);
147
+ } else if (contentType === 'quiz' && data.quiz) {
148
+ displayQuiz(data.quiz);
 
 
 
 
 
 
 
 
 
 
 
 
149
  }
150
+ })
151
+ .catch(error => {
152
+ document.getElementById('loading').style.display = 'none';
153
+ alert('Erreur lors de la génération: ' + error);
154
+ });
155
+ });
156
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
  function displayFlashcards(flashcards) {
158
+ const container = document.getElementById('flashcardsContainer');
159
+ container.innerHTML = `
160
+ <div class="col-12 mb-4">
161
+ <h2 class="text-center">Flashcards générées (${flashcards.length})</h2>
162
+ <p class="text-center text-muted">Cliquez sur une carte pour voir la réponse</p>
163
+ </div>
164
+ `;
165
+
166
+ flashcards.forEach((card, index) => {
167
  const cardElement = document.createElement('div');
168
+ cardElement.className = 'col-md-6 col-lg-4';
169
+ cardElement.innerHTML = `
170
+ <div class="flashcard" onclick="toggleAnswer(${index})">
171
+ <h5 class="card-title">${card.question}</h5>
172
+ <div id="answer-${index}" class="answer">
173
+ <strong>Réponse:</strong> ${card.answer}
174
+ </div>
175
+ </div>
176
+ `;
177
+ container.appendChild(cardElement);
178
+ });
179
+ }
180
+
181
+ function toggleAnswer(index) {
182
+ const answerElement = document.getElementById(`answer-${index}`);
183
+ if (answerElement.style.display === 'block') {
184
+ answerElement.style.display = 'none';
185
+ } else {
186
+ answerElement.style.display = 'block';
187
+ }
188
+ }
189
+
190
+ function displayQuiz(quizQuestions) {
191
+ const container = document.getElementById('quizContainer');
192
+ container.innerHTML = `
193
+ <div class="col-12 mb-4">
194
+ <h2 class="text-center">Quiz généré (${quizQuestions.length} questions)</h2>
195
+ <p class="text-center text-muted">Sélectionnez une réponse pour chaque question</p>
196
+ </div>
197
+ `;
198
+
199
+ quizQuestions.forEach((question, qIndex) => {
200
  const questionElement = document.createElement('div');
201
+ questionElement.className = 'col-12 mb-4';
202
+
203
+ let optionsHtml = '';
204
+ question.options.forEach((option, oIndex) => {
205
+ optionsHtml += `
206
+ <div class="option" id="q${qIndex}-o${oIndex}"
207
+ onclick="selectOption(${qIndex}, ${oIndex}, '${question.correctAnswer}')">
208
+ ${option}
209
+ </div>
210
+ `;
 
 
 
211
  });
212
+
213
+ questionElement.innerHTML = `
214
+ <div class="quiz-question">
215
+ <h5>${qIndex + 1}. ${question.question}</h5>
216
+ <div class="options mt-3">
217
+ ${optionsHtml}
218
+ </div>
219
+ <div class="explanation" id="explanation-${qIndex}">
220
+ <strong>Explication:</strong> ${question.explanation}
221
+ </div>
222
+ </div>
223
+ `;
224
+ container.appendChild(questionElement);
225
  });
226
  }
227
+
228
+ function selectOption(questionIndex, optionIndex, correctAnswer) {
229
+ const questionOptions = document.querySelectorAll(`[id^="q${questionIndex}-o"]`);
230
+ const selectedOption = document.getElementById(`q${questionIndex}-o${optionIndex}`);
231
+ const explanationElement = document.getElementById(`explanation-${questionIndex}`);
232
+
233
+ // Retirer les classes des autres options
234
+ questionOptions.forEach(option => {
235
+ option.classList.remove('selected', 'correct', 'incorrect');
236
+ });
237
+
238
+ // Sélectionner l'option
239
+ selectedOption.classList.add('selected');
240
+
241
+ // Vérifier si c'est la bonne réponse
242
+ const selectedText = selectedOption.textContent.trim();
243
+ if (selectedText === correctAnswer) {
244
+ selectedOption.classList.add('correct');
245
+ } else {
246
+ selectedOption.classList.add('incorrect');
247
+ // Mettre en évidence la bonne réponse
248
+ questionOptions.forEach(option => {
249
+ if (option.textContent.trim() === correctAnswer) {
250
+ option.classList.add('correct');
251
+ }
252
+ });
253
+ }
254
+
255
+ // Afficher l'explication
256
+ explanationElement.style.display = 'block';
257
+ }
258
  </script>
259
  </body>
260
  </html>