Docfile commited on
Commit
e2d63ac
·
verified ·
1 Parent(s): 1759e8b

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +183 -470
templates/index.html CHANGED
@@ -132,7 +132,7 @@
132
  }
133
 
134
  .step-section, .code-section, .output-section {
135
- margin: 0 0 1px 0;
136
  padding: 20px;
137
  border-radius: 0;
138
  overflow-x: auto;
@@ -141,7 +141,7 @@
141
 
142
  .step-section {
143
  border-left: 4px solid var(--primary-color);
144
- padding-left: calc(20px - 4px);
145
  background-color: #f9f9f9;
146
  font-size: 16px;
147
  line-height: 1.8;
@@ -149,29 +149,31 @@
149
 
150
  /* Improved LaTeX styling */
151
  .step-section .mjx-chtml {
152
- display: inline-block !important;
153
- line-height: 0;
154
- text-indent: 0;
155
- text-align: left;
156
- text-transform: none;
157
- font-size: 100%;
158
- font-style: normal;
159
- font-weight: normal;
160
- font-family: MJXZERO, MJXTEX;
161
- direction: ltr;
162
- margin: 0 0.2em;
163
- vertical-align: -0.25em;
 
164
  }
165
 
166
  .step-section .MathJax {
167
- display: inline !important;
168
- font-size: 100% !important;
169
- text-align: left;
 
170
  }
171
 
172
  /* Fix for inline math to prevent weird line breaks */
173
  .step-section p {
174
- display: block;
175
  margin-block-start: 1em;
176
  margin-block-end: 1em;
177
  margin-inline-start: 0px;
@@ -189,9 +191,9 @@
189
  }
190
 
191
  .code-section {
192
- background-color: transparent;
193
- padding: 0;
194
- border-left: none;
195
  }
196
 
197
  .code-header {
@@ -203,6 +205,7 @@
203
  display: flex;
204
  justify-content: space-between;
205
  align-items: center;
 
206
  border-top-left-radius: 0px;
207
  border-top-right-radius: 0px;
208
  }
@@ -216,6 +219,7 @@
216
  font-family: 'Courier New', monospace;
217
  font-size: 14px;
218
  line-height: 1.5;
 
219
  border-bottom-left-radius: 0px;
220
  border-bottom-right-radius: 0px;
221
  }
@@ -229,23 +233,28 @@
229
  font-size: 14px;
230
  white-space: pre-wrap;
231
  overflow-x: auto;
232
- border-left: none;
 
233
  border-bottom-left-radius: 0px;
234
  border-bottom-right-radius: 0px;
235
  }
236
 
237
  /* Add border-radius back to the very first and very last child inside #solution */
238
- #solution > div:first-child,
 
 
 
 
239
  #solution > div:first-child .code-header {
240
- border-top-left-radius: 8px;
241
- border-top-right-radius: 8px;
242
  }
243
 
244
- #solution > div:last-child,
245
- #solution > div:last-child .code-content,
246
- #solution > div:last-child.output-section {
247
- border-bottom-left-radius: 8px;
248
- border-bottom-right-radius: 8px;
249
  }
250
 
251
  #solution > .code-section:last-child .code-content {
@@ -253,19 +262,48 @@
253
  border-bottom-right-radius: 8px;
254
  }
255
 
256
- #solution > .code-section:not(:last-child) .code-content {
257
- border-bottom-left-radius: 0;
258
- border-bottom-right-radius: 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
259
  }
260
 
 
 
 
 
 
 
 
261
  /* Fixed display of MathJax content */
262
  .mjx-container {
263
  display: inline-block !important;
264
  margin: 0 !important;
265
  text-align: center !important;
266
- overflow-x: auto;
267
  overflow-y: hidden;
268
  padding: 0 !important;
 
269
  }
270
 
271
  .mjx-container.MJX-display {
@@ -273,6 +311,8 @@
273
  margin: 1em auto !important;
274
  text-align: center !important;
275
  max-width: 100%;
 
 
276
  }
277
 
278
  /* Fix markdown list rendering */
