OUAREDAEK commited on
Commit
ff69b3c
·
verified ·
1 Parent(s): 50fa467

Upload templates/index-old33.html with huggingface_hub

Browse files
Files changed (1) hide show
  1. templates/index-old33.html +1465 -0
templates/index-old33.html ADDED
@@ -0,0 +1,1465 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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, user-scalable=yes">
6
+ <title>ReflAgent | Tableau de Recherche – Auto‑détermination & Analyse Réflexive (InclusionAI)</title>
7
+ <style>
8
+ /* ----- STYLES PROFESSIONNELS / RECHERCHE (épurés, académiques) ----- */
9
+ * {
10
+ margin: 0;
11
+ padding: 0;
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ body {
16
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, system-ui, sans-serif;
17
+ background: #f0f2f5;
18
+ color: #1e2a3a;
19
+ padding: 2rem 1.5rem;
20
+ line-height: 1.45;
21
+ }
22
+
23
+ .dashboard {
24
+ max-width: 1400px;
25
+ margin: 0 auto;
26
+ }
27
+
28
+ /* Cartes sobres */
29
+ .card {
30
+ background: #ffffff;
31
+ border-radius: 1rem;
32
+ box-shadow: 0 1px 3px rgba(0,0,0,0.04), 0 2px 6px rgba(0,0,0,0.02);
33
+ padding: 1.5rem 1.75rem;
34
+ margin-bottom: 1.75rem;
35
+ border: 1px solid #e2e8f0;
36
+ }
37
+
38
+ .card-header {
39
+ display: flex;
40
+ justify-content: space-between;
41
+ align-items: flex-end;
42
+ flex-wrap: wrap;
43
+ gap: 1rem;
44
+ margin-bottom: 1.25rem;
45
+ border-bottom: 1px solid #e9edf2;
46
+ padding-bottom: 0.75rem;
47
+ }
48
+
49
+ .card-header h2 {
50
+ font-size: 1.35rem;
51
+ font-weight: 600;
52
+ color: #0f172a;
53
+ letter-spacing: -0.2px;
54
+ }
55
+
56
+ .card-header h3 {
57
+ font-size: 1.1rem;
58
+ font-weight: 600;
59
+ color: #1e293b;
60
+ }
61
+
62
+ .badge {
63
+ background: #eef2ff;
64
+ padding: 0.2rem 0.7rem;
65
+ border-radius: 2rem;
66
+ font-size: 0.7rem;
67
+ font-weight: 500;
68
+ color: #1e40af;
69
+ font-family: monospace;
70
+ }
71
+
72
+ /* Onglets */
73
+ .tabs {
74
+ display: flex;
75
+ gap: 0.25rem;
76
+ margin-bottom: 1.75rem;
77
+ border-bottom: 1px solid #e2e8f0;
78
+ }
79
+ .tab-btn {
80
+ background: transparent;
81
+ border: none;
82
+ padding: 0.6rem 1.4rem;
83
+ font-size: 0.85rem;
84
+ font-weight: 500;
85
+ color: #4b5563;
86
+ cursor: pointer;
87
+ border-radius: 0;
88
+ transition: all 0.1s linear;
89
+ border-bottom: 2px solid transparent;
90
+ margin-bottom: -1px;
91
+ }
92
+ .tab-btn:hover {
93
+ color: #1e3a8a;
94
+ background: #f8fafc;
95
+ }
96
+ .tab-btn.active {
97
+ color: #1e40af;
98
+ border-bottom: 2px solid #1e40af;
99
+ font-weight: 600;
100
+ }
101
+ .tab-content {
102
+ display: none;
103
+ }
104
+ .tab-content.active {
105
+ display: block;
106
+ }
107
+
108
+ /* Grilles */
109
+ .grid-2col {
110
+ display: grid;
111
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
112
+ gap: 1.5rem;
113
+ }
114
+
115
+ /* Disposition côte à côte pour heatmap + analyse persistance */
116
+ .persistance-heatmap-container {
117
+ display: flex;
118
+ gap: 1.75rem;
119
+ flex-wrap: wrap;
120
+ margin: 1rem 0 1.5rem 0;
121
+ }
122
+
123
+ .persistance-card {
124
+ flex: 1.2;
125
+ min-width: 260px;
126
+ background: #fefefe;
127
+ border-radius: 1rem;
128
+ padding: 1rem 1.25rem;
129
+ border: 1px solid #e9edf2;
130
+ box-shadow: 0 1px 2px rgba(0,0,0,0.02);
131
+ }
132
+
133
+ .heatmap-card {
134
+ flex: 2.2;
135
+ min-width: 320px;
136
+ background: #fefefe;
137
+ border-radius: 1rem;
138
+ padding: 1rem 1.25rem;
139
+ border: 1px solid #e9edf2;
140
+ }
141
+
142
+ .section-title-sm {
143
+ font-size: 0.75rem;
144
+ font-weight: 600;
145
+ text-transform: uppercase;
146
+ letter-spacing: 0.5px;
147
+ color: #4b5563;
148
+ margin-bottom: 0.75rem;
149
+ border-left: 3px solid #3b82f6;
150
+ padding-left: 0.6rem;
151
+ }
152
+
153
+ .metrique-persistance-compact {
154
+ margin-bottom: 1.25rem;
155
+ }
156
+ .metrique-persistance-compact label {
157
+ display: block;
158
+ font-size: 0.7rem;
159
+ font-weight: 600;
160
+ text-transform: uppercase;
161
+ color: #4b5563;
162
+ margin-bottom: 0.2rem;
163
+ }
164
+ .valeur-persistance-compact {
165
+ font-size: 1.3rem;
166
+ font-weight: 700;
167
+ color: #0f172a;
168
+ }
169
+ .note-persistance-compact {
170
+ font-size: 0.65rem;
171
+ color: #5b6e8c;
172
+ margin-top: 0.2rem;
173
+ }
174
+ .slider-compact {
175
+ width: 100%;
176
+ margin-top: 0.4rem;
177
+ accent-color: #2563eb;
178
+ }
179
+ .select-compact {
180
+ width: 100%;
181
+ padding: 0.4rem 0.6rem;
182
+ border-radius: 2rem;
183
+ border: 1px solid #cbd5e1;
184
+ background: white;
185
+ font-size: 0.75rem;
186
+ margin-top: 0.4rem;
187
+ }
188
+
189
+ .control {
190
+ flex: 1;
191
+ min-width: 160px;
192
+ }
193
+ .control label {
194
+ display: block;
195
+ font-size: 0.7rem;
196
+ font-weight: 600;
197
+ text-transform: uppercase;
198
+ letter-spacing: 0.3px;
199
+ color: #4b5563;
200
+ margin-bottom: 0.3rem;
201
+ }
202
+ .control input, .control select, .control textarea {
203
+ width: 100%;
204
+ padding: 0.55rem 0.85rem;
205
+ border: 1px solid #cbd5e1;
206
+ border-radius: 0.5rem;
207
+ font-size: 0.85rem;
208
+ background: white;
209
+ font-family: inherit;
210
+ }
211
+ .control input:focus, .control select:focus, .control textarea:focus {
212
+ outline: none;
213
+ border-color: #3b82f6;
214
+ box-shadow: 0 0 0 2px rgba(59,130,246,0.15);
215
+ }
216
+
217
+ button {
218
+ background: #1e3a8a;
219
+ border: none;
220
+ padding: 0.55rem 1.25rem;
221
+ border-radius: 2rem;
222
+ font-weight: 500;
223
+ font-size: 0.75rem;
224
+ color: white;
225
+ cursor: pointer;
226
+ transition: background 0.15s;
227
+ display: inline-flex;
228
+ align-items: center;
229
+ gap: 0.5rem;
230
+ }
231
+ button:hover {
232
+ background: #1e40af;
233
+ }
234
+ .btn-secondaire {
235
+ background: #475569;
236
+ }
237
+ .btn-secondaire:hover {
238
+ background: #334155;
239
+ }
240
+
241
+ /* Compétences */
242
+ .grille-competences {
243
+ display: grid;
244
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
245
+ gap: 1rem;
246
+ margin-top: 0.5rem;
247
+ margin-bottom: 1.5rem;
248
+ }
249
+ .item-competence {
250
+ background: #fefefe;
251
+ border-radius: 0.75rem;
252
+ padding: 0.85rem 1rem;
253
+ border-left: 3px solid #3b82f6;
254
+ border-bottom: 1px solid #ecf3fa;
255
+ transition: all 0.1s;
256
+ }
257
+ .en-tete-competence {
258
+ display: flex;
259
+ justify-content: space-between;
260
+ align-items: baseline;
261
+ font-size: 0.8rem;
262
+ font-weight: 500;
263
+ margin-bottom: 0.5rem;
264
+ }
265
+ .valeur-competence {
266
+ font-weight: 600;
267
+ font-size: 0.85rem;
268
+ }
269
+ .legende-niveau {
270
+ display: inline-block;
271
+ font-size: 0.65rem;
272
+ font-weight: 500;
273
+ padding: 0.15rem 0.5rem;
274
+ border-radius: 2rem;
275
+ margin-left: 0.5rem;
276
+ }
277
+ .niveau-faible { background: #fee2e2; color: #991b1b; }
278
+ .niveau-moyen { background: #fef9c3; color: #854d0e; }
279
+ .niveau-eleve { background: #dcfce7; color: #166534; }
280
+ .curseur-competence {
281
+ width: 100%;
282
+ margin-top: 0.5rem;
283
+ accent-color: #2563eb;
284
+ }
285
+ .legende-competences {
286
+ display: flex;
287
+ gap: 1rem;
288
+ margin-bottom: 1rem;
289
+ padding: 0.5rem 0;
290
+ border-bottom: 1px dashed #e2e8f0;
291
+ font-size: 0.7rem;
292
+ }
293
+ .legende-item {
294
+ display: inline-flex;
295
+ align-items: center;
296
+ gap: 0.4rem;
297
+ }
298
+ .legende-couleur {
299
+ width: 14px;
300
+ height: 14px;
301
+ border-radius: 4px;
302
+ }
303
+ .legende-couleur.faible { background: #fee2e2; border: 1px solid #fecaca; }
304
+ .legende-couleur.moyen { background: #fef9c3; border: 1px solid #fde047; }
305
+ .legende-couleur.eleve { background: #dcfce7; border: 1px solid #bbf7d0; }
306
+
307
+ /* Radar */
308
+ .radar-wrapper {
309
+ display: flex;
310
+ justify-content: center;
311
+ align-items: center;
312
+ background: linear-gradient(145deg, #fafcff 0%, #ffffff 100%);
313
+ border-radius: 1.5rem;
314
+ padding: 1.25rem;
315
+ box-shadow: 0 8px 20px rgba(0,0,0,0.04), 0 2px 4px rgba(0,0,0,0.02);
316
+ }
317
+
318
+ #canvasRadar {
319
+ display: block;
320
+ width: 100%;
321
+ max-width: 420px;
322
+ height: auto;
323
+ background: transparent;
324
+ border-radius: 1rem;
325
+ transition: all 0.2s ease;
326
+ }
327
+
328
+ canvas {
329
+ background: transparent !important;
330
+ border-radius: 1rem;
331
+ width: 100%;
332
+ max-width: 420px;
333
+ margin: 0 auto;
334
+ display: block;
335
+ filter: drop-shadow(0 4px 8px rgba(0,0,0,0.05));
336
+ }
337
+
338
+ .ligne-metrique {
339
+ display: flex;
340
+ align-items: center;
341
+ gap: 0.75rem;
342
+ margin-bottom: 0.7rem;
343
+ background: #fafcff;
344
+ padding: 0.5rem 0.75rem;
345
+ border-radius: 2rem;
346
+ border: 1px solid #eef2f8;
347
+ }
348
+ .nom-metrique {
349
+ flex: 2;
350
+ font-size: 0.75rem;
351
+ font-weight: 500;
352
+ }
353
+ .ligne-metrique input {
354
+ width: 65px;
355
+ padding: 0.25rem 0.5rem;
356
+ border-radius: 2rem;
357
+ border: 1px solid #cbd5e1;
358
+ text-align: center;
359
+ font-size: 0.8rem;
360
+ }
361
+
362
+ /* Heatmap 3 mois vert clair */
363
+ .heatmap-github {
364
+ display: flex;
365
+ gap: 3px;
366
+ overflow-x: auto;
367
+ }
368
+ .colonne-semaine {
369
+ display: flex;
370
+ flex-direction: column;
371
+ gap: 2px;
372
+ }
373
+ .cellule-jour {
374
+ width: 14px;
375
+ height: 14px;
376
+ border-radius: 2px;
377
+ }
378
+ .etiquettes-jours {
379
+ display: flex;
380
+ flex-direction: column;
381
+ gap: 2px;
382
+ font-size: 0.55rem;
383
+ color: #4b5563;
384
+ margin-right: 6px;
385
+ width: 24px;
386
+ }
387
+ .etiquettes-jours span {
388
+ height: 14px;
389
+ line-height: 14px;
390
+ text-align: right;
391
+ }
392
+ .stats-heatmap {
393
+ display: flex;
394
+ gap: 1rem;
395
+ margin-top: 1rem;
396
+ flex-wrap: wrap;
397
+ }
398
+ .pastille-stat {
399
+ background: #f1f5f9;
400
+ padding: 0.25rem 1rem;
401
+ border-radius: 2rem;
402
+ font-size: 0.7rem;
403
+ font-weight: 500;
404
+ color: #1f3a6b;
405
+ }
406
+
407
+ /* Boîte réflexive */
408
+ .boite-reflexive {
409
+ background: #f8fafc;
410
+ border-radius: 1rem;
411
+ padding: 1.25rem;
412
+ border-left: 4px solid #2c6e9e;
413
+ margin: 1rem 0;
414
+ line-height: 1.5;
415
+ font-size: 0.9rem;
416
+ color: #1e2a3a;
417
+ }
418
+
419
+ /* Métriques expert */
420
+ .metrique-expert {
421
+ background: #ffffff;
422
+ border: 1px solid #e9edf2;
423
+ border-radius: 1rem;
424
+ padding: 1rem 1.2rem;
425
+ margin-bottom: 1rem;
426
+ }
427
+ .titre-metrique {
428
+ font-weight: 600;
429
+ font-size: 0.9rem;
430
+ color: #1e293b;
431
+ display: flex;
432
+ align-items: center;
433
+ gap: 0.75rem;
434
+ flex-wrap: wrap;
435
+ margin-bottom: 0.25rem;
436
+ }
437
+ .titre-metrique code {
438
+ background: #f1f5f9;
439
+ padding: 0.1rem 0.6rem;
440
+ border-radius: 2rem;
441
+ font-size: 0.7rem;
442
+ font-weight: 500;
443
+ color: #1e40af;
444
+ }
445
+ .description-metrique {
446
+ font-size: 0.7rem;
447
+ color: #5b6e8c;
448
+ margin-bottom: 0.7rem;
449
+ }
450
+ .etoiles {
451
+ display: flex;
452
+ gap: 0.5rem;
453
+ align-items: center;
454
+ }
455
+ .etoile {
456
+ font-size: 1.5rem;
457
+ cursor: pointer;
458
+ color: #cfdde6;
459
+ transition: 0.05s;
460
+ }
461
+ .etoile.active {
462
+ color: #f5b042;
463
+ }
464
+ .etoile:hover {
465
+ transform: scale(1.05);
466
+ }
467
+ .synthese-confiance {
468
+ background: #f1f5f9;
469
+ border-radius: 1rem;
470
+ padding: 1rem 1.25rem;
471
+ margin-top: 1rem;
472
+ display: flex;
473
+ justify-content: space-between;
474
+ align-items: center;
475
+ flex-wrap: wrap;
476
+ gap: 1rem;
477
+ }
478
+ .barre-confiance {
479
+ flex: 2;
480
+ background: #e2e8f0;
481
+ border-radius: 2rem;
482
+ height: 1.6rem;
483
+ overflow: hidden;
484
+ }
485
+ #remplissageConfiance {
486
+ height: 100%;
487
+ width: 0%;
488
+ background: #2c6e9e;
489
+ text-align: center;
490
+ line-height: 1.6rem;
491
+ color: white;
492
+ font-size: 0.7rem;
493
+ font-weight: 600;
494
+ transition: width 0.2s;
495
+ }
496
+ textarea {
497
+ width: 100%;
498
+ border-radius: 0.75rem;
499
+ border: 1px solid #cbd5e1;
500
+ padding: 0.6rem;
501
+ font-family: inherit;
502
+ margin-top: 0.75rem;
503
+ resize: vertical;
504
+ font-size: 0.8rem;
505
+ }
506
+ .groupe-likert {
507
+ display: flex;
508
+ gap: 0.75rem;
509
+ align-items: center;
510
+ flex-wrap: wrap;
511
+ margin-top: 0.5rem;
512
+ }
513
+ .btn-likert {
514
+ width: 44px;
515
+ height: 44px;
516
+ border-radius: 50%;
517
+ background: #f1f5f9;
518
+ border: 1px solid #cbd5e1;
519
+ font-size: 1.1rem;
520
+ font-weight: 600;
521
+ color: #1e293b;
522
+ cursor: pointer;
523
+ transition: all 0.15s ease;
524
+ display: inline-flex;
525
+ align-items: center;
526
+ justify-content: center;
527
+ box-shadow: 0 1px 2px rgba(0,0,0,0.02);
528
+ }
529
+ .btn-likert:hover {
530
+ background: #e2e8f0;
531
+ border-color: #94a3b8;
532
+ transform: scale(1.02);
533
+ }
534
+ .btn-likert.actif {
535
+ background: #0f172a;
536
+ border-color: #0f172a;
537
+ color: #ffffff;
538
+ box-shadow: 0 2px 6px rgba(0,0,0,0.1);
539
+ }
540
+ .manifeste-panel {
541
+ background: #fefce8;
542
+ border: 1px solid #e7e5c3;
543
+ border-radius: 1rem;
544
+ padding: 1rem;
545
+ margin-bottom: 1.25rem;
546
+ }
547
+ .manifeste-panel label {
548
+ font-weight: 600;
549
+ font-size: 0.8rem;
550
+ color: #3b2e1e;
551
+ }
552
+ .profile-selector {
553
+ background: #f1f5f9;
554
+ border-radius: 1rem;
555
+ padding: 0.75rem 1rem;
556
+ margin: 1rem 0 0.5rem 0;
557
+ display: flex;
558
+ flex-wrap: wrap;
559
+ align-items: center;
560
+ gap: 1rem;
561
+ }
562
+ .profile-selector label {
563
+ font-weight: 600;
564
+ font-size: 0.75rem;
565
+ color: #0f172a;
566
+ }
567
+ .profile-selector select {
568
+ flex: 2;
569
+ min-width: 200px;
570
+ background: white;
571
+ }
572
+ .question-item {
573
+ margin-bottom: 1.2rem;
574
+ border-bottom: 1px solid #eef2f8;
575
+ padding-bottom: 0.8rem;
576
+ }
577
+ .question-label {
578
+ font-weight: 500;
579
+ font-size: 0.85rem;
580
+ margin-bottom: 0.4rem;
581
+ color: #1e293b;
582
+ }
583
+ .dimension-header {
584
+ background: #eef2ff;
585
+ padding: 0.4rem 1rem;
586
+ border-radius: 2rem;
587
+ font-weight: 700;
588
+ font-size: 0.8rem;
589
+ margin: 1rem 0 0.5rem 0;
590
+ color: #1e3a8a;
591
+ display: inline-block;
592
+ }
593
+ .questions-container {
594
+ max-height: 600px;
595
+ overflow-y: auto;
596
+ padding-right: 0.5rem;
597
+ }
598
+ @media (max-width: 700px) {
599
+ body { padding: 1rem; }
600
+ .card { padding: 1rem; }
601
+ .etoile { font-size: 1.25rem; }
602
+ .tab-btn { padding: 0.5rem 1rem; }
603
+ .btn-likert { width: 38px; height: 38px; font-size: 1rem; }
604
+ .cellule-jour { width: 10px; height: 10px; }
605
+ .etiquettes-jours span { height: 10px; line-height: 10px; font-size: 0.5rem; }
606
+ }
607
+
608
+ .profile-completion {
609
+ background: #ffffff;
610
+ border: 1px solid #e2e8f0;
611
+ border-radius: 1.25rem;
612
+ padding: 1rem 1.2rem;
613
+ margin: 1.25rem 0 1rem 0;
614
+ box-shadow: 0 1px 2px rgba(0,0,0,0.02);
615
+ }
616
+ .completion-header {
617
+ display: flex;
618
+ justify-content: space-between;
619
+ align-items: baseline;
620
+ flex-wrap: wrap;
621
+ gap: 0.75rem;
622
+ margin-bottom: 0.6rem;
623
+ }
624
+ .completion-title {
625
+ font-weight: 700;
626
+ font-size: 0.85rem;
627
+ color: #0f172a;
628
+ letter-spacing: -0.2px;
629
+ }
630
+ .completion-percent {
631
+ font-size: 1.2rem;
632
+ font-weight: 800;
633
+ color: #1e3a8a;
634
+ }
635
+ .progress-bar-bg {
636
+ background: #e2e8f0;
637
+ border-radius: 2rem;
638
+ height: 0.7rem;
639
+ width: 100%;
640
+ overflow: hidden;
641
+ margin: 0.5rem 0 0.6rem 0;
642
+ }
643
+ .progress-fill {
644
+ background: #2c6e9e;
645
+ width: 0%;
646
+ height: 100%;
647
+ border-radius: 2rem;
648
+ transition: width 0.25s ease;
649
+ }
650
+ .completion-stats {
651
+ display: flex;
652
+ justify-content: space-between;
653
+ align-items: center;
654
+ flex-wrap: wrap;
655
+ gap: 0.8rem;
656
+ margin-top: 0.5rem;
657
+ font-size: 0.7rem;
658
+ color: #334155;
659
+ font-weight: 500;
660
+ }
661
+ .badge-profil {
662
+ background: #eef2ff;
663
+ padding: 0.2rem 0.8rem;
664
+ border-radius: 2rem;
665
+ color: #1e3a8a;
666
+ }
667
+ .titre-personnalisation {
668
+ font-size: 0.85rem;
669
+ font-weight: 600;
670
+ color: #1e293b;
671
+ margin: 0.75rem 0 0.5rem 0;
672
+ padding-left: 0.25rem;
673
+ border-left: 3px solid #3b82f6;
674
+ letter-spacing: -0.2px;
675
+ }
676
+
677
+ /* Légende heatmap vert clair */
678
+ .heatmap-legend {
679
+ display: flex;
680
+ gap: 0.5rem;
681
+ align-items: center;
682
+ margin-top: 0.75rem;
683
+ font-size: 0.65rem;
684
+ color: #4b5563;
685
+ }
686
+ .legend-color {
687
+ width: 14px;
688
+ height: 14px;
689
+ border-radius: 2px;
690
+ }
691
+ .loading-spinner {
692
+ display: inline-block;
693
+ width: 16px;
694
+ height: 16px;
695
+ border: 2px solid #e2e8f0;
696
+ border-top-color: #1e3a8a;
697
+ border-radius: 50%;
698
+ animation: spin 0.6s linear infinite;
699
+ vertical-align: middle;
700
+ margin-right: 6px;
701
+ }
702
+ @keyframes spin { to { transform: rotate(360deg); } }
703
+ </style>
704
+ </head>
705
+ <body>
706
+ <div class="dashboard">
707
+ <div class="card">
708
+ <div class="card-header">
709
+ <h2>ReflAgent – Profile-Aware Feedback for Metacognitive Support</h2>
710
+ <span class="badge">Prototype Recherche (SDT + Analytics) | InclusionAI</span>
711
+ </div>
712
+ </div>
713
+
714
+ <div class="card" style="padding-bottom: 1rem;">
715
+ <div class="tabs">
716
+ <button class="tab-btn active" data-tab="sdt">Profil d'auto-détermination (SDT)</button>
717
+ <button class="tab-btn" data-tab="analytics">Analytique de l'apprenant</button>
718
+ <button class="tab-btn" data-tab="reflexion">Message Réflexif & Évaluation experte</button>
719
+ </div>
720
+
721
+ <!-- VOLET SDT -->
722
+ <div id="tab-sdt" class="tab-content active">
723
+ <div class="card-header" style="margin-top:0; padding-top:0;"><h3>Échelle d'auto‑évaluation (1 → 5)</h3><button id="appliquerQuestionnaireBtn" style="background:#2c5282;"> Sauvegarder & Mettre à jour</button></div>
724
+ <div class="profile-completion" id="profileCompletionWidget">
725
+ <div class="completion-header">
726
+ <span class="completion-title">Complétion du Profil</span>
727
+ <span class="completion-percent" id="completionPourcentage">0%</span>
728
+ </div>
729
+ <div class="progress-bar-bg">
730
+ <div class="progress-fill" id="completionProgressFill" style="width:0%"></div>
731
+ </div>
732
+ <div class="completion-stats">
733
+ <span id="completionTexte">Questionnaires complétés: 0/28</span>
734
+ <span class="badge-profil" id="profilPersonnaliseBadge">Profil personnalisé: Non renseigné</span>
735
+ </div>
736
+ </div>
737
+ <div class="titre-personnalisation"> Personnaliser le profil des apprenants</div>
738
+ <div class="profile-selector">
739
+ <label> Profil apprenant prédéfini :</label>
740
+ <select id="selectProfilEtudiant">
741
+ <option value="">-- Sélectionner --</option>
742
+ <option value="engage">Étudiant engagé</option><option value="actifInefficace">Étudiant actif mais inefficace</option>
743
+ <option value="succes">Étudiant orienté vers le succès</option><option value="motivé">Étudiant motivé</option>
744
+ <option value="surmotivé">Étudiant surmotivé</option><option value="strategique">Étudiant stratégique</option>
745
+ <option value="amelioration">Étudiant en amélioration</option><option value="difficulte">Étudiant en difficulté</option>
746
+ <option value="evitement">Étudiant évitant l'échec</option><option value="risque">Étudiant à risque</option>
747
+ <option value="progression">Étudiant en progression</option><option value="acceptechec">Étudiant acceptant l'échec</option>
748
+ <option value="inactif">Étudiant inactif</option><option value="nonengage">Étudiant non engagé</option>
749
+ <option value="perseverant">Étudiant persévérant</option><option value="actif">Étudiant actif</option>
750
+ </select>
751
+ <button id="chargerProfilBtn" style="background:#2c5282;">Charger ce profil</button>
752
+ </div>
753
+ <div id="zoneQuestionnaire" class="questions-container"></div>
754
+ <p class="note-persistance" style="margin-top: 12px;">Les réponses modulent les indicateurs d'engagement, de régularité et les compétences.</p>
755
+ </div>
756
+
757
+ <!-- VOLET LEARNING ANALYTICS -->
758
+ <div id="tab-analytics" class="tab-content">
759
+ <div class="card-header" style="margin-top:0; padding-top:0;"><h3>Progression par compétence</h3></div>
760
+ <div class="legende-competences">
761
+ <span class="legende-item"><span class="legende-couleur faible"></span> Faible (0-50%)</span>
762
+ <span class="legende-item"><span class="legende-couleur moyen"></span> Moyen (50-70%)</span>
763
+ <span class="legende-item"><span class="legende-couleur eleve"></span> Élevé (70-100%)</span>
764
+ </div>
765
+ <div id="conteneurCompetences" class="grille-competences"></div>
766
+
767
+ <div class="card-header" style="margin-top: 0.5rem;"><h3>Analyse de la persistance et du management de l'effort (persévérance) - 3 mois</h3></div>
768
+ <div class="persistance-heatmap-container">
769
+ <div class="persistance-card">
770
+ <div class="section-title-sm"> Régularité & Organisation</div>
771
+ <div class="metrique-persistance-compact">
772
+ <label>Régularité (%)</label>
773
+ <div class="valeur-persistance-compact" id="affichageRegularite">90</div>
774
+ <input type="range" id="curseurRegularite" min="0" max="100" step="1" value="90" class="slider-compact">
775
+ <div class="note-persistance-compact">Constance dans l'engagement hebdomadaire</div>
776
+ </div>
777
+ <div class="metrique-persistance-compact">
778
+ <label>Gestion échéances (%)</label>
779
+ <div class="valeur-persistance-compact" id="affichageEcheances">84</div>
780
+ <input type="range" id="curseurEcheances" min="0" max="100" step="1" value="84" class="slider-compact">
781
+ <div class="note-persistance-compact">Respect des délais et planification</div>
782
+ </div>
783
+ <div class="metrique-persistance-compact">
784
+ <label>Schéma d'effort</label>
785
+ <select id="selectPatternEffort" class="select-compact">
786
+ <option value="Régulier (Effort équilibré toute la semaine)" selected>Régulier (Effort équilibré toute la semaine)</option>
787
+ <option value="Effort concentré (Pic d'activité jeudi/vendredi)">Effort concentré (Pic d'activité jeudi/vendredi)</option>
788
+ <option value="Travail weekend (Activité principalement le weekend)">Travail weekend (Activité principalement le weekend)</option>
789
+ <option value="Accélération progressive (Démarrage lent, fin forte)">Accélération progressive (Démarrage lent, fin forte)</option>
790
+ <option value="Très faible (Activité minimale toute la semaine)">Très faible (Activité minimale toute la semaine)</option>
791
+ </select>
792
+ <div class="note-persistance-compact">Distribution temporelle du travail</div>
793
+ </div>
794
+ </div>
795
+ <div class="heatmap-card">
796
+ <div class="section-title-sm"> Heatmap d'activité sur 3 mois</div>
797
+ <div id="zoneHeatmap"></div>
798
+ <div class="heatmap-legend">
799
+ <span class="legend-color" style="background:#e8f5e9;"></span><span>Faible</span>
800
+ <span class="legend-color" style="background:#c8e6c9;"></span><span>Peu actif</span>
801
+ <span class="legend-color" style="background:#a5d6a7;"></span><span>Actif</span>
802
+ <span class="legend-color" style="background:#81c784;"></span><span>Très actif</span>
803
+ <span class="legend-color" style="background:#4caf50;"></span><span>Intense</span>
804
+ </div>
805
+ <div id="statsHeatmap" class="stats-heatmap" style="margin-top: 0.75rem;"></div>
806
+ </div>
807
+ </div>
808
+
809
+ <div class="grid-2col" style="margin-top: 1.5rem;">
810
+ <div class="card" style="padding: 1rem; margin-bottom: 0;">
811
+ <h3 style="margin-bottom: 0.75rem;">Analyse de l'engagement: Indicateurs de comportement d'apprentissage</h3>
812
+ <div class="radar-wrapper"><canvas id="canvasRadar" width="420" height="420" style="width:100%; max-width:420px; height:auto;"></canvas></div>
813
+ <div id="analyseRadar" style="background:#f8fafc; border-radius:0.75rem; padding:0.6rem; margin-top:1rem; text-align:center; font-size:0.75rem;"></div>
814
+ </div>
815
+ <div class="card" style="padding: 1rem; margin-bottom: 0;"><h3 style="margin-bottom: 0.75rem;">Personnaliser les metriques (radar)</h3><div id="listeMetriquesModifiables"></div></div>
816
+ </div>
817
+ </div>
818
+
819
+ <!-- VOLET REFLAGENT & EXPERT (avec INCLUSIONAI) -->
820
+ <div id="tab-reflexion" class="tab-content">
821
+ <div class="card-header" style="margin-top:0; padding-top:0;"><h3>ReflAgent – Feedback réflexif adaptatif </h3><button id="genererMessageBtn"> Générer l'analyse réflexive </button></div>
822
+ <div class="manifeste-panel">
823
+ <div style="display: flex; flex-wrap: wrap; gap: 1.5rem; align-items: flex-end;">
824
+ <div class="control" style="flex: 1.5;">
825
+ <label>Intention de l'apprenant</label>
826
+ <select id="selectIntention">
827
+ <option value="engagement">Engagement / régularité</option><option value="risk">Niveau de risque</option>
828
+ <option value="challenges">Difficultés / défis</option><option value="emotions">Émotions (stress, confiance)</option>
829
+ <option value="advice">Conseil méthodologique</option><option value="progress">Progression et axes d'amélioration</option>
830
+ <option value="improvement">Axes de développement prioritaires</option>
831
+ </select>
832
+ </div>
833
+ <div class="control" style="flex: 3;">
834
+ <label>Manifeste (question / préoccupation)</label>
835
+ <input type="text" id="manifesteNaturel" placeholder="Ex: Comment mieux organiser mes révisions ?">
836
+ </div>
837
+ </div>
838
+ </div>
839
+ <div id="messageReflexif" class="boite-reflexive"><i> Cliquez sur "Générer l'analyse réflexive" pour recevoir un feedback personnalisé par IA basé sur votre profil d'apprentissage.</i></div>
840
+ <div class="card-header" style="margin-top: 1rem;"><h3>Calibration experte – Métriques de confiance</h3></div>
841
+ <p style="font-size:0.75rem; margin-bottom: 0.75rem;">Chaque dimension évalue la qualité du message réflexif produit par ReflAgent.</p>
842
+ <div class="metrique-expert" data-metric="AR"><div class="titre-metrique">Authenticité réflexive (AR) <code>AR</code></div><div class="description-metrique">Le message reflète-t-il fidèlement les indicateurs réels de l'apprenant ?</div><div class="etoiles" id="etoiles-AR"></div></div>
843
+ <div class="metrique-expert" data-metric="AE"><div class="titre-metrique">Alignement empathique (AE) <code>AE</code></div><div class="description-metrique">Le message comporte-t-il des marqueurs linguistiques empathiques ?</div><div class="etoiles" id="etoiles-AE"></div></div>
844
+ <div class="metrique-expert" data-metric="ESR"><div class="titre-metrique">Encouragement sensible au risque (ESR) <code>ESR</code></div><div class="description-metrique">Équilibre entre encouragement et indication du niveau de risque.</div><div class="etoiles" id="etoiles-ESR"></div></div>
845
+ <div class="metrique-expert" data-metric="SDM"><div class="titre-metrique">Soutien aux défis cognitifs (SDM) <code>SDM</code></div><div class="description-metrique">Stimule l'apprenant et renforce son sentiment de compétence.</div><div class="etoiles" id="etoiles-SDM"></div></div>
846
+ <div class="metrique-expert" data-metric="SM"><div class="titre-metrique">Soutien métacognitif (SM) <code>SM</code></div><div class="description-metrique">Aide l'étudiant à réfléchir sur ses stratégies d'apprentissage.</div><div class="etoiles" id="etoiles-SM"></div></div>
847
+ <div class="synthese-confiance"><div style="font-weight: 600;">Confiance globale</div><div class="barre-confiance"><div id="remplissageConfiance">0%</div></div><button id="sauvegarderEvalBtn" class="btn-secondaire">Enregistrer évaluation</button></div>
848
+ <div id="retourSauvegarde" style="margin-top:0.5rem; font-size:0.7rem; color:#2c6e9e;"></div>
849
+ <textarea id="commentaireExpert" rows="2" placeholder="Observations complémentaires de l'expert (optionnel)..."></textarea>
850
+ <div style="display: flex; gap: 1rem; flex-wrap: wrap; margin-top: 1rem;">
851
+ <div class="pastille-stat">Niveau de risque : <strong id="niveauRisque">-</strong></div>
852
+ <div class="pastille-stat">Engagement moyen : <strong id="moyenneEngagement">-</strong></div>
853
+ <div class="pastille-stat">Confiance experte : <strong id="confianceGlobaleValeur">0%</strong></div>
854
+ </div>
855
+ </div>
856
+ </div>
857
+ </div>
858
+
859
+ <script>
860
+ // ============================================================
861
+ // ✅ CONFIGURATION INCLUSIONAI VIA OPENROUTER (CORRIGÉE)
862
+ // ============================================================
863
+ const OPENROUTER_API_KEY = "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";
864
+ const OPENROUTER_URL = "https://openrouter.ai/api/v1/chat/completions";
865
+ const INCLUSIONAI_MODEL = "inclusionai/ling-2.6-1t:free";
866
+
867
+ // ---------- DONNÉES DE BASE ----------
868
+ const metriquesRadarDefaut = [
869
+ { label: "Initiation des tâches", value: 85, desc: "Rapidité d'engagement" },
870
+ { label: "Connaissances validées", value: 72, desc: "Taux de validation" },
871
+ { label: "Niveau de compétence", value: 68, desc: "Maîtrise moyenne" },
872
+ { label: "Taux d'erreur (inversé)", value: 65, desc: "Précision" },
873
+ { label: "Achèvement des tâches", value: 74, desc: "Terminaison" },
874
+ { label: "Interaction ressources", value: 80, desc: "Utilisation contenus" },
875
+ { label: "Score global", value: 70, desc: "Activité globale" },
876
+ { label: "Tentatives de réponse", value: 78, desc: "Engagement réponse" }
877
+ ];
878
+ const competencesDefaut = [
879
+ { label: "Choix lexical", value: 72 }, { label: "Compréhension des mots", value: 60 },
880
+ { label: "Développement du vocabulaire", value: 65 }, { label: "Maîtrise orthographique", value: 70 },
881
+ { label: "Articulation des termes", value: 68 }, { label: "Construction phrastique", value: 48 },
882
+ { label: "Orthographe grammaticale", value: 55 }, { label: "Modalités des phrases", value: 62 },
883
+ { label: "Enchaînement des phrases", value: 66 }, { label: "Organisation textuelle", value: 78 },
884
+ { label: "Reprises anaphoriques", value: 74 }, { label: "Conjugaison", value: 80 }
885
+ ];
886
+
887
+ let profil = {
888
+ titre: "Apprenant en progression",
889
+ manifeste: "Développement des compétences langagières",
890
+ competences: JSON.parse(JSON.stringify(competencesDefaut)),
891
+ metriquesRadar: JSON.parse(JSON.stringify(metriquesRadarDefaut)),
892
+ regularite: 90,
893
+ echeances: 84,
894
+ patternEffort: "Régulier (Effort équilibré toute la semaine)",
895
+ risque: 25
896
+ };
897
+
898
+ let scoresConfiance = { AR: 0, AE: 0, ESR: 0, SDM: 0, SM: 0 };
899
+ const poidsConfiance = { AR: 0.30, AE: 0.20, ESR: 0.20, SDM: 0.10, SM: 0.20 };
900
+ let questionnaireReponses = {};
901
+
902
+ const questionsSDT = [
903
+ { dim:"AUTONOMIE", text:"Dans mes études, j'ai l'impression de pouvoir choisir ce que j'apprends." }, { dim:"AUTONOMIE", text:"Quand je travaille, c'est avant tout parce que c'est mon choix personnel." },
904
+ { dim:"AUTONOMIE", text:"Je devrais apprendre ce qu'on me dit, sans discuter." }, { dim:"COMPÉTENCE PERÇUE", text:"En général, je réussis ce que j'entreprends dans mes études." },
905
+ { dim:"COMPÉTENCE PERÇUE", text:"Face à une difficulté, je me sens capable de trouver une solution." }, { dim:"COMPÉTENCE PERÇUE", text:"J'ai besoin d'être rassuré(e) sur mes capacités." },
906
+ { dim:"AFFILIATION / RELATION", text:"Je préfère travailler en groupe plutôt que seul(e)." }, { dim:"AFFILIATION / RELATION", text:"Il est important pour moi d'être reconnu(e) par mes professeurs." },
907
+ { dim:"AFFILIATION / RELATION", text:"En cas de doute, je demande de l'aide facilement." }, { dim:"MOTIVATION", text:"Ce qui me motive le plus, c'est le plaisir d'apprendre (et non les notes)." },
908
+ { dim:"MOTIVATION", text:"Si on supprimait les notes, j'étudierais autant ou plus." }, { dim:"MOTIVATION", text:"J'ai parfois l'impression que cela ne sert à rien d'étudier." },
909
+ { dim:"PROFIL MOTIVATIONNEL (DEMBO)", text:"Je recherche activement les défis." }, { dim:"PROFIL MOTIVATIONNEL (DEMBO)", text:"La peur d'échouer me limite." },
910
+ { dim:"TRAITS STABLES", text:"Je suis une personne organisée." }, { dim:"TRAITS STABLES", text:"Je ressens facilement du stress ou de l'anxiété." },
911
+ { dim:"TRAITS STABLES", text:"J'ai plus d'énergie le soir que le matin." }, { dim:"GESTION DU STRESS & DÉLAIS", text:"Face à une échéance importante, la pression me bloque plus qu'elle ne me motive." },
912
+ { dim:"GESTION DU STRESS & DÉLAIS", text:"Je suis capable de travailler efficacement même dans les derniers jours." }, { dim:"GESTION DU STRESS & DÉLAIS", text:"Quand je suis en retard, j'abandonne mentalement cette matière." },
913
+ { dim:"GESTION DU STRESS & DÉLAIS", text:"Le stress me pousse à éviter de commencer une tâche difficile." }, { dim:"TOLÉRANCE À L'ÉCHEC", text:"Une mauvaise note me fait douter de ma capacité à réussir les autres." },
914
+ { dim:"TOLÉRANCE À L'ÉCHEC", text:"Je peux recevoir un feedback négatif sans affecter ma motivation." }, { dim:"TOLÉRANCE À L'ÉCHEC", text:"Je préfère éviter de savoir où j'en suis par peur d'être déçu." },
915
+ { dim:"COMPORTEMENT FACE AU RETARD", text:"Je rattrape facilement mon retard." }, { dim:"COMPORTEMENT FACE AU RETARD", text:"Plus je suis en retard, plus j'ai besoin qu'on me guide." },
916
+ { dim:"COMPORTEMENT FACE AU RETARD", text:"Je produis un meilleur travail sous pression de dernière minute." }, { dim:"COMPORTEMENT FACE AU RETARD", text:"Travailler derrière les délais me stresse au point d'arrêter." }
917
+ ];
918
+ const TOTAL_QUESTIONS = questionsSDT.length;
919
+
920
+ // ============================================================
921
+ // PROMPT ENRICHI POUR INCLUSIONAI
922
+ // ============================================================
923
+ function construirePromptEnrichi() {
924
+ const intention = document.getElementById("selectIntention").value;
925
+ const manifeste = document.getElementById("manifesteNaturel").value || "Fournir un feedback réflexif personnalisé.";
926
+
927
+ const engagementMoy = profil.metriquesRadar.reduce((s,m)=>s+m.value,0)/profil.metriquesRadar.length;
928
+ const competencesFaibles = profil.competences.filter(c => c.value < 55).map(c => c.label);
929
+ const competencesFortes = profil.competences.filter(c => c.value > 75).map(c => c.label);
930
+
931
+ let competenceCible = "Non définie";
932
+ let valeurCompetenceCible = 0;
933
+ if (profil.competences.length > 0) {
934
+ const plusFaible = profil.competences.reduce((min, c) => c.value < min.value ? c : min, profil.competences[0]);
935
+ competenceCible = plusFaible.label;
936
+ valeurCompetenceCible = plusFaible.value;
937
+ }
938
+
939
+ const niveauRisqueTexte = profil.risque < 40 ? "faible" : (profil.risque < 70 ? "modéré" : "élevé");
940
+
941
+ const moyenneGroupeCompetence = 68;
942
+ const ecartCompetence = valeurCompetenceCible - moyenneGroupeCompetence;
943
+ const interpretationCompetence = ecartCompetence >= 10 ? "en avance" : (ecartCompetence <= -10 ? "en retard" : "dans la moyenne");
944
+
945
+ const moyenneGroupeRegularite = 72;
946
+ const ecartRegularite = profil.regularite - moyenneGroupeRegularite;
947
+ const interpretationEffort = ecartRegularite >= 15 ? "effort soutenu" : (ecartRegularite <= -15 ? "effort insuffisant" : "effort normal");
948
+
949
+ const moyenneGroupeTentatives = 2.5;
950
+ const tentativeEtudiant = Math.max(1, Math.min(5, Math.round(5 - (valeurCompetenceCible / 100) * 3)));
951
+ const ecartTentatives = tentativeEtudiant - moyenneGroupeTentatives;
952
+ const interpretationTentatives = ecartTentatives <= -0.5 ? "plus efficace" : (ecartTentatives >= 0.8 ? "plus lent" : "comparable");
953
+
954
+ const moyenneGroupeRessources = 65;
955
+ const tauxRessourcesEtudiant = Math.min(95, Math.max(20, Math.round(engagementMoy * 0.85)));
956
+ const ecartRessources = tauxRessourcesEtudiant - moyenneGroupeRessources;
957
+ const interpretationRessources = ecartRessources >= 15 ? "bonne utilisation" : (ecartRessources <= -15 ? "sous-utilisation" : "usage moyen");
958
+
959
+ const moyenneGroupeProgression = 5;
960
+ const progressionEtudiant = Math.min(25, Math.max(-10, Math.round((profil.regularite / 100) * 15 + (engagementMoy / 100) * 10 - 5)));
961
+ const ecartProgression = progressionEtudiant - moyenneGroupeProgression;
962
+ const interpretationProgression = ecartProgression >= 8 ? "progression rapide" : (ecartProgression <= -5 ? "progression stagnante" : "progression normale");
963
+
964
+ let positionnementGlobal = "dans la moyenne";
965
+ const scoreGlobalEtudiant = (engagementMoy + profil.regularite + valeurCompetenceCible) / 3;
966
+ if (scoreGlobalEtudiant >= 75) positionnementGlobal = "dans le top 25%";
967
+ else if (scoreGlobalEtudiant <= 45) positionnementGlobal = "dans le dernier quartile";
968
+
969
+ const listeCompetences = profil.competences.map(c => `- ${c.label}: ${c.value}%`).join("\n");
970
+
971
+ return `# 🧠 PROMPT GLOBAL ENRICHI – Feedback réflexif avec template de performance et normalisation collective
972
+
973
+ ## Rôle du système
974
+
975
+ Tu es un tuteur intelligent spécialisé en écriture académique, Learning Analytics et auto-régulation de l'apprentissage (SRL). Ton objectif est de produire un feedback réflexif personnalisé qui aide l'étudiant à comprendre sa situation d'apprentissage, régule ses émotions, identifie ses défis cognitifs, ajuste ses stratégies, renforce son engagement et sa motivation, et lui fournit une vision claire de sa performance relative au groupe.
976
+
977
+ ## Contexte pédagogique – 14 compétences
978
+
979
+ ${listeCompetences}
980
+
981
+ ## Compétences ciblées & seuils
982
+
983
+ - Compétence cible : ${competenceCible}
984
+ - Domaine prioritaire : ${competenceCible.includes("lexical") || competenceCible.includes("orthographique") ? "mot/phrase" : (competenceCible.includes("phrastique") || competenceCible.includes("modalités") ? "texte" : "discours")}
985
+ - Niveau attendu : intermédiaire
986
+ - Seuil attendu (%) : 70%
987
+ - Seuil de vigilance (%) : 50%
988
+
989
+ ## Intention & difficulté exprimée
990
+
991
+ - Intention déclarée : ${intention}
992
+ - Difficulté exprimée : ${manifeste}
993
+
994
+ ## Profil étudiant & traces d'apprentissage
995
+
996
+ - Score compétence cible (%) : ${valeurCompetenceCible}
997
+ - Engagement moyen (radar) : ${Math.round(engagementMoy)}%
998
+ - Régularité : ${profil.regularite}%
999
+ - Gestion des échéances : ${profil.echeances}%
1000
+ - Compétences faibles (sous 55%) : ${competencesFaibles.length > 0 ? competencesFaibles.join(", ") : "aucune"}
1001
+ - Points forts (au-dessus 75%) : ${competencesFortes.length > 0 ? competencesFortes.join(", ") : "aucun"}
1002
+ - Niveau de risque : ${niveauRisqueTexte}
1003
+
1004
+ ## 🆕 Données de normalisation collective (comparaison au groupe)
1005
+
1006
+ | Indicateur | Valeur étudiant | Moyenne du groupe | Écart | Interprétation |
1007
+ |------------|----------------|-------------------|-------|----------------|
1008
+ | Score compétence cible (%) | ${valeurCompetenceCible} | ${moyenneGroupeCompetence} | ${ecartCompetence >= 0 ? "+" : ""}${ecartCompetence} | ${interpretationCompetence} |
1009
+ | Taux d'effort (régularité) | ${profil.regularite}% | ${moyenneGroupeRegularite}% | ${ecartRegularite >= 0 ? "+" : ""}${ecartRegularite} | ${interpretationEffort} |
1010
+ | Nombre de tentatives avant réussite | ${tentativeEtudiant} | ${moyenneGroupeTentatives} | ${ecartTentatives >= 0 ? "+" : ""}${ecartTentatives.toFixed(1)} | ${interpretationTentatives} |
1011
+ | Taux d'utilisation des ressources | ${tauxRessourcesEtudiant}% | ${moyenneGroupeRessources}% | ${ecartRessources >= 0 ? "+" : ""}${ecartRessources} | ${interpretationRessources} |
1012
+ | Progression récente (7 derniers jours, en pts) | ${progressionEtudiant >= 0 ? "+" : ""}${progressionEtudiant} pts | +${moyenneGroupeProgression} pts | ${ecartProgression >= 0 ? "+" : ""}${ecartProgression} | ${interpretationProgression} |
1013
+
1014
+ Positionnement global de l'étudiant : ${positionnementGlobal}
1015
+
1016
+ ## 🧭 Instructions pour générer le feedback réflexif
1017
+
1018
+ Produis un message unique, structuré selon le plan ci-dessous. Le message doit rester en langage naturel, empathique et réflexif.
1019
+
1020
+ ### 📊 A. Informing learners on their performance
1021
+
1022
+ 1. 🎯 Compétence & maîtrise (ciblée + globale) : score actuel vs seuil attendu, positionnement par rapport au groupe.
1023
+ 2. ⚙️ How you worked (process) : régularité, gestion du temps, tentatives, comparaison au groupe.
1024
+ 3. 📄 Quality of output (product) : qualité des productions, écart au niveau attendu.
1025
+
1026
+ ### 📉 B. Collective normalization of performance
1027
+
1028
+ Présente un tableau synthétique des indicateurs clés et une phrase de positionnement : "Globalement, tu te situes dans le {${positionnementGlobal}}."
1029
+
1030
+ ### ⚠️ C. Conscience du risque & régulation émotionnelle
1031
+
1032
+ Identifie le niveau de risque (${niveauRisqueTexte}), valide les émotions, propose une réassurance.
1033
+
1034
+ ### 🧠 D. Défis cognitifs liés à l'écriture
1035
+
1036
+ Identifie 1 ou 2 défis spécifiques liés aux compétences faibles (${competencesFaibles.slice(0,2).join(", ") || "à identifier"}) et à l'intention exprimée (${intention}).
1037
+
1038
+ ### 💪 E. Engagement et motivation
1039
+
1040
+ Valorise les points forts (${competencesFortes.slice(0,3).join(", ") || "les aspects positifs de ton travail"}) et les efforts visibles.
1041
+
1042
+ ### 📊 F. Visual Analytics recommandées
1043
+
1044
+ Suggère radar, courbe de progression, heatmap, histogramme cohorte.
1045
+
1046
+ ### ✅ G. Actions d'auto-régulation (priorisées)
1047
+
1048
+ Propose 3 à 5 actions concrètes, alignées avec l'intention "${intention}", avec "pourquoi" et "comment mesurer le progrès".
1049
+
1050
+ ## Contraintes de qualité
1051
+
1052
+ Personnalisé, empathique, réflexif, ancré dans les traces, structuré (sections A à G visibles), longueur 300-400 mots, français, émoticônes légères.`;
1053
+ }
1054
+
1055
+ // ============================================================
1056
+ // ✅ FONCTION PRINCIPALE AVEC INCLUSIONAI/OPENROUTER
1057
+ // ============================================================
1058
+ async function genererAvecInclusionAI() {
1059
+ const messageDiv = document.getElementById("messageReflexif");
1060
+ const bouton = document.getElementById("genererMessageBtn");
1061
+ const originalText = bouton.innerHTML;
1062
+ bouton.innerHTML = '<span class="loading-spinner"></span> Génération en cours...';
1063
+ bouton.disabled = true;
1064
+ messageDiv.innerHTML = '<em>🤖 Analyse de votre profil et génération d\'un feedback personnalisé avec InclusionAI...</em>';
1065
+
1066
+ try {
1067
+ const prompt = construirePromptEnrichi();
1068
+ console.log("Prompt envoyé à InclusionAI:", prompt);
1069
+
1070
+ const response = await fetch(OPENROUTER_URL, {
1071
+ method: "POST",
1072
+ headers: {
1073
+ "Content-Type": "application/json",
1074
+ "Authorization": `Bearer ${OPENROUTER_API_KEY}`,
1075
+ "HTTP-Referer": window.location.href,
1076
+ "X-Title": "ReflAgent - Analyse Reflexive"
1077
+ },
1078
+ body: JSON.stringify({
1079
+ model: INCLUSIONAI_MODEL,
1080
+ messages: [
1081
+ {
1082
+ role: "system",
1083
+ content: "Vous êtes un expert en sciences de l'éducation, spécialisé en Learning Analytics et en auto-régulation de l'apprentissage. Vous produisez des feedbacks réflexifs structurés, empathiques et personnalisés, en français."
1084
+ },
1085
+ {
1086
+ role: "user",
1087
+ content: prompt
1088
+ }
1089
+ ],
1090
+ temperature: 0.7,
1091
+ max_tokens: 2000,
1092
+ top_p: 0.95
1093
+ })
1094
+ });
1095
+
1096
+ if (!response.ok) {
1097
+ const err = await response.text();
1098
+ console.error("Erreur API InclusionAI:", err);
1099
+ let errorMessage = `Erreur API (${response.status})`;
1100
+ if (response.status === 401) errorMessage = "❌ Clé API invalide. Vérifiez votre clé OpenRouter.";
1101
+ else if (response.status === 429) errorMessage = "⏰ Trop de requêtes. Attendez quelques instants.";
1102
+ else if (response.status === 403) errorMessage = "🔒 Accès refusé. Vérifiez vos permissions.";
1103
+ throw new Error(`${errorMessage}: ${err.substring(0, 200)}`);
1104
+ }
1105
+
1106
+ const data = await response.json();
1107
+ console.log("Réponse InclusionAI:", data);
1108
+
1109
+ let inclusionText = data?.choices?.[0]?.message?.content;
1110
+ if (!inclusionText) {
1111
+ if (data?.error) {
1112
+ inclusionText = `⚠️ Erreur API: ${data.error.message || "Erreur inconnue"}`;
1113
+ } else {
1114
+ inclusionText = "⚠️ Le service a retourné une réponse inattendue. Veuillez réessayer.";
1115
+ }
1116
+ }
1117
+
1118
+ inclusionText = inclusionText.replace(/\n/g, '<br>');
1119
+ messageDiv.innerHTML = inclusionText;
1120
+ } catch (error) {
1121
+ console.error("Erreur détaillée InclusionAI:", error);
1122
+ messageDiv.innerHTML = `<span style="color:#b91c1c;">⚠️ Erreur lors de la génération: ${error.message}<br><br>💡 Vérifiez votre connexion et que la clé API OpenRouter est valide.</span>`;
1123
+ } finally {
1124
+ bouton.innerHTML = originalText;
1125
+ bouton.disabled = false;
1126
+ }
1127
+ }
1128
+
1129
+ // --- Fonctions UI (inchangées) ---
1130
+ function miseAJourBarreProgressionSDT() {
1131
+ const repondues = Object.keys(questionnaireReponses).length;
1132
+ const pourcentage = Math.round((repondues / TOTAL_QUESTIONS) * 100);
1133
+ document.getElementById("completionPourcentage").innerText = `${pourcentage}%`;
1134
+ document.getElementById("completionProgressFill").style.width = `${pourcentage}%`;
1135
+ document.getElementById("completionTexte").innerHTML = `Questionnaires complétés: ${repondues}/${TOTAL_QUESTIONS}`;
1136
+ let niveauProfil = "Non renseigné";
1137
+ if (pourcentage >= 90) niveauProfil = "Très avancé";
1138
+ else if (pourcentage >= 70) niveauProfil = "Avancé";
1139
+ else if (pourcentage >= 40) niveauProfil = "Intermédiaire";
1140
+ else if (pourcentage >= 20) niveauProfil = "Débutant";
1141
+ else niveauProfil = "À compléter";
1142
+ document.getElementById("profilPersonnaliseBadge").innerHTML = `Profil personnalisé: ${niveauProfil}`;
1143
+ }
1144
+
1145
+ function toutActualiser() {
1146
+ afficherCompetences(); afficherMetriquesModifiables(); dessinerRadar(); analyserRadar(); afficherHeatmap3Mois(); actualiserRisqueEtEngagement();
1147
+ document.getElementById("curseurRegularite").value = profil.regularite;
1148
+ document.getElementById("curseurEcheances").value = profil.echeances;
1149
+ document.getElementById("affichageRegularite").innerText = profil.regularite;
1150
+ document.getElementById("affichageEcheances").innerText = profil.echeances;
1151
+ document.getElementById("selectPatternEffort").value = profil.patternEffort;
1152
+ }
1153
+
1154
+ function synchroniserControles() {
1155
+ profil.regularite = parseInt(document.getElementById("curseurRegularite").value);
1156
+ profil.echeances = parseInt(document.getElementById("curseurEcheances").value);
1157
+ profil.patternEffort = document.getElementById("selectPatternEffort").value;
1158
+ toutActualiser();
1159
+ }
1160
+
1161
+ function afficherCompetences() {
1162
+ const conteneur = document.getElementById("conteneurCompetences");
1163
+ if(!conteneur) return;
1164
+ conteneur.innerHTML = "";
1165
+ profil.competences.forEach((c, idx) => {
1166
+ const valeur = c.value;
1167
+ const getNiveau = (v) => v < 50 ? { texte:"Faible", classe:"niveau-faible" } : (v < 70 ? { texte:"Moyen", classe:"niveau-moyen" } : { texte:"Élevé", classe:"niveau-eleve" });
1168
+ const niveau = getNiveau(valeur);
1169
+ const div = document.createElement("div");
1170
+ div.className = "item-competence";
1171
+ div.innerHTML = `<div class="en-tete-competence"><span>${c.label}</span><span class="valeur-competence">${valeur}% <span class="legende-niveau ${niveau.classe}">${niveau.texte}</span></span></div><input type="range" min="0" max="100" value="${valeur}" data-idx="${idx}" class="curseur-competence">`;
1172
+ conteneur.appendChild(div);
1173
+ div.querySelector(".curseur-competence").addEventListener("input", (e) => { profil.competences[idx].value = parseInt(e.target.value); toutActualiser(); });
1174
+ });
1175
+ }
1176
+
1177
+ function afficherMetriquesModifiables() {
1178
+ const conteneur = document.getElementById("listeMetriquesModifiables");
1179
+ if(!conteneur) return;
1180
+ conteneur.innerHTML = "";
1181
+ profil.metriquesRadar.forEach((m, idx) => {
1182
+ const ligne = document.createElement("div");
1183
+ ligne.className = "ligne-metrique";
1184
+ ligne.innerHTML = `<span class="nom-metrique">${m.label}<br><small>${m.desc}</small></span><input type="number" min="0" max="100" value="${m.value}" data-idx="${idx}" class="input-metrique"><span>${m.value}%</span>`;
1185
+ conteneur.appendChild(ligne);
1186
+ const input = ligne.querySelector(".input-metrique");
1187
+ input.addEventListener("input", (e) => { let v = Math.min(100,Math.max(0, parseInt(e.target.value)||0)); profil.metriquesRadar[idx].value=v; toutActualiser(); });
1188
+ });
1189
+ }
1190
+
1191
+ function dessinerRadar() {
1192
+ const canvas = document.getElementById("canvasRadar");
1193
+ if(!canvas) return;
1194
+ const ctx = canvas.getContext("2d");
1195
+ const w = canvas.width = 420, h = canvas.height = 420, cx = w/2, cy = h/2, rayon = Math.min(cx,cy) - 50;
1196
+ const metriques = profil.metriquesRadar, n = metriques.length;
1197
+ ctx.clearRect(0,0,w,h);
1198
+ for(let i=1;i<=5;i++){
1199
+ ctx.beginPath();
1200
+ ctx.arc(cx,cy,(rayon/5)*i,0,2*Math.PI);
1201
+ ctx.strokeStyle = "#cbd5e1";
1202
+ ctx.stroke();
1203
+ ctx.fillStyle = "#94a3b8";
1204
+ ctx.font = "bold 9px 'Inter'";
1205
+ ctx.fillText((i*20)+"%", cx+3, cy-(rayon/5)*i - 2);
1206
+ }
1207
+ for(let i=0;i<n;i++){
1208
+ let angle = (2*Math.PI*i)/n - Math.PI/2;
1209
+ let x = cx + rayon * Math.cos(angle), y = cy + rayon * Math.sin(angle);
1210
+ ctx.beginPath();
1211
+ ctx.moveTo(cx,cy);
1212
+ ctx.lineTo(x,y);
1213
+ ctx.strokeStyle = "#e2e8f0";
1214
+ ctx.stroke();
1215
+ let label = metriques[i].label.length > 12 ? metriques[i].label.slice(0,10)+".." : metriques[i].label;
1216
+ let tx = cx + (rayon + 22) * Math.cos(angle), ty = cy + (rayon + 22) * Math.sin(angle);
1217
+ ctx.fillStyle = "#1e293b";
1218
+ ctx.font = "bold 10px 'Inter'";
1219
+ ctx.textAlign = (angle > Math.PI/2 || angle < -Math.PI/2) ? "right" : "left";
1220
+ ctx.fillText(label, tx, ty);
1221
+ }
1222
+ ctx.beginPath();
1223
+ for(let i=0;i<n;i++){
1224
+ let angle = (2*Math.PI*i)/n - Math.PI/2;
1225
+ let r = rayon * (metriques[i].value/100);
1226
+ let x = cx + r * Math.cos(angle), y = cy + r * Math.sin(angle);
1227
+ if(i===0) ctx.moveTo(x,y);
1228
+ else ctx.lineTo(x,y);
1229
+ }
1230
+ ctx.closePath();
1231
+ ctx.fillStyle = "rgba(44, 110, 158, 0.12)";
1232
+ ctx.fill();
1233
+ ctx.strokeStyle = "#2c6e9e";
1234
+ ctx.lineWidth = 2.5;
1235
+ ctx.stroke();
1236
+ for(let i=0;i<n;i++){
1237
+ let angle = (2*Math.PI*i)/n - Math.PI/2;
1238
+ let r = rayon * (metriques[i].value/100);
1239
+ let x = cx + r * Math.cos(angle), y = cy + r * Math.sin(angle);
1240
+ ctx.beginPath();
1241
+ ctx.arc(x, y, 4, 0, 2*Math.PI);
1242
+ ctx.fillStyle = "#2c6e9e";
1243
+ ctx.fill();
1244
+ ctx.beginPath();
1245
+ ctx.arc(x, y, 1.8, 0, 2*Math.PI);
1246
+ ctx.fillStyle = "#ffffff";
1247
+ ctx.fill();
1248
+ let offsetX = 8 * Math.cos(angle), offsetY = 8 * Math.sin(angle);
1249
+ ctx.fillStyle = "#0f172a";
1250
+ ctx.font = "bold 9px 'Inter'";
1251
+ ctx.fillText(metriques[i].value + "%", x + offsetX, y + offsetY - 2);
1252
+ }
1253
+ }
1254
+
1255
+ function analyserRadar() {
1256
+ const moyenne = profil.metriquesRadar.reduce((s,m)=>s+m.value,0)/profil.metriquesRadar.length;
1257
+ const div = document.getElementById("analyseRadar");
1258
+ if(div) div.innerHTML = `Engagement moyen : ${Math.round(moyenne)}% — ${moyenne>=70?"Activité soutenue 🚀":(moyenne>=50?"Développement modéré 📈":"Renforcement nécessaire 💪")}`;
1259
+ }
1260
+
1261
+ function afficherHeatmap3Mois() {
1262
+ const wrapper = document.getElementById("zoneHeatmap");
1263
+ if(!wrapper) return;
1264
+ wrapper.innerHTML = "";
1265
+ const semaines = 12;
1266
+ const jours = ["Lun","Mar","Mer","Jeu","Ven","Sam","Dim"];
1267
+ let intensites = [];
1268
+ for(let w=0; w<semaines; w++){
1269
+ let ligne = [];
1270
+ for(let d=0; d<7; d++){
1271
+ let base = 3;
1272
+ if(profil.patternEffort.includes("Effort concentré")) base = (d===3||d===4)? 4 : 2;
1273
+ else if(profil.patternEffort.includes("Travail weekend")) base = (d===5||d===6)? 4 : 1;
1274
+ else if(profil.patternEffort.includes("Accélération progressive")) base = Math.min(4, Math.floor(w/3) + 2);
1275
+ else if(profil.patternEffort.includes("Très faible")) base = 0;
1276
+ else base = 3;
1277
+ if(profil.regularite < 35) base = Math.max(0, base - 2);
1278
+ else if(profil.regularite < 60) base = Math.max(0, base - 1);
1279
+ else if(profil.regularite > 85) base = Math.min(4, base + 1);
1280
+ if(w < 3) base = Math.max(0, base - 1);
1281
+ if(w > 8 && profil.regularite > 70) base = Math.min(4, base + 1);
1282
+ ligne.push(Math.min(4, Math.max(0, Math.round(base))));
1283
+ }
1284
+ intensites.push(ligne);
1285
+ }
1286
+ const couleurs = ["#e8f5e9", "#c8e6c9", "#a5d6a7", "#81c784", "#4caf50"];
1287
+ const leftDiv = document.createElement("div");
1288
+ leftDiv.className = "etiquettes-jours";
1289
+ jours.forEach(j=>{ let s=document.createElement("span"); s.innerText=j; leftDiv.appendChild(s); });
1290
+ const heat = document.createElement("div");
1291
+ heat.className = "heatmap-github";
1292
+ heat.style.maxHeight = "180px";
1293
+ for(let w=0; w<semaines; w++){
1294
+ const col=document.createElement("div");
1295
+ col.className="colonne-semaine";
1296
+ for(let d=0; d<7; d++){
1297
+ const cell=document.createElement("div");
1298
+ cell.className="cellule-jour";
1299
+ cell.style.backgroundColor = couleurs[intensites[w][d]];
1300
+ cell.title = `Semaine ${w+1}, ${jours[d]} - Activité: ${["Inactif","Faible","Moyen","Bon","Intense"][intensites[w][d]]}`;
1301
+ col.appendChild(cell);
1302
+ }
1303
+ heat.appendChild(col);
1304
+ }
1305
+ const main = document.createElement("div");
1306
+ main.style.display="flex";
1307
+ main.style.gap="8px";
1308
+ main.appendChild(leftDiv);
1309
+ main.appendChild(heat);
1310
+ wrapper.appendChild(main);
1311
+ const totalActivite = intensites.flat().reduce((a,b)=>a+b,0);
1312
+ const activiteMoyenne = (totalActivite / (semaines*7)).toFixed(1);
1313
+ const statsDiv = document.getElementById("statsHeatmap");
1314
+ if(statsDiv) statsDiv.innerHTML = `<div class="pastille-stat">📊 Activité moyenne: ${activiteMoyenne}/4</div><div class="pastille-stat">✅ Régularité: ${profil.regularite}%</div><div class="pastille-stat">⏱️ Persistance: ${Math.round(profil.regularite * 0.7 + profil.echeances * 0.3)}%</div><div class="pastille-stat">📅 Pattern: ${profil.patternEffort.substring(0,25)}</div>`;
1315
+ }
1316
+
1317
+ function actualiserRisqueEtEngagement() {
1318
+ const moyenne = profil.metriquesRadar.reduce((s,m)=>s+m.value,0)/profil.metriquesRadar.length;
1319
+ document.getElementById("moyenneEngagement").innerText=Math.round(moyenne)+"%";
1320
+ let risque = Math.min(90,Math.max(5,Math.round(100-moyenne*0.6+(100-profil.regularite)*0.4)));
1321
+ profil.risque=risque;
1322
+ document.getElementById("niveauRisque").innerHTML=risque<40?"🟢 Faible":(risque<70?"🟡 Modéré":"🔴 Élevé");
1323
+ }
1324
+
1325
+ function initialiserEtoilesExpert() {
1326
+ ["AR","AE","ESR","SDM","SM"].forEach(m => {
1327
+ const cont = document.getElementById(`etoiles-${m}`);
1328
+ if(!cont) return;
1329
+ cont.innerHTML = "";
1330
+ for(let i=1;i<=5;i++) {
1331
+ const etoile = document.createElement("span");
1332
+ etoile.textContent = "★";
1333
+ etoile.classList.add("etoile");
1334
+ if(scoresConfiance[m] >= i) etoile.classList.add("active");
1335
+ etoile.dataset.valeur = i;
1336
+ etoile.addEventListener("click", () => { scoresConfiance[m] = i; miseAJourEtoiles(m, i); mettreAJourBarreConfiance(); });
1337
+ cont.appendChild(etoile);
1338
+ }
1339
+ });
1340
+ }
1341
+
1342
+ function miseAJourEtoiles(metrique, valeur) {
1343
+ const container = document.getElementById(`etoiles-${metrique}`);
1344
+ if(!container) return;
1345
+ for(let i=0;i<container.children.length;i++) {
1346
+ if(parseInt(container.children[i].dataset.valeur) <= valeur) container.children[i].classList.add("active");
1347
+ else container.children[i].classList.remove("active");
1348
+ }
1349
+ }
1350
+
1351
+ function mettreAJourBarreConfiance() {
1352
+ let total=0, maxTotal=0;
1353
+ for(let [k,v] of Object.entries(scoresConfiance)) {
1354
+ total += v * poidsConfiance[k];
1355
+ maxTotal += 5 * poidsConfiance[k];
1356
+ }
1357
+ let pct = maxTotal>0 ? Math.round((total/maxTotal)*100) : 0;
1358
+ const fill = document.getElementById("remplissageConfiance");
1359
+ if(fill) {
1360
+ fill.style.width = pct+"%";
1361
+ fill.innerText = pct+"%";
1362
+ fill.style.background = pct<40?"#b45309":(pct<70?"#b68b40":"#2c6e9e");
1363
+ }
1364
+ document.getElementById("confianceGlobaleValeur").innerText = pct+"%";
1365
+ }
1366
+
1367
+ function sauvegarderEvaluation() {
1368
+ document.getElementById("retourSauvegarde").innerHTML = "✅ Évaluation experte enregistrée.";
1369
+ setTimeout(()=>document.getElementById("retourSauvegarde").innerHTML="",2000);
1370
+ }
1371
+
1372
+ function chargerProfilEtudiant(cle) {
1373
+ const profils = {
1374
+ engage:{ regularite:92, echeances:90 }, actifInefficace:{ regularite:82, echeances:52 },
1375
+ succes:{ regularite:94, echeances:96 }, motivé:{ regularite:88, echeances:84 },
1376
+ surmotivé:{ regularite:96, echeances:88 }, strategique:{ regularite:89, echeances:92 },
1377
+ amelioration:{ regularite:70, echeances:68 }, difficulte:{ regularite:44, echeances:38 },
1378
+ evitement:{ regularite:55, echeances:40 }, risque:{ regularite:32, echeances:28 },
1379
+ progression:{ regularite:74, echeances:72 }, acceptechec:{ regularite:65, echeances:60 },
1380
+ inactif:{ regularite:22, echeances:18 }, nonengage:{ regularite:38, echeances:32 },
1381
+ perseverant:{ regularite:90, echeances:88 }, actif:{ regularite:82, echeances:78 }
1382
+ };
1383
+ const p = profils[cle];
1384
+ if(p){
1385
+ profil.regularite = p.regularite;
1386
+ profil.echeances = p.echeances;
1387
+ profil.patternEffort = "Régulier (Effort équilibré toute la semaine)";
1388
+ toutActualiser();
1389
+ }
1390
+ }
1391
+
1392
+ function initOnglets() {
1393
+ document.querySelectorAll('.tab-btn').forEach(btn => {
1394
+ btn.addEventListener('click', () => {
1395
+ const id = btn.dataset.tab;
1396
+ document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
1397
+ btn.classList.add('active');
1398
+ document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
1399
+ document.getElementById(`tab-${id}`).classList.add('active');
1400
+ });
1401
+ });
1402
+ }
1403
+
1404
+ function initialiserQuestionnaire() {
1405
+ const container = document.getElementById("zoneQuestionnaire");
1406
+ if(!container) return;
1407
+ container.innerHTML = "";
1408
+ let lastDim = "";
1409
+ questionsSDT.forEach((q, idx) => {
1410
+ if (q.dim !== lastDim) {
1411
+ const header = document.createElement("div");
1412
+ header.className = "dimension-header";
1413
+ header.innerText = q.dim;
1414
+ container.appendChild(header);
1415
+ lastDim = q.dim;
1416
+ }
1417
+ const qDiv = document.createElement("div");
1418
+ qDiv.className = "question-item";
1419
+ qDiv.innerHTML = `<div class="question-label">${q.text}</div><div class="groupe-likert" data-qidx="${idx}"></div>`;
1420
+ container.appendChild(qDiv);
1421
+ const group = qDiv.querySelector(".groupe-likert");
1422
+ for (let v = 1; v <= 5; v++) {
1423
+ const btn = document.createElement("button");
1424
+ btn.innerText = v;
1425
+ btn.classList.add("btn-likert");
1426
+ btn.dataset.valeur = v;
1427
+ btn.addEventListener("click", (e) => {
1428
+ e.stopPropagation();
1429
+ group.querySelectorAll(".btn-likert").forEach(b => b.classList.remove("actif"));
1430
+ btn.classList.add("actif");
1431
+ questionnaireReponses[idx] = v;
1432
+ const moyenneResponses = Object.values(questionnaireReponses).reduce((a,b)=>a+b,0) / (Object.keys(questionnaireReponses).length || 1);
1433
+ const facteur = Math.min(1.1, Math.max(0.9, moyenneResponses / 3));
1434
+ if(document.getElementById("curseurRegularite")) profil.regularite = Math.min(100, Math.max(0, Math.round((parseInt(document.getElementById("curseurRegularite")?.value || 90) * facteur))));
1435
+ toutActualiser();
1436
+ miseAJourBarreProgressionSDT();
1437
+ });
1438
+ group.appendChild(btn);
1439
+ }
1440
+ if (questionnaireReponses[idx]) {
1441
+ const btnActif = group.querySelector(`button[data-valeur="${questionnaireReponses[idx]}"]`);
1442
+ if(btnActif) btnActif.classList.add("actif");
1443
+ }
1444
+ });
1445
+ miseAJourBarreProgressionSDT();
1446
+ }
1447
+
1448
+ // Événements
1449
+ document.getElementById("genererMessageBtn")?.addEventListener("click", genererAvecInclusionAI);
1450
+ document.getElementById("sauvegarderEvalBtn")?.addEventListener("click", sauvegarderEvaluation);
1451
+ document.getElementById("chargerProfilBtn")?.addEventListener("click", () => { const sel = document.getElementById("selectProfilEtudiant").value; if(sel) chargerProfilEtudiant(sel); });
1452
+ document.getElementById("curseurRegularite")?.addEventListener("input", synchroniserControles);
1453
+ document.getElementById("curseurEcheances")?.addEventListener("input", synchroniserControles);
1454
+ document.getElementById("selectPatternEffort")?.addEventListener("change", synchroniserControles);
1455
+ document.getElementById("appliquerQuestionnaireBtn")?.addEventListener("click", () => { toutActualiser(); });
1456
+
1457
+ // Initialisation
1458
+ initOnglets();
1459
+ initialiserQuestionnaire();
1460
+ initialiserEtoilesExpert();
1461
+ toutActualiser();
1462
+ mettreAJourBarreConfiance();
1463
+ </script>
1464
+ </body>
1465
+ </html>