Docfile commited on
Commit
f9aefa0
·
verified ·
1 Parent(s): f9a4061

Create templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +435 -0
templates/index.html ADDED
@@ -0,0 +1,435 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 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;
279
+ let statusInterval = null;
280
+
281
+ // Gestion du drag & drop
282
+ const uploadSection = document.getElementById('uploadSection');
283
+ const fileInput = document.getElementById('fileInput');
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) {
300
+ fileInput.files = files;
301
+ handleFileSelect();
302
+ }
303
+ });
304
+
305
+ fileInput.addEventListener('change', handleFileSelect);
306
+
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
+ }
314
+
315
+ function startGeneration() {
316
+ const file = fileInput.files[0];
317
+ if (!file) {
318
+ showNotification('Veuillez sélectionner un fichier', 'error');
319
+ return;
320
+ }
321
+
322
+ const formData = new FormData();
323
+ formData.append('file', file);
324
+
325
+ fetch('/upload', {
326
+ method: 'POST',
327
+ body: formData
328
+ })
329
+ .then(response => response.json())
330
+ .then(data => {
331
+ if (data.error) {
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
+ }
339
+ })
340
+ .catch(error => {
341
+ showNotification('Erreur lors du démarrage', 'error');
342
+ console.error('Error:', error);
343
+ });
344
+ }
345
+
346
+ function startStatusPolling() {
347
+ if (statusInterval) clearInterval(statusInterval);
348
+
349
+ statusInterval = setInterval(() => {
350
+ if (currentTaskId) {
351
+ fetch(`/status/${currentTaskId}`)
352
+ .then(response => response.json())
353
+ .then(data => {
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
+ })
361
+ .catch(console.error);
362
+ }
363
+ }, 2000);
364
+ }
365
+
366
+ function updateProgress(data) {
367
+ const progressFill = document.getElementById('progressFill');
368
+ const progressText = document.getElementById('progressText');
369
+ const percentageText = document.getElementById('percentageText');
370
+ const statusText = document.getElementById('statusText');
371
+ const startTimeText = document.getElementById('startTimeText');
372
+
373
+ progressFill.style.width = `${data.percentage}%`;
374
+ progressText.textContent = `${data.progress} / ${data.total}`;
375
+ percentageText.textContent = `${data.percentage}%`;
376
+ statusText.textContent = data.status === 'running' ? 'En cours' :
377
+ data.status === 'completed' ? 'Terminé' : data.status;
378
+ startTimeText.textContent = data.start_time;
379
+ }
380
+
381
+ function downloadResults() {
382
+ if (currentTaskId) {
383
+ window.location.href = `/download/${currentTaskId}`;
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
+
398
+ function loadTasks() {
399
+ fetch('/tasks')
400
+ .then(response => response.json())
401
+ .then(tasks => {
402
+ const tasksList = document.getElementById('tasksList');
403
+ tasksList.innerHTML = '';
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>
421
+ `;
422
+ tasksList.appendChild(taskItem);
423
+ });
424
+ })
425
+ .catch(console.error);
426
+ }
427
+
428
+ // Charger les tâches au démarrage
429
+ loadTasks();
430
+
431
+ // Recharger les tâches toutes les 30 secondes
432
+ setInterval(loadTasks, 30000);
433
+ </script>
434
+ </body>
435
+ </html>