@@ -304,20 +344,20 @@
304
  .executing-indicator { background-color: #ede7f6; color: #5e35b1; }
305
  .answering-indicator { background-color: #e8f5e9; color: #2e7d32; }
306
 
307
- .indicator-icon {
308
- margin-right: 12px;
309
- animation: pulse 1.5s infinite ease-in-out;
310
  font-size: 1.1rem;
311
  }
312
-
313
- @keyframes pulse {
314
- 0% { opacity: 0.6; }
315
- 50% { opacity: 1; }
316
- 100% { opacity: 0.6; }
317
  }
318
 
319
  /* Fix assistive MML elements */
320
- mjx-assistive-mml {
321
  position: absolute !important;
322
  top: 0 !important;
323
  left: 0 !important;
@@ -327,13 +367,15 @@
327
  }
328
 
329
  /* Unified consistent LaTeX size for all equations */
330
- .step-section .MathJax {
331
- font-size: 16px !important;
 
 
332
  }
333
-
334
  .step-section .MathJax_Display {
335
  text-align: center !important;
336
- margin: 1em 0 !important;
337
  display: block !important;
338
  overflow-x: auto;
339
  overflow-y: hidden;
@@ -408,395 +450,34 @@
408
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
409
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/python.min.js"></script>
410
 
 
411
  <script>
412
  window.MathJax = {
413
  tex: {
414
- inlineMath: [['
415
- </script>
416
- <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script>
417
-
418
- <script>
419
- document.getElementById('imageInput').addEventListener('change', function(event) {
420
- const file = event.target.files[0];
421
- if (file) {
422
- const reader = new FileReader();
423
- reader.onload = function(e) {
424
- document.getElementById('preview').src = e.target.result;
425
- document.getElementById('imagePreview').style.display = 'block';
426
- document.getElementById('solveButton').style.display = 'inline-block';
427
- document.getElementById('uploadStatus').textContent = `Image sélectionnée : ${file.name}`;
428
- }
429
- reader.readAsDataURL(file);
430
- }
431
- });
432
-
433
- document.getElementById('solveButton').addEventListener('click', function() {
434
- const formData = new FormData(document.getElementById('imageForm'));
435
- const solutionOutput = document.getElementById('solutionOutput');
436
- const loadingIndicator = document.getElementById('loadingIndicator');
437
- const solutionContainer = document.getElementById('solution');
438
-
439
- solutionOutput.style.display = 'block';
440
- loadingIndicator.style.display = 'flex';
441
- solutionContainer.innerHTML = '';
442
-
443
- fetch('/solved', {
444
- method: 'POST',
445
- body: formData
446
- })
447
- .then(response => {
448
- if (!response.ok) {
449
- throw new Error(`Erreur serveur: ${response.statusText}`);
450
- }
451
- const reader = response.body.getReader();
452
- const decoder = new TextDecoder();
453
- let buffer = '';
454
-
455
- function processStream({ done, value }) {
456
- if (done) {
457
- loadingIndicator.style.display = 'none';
458
- // Force MathJax to reprocess entire solution when done
459
- if (typeof MathJax !== 'undefined') {
460
- MathJax.typesetPromise([solutionContainer]).catch(e => console.error('MathJax final typesetting error:', e));
461
- }
462
- return;
463
- }
464
-
465
- buffer += decoder.decode(value, { stream: true });
466
- const lines = buffer.split(/\r?\n\r?\n/);
467
- buffer = lines.pop();
468
-
469
- for (const line of lines) {
470
- if (line.startsWith('data: ')) {
471
- try {
472
- const data = JSON.parse(line.substr(6));
473
-
474
- if (data.mode) {
475
- const modes = {
476
- thinking: { icon: 'fa-brain', text: 'Je réfléchis...', class: 'thinking-indicator' },
477
- answering: { icon: 'fa-pencil-alt', text: 'Rédaction...', class: 'answering-indicator' },
478
- executing_code: { icon: 'fa-code', text: 'Exécution...', class: 'executing-indicator' },
479
- code_result: { icon: 'fa-terminal', text: 'Résultats...', class: 'executing-indicator' }
480
- };
481
- const modeInfo = modes[data.mode];
482
- if (modeInfo) {
483
- loadingIndicator.className = modeInfo.class;
484
- loadingIndicator.innerHTML = `<i class="fas ${modeInfo.icon} indicator-icon"></i><span>${modeInfo.text}</span>`;
485
- }
486
- }
487
-
488
- if (data.content) {
489
- const content = data.content;
490
- const tempDiv = document.createElement('div');
491
- tempDiv.innerHTML = content;
492
-
493
- const codeSection = tempDiv.querySelector('.code-section');
494
- const outputSection = tempDiv.querySelector('.output-section');
495
-
496
- if (codeSection) {
497
- solutionContainer.appendChild(codeSection);
498
- codeSection.querySelectorAll('pre code').forEach((block) => {
499
- hljs.highlightElement(block);
500
- });
501
- } else if (outputSection) {
502
- solutionContainer.appendChild(outputSection);
503
- } else {
504
- // Process regular text/LaTeX step section
505
- const stepDiv = document.createElement('div');
506
- stepDiv.className = 'step-section';
507
-
508
- // Fix markdown content before adding
509
- let processedContent = content;
510
-
511
- // Ensure proper paragraph breaks
512
- processedContent = processedContent.replace(/\n\n/g, '</p><p>');
513
-
514
- // Wrap in paragraph tags if not already
515
- if (!processedContent.startsWith('<p>')) {
516
- processedContent = '<p>' + processedContent;
517
- }
518
- if (!processedContent.endsWith('</p>')) {
519
- processedContent = processedContent + '</p>';
520
- }
521
-
522
- // Fix lists in markdown
523
- processedContent = processedContent.replace(/<p>(\s*[-*]\s+.*?)<\/p>/g, '<ul><li>$1</li></ul>');
524
- processedContent = processedContent.replace(/<p>(\s*\d+\.\s+.*?)<\/p>/g, '<ol><li>$1</li></ol>');
525
-
526
- stepDiv.innerHTML = processedContent;
527
- solutionContainer.appendChild(stepDiv);
528
-
529
- // Process MathJax for this section
530
- if (typeof MathJax !== 'undefined') {
531
- MathJax.typesetPromise([stepDiv]).catch(e => console.error('MathJax typesetting error:', e));
532
- }
533
- }
534
- }
535
-
536
- if (data.error) {
537
- const errorDiv = document.createElement('div');
538
- errorDiv.className = 'step-section';
539
- errorDiv.style.color = 'red';
540
- errorDiv.style.backgroundColor = '#ffeeee';
541
- errorDiv.style.borderColor = 'red';
542
- errorDiv.textContent = `Erreur: ${data.error}`;
543
- solutionContainer.appendChild(errorDiv);
544
- loadingIndicator.style.display = 'none';
545
- }
546
- } catch (e) {
547
- console.error('Error parsing JSON or processing chunk:', e, line);
548
- const errorDiv = document.createElement('div');
549
- errorDiv.className = 'step-section';
550
- errorDiv.style.color = 'orange';
551
- errorDiv.textContent = `Erreur traitement chunk: ${line.substring(0, 100)}...`;
552
- solutionContainer.appendChild(errorDiv);
553
- }
554
- }
555
- }
556
-
557
- window.scrollTo(0, document.body.scrollHeight);
558
- return reader.read().then(processStream);
559
- }
560
-
561
- return reader.read().then(processStream);
562
- })
563
- .catch(error => {
564
- const errorDiv = document.createElement('div');
565
- errorDiv.className = 'step-section';
566
- errorDiv.style.color = 'red';
567
- errorDiv.style.backgroundColor = '#ffeeee';
568
- errorDiv.style.borderColor = 'red';
569
- errorDiv.textContent = `Erreur de connexion ou du serveur: ${error}`;
570
- solutionContainer.appendChild(errorDiv);
571
- loadingIndicator.style.display = 'none';
572
- console.error('Fetch error:', error);
573
- });
574
- });
575
-
576
- // Helper function to ensure proper markdown formatting
577
- function processMarkdown(content) {
578
- // Process lists
579
- content = content.replace(/^(\s*[-*]\s+.*?)$/gm, '<li>$1</li>');
580
- content = content.replace(/^(\s*\d+\.\s+.*?)$/gm, '<li>$1</li>');
581
-
582
- // Wrap adjacent list items in proper containers
583
- content = content.replace(/<li>.*?<\/li>(\s*<li>.*?<\/li>)+/g, match => {
584
- if (match.includes('*') || match.includes('-')) {
585
- return '<ul>' + match + '</ul>';
586
- } else {
587
- return '<ol>' + match + '</ol>';
588
- }
589
- });
590
-
591
- return content;
592
- }
593
- </script>
594
- </body>
595
- </html>, '
596
- </script>
597
- <script id="MathJax-script" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-svg.js"></script>
598
-
599
- <script>
600
- document.getElementById('imageInput').addEventListener('change', function(event) {
601
- const file = event.target.files[0];
602
- if (file) {
603
- const reader = new FileReader();
604
- reader.onload = function(e) {
605
- document.getElementById('preview').src = e.target.result;
606
- document.getElementById('imagePreview').style.display = 'block';
607
- document.getElementById('solveButton').style.display = 'inline-block';
608
- document.getElementById('uploadStatus').textContent = `Image sélectionnée : ${file.name}`;
609
- }
610
- reader.readAsDataURL(file);
611
- }
612
- });
613
-
614
- document.getElementById('solveButton').addEventListener('click', function() {
615
- const formData = new FormData(document.getElementById('imageForm'));
616
- const solutionOutput = document.getElementById('solutionOutput');
617
- const loadingIndicator = document.getElementById('loadingIndicator');
618
- const solutionContainer = document.getElementById('solution');
619
-
620
- solutionOutput.style.display = 'block';
621
- loadingIndicator.style.display = 'flex';
622
- solutionContainer.innerHTML = '';
623
-
624
- fetch('/solved', {
625
- method: 'POST',
626
- body: formData
627
- })
628
- .then(response => {
629
- if (!response.ok) {
630
- throw new Error(`Erreur serveur: ${response.statusText}`);
631
- }
632
- const reader = response.body.getReader();
633
- const decoder = new TextDecoder();
634
- let buffer = '';
635
-
636
- function processStream({ done, value }) {
637
- if (done) {
638
- loadingIndicator.style.display = 'none';
639
- // Force MathJax to reprocess entire solution when done
640
- if (typeof MathJax !== 'undefined') {
641
- MathJax.typesetPromise([solutionContainer]).catch(e => console.error('MathJax final typesetting error:', e));
642
- }
643
- return;
644
- }
645
-
646
- buffer += decoder.decode(value, { stream: true });
647
- const lines = buffer.split(/\r?\n\r?\n/);
648
- buffer = lines.pop();
649
-
650
- for (const line of lines) {
651
- if (line.startsWith('data: ')) {
652
- try {
653
- const data = JSON.parse(line.substr(6));
654
-
655
- if (data.mode) {
656
- const modes = {
657
- thinking: { icon: 'fa-brain', text: 'Je réfléchis...', class: 'thinking-indicator' },
658
- answering: { icon: 'fa-pencil-alt', text: 'Rédaction...', class: 'answering-indicator' },
659
- executing_code: { icon: 'fa-code', text: 'Exécution...', class: 'executing-indicator' },
660
- code_result: { icon: 'fa-terminal', text: 'Résultats...', class: 'executing-indicator' }
661
- };
662
- const modeInfo = modes[data.mode];
663
- if (modeInfo) {
664
- loadingIndicator.className = modeInfo.class;
665
- loadingIndicator.innerHTML = `<i class="fas ${modeInfo.icon} indicator-icon"></i><span>${modeInfo.text}</span>`;
666
- }
667
- }
668
-
669
- if (data.content) {
670
- const content = data.content;
671
- const tempDiv = document.createElement('div');
672
- tempDiv.innerHTML = content;
673
-
674
- const codeSection = tempDiv.querySelector('.code-section');
675
- const outputSection = tempDiv.querySelector('.output-section');
676
-
677
- if (codeSection) {
678
- solutionContainer.appendChild(codeSection);
679
- codeSection.querySelectorAll('pre code').forEach((block) => {
680
- hljs.highlightElement(block);
681
- });
682
- } else if (outputSection) {
683
- solutionContainer.appendChild(outputSection);
684
- } else {
685
- // Process regular text/LaTeX step section
686
- const stepDiv = document.createElement('div');
687
- stepDiv.className = 'step-section';
688
-
689
- // Fix markdown content before adding
690
- let processedContent = content;
691
-
692
- // Ensure proper paragraph breaks
693
- processedContent = processedContent.replace(/\n\n/g, '</p><p>');
694
-
695
- // Wrap in paragraph tags if not already
696
- if (!processedContent.startsWith('<p>')) {
697
- processedContent = '<p>' + processedContent;
698
- }
699
- if (!processedContent.endsWith('</p>')) {
700
- processedContent = processedContent + '</p>';
701
- }
702
-
703
- // Fix lists in markdown
704
- processedContent = processedContent.replace(/<p>(\s*[-*]\s+.*?)<\/p>/g, '<ul><li>$1</li></ul>');
705
- processedContent = processedContent.replace(/<p>(\s*\d+\.\s+.*?)<\/p>/g, '<ol><li>$1</li></ol>');
706
-
707
- stepDiv.innerHTML = processedContent;
708
- solutionContainer.appendChild(stepDiv);
709
-
710
- // Process MathJax for this section
711
- if (typeof MathJax !== 'undefined') {
712
- MathJax.typesetPromise([stepDiv]).catch(e => console.error('MathJax typesetting error:', e));
713
- }
714
- }
715
- }
716
-
717
- if (data.error) {
718
- const errorDiv = document.createElement('div');
719
- errorDiv.className = 'step-section';
720
- errorDiv.style.color = 'red';
721
- errorDiv.style.backgroundColor = '#ffeeee';
722
- errorDiv.style.borderColor = 'red';
723
- errorDiv.textContent = `Erreur: ${data.error}`;
724
- solutionContainer.appendChild(errorDiv);
725
- loadingIndicator.style.display = 'none';
726
- }
727
- } catch (e) {
728
- console.error('Error parsing JSON or processing chunk:', e, line);
729
- const errorDiv = document.createElement('div');
730
- errorDiv.className = 'step-section';
731
- errorDiv.style.color = 'orange';
732
- errorDiv.textContent = `Erreur traitement chunk: ${line.substring(0, 100)}...`;
733
- solutionContainer.appendChild(errorDiv);
734
- }
735
- }
736
- }
737
-
738
- window.scrollTo(0, document.body.scrollHeight);
739
- return reader.read().then(processStream);
740
- }
741
-
742
- return reader.read().then(processStream);
743
- })
744
- .catch(error => {
745
- const errorDiv = document.createElement('div');
746
- errorDiv.className = 'step-section';
747
- errorDiv.style.color = 'red';
748
- errorDiv.style.backgroundColor = '#ffeeee';
749
- errorDiv.style.borderColor = 'red';
750
- errorDiv.textContent = `Erreur de connexion ou du serveur: ${error}`;
751
- solutionContainer.appendChild(errorDiv);
752
- loadingIndicator.style.display = 'none';
753
- console.error('Fetch error:', error);
754
- });
755
- });
756
-
757
- // Helper function to ensure proper markdown formatting
758
- function processMarkdown(content) {
759
- // Process lists
760
- content = content.replace(/^(\s*[-*]\s+.*?)$/gm, '<li>$1</li>');
761
- content = content.replace(/^(\s*\d+\.\s+.*?)$/gm, '<li>$1</li>');
762
-
763
- // Wrap adjacent list items in proper containers
764
- content = content.replace(/<li>.*?<\/li>(\s*<li>.*?<\/li>)+/g, match => {
765
- if (match.includes('*') || match.includes('-')) {
766
- return '<ul>' + match + '</ul>';
767
- } else {
768
- return '<ol>' + match + '</ol>';
769
- }
770
- });
771
-
772
- return content;
773
- }
774
- </script>
775
- </body>
776
- </html>], ['\\(', '\\)']],
777
- displayMath: [['$', '$'], ['\\[', '\\]']],
778
  processEscapes: true,
779
  processEnvironments: true,
780
  packages: {'[+]': ['noerrors', 'physics', 'cancel', 'color']}
781
  },
782
  options: {
783
  enableMenu: false,
784
- ignoreHtmlClass: 'code-content',
785
- processHtmlClass: 'step-section|latex-display',
786
  skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
787
  },
788
  loader: {
789
- load: ['input/tex-full', 'output/svg']
790
  },
791
  svg: {
792
  fontCache: 'global',
793
- scale: 1, // Global scaling factor for all expressions
794
  minScale: 1, // Minimum scaling factor
795
- mtextInheritFont: true, // True to make mtext elements use surrounding font
796
- merrorInheritFont: true, // True to make merror text use surrounding font
797
- mathmlSpacing: false // True for MathML spacing rules, false for TeX rules
798
  },
799
- chtml: {
800
  scale: 1,
801
  minScale: 1,
802
  mtextInheritFont: true,
@@ -804,7 +485,8 @@
804
  }
805
  };
806
  </script>
807
- <script id="MathJax-script" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-svg.js"></script>
 
808
 
809
  <script>
810
  document.getElementById('imageInput').addEventListener('change', function(event) {
@@ -829,15 +511,18 @@
829
 
830
  solutionOutput.style.display = 'block';
831
  loadingIndicator.style.display = 'flex';
832
- solutionContainer.innerHTML = '';
833
 
834
- fetch('/solved', {
835
  method: 'POST',
836
  body: formData
837
  })
838
  .then(response => {
839
  if (!response.ok) {
840
- throw new Error(`Erreur serveur: ${response.statusText}`);
 
 
 
841
  }
842
  const reader = response.body.getReader();
843
  const decoder = new TextDecoder();
@@ -854,38 +539,47 @@
854
  }
855
 
856
  buffer += decoder.decode(value, { stream: true });
 
857
  const lines = buffer.split(/\r?\n\r?\n/);
858
- buffer = lines.pop();
859
 
860
  for (const line of lines) {
 
861
  if (line.startsWith('data: ')) {
862
  try {
863
- const data = JSON.parse(line.substr(6));
864
 
 
865
  if (data.mode) {
866
  const modes = {
867
  thinking: { icon: 'fa-brain', text: 'Je réfléchis...', class: 'thinking-indicator' },
868
  answering: { icon: 'fa-pencil-alt', text: 'Rédaction...', class: 'answering-indicator' },
869
  executing_code: { icon: 'fa-code', text: 'Exécution...', class: 'executing-indicator' },
870
- code_result: { icon: 'fa-terminal', text: 'Résultats...', class: 'executing-indicator' }
871
  };
872
  const modeInfo = modes[data.mode];
873
  if (modeInfo) {
874
- loadingIndicator.className = modeInfo.class;
875
- loadingIndicator.innerHTML = `<i class="fas ${modeInfo.icon} indicator-icon"></i><span>${modeInfo.text}</span>`;
 
 
 
 
876
  }
877
  }
878
 
 
879
  if (data.content) {
880
  const content = data.content;
881
  const tempDiv = document.createElement('div');
882
- tempDiv.innerHTML = content;
883
 
884
  const codeSection = tempDiv.querySelector('.code-section');
885
  const outputSection = tempDiv.querySelector('.output-section');
886
 
887
  if (codeSection) {
888
  solutionContainer.appendChild(codeSection);
 
889
  codeSection.querySelectorAll('pre code').forEach((block) => {
890
  hljs.highlightElement(block);
891
  });
@@ -895,63 +589,99 @@
895
  // Process regular text/LaTeX step section
896
  const stepDiv = document.createElement('div');
897
  stepDiv.className = 'step-section';
898
-
899
- // Fix markdown content before adding
900
  let processedContent = content;
901
-
902
- // Ensure proper paragraph breaks
903
- processedContent = processedContent.replace(/\n\n/g, '</p><p>');
904
-
905
- // Wrap in paragraph tags if not already
906
- if (!processedContent.startsWith('<p>')) {
907
- processedContent = '<p>' + processedContent;
908
- }
909
- if (!processedContent.endsWith('</p>')) {
910
- processedContent = processedContent + '</p>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
911
  }
912
-
913
- // Fix lists in markdown
914
- processedContent = processedContent.replace(/<p>(\s*[-*]\s+.*?)<\/p>/g, '<ul><li>$1</li></ul>');
915
- processedContent = processedContent.replace(/<p>(\s*\d+\.\s+.*?)<\/p>/g, '<ol><li>$1</li></ol>');
916
-
917
- stepDiv.innerHTML = processedContent;
918
  solutionContainer.appendChild(stepDiv);
919
-
920
- // Process MathJax for this section
921
  if (typeof MathJax !== 'undefined') {
922
  MathJax.typesetPromise([stepDiv]).catch(e => console.error('MathJax typesetting error:', e));
923
  }
924
  }
925
  }
926
 
 
927
  if (data.error) {
928
  const errorDiv = document.createElement('div');
929
- errorDiv.className = 'step-section';
930
  errorDiv.style.color = 'red';
931
  errorDiv.style.backgroundColor = '#ffeeee';
932
  errorDiv.style.borderColor = 'red';
933
  errorDiv.textContent = `Erreur: ${data.error}`;
934
  solutionContainer.appendChild(errorDiv);
935
- loadingIndicator.style.display = 'none';
936
  }
937
  } catch (e) {
938
  console.error('Error parsing JSON or processing chunk:', e, line);
 
939
  const errorDiv = document.createElement('div');
940
  errorDiv.className = 'step-section';
941
  errorDiv.style.color = 'orange';
942
- errorDiv.textContent = `Erreur traitement chunk: ${line.substring(0, 100)}...`;
943
  solutionContainer.appendChild(errorDiv);
 
944
  }
 
 
 
945
  }
946
  }
947
 
948
- window.scrollTo(0, document.body.scrollHeight);
 
 
 
949
  return reader.read().then(processStream);
950
  }
951
 
 
952
  return reader.read().then(processStream);
953
  })
954
  .catch(error => {
 
955
  const errorDiv = document.createElement('div');
956
  errorDiv.className = 'step-section';
957
  errorDiv.style.color = 'red';
@@ -964,23 +694,6 @@
964
  });
965
  });
966
 
967
- // Helper function to ensure proper markdown formatting
968
- function processMarkdown(content) {
969
- // Process lists
970
- content = content.replace(/^(\s*[-*]\s+.*?)$/gm, '<li>$1</li>');
971
- content = content.replace(/^(\s*\d+\.\s+.*?)$/gm, '<li>$1</li>');
972
-
973
- // Wrap adjacent list items in proper containers
974
- content = content.replace(/<li>.*?<\/li>(\s*<li>.*?<\/li>)+/g, match => {
975
- if (match.includes('*') || match.includes('-')) {
976
- return '<ul>' + match + '</ul>';
977
- } else {
978
- return '<ol>' + match + '</ol>';
979
- }
980
- });
981
-
982
- return content;
983
- }
984
  </script>
985
  </body>
986
  </html>
 
132
  }
