OUAREDAEK commited on
Commit
02f6299
·
verified ·
1 Parent(s): f6b3e37

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +91 -124
index.html CHANGED
@@ -373,6 +373,12 @@
373
  border-radius: 50%;
374
  cursor: pointer;
375
  transition: all 0.3s;
 
 
 
 
 
 
376
  }
377
 
378
  .quality-dot:hover {
@@ -450,7 +456,7 @@
450
  <div class="form-row">
451
  <div class="form-col">
452
  <label class="form-label"><i class="fas fa-language"></i> Compétence Cible</label>
453
- <select id="competence" class="form-control">
454
  <option value="">Sélectionnez une compétence...</option>
455
  </select>
456
  </div>
@@ -489,12 +495,12 @@
489
  <div class="form-group">
490
  <label class="form-label"><i class="fas fa-chart-line"></i> Qualité Estimée de Rétention</label>
491
  <div class="quality-indicator">
492
- <div class="quality-dot quality-0 active" data-quality="0" onclick="selectQuality(0)"></div>
493
- <div class="quality-dot quality-1" data-quality="1" onclick="selectQuality(1)"></div>
494
- <div class="quality-dot quality-2" data-quality="2" onclick="selectQuality(2)"></div>
495
- <div class="quality-dot quality-3" data-quality="3" onclick="selectQuality(3)"></div>
496
  </div>
497
- <small id="quality-description">Difficulté - Révision fréquente nécessaire</small>
498
  </div>
499
 
500
  <button class="btn btn-primary btn-large" onclick="generatePlanner()">
@@ -564,9 +570,9 @@
564
  <div class="quality-indicator">
565
  <div class="quality-dot quality-0" onclick="setEvaluation(1)">1</div>
566
  <div class="quality-dot quality-1" onclick="setEvaluation(2)">2</div>
567
- <div class="quality-dot quality-2" onclick="setEvaluation(3)">3</div>
568
  <div class="quality-dot quality-3" onclick="setEvaluation(4)">4</div>
569
- <div class="quality-dot quality-3" onclick="setEvaluation(5)" style="background:linear-gradient(135deg, #8b5cf6, #7c3aed)">5</div>
570
  </div>
571
  <input type="hidden" id="auto_eval" value="3">
572
  </div>
@@ -655,15 +661,15 @@
655
  <script>
656
  // Variables globales
657
  let currentChart = null;
658
- let currentQuality = 0;
659
- let currentCompetence = '';
660
 
661
  // Initialisation
662
  document.addEventListener('DOMContentLoaded', function() {
663
  loadCompetences();
664
- selectQuality(2); // Qualité moyenne par défaut
665
  refreshStats();
666
  loadSM2Explanation();
 
667
  });
668
 
669
  // Navigation
@@ -682,8 +688,17 @@
682
  document.getElementById(tabId).classList.add('active');
683
 
684
  // Activer l'onglet correspondant
 
 
 
 
 
 
 
 
 
685
  document.querySelectorAll('.nav-tab').forEach(tab => {
686
- if (tab.textContent.includes(getTabName(tabId))) {
687
  tab.classList.add('active');
688
  }
689
  });
@@ -696,18 +711,6 @@
696
  }
697
  }
698
 
699
- function getTabName(tabId) {
700
- const names = {
701
- 'objectif': 'Objectif',
702
- 'planner': 'Planner',
703
- 'journal': 'Journal',
704
- 'notifications': 'Notifications',
705
- 'stats': 'Statistiques',
706
- 'learn': 'Apprendre'
707
- };
708
- return names[tabId] || tabId;
709
- }
710
-
711
  // Charger les compétences
