Docfile commited on
Commit
9a3cea8
1 Parent(s): 93b0af7

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +208 -196
templates/index.html CHANGED
@@ -3,235 +3,247 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Application de Reconnaissance Faciale</title>
7
- <!-- Tailwind CSS -->
8
  <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
9
- <!-- Font Awesome (pour les icônes) -->
10
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css">
 
11
  <style>
12
- /* Styles personnalisés (si nécessaire) */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  .preview-image {
 
 
 
 
 
14
  background-size: cover;
15
  background-position: center;
16
- min-height: 150px;
 
 
 
 
17
  }
18
 
19
- .github-link {
20
  position: fixed;
21
- bottom: 20px;
22
- right: 20px;
23
- padding: 10px;
24
- background-color: #333;
25
- color: white;
26
- border-radius: 5px;
27
- text-decoration: none;
28
- display: flex;
29
  align-items: center;
30
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
 
 
 
 
 
 
 
 
 
 
31
  }
32
 
33
- .github-link i {
34
- margin-right: 8px;
35
- font-size: 20px;
 
36
  }
37
 
38
- .github-link:hover {
39
- background-color: #555;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  }
41
  </style>
42
  </head>
43
- <body class="bg-gray-100 font-sans">
44
- <div class="container mx-auto p-4">
45
- <h1 class="text-4xl font-bold text-center text-blue-700 mb-8">
46
- <i class="fas fa-user-check text-5xl mr-3"></i>
47
- Reconnaissance et Comparaison Faciale
48
- </h1>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
 
50
  <div class="grid md:grid-cols-2 gap-8">
51
- <!-- Section de sélection d'images -->
52
- <div class="bg-white p-6 rounded-lg shadow-lg">
53
- <h2 class="text-2xl font-semibold mb-4 text-gray-700">
54
- <i class="fas fa-images text-blue-500 mr-2"></i>
55
- Sélectionner des images
56
  </h2>
57
- <input type="file" id="imageUpload" accept="image/*" class="mb-4 hidden">
58
- <label for="imageUpload" class="cursor-pointer bg-blue-500 hover:bg-blue-600 text-white font-bold py-3 px-6 rounded-lg inline-flex items-center transition duration-200 ease-in-out">
59
- <i class="fas fa-upload mr-2"></i>
60
- Choisir un fichier
61
- </label>
62
-
63
- <button id="cameraButton" class="bg-green-500 hover:bg-green-600 text-white font-bold py-3 px-6 rounded-lg ml-4 inline-flex items-center transition duration-200 ease-in-out">
64
- <i class="fas fa-camera mr-2"></i>
65
- Utiliser la caméra
66
- </button>
67
-
68
- <video id="videoFeed" width="320" height="240" autoplay class="hidden mt-4 rounded-lg"></video>
69
- <canvas id="canvas" width="320" height="240" class="hidden"></canvas>
70
-
71
- <!-- Prévisualisation des images -->
72
- <div class="grid grid-cols-2 gap-4 mt-6">
73
- <div id="imagePreview1" class="w-full aspect-w-1 aspect-h-1 rounded-lg overflow-hidden preview-image"></div>
74
- <div id="imagePreview2" class="w-full aspect-w-1 aspect-h-1 rounded-lg overflow-hidden preview-image"></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  </div>
76
  </div>
77
 
78
  <!-- Section des résultats -->
79
- <div class="bg-white p-6 rounded-lg shadow-lg">
80
- <h2 class="text-2xl font-semibold mb-4 text-gray-700">
81
- <i class="fas fa-poll-h text-blue-500 mr-2"></i>
82
- Résultats de la comparaison
83
  </h2>
84
- <div id="results" class="text-center">
85
- <p class="text-gray-600">Veuillez sélectionner des images ou utiliser la caméra pour commencer.</p>
 
 
 
 
86
  </div>
87
- <button id="compareButton" class="hidden bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded mt-4">
88
- Comparer les visages
 
 
89
  </button>
90
  </div>
91
  </div>
92
- </div>
93
-
94
- <!-- Lien GitHub -->
95
- <a href="https://github.com/Yusufibin" target="_blank" class="github-link">
96
- <i class="fab fa-github"></i>
97
- <span>Yusufibin</span>
 
 
 
98
  </a>
99
 
100
  <script>
101
- const imageUpload = document.getElementById('imageUpload');
102
- const cameraButton = document.getElementById('cameraButton');
103
- const videoFeed = document.getElementById('videoFeed');
104
- const canvas = document.getElementById('canvas');
105
- const imagePreview1 = document.getElementById('imagePreview1');
106
- const imagePreview2 = document.getElementById('imagePreview2');
107
- const resultsDiv = document.getElementById('results');
108
- const compareButton = document.getElementById('compareButton');
109
- const API_BASE_URL = 'http://127.0.0.1:5000'; // URL de base de ton API Flask
110
-
111
- let usingCamera = false;
112
- let currentImage = 1; // 1 or 2 pour suivre quelle image prévisualiser
113
-
114
- // Gestionnaire pour le téléchargement de fichiers
115
- imageUpload.addEventListener('change', async (event) => {
116
- const file = event.target.files[0];
117
- if (file) {
118
- const reader = new FileReader();
119
- reader.onload = (e) => {
120
- if (currentImage === 1) {
121
- imagePreview1.style.backgroundImage = `url(${e.target.result})`;
122
- currentImage = 2;
123
- } else {
124
- imagePreview2.style.backgroundImage = `url(${e.target.result})`;
125
- currentImage = 1;
126
- }
127
- compareButton.classList.remove('hidden'); // Affiche le bouton de comparaison
128
- };
129
- reader.readAsDataURL(file);
130
- }
131
- });
132
-
133
- // Gestionnaire pour le bouton de la caméra
134
- cameraButton.addEventListener('click', async () => {
135
- usingCamera = !usingCamera;
136
-
137
- if (usingCamera) {
138
- cameraButton.textContent = 'Arrêter la caméra';
139
- try {
140
- const stream = await navigator.mediaDevices.getUserMedia({ video: true });
141
- videoFeed.srcObject = stream;
142
- videoFeed.classList.remove('hidden');
143
- } catch (err) {
144
- console.error("Erreur lors de l'accès à la caméra :", err);
145
- }
146
- } else {
147
- cameraButton.textContent = 'Utiliser la caméra';
148
- const tracks = videoFeed.srcObject.getTracks();
149
- tracks.forEach(track => track.stop());
150
- videoFeed.classList.add('hidden');
151
- }
152
- });
153
-
154
- // Capture d'image à partir de la caméra
155
- function captureImageFromCamera() {
156
- const context = canvas.getContext('2d');
157
- context.drawImage(videoFeed, 0, 0, canvas.width, canvas.height);
158
- const imageDataURL = canvas.toDataURL('image/png');
159
-
160
- if (currentImage === 1) {
161
- imagePreview1.style.backgroundImage = `url(${imageDataURL})`;
162
- currentImage = 2;
163
- } else {
164
- imagePreview2.style.backgroundImage = `url(${imageDataURL})`;
165
- currentImage = 1;
166
- }
167
- compareButton.classList.remove('hidden'); // Affiche le bouton de comparaison
168
- }
169
-
170
- // Gestionnaire pour le bouton de comparaison
171
- compareButton.addEventListener('click', () => {
172
- if (imagePreview1.style.backgroundImage && imagePreview2.style.backgroundImage) {
173
- const formData = new FormData();
174
- const imageData1 = dataURLtoBlob(imagePreview1.style.backgroundImage.slice(5, -2));
175
- const imageData2 = dataURLtoBlob(imagePreview2.style.backgroundImage.slice(5, -2));
176
-
177
- formData.append('image1', imageData1, 'image1.png');
178
- formData.append('image2', imageData2, 'image2.png');
179
-
180
- fetch(`${API_BASE_URL}/verify`, {
181
- method: 'POST',
182
- body: formData,
183
- })
184
- .then(response => response.json())
185
- .then(data => {
186
- displayResults(data);
187
- })
188
- .catch(error => {
189
- console.error('Erreur lors de la comparaison des visages:', error);
190
- resultsDiv.innerHTML = `<p>Erreur lors de la comparaison.</p>`;
191
- });
192
- } else {
193
- alert('Veuillez télécharger deux images pour la comparaison.');
194
- }
195
- });
196
-
197
- // Fonction pour convertir une URL de données en Blob
198
- function dataURLtoBlob(dataURL) {
199
- const parts = dataURL.split(';base64,');
200
- const contentType = parts[0].split(':')[1];
201
- const raw = window.atob(parts[1]);
202
- const rawLength = raw.length;
203
- const uInt8Array = new Uint8Array(rawLength);
204
-
205
- for (let i = 0; i < rawLength; ++i) {
206
- uInt8Array[i] = raw.charCodeAt(i);
207
- }
208
-
209
- return new Blob([uInt8Array], { type: contentType });
210
- }
211
-
212
- // Fonction pour afficher les résultats de la comparaison
213
- function displayResults(data) {
214
- let resultHTML = '';
215
-
216
- if (data.error) {
217
- resultHTML = `<p class="text-red-600">${data.error}</p>`;
218
- } else {
219
- const similarity = data.verified ? 'Visages similaires' : 'Visages différents';
220
- resultHTML += `<p class="text-lg ${data.verified ? 'text-green-600' : 'text-red-600'}">${similarity}</p>`;
221
-
222
- if (data.distance !== undefined && data.threshold !== undefined) {
223
- resultHTML += `<p class="mt-2">Distance : ${data.distance.toFixed(4)}</p>`;
224
- resultHTML += `<p>Seuil de similarité : ${data.threshold.toFixed(4)}</p>`;
225
- }
226
-
227
- if (data.image1_url && data.image2_url) {
228
- resultHTML += `<img src="${API_BASE_URL}/${data.image1_url}" alt="Image 1" class="w-32 h-32 mt-4 rounded-lg">`;
229
- resultHTML += `<img src="${API_BASE_URL}/${data.image2_url}" alt="Image 2" class="w-32 h-32 mt-4 rounded-lg">`;
230
- }
231
- }
232
-
233
- resultsDiv.innerHTML = resultHTML;
234
  }
 
 
 
 
 
 
 
 
 
 
 
235
  </script>
236
  </body>
237
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Système de Reconnaissance Faciale Pro</title>
 
7
  <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
 
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css">
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css">
10
  <style>
11
+ @keyframes pulse-border {
12
+ 0% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.7); }
13
+ 70% { box-shadow: 0 0 0 10px rgba(59, 130, 246, 0); }
14
+ 100% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0); }
15
+ }
16
+
17
+ .preview-container {
18
+ position: relative;
19
+ aspect-ratio: 1;
20
+ background: #f8fafc;
21
+ border-radius: 1rem;
22
+ overflow: hidden;
23
+ transition: all 0.3s ease;
24
+ }
25
+
26
  .preview-image {
27
+ position: absolute;
28
+ top: 0;
29
+ left: 0;
30
+ width: 100%;
31
+ height: 100%;
32
  background-size: cover;
33
  background-position: center;
34
+ transition: transform 0.3s ease;
35
+ }
36
+
37
+ .preview-container:hover .preview-image {
38
+ transform: scale(1.05);
39
  }