133
 
134
  .step-section, .code-section, .output-section {
135
+ margin: 0 0 1px 0; /* Reduced bottom margin to make sections appear connected */
136
  padding: 20px;
137
  border-radius: 0;
138
  overflow-x: auto;
 
141
 
142
  .step-section {
143
  border-left: 4px solid var(--primary-color);
144
+ padding-left: calc(20px - 4px); /* Adjust padding to account for border */
145
  background-color: #f9f9f9;
146
  font-size: 16px;
147
  line-height: 1.8;
 
149
 
150
  /* Improved LaTeX styling */
151
  .step-section .mjx-chtml {
152
+ /* Default MathJax inline styling */
153
+ display: inline-block;
154
+ line-height: 0;
155
+ text-indent: 0;
156
+ text-align: left;
157
+ text-transform: none;
158
+ font-size: 100%; /* Ensure inline MathJax respects container font size */
159
+ font-style: normal;
160
+ font-weight: normal;
161
+ font-family: MJXZERO, MJXTEX;
162
+ direction: ltr;
163
+ vertical-align: -0.25em; /* Standard vertical alignment */
164
+ margin: 0 0.2em; /* Small horizontal margin */
165
  }
166
 
167
  .step-section .MathJax {
168
+ /* Default MathJax container styling */
169
+ display: inline;
170
+ font-size: 100% !important; /* Ensure inline MathJax respects container font size */
171
+ text-align: left;
172
  }
173
 
174
  /* Fix for inline math to prevent weird line breaks */
175
  .step-section p {
176
+ display: block; /* Paragraphs should be block elements */
177
  margin-block-start: 1em;
178
  margin-block-end: 1em;
179
  margin-inline-start: 0px;
 
191
  }
192
 
193
  .code-section {
194
+ background-color: transparent; /* Background handled by code-content */
195
+ padding: 0; /* Padding handled by code-content */
196
+ border-left: none; /* No left border */
197
  }
198
 
199
  .code-header {
 
205
  display: flex;
206
  justify-content: space-between;
207
  align-items: center;
208
+ /* Border radius handled by first/last child rules */
209
  border-top-left-radius: 0px;
210
  border-top-right-radius: 0px;
211
  }
 
219
  font-family: 'Courier New', monospace;
220
  font-size: 14px;
221
  line-height: 1.5;
222
+ /* Border radius handled by first/last child rules */
223
  border-bottom-left-radius: 0px;
224
  border-bottom-right-radius: 0px;
225
  }
 
233
  font-size: 14px;
234
  white-space: pre-wrap;
235
  overflow-x: auto;
236
+ border-left: none; /* No left border */
237
+ /* Border radius handled by first/last child rules */
238
  border-bottom-left-radius: 0px;
239
  border-bottom-right-radius: 0px;
240
  }
