Zeggai Abdellah commited on
Commit
944616a
·
1 Parent(s): b8f2d15

add index html

Browse files
Files changed (2) hide show
  1. app.py +4 -19
  2. index.html +329 -0
app.py CHANGED
@@ -145,18 +145,6 @@ def save_dataset_to_space(dataset: Dict, filename: str):
145
  json.dump(dataset, f, indent=4, ensure_ascii=False)
146
  print(f"Dataset saved to {persistent_path}")
147
 
148
- # # Optionally upload to Space files
149
- # try:
150
- # api = HfApi(token=os.getenv("HF_TOKEN"))
151
- # api.upload_file(
152
- # path_or_fileobj=persistent_path,
153
- # path_in_repo=filename,
154
- # repo_id=os.getenv("SPACE_ID"),
155
- # repo_type="space"
156
- # )
157
- # print(f"File {filename} uploaded to Space")
158
- # except Exception as e:
159
- # print(f"Could not upload to Space: {e}")
160
 
161
  @app.get("/generate-questions")
162
  async def generate_questions():
@@ -203,13 +191,10 @@ async def download_file(filename: str):
203
 
204
  @app.get("/")
205
  async def root():
206
- return {
207
- "message": "Vaccine Question Generator API",
208
- "endpoints": {
209
- "GET /generate-questions": "Generate questions from vaccine guide",
210
- "GET /download/{filename}": "Download generated files"
211
- }
212
- }
213
 
214
  if __name__ == "__main__":
215
  import uvicorn
 
145
  json.dump(dataset, f, indent=4, ensure_ascii=False)
146
  print(f"Dataset saved to {persistent_path}")
147
 
 
 
 
 
 
 
 
 
 
 
 
 
148
 
149
  @app.get("/generate-questions")
150
  async def generate_questions():
 
191
 
192
  @app.get("/")
193
  async def root():
194
+ """
195
+ Root endpoint that serves the HTML UI from the index.html file.
196
+ """
197
+ return FileResponse("./index.html", media_type="text/html")
 
 
 
198
 
199
  if __name__ == "__main__":
200
  import uvicorn
