Docfile commited on
Commit
d60a63a
·
verified ·
1 Parent(s): a8f80bb

Create index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +379 -0
templates/index.html ADDED
@@ -0,0 +1,379 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Mariam M-0 | Solution Mathématique</title>
7
+ <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
8
+ <script>
9
+ window.MathJax = {
10
+ tex: {
11
+ inlineMath: [['$', '$'], ['\\(', '\\)']],
12
+ displayMath: [['$$', '$$'], ['\\[', '\\]']],
13
+ processEscapes: true,
14
+ packages: ['base', 'ams', 'noerrors', 'noundefined']
15
+ },
16
+ options: {
17
+ ignoreHtmlClass: 'tex2jax_ignore',
18
+ processHtmlClass: 'tex2jax_process'
19
+ },
20
+ svg: {
21
+ fontCache: 'global'
22
+ }
23
+ };
24
+ </script>
25
+ <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
26
+ <style>
27
+ @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap');
28
+
29
+ body {
30
+ font-family: 'Space Grotesk', sans-serif;
31
+ background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
32
+ min-height: 100vh;
33
+ }
34
+
35
+ .glass-card {
36
+ background: rgba(255, 255, 255, 0.95);
37
+ backdrop-filter: blur(10px);
38
+ border: 1px solid rgba(255, 255, 255, 0.2);
39
+ box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.2);
40
+ }
41
+
42
+ .uploadArea {
43
+ background: white;
44
+ border: 2px dashed #2a5298;
45
+ transition: all 0.3s ease;
46
+ }
47
+
48
+ .uploadArea:hover {
49
+ border-color: #1e3c72;
50
+ background: rgba(42, 82, 152, 0.05);
51
+ }
52
+
53
+ .neon-button {
54
+ background: linear-gradient(90deg, #1e3c72 0%, #2a5298 100%);
55
+ box-shadow: 0 4px 15px rgba(42, 82, 152, 0.3);
56
+ transition: all 0.3s ease;
57
+ }
58
+
59
+ .neon-button:hover {
60
+ box-shadow: 0 6px 20px rgba(42, 82, 152, 0.5);
61
+ transform: translateY(-2px);
62
+ }
63
+
64
+ .loader {
65
+ width: 48px;
66
+ height: 48px;
67
+ border: 3px solid #1e3c72;
68
+ border-bottom-color: transparent;
69
+ border-radius: 50%;
70
+ display: inline-block;
71
+ box-sizing: border-box;
72
+ animation: rotation 1s linear infinite;
73
+ }
74
+
75
+ @keyframes rotation {
76
+ 0% { transform: rotate(0deg); }
77
+ 100% { transform: rotate(360deg); }
78
+ }
79
+
80
+ .thought-box {
81
+ transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
82
+ max-height: 0;
83
+ overflow: hidden;
84
+ }
85
+
86
+ .thought-box.open {
87
+ max-height: 1000px;
88
+ }
89
+
90
+ .glow {
91
+ animation: glow 2s ease-in-out infinite alternate;
92
+ }
93
+
94
+ @keyframes glow {
95
+ from { text-shadow: 0 0 10px #fff, 0 0 20px #1e3c72; }
96
+ to { text-shadow: 0 0 15px #fff, 0 0 25px #2a5298; }
97
+ }
98
+
99
+ .preview-container {
100
+ display: flex;
101
+ justify-content: center;
102
+ align-items: center;
103
+ margin-top: 20px;
104
+ }
105
+
106
+ .preview-image {
107
+ max-width: 300px;
108
+ max-height: 300px;
109
+ border-radius: 8px;
110
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
111
+ }
112
+
113
+ #thoughtsContent, #answerContent {
114
+ max-height: 500px;
115
+ overflow-y: auto;
116
+ width: 100%;
117
+ color: #1e3c72;
118
+ }
119
+
120
+ .timestamp {
121
+ color: #2a5298;
122
+ margin-left: 10px;
123
+ font-size: 0.9em;
124
+ }
125
+
126
+ .container {
127
+ width: 95% !important;
128
+ max-width: none !important;
129
+ }
130
+ </style>
131
+ </head>
132
+ <body class="p-4">
133
+ <div class="container mx-auto">
134
+ <div class="glass-card rounded-3xl p-8">
135
+ <div class="text-center mb-12">
136
+ <h1 class="text-4xl font-bold text-blue-900 glow mb-4">Mariam M-0</h1>
137
+ <p class="text-blue-800 text-lg">Solution Mathématique Intelligente</p>
138
+ </div>
139
+
140
+ <form id="problemForm" class="space-y-8" enctype="multipart/form-data">
141
+ <div class="relative">
142
+ <div class="uploadArea rounded-2xl p-12 text-center cursor-pointer">
143
+ <input type="file" id="imageInput" name="image" accept="image/*" class="absolute inset-0 w-full h-full opacity-0 cursor-pointer">
144
+ <div class="space-y-4">
145
+ <div class="w-20 h-20 mx-auto border-2 border-blue-700 rounded-full flex items-center justify-center">
146
+ <svg class="w-10 h-10 text-blue-700" fill="none" stroke="currentColor" viewBox="0 0 24 24">
147
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
148
+ </svg>
149
+ </div>
150
+ <div class="text-blue-800 text-lg font-medium">Déposez votre image ici</div>
151
+ <div class="text-blue-600/60 text-sm">ou cliquez pour sélectionner</div>
152
+ </div>
153
+ </div>
154
+ <div id="imagePreview" class="preview-container hidden">
155
+ <img id="previewImage" src="#" alt="Prévisualisation de l'image" class="preview-image">
156
+ </div>
157
+ </div>
158
+
159
+ <button type="submit" class="neon-button w-full py-4 rounded-xl text-white font-medium text-lg">
160
+ Résoudre le problème
161
+ </button>
162
+ </form>
163
+
164
+ <div id="loader" class="hidden mt-12">
165
+ <div class="flex flex-col items-center justify-center space-y-4">
166
+ <span class="loader"></span>
167
+ <div class="text-blue-800 text-lg">Analyse en cours...</div>
168
+ </div>
169
+ </div>
170
+
171
+ <div id="solution" class="hidden mt-12 space-y-8">
172
+ <div class="glass-card rounded-2xl p-6 w-full">
173
+ <button id="thoughtsToggle" class="w-full flex justify-between items-center text-left text-lg font-medium text-blue-900 hover:text-blue-700 transition-colors">
174
+ <div class="flex items-center">
175
+ <span>Processus de Réflexion</span>
176
+ <span id="timestamp" class="timestamp"></span>
177
+ </div>
178
+ <svg class="w-6 h-6 transform transition-transform duration-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
179
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
180
+ </svg>
181
+ </button>
182
+ <div id="thoughtsBox" class="thought-box">
183
+ <div id="thoughtsContent" class="prose max-w-none mt-4"></div>
184
+ </div>
185
+ </div>
186
+
187
+ <div class="glass-card rounded-2xl p-8 w-full">
188
+ <h3 class="text-2xl font-bold text-blue-900 mb-6">Solution</h3>
189
+ <div id="answerContent" class="prose max-w-none"></div>
190
+ </div>
191
+ </div>
192
+ </div>
193
+ </div>
194
+
195
+ <script>
196
+ // [Le JavaScript reste identique au template original]
197
+ document.addEventListener('DOMContentLoaded', () => {
198
+ const form = document.getElementById('problemForm');
199
+ const imageInput = document.getElementById('imageInput');
200
+ const loader = document.getElementById('loader');
201
+ const solutionDiv = document.getElementById('solution');
202
+ const thoughtsContent = document.getElementById('thoughtsContent');
203
+ const answerContent = document.getElementById('answerContent');
204
+ const thoughtsToggle = document.getElementById('thoughtsToggle');
205
+ const thoughtsBox = document.getElementById('thoughtsBox');
206
+ const imagePreview = document.getElementById('imagePreview');
207
+ const previewImage = document.getElementById('previewImage');
208
+ const timestamp = document.getElementById('timestamp');
209
+
210
+ let startTime = null;
211
+ let timerInterval = null;
212
+
213
+ function updateTimestamp() {
214
+ if (startTime) {
215
+ const elapsed = Math.floor((Date.now() - startTime) / 1000);
216
+ timestamp.textContent = elapsed + "s";
217
+ }
218
+ }
219
+
220
+ function startTimer() {
221
+ startTime = Date.now();
222
+ timerInterval = setInterval(updateTimestamp, 1000);
223
+ updateTimestamp();
224
+ }
225
+
226
+ function stopTimer() {
227
+ if (timerInterval) {
228
+ clearInterval(timerInterval);
229
+ timerInterval = null;
230
+ }
231
+ startTime = null;
232
+ timestamp.textContent = "";
233
+ }
234
+
235
+ thoughtsToggle.addEventListener('click', () => {
236
+ thoughtsBox.classList.toggle('open');
237
+ thoughtsToggle.querySelector('svg').classList.toggle('rotate-180');
238
+ });
239
+
240
+ imageInput.addEventListener('change', function(e) {
241
+ const file = this.files[0];
242
+ if (file) {
243
+ const reader = new FileReader();
244
+ reader.onload = function(e) {
245
+ previewImage.src = e.target.result;
246
+ imagePreview.classList.remove('hidden');
247
+ }
248
+ reader.readAsDataURL(file);
249
+ } else {
250
+ previewImage.src = "";
251
+ imagePreview.classList.add('hidden');
252
+ }
253
+ });
254
+
255
+ const dropZone = document.querySelector('.uploadArea');
256
+
257
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
258
+ dropZone.addEventListener(eventName, preventDefaults, false);
259
+ });
260
+
261
+ function preventDefaults(e) {
262
+ e.preventDefault();
263
+ e.stopPropagation();
264
+ }
265
+
266
+ ['dragenter', 'dragover'].forEach(eventName => {
267
+ dropZone.addEventListener(eventName, highlight, false);
268
+ });
269
+
270
+ ['dragleave', 'drop'].forEach(eventName => {
271
+ dropZone.addEventListener(eventName, unhighlight, false);
272
+ });
273
+
274
+ function highlight(e) {
275
+ dropZone.classList.add('border-blue-700');
276
+ }
277
+
278
+ function unhighlight(e) {
279
+ dropZone.classList.remove('border-blue-700');
280
+ }
281
+
282
+ dropZone.addEventListener('drop', handleDrop, false);
283
+
284
+ function handleDrop(e) {
285
+ const dt = e.dataTransfer;
286
+ const files = dt.files;
287
+
288
+ if (files.length) {
289
+ imageInput.files = files;
290
+ const file = files[0];
291
+ const reader = new FileReader();
292
+ reader.onload = function(e) {
293
+ previewImage.src = e.target.result;
294
+ imagePreview.classList.remove('hidden');
295
+ }
296
+ reader.readAsDataURL(file);
297
+ }
298
+ }
299
+
300
+ form.addEventListener('submit', async (event) => {
301
+ event.preventDefault();
302
+ const file = imageInput.files[0];
303
+ if (!file) {
304
+ alert('Veuillez sélectionner une image.');
305
+ return;
306
+ }
307
+
308
+ startTimer();
309
+
310
+ loader.classList.remove('hidden');
311
+ solutionDiv.classList.add('hidden');
312
+ thoughtsContent.innerHTML = '';
313
+ answerContent.innerHTML = '';
314
+ thoughtsBox.classList.add('open');
315
+
316
+ const formData = new FormData();
317
+ formData.append('image', file);
318
+
319
+ try {
320
+ let currentMode = null;
321
+ const response = await fetch('/solve', {
322
+ method: 'POST',
323
+ body: formData
324
+ });
325
+
326
+ const reader = response.body.getReader();
327
+ const decoder = new TextDecoder();
328
+ let buffer = '';
329
+
330
+ while (true) {
331
+ const { done, value } = await reader.read();
332
+ if (done) {
333
+ stopTimer();
334
+ break;
335
+ }
336
+
337
+ buffer += decoder.decode(value, { stream: true });
338
+ let eolIndex;
339
+
340
+ while ((eolIndex = buffer.indexOf('\n\n')) >= 0) {
341
+ const line = buffer.slice(0, eolIndex).trim();
342
+ buffer = buffer.slice(eolIndex + 2);
343
+
344
+ if (line.startsWith('data:')) {
345
+ const data = JSON.parse(line.slice(5));
346
+
347
+ if (data.mode) {
348
+ currentMode = data.mode;
349
+ loader.classList.add('hidden');
350
+ solutionDiv.classList.remove('hidden');
351
+ }
352
+
353
+ if (data.content) {
354
+ const content = data.content;
355
+ if (currentMode === 'thinking') {
356
+ thoughtsContent.innerHTML += `<p>${content}</p>`;
357
+ thoughtsContent.scrollTop = thoughtsContent.scrollHeight;
358
+ } else if (currentMode === 'answering') {
359
+ answerContent.innerHTML += content;
360
+ if (window.MathJax) {
361
+ MathJax.typesetPromise([answerContent]).catch((err) => console.log('MathJax error:', err));
362
+ }
363
+ }
364
+ }
365
+ }
366
+ }
367
+ }
368
+
369
+ } catch (error) {
370
+ console.error('Erreur:', error);
371
+ alert('Une erreur est survenue lors du traitement de la requête.');
372
+ loader.classList.add('hidden');
373
+ stopTimer();
374
+ }
375
+ });
376
+ });
377
+ </script>
378
+ </body>
379
+ </html>