241
 
242
  /* Add border-radius back to the very first and very last child inside #solution */
243
+ #solution > div:first-child {
244
+ border-top-left-radius: 8px;
245
+ border-top-right-radius: 8px;
246
+ }
247
+
248
  #solution > div:first-child .code-header {
249
+ border-top-left-radius: 8px;
250
+ border-top-right-radius: 8px;
251
  }
252
 
253
+
254
+ #solution > div:last-child {
255
+ border-bottom-left-radius: 8px;
256
+ border-bottom-right-radius: 8px;
257
+ margin-bottom: 0; /* Remove extra margin on the last child */
258
  }
259
 
260
  #solution > .code-section:last-child .code-content {
 
262
  border-bottom-right-radius: 8px;
263
  }
264
 
265
+ /* Specific case for a single code section */
266
+ #solution > .code-section:only-child .code-header {
267
+ border-top-left-radius: 8px;
268
+ border-top-right-radius: 8px;
269
+ }
270
+ #solution > .code-section:only-child .code-content {
271
+ border-bottom-left-radius: 8px;
272
+ border-bottom-right-radius: 8px;
273
+ }
274
+
275
+
276
+ #solution > .output-section:last-child {
277
+ border-bottom-left-radius: 8px;
278
+ border-bottom-right-radius: 8px;
279
+ margin-bottom: 0;
280
+ }
281
+
282
+ /* Specific case for a single output section */
283
+ #solution > .output-section:only-child {
284
+ border-top-left-radius: 8px;
285
+ border-top-right-radius: 8px;
286
+ border-bottom-left-radius: 8px;
287
+ border-bottom-right-radius: 8px;
288
+ margin-bottom: 0;
289
  }