712
  async function loadCompetences() {
713
  try {
@@ -749,32 +752,65 @@
749
 
750
  document.getElementById('quality-description').textContent = descriptions[level];
751
 
752
- // Générer un aperçu si une compétence est sélectionnée
753
- if (document.getElementById('competence').value) {
754
- previewSM2Curve();
755
- }
756
  }
757
 
758
  // Prévisualiser la courbe SM-2
759
  async function previewSM2Curve() {
760
  const competence = document.getElementById('competence').value;
761
- if (!competence) return;
 
 
 
762
 
763
  try {
764
  const response = await fetch(`/api/planner/visualize?competence=${encodeURIComponent(competence)}&quality=${currentQuality}`);
 
765
 
766
- if (response.ok) {
767
  document.getElementById('preview').style.display = 'block';
768
 
769
- const blob = await response.blob();
770
- const img = document.createElement('img');
771
- img.src = URL.createObjectURL(blob);
772
- img.style.width = '100%';
773
- img.style.borderRadius = '10px';
 
 
774
 
775
- const container = document.getElementById('intervalChart').parentElement;
776
- container.innerHTML = '';
777
- container.appendChild(img);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
778
  }
779
  } catch (error) {
780
  console.error('Erreur génération preview:', error);
@@ -785,11 +821,10 @@
785
  async function generatePlanner() {
786
  const competence = document.getElementById('competence').value;
787
  const startDate = document.getElementById('start').value;
788
- const endDate = document.getElementById('end').value;
789
  const duration = document.getElementById('duration').value;
790
 
791
- if (!competence || !startDate || !endDate) {
792
- alert('Veuillez remplir tous les champs obligatoires');
793
  return;
794
  }
795
 
@@ -800,8 +835,8 @@
800
  body: JSON.stringify({
801
  competence: competence,
802
  start_date: startDate,
803
- end_date: endDate,
804
  session_duration: duration,
 
805
  quality_level: currentQuality
806
  })
807
  });
@@ -809,7 +844,7 @@
809
  const data = await response.json();
810
 
811
  if (data.success) {
812
- displayPlanner(data.plan, data.visual_data);
813
  showTab('planner');
814
  } else {
815
  alert('Erreur: ' + data.error);
@@ -825,6 +860,9 @@
825
  const container = document.getElementById('plannerContent');
826
  const statsContainer = document.getElementById('plannerStats');
827
 
 
 
 
828
  // Statistiques
829
  statsContainer.innerHTML = `
830
  <div class="stat-card">
@@ -832,7 +870,7 @@
832
  <div class="stat-label">Sessions Planifiées</div>
833
  </div>
834
  <div class="stat-card">
835
- <div class="stat-value">${intervals[intervals.length - 1]}</div>
836
  <div class="stat-label">Jours Totaux</div>
837
  </div>
838
  <div class="stat-card">
@@ -880,7 +918,7 @@
880
  </div>
881
  </div>
882
  <div style="margin-top: 15px; padding: 10px; background: #f1f5f9; border-radius: 8px; font-size: 0.9rem;">
883
- <i class="fas fa-bell"></i> ${session.reminder}
884
  </div>
885
  `;
886
  container.appendChild(card);
@@ -899,7 +937,6 @@
899
  }
900
 
901
  const labels = intervals.map((_, i) => `Répétition ${i + 1}`);
902
- const dataPoints = intervals;
903
 
904
  currentChart = new Chart(ctx, {
905
  type: 'line',
@@ -907,7 +944,7 @@
907
  labels: labels,
908
  datasets: [{
909
  label: 'Intervalle (jours)',
910
- data: dataPoints,
911
  borderColor: '#3b82f6',
912
  backgroundColor: 'rgba(59, 130, 246, 0.1)',
913
  borderWidth: 3,
@@ -956,7 +993,7 @@
956
  document.getElementById('auto_eval').value = score;
957
 
958
  // Mettre à jour les indicateurs
959
- document.querySelectorAll('.quality-dot').forEach((dot, index) => {
960
  dot.classList.toggle('active', index === score - 1);
961
  });
962
  }
@@ -1052,9 +1089,9 @@
1052
 
1053
  card.innerHTML = `
1054
  <div style="display: flex; align-items: center; gap: 15px; margin-bottom: 10px;">
1055
- <div style="font-size: 2rem;">${icons[data.type]}</div>
1056
  <div>
1057
- <div style="font-weight: bold; color: #1e293b;">${data.type.charAt(0).toUpperCase() + data.type.slice(1)}</div>
1058
  <div style="font-size: 0.9rem; color: #64748b;">
1059
  Efficacité: ${(data.effectiveness_score * 100).toFixed(1)}%
1060
  </div>
@@ -1068,80 +1105,11 @@
1068
 
1069
  container.insertBefore(card, container.firstChild);
1070
 
1071
- // Mettre à jour le graphique
1072
- updateNotificationChart();
1073
-
1074
  } catch (error) {
1075
  console.error('Erreur notification:', error);
1076
  }
1077
  }
1078
 
1079
- async function updateNotificationChart() {
1080
- try {
1081
- const response = await fetch('/api/learner/stats');
1082
- const stats = await response.json();
1083
-
1084
- const ctx = document.getElementById('notificationChart').getContext('2d');
1085
-
1086
- if (window.notificationChart) {
1087
- window.notificationChart.destroy();
1088
- }
1089
-
1090
- const labels = Object.keys(stats.notification_effectiveness);
1091
- const data = Object.values(stats.notification_effectiveness);
1092
-
1093
- window.notificationChart = new Chart(ctx, {
1094
- type: 'bar',
1095
- data: {
1096
- labels: labels.map(l => l.replace('_', ' ')),
1097
- datasets: [{
1098
- label: 'Taux de Réussite',
1099
- data: data,
1100
- backgroundColor: [
1101
- 'rgba(59, 130, 246, 0.7)',
1102
- 'rgba(16, 185, 129, 0.7)',
1103
- 'rgba(139, 92, 246, 0.7)',
1104
- 'rgba(245, 158, 11, 0.7)'
1105
- ],
1106
- borderColor: [
1107
- 'rgb(59, 130, 246)',
1108
- 'rgb(16, 185, 129)',
1109
- 'rgb(139, 92, 246)',
1110
- 'rgb(245, 158, 11)'
1111
- ],
1112
- borderWidth: 2
1113
- }]
1114
- },
1115
- options: {
1116
- responsive: true,
1117
- maintainAspectRatio: false,
1118
- scales: {
1119
- y: {
1120
- beginAtZero: true,
1121
- max: 1,
1122
- ticks: {
1123
- callback: function(value) {
1124
- return (value * 100) + '%';
1125
- }
1126
- }
1127
- }
1128
- },
1129
- plugins: {
1130
- tooltip: {
1131
- callbacks: {
1132
- label: function(context) {
1133
- return (context.raw * 100).toFixed(1) + '%';
1134
- }
1135
- }
1136
- }
1137
- }
1138
- }
1139
- });
1140
- } catch (error) {
1141
- console.error('Erreur graphique notifications:', error);
1142
- }
1143
- }
1144
-
1145
  // Statistiques
1146
  async function refreshStats() {
1147
  try {
@@ -1308,10 +1276,10 @@
1308
 
1309
  // Données des différents niveaux de qualité
1310
  const intervals = {
1311
- 'Difficulté (N0)': [1, 1, 3, 7, 16, 35],
1312
  'Moyen (N1)': [1, 3, 7, 14, 30, 60],
1313
- 'Bon (N2)': [1, 7, 16, 35, 90, 180],
1314
- 'Excellent (N3)': [1, 14, 30, 90, 180, 365]
1315
  };
1316
 
1317
  const labels = ['R1', 'R2', 'R3', 'R4', 'R5', 'R6'];
@@ -1342,8 +1310,7 @@
1342
  title: {
1343
  display: true,
1344
  text: 'Intervalle (jours)'
1345
- },
1346
- type: 'logarithmic'
1347
  }
1348
  },
1349
  plugins: {
 
373
  border-radius: 50%;
374
  cursor: pointer;
375
  transition: all 0.3s;
376
+ display: flex;
377
+ align-items: center;
378
+ justify-content: center;
379
+ color: white;
380
+ font-weight: bold;
381
+ font-size: 0.8rem;
382
  }
383
 
384
  .quality-dot:hover {
 
456
  <div class="form-row">
457
  <div class="form-col">
458
  <label class="form-label"><i class="fas fa-language"></i> Compétence Cible</label>
459
+ <select id="competence" class="form-control" onchange="previewSM2Curve()">
460
  <option value="">Sélectionnez une compétence...</option>
461
  </select>
462
  </div>
 
495
  <div class="form-group">
496
  <label class="form-label"><i class="fas fa-chart-line"></i> Qualité Estimée de Rétention</label>
497
  <div class="quality-indicator">
498
+ <div class="quality-dot quality-0" data-quality="0" onclick="selectQuality(0)">0</div>
499
+ <div class="quality-dot quality-1" data-quality="1" onclick="selectQuality(1)">1</div>
500
+ <div class="quality-dot quality-2 active" data-quality="2" onclick="selectQuality(2)">2</div>
501
+ <div class="quality-dot quality-3" data-quality="3" onclick="selectQuality(3)">3</div>
502
  </div>
503
+ <small id="quality-description">Bon - Consolidation progressive</small>
504
  </div>
505
 
506
  <button class="btn btn-primary btn-large" onclick="generatePlanner()">
 
570
  <div class="quality-indicator">
571
  <div class="quality-dot quality-0" onclick="setEvaluation(1)">1</div>
572
  <div class="quality-dot quality-1" onclick="setEvaluation(2)">2</div>
573
+ <div class="quality-dot quality-2 active" onclick="setEvaluation(3)">3</div>
574
  <div class="quality-dot quality-3" onclick="setEvaluation(4)">4</div>
575
+ <div class="quality-dot" onclick="setEvaluation(5)" style="background:linear-gradient(135deg, #8b5cf6, #7c3aed)">5</div>
576
  </div>
577
  <input type="hidden" id="auto_eval" value="3">
578
  </div>
 
661
  <script>
662
  // Variables globales
663
  let currentChart = null;
664
+ let currentQuality = 2; // Niveau 2 par défaut
665
+ let previewChart = null;
666
 
667
  // Initialisation
668
  document.addEventListener('DOMContentLoaded', function() {
669
  loadCompetences();
 
670
  refreshStats();
671
  loadSM2Explanation();
672
+ updateComparisonChart();
673
  });
674
 
675
  // Navigation
 
688
  document.getElementById(tabId).classList.add('active');
689
 
690
  // Activer l'onglet correspondant
691
+ const tabNames = {
692
+ 'objectif': 'Objectif',
693
+ 'planner': 'Planner',
694
+ 'journal': 'Journal',
695
+ 'notifications': 'Notifications',
696
+ 'stats': 'Statistiques',
697
+ 'learn': 'Apprendre'
698
+ };
699
+
700
  document.querySelectorAll('.nav-tab').forEach(tab => {
701
+ if (tab.textContent.includes(tabNames[tabId])) {
702
  tab.classList.add('active');
703
  }
704
  });
 
711
  }
712
  }
713
 
 
 
 
 
 
 
 
 
 
 
 
 
714
  // Charger les compétences
715
  async function loadCompetences() {
716
  try {
 
752
 
753
  document.getElementById('quality-description').textContent = descriptions[level];
754
 
755
+ // Mettre à jour l'aperçu
756
+ previewSM2Curve();
 
 
757
  }
758
 
759
  // Prévisualiser la courbe SM-2
760
  async function previewSM2Curve() {
761
  const competence = document.getElementById('competence').value;
762
+ if (!competence) {
763
+ document.getElementById('preview').style.display = 'none';
764
+ return;
765
+ }
766
 
767
  try {
768
  const response = await fetch(`/api/planner/visualize?competence=${encodeURIComponent(competence)}&quality=${currentQuality}`);
769
+ const data = await response.json();
770
 
771
+ if (data.success) {
772
  document.getElementById('preview').style.display = 'block';
773
 
774
+ const ctx = document.getElementById('intervalChart').getContext('2d');
775
+
776
+ if (previewChart) {
777
+ previewChart.destroy();
778
+ }
779
+
780
+ const labels = data.intervals.map((_, i) => `Répétition ${i + 1}`);
781
 
782
+ previewChart = new Chart(ctx, {
783
+ type: 'bar',
784
+ data: {
785
+ labels: labels,
786
+ datasets: [{
787
+ label: 'Intervalle (jours)',
788
+ data: data.intervals,
789
+ backgroundColor: '#3b82f6',
790
+ borderColor: '#2563eb',
791
+ borderWidth: 2
792
+ }]
793
+ },
794
+ options: {
795
+ responsive: true,
796
+ maintainAspectRatio: false,
797
+ plugins: {
798
+ title: {
799
+ display: true,
800
+ text: `Courbe SM-2 - Niveau ${currentQuality}`
801
+ }
802
+ },
803
+ scales: {
804
+ y: {
805
+ beginAtZero: true,
806
+ title: {
807
+ display: true,
808
+ text: 'Jours'
809
+ }
810
+ }
811
+ }
812
+ }
813
+ });
814
  }
815
  } catch (error) {
816
  console.error('Erreur génération preview:', error);
 
821
  async function generatePlanner() {
822
  const competence = document.getElementById('competence').value;
823
  const startDate = document.getElementById('start').value;
 
824
  const duration = document.getElementById('duration').value;
825
 
826
+ if (!competence || !startDate) {
827
+ alert('Veuillez sélectionner une compétence et une date de début');
828
  return;
829
  }
830
 
 
835
  body: JSON.stringify({
836
  competence: competence,
837
  start_date: startDate,
 
838
  session_duration: duration,
839
+ repetitions: 6,
840
  quality_level: currentQuality
841
  })
842
  });
 
844
  const data = await response.json();
845
 
846
  if (data.success) {
847
+ displayPlanner(data.plan, data.intervals);
848
  showTab('planner');
849
  } else {
850
  alert('Erreur: ' + data.error);
 
860
  const container = document.getElementById('plannerContent');
861
  const statsContainer = document.getElementById('plannerStats');
862
 
863
+ // Calculer le total des jours
864
+ const totalDays = intervals.reduce((a, b) => a + b, 0);
865
+
866
  // Statistiques
867
  statsContainer.innerHTML = `
868
  <div class="stat-card">
 
870
  <div class="stat-label">Sessions Planifiées</div>
871
  </div>
872
  <div class="stat-card">
873
+ <div class="stat-value">${totalDays}</div>
874
  <div class="stat-label">Jours Totaux</div>
875
  </div>
876
  <div class="stat-card">
 
918
  </div>
919
  </div>
920
  <div style="margin-top: 15px; padding: 10px; background: #f1f5f9; border-radius: 8px; font-size: 0.9rem;">
921
+ <i class="fas fa-bell"></i> ${session.reminder || ''}
922
  </div>
923
  `;
924
  container.appendChild(card);
 
937
  }
938
 
939
  const labels = intervals.map((_, i) => `Répétition ${i + 1}`);
 
940
 
941
  currentChart = new Chart(ctx, {
942
  type: 'line',
 
944
  labels: labels,
945
  datasets: [{
946
  label: 'Intervalle (jours)',
947
+ data: intervals,
948
  borderColor: '#3b82f6',
949
  backgroundColor: 'rgba(59, 130, 246, 0.1)',
950
  borderWidth: 3,
 
993
  document.getElementById('auto_eval').value = score;
994
 
995
  // Mettre à jour les indicateurs
996
+ document.querySelectorAll('.quality-indicator .quality-dot').forEach((dot, index) => {
997
  dot.classList.toggle('active', index === score - 1);
998
  });
999
  }
 
1089
 
1090
  card.innerHTML = `
1091
  <div style="display: flex; align-items: center; gap: 15px; margin-bottom: 10px;">
1092
+ <div style="font-size: 2rem;">${icons[data.type] || '🔔'}</div>
1093
  <div>
1094
+ <div style="font-weight: bold; color: #1e293b;">${data.type ? data.type.charAt(0).toUpperCase() + data.type.slice(1).replace('_', ' ') : 'Notification'}</div>
1095
  <div style="font-size: 0.9rem; color: #64748b;">
1096
  Efficacité: ${(data.effectiveness_score * 100).toFixed(1)}%
1097
  </div>
 
1105
 
1106
  container.insertBefore(card, container.firstChild);
1107
 
 
 
 
1108
  } catch (error) {
1109
  console.error('Erreur notification:', error);
1110
  }
1111
  }
1112
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1113
  // Statistiques
1114
  async function refreshStats() {
1115
  try {
 
1276
 
1277
  // Données des différents niveaux de qualité
1278
  const intervals = {
1279
+ 'Difficulté (N0)': [1, 2, 4, 8, 16, 32],
1280
  'Moyen (N1)': [1, 3, 7, 14, 30, 60],
1281
+ 'Bon (N2)': [2, 7, 16, 35, 70, 140],
1282
+ 'Excellent (N3)': [3, 10, 25, 60, 120, 240]
1283
  };
1284
 
1285
  const labels = ['R1', 'R2', 'R3', 'R4', 'R5', 'R6'];
 
1310
  title: {
1311
  display: true,
1312
  text: 'Intervalle (jours)'
1313
+ }
 
1314
  }
1315
  },
1316
  plugins: {