devusman commited on
Commit
9c9f9cc
·
1 Parent(s): ff9a953
selfanalysis-ui/index.html ADDED
@@ -0,0 +1,891 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="it">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Analisi Logica Avanzata</title>
8
+ <style>
9
+ * {
10
+ margin: 0;
11
+ padding: 0;
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ :root {
16
+ --bg-primary: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
17
+ --bg-secondary: #ffffff;
18
+ --bg-tertiary: #f8fafc;
19
+ --text-primary: #2d3748;
20
+ --text-secondary: #4a5568;
21
+ --border-color: #e2e8f0;
22
+ --shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
23
+ --shadow-hover: 0 15px 35px rgba(0, 0, 0, 0.15);
24
+ --subject-color: #c53030;
25
+ --predicate-color: #2c7a7b;
26
+ --object-color: #2b6cb0;
27
+ --complement-color: #2f855a;
28
+ --modifier-color: #b7791f;
29
+ --clause-color: #553c9a;
30
+ --title-color: #ffffff;
31
+ --accent-color: #667eea;
32
+ --success-color: #38a169;
33
+ --error-color: #e53e3e;
34
+ --info-color: #3182ce;
35
+ --entity-color: #dd6b20;
36
+ }
37
+
38
+ [data-theme="scuro"] {
39
+ --bg-primary: linear-gradient(135deg, #2d3748 0%, #1a202c 100%);
40
+ --bg-secondary: #2d3748;
41
+ --bg-tertiary: #1a202c;
42
+ --text-primary: #f7fafc;
43
+ --text-secondary: #a0aec0;
44
+ --border-color: #4a5568;
45
+ --title-color: #ffffff;
46
+ --accent-color: #667eea;
47
+ --success-color: #68d391;
48
+ --error-color: #fc8181;
49
+ --info-color: #63b3ed;
50
+ --entity-color: #f6ad55;
51
+ }
52
+
53
+ body {
54
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
55
+ }
56
+
57
+ .container {
58
+ max-width: 1000px;
59
+ margin: 0 auto;
60
+ background: var(--bg-secondary);
61
+ border-radius: 20px;
62
+ box-shadow: var(--shadow);
63
+ overflow: hidden;
64
+ transition: all 0.3s ease;
65
+ }
66
+
67
+ .header {
68
+ background: var(--bg-primary);
69
+ color: var(--title-color);
70
+ padding: 40px 30px;
71
+ text-align: center;
72
+ position: relative;
73
+ }
74
+
75
+ .theme-toggle {
76
+ position: absolute;
77
+ top: 20px;
78
+ right: 20px;
79
+ background: rgba(255, 255, 255, 0.2);
80
+ border: none;
81
+ color: white;
82
+ padding: 10px;
83
+ width: 44px;
84
+ height: 44px;
85
+ border-radius: 50%;
86
+ cursor: pointer;
87
+ font-size: 20px;
88
+ transition: all 0.3s ease;
89
+ backdrop-filter: blur(10px);
90
+ display: flex;
91
+ align-items: center;
92
+ justify-content: center;
93
+ }
94
+
95
+ .theme-toggle:hover {
96
+ background: rgba(255, 255, 255, 0.3);
97
+ transform: scale(1.1) rotate(15deg);
98
+ }
99
+
100
+ .header h1 {
101
+ font-size: clamp(2rem, 5vw, 3.2rem);
102
+ margin-bottom: 10px;
103
+ text-shadow: 2px 2px 8px rgba(0, 0, 0, 0.4);
104
+ font-family: 'Trebuchet MS', 'Arial Black', sans-serif;
105
+ font-weight: 900;
106
+ }
107
+
108
+ .header p {
109
+ font-size: clamp(1rem, 2.5vw, 1.25rem);
110
+ opacity: 0.95;
111
+ }
112
+
113
+ .main-content {
114
+ padding: 40px;
115
+ background: var(--bg-secondary);
116
+ transition: all 0.3s ease;
117
+ }
118
+
119
+ .input-section {
120
+ margin-bottom: 30px;
121
+ }
122
+
123
+ .input-container {
124
+ position: relative;
125
+ margin-bottom: 20px;
126
+ }
127
+
128
+ #sentenceInput {
129
+ width: 100%;
130
+ padding: 20px;
131
+ padding-right: 60px;
132
+ border: 2px solid var(--border-color);
133
+ border-radius: 15px;
134
+ font-size: 18px;
135
+ background: var(--bg-tertiary);
136
+ color: var(--text-primary);
137
+ transition: all 0.3s ease;
138
+ resize: vertical;
139
+ min-height: 120px;
140
+ font-family: inherit;
141
+ }
142
+
143
+ #sentenceInput:focus {
144
+ outline: none;
145
+ border-color: var(--accent-color);
146
+ box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.2);
147
+ }
148
+
149
+ #sentenceInput::placeholder {
150
+ color: var(--text-secondary);
151
+ opacity: 0.7;
152
+ }
153
+
154
+ .voice-btn {
155
+ position: absolute;
156
+ right: 15px;
157
+ top: 15px;
158
+ background: transparent;
159
+ border: none;
160
+ cursor: pointer;
161
+ color: var(--text-secondary);
162
+ padding: 10px;
163
+ border-radius: 50%;
164
+ transition: all 0.3s ease;
165
+ }
166
+
167
+ .voice-btn:hover {
168
+ background-color: rgba(102, 126, 234, 0.1);
169
+ color: var(--accent-color);
170
+ }
171
+
172
+ .voice-btn.is-listening {
173
+ color: var(--error-color);
174
+ animation: pulse 1.5s infinite;
175
+ }
176
+
177
+ @keyframes pulse {
178
+ 0% {
179
+ transform: scale(1);
180
+ box-shadow: 0 0 0 0 rgba(229, 62, 62, 0.7);
181
+ }
182
+
183
+ 70% {
184
+ transform: scale(1.1);
185
+ box-shadow: 0 0 10px 10px rgba(229, 62, 62, 0);
186
+ }
187
+
188
+ 100% {
189
+ transform: scale(1);
190
+ box-shadow: 0 0 0 0 rgba(229, 62, 62, 0);
191
+ }
192
+ }
193
+
194
+ .analyze-btn {
195
+ background: var(--bg-primary);
196
+ color: #ffffff;
197
+ border: none;
198
+ padding: 15px 40px;
199
+ border-radius: 50px;
200
+ font-size: 16px;
201
+ font-weight: 600;
202
+ cursor: pointer;
203
+ transition: all 0.3s ease;
204
+ box-shadow: var(--shadow);
205
+ display: block;
206
+ margin: 0 auto;
207
+ }
208
+
209
+ .analyze-btn:hover {
210
+ box-shadow: var(--shadow-hover);
211
+ transform: translateY(-2px);
212
+ }
213
+
214
+ .analyze-btn:disabled {
215
+ opacity: 0.6;
216
+ cursor: not-allowed;
217
+ transform: none;
218
+ }
219
+
220
+ .examples {
221
+ margin: 30px 0;
222
+ text-align: center;
223
+ }
224
+
225
+ .examples h3 {
226
+ color: var(--text-secondary);
227
+ margin-bottom: 15px;
228
+ font-size: 1rem;
229
+ font-weight: 500;
230
+ }
231
+
232
+ .example-btn {
233
+ background: var(--bg-tertiary);
234
+ border: 1px solid var(--border-color);
235
+ color: var(--text-secondary);
236
+ padding: 8px 15px;
237
+ margin: 4px;
238
+ border-radius: 20px;
239
+ cursor: pointer;
240
+ font-size: 14px;
241
+ transition: all 0.3s ease;
242
+ }
243
+
244
+ .example-btn:hover {
245
+ background: rgba(102, 126, 234, 0.1);
246
+ border-color: var(--accent-color);
247
+ color: var(--accent-color);
248
+ }
249
+
250
+ .results {
251
+ margin-top: 30px;
252
+ display: none;
253
+ }
254
+
255
+ .format-selector {
256
+ display: flex;
257
+ justify-content: center;
258
+ gap: 10px;
259
+ margin: 20px 0 30px 0;
260
+ }
261
+
262
+ .format-btn {
263
+ background: var(--bg-tertiary);
264
+ border: 2px solid var(--border-color);
265
+ color: var(--text-secondary);
266
+ padding: 10px 20px;
267
+ border-radius: 25px;
268
+ cursor: pointer;
269
+ font-size: 14px;
270
+ transition: all 0.3s ease;
271
+ font-weight: 600;
272
+ }
273
+
274
+ .format-btn.active {
275
+ background: var(--accent-color);
276
+ color: white;
277
+ border-color: var(--accent-color);
278
+ }
279
+
280
+ .result-item {
281
+ border: 1px solid var(--border-color);
282
+ border-radius: 15px;
283
+ padding: 25px;
284
+ margin-bottom: 25px;
285
+ transition: all 0.3s ease;
286
+ overflow: hidden;
287
+ background: var(--bg-tertiary);
288
+ }
289
+
290
+ .subordinate-clause {
291
+ margin-left: 40px;
292
+ border-left: 3px solid var(--clause-color);
293
+ }
294
+
295
+ .result-header {
296
+ display: flex;
297
+ justify-content: space-between;
298
+ align-items: center;
299
+ margin-bottom: 20px;
300
+ flex-wrap: wrap;
301
+ gap: 10px;
302
+ }
303
+
304
+ .result-title {
305
+ font-weight: 700;
306
+ font-size: 1.3rem;
307
+ color: var(--text-primary);
308
+ }
309
+
310
+ .result-subtitle {
311
+ font-weight: 500;
312
+ font-size: 1rem;
313
+ color: var(--clause-color);
314
+ }
315
+
316
+ .copy-btn {
317
+ background: rgba(102, 126, 234, 0.1);
318
+ border: none;
319
+ color: var(--accent-color);
320
+ padding: 8px 15px;
321
+ border-radius: 20px;
322
+ cursor: pointer;
323
+ font-size: 12px;
324
+ font-weight: 600;
325
+ transition: all 0.3s ease;
326
+ flex-shrink: 0;
327
+ }
328
+
329
+ .copy-btn:hover {
330
+ background: rgba(102, 126, 234, 0.2);
331
+ }
332
+
333
+ .component {
334
+ display: inline-block;
335
+ padding: 6px 12px;
336
+ margin: 4px 2px;
337
+ border-radius: 8px;
338
+ font-weight: 500;
339
+ color: white;
340
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
341
+ transition: all 0.3s ease;
342
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
343
+ cursor: help;
344
+ }
345
+
346
+ .subject {
347
+ background: var(--subject-color);
348
+ }
349
+
350
+ .predicate {
351
+ background: var(--predicate-color);
352
+ }
353
+
354
+ .object {
355
+ background: var(--object-color);
356
+ }
357
+
358
+ .complement {
359
+ background: var(--complement-color);
360
+ }
361
+
362
+ .modifier {
363
+ background: var(--modifier-color);
364
+ }
365
+
366
+ .clause {
367
+ background: var(--clause-color);
368
+ }
369
+
370
+ .entity {
371
+ background: var(--entity-color);
372
+ }
373
+
374
+
375
+ .table-format {
376
+ width: 100%;
377
+ border-collapse: collapse;
378
+ margin-top: 15px;
379
+ background: var(--bg-secondary);
380
+ }
381
+
382
+ .table-format th,
383
+ .table-format td {
384
+ padding: 12px 15px;
385
+ border-bottom: 1px solid var(--border-color);
386
+ text-align: left;
387
+ vertical-align: top;
388
+ }
389
+
390
+ .table-format th {
391
+ background: rgba(102, 126, 234, 0.05);
392
+ font-size: 0.9rem;
393
+ text-transform: uppercase;
394
+ letter-spacing: 0.5px;
395
+ color: var(--text-secondary);
396
+ }
397
+
398
+ .table-format td {
399
+ color: var(--text-primary);
400
+ }
401
+
402
+ .table-format td:nth-child(2) {
403
+ font-weight: 600;
404
+ }
405
+
406
+ .table-format td small {
407
+ display: block;
408
+ margin-top: 5px;
409
+ color: var(--text-secondary);
410
+ font-size: 0.85rem;
411
+ line-height: 1.4;
412
+ }
413
+
414
+ /* Entity Section */
415
+ .entities-container {
416
+ margin-top: 20px;
417
+ }
418
+
419
+ .entity-tag {
420
+ display: inline-block;
421
+ padding: 8px 12px;
422
+ margin: 5px;
423
+ border-radius: 8px;
424
+ background: var(--bg-tertiary);
425
+ border: 1px solid var(--border-color);
426
+ transition: all 0.3s ease;
427
+ }
428
+
429
+ .entity-text {
430
+ font-weight: 600;
431
+ color: var(--entity-color);
432
+ }
433
+
434
+ .entity-label {
435
+ font-size: 0.8rem;
436
+ background: var(--border-color);
437
+ color: var(--text-secondary);
438
+ padding: 2px 6px;
439
+ border-radius: 4px;
440
+ margin-left: 8px;
441
+ font-weight: 600;
442
+ }
443
+
444
+ .entity-explanation {
445
+ display: block;
446
+ font-size: 0.9rem;
447
+ margin-top: 5px;
448
+ color: var(--text-secondary);
449
+ }
450
+
451
+ /* Updated Loading Styles - Bottom loader only */
452
+ .loading-section {
453
+ margin-top: 30px;
454
+ padding: 40px 20px;
455
+ background: var(--bg-tertiary);
456
+ border-radius: 15px;
457
+ border: 1px solid var(--border-color);
458
+ text-align: center;
459
+ display: none;
460
+ }
461
+
462
+ .loading-section.show {
463
+ display: block;
464
+ }
465
+
466
+ .spinner {
467
+ border: 4px solid var(--border-color);
468
+ border-top: 4px solid var(--accent-color);
469
+ border-radius: 50%;
470
+ width: 50px;
471
+ height: 50px;
472
+ animation: spin 1s linear infinite;
473
+ margin: 0 auto 20px auto;
474
+ }
475
+
476
+ .loading-text {
477
+ color: var(--text-primary);
478
+ font-size: 1.1rem;
479
+ font-weight: 500;
480
+ margin-bottom: 10px;
481
+ }
482
+
483
+ .loading-subtext {
484
+ color: var(--text-secondary);
485
+ font-size: 0.95rem;
486
+ }
487
+
488
+ @keyframes spin {
489
+ 100% {
490
+ transform: rotate(360deg);
491
+ }
492
+ }
493
+
494
+ .toast {
495
+ position: fixed;
496
+ top: 20px;
497
+ right: 20px;
498
+ color: white;
499
+ padding: 12px 20px;
500
+ border-radius: 8px;
501
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
502
+ z-index: 1000;
503
+ font-weight: 600;
504
+ transform: translateX(calc(100% + 20px));
505
+ transition: transform 0.4s ease-in-out;
506
+ }
507
+
508
+ .toast.show {
509
+ transform: translateX(0);
510
+ }
511
+
512
+ .toast.successo {
513
+ background: var(--success-color);
514
+ }
515
+
516
+ .toast.errore {
517
+ background: var(--error-color);
518
+ }
519
+
520
+ .toast.info {
521
+ background: var(--info-color);
522
+ }
523
+
524
+ @media (max-width: 600px) {
525
+ body {
526
+ padding: 10px;
527
+ }
528
+
529
+ .container {
530
+ border-radius: 15px;
531
+ }
532
+
533
+ .main-content {
534
+ padding: 20px;
535
+ }
536
+
537
+ .subordinate-clause {
538
+ margin-left: 15px;
539
+ }
540
+
541
+ #sentenceInput {
542
+ min-height: 100px;
543
+ padding: 15px;
544
+ padding-right: 50px;
545
+ }
546
+
547
+ .example-btn {
548
+ font-size: 13px;
549
+ padding: 6px 10px;
550
+ }
551
+
552
+ .format-selector {
553
+ flex-direction: column;
554
+ align-items: center;
555
+ gap: 8px;
556
+ }
557
+
558
+ .format-btn {
559
+ width: 150px;
560
+ }
561
+
562
+ .table-format {
563
+ font-size: 0.9rem;
564
+ }
565
+
566
+ .table-format th,
567
+ .table-format td {
568
+ padding: 8px;
569
+ }
570
+
571
+ .loading-section {
572
+ padding: 30px 15px;
573
+ }
574
+ }
575
+ </style>
576
+ </head>
577
+
578
+ <body>
579
+ <div class="container">
580
+ <div class="header">
581
+ <button class="theme-toggle">☾</button>
582
+ <h1>Analisi Logica Avanzata</h1>
583
+ <p>Scomponi qualsiasi frase con la potenza dell'IA</p>
584
+ </div>
585
+
586
+ <div class="main-content">
587
+ <div class="input-section">
588
+ <div class="input-container">
589
+ <textarea id="sentenceInput"
590
+ placeholder="Es: Il ragazzo, che ha studiato molto, ha superato l'esame con un ottimo voto."
591
+ rows="4"></textarea>
592
+ <button id="voiceInputBtn" class="voice-btn" title="Avvia riconoscimento vocale">
593
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" width="24"
594
+ height="24">
595
+ <path
596
+ d="M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6 6.72V21h2v-3.28c3.28-.49 6-3.31 6-6.72h-1.7z" />
597
+ </svg>
598
+ </button>
599
+ </div>
600
+ <button class="analyze-btn" onclick="analizzaFrase()">Analizza Frase</button>
601
+ </div>
602
+
603
+ <div class="examples">
604
+ <h3>Oppure prova con un esempio:</h3>
605
+ <button class="example-btn"
606
+ onclick="impostaEsempio('Il cane corre velocemente nel parco.')">Semplice</button>
607
+ <button class="example-btn"
608
+ onclick="impostaEsempio('Maria ha regalato a suo fratello un libro che era molto interessante.')">Con
609
+ Subordinata</button>
610
+ <button class="example-btn"
611
+ onclick="impostaEsempio('Mentre il sole tramontava, la nave salpava dal porto di Genova.')">Complessa</button>
612
+ <button class="example-btn"
613
+ onclick="impostaEsempio('Il Colosseo fu costruito dagli imperatori Flavi per intrattenere il popolo.')">Passiva</button>
614
+ </div>
615
+
616
+ <!-- Loading section at the bottom -->
617
+ <div id="loadingSection" class="loading-section">
618
+ <div class="spinner"></div>
619
+ <div class="loading-text">Analisi in corso...</div>
620
+ <div class="loading-subtext">Stiamo processando la tua frase con intelligenza artificiale</div>
621
+ </div>
622
+
623
+ <div id="results" class="results"></div>
624
+ </div>
625
+ </div>
626
+
627
+ <script>
628
+ let formatoCorrente = 'visuale';
629
+ const API_URL = 'https://devusman-analysis-tool.hf.space/api/analyze';
630
+
631
+ const etichettaAClasseColore = {
632
+ 'Soggetto': 'subject',
633
+ 'Predicato Verbale': 'predicate',
634
+ 'Parte Nominale del Predicato': 'predicate',
635
+ 'Copula': 'predicate',
636
+ 'Complemento Oggetto': 'object',
637
+ 'Complemento di Termine': 'complement',
638
+ 'Complemento di Specificazione': 'complement',
639
+ 'Complemento d\'Agente': 'complement',
640
+ 'Complemento di Moto da Luogo': 'complement',
641
+ 'Complemento di Stato in Luogo': 'complement',
642
+ 'Complemento di Compagnia o Mezzo': 'complement',
643
+ 'Complemento di Argomento o Luogo': 'complement',
644
+ 'Complemento di Fine o Causa': 'complement',
645
+ 'Complemento di Luogo o Tempo (Partitivo)': 'complement',
646
+ 'Complemento Indiretto': 'complement',
647
+ 'Attributo': 'modifier',
648
+ 'Apposizione': 'modifier',
649
+ 'Complemento Avverbiale': 'modifier',
650
+ 'Proposizione Subordinata Relativa': 'clause',
651
+ 'Proposizione Subordinata Avverbiale': 'clause',
652
+ 'Proposizione Subordinata Oggettiva': 'clause',
653
+ 'Proposizione Subordinata Soggettiva': 'clause'
654
+ };
655
+
656
+ document.addEventListener('DOMContentLoaded', () => {
657
+ const cambiaTemaBtn = document.querySelector('.theme-toggle');
658
+ const temaSalvato = localStorage.getItem('tema') || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'scuro' : 'chiaro');
659
+ document.documentElement.setAttribute('data-theme', temaSalvato);
660
+ cambiaTemaBtn.textContent = temaSalvato === 'scuro' ? '☀️' : '☾';
661
+ cambiaTemaBtn.addEventListener('click', cambiaTema);
662
+ impostaRiconoscimentoVocale();
663
+ document.getElementById('sentenceInput').addEventListener('keydown', (e) => {
664
+ if (e.key === 'Enter' && !e.shiftKey) {
665
+ e.preventDefault();
666
+ analizzaFrase();
667
+ }
668
+ });
669
+ });
670
+
671
+ function cambiaTema() {
672
+ const temaCorrente = document.documentElement.getAttribute('data-theme');
673
+ const nuovoTema = temaCorrente === 'scuro' ? 'chiaro' : 'scuro';
674
+ document.documentElement.setAttribute('data-theme', nuovoTema);
675
+ localStorage.setItem('tema', nuovoTema);
676
+ document.querySelector('.theme-toggle').textContent = nuovoTema === 'scuro' ? '☀️' : '☾';
677
+ }
678
+
679
+ function impostaEsempio(frase) {
680
+ document.getElementById('sentenceInput').value = frase;
681
+ analizzaFrase();
682
+ }
683
+
684
+ function impostaFormato(formato) {
685
+ formatoCorrente = formato;
686
+ const risultatiDiv = document.getElementById('results');
687
+ if (risultatiDiv.dataset.analysis) {
688
+ const analisi = JSON.parse(risultatiDiv.dataset.analysis);
689
+ mostraRisultati(analisi);
690
+ }
691
+ }
692
+
693
+ async function analizzaFrase() {
694
+ const frase = document.getElementById('sentenceInput').value.trim();
695
+ const risultatiDiv = document.getElementById('results');
696
+ const sezioneCaricamento = document.getElementById('loadingSection');
697
+ const analizzaBtn = document.querySelector('.analyze-btn');
698
+
699
+ if (!frase) {
700
+ mostraNotifica('Per favore, inserisci una frase.', 'info');
701
+ return;
702
+ }
703
+
704
+ sezioneCaricamento.classList.add('show');
705
+ risultatiDiv.style.display = 'none';
706
+ analizzaBtn.disabled = true;
707
+ analizzaBtn.textContent = 'Analizzando...';
708
+ risultatiDiv.dataset.analysis = "";
709
+
710
+ try {
711
+ const response = await fetch(API_URL, {
712
+ method: 'POST',
713
+ headers: { 'Content-Type': 'application/json' },
714
+ body: JSON.stringify({ sentence: frase }),
715
+ });
716
+ if (!response.ok) {
717
+ const datiErrore = await response.json().catch(() => ({}));
718
+ throw new Error(datiErrore.error || `Errore del server: ${response.status}`);
719
+ }
720
+ const analisi = await response.json();
721
+ risultatiDiv.dataset.analysis = JSON.stringify(analisi);
722
+
723
+ sezioneCaricamento.classList.remove('show');
724
+ mostraRisultati(analisi);
725
+ mostraNotifica('Analisi completata!', 'successo');
726
+ } catch (errore) {
727
+ console.error('Errore di analisi:', errore);
728
+ sezioneCaricamento.classList.remove('show');
729
+ risultatiDiv.innerHTML = `
730
+ <div class="result-item" style="text-align: center; color: var(--error-color); border-color: var(--error-color);">
731
+ <h3 style="margin-bottom: 10px;">Errore nell'analisi</h3>
732
+ <p>${errore.message}</p>
733
+ </div>`;
734
+ risultatiDiv.style.display = 'block';
735
+ mostraNotifica('Analisi fallita. Riprova.', 'errore');
736
+ } finally {
737
+ analizzaBtn.disabled = false;
738
+ analizzaBtn.textContent = 'Analizza Frase';
739
+ }
740
+ }
741
+
742
+ function mostraRisultati(analisi) {
743
+ const risultatiDiv = document.getElementById('results');
744
+ let html = `
745
+ <h2 style="color: var(--text-primary); margin-bottom: 20px; text-align: center; font-size: 1.8rem;">Risultati dell'Analisi</h2>
746
+ <div class="format-selector">
747
+ <button class="format-btn ${formatoCorrente === 'visuale' ? 'active' : ''}" onclick="impostaFormato('visuale')">📊 Visuale</button>
748
+ <button class="format-btn ${formatoCorrente === 'tabella' ? 'active' : ''}" onclick="impostaFormato('tabella')">📋 Tabella</button>
749
+ </div>`;
750
+
751
+ if (analisi.main_clause && analisi.main_clause.analysis.length > 0) {
752
+ html += generaHTMLClausola(analisi.main_clause, 'Proposizione Principale', false);
753
+ }
754
+
755
+ if (analisi.subordinate_clauses && analisi.subordinate_clauses.length > 0) {
756
+ analisi.subordinate_clauses.forEach(subClausola => {
757
+ const titolo = subClausola.type_info ? subClausola.type_info.label : 'Proposizione Subordinata';
758
+ html += generaHTMLClausola(subClausola, titolo, true, subClausola.intro);
759
+ });
760
+ }
761
+
762
+ if (analisi.named_entities && analisi.named_entities.length > 0) {
763
+ html += generaHTMLEntita(analisi.named_entities);
764
+ }
765
+
766
+ risultatiDiv.innerHTML = html;
767
+ risultatiDiv.style.display = 'block';
768
+ }
769
+
770
+ function generaHTMLClausola(datiClausola, titolo, isSubordinata = false, intro = '') {
771
+ const classeClausola = isSubordinata ? 'result-item subordinate-clause' : 'result-item';
772
+ const testoAnalisiPerCopia = datiClausola.analysis.map(item =>
773
+ `${item.text} (${item.label_info.label}: ${item.label_info.description})`
774
+ ).join('\n');
775
+
776
+ let html = `<div class="${classeClausola}">
777
+ <div class="result-header">
778
+ <div>
779
+ <div class="result-title">${titolo}</div>
780
+ ${isSubordinata && intro ? `<div class="result-subtitle">Introdotta da: <strong>${intro}</strong></div>` : ''}
781
+ </div>
782
+ <button class="copy-btn" onclick="copiaNegliAppunti(\`${testoAnalisiPerCopia.replace(/`/g, '\\`')}\`)">📋 Copia Analisi</button>
783
+ </div>`;
784
+
785
+ if (formatoCorrente === 'visuale') {
786
+ const scomposizioneVisuale = datiClausola.analysis.map(item => {
787
+ const classeColore = etichettaAClasseColore[item.label_info.label] || 'complement';
788
+ // MODIFICA 1: Rimuove i dettagli grammaticali dal tooltip
789
+ const tooltip = `FUNZIONE: ${item.label_info.label}\nDESCRIZIONE: ${item.label_info.description}`;
790
+ return `<span class="component ${classeColore}" title="${tooltip}">${item.text}</span>`;
791
+ }).join(' ');
792
+ html += `<div style="font-size: 1.1rem; line-height: 2.2; margin-top: 15px;">${scomposizioneVisuale}</div>`;
793
+ } else { // formato tabella
794
+ // MODIFICA 2: Rimuove l'intestazione della colonna "Dettagli Grammaticali"
795
+ html += `<table class="table-format">
796
+ <thead><tr><th>Elemento</th><th>Funzione Logica</th></tr></thead>
797
+ <tbody>`;
798
+ datiClausola.analysis.forEach(item => {
799
+ const classeColore = etichettaAClasseColore[item.label_info.label] || 'complement';
800
+ // MODIFICA 3: Rimuove la cella della tabella con i dettagli
801
+ html += `<tr>
802
+ <td><span class="component ${classeColore}">${item.text}</span></td>
803
+ <td>
804
+ ${item.label_info.label}
805
+ <small>${item.label_info.description}</small>
806
+ </td>
807
+ </tr>`;
808
+ });
809
+ html += `</tbody></table>`;
810
+ }
811
+ html += `</div>`;
812
+ return html;
813
+ }
814
+
815
+ function generaHTMLEntita(entita) {
816
+ let html = `
817
+ <div class="result-item entities-container">
818
+ <div class="result-header"><div class="result-title">Entità Riconosciute</div></div>
819
+ `;
820
+ entita.forEach(ent => {
821
+ html += `
822
+ <div class="entity-tag">
823
+ <span class="entity-text">${ent.text}</span>
824
+ <span class="entity-label">${ent.label}</span>
825
+ <span class="entity-explanation">${ent.explanation}</span>
826
+ </div>
827
+ `;
828
+ });
829
+ html += `</div>`;
830
+ return html;
831
+ }
832
+
833
+ function impostaRiconoscimentoVocale() {
834
+ const voiceBtn = document.getElementById('voiceInputBtn');
835
+ const sentenceInput = document.getElementById('sentenceInput');
836
+ const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
837
+ if (!SpeechRecognition) {
838
+ voiceBtn.style.display = 'none';
839
+ return;
840
+ }
841
+ const recognition = new SpeechRecognition();
842
+ recognition.lang = 'it-IT';
843
+ recognition.interimResults = false;
844
+ recognition.maxAlternatives = 1;
845
+ voiceBtn.addEventListener('click', () => {
846
+ if (voiceBtn.classList.contains('is-listening')) {
847
+ recognition.stop();
848
+ } else {
849
+ recognition.start();
850
+ }
851
+ });
852
+ recognition.onstart = () => {
853
+ voiceBtn.classList.add('is-listening');
854
+ mostraNotifica('Ascolto in corso...', 'info');
855
+ };
856
+ recognition.onend = () => voiceBtn.classList.remove('is-listening');
857
+ recognition.onerror = (event) => {
858
+ mostraNotifica(`Errore: ${event.error}`, 'errore');
859
+ voiceBtn.classList.remove('is-listening');
860
+ };
861
+ recognition.onresult = (event) => {
862
+ sentenceInput.value = event.results[0][0].transcript;
863
+ mostraNotifica('Frase trascritta! Clicca per analizzare.', 'successo');
864
+ };
865
+ }
866
+
867
+ function copiaNegliAppunti(testo) {
868
+ navigator.clipboard.writeText(testo).then(() => {
869
+ mostraNotifica('Analisi copiata negli appunti!', 'successo');
870
+ }, (err) => {
871
+ mostraNotifica('Errore nella copia', 'errore');
872
+ console.error('Copia fallita:', err);
873
+ });
874
+ }
875
+
876
+ function mostraNotifica(messaggio, tipo = 'successo') {
877
+ document.querySelectorAll('.toast').forEach(t => t.remove());
878
+ const notifica = document.createElement('div');
879
+ notifica.className = `toast ${tipo}`;
880
+ notifica.textContent = messaggio;
881
+ document.body.appendChild(notifica);
882
+ setTimeout(() => notifica.classList.add('show'), 10);
883
+ setTimeout(() => {
884
+ notifica.classList.remove('show');
885
+ setTimeout(() => notifica.remove(), 400);
886
+ }, 3000);
887
+ }
888
+ </script>
889
+ </body>
890
+
891
+ </html>
selfanalysis-ui/selfanalysis.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Plugin Name: Self Analysis Tool
4
+ * Description: Provides a shortcode [selfanalysistool] to embed the index.html file on any page or post.
5
+ * Version: 1.2.0
6
+ * Author: Muhammad Usman
7
+ * Author URI: https://devusman.vercel.app
8
+ * License: GPL-2.0+
9
+ * License URI: http://www.gnu.org/licenses/gpl-2.0.txt
10
+ * Text Domain: selfanalysistool
11
+ */
12
+
13
+ // Abort if this file is called directly
14
+ if (!defined('WPINC')) {
15
+ die;
16
+ }
17
+
18
+
19
+ /**
20
+ * Shortcode callback function
21
+ */
22
+ function selfanalysistool_shortcode_handler($atts)
23
+ {
24
+ // Enqueue styles and scripts only when shortcode is used
25
+
26
+ $file_path = plugin_dir_path(__FILE__) . 'index.html';
27
+ if (file_exists($file_path)) {
28
+ ob_start();
29
+ include($file_path);
30
+ return ob_get_clean();
31
+ } else {
32
+ if (current_user_can('manage_options')) {
33
+ return 'Error: index.html not found in selfanalysistool plugin directory.';
34
+ }
35
+ return '';
36
+ }
37
+ }
38
+ add_shortcode('selfanalysistool', 'selfanalysistool_shortcode_handler');