index.html ADDED
@@ -0,0 +1,329 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
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 Questions sur les Vaccins</title>
7
+ <style>
8
+ body {
9
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
10
+ line-height: 1.6;
11
+ color: #333;
12
+ max-width: 1000px;
13
+ margin: 0 auto;
14
+ padding: 20px;
15
+ background-color: #f5f7fa;
16
+ }
17
+ h1 {
18
+ color: #2c3e50;
19
+ text-align: center;
20
+ border-bottom: 2px solid #3498db;
21
+ padding-bottom: 10px;
22
+ }
23
+ .container {
24
+ background-color: white;
25
+ border-radius: 8px;
26
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
27
+ padding: 20px;
28
+ margin-bottom: 20px;
29
+ }
30
+ button {
31
+ background-color: #3498db;
32
+ color: white;
33
+ border: none;
34
+ padding: 10px 20px;
35
+ border-radius: 4px;
36
+ cursor: pointer;
37
+ font-size: 16px;
38
+ transition: background-color 0.3s;
39
+ }
40
+ button:hover {
41
+ background-color: #2980b9;
42
+ }
43
+ button:disabled {
44
+ background-color: #95a5a6;
45
+ cursor: not-allowed;
46
+ }
47
+ .download-btn {
48
+ background-color: #27ae60;
49
+ }
50
+ .download-btn:hover {
51
+ background-color: #219955;
52
+ }
53
+ #statusContainer {
54
+ margin-top: 20px;
55
+ padding: 15px;
56
+ border-left: 4px solid #3498db;
57
+ background-color: #e8f4fc;
58
+ }
59
+ .loader {
60
+ display: inline-block;
61
+ width: 20px;
62
+ height: 20px;
63
+ border: 3px solid rgba(0, 0, 0, 0.1);
64
+ border-radius: 50%;
65
+ border-top-color: #3498db;
66
+ animation: spin 1s ease infinite;
67
+ margin-right: 10px;
68
+ vertical-align: middle;
69
+ }
70
+ @keyframes spin {
71
+ to { transform: rotate(360deg); }
72
+ }
73
+ .stats-container {
74
+ display: grid;
75
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
76
+ gap: 15px;
77
+ margin-top: 20px;
78
+ }
79
+ .stat-card {
80
+ background-color: white;
81
+ padding: 15px;
82
+ border-radius: 8px;
83
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
84
+ text-align: center;
85
+ }
86
+ .stat-value {
87
+ font-size: 24px;
88
+ font-weight: bold;
89
+ color: #2c3e50;
90
+ margin: 10px 0;
91
+ }
92
+ .stat-label {
93
+ color: #7f8c8d;
94
+ font-size: 14px;
95
+ }
96
+ #questionsPreview {
97
+ margin-top: 20px;
98
+ max-height: 400px;
99
+ overflow-y: auto;
100
+ background-color: white;
101
+ border-radius: 8px;
102
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
103
+ }
104
+ table {
105
+ width: 100%;
106
+ border-collapse: collapse;
107
+ }
108
+ th, td {
109
+ padding: 12px 15px;
110
+ text-align: left;
111
+ border-bottom: 1px solid #ddd;
112
+ }
113
+ th {
114
+ background-color: #f8f9fa;
115
+ font-weight: 600;
116
+ }
117
+ tr:hover {
118
+ background-color: #f1f5f9;
119
+ }
120
+ .badge {
121
+ display: inline-block;
122
+ padding: 4px 8px;
123
+ border-radius: 4px;
124
+ font-size: 12px;
125
+ font-weight: 600;
126
+ text-transform: uppercase;
127
+ color: white;
128
+ }
129
+ .badge-easy { background-color: #27ae60; }
130
+ .badge-medium { background-color: #f39c12; }
131
+ .badge-hard { background-color: #e74c3c; }
132
+ .badge-factual { background-color: #3498db; }
133
+ .badge-conceptual { background-color: #9b59b6; }
134
+ .badge-applied { background-color: #e67e22; }
135
+ </style>
136
+ </head>
137
+ <body>
138
+ <h1>Générateur de Questions sur les Vaccins</h1>
139
+
140
+ <div class="container">
141
+ <h2>Générer des Questions</h2>
142
+ <p>Cliquez sur le bouton ci-dessous pour commencer la génération de questions à partir du guide de vaccination.</p>
143
+ <button id="generateBtn">Générer des Questions</button>
144
+
145
+ <div id="statusContainer" style="display: none;">
146
+ <div class="loader"></div>
147
+ <span id="statusText">Initialisation de la génération...</span>
148
+ </div>
149
+ </div>
150
+
151
+ <div class="container" id="resultsContainer" style="display: none;">
152
+ <h2>Résultats</h2>
153
+
154
+ <div class="stats-container" id="statsContainer">
155
+ <!-- Stats will be populated here -->
156
+ </div>
157
+
158
+ <div style="margin-top: 20px; text-align: center;">
159
+ <button id="downloadBtn" class="download-btn">Télécharger le Dataset</button>
160
+ </div>
161
+
162
+ <h3 style="margin-top: 30px;">Aperçu des Questions</h3>
163
+ <div id="questionsPreview">
164
+ <table>
165
+ <thead>
166
+ <tr>
167
+ <th>Question</th>
168
+ <th>Type</th>
169
+ <th>Difficulté</th>
170
+ <th>But d'Entraînement</th>
171
+ </tr>
172
+ </thead>
173
+ <tbody id="questionsTableBody">
174
+ <!-- Questions will be populated here -->
175
+ </tbody>
176
+ </table>
177
+ </div>
178
+ </div>
179
+
180
+ <script>
181
+ const apiBaseUrl = window.location.origin; // Use the same origin for API calls
182
+ let generatedDataset = null;
183
+ let downloadUrl = '';
184
+
185
+ document.getElementById('generateBtn').addEventListener('click', startGeneration);
186
+ document.getElementById('downloadBtn').addEventListener('click', downloadDataset);
187
+
188
+ function startGeneration() {
189
+ const generateBtn = document.getElementById('generateBtn');
190
+ const statusContainer = document.getElementById('statusContainer');
191
+ const statusText = document.getElementById('statusText');
192
+ const resultsContainer = document.getElementById('resultsContainer');
193
+
194
+ // Disable button and show status
195
+ generateBtn.disabled = true;
196
+ statusContainer.style.display = 'block';
197
+ statusText.textContent = 'Génération des questions en cours... Cela peut prendre quelques minutes.';
198
+ resultsContainer.style.display = 'none';
199
+
200
+ // Call the API endpoint
201
+ fetch(`${apiBaseUrl}/generate-questions`)
202
+ .then(response => {
203
+ if (!response.ok) {
204
+ throw new Error(`HTTP error! Status: ${response.status}`);
205
+ }
206
+ return response.json();
207
+ })
208
+ .then(data => {
209
+ console.log('Generation successful:', data);
210
+ downloadUrl = data.download_url;
211
+
212
+ // Fetch the generated dataset
213
+ return fetch(`${apiBaseUrl}${downloadUrl}`);
214
+ })
215
+ .then(response => response.json())
216
+ .then(dataset => {
217
+ generatedDataset = dataset;
218
+ displayResults(dataset);
219
+
220
+ // Update status and re-enable button
221
+ statusText.textContent = 'Génération terminée avec succès !';
222
+ setTimeout(() => {
223
+ statusContainer.style.display = 'none';
224
+ generateBtn.disabled = false;
225
+ }, 3000);
226
+ })
227
+ .catch(error => {
228
+ console.error('Error generating questions:', error);
229
+ statusText.textContent = `Erreur: ${error.message}`;
230
+ generateBtn.disabled = false;
231
+ });
232
+ }
233
+
234
+ function displayResults(dataset) {
235
+ const resultsContainer = document.getElementById('resultsContainer');
236
+ const statsContainer = document.getElementById('statsContainer');
237
+ const questionsTableBody = document.getElementById('questionsTableBody');
238
+
239
+ // Display dataset info stats
240
+ statsContainer.innerHTML = '';
241
+
242
+ // Total questions
243
+ addStatCard(statsContainer, dataset.dataset_info.total_questions, 'Questions Totales');
244
+
245
+ // Count by type
246
+ const typeCount = countByProperty(dataset.questions, 'type');
247
+ for (const [type, count] of Object.entries(typeCount)) {
248
+ addStatCard(statsContainer, count, `Questions ${capitalizeFirstLetter(type)}`);
249
+ }
250
+
251
+ // Count by difficulty
252
+ const difficultyCount = countByProperty(dataset.questions, 'difficulty');
253
+ for (const [difficulty, count] of Object.entries(difficultyCount)) {
254
+ addStatCard(statsContainer, count, `Niveau ${capitalizeFirstLetter(difficulty)}`);
255
+ }
256
+
257
+ // Display questions preview
258
+ questionsTableBody.innerHTML = '';
259
+ dataset.questions.forEach(question => {
260
+ const row = document.createElement('tr');
261
+
262
+ const questionCell = document.createElement('td');
263
+ questionCell.textContent = question.question;
264
+
265
+ const typeCell = document.createElement('td');
266
+ const typeBadge = document.createElement('span');
267
+ typeBadge.className = `badge badge-${question.type}`;
268
+ typeBadge.textContent = question.type;
269
+ typeCell.appendChild(typeBadge);
270
+
271
+ const difficultyCell = document.createElement('td');
272
+ const difficultyBadge = document.createElement('span');
273
+ difficultyBadge.className = `badge badge-${question.difficulty}`;
274
+ difficultyBadge.textContent = question.difficulty;
275
+ difficultyCell.appendChild(difficultyBadge);
276
+
277
+ const purposeCell = document.createElement('td');
278
+ purposeCell.textContent = question.training_purpose;
279
+
280
+ row.appendChild(questionCell);
281
+ row.appendChild(typeCell);
282
+ row.appendChild(difficultyCell);
283
+ row.appendChild(purposeCell);
284
+
285
+ questionsTableBody.appendChild(row);
286
+ });
287
+
288
+ // Show the results container
289
+ resultsContainer.style.display = 'block';
290
+ }
291
+
292
+ function addStatCard(container, value, label) {
293
+ const card = document.createElement('div');
294
+ card.className = 'stat-card';
295
+
296
+ const valueElement = document.createElement('div');
297
+ valueElement.className = 'stat-value';
298
+ valueElement.textContent = value;
299
+
300
+ const labelElement = document.createElement('div');
301
+ labelElement.className = 'stat-label';
302
+ labelElement.textContent = label;
303
+
304
+ card.appendChild(valueElement);
305
+ card.appendChild(labelElement);
306
+ container.appendChild(card);
307
+ }
308
+
309
+ function countByProperty(array, property) {
310
+ const counts = {};
311
+ array.forEach(item => {
312
+ const value = item[property];
313
+ counts[value] = (counts[value] || 0) + 1;
314
+ });
315
+ return counts;
316
+ }
317
+
318
+ function capitalizeFirstLetter(string) {
319
+ return string.charAt(0).toUpperCase() + string.slice(1);
320
+ }
321
+
322
+ function downloadDataset() {
323
+ if (downloadUrl) {
324
+ window.location.href = `${apiBaseUrl}${downloadUrl}`;
325
+ }
326
+ }
327
+ </script>
328
+ </body>
329
+ </html>