290
 
291
+ /* Remove bottom border/margin for sections that are not the last child, */
292
+ /* to make them appear connected to the next section */
293
+ #solution > div:not(:last-child) {
294
+ margin-bottom: 0;
295
+ }
296
+
297
+
298
  /* Fixed display of MathJax content */
299
  .mjx-container {
300
  display: inline-block !important;
301
  margin: 0 !important;
302
  text-align: center !important;
303
+ overflow-x: auto; /* Allow horizontal scrolling for large inline equations */
304
  overflow-y: hidden;
305
  padding: 0 !important;
306
+ vertical-align: middle; /* Better vertical alignment for inline math */
307
  }
308
 
309
  .mjx-container.MJX-display {
 
311
  margin: 1em auto !important;
312
  text-align: center !important;
313
  max-width: 100%;
314
+ overflow-x: auto; /* Allow horizontal scrolling for large block equations */
315
+ overflow-y: hidden;
316
  }
317
 
318
  /* Fix markdown list rendering */
 
344
  .executing-indicator { background-color: #ede7f6; color: #5e35b1; }
345
  .answering-indicator { background-color: #e8f5e9; color: #2e7d32; }
346
 
347
+ .indicator-icon {
348
+ margin-right: 12px;
349
+ animation: pulse 1.5s infinite ease-in-out;
350
  font-size: 1.1rem;
351
  }
352
+
353
+ @keyframes pulse {
354
+ 0% { opacity: 0.6; }
355
+ 50% { opacity: 1; }
356
+ 100% { opacity: 0.6; }
357
  }
358
 
359
  /* Fix assistive MML elements */
360
+ mjx-assistive-mml {
361
  position: absolute !important;
362
  top: 0 !important;
363
  left: 0 !important;
 
367
  }
368
 
369
  /* Unified consistent LaTeX size for all equations */
370
+ /* Ensure MathJax respects container font size */
371
+ .step-section .MathJax,
372
+ .step-section .mjx-container {
373
+ font-size: inherit !important;
374
  }
375
+
376
  .step-section .MathJax_Display {
377
  text-align: center !important;
378
+ margin: 1em auto !important;
379
  display: block !important;
380
  overflow-x: auto;
381
  overflow-y: hidden;
 
450
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
451
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/python.min.js"></script>
452
 
453
+ <!-- MathJax Configuration -->
454
  <script>
455
  window.MathJax = {
456
  tex: {
457
+ inlineMath: [['$', '$'], ['\\(', '\\)']], // Correct inline delimiters
458
+ displayMath: [['$$', '$$'], ['\\[', '\\]']], // Correct block delimiters
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
459
  processEscapes: true,
460
  processEnvironments: true,
461
  packages: {'[+]': ['noerrors', 'physics', 'cancel', 'color']}
462
  },
463
  options: {
464
  enableMenu: false,
465
+ ignoreHtmlClass: 'code-content', // Don't process code blocks
466
+ processHtmlClass: 'step-section|latex-display', // Only process step and latex-display sections
467
  skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
468
  },
469
  loader: {
470
+ load: ['input/tex-full', 'output/svg'] // Load full TeX input and SVG output
471
  },
472
  svg: {
473
  fontCache: 'global',
474
+ scale: 1, // Global scaling factor
475
  minScale: 1, // Minimum scaling factor
476
+ mtextInheritFont: true, // mtext uses surrounding font
477
+ merrorInheritFont: true, // merror uses surrounding font
478
+ mathmlSpacing: false // TeX spacing rules
479
  },
480
+ chtml: { // Also configure for CHTML output as a fallback or alternative
481
  scale: 1,
482
  minScale: 1,
483
  mtextInheritFont: true,
 
485
  }
486
  };
487
  </script>
488
+ <!-- MathJax v3 Script -->
489
+ <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script>
490
 
491
  <script>
492
  document.getElementById('imageInput').addEventListener('change', function(event) {
 
511
 
512
  solutionOutput.style.display = 'block';
513
  loadingIndicator.style.display = 'flex';
514
+ solutionContainer.innerHTML = ''; // Clear previous solution
515
 
516
+ fetch('/solved', { // Assuming the Flask endpoint is '/solved'
517
  method: 'POST',
518
  body: formData
519
  })
520
  .then(response => {
521
  if (!response.ok) {
522
+ // Attempt to read error message from body if available
523
+ return response.text().then(text => {
524
+ throw new Error(`Erreur serveur: ${response.status} ${response.statusText}\n${text}`);
525
+ });
526
  }
527
  const reader = response.body.getReader();
528
  const decoder = new TextDecoder();
 
539
  }
540
 
541
  buffer += decoder.decode(value, { stream: true });
542
+ // Split by double newline to separate chunks, but keep the last incomplete chunk in buffer
543
  const lines = buffer.split(/\r?\n\r?\n/);
544
+ buffer = lines.pop(); // Store the last potentially incomplete chunk
545
 
546
  for (const line of lines) {
547
+ // Only process lines that start with 'data: ' for SSE
548
  if (line.startsWith('data: ')) {
549
  try {
550
+ const data = JSON.parse(line.substr(6)); // Extract JSON after 'data: '
551
 
552
+ // Handle mode updates
553
  if (data.mode) {
554
  const modes = {
555
  thinking: { icon: 'fa-brain', text: 'Je réfléchis...', class: 'thinking-indicator' },
556
  answering: { icon: 'fa-pencil-alt', text: 'Rédaction...', class: 'answering-indicator' },
557
  executing_code: { icon: 'fa-code', text: 'Exécution...', class: 'executing-indicator' },
558
+ code_result: { icon: 'fa-terminal', text: 'Résultats...', class: 'executing-indicator' } // Use executing indicator for results too, or create a new one
559
  };
560
  const modeInfo = modes[data.mode];
561
  if (modeInfo) {
562
+ loadingIndicator.className = modeInfo.class; // Update class for styling
563
+ loadingIndicator.innerHTML = `<i class="fas ${modeInfo.icon} indicator-icon"></i><span>${modeInfo.text}</span>`; // Update icon and text
564
+ } else {
565
+ // Default or unknown mode
566
+ loadingIndicator.className = 'thinking-indicator';
567
+ loadingIndicator.innerHTML = `<i class="fas fa-sync-alt indicator-icon fa-spin"></i><span>Traitement...</span>`;
568
  }
569
  }
570
 
571
+ // Handle content blocks
572
  if (data.content) {
573
  const content = data.content;
574
  const tempDiv = document.createElement('div');
575
+ tempDiv.innerHTML = content; // Parse HTML chunk
576
 
577
  const codeSection = tempDiv.querySelector('.code-section');
578
  const outputSection = tempDiv.querySelector('.output-section');
579
 
580
  if (codeSection) {
581
  solutionContainer.appendChild(codeSection);
582
+ // Highlight code within the added section
583
  codeSection.querySelectorAll('pre code').forEach((block) => {
584
  hljs.highlightElement(block);
585
  });
 
589
  // Process regular text/LaTeX step section
590
  const stepDiv = document.createElement('div');
591
  stepDiv.className = 'step-section';
592
+
593
+ // Basic markdown processing for lists (more robust processing might need a library)
594
  let processedContent = content;
595
+
596
+ // Convert markdown lists to HTML lists
597
+ processedContent = processedContent.replace(/^(-|\*|\+)\s+(.*)$/gm, '<li>$2</li>'); // Handles -, *, + markers
598
+ processedContent = processedContent.replace(/^(\d+)\.\s+(.*)$/gm, '<li>$2</li>'); // Handles numbered lists
599
+
600
+ // Wrap consecutive list items in ul/ol tags
601
+ let listHtml = '';
602
+ let inList = false;
603
+ let listType = ''; // 'ul' or 'ol'
604
+
605
+ processedContent.split('\n').forEach(line => {
606
+ if (line.startsWith('<li>')) {
607
+ const itemType = line.match(/^\d+\./) ? 'ol' : 'ul';
608
+ if (!inList) {
609
+ listType = itemType;
610
+ listHtml += `<${listType}>${line}`;
611
+ inList = true;
612
+ } else if (listType === itemType) {
613
+ listHtml += line;
614
+ } else {
615
+ // Different list type, close previous and start new
616
+ listHtml += `</${listType}><${itemType}>${line}`;
617
+ listType = itemType;
618
+ }
619
+ } else {
620
+ if (inList) {
621
+ listHtml += `</${listType}>`;
622
+ inList = false;
623
+ }
624
+ listHtml += `<p>${line}</p>`; // Wrap non-list lines in paragraphs
625
+ }
626
+ });
627
+
628
+ if (inList) {
629
+ listHtml += `</${listType}>`;
630
  }
631
+
632
+ // Clean up empty paragraph tags that might have been created
633
+ listHtml = listHtml.replace(/<p><\/p>/g, '');
634
+
635
+
636
+ stepDiv.innerHTML = listHtml; // Use the processed HTML
637
  solutionContainer.appendChild(stepDiv);
638
+
639
+ // Process MathJax for this section (will process the new content)
640
  if (typeof MathJax !== 'undefined') {
641
  MathJax.typesetPromise([stepDiv]).catch(e => console.error('MathJax typesetting error:', e));
642
  }
643
  }
644
  }
645
 
646
+ // Handle error messages
647
  if (data.error) {
648
  const errorDiv = document.createElement('div');
649
+ errorDiv.className = 'step-section'; // Use step section styling for errors
650
  errorDiv.style.color = 'red';
651
  errorDiv.style.backgroundColor = '#ffeeee';
652
  errorDiv.style.borderColor = 'red';
653
  errorDiv.textContent = `Erreur: ${data.error}`;
654
  solutionContainer.appendChild(errorDiv);
655
+ loadingIndicator.style.display = 'none'; // Hide loading indicator on error
656
  }
657
  } catch (e) {
658
  console.error('Error parsing JSON or processing chunk:', e, line);
659
+ // Display a client-side processing error message
660
  const errorDiv = document.createElement('div');
661
  errorDiv.className = 'step-section';
662
  errorDiv.style.color = 'orange';
663
+ errorDiv.textContent = `Erreur traitement chunk: ${line.substring(0, 100)}...`; // Show a snippet of the problematic line
664
  solutionContainer.appendChild(errorDiv);
665
+ loadingIndicator.style.display = 'none';
666
  }
667
+ } else {
668
+ // Handle potential non-data lines if necessary, or ignore
669
+ console.warn("Received non-data line:", line);
670
  }
671
  }
672
 
673
+ // Scroll to the bottom of the solution container as new content arrives
674
+ solutionOutput.scrollTop = solutionOutput.scrollHeight;
675
+
676
+ // Continue reading the stream
677
  return reader.read().then(processStream);
678
  }
679
 
680
+ // Start processing the stream
681
  return reader.read().then(processStream);
682
  })
683
  .catch(error => {
684
+ // Handle errors during the fetch or from the initial response check
685
  const errorDiv = document.createElement('div');
686
  errorDiv.className = 'step-section';
687
  errorDiv.style.color = 'red';
 
694
  });
695
  });
696
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
697
  </script>
698
  </body>
699
  </html>