Docfile commited on
Commit
0d104ce
·
verified ·
1 Parent(s): ee28809

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +162 -269
templates/index.html CHANGED
@@ -4,275 +4,119 @@
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Générateur de Données Synthétiques</title>
7
- <style>
8
- * {
9
- margin: 0;
10
- padding: 0;
11
- box-sizing: border-box;
12
- }
13
-
14
- body {
15
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
16
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
17
- min-height: 100vh;
18
- display: flex;
19
- align-items: center;
20
- justify-content: center;
21
- padding: 20px;
22
- }
23
-
24
- .container {
25
- background: white;
26
- border-radius: 20px;
27
- box-shadow: 0 20px 40px rgba(0,0,0,0.1);
28
- padding: 40px;
29
- max-width: 800px;
30
- width: 100%;
31
- }
32
-
33
- .header {
34
- text-align: center;
35
- margin-bottom: 40px;
36
- }
37
-
38
- .header h1 {
39
- color: #333;
40
- font-size: 2.5em;
41
- margin-bottom: 10px;
42
- background: linear-gradient(135deg, #667eea, #764ba2);
43
- -webkit-background-clip: text;
44
- -webkit-text-fill-color: transparent;
45
- background-clip: text;
46
- }
47
-
48
- .header p {
49
- color: #666;
50
- font-size: 1.1em;
51
- }
52
-
53
- .upload-section {
54
- border: 3px dashed #ddd;
55
- border-radius: 15px;
56
- padding: 40px;
57
- text-align: center;
58
- margin-bottom: 30px;
59
- transition: all 0.3s ease;
60
- }
61
-
62
- .upload-section:hover {
63
- border-color: #667eea;
64
- background: #f8f9ff;
65
- }
66
-
67
- .upload-section.dragover {
68
- border-color: #667eea;
69
- background: #f0f4ff;
70
- }
71
-
72
- input[type="file"] {
73
- display: none;
74
- }
75
-
76
- .upload-btn {
77
- background: linear-gradient(135deg, #667eea, #764ba2);
78
- color: white;
79
- padding: 15px 30px;
80
- border: none;
81
- border-radius: 50px;
82
- cursor: pointer;
83
- font-size: 1.1em;
84
- font-weight: 600;
85
- transition: all 0.3s ease;
86
- margin: 10px;
87
- }
88
-
89
- .upload-btn:hover {
90
- transform: translateY(-2px);
91
- box-shadow: 0 10px 20px rgba(0,0,0,0.2);
92
- }
93
-
94
- .progress-section {
95
- display: none;
96
- margin-top: 30px;
97
- }
98
-
99
- .progress-bar {
100
- width: 100%;
101
- height: 20px;
102
- background: #f0f0f0;
103
- border-radius: 10px;
104
- overflow: hidden;
105
- margin: 20px 0;
106
- }
107
-
108
- .progress-fill {
109
- height: 100%;
110
- background: linear-gradient(90deg, #667eea, #764ba2);
111
- width: 0%;
112
- transition: width 0.3s ease;
113
- position: relative;
114
- }
115
-
116
- .progress-fill::after {
117
- content: '';
118
- position: absolute;
119
- top: 0;
120
- left: 0;
121
- right: 0;
122
- bottom: 0;
123
- background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
124
- animation: shimmer 2s infinite;
125
- }
126
-
127
- @keyframes shimmer {
128
- 0% { transform: translateX(-100%); }
129
- 100% { transform: translateX(100%); }
130
- }
131
-
132
- .status-info {
133
- display: grid;
134
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
135
- gap: 20px;
136
- margin: 20px 0;
137
- }
138
-
139
- .status-card {
140
- background: #f8f9ff;
141
- padding: 20px;
142
- border-radius: 10px;
143
- text-align: center;
144
- border-left: 4px solid #667eea;
145
- }
146
-
147
- .status-card h3 {
148
- color: #333;
149
- margin-bottom: 10px;
150
- }
151
-
152
- .status-card p {
153
- color: #666;
154
- font-size: 1.2em;
155
- font-weight: bold;
156
- }
157
-
158
- .download-btn {
159
- background: linear-gradient(135deg, #28a745, #20c997);
160
- color: white;
161
- padding: 15px 30px;
162
- border: none;
163
- border-radius: 50px;
164
- cursor: pointer;
165
- font-size: 1.1em;
166
- font-weight: 600;
167
- transition: all 0.3s ease;
168
- margin: 20px 10px;
169
- display: none;
170
- }
171
-
172
- .download-btn:hover {
173
- transform: translateY(-2px);
174
- box-shadow: 0 10px 20px rgba(0,0,0,0.2);
175
- }
176
-
177
- .tasks-section {
178
- margin-top: 30px;
179
- padding-top: 30px;
180
- border-top: 2px solid #eee;
181
- }
182
-
183
- .task-item {
184
- background: #f8f9ff;
185
- padding: 15px;
186
- border-radius: 10px;
187
- margin: 10px 0;
188
- border-left: 4px solid #667eea;
189
- }
190
-
191
- .task-item.completed {
192
- border-left-color: #28a745;
193
- }
194
-
195
- .notification {
196
- position: fixed;
197
- top: 20px;
198
- right: 20px;
199
- padding: 15px 25px;
200
- border-radius: 10px;
201
- color: white;
202
- font-weight: 600;
203
- transform: translateX(100%);
204
- transition: transform 0.3s ease;
205
- z-index: 1000;
206
- }
207
-
208
- .notification.success {
209
- background: linear-gradient(135deg, #28a745, #20c997);
210
- }
211
-
212
- .notification.error {
213
- background: linear-gradient(135deg, #dc3545, #c82333);
214
- }
215
-
216
- .notification.show {
217
- transform: translateX(0);
218
  }
219
- </style>
220
  </head>
221
- <body>
222
- <div class="container">
223
- <div class="header">
224
- <h1>🤖 Générateur de Données Synthétiques</h1>
225
- <p>Uploadez votre fichier pour générer 470 jeux de données synthétiques</p>
 
 
 
226
  </div>
227
 
228
- <div class="upload-section" id="uploadSection">
229
- <h3>📁 Sélectionnez votre fichier</h3>
230
- <p>Glissez-déposez votre fichier ici ou cliquez pour sélectionner</p>
231
- <input type="file" id="fileInput" accept=".txt">
232
- <button class="upload-btn" onclick="document.getElementById('fileInput').click()">
233
- Choisir le fichier
234
- </button>
235
- <button class="upload-btn" id="startBtn" onclick="startGeneration()" style="display: none;">
236
- 🚀 Démarrer la génération
237
- </button>
 
 
 
 
 
 
 
238
  </div>
239
 
240
- <div class="progress-section" id="progressSection">
241
- <h3>⏳ Génération en cours...</h3>
242
- <div class="progress-bar">
243
- <div class="progress-fill" id="progressFill"></div>
 
 
 
 
 
244
  </div>
245
- <div class="status-info">
246
- <div class="status-card">
247
- <h3>Progrès</h3>
248
- <p id="progressText">0 / 470</p>
 
 
249
  </div>
250
- <div class="status-card">
251
- <h3>Pourcentage</h3>
252
- <p id="percentageText">0%</p>
253
  </div>
254
- <div class="status-card">
255
- <h3>Statut</h3>
256
- <p id="statusText">En attente</p>
257
  </div>
258
- <div class="status-card">
259
- <h3>Heure de début</h3>
260
- <p id="startTimeText">-</p>
261
  </div>
262
  </div>
263
-
264
- <button class="download-btn" id="downloadBtn" onclick="downloadResults()">
265
- 📥 Télécharger les résultats
266
- </button>
 
 
 
 
 
 
 
 
 
267
  </div>
268
 
269
- <div class="tasks-section">
270
- <h3>📋 Tâches précédentes</h3>
271
- <div id="tasksList"></div>
 
272
  </div>
273
  </div>
274
 
275
- <div class="notification" id="notification"></div>
 
276
 
277
  <script>
278
  let currentTaskId = null;
@@ -284,16 +128,16 @@
284
 
285
  uploadSection.addEventListener('dragover', (e) => {
286
  e.preventDefault();
287
- uploadSection.classList.add('dragover');
288
  });
289
 
290
  uploadSection.addEventListener('dragleave', () => {
291
- uploadSection.classList.remove('dragover');
292
  });
293
 
294
  uploadSection.addEventListener('drop', (e) => {
295
  e.preventDefault();
296
- uploadSection.classList.remove('dragover');
297
 
298
  const files = e.dataTransfer.files;
299
  if (files.length > 0) {
@@ -307,7 +151,8 @@
307
  function handleFileSelect() {
308
  const file = fileInput.files[0];
309
  if (file) {
310
- document.getElementById('startBtn').style.display = 'inline-block';
 
311
  showNotification(`Fichier sélectionné: ${file.name}`, 'success');
312
  }
313
  }
@@ -332,7 +177,8 @@
332
  showNotification(data.error, 'error');
333
  } else {
334
  currentTaskId = data.task_id;
335
- document.getElementById('progressSection').style.display = 'block';
 
336
  startStatusPolling();
337
  showNotification('Génération démarrée!', 'success');
338
  }
@@ -354,7 +200,8 @@
354
  updateProgress(data);
355
  if (data.status === 'completed') {
356
  clearInterval(statusInterval);
357
- document.getElementById('downloadBtn').style.display = 'inline-block';
 
358
  showNotification('Génération terminée!', 'success');
359
  }
360
  })
@@ -384,14 +231,36 @@
384
  }
385
  }
386
 
 
 
 
 
 
 
 
387
  function showNotification(message, type) {
388
  const notification = document.getElementById('notification');
389
  notification.textContent = message;
390
- notification.className = `notification ${type}`;
391
- notification.classList.add('show');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
392
 
 
393
  setTimeout(() => {
394
- notification.classList.remove('show');
395
  }, 3000);
396
  }
397
 
@@ -404,17 +273,41 @@
404
 
405
  tasks.forEach(task => {
406
  const taskItem = document.createElement('div');
407
- taskItem.className = `task-item ${task.status}`;
 
 
 
 
408
  taskItem.innerHTML = `
409
- <div style="display: flex; justify-content: space-between; align-items: center;">
410
- <div>
411
- <strong>Tâche ${task.id.substring(0, 8)}...</strong><br>
412
- <small>Démarré: ${task.start_time} | Progrès: ${task.progress}/${task.total} (${task.percentage}%)</small>
 
 
 
 
 
 
 
 
 
 
 
 
413
  </div>
414
- <div>
415
  ${task.status === 'completed' ?
416
- `<button class="download-btn" style="display: inline-block; margin: 0;" onclick="window.location.href='/download/${task.id}'">Télécharger</button>` :
417
- `<span style="color: #667eea; font-weight: bold;">${task.status}</span>`
 
 
 
 
 
 
 
 
418
  }
419
  </div>
420
  </div>
 
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Générateur de Données Synthétiques</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script>
9
+ tailwind.config = {
10
+ theme: {
11
+ extend: {
12
+ animation: {
13
+ 'shimmer': 'shimmer 2s infinite',
14
+ 'bounce-in': 'bounceIn 0.5s ease-out',
15
+ 'slide-in': 'slideIn 0.3s ease-out'
16
+ },
17
+ keyframes: {
18
+ shimmer: {
19
+ '0%': { transform: 'translateX(-100%)' },
20
+ '100%': { transform: 'translateX(100%)' }
21
+ },
22
+ bounceIn: {
23
+ '0%': { transform: 'scale(0.3)', opacity: '0' },
24
+ '50%': { transform: 'scale(1.05)' },
25
+ '100%': { transform: 'scale(1)', opacity: '1' }
26
+ },
27
+ slideIn: {
28
+ '0%': { transform: 'translateX(100%)', opacity: '0' },
29
+ '100%': { transform: 'translateX(0)', opacity: '1' }
30
+ }
31
+ }
32
+ }
33
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  }
35
+ </script>
36
  </head>
37
+ <body class="min-h-screen bg-gradient-to-br from-indigo-500 via-purple-500 to-pink-500 flex items-center justify-center p-5">
38
+ <div class="bg-white rounded-3xl shadow-2xl p-8 max-w-4xl w-full backdrop-blur-sm">
39
+ <!-- Header -->
40
+ <div class="text-center mb-10">
41
+ <h1 class="text-4xl font-bold bg-gradient-to-r from-indigo-600 to-purple-600 bg-clip-text text-transparent mb-3">
42
+ 🤖 Générateur de Données Synthétiques
43
+ </h1>
44
+ <p class="text-gray-600 text-lg">Uploadez votre fichier pour générer 470 jeux de données synthétiques</p>
45
  </div>
46
 
47
+ <!-- Upload Section -->
48
+ <div id="uploadSection" class="border-3 border-dashed border-gray-300 rounded-2xl p-10 text-center mb-8 transition-all duration-300 hover:border-indigo-500 hover:bg-indigo-50/30">
49
+ <div class="space-y-4">
50
+ <h3 class="text-xl font-semibold text-gray-700">📁 Sélectionnez votre fichier</h3>
51
+ <p class="text-gray-500">Glissez-déposez votre fichier ici ou cliquez pour sélectionner</p>
52
+ <input type="file" id="fileInput" accept=".txt" class="hidden">
53
+ <div class="space-x-4">
54
+ <button onclick="document.getElementById('fileInput').click()"
55
+ class="bg-gradient-to-r from-indigo-500 to-purple-600 text-white px-8 py-3 rounded-full font-semibold transition-all duration-300 hover:scale-105 hover:shadow-lg">
56
+ Choisir le fichier
57
+ </button>
58
+ <button id="startBtn" onclick="startGeneration()"
59
+ class="hidden bg-gradient-to-r from-green-500 to-emerald-600 text-white px-8 py-3 rounded-full font-semibold transition-all duration-300 hover:scale-105 hover:shadow-lg">
60
+ 🚀 Démarrer la génération
61
+ </button>
62
+ </div>
63
+ </div>
64
  </div>
65
 
66
+ <!-- Progress Section -->
67
+ <div id="progressSection" class="hidden space-y-6">
68
+ <div class="text-center">
69
+ <h3 class="text-2xl font-bold text-gray-800 mb-4">⏳ Génération en cours...</h3>
70
+ <div class="w-full bg-gray-200 rounded-full h-6 overflow-hidden">
71
+ <div id="progressFill" class="h-full bg-gradient-to-r from-indigo-500 to-purple-600 transition-all duration-500 relative">
72
+ <div class="absolute inset-0 bg-gradient-to-r from-transparent via-white/30 to-transparent animate-shimmer"></div>
73
+ </div>
74
+ </div>
75
  </div>
76
+
77
+ <!-- Status Cards -->
78
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
79
+ <div class="bg-gradient-to-br from-blue-50 to-indigo-100 p-6 rounded-xl border-l-4 border-indigo-500">
80
+ <h4 class="font-semibold text-gray-700 mb-2">Progrès</h4>
81
+ <p id="progressText" class="text-2xl font-bold text-indigo-600">0 / 470</p>
82
  </div>
83
+ <div class="bg-gradient-to-br from-green-50 to-emerald-100 p-6 rounded-xl border-l-4 border-emerald-500">
84
+ <h4 class="font-semibold text-gray-700 mb-2">Pourcentage</h4>
85
+ <p id="percentageText" class="text-2xl font-bold text-emerald-600">0%</p>
86
  </div>
87
+ <div class="bg-gradient-to-br from-purple-50 to-violet-100 p-6 rounded-xl border-l-4 border-violet-500">
88
+ <h4 class="font-semibold text-gray-700 mb-2">Statut</h4>
89
+ <p id="statusText" class="text-lg font-bold text-violet-600">En attente</p>
90
  </div>
91
+ <div class="bg-gradient-to-br from-orange-50 to-amber-100 p-6 rounded-xl border-l-4 border-amber-500">
92
+ <h4 class="font-semibold text-gray-700 mb-2">Heure de début</h4>
93
+ <p id="startTimeText" class="text-lg font-bold text-amber-600">-</p>
94
  </div>
95
  </div>
96
+
97
+ <!-- Download Button -->
98
+ <div class="text-center">
99
+ <button id="downloadBtn" onclick="downloadResults()"
100
+ class="hidden bg-gradient-to-r from-green-500 to-emerald-600 text-white px-8 py-3 rounded-full font-semibold transition-all duration-300 hover:scale-105 hover:shadow-lg">
101
+ 📥 Télécharger les résultats
102
+ </button>
103
+ <!-- Bouton de téléchargement en cours -->
104
+ <button id="downloadProgressBtn" onclick="downloadCurrentResults()"
105
+ class="hidden bg-gradient-to-r from-yellow-500 to-orange-500 text-white px-8 py-3 rounded-full font-semibold transition-all duration-300 hover:scale-105 hover:shadow-lg">
106
+ 📥 Télécharger les données actuelles
107
+ </button>
108
+ </div>
109
  </div>
110
 
111
+ <!-- Tasks Section -->
112
+ <div class="mt-10 pt-8 border-t-2 border-gray-200">
113
+ <h3 class="text-xl font-bold text-gray-800 mb-6">📋 Tâches précédentes</h3>
114
+ <div id="tasksList" class="space-y-4"></div>
115
  </div>
116
  </div>
117
 
118
+ <!-- Notification -->
119
+ <div id="notification" class="fixed top-5 right-5 px-6 py-4 rounded-xl text-white font-semibold transform translate-x-full transition-transform duration-300 z-50"></div>
120
 
121
  <script>
122
  let currentTaskId = null;
 
128
 
129
  uploadSection.addEventListener('dragover', (e) => {
130
  e.preventDefault();
131
+ uploadSection.classList.add('border-indigo-500', 'bg-indigo-50/50');
132
  });
133
 
134
  uploadSection.addEventListener('dragleave', () => {
135
+ uploadSection.classList.remove('border-indigo-500', 'bg-indigo-50/50');
136
  });
137
 
138
  uploadSection.addEventListener('drop', (e) => {
139
  e.preventDefault();
140
+ uploadSection.classList.remove('border-indigo-500', 'bg-indigo-50/50');
141
 
142
  const files = e.dataTransfer.files;
143
  if (files.length > 0) {
 
151
  function handleFileSelect() {
152
  const file = fileInput.files[0];
153
  if (file) {
154
+ document.getElementById('startBtn').classList.remove('hidden');
155
+ document.getElementById('startBtn').classList.add('animate-bounce-in');
156
  showNotification(`Fichier sélectionné: ${file.name}`, 'success');
157
  }
158
  }
 
177
  showNotification(data.error, 'error');
178
  } else {
179
  currentTaskId = data.task_id;
180
+ document.getElementById('progressSection').classList.remove('hidden');
181
+ document.getElementById('downloadProgressBtn').classList.remove('hidden');
182
  startStatusPolling();
183
  showNotification('Génération démarrée!', 'success');
184
  }
 
200
  updateProgress(data);
201
  if (data.status === 'completed') {
202
  clearInterval(statusInterval);
203
+ document.getElementById('downloadBtn').classList.remove('hidden');
204
+ document.getElementById('downloadProgressBtn').classList.add('hidden');
205
  showNotification('Génération terminée!', 'success');
206
  }
207
  })
 
231
  }
232
  }
233
 
234
+ function downloadCurrentResults() {
235
+ if (currentTaskId) {
236
+ window.location.href = `/download/${currentTaskId}?partial=true`;
237
+ showNotification('Téléchargement des données actuelles...', 'success');
238
+ }
239
+ }
240
+
241
  function showNotification(message, type) {
242
  const notification = document.getElementById('notification');
243
  notification.textContent = message;
244
+
245
+ // Reset classes
246
+ notification.className = 'fixed top-5 right-5 px-6 py-4 rounded-xl text-white font-semibold transform translate-x-full transition-transform duration-300 z-50';
247
+
248
+ // Add type-specific classes
249
+ if (type === 'success') {
250
+ notification.classList.add('bg-gradient-to-r', 'from-green-500', 'to-emerald-600');
251
+ } else if (type === 'error') {
252
+ notification.classList.add('bg-gradient-to-r', 'from-red-500', 'to-rose-600');
253
+ }
254
+
255
+ // Show notification
256
+ setTimeout(() => {
257
+ notification.classList.remove('translate-x-full');
258
+ notification.classList.add('animate-slide-in');
259
+ }, 100);
260
 
261
+ // Hide notification after 3 seconds
262
  setTimeout(() => {
263
+ notification.classList.add('translate-x-full');
264
  }, 3000);
265
  }
266
 
 
273
 
274
  tasks.forEach(task => {
275
  const taskItem = document.createElement('div');
276
+ taskItem.className = `bg-gradient-to-r from-gray-50 to-gray-100 p-6 rounded-xl border-l-4 ${
277
+ task.status === 'completed' ? 'border-green-500' :
278
+ task.status === 'running' ? 'border-blue-500' : 'border-gray-400'
279
+ } transition-all duration-300 hover:shadow-md`;
280
+
281
  taskItem.innerHTML = `
282
+ <div class="flex justify-between items-center">
283
+ <div class="space-y-2">
284
+ <div class="flex items-center space-x-3">
285
+ <span class="font-bold text-gray-800">Tâche ${task.id.substring(0, 8)}...</span>
286
+ <span class="px-3 py-1 rounded-full text-sm font-medium ${
287
+ task.status === 'completed' ? 'bg-green-100 text-green-800' :
288
+ task.status === 'running' ? 'bg-blue-100 text-blue-800' : 'bg-gray-100 text-gray-800'
289
+ }">
290
+ ${task.status === 'completed' ? 'Terminé' :
291
+ task.status === 'running' ? 'En cours' : task.status}
292
+ </span>
293
+ </div>
294
+ <div class="text-sm text-gray-600">
295
+ <span>Démarré: ${task.start_time}</span> |
296
+ <span>Progrès: ${task.progress}/${task.total} (${task.percentage}%)</span>
297
+ </div>
298
  </div>
299
+ <div class="space-x-2">
300
  ${task.status === 'completed' ?
301
+ `<button onclick="window.location.href='/download/${task.id}'"
302
+ class="bg-gradient-to-r from-green-500 to-emerald-600 text-white px-4 py-2 rounded-lg font-medium transition-all duration-300 hover:scale-105">
303
+ Télécharger
304
+ </button>` :
305
+ task.status === 'running' ?
306
+ `<button onclick="window.location.href='/download/${task.id}?partial=true'"
307
+ class="bg-gradient-to-r from-yellow-500 to-orange-500 text-white px-4 py-2 rounded-lg font-medium transition-all duration-300 hover:scale-105">
308
+ Télécharger actuel
309
+ </button>` :
310
+ `<span class="text-gray-500 font-medium">${task.status}</span>`
311
  }
312
  </div>
313
  </div>