40
 
41
+ .loading-overlay {
42
  position: fixed;
43
+ top: 0;
44
+ left: 0;
45
+ width: 100%;
46
+ height: 100%;
47
+ background: rgba(0, 0, 0, 0.7);
48
+ display: none;
49
+ justify-content: center;
 
50
  align-items: center;
51
+ z-index: 1000;
52
+ }
53
+
54
+ .progress-ring {
55
+ animation: spin 2s linear infinite;
56
+ width: 50px;
57
+ height: 50px;
58
+ }
59
+
60
+ @keyframes spin {
61
+ 100% { transform: rotate(360deg); }
62
  }
63
 
64
+ .btn-primary {
65
+ background: linear-gradient(135deg, #4f46e5, #3b82f6);
66
+ transition: all 0.3s ease;
67
+ animation: pulse-border 2s infinite;
68
  }
69
 
70
+ .btn-primary:hover {
71
+ transform: translateY(-2px);
72
+ box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
73
+ }
74
+
75
+ .result-card {
76
+ transition: all 0.3s ease;
77
+ transform-origin: center;
78
+ }
79
+
80
+ .result-card.show {
81
+ animation: bounceIn 0.6s;
82
+ }
83
+
84
+ .camera-feed {
85
+ border-radius: 1rem;
86
+ transform: scaleX(-1);
87
+ transition: all 0.3s ease;
88
+ }
89
+
90
+ .github-corner {
91
+ position: fixed;
92
+ top: 0;
93
+ right: 0;
94
+ width: 80px;
95
+ height: 80px;
96
+ transition: transform 0.3s ease;
97
+ }
98
+
99
+ .github-corner:hover {
100
+ transform: scale(1.1);
101
  }
102
  </style>
103
  </head>
104
+ <body class="bg-gradient-to-br from-gray-100 to-gray-200 min-h-screen font-sans">
105
+ <div class="loading-overlay">
106
+ <svg class="progress-ring text-blue-500" viewBox="0 0 50 50">
107
+ <circle cx="25" cy="25" r="20" fill="none" stroke="currentColor" stroke-width="5" stroke-dasharray="80, 200"/>
108
+ </svg>
109
+ </div>
110
+
111
+ <nav class="bg-white shadow-lg">
112
+ <div class="container mx-auto px-6 py-4">
113
+ <div class="flex items-center justify-between">
114
+ <div class="flex items-center">
115
+ <i class="fas fa-brain text-4xl text-blue-600 mr-3"></i>
116
+ <h1 class="text-2xl font-bold text-gray-800">FaceAI Pro</h1>
117
+ </div>
118
+ <div class="flex items-center space-x-4">
119
+ <button class="text-gray-600 hover:text-blue-600 transition-colors">
120
+ <i class="fas fa-question-circle text-xl"></i>
121
+ </button>
122
+ <button class="text-gray-600 hover:text-blue-600 transition-colors">
123
+ <i class="fas fa-cog text-xl"></i>
124
+ </button>
125
+ </div>
126
+ </div>
127
+ </div>
128
+ </nav>
129
 
130
+ <main class="container mx-auto p-6">
131
  <div class="grid md:grid-cols-2 gap-8">
132
+ <!-- Section de capture -->
133
+ <div class="bg-white rounded-xl shadow-xl p-6 animate__animated animate__fadeInLeft">
134
+ <h2 class="text-2xl font-bold text-gray-800 mb-6 flex items-center">
135
+ <i class="fas fa-camera text-blue-600 mr-3"></i>
136
+ Capture d'Images
137
  </h2>
138
+
139
+ <div class="space-y-4">
140
+ <div class="flex space-x-4">
141
+ <button id="uploadBtn" class="btn-primary text-white px-6 py-3 rounded-lg flex items-center">
142
+ <i class="fas fa-upload mr-2"></i>
143
+ Importer
144
+ </button>
145
+ <button id="cameraBtn" class="bg-green-500 hover:bg-green-600 text-white px-6 py-3 rounded-lg flex items-center transition-all">
146
+ <i class="fas fa-video mr-2"></i>
147
+ Caméra
148
+ </button>
149
+ </div>
150
+
151
+ <input type="file" id="fileInput" class="hidden" accept="image/*">
152
+ <video id="video" class="camera-feed w-full hidden" autoplay></video>
153
+
154
+ <div class="grid grid-cols-2 gap-4">
155
+ <div class="preview-container shadow-lg">
156
+ <div id="preview1" class="preview-image"></div>
157
+ <div class="absolute bottom-2 right-2">
158
+ <button class="bg-red-500 text-white p-2 rounded-full opacity-0 transition-opacity hover:opacity-100">
159
+ <i class="fas fa-times"></i>
160
+ </button>
161
+ </div>
162
+ </div>
163
+ <div class="preview-container shadow-lg">
164
+ <div id="preview2" class="preview-image"></div>
165
+ <div class="absolute bottom-2 right-2">
166
+ <button class="bg-red-500 text-white p-2 rounded-full opacity-0 transition-opacity hover:opacity-100">
167
+ <i class="fas fa-times"></i>
168
+ </button>
169
+ </div>
170
+ </div>
171
+ </div>
172
  </div>
173
  </div>
174
 
175
  <!-- Section des résultats -->
176
+ <div class="bg-white rounded-xl shadow-xl p-6 animate__animated animate__fadeInRight">
177
+ <h2 class="text-2xl font-bold text-gray-800 mb-6 flex items-center">
178
+ <i class="fas fa-chart-bar text-blue-600 mr-3"></i>
179
+ Résultats
180
  </h2>
181
+
182
+ <div id="results" class="result-card p-4 rounded-lg bg-gray-50">
183
+ <div class="text-center text-gray-500">
184
+ <i class="fas fa-upload text-4xl mb-3"></i>
185
+ <p>Importez ou capturez deux images pour démarrer l'analyse</p>
186
+ </div>
187
  </div>
188
+
189
+ <button id="compareBtn" class="btn-primary w-full mt-6 py-3 rounded-lg text-white font-semibold hidden">
190
+ <i class="fas fa-sync-alt mr-2"></i>
191
+ Lancer la comparaison
192
  </button>
193
  </div>
194
  </div>
195
+ </main>
196
+
197
+ <!-- GitHub Corner -->
198
+ <a href="https://github.com/Yusufibin" class="github-corner" target="_blank">
199
+ <svg width="80" height="80" viewBox="0 0 250 250" style="fill:#151513; color:#fff; position: absolute; top: 0; border: 0; right: 0;">
200
+ <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
201
+ <path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>
202
+ <path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path>
203
+ </svg>
204
  </a>
205
 
206
  <script>
207
+ // Le code JavaScript reste similaire mais avec des améliorations pour les animations
208
+ // et la gestion des états de l'interface...
209
+
210
+ // Exemple d'amélioration pour l'affichage des résultats
211
+ function showResults(data) {
212
+ const resultsDiv = document.getElementById('results');
213
+ resultsDiv.classList.remove('show');
214
+
215
+ setTimeout(() => {
216
+ resultsDiv.innerHTML = `
217
+ <div class="text-center">
218
+ <div class="text-4xl mb-4 ${data.verified ? 'text-green-500' : 'text-red-500'}">
219
+ <i class="fas ${data.verified ? 'fa-check-circle' : 'fa-times-circle'}"></i>
220
+ </div>
221
+ <h3 class="text-xl font-bold mb-2">
222
+ ${data.verified ? 'Visages identiques' : 'Visages différents'}
223
+ </h3>
224
+ <div class="space-y-2">
225
+ <p>Similarité: ${(data.similarity * 100).toFixed(1)}%</p>
226
+ <div class="w-full bg-gray-200 rounded-full h-2.5">
227
+ <div class="bg-blue-600 h-2.5 rounded-full"
228
+ style="width: ${data.similarity * 100}%"></div>
229
+ </div>
230
+ </div>
231
+ </div>
232
+ `;
233
+ resultsDiv.classList.add('show');
234
+ }, 300);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
  }
236
+
237
+ // Ajout des animations pour le chargement
238
+ function showLoading() {
239
+ document.querySelector('.loading-overlay').style.display = 'flex';
240
+ }
241
+
242
+ function hideLoading() {
243
+ document.querySelector('.loading-overlay').style.display = 'none';
244
+ }
245
+
246
+ // Le reste du code JavaScript original avec les gestionnaires d'événements...
247
  </script>
248
  </body>
249
  </html>