OUAREDAEK commited on
Commit
5c8b337
·
verified ·
1 Parent(s): b825c84

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. index-old1.html +159 -0
  2. index.html +1382 -0
index-old1.html ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Cognitive-Driven Language Learning</title>
6
+
7
+ <style>
8
+ body { font-family: Arial; margin: 0; background: #f4f6f8; }
9
+ header { background: #1e293b; color: white; padding: 15px; text-align: center; }
10
+ nav { display: flex; background: #334155; }
11
+ nav button {
12
+ flex: 1; padding: 12px; border: none; color: white;
13
+ background: #334155; cursor: pointer;
14
+ }
15
+ nav button:hover { background: #475569; }
16
+ section { display: none; padding: 20px; }
17
+ section.active { display: block; background: white; margin: 10px; border-radius: 8px; }
18
+
19
+ input, select, textarea {
20
+ width: 100%; padding: 8px; margin: 5px 0;
21
+ }
22
+
23
+ .card {
24
+ background: #f8fafc; padding: 10px; margin: 8px 0; border-left: 4px solid #3b82f6;
25
+ }
26
+ </style>
27
+ </head>
28
+
29
+ <body>
30
+
31
+ <header>
32
+ <h2>🧠 Cognitive-Driven AI for Language Learning</h2>
33
+ <p>Optimizing Long-Term Memory Retention through Spaced Repetition (SM-2), Self-Regulated Learning, Metacognition, and Gentle Reminders via Multi-Armed Bandits</p>
34
+ </header>
35
+
36
+ <nav>
37
+ <button onclick="showTab('objectif')">🎯 Objectif</button>
38
+ <button onclick="showTab('planner')">📅 Planner</button>
39
+ <button onclick="showTab('journal')">📔 Journal SRL</button>
40
+ <button onclick="showTab('notifications')">🔔 Notifications</button>
41
+ </nav>
42
+
43
+ <!-- OBJECTIF -->
44
+ <section id="objectif" class="active">
45
+ <h3>🎯 Définir mon objectif</h3>
46
+
47
+ <label>Compétence cible</label>
48
+ <select id="competence">
49
+ {% for c in competences %}
50
+ <option>{{ c }}</option>
51
+ {% endfor %}
52
+ </select>
53
+
54
+ <label>Date de début</label>
55
+ <input type="date" id="start">
56
+
57
+ <label>Date de fin</label>
58
+ <input type="date" id="end">
59
+
60
+ <label>Durée par session (minutes)</label>
61
+ <select id="duration">
62
+ <option>10</option><option>20</option><option>30</option>
63
+ </select>
64
+
65
+ <button onclick="generatePlanner()">Générer le planner</button>
66
+ </section>
67
+
68
+ <!-- PLANNER -->
69
+ <section id="planner">
70
+ <h3>📅 Planner personnalisé</h3>
71
+ <div id="plannerContent"></div>
72
+ </section>
73
+
74
+ <!-- JOURNAL -->
75
+ <section id="journal">
76
+ <h3>📔 Journal de bord – Self-Regulated Learning</h3>
77
+
78
+ <label>To-Do</label>
79
+ <textarea id="todo"></textarea>
80
+
81
+ <label>Doing</label>
82
+ <textarea id="doing"></textarea>
83
+
84
+ <label>Done</label>
85
+ <textarea id="done"></textarea>
86
+
87
+ <label>Qu’est-ce qui a facilité l’apprentissage ?</label>
88
+ <textarea id="q1"></textarea>
89
+
90
+ <label>Qu’est-ce qui a été difficile ?</label>
91
+ <textarea id="q2"></textarea>
92
+
93
+ <label>Stratégie à tester la prochaine fois</label>
94
+ <textarea id="q3"></textarea>
95
+
96
+ <button onclick="saveJournal()">Sauvegarder</button>
97
+ </section>
98
+
99
+ <!-- NOTIFICATIONS -->
100
+ <section id="notifications">
101
+ <h3>🔔 Gentle Reminders intelligents</h3>
102
+ <button onclick="getReminder()">Afficher un rappel</button>
103
+ <div id="notifBox" class="card"></div>
104
+ </section>
105
+
106
+ <script>
107
+ function showTab(id){
108
+ document.querySelectorAll("section").forEach(s => s.classList.remove("active"));
109
+ document.getElementById(id).classList.add("active");
110
+ }
111
+
112
+ function generatePlanner(){
113
+ fetch("/planner", {
114
+ method:"POST",
115
+ headers:{'Content-Type':'application/json'},
116
+ body:JSON.stringify({
117
+ competence: document.getElementById("competence").value,
118
+ start_date: document.getElementById("start").value,
119
+ end_date: document.getElementById("end").value,
120
+ session_duration: document.getElementById("duration").value
121
+ })
122
+ }).then(r=>r.json()).then(data=>{
123
+ let html="";
124
+ data.forEach(p=>{
125
+ html+=`<div class="card">
126
+ 📆 ${p.date}<br>
127
+ 📘 ${p.competence}<br>
128
+ ⏱ ${p.duration} min<br>
129
+ 🔁 Répétition ${p.repetition}
130
+ </div>`;
131
+ });
132
+ document.getElementById("plannerContent").innerHTML = html;
133
+ showTab("planner");
134
+ });
135
+ }
136
+
137
+ function saveJournal(){
138
+ fetch("/journal",{
139
+ method:"POST",
140
+ headers:{'Content-Type':'application/json'},
141
+ body:JSON.stringify({
142
+ todo:todo.value,
143
+ doing:doing.value,
144
+ done:done.value,
145
+ reflection:[q1.value,q2.value,q3.value]
146
+ })
147
+ });
148
+ alert("Journal sauvegardé ✔");
149
+ }
150
+
151
+ function getReminder(){
152
+ fetch("/notifications").then(r=>r.json()).then(data=>{
153
+ document.getElementById("notifBox").innerText=data.message;
154
+ });
155
+ }
156
+ </script>
157
+
158
+ </body>
159
+ </html>
index.html ADDED
@@ -0,0 +1,1382 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Cognitive-Driven AI for Language Learning | Professionnel</title>
7
+
8
+ <!-- Chart.js pour les visualisations -->
9
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
10
+ <!-- Font Awesome pour les icônes -->
11
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
12
+
13
+ <style>
14
+ :root {
15
+ --primary-color: #3b82f6;
16
+ --secondary-color: #10b981;
17
+ --accent-color: #8b5cf6;
18
+ --warning-color: #f59e0b;
19
+ --danger-color: #ef4444;
20
+ --dark-color: #1e293b;
21
+ --light-color: #f8fafc;
22
+ --gray-color: #64748b;
23
+ }
24
+
25
+ * {
26
+ margin: 0;
27
+ padding: 0;
28
+ box-sizing: border-box;
29
+ }
30
+
31
+ body {
32
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
33
+ background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
34
+ color: var(--dark-color);
35
+ line-height: 1.6;
36
+ min-height: 100vh;
37
+ }
38
+
39
+ .container {
40
+ max-width: 1400px;
41
+ margin: 0 auto;
42
+ padding: 20px;
43
+ }
44
+
45
+ /* Header */
46
+ .header {
47
+ background: linear-gradient(135deg, var(--dark-color) 0%, #0f172a 100%);
48
+ color: white;
49
+ padding: 2rem;
50
+ border-radius: 15px;
51
+ margin-bottom: 2rem;
52
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
53
+ position: relative;
54
+ overflow: hidden;
55
+ }
56
+
57
+ .header::before {
58
+ content: '';
59
+ position: absolute;
60
+ top: 0;
61
+ left: 0;
62
+ right: 0;
63
+ height: 4px;
64
+ background: linear-gradient(90deg, var(--primary-color), var(--secondary-color), var(--accent-color));
65
+ }
66
+
67
+ .header h1 {
68
+ font-size: 2.5rem;
69
+ margin-bottom: 0.5rem;
70
+ display: flex;
71
+ align-items: center;
72
+ gap: 15px;
73
+ }
74
+
75
+ .header p {
76
+ font-size: 1.1rem;
77
+ opacity: 0.9;
78
+ max-width: 800px;
79
+ }
80
+
81
+ .badge {
82
+ background: var(--primary-color);
83
+ color: white;
84
+ padding: 5px 15px;
85
+ border-radius: 20px;
86
+ font-size: 0.9rem;
87
+ display: inline-block;
88
+ margin-top: 10px;
89
+ }
90
+
91
+ /* Navigation */
92
+ .nav-tabs {
93
+ display: flex;
94
+ background: white;
95
+ border-radius: 12px;
96
+ overflow: hidden;
97
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
98
+ margin-bottom: 2rem;
99
+ flex-wrap: wrap;
100
+ }
101
+
102
+ .nav-tab {
103
+ flex: 1;
104
+ min-width: 200px;
105
+ padding: 1.2rem;
106
+ border: none;
107
+ background: transparent;
108
+ color: var(--gray-color);
109
+ font-size: 1rem;
110
+ font-weight: 600;
111
+ cursor: pointer;
112
+ display: flex;
113
+ align-items: center;
114
+ justify-content: center;
115
+ gap: 10px;
116
+ transition: all 0.3s ease;
117
+ }
118
+
119
+ .nav-tab:hover {
120
+ background: #f8fafc;
121
+ color: var(--primary-color);
122
+ }
123
+
124
+ .nav-tab.active {
125
+ background: var(--primary-color);
126
+ color: white;
127
+ box-shadow: 0 5px 15px rgba(59, 130, 246, 0.3);
128
+ }
129
+
130
+ /* Sections */
131
+ .tab-content {
132
+ display: none;
133
+ animation: fadeIn 0.5s ease;
134
+ }
135
+
136
+ .tab-content.active {
137
+ display: block;
138
+ }
139
+
140
+ @keyframes fadeIn {
141
+ from { opacity: 0; transform: translateY(10px); }
142
+ to { opacity: 1; transform: translateY(0); }
143
+ }
144
+
145
+ .card {
146
+ background: white;
147
+ border-radius: 15px;
148
+ padding: 2rem;
149
+ margin-bottom: 2rem;
150
+ box-shadow: 0 5px 20px rgba(0, 0, 0, 0.05);
151
+ border-left: 5px solid var(--primary-color);
152
+ }
153
+
154
+ .card-header {
155
+ display: flex;
156
+ justify-content: space-between;
157
+ align-items: center;
158
+ margin-bottom: 1.5rem;
159
+ padding-bottom: 1rem;
160
+ border-bottom: 2px solid #f1f5f9;
161
+ }
162
+
163
+ .card-header h3 {
164
+ font-size: 1.5rem;
165
+ color: var(--dark-color);
166
+ display: flex;
167
+ align-items: center;
168
+ gap: 10px;
169
+ }
170
+
171
+ /* Form Elements */
172
+ .form-group {
173
+ margin-bottom: 1.5rem;
174
+ }
175
+
176
+ .form-label {
177
+ display: block;
178
+ margin-bottom: 0.5rem;
179
+ font-weight: 600;
180
+ color: var(--dark-color);
181
+ display: flex;
182
+ align-items: center;
183
+ gap: 8px;
184
+ }
185
+
186
+ .form-control {
187
+ width: 100%;
188
+ padding: 12px 15px;
189
+ border: 2px solid #e2e8f0;
190
+ border-radius: 10px;
191
+ font-size: 1rem;
192
+ transition: all 0.3s;
193
+ background: #f8fafc;
194
+ }
195
+
196
+ .form-control:focus {
197
+ outline: none;
198
+ border-color: var(--primary-color);
199
+ background: white;
200
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
201
+ }
202
+
203
+ .form-row {
204
+ display: flex;
205
+ gap: 20px;
206
+ margin-bottom: 1.5rem;
207
+ }
208
+
209
+ .form-col {
210
+ flex: 1;
211
+ }
212
+
213
+ /* Buttons */
214
+ .btn {
215
+ padding: 12px 25px;
216
+ border: none;
217
+ border-radius: 10px;
218
+ font-size: 1rem;
219
+ font-weight: 600;
220
+ cursor: pointer;
221
+ transition: all 0.3s;
222
+ display: inline-flex;
223
+ align-items: center;
224
+ justify-content: center;
225
+ gap: 10px;
226
+ }
227
+
228
+ .btn-primary {
229
+ background: linear-gradient(135deg, var(--primary-color) 0%, #2563eb 100%);
230
+ color: white;
231
+ }
232
+
233
+ .btn-primary:hover {
234
+ transform: translateY(-2px);
235
+ box-shadow: 0 10px 20px rgba(59, 130, 246, 0.3);
236
+ }
237
+
238
+ .btn-secondary {
239
+ background: var(--secondary-color);
240
+ color: white;
241
+ }
242
+
243
+ .btn-large {
244
+ padding: 15px 30px;
245
+ font-size: 1.1rem;
246
+ }
247
+
248
+ /* Visualizations */
249
+ .visualization-container {
250
+ background: white;
251
+ border-radius: 15px;
252
+ padding: 2rem;
253
+ margin-top: 2rem;
254
+ box-shadow: 0 5px 20px rgba(0, 0, 0, 0.05);
255
+ }
256
+
257
+ .chart-container {
258
+ position: relative;
259
+ height: 400px;
260
+ width: 100%;
261
+ }
262
+
263
+ /* Planner Cards */
264
+ .planning-grid {
265
+ display: grid;
266
+ grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
267
+ gap: 20px;
268
+ margin-top: 2rem;
269
+ }
270
+
271
+ .session-card {
272
+ background: white;
273
+ border-radius: 12px;
274
+ padding: 1.5rem;
275
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
276
+ border-top: 4px solid var(--primary-color);
277
+ transition: transform 0.3s;
278
+ }
279
+
280
+ .session-card:hover {
281
+ transform: translateY(-5px);
282
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
283
+ }
284
+
285
+ .session-header {
286
+ display: flex;
287
+ justify-content: space-between;
288
+ align-items: flex-start;
289
+ margin-bottom: 1rem;
290
+ }
291
+
292
+ .session-date {
293
+ font-size: 1.2rem;
294
+ font-weight: bold;
295
+ color: var(--dark-color);
296
+ }
297
+
298
+ .session-repetition {
299
+ background: var(--primary-color);
300
+ color: white;
301
+ padding: 5px 15px;
302
+ border-radius: 20px;
303
+ font-size: 0.9rem;
304
+ }
305
+
306
+ .session-details {
307
+ margin-top: 1rem;
308
+ display: flex;
309
+ flex-direction: column;
310
+ gap: 8px;
311
+ }
312
+
313
+ .detail-item {
314
+ display: flex;
315
+ justify-content: space-between;
316
+ padding: 5px 0;
317
+ border-bottom: 1px dashed #e2e8f0;
318
+ }
319
+
320
+ /* Notifications */
321
+ .notification-card {
322
+ background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
323
+ border-left: 5px solid var(--warning-color);
324
+ padding: 1.5rem;
325
+ border-radius: 12px;
326
+ margin-bottom: 1rem;
327
+ animation: slideIn 0.5s ease;
328
+ }
329
+
330
+ @keyframes slideIn {
331
+ from { transform: translateX(-20px); opacity: 0; }
332
+ to { transform: translateX(0); opacity: 1; }
333
+ }
334
+
335
+ /* Stats Cards */
336
+ .stats-grid {
337
+ display: grid;
338
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
339
+ gap: 20px;
340
+ margin-top: 2rem;
341
+ }
342
+
343
+ .stat-card {
344
+ background: white;
345
+ border-radius: 12px;
346
+ padding: 1.5rem;
347
+ text-align: center;
348
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
349
+ }
350
+
351
+ .stat-value {
352
+ font-size: 2.5rem;
353
+ font-weight: bold;
354
+ color: var(--primary-color);
355
+ margin: 10px 0;
356
+ }
357
+
358
+ .stat-label {
359
+ color: var(--gray-color);
360
+ font-size: 0.9rem;
361
+ }
362
+
363
+ /* Quality Indicators */
364
+ .quality-indicator {
365
+ display: flex;
366
+ gap: 10px;
367
+ margin: 15px 0;
368
+ }
369
+
370
+ .quality-dot {
371
+ width: 25px;
372
+ height: 25px;
373
+ border-radius: 50%;
374
+ cursor: pointer;
375
+ transition: all 0.3s;
376
+ }
377
+
378
+ .quality-dot:hover {
379
+ transform: scale(1.2);
380
+ }
381
+
382
+ .quality-0 { background: linear-gradient(135deg, #ef4444, #dc2626); }
383
+ .quality-1 { background: linear-gradient(135deg, #f59e0b, #d97706); }
384
+ .quality-2 { background: linear-gradient(135deg, #10b981, #059669); }
385
+ .quality-3 { background: linear-gradient(135deg, #3b82f6, #1d4ed8); }
386
+
387
+ .quality-dot.active {
388
+ box-shadow: 0 0 0 3px white, 0 0 0 6px currentColor;
389
+ }
390
+
391
+ /* Responsive */
392
+ @media (max-width: 768px) {
393
+ .form-row {
394
+ flex-direction: column;
395
+ gap: 0;
396
+ }
397
+
398
+ .nav-tabs {
399
+ flex-direction: column;
400
+ }
401
+
402
+ .planning-grid {
403
+ grid-template-columns: 1fr;
404
+ }
405
+
406
+ .header h1 {
407
+ font-size: 2rem;
408
+ }
409
+ }
410
+ </style>
411
+ </head>
412
+ <body>
413
+ <div class="container">
414
+ <!-- Header -->
415
+ <header class="header">
416
+ <h1><i class="fas fa-brain"></i> Cognitive-Driven AI for Language Learning</h1>
417
+ <p>Optimizing Long-Term Memory Retention through Spaced Repetition (SM-2), Self-Regulated Learning, Metacognition, and Gentle Reminders via Multi-Armed Bandits</p>
418
+ <div class="badge">Version Professionnelle 2.0 | SM-2 Niveau Avancé</div>
419
+ </header>
420
+
421
+ <!-- Navigation -->
422
+ <nav class="nav-tabs">
423
+ <button class="nav-tab active" onclick="showTab('objectif')">
424
+ <i class="fas fa-bullseye"></i> Objectif
425
+ </button>
426
+ <button class="nav-tab" onclick="showTab('planner')">
427
+ <i class="fas fa-calendar-alt"></i> Planner SM-2
428
+ </button>
429
+ <button class="nav-tab" onclick="showTab('journal')">
430
+ <i class="fas fa-book"></i> Journal SRL
431
+ </button>
432
+ <button class="nav-tab" onclick="showTab('notifications')">
433
+ <i class="fas fa-bell"></i> Notifications IA
434
+ </button>
435
+ <button class="nav-tab" onclick="showTab('stats')">
436
+ <i class="fas fa-chart-line"></i> Statistiques
437
+ </button>
438
+ <button class="nav-tab" onclick="showTab('learn')">
439
+ <i class="fas fa-graduation-cap"></i> Apprendre SM-2
440
+ </button>
441
+ </nav>
442
+
443
+ <!-- Objectif Section -->
444
+ <section id="objectif" class="tab-content active">
445
+ <div class="card">
446
+ <div class="card-header">
447
+ <h3><i class="fas fa-bullseye"></i> Définir mon Objectif d'Apprentissage</h3>
448
+ </div>
449
+
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>
457
+ <div class="form-col">
458
+ <label class="form-label"><i class="fas fa-brain"></i> Niveau Actuel</label>
459
+ <select id="level" class="form-control">
460
+ <option value="0">Débutant</option>
461
+ <option value="1" selected>Intermédiaire</option>
462
+ <option value="2">Avancé</option>
463
+ <option value="3">Expert</option>
464
+ </select>
465
+ </div>
466
+ </div>
467
+
468
+ <div class="form-row">
469
+ <div class="form-col">
470
+ <label class="form-label"><i class="fas fa-calendar-start"></i> Date de Début</label>
471
+ <input type="date" id="start" class="form-control" value="2026-01-29">
472
+ </div>
473
+ <div class="form-col">
474
+ <label class="form-label"><i class="fas fa-calendar-end"></i> Date de Fin</label>
475
+ <input type="date" id="end" class="form-control" value="2026-12-31">
476
+ </div>
477
+ </div>
478
+
479
+ <div class="form-group">
480
+ <label class="form-label"><i class="fas fa-clock"></i> Durée par Session (minutes)</label>
481
+ <select id="duration" class="form-control">
482
+ <option value="10">10 minutes (Micro-learning)</option>
483
+ <option value="20" selected>20 minutes (Optimal)</option>
484
+ <option value="30">30 minutes (Approfondissement)</option>
485
+ <option value="45">45 minutes (Session intensive)</option>
486
+ </select>
487
+ </div>
488
+
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()">
501
+ <i class="fas fa-cogs"></i> Générer le Planner SM-2
502
+ </button>
503
+
504
+ <div id="preview" style="display: none; margin-top: 2rem;">
505
+ <h4><i class="fas fa-eye"></i> Aperçu de la Courbe SM-2</h4>
506
+ <div class="chart-container">
507
+ <canvas id="intervalChart"></canvas>
508
+ </div>
509
+ </div>
510
+ </div>
511
+ </section>
512
+
513
+ <!-- Planner Section -->
514
+ <section id="planner" class="tab-content">
515
+ <div class="card">
516
+ <div class="card-header">
517
+ <h3><i class="fas fa-calendar-alt"></i> Planner SM-2 Personnalisé</h3>
518
+ <button class="btn btn-secondary" onclick="exportPlanner()">
519
+ <i class="fas fa-download"></i> Exporter
520
+ </button>
521
+ </div>
522
+
523
+ <div id="plannerStats" class="stats-grid"></div>
524
+
525
+ <div id="plannerContent" class="planning-grid"></div>
526
+
527
+ <div class="visualization-container">
528
+ <h4><i class="fas fa-chart-line"></i> Visualisation des Intervalles SM-2</h4>
529
+ <div class="chart-container">
530
+ <canvas id="sm2Visualization"></canvas>
531
+ </div>
532
+ </div>
533
+ </div>
534
+ </section>
535
+
536
+ <!-- Journal Section -->
537
+ <section id="journal" class="tab-content">
538
+ <div class="card">
539
+ <div class="card-header">
540
+ <h3><i class="fas fa-book"></i> Journal d'Apprentissage Autorégulé</h3>
541
+ <button class="btn btn-secondary" onclick="loadJournalEntries()">
542
+ <i class="fas fa-history"></i> Historique
543
+ </button>
544
+ </div>
545
+
546
+ <div class="form-row">
547
+ <div class="form-col">
548
+ <label class="form-label"><i class="fas fa-tasks"></i> Planifié (To-Do)</label>
549
+ <textarea id="todo" class="form-control" rows="3" placeholder="Ce que vous prévoyez d'apprendre..."></textarea>
550
+ </div>
551
+ <div class="form-col">
552
+ <label class="form-label"><i class="fas fa-spinner"></i> En Cours (Doing)</label>
553
+ <textarea id="doing" class="form-control" rows="3" placeholder="Ce que vous faites actuellement..."></textarea>
554
+ </div>
555
+ </div>
556
+
557
+ <div class="form-group">
558
+ <label class="form-label"><i class="fas fa-check-circle"></i> Accompli (Done)</label>
559
+ <textarea id="done" class="form-control" rows="3" placeholder="Ce que vous avez accompli..."></textarea>
560
+ </div>
561
+
562
+ <div class="form-group">
563
+ <label class="form-label"><i class="fas fa-star"></i> Auto-évaluation (1-5)</label>
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>
573
+
574
+ <div class="form-group">
575
+ <label class="form-label"><i class="fas fa-lightbulb"></i> Stratégie Métacognitive</label>
576
+ <textarea id="metacognition" class="form-control" rows="3" placeholder="Quelle stratégie avez-vous utilisée ? Que changeriez-vous ?"></textarea>
577
+ </div>
578
+
579
+ <button class="btn btn-primary btn-large" onclick="saveJournal()">
580
+ <i class="fas fa-save"></i> Sauvegarder l'Entrée
581
+ </button>
582
+
583
+ <div id="journalHistory" style="display: none; margin-top: 2rem;">
584
+ <h4><i class="fas fa-history"></i> Dernières Entrées</h4>
585
+ <div id="journalEntries"></div>
586
+ </div>
587
+ </div>
588
+ </section>
589
+
590
+ <!-- Notifications Section -->
591
+ <section id="notifications" class="tab-content">
592
+ <div class="card">
593
+ <div class="card-header">
594
+ <h3><i class="fas fa-bell"></i> Notifications Intelligentes par Bandits Multi-Bras</h3>
595
+ <button class="btn btn-secondary" onclick="getIntelligentReminder()">
596
+ <i class="fas fa-sync"></i> Nouveau Rappel
597
+ </button>
598
+ </div>
599
+
600
+ <div id="notificationContainer">
601
+ <div class="notification-card">
602
+ <p><i class="fas fa-info-circle"></i> Cliquez sur "Nouveau Rappel" pour recevoir une notification personnalisée basée sur vos habitudes d'apprentissage.</p>
603
+ </div>
604
+ </div>
605
+
606
+ <div class="visualization-container">
607
+ <h4><i class="fas fa-chart-bar"></i> Efficacité des Types de Notifications</h4>
608
+ <div class="chart-container">
609
+ <canvas id="notificationChart"></canvas>
610
+ </div>
611
+ </div>
612
+ </div>
613
+ </section>
614
+
615
+ <!-- Statistics Section -->
616
+ <section id="stats" class="tab-content">
617
+ <div class="card">
618
+ <div class="card-header">
619
+ <h3><i class="fas fa-chart-line"></i> Tableau de Bord d'Apprentissage</h3>
620
+ <button class="btn btn-secondary" onclick="refreshStats()">
621
+ <i class="fas fa-redo"></i> Actualiser
622
+ </button>
623
+ </div>
624
+
625
+ <div id="statsContainer" class="stats-grid"></div>
626
+
627
+ <div class="visualization-container">
628
+ <h4><i class="fas fa-chart-area"></i> Progression de la Rétention</h4>
629
+ <div class="chart-container">
630
+ <canvas id="retentionChart"></canvas>
631
+ </div>
632
+ </div>
633
+ </div>
634
+ </section>
635
+
636
+ <!-- Learn SM-2 Section -->
637
+ <section id="learn" class="tab-content">
638
+ <div class="card">
639
+ <div class="card-header">
640
+ <h3><i class="fas fa-graduation-cap"></i> Apprendre l'Algorithme SM-2</h3>
641
+ </div>
642
+
643
+ <div id="sm2Explanation"></div>
644
+
645
+ <div class="visualization-container">
646
+ <h4><i class="fas fa-chart-network"></i> Comparaison des Niveaux de Qualité SM-2</h4>
647
+ <div class="chart-container">
648
+ <canvas id="comparisonChart"></canvas>
649
+ </div>
650
+ </div>
651
+ </div>
652
+ </section>
653
+ </div>
654
+
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
670
+ function showTab(tabId) {
671
+ // Masquer toutes les sections
672
+ document.querySelectorAll('.tab-content').forEach(section => {
673
+ section.classList.remove('active');
674
+ });
675
+
676
+ // Désactiver tous les onglets
677
+ document.querySelectorAll('.nav-tab').forEach(tab => {
678
+ tab.classList.remove('active');
679
+ });
680
+
681
+ // Activer la section sélectionnée
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
+ });
690
+
691
+ // Actions spécifiques par onglet
692
+ if (tabId === 'stats') {
693
+ refreshStats();
694
+ } else if (tabId === 'learn') {
695
+ updateComparisonChart();
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 {
714
+ const response = await fetch('/api/competences');
715
+ const competences = await response.json();
716
+
717
+ const select = document.getElementById('competence');
718
+ select.innerHTML = '<option value="">Sélectionnez une compétence...</option>';
719
+
720
+ competences.forEach(comp => {
721
+ const option = document.createElement('option');
722
+ option.value = comp.label;
723
+ option.textContent = `${comp.id} - ${comp.label} (${comp.category})`;
724
+ select.appendChild(option);
725
+ });
726
+ } catch (error) {
727
+ console.error('Erreur chargement compétences:', error);
728
+ }
729
+ }
730
+
731
+ // Sélection de la qualité
732
+ function selectQuality(level) {
733
+ currentQuality = level;
734
+
735
+ // Mettre à jour les indicateurs visuels
736
+ document.querySelectorAll('.quality-dot').forEach(dot => {
737
+ dot.classList.remove('active');
738
+ });
739
+
740
+ document.querySelector(`.quality-dot[data-quality="${level}"]`).classList.add('active');
741
+
742
+ // Mettre à jour la description
743
+ const descriptions = [
744
+ "Difficulté - Révision fréquente nécessaire",
745
+ "Moyen - Intervalles standard recommandés",
746
+ "Bon - Consolidation progressive",
747
+ "Excellent - Rétention à long terme optimale"
748
+ ];
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);
781
+ }
782
+ }
783
+
784
+ // Générer le planner
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
+
796
+ try {
797
+ const response = await fetch('/api/planner/generate', {
798
+ method: 'POST',
799
+ headers: { 'Content-Type': 'application/json' },
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
+ });
808
+
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);
816
+ }
817
+ } catch (error) {
818
+ console.error('Erreur génération planner:', error);
819
+ alert('Erreur lors de la génération du planner');
820
+ }
821
+ }
822
+
823
+ // Afficher le planner
824
+ function displayPlanner(plan, intervals) {
825
+ const container = document.getElementById('plannerContent');
826
+ const statsContainer = document.getElementById('plannerStats');
827
+
828
+ // Statistiques
829
+ statsContainer.innerHTML = `
830
+ <div class="stat-card">
831
+ <div class="stat-value">${plan.length}</div>
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">
839
+ <div class="stat-value">${currentQuality + 1}/4</div>
840
+ <div class="stat-label">Niveau de Qualité</div>
841
+ </div>
842
+ <div class="stat-card">
843
+ <div class="stat-value">${document.getElementById('duration').value}min</div>
844
+ <div class="stat-label">Durée/Session</div>
845
+ </div>
846
+ `;
847
+
848
+ // Sessions
849
+ container.innerHTML = '';
850
+ plan.forEach(session => {
851
+ const card = document.createElement('div');
852
+ card.className = 'session-card';
853
+ card.innerHTML = `
854
+ <div class="session-header">
855
+ <div class="session-date">
856
+ <i class="fas fa-calendar-day"></i> ${session.date}
857
+ <div style="font-size: 0.9rem; color: #64748b;">${session.jour}</div>
858
+ </div>
859
+ <div class="session-repetition">
860
+ R${session.repetition}
861
+ </div>
862
+ </div>
863
+ <h4 style="margin: 10px 0; color: #1e293b;">${session.competence}</h4>
864
+ <div class="session-details">
865
+ <div class="detail-item">
866
+ <span><i class="fas fa-clock"></i> Durée</span>
867
+ <span>${session.duree}</span>
868
+ </div>
869
+ <div class="detail-item">
870
+ <span><i class="fas fa-sync-alt"></i> Intervalle</span>
871
+ <span>${session.intervalle}</span>
872
+ </div>
873
+ <div class="detail-item">
874
+ <span><i class="fas fa-bullseye"></i> Type</span>
875
+ <span>${session.type}</span>
876
+ </div>
877
+ <div class="detail-item">
878
+ <span><i class="fas fa-lightbulb"></i> Stratégie</span>
879
+ <span>${session.strategie}</span>
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);
887
+ });
888
+
889
+ // Visualisation
890
+ createSM2Visualization(intervals, plan[0]?.competence || 'Compétence');
891
+ }
892
+
893
+ // Créer la visualisation SM-2
894
+ function createSM2Visualization(intervals, competence) {
895
+ const ctx = document.getElementById('sm2Visualization').getContext('2d');
896
+
897
+ if (currentChart) {
898
+ currentChart.destroy();
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',
906
+ data: {
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,
914
+ fill: true,
915
+ tension: 0.4
916
+ }]
917
+ },
918
+ options: {
919
+ responsive: true,
920
+ maintainAspectRatio: false,
921
+ plugins: {
922
+ title: {
923
+ display: true,
924
+ text: `Courbe de Répétition Espacée - ${competence}`,
925
+ font: { size: 16 }
926
+ },
927
+ tooltip: {
928
+ callbacks: {
929
+ label: function(context) {
930
+ return `Intervalle: ${context.raw} jours`;
931
+ }
932
+ }
933
+ }
934
+ },
935
+ scales: {
936
+ y: {
937
+ beginAtZero: true,
938
+ title: {
939
+ display: true,
940
+ text: 'Jours'
941
+ }
942
+ },
943
+ x: {
944
+ title: {
945
+ display: true,
946
+ text: 'Numéro de Répétition'
947
+ }
948
+ }
949
+ }
950
+ }
951
+ });
952
+ }
953
+
954
+ // Journal
955
+ function setEvaluation(score) {
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
+ }
963
+
964
+ async function saveJournal() {
965
+ const entry = {
966
+ todo: document.getElementById('todo').value,
967
+ doing: document.getElementById('doing').value,
968
+ done: document.getElementById('done').value,
969
+ metacognition: document.getElementById('metacognition').value,
970
+ auto_eval: document.getElementById('auto_eval').value,
971
+ competence: document.getElementById('competence').value,
972
+ timestamp: new Date().toISOString()
973
+ };
974
+
975
+ try {
976
+ const response = await fetch('/api/journal', {
977
+ method: 'POST',
978
+ headers: { 'Content-Type': 'application/json' },
979
+ body: JSON.stringify(entry)
980
+ });
981
+
982
+ const result = await response.json();
983
+
984
+ if (result.success) {
985
+ alert('✅ Journal sauvegardé avec succès !');
986
+ clearJournalForm();
987
+ } else {
988
+ alert('Erreur: ' + result.error);
989
+ }
990
+ } catch (error) {
991
+ console.error('Erreur sauvegarde journal:', error);
992
+ alert('Erreur lors de la sauvegarde');
993
+ }
994
+ }
995
+
996
+ function clearJournalForm() {
997
+ document.getElementById('todo').value = '';
998
+ document.getElementById('doing').value = '';
999
+ document.getElementById('done').value = '';
1000
+ document.getElementById('metacognition').value = '';
1001
+ setEvaluation(3);
1002
+ }
1003
+
1004
+ async function loadJournalEntries() {
1005
+ try {
1006
+ const response = await fetch('/api/journal/entries?limit=5');
1007
+ const entries = await response.json();
1008
+
1009
+ const container = document.getElementById('journalEntries');
1010
+ container.innerHTML = '';
1011
+
1012
+ entries.forEach(entry => {
1013
+ const div = document.createElement('div');
1014
+ div.className = 'session-card';
1015
+ div.innerHTML = `
1016
+ <div class="session-header">
1017
+ <div class="session-date">
1018
+ ${new Date(entry.timestamp).toLocaleDateString('fr-FR')}
1019
+ </div>
1020
+ <div style="background: #10b981; color: white; padding: 5px 15px; border-radius: 20px;">
1021
+ ${entry.auto_eval || '?'}/5
1022
+ </div>
1023
+ </div>
1024
+ ${entry.competence ? `<div style="color: #3b82f6; margin: 5px 0;"><i class="fas fa-language"></i> ${entry.competence}</div>` : ''}
1025
+ ${entry.done ? `<div style="margin-top: 10px;"><strong>Accompli:</strong> ${entry.done.substring(0, 100)}...</div>` : ''}
1026
+ `;
1027
+ container.appendChild(div);
1028
+ });
1029
+
1030
+ document.getElementById('journalHistory').style.display = 'block';
1031
+ } catch (error) {
1032
+ console.error('Erreur chargement journal:', error);
1033
+ }
1034
+ }
1035
+
1036
+ // Notifications
1037
+ async function getIntelligentReminder() {
1038
+ try {
1039
+ const response = await fetch('/api/notifications/intelligent');
1040
+ const data = await response.json();
1041
+
1042
+ const container = document.getElementById('notificationContainer');
1043
+ const card = document.createElement('div');
1044
+ card.className = 'notification-card';
1045
+
1046
+ const icons = {
1047
+ 'motivation': '🌱',
1048
+ 'rappel_court': '⏰',
1049
+ 'encouragement': '💪',
1050
+ 'metacognition': '🤔'
1051
+ };
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>
1061
+ </div>
1062
+ </div>
1063
+ <p style="font-size: 1.1rem; line-height: 1.5;">${data.message}</p>
1064
+ <div style="margin-top: 10px; font-size: 0.8rem; color: #64748b; text-align: right;">
1065
+ ${new Date(data.timestamp).toLocaleTimeString('fr-FR')}
1066
+ </div>
1067
+ `;
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 {
1148
+ const response = await fetch('/api/learner/stats');
1149
+ const stats = await response.json();
1150
+
1151
+ const container = document.getElementById('statsContainer');
1152
+ container.innerHTML = `
1153
+ <div class="stat-card">
1154
+ <div class="stat-value">${stats.total_sessions}</div>
1155
+ <div class="stat-label">Sessions Complétées</div>
1156
+ </div>
1157
+ <div class="stat-card">
1158
+ <div class="stat-value">${stats.success_rate.toFixed(2)}/5</div>
1159
+ <div class="stat-label">Score Moyen</div>
1160
+ </div>
1161
+ <div class="stat-card">
1162
+ <div class="stat-value">${stats.journal_entries}</div>
1163
+ <div class="stat-label">Entrées Journal</div>
1164
+ </div>
1165
+ <div class="stat-card">
1166
+ <div class="stat-value">${stats.planned_sessions}</div>
1167
+ <div class="stat-label">Sessions Planifiées</div>
1168
+ </div>
1169
+ <div class="stat-card">
1170
+ <div class="stat-value" style="color: ${stats.engagement_level === 'high' ? '#10b981' : stats.engagement_level === 'medium' ? '#f59e0b' : '#ef4444'}">
1171
+ ${stats.engagement_level}
1172
+ </div>
1173
+ <div class="stat-label">Niveau d'Engagement</div>
1174
+ </div>
1175
+ <div class="stat-card">
1176
+ <div class="stat-value" style="color: ${stats.risk_level === 'low' ? '#10b981' : stats.risk_level === 'medium' ? '#f59e0b' : '#ef4444'}">
1177
+ ${stats.risk_level}
1178
+ </div>
1179
+ <div class="stat-label">Niveau de Risque</div>
1180
+ </div>
1181
+ `;
1182
+
1183
+ // Mettre à jour le graphique de rétention
1184
+ updateRetentionChart(stats);
1185
+
1186
+ } catch (error) {
1187
+ console.error('Erreur statistiques:', error);
1188
+ }
1189
+ }
1190
+
1191
+ function updateRetentionChart(stats) {
1192
+ const ctx = document.getElementById('retentionChart').getContext('2d');
1193
+
1194
+ if (window.retentionChart) {
1195
+ window.retentionChart.destroy();
1196
+ }
1197
+
1198
+ // Données simulées pour la démonstration
1199
+ const labels = ['Sem 1', 'Sem 2', 'Sem 3', 'Sem 4', 'Sem 5', 'Sem 6'];
1200
+ const retentionData = [0.3, 0.5, 0.65, 0.75, 0.8, 0.85];
1201
+ const engagementData = [0.7, 0.8, 0.75, 0.85, 0.9, 0.88];
1202
+
1203
+ window.retentionChart = new Chart(ctx, {
1204
+ type: 'line',
1205
+ data: {
1206
+ labels: labels,
1207
+ datasets: [
1208
+ {
1209
+ label: 'Taux de Rétention',
1210
+ data: retentionData,
1211
+ borderColor: '#3b82f6',
1212
+ backgroundColor: 'rgba(59, 130, 246, 0.1)',
1213
+ borderWidth: 3,
1214
+ fill: true,
1215
+ tension: 0.4
1216
+ },
1217
+ {
1218
+ label: 'Niveau d\'Engagement',
1219
+ data: engagementData,
1220
+ borderColor: '#10b981',
1221
+ backgroundColor: 'rgba(16, 185, 129, 0.1)',
1222
+ borderWidth: 3,
1223
+ fill: true,
1224
+ tension: 0.4
1225
+ }
1226
+ ]
1227
+ },
1228
+ options: {
1229
+ responsive: true,
1230
+ maintainAspectRatio: false,
1231
+ scales: {
1232
+ y: {
1233
+ beginAtZero: true,
1234
+ max: 1,
1235
+ ticks: {
1236
+ callback: function(value) {
1237
+ return (value * 100) + '%';
1238
+ }
1239
+ }
1240
+ }
1241
+ },
1242
+ plugins: {
1243
+ tooltip: {
1244
+ callbacks: {
1245
+ label: function(context) {
1246
+ return context.dataset.label + ': ' + (context.raw * 100).toFixed(1) + '%';
1247
+ }
1248
+ }
1249
+ }
1250
+ }
1251
+ }
1252
+ });
1253
+ }
1254
+
1255
+ // Apprendre SM-2
1256
+ async function loadSM2Explanation() {
1257
+ try {
1258
+ const response = await fetch('/api/sm2/explain');
1259
+ const explanation = await response.json();
1260
+
1261
+ const container = document.getElementById('sm2Explanation');
1262
+ container.innerHTML = `
1263
+ <div class="card" style="margin-bottom: 20px;">
1264
+ <h3 style="color: #3b82f6; margin-bottom: 15px;">${explanation.title}</h3>
1265
+ <p style="margin-bottom: 20px; line-height: 1.6;">${explanation.description}</p>
1266
+
1267
+ <h4 style="margin-bottom: 15px; color: #1e293b;"><i class="fas fa-layer-group"></i> Niveaux de Qualité</h4>
1268
+ <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 15px; margin-bottom: 20px;">
1269
+ ${Object.entries(explanation.quality_levels).map(([level, desc]) => `
1270
+ <div style="padding: 15px; background: #f8fafc; border-radius: 10px; border-left: 4px solid ${getQualityColor(level)};">
1271
+ <div style="font-weight: bold; color: ${getQualityColor(level)};">Niveau ${level}</div>
1272
+ <div style="font-size: 0.9rem; color: #64748b;">${desc}</div>
1273
+ </div>
1274
+ `).join('')}
1275
+ </div>
1276
+
1277
+ <h4 style="margin-bottom: 15px; color: #1e293b;"><i class="fas fa-lightbulb"></i> Principes Fondamentaux</h4>
1278
+ <ul style="margin-bottom: 20px; padding-left: 20px;">
1279
+ ${explanation.principles.map(principle => `
1280
+ <li style="margin-bottom: 10px; line-height: 1.5;">${principle}</li>
1281
+ `).join('')}
1282
+ </ul>
1283
+
1284
+ <h4 style="margin-bottom: 15px; color: #1e293b;"><i class="fas fa-check-circle"></i> Recommandations</h4>
1285
+ <ul style="padding-left: 20px;">
1286
+ ${explanation.recommendations.map(recommendation => `
1287
+ <li style="margin-bottom: 10px; line-height: 1.5;">${recommendation}</li>
1288
+ `).join('')}
1289
+ </ul>
1290
+ </div>
1291
+ `;
1292
+ } catch (error) {
1293
+ console.error('Erreur chargement explication SM-2:', error);
1294
+ }
1295
+ }
1296
+
1297
+ function getQualityColor(level) {
1298
+ const colors = ['#ef4444', '#f59e0b', '#10b981', '#3b82f6'];
1299
+ return colors[parseInt(level)] || colors[0];
1300
+ }
1301
+
1302
+ function updateComparisonChart() {
1303
+ const ctx = document.getElementById('comparisonChart').getContext('2d');
1304
+
1305
+ if (window.comparisonChart) {
1306
+ window.comparisonChart.destroy();
1307
+ }
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'];
1318
+ const colors = ['#ef4444', '#f59e0b', '#10b981', '#3b82f6'];
1319
+
1320
+ const datasets = Object.entries(intervals).map(([label, data], index) => ({
1321
+ label: label,
1322
+ data: data,
1323
+ borderColor: colors[index],
1324
+ backgroundColor: colors[index] + '20',
1325
+ borderWidth: 2,
1326
+ tension: 0.4,
1327
+ fill: false
1328
+ }));
1329
+
1330
+ window.comparisonChart = new Chart(ctx, {
1331
+ type: 'line',
1332
+ data: {
1333
+ labels: labels,
1334
+ datasets: datasets
1335
+ },
1336
+ options: {
1337
+ responsive: true,
1338
+ maintainAspectRatio: false,
1339
+ scales: {
1340
+ y: {
1341
+ beginAtZero: true,
1342
+ title: {
1343
+ display: true,
1344
+ text: 'Intervalle (jours)'
1345
+ },
1346
+ type: 'logarithmic'
1347
+ }
1348
+ },
1349
+ plugins: {
1350
+ title: {
1351
+ display: true,
1352
+ text: 'Comparaison des Courbes SM-2 par Niveau de Qualité',
1353
+ font: { size: 16 }
1354
+ },
1355
+ tooltip: {
1356
+ callbacks: {
1357
+ label: function(context) {
1358
+ return `${context.dataset.label}: ${context.raw} jours`;
1359
+ }
1360
+ }
1361
+ }
1362
+ }
1363
+ }
1364
+ });
1365
+ }
1366
+
1367
+ // Export
1368
+ function exportPlanner() {
1369
+ const plannerData = document.getElementById('plannerContent').innerText;
1370
+ const blob = new Blob([plannerData], { type: 'text/plain' });
1371
+ const url = URL.createObjectURL(blob);
1372
+ const a = document.createElement('a');
1373
+ a.href = url;
1374
+ a.download = 'planner-sm2.txt';
1375
+ document.body.appendChild(a);
1376
+ a.click();
1377
+ document.body.removeChild(a);
1378
+ URL.revokeObjectURL(url);
1379
+ }
1380
+ </script>
1381
+ </body>
1382
+ </html>