Spaces:
Sleeping
Sleeping
Update templates/index.html
Browse files- templates/index.html +187 -134
templates/index.html
CHANGED
|
@@ -159,158 +159,211 @@
|
|
| 159 |
</div>
|
| 160 |
|
| 161 |
<script>
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 178 |
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
const file = this.files[0];
|
| 182 |
-
if (file) {
|
| 183 |
-
const reader = new FileReader();
|
| 184 |
-
reader.onload = function(e) {
|
| 185 |
-
previewImage.src = e.target.result;
|
| 186 |
-
imagePreview.classList.remove('hidden');
|
| 187 |
-
}
|
| 188 |
-
reader.readAsDataURL(file);
|
| 189 |
-
} else {
|
| 190 |
-
previewImage.src = "";
|
| 191 |
-
imagePreview.classList.add('hidden');
|
| 192 |
-
}
|
| 193 |
-
});
|
| 194 |
|
| 195 |
-
|
| 196 |
-
|
|
|
|
| 197 |
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
|
|
|
| 201 |
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
}
|
| 206 |
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
| 218 |
|
| 219 |
-
|
| 220 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 221 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 222 |
|
| 223 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 224 |
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
const reader = new FileReader();
|
| 233 |
-
reader.onload = function(e) {
|
| 234 |
-
previewImage.src = e.target.result;
|
| 235 |
-
imagePreview.classList.remove('hidden');
|
| 236 |
-
}
|
| 237 |
-
reader.readAsDataURL(file);
|
| 238 |
-
}
|
| 239 |
-
}
|
| 240 |
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
event.preventDefault();
|
| 244 |
-
const file = imageInput.files[0];
|
| 245 |
-
if (!file) {
|
| 246 |
-
alert('Veuillez sélectionner une image.');
|
| 247 |
-
return;
|
| 248 |
-
}
|
| 249 |
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
buffer += decoder.decode(value, { stream: true });
|
| 276 |
-
let eolIndex;
|
| 277 |
-
|
| 278 |
-
while ((eolIndex = buffer.indexOf('\n\n')) >= 0) {
|
| 279 |
-
const line = buffer.slice(0, eolIndex).trim();
|
| 280 |
-
buffer = buffer.slice(eolIndex + 2);
|
| 281 |
-
|
| 282 |
-
if (line.startsWith('data:')) {
|
| 283 |
-
const data = JSON.parse(line.slice(5));
|
| 284 |
-
|
| 285 |
-
if (data.mode) {
|
| 286 |
-
currentMode = data.mode;
|
| 287 |
-
loader.classList.add('hidden');
|
| 288 |
-
solutionDiv.classList.remove('hidden');
|
| 289 |
-
}
|
| 290 |
-
|
| 291 |
-
if (data.content) {
|
| 292 |
-
const content = data.content;
|
| 293 |
-
if (currentMode === 'thinking') {
|
| 294 |
-
thoughtsContent.innerHTML += `<p>${content}</p>`;
|
| 295 |
-
thoughtsContent.scrollTop = thoughtsContent.scrollHeight;
|
| 296 |
-
} else if (currentMode === 'answering') {
|
| 297 |
-
answerContent.innerHTML += content;
|
| 298 |
-
if (window.MathJax) {
|
| 299 |
-
MathJax.Hub.Queue(["Typeset", MathJax.Hub, answerContent]);
|
| 300 |
-
}
|
| 301 |
-
}
|
| 302 |
}
|
| 303 |
}
|
| 304 |
}
|
| 305 |
-
}
|
| 306 |
|
| 307 |
-
|
| 308 |
-
|
| 309 |
-
|
| 310 |
-
|
|
|
|
| 311 |
}
|
| 312 |
-
}
|
| 313 |
-
|
| 314 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 315 |
</body>
|
| 316 |
</html>
|
|
|
|
| 159 |
</div>
|
| 160 |
|
| 161 |
<script>
|
| 162 |
+
document.addEventListener('DOMContentLoaded', () => {
|
| 163 |
+
// Configuration de MathJax pour un meilleur support LaTeX
|
| 164 |
+
window.MathJax = {
|
| 165 |
+
tex: {
|
| 166 |
+
inlineMath: [['$', '$'], ['\\(', '\\)']],
|
| 167 |
+
displayMath: [['$$', '$$'], ['\\[', '\\]']],
|
| 168 |
+
processEscapes: true,
|
| 169 |
+
processEnvironments: true,
|
| 170 |
+
packages: ['base', 'ams', 'noerrors', 'noundefined']
|
| 171 |
+
},
|
| 172 |
+
options: {
|
| 173 |
+
ignoreHtmlClass: 'tex2jax_ignore',
|
| 174 |
+
processHtmlClass: 'tex2jax_process'
|
| 175 |
+
},
|
| 176 |
+
svg: {
|
| 177 |
+
fontCache: 'global'
|
| 178 |
+
}
|
| 179 |
+
};
|
| 180 |
+
|
| 181 |
+
const form = document.getElementById('problemForm');
|
| 182 |
+
const imageInput = document.getElementById('imageInput');
|
| 183 |
+
const loader = document.getElementById('loader');
|
| 184 |
+
const solutionDiv = document.getElementById('solution');
|
| 185 |
+
const thoughtsContent = document.getElementById('thoughtsContent');
|
| 186 |
+
const answerContent = document.getElementById('answerContent');
|
| 187 |
+
const thoughtsToggle = document.getElementById('thoughtsToggle');
|
| 188 |
+
const thoughtsBox = document.getElementById('thoughtsBox');
|
| 189 |
+
const imagePreview = document.getElementById('imagePreview');
|
| 190 |
+
const previewImage = document.getElementById('previewImage');
|
| 191 |
+
|
| 192 |
+
// Fonction pour formater le temps écoulé
|
| 193 |
+
function formatElapsedTime(seconds) {
|
| 194 |
+
return `${seconds}s`;
|
| 195 |
+
}
|
| 196 |
+
|
| 197 |
+
// Fonction pour nettoyer et préparer le texte LaTeX
|
| 198 |
+
function prepareMathContent(content) {
|
| 199 |
+
// Protège les expressions LaTeX déjà correctement formatées
|
| 200 |
+
content = content.replace(/\$\$(.*?)\$\$/g, '[[DISPLAY_MATH_$1]]');
|
| 201 |
+
content = content.replace(/\$(.*?)\$/g, '[[INLINE_MATH_$1]]');
|
| 202 |
+
|
| 203 |
+
// Convertit les expressions potentiellement non formatées
|
| 204 |
+
content = content.replace(/\\boxed\{(.*?)\}/g, '$\\boxed{$1}$');
|
| 205 |
+
content = content.replace(/\\frac\{(.*?)\}\{(.*?)\}/g, '$\\frac{$1}{$2}$');
|
| 206 |
+
content = content.replace(/\\cos/g, '$\\cos$');
|
| 207 |
+
content = content.replace(/\\sin/g, '$\\sin$');
|
| 208 |
+
content = content.replace(/\\theta/g, '$\\theta$');
|
| 209 |
+
content = content.replace(/\\alpha/g, '$\\alpha$');
|
| 210 |
+
content = content.replace(/e\^{([^}]+)}/g, '$e^{$1}$');
|
| 211 |
+
|
| 212 |
+
// Restaure les expressions protégées
|
| 213 |
+
content = content.replace(/\[\[DISPLAY_MATH_(.*?)\]\]/g, '$$$$1$$');
|
| 214 |
+
content = content.replace(/\[\[INLINE_MATH_(.*?)\]\]/g, '$$$1$');
|
| 215 |
+
|
| 216 |
+
return content;
|
| 217 |
+
}
|
| 218 |
+
|
| 219 |
+
// Gestion du toggle des pensées
|
| 220 |
+
thoughtsToggle.addEventListener('click', () => {
|
| 221 |
+
thoughtsBox.classList.toggle('open');
|
| 222 |
+
thoughtsToggle.querySelector('svg').classList.toggle('rotate-180');
|
| 223 |
+
});
|
| 224 |
+
|
| 225 |
+
// Gestion de la prévisualisation des images
|
| 226 |
+
imageInput.addEventListener('change', function(e) {
|
| 227 |
+
const file = this.files[0];
|
| 228 |
+
if (file) {
|
| 229 |
+
const reader = new FileReader();
|
| 230 |
+
reader.onload = function(e) {
|
| 231 |
+
previewImage.src = e.target.result;
|
| 232 |
+
imagePreview.classList.remove('hidden');
|
| 233 |
+
}
|
| 234 |
+
reader.readAsDataURL(file);
|
| 235 |
+
} else {
|
| 236 |
+
previewImage.src = "";
|
| 237 |
+
imagePreview.classList.add('hidden');
|
| 238 |
+
}
|
| 239 |
+
});
|
| 240 |
|
| 241 |
+
// Gestion du drag & drop
|
| 242 |
+
const dropZone = document.querySelector('.uploadArea');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 243 |
|
| 244 |
+
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
|
| 245 |
+
dropZone.addEventListener(eventName, preventDefaults, false);
|
| 246 |
+
});
|
| 247 |
|
| 248 |
+
function preventDefaults(e) {
|
| 249 |
+
e.preventDefault();
|
| 250 |
+
e.stopPropagation();
|
| 251 |
+
}
|
| 252 |
|
| 253 |
+
['dragenter', 'dragover'].forEach(eventName => {
|
| 254 |
+
dropZone.addEventListener(eventName, highlight, false);
|
| 255 |
+
});
|
|
|
|
| 256 |
|
| 257 |
+
['dragleave', 'drop'].forEach(eventName => {
|
| 258 |
+
dropZone.addEventListener(eventName, unhighlight, false);
|
| 259 |
+
});
|
| 260 |
|
| 261 |
+
function highlight(e) {
|
| 262 |
+
dropZone.classList.add('border-blue-400');
|
| 263 |
+
}
|
| 264 |
|
| 265 |
+
function unhighlight(e) {
|
| 266 |
+
dropZone.classList.remove('border-blue-400');
|
| 267 |
+
}
|
| 268 |
|
| 269 |
+
dropZone.addEventListener('drop', handleDrop, false);
|
| 270 |
+
|
| 271 |
+
function handleDrop(e) {
|
| 272 |
+
const dt = e.dataTransfer;
|
| 273 |
+
const files = dt.files;
|
| 274 |
+
|
| 275 |
+
if (files.length) {
|
| 276 |
+
imageInput.files = files;
|
| 277 |
+
const file = files[0];
|
| 278 |
+
const reader = new FileReader();
|
| 279 |
+
reader.onload = function(e) {
|
| 280 |
+
previewImage.src = e.target.result;
|
| 281 |
+
imagePreview.classList.remove('hidden');
|
| 282 |
}
|
| 283 |
+
reader.readAsDataURL(file);
|
| 284 |
+
}
|
| 285 |
+
}
|
| 286 |
+
|
| 287 |
+
// Gestion de la soumission du formulaire et du streaming
|
| 288 |
+
form.addEventListener('submit', async (event) => {
|
| 289 |
+
event.preventDefault();
|
| 290 |
+
const file = imageInput.files[0];
|
| 291 |
+
if (!file) {
|
| 292 |
+
alert('Veuillez sélectionner une image.');
|
| 293 |
+
return;
|
| 294 |
+
}
|
| 295 |
|
| 296 |
+
// Reset UI
|
| 297 |
+
loader.classList.remove('hidden');
|
| 298 |
+
solutionDiv.classList.add('hidden');
|
| 299 |
+
thoughtsContent.innerHTML = '';
|
| 300 |
+
answerContent.innerHTML = '';
|
| 301 |
+
thoughtsBox.classList.add('open');
|
| 302 |
+
|
| 303 |
+
const formData = new FormData();
|
| 304 |
+
formData.append('image', file);
|
| 305 |
+
|
| 306 |
+
try {
|
| 307 |
+
let currentMode = null;
|
| 308 |
+
const response = await fetch('/solve', {
|
| 309 |
+
method: 'POST',
|
| 310 |
+
body: formData
|
| 311 |
+
});
|
| 312 |
|
| 313 |
+
const reader = response.body.getReader();
|
| 314 |
+
const decoder = new TextDecoder();
|
| 315 |
+
let buffer = '';
|
| 316 |
|
| 317 |
+
while (true) {
|
| 318 |
+
const { done, value } = await reader.read();
|
| 319 |
+
if (done) break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 320 |
|
| 321 |
+
buffer += decoder.decode(value, { stream: true });
|
| 322 |
+
let eolIndex;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 323 |
|
| 324 |
+
while ((eolIndex = buffer.indexOf('\n\n')) >= 0) {
|
| 325 |
+
const line = buffer.slice(0, eolIndex).trim();
|
| 326 |
+
buffer = buffer.slice(eolIndex + 2);
|
| 327 |
+
|
| 328 |
+
if (line.startsWith('data:')) {
|
| 329 |
+
const data = JSON.parse(line.slice(5));
|
| 330 |
+
|
| 331 |
+
if (data.mode) {
|
| 332 |
+
currentMode = data.mode;
|
| 333 |
+
loader.classList.add('hidden');
|
| 334 |
+
solutionDiv.classList.remove('hidden');
|
| 335 |
+
}
|
| 336 |
+
|
| 337 |
+
if (data.content) {
|
| 338 |
+
const content = prepareMathContent(data.content);
|
| 339 |
+
const timeString = data.elapsed_time ? ` <span class="text-blue-400">(${formatElapsedTime(data.elapsed_time)})</span> ` : '';
|
| 340 |
+
|
| 341 |
+
if (currentMode === 'thinking') {
|
| 342 |
+
thoughtsContent.innerHTML += `<p>${timeString}${content}</p>`;
|
| 343 |
+
thoughtsContent.scrollTop = thoughtsContent.scrollHeight;
|
| 344 |
+
} else if (currentMode === 'answering') {
|
| 345 |
+
answerContent.innerHTML += content;
|
| 346 |
+
if (window.MathJax) {
|
| 347 |
+
MathJax.Hub.Queue(["Typeset", MathJax.Hub, answerContent]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 348 |
}
|
| 349 |
}
|
| 350 |
}
|
|
|
|
| 351 |
|
| 352 |
+
// Mettre à jour MathJax pour le contenu des pensées aussi
|
| 353 |
+
if (window.MathJax) {
|
| 354 |
+
MathJax.Hub.Queue(["Typeset", MathJax.Hub, thoughtsContent]);
|
| 355 |
+
}
|
| 356 |
+
}
|
| 357 |
}
|
| 358 |
+
}
|
| 359 |
+
|
| 360 |
+
} catch (error) {
|
| 361 |
+
console.error('Erreur:', error);
|
| 362 |
+
alert('Une erreur est survenue lors du traitement de la requête.');
|
| 363 |
+
loader.classList.add('hidden');
|
| 364 |
+
}
|
| 365 |
+
});
|
| 366 |
+
});
|
| 367 |
+
</script>
|
| 368 |
</body>
|
| 369 |
</html>
|