atlury commited on
Commit
0172488
·
verified ·
1 Parent(s): 860c0c2

Create index.html

Browse files
Files changed (1) hide show
  1. index.html +916 -0
index.html ADDED
@@ -0,0 +1,916 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Aged Guru Education Assistant</title>
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <!-- Google Fonts for better typography -->
8
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&family=Roboto:wght@400;500&display=swap" rel="stylesheet">
9
+ <!-- Include necessary CSS styles -->
10
+ <style>
11
+ /* Reset and base styles */
12
+ * {
13
+ box-sizing: border-box;
14
+ margin: 0;
15
+ padding: 0;
16
+ }
17
+
18
+ body {
19
+ font-family: 'Inter', sans-serif;
20
+ background-color: #f9f9f9;
21
+ display: flex;
22
+ min-height: 100vh;
23
+ color: #333;
24
+ overflow: hidden;
25
+ }
26
+
27
+ /* Sidebar styling */
28
+ .sidebar {
29
+ width: 260px;
30
+ background-color: #ffffff;
31
+ box-shadow: 2px 0 5px rgba(0,0,0,0.1);
32
+ flex-shrink: 0;
33
+ display: flex;
34
+ flex-direction: column;
35
+ padding: 30px 20px;
36
+ position: fixed;
37
+ height: 100%;
38
+ overflow-y: auto;
39
+ transition: width 0.3s ease;
40
+ }
41
+
42
+ .sidebar h2 {
43
+ text-align: center;
44
+ margin-bottom: 40px;
45
+ font-family: 'Roboto', sans-serif;
46
+ font-weight: 600;
47
+ font-size: 1.6em;
48
+ color: #4A4A4A;
49
+ }
50
+
51
+ .sidebar a {
52
+ color: #555555;
53
+ padding: 12px 15px;
54
+ text-decoration: none;
55
+ font-size: 1em;
56
+ border-radius: 8px;
57
+ margin-bottom: 10px;
58
+ transition: background-color 0.3s, color 0.3s, transform 0.2s;
59
+ display: flex;
60
+ align-items: center;
61
+ }
62
+
63
+ .sidebar a:hover {
64
+ background-color: #f0f0f0;
65
+ color: #333333;
66
+ transform: translateX(5px);
67
+ }
68
+
69
+ .sidebar a.active {
70
+ background-color: #e0f7fa;
71
+ color: #00796B;
72
+ font-weight: 500;
73
+ }
74
+
75
+ .sidebar a::before {
76
+ content: '';
77
+ display: inline-block;
78
+ width: 6px;
79
+ height: 6px;
80
+ background-color: #00796B;
81
+ border-radius: 50%;
82
+ margin-right: 10px;
83
+ opacity: 0;
84
+ transition: opacity 0.3s;
85
+ }
86
+
87
+ .sidebar a.active::before {
88
+ opacity: 1;
89
+ }
90
+
91
+ /* Main content styling */
92
+ .main-content {
93
+ margin-left: 260px;
94
+ padding: 30px;
95
+ flex: 1;
96
+ background-color: #f9f9f9;
97
+ overflow-y: auto;
98
+ height: 100vh;
99
+ transition: margin-left 0.3s ease;
100
+ }
101
+
102
+ /* Header */
103
+ .header {
104
+ display: flex;
105
+ justify-content: space-between;
106
+ align-items: center;
107
+ margin-bottom: 25px;
108
+ }
109
+
110
+ .header h1 {
111
+ font-family: 'Roboto', sans-serif;
112
+ font-size: 2em;
113
+ color: #333333;
114
+ }
115
+
116
+ /* Card Styling */
117
+ .card {
118
+ background-color: #ffffff;
119
+ border-radius: 12px;
120
+ box-shadow: 0 4px 10px rgba(0,0,0,0.05);
121
+ padding: 25px;
122
+ margin-bottom: 25px;
123
+ transition: transform 0.3s, box-shadow 0.3s;
124
+ }
125
+
126
+ .card:hover {
127
+ transform: translateY(-5px);
128
+ box-shadow: 0 6px 15px rgba(0,0,0,0.1);
129
+ }
130
+
131
+ /* Button Styling */
132
+ button {
133
+ background-color: #00796B;
134
+ border: none;
135
+ color: white;
136
+ padding: 12px 20px;
137
+ font-size: 1em;
138
+ border-radius: 8px;
139
+ cursor: pointer;
140
+ transition: background-color 0.3s, transform 0.2s;
141
+ }
142
+
143
+ button:hover {
144
+ background-color: #005D56;
145
+ transform: translateY(-2px);
146
+ }
147
+
148
+ button:disabled {
149
+ background-color: #A5D6A7;
150
+ cursor: not-allowed;
151
+ }
152
+
153
+ /* Select Dropdown Styling */
154
+ select {
155
+ width: 100%;
156
+ padding: 10px 15px;
157
+ border: 1px solid #cccccc;
158
+ border-radius: 8px;
159
+ font-size: 1em;
160
+ background-color: #ffffff;
161
+ transition: border-color 0.3s;
162
+ margin-bottom: 15px;
163
+ }
164
+
165
+ select:focus {
166
+ border-color: #00796B;
167
+ outline: none;
168
+ }
169
+
170
+ /* Chat Box Styling */
171
+ #chat-box {
172
+ height: 400px;
173
+ border: 1px solid #e0e0e0;
174
+ border-radius: 12px;
175
+ overflow-y: auto;
176
+ padding: 20px;
177
+ background-color: #fafafa;
178
+ margin-bottom: 20px;
179
+ position: relative;
180
+ box-shadow: inset 0 2px 4px rgba(0,0,0,0.05);
181
+ }
182
+
183
+ .message-container {
184
+ margin-bottom: 20px;
185
+ display: flex;
186
+ }
187
+
188
+ .message {
189
+ padding: 12px 18px;
190
+ border-radius: 20px;
191
+ max-width: 75%;
192
+ position: relative;
193
+ word-wrap: break-word;
194
+ box-shadow: 0 2px 8px rgba(0,0,0,0.05);
195
+ font-size: 0.95em;
196
+ line-height: 1.4;
197
+ }
198
+
199
+ .user {
200
+ justify-content: flex-end;
201
+ }
202
+
203
+ .user .message {
204
+ background-color: #DCF8C6;
205
+ border-bottom-right-radius: 0;
206
+ }
207
+
208
+ .assistant {
209
+ justify-content: flex-start;
210
+ }
211
+
212
+ .assistant .message {
213
+ background-color: #FFFFFF;
214
+ border-bottom-left-radius: 0;
215
+ }
216
+
217
+ /* Microphone Button Styling */
218
+ #mic-container {
219
+ text-align: center;
220
+ margin-bottom: 20px;
221
+ }
222
+
223
+ /* Updated Start Button */
224
+ #start_button {
225
+ background-color: #00796B;
226
+ border: none;
227
+ color: white;
228
+ padding: 15px;
229
+ border-radius: 50%;
230
+ cursor: pointer;
231
+ transition: background-color 0.3s, transform 0.2s;
232
+ width: 60px;
233
+ height: 60px;
234
+ display: flex;
235
+ justify-content: center;
236
+ align-items: center;
237
+ position: relative;
238
+ overflow: hidden;
239
+ }
240
+
241
+ #start_button::before {
242
+ content: '';
243
+ position: absolute;
244
+ width: 200%;
245
+ height: 200%;
246
+ background: rgba(255, 255, 255, 0.3);
247
+ top: 50%;
248
+ left: 50%;
249
+ transform: translate(-50%, -50%) scale(0);
250
+ border-radius: 50%;
251
+ transition: transform 0.5s ease-out;
252
+ }
253
+
254
+ #start_button:active::before {
255
+ transform: translate(-50%, -50%) scale(1);
256
+ }
257
+
258
+ #start_button:disabled {
259
+ background-color: #A5D6A7;
260
+ cursor: not-allowed;
261
+ }
262
+
263
+ #start_button:hover:not(:disabled) {
264
+ background-color: #005D56;
265
+ transform: scale(1.05);
266
+ }
267
+
268
+ /* Icon Styling */
269
+ .mic-icon {
270
+ width: 30px;
271
+ height: 30px;
272
+ transition: transform 0.3s;
273
+ }
274
+
275
+ /* Animation for Mic Icon */
276
+ .mic-animate {
277
+ animation: pulse 2s infinite;
278
+ }
279
+
280
+ @keyframes pulse {
281
+ 0% {
282
+ transform: scale(1);
283
+ }
284
+ 50% {
285
+ transform: scale(1.2);
286
+ }
287
+ 100% {
288
+ transform: scale(1);
289
+ }
290
+ }
291
+
292
+ /* Logs Styling */
293
+ #logs {
294
+ height: 120px;
295
+ border: 1px solid #e0e0e0;
296
+ border-radius: 12px;
297
+ overflow-y: auto;
298
+ padding: 15px;
299
+ background-color: #f1f1f1;
300
+ font-size: 0.85em;
301
+ margin-bottom: 10px;
302
+ box-shadow: inset 0 2px 4px rgba(0,0,0,0.05);
303
+ }
304
+
305
+ #clear-logs {
306
+ background-color: #FF5252;
307
+ border: none;
308
+ color: white;
309
+ padding: 10px 18px;
310
+ font-size: 0.9em;
311
+ cursor: pointer;
312
+ border-radius: 8px;
313
+ transition: background-color 0.3s, transform 0.2s;
314
+ }
315
+
316
+ #clear-logs:hover {
317
+ background-color: #E53935;
318
+ transform: scale(1.02);
319
+ }
320
+
321
+ /* Chat Stats */
322
+ #chat-stats {
323
+ font-size: 0.85em;
324
+ color: #888888;
325
+ text-align: center;
326
+ margin-top: 10px;
327
+ }
328
+
329
+ /* Voice Selection Container */
330
+ #tts-voice-container label {
331
+ display: block;
332
+ margin-bottom: 8px;
333
+ color: #555555;
334
+ font-weight: 500;
335
+ }
336
+
337
+ /* Hidden Class */
338
+ .hidden {
339
+ display: none;
340
+ }
341
+
342
+ /* Scrollbar Styling */
343
+ #chat-box::-webkit-scrollbar,
344
+ #logs::-webkit-scrollbar {
345
+ width: 8px;
346
+ }
347
+
348
+ #chat-box::-webkit-scrollbar-track,
349
+ #logs::-webkit-scrollbar-track {
350
+ background: #f1f1f1;
351
+ border-radius: 4px;
352
+ }
353
+
354
+ #chat-box::-webkit-scrollbar-thumb,
355
+ #logs::-webkit-scrollbar-thumb {
356
+ background: #cccccc;
357
+ border-radius: 4px;
358
+ }
359
+
360
+ #chat-box::-webkit-scrollbar-thumb:hover,
361
+ #logs::-webkit-scrollbar-thumb:hover {
362
+ background: #a8a8a8;
363
+ }
364
+
365
+ /* Responsive Adjustments */
366
+ @media (max-width: 768px) {
367
+ .sidebar {
368
+ width: 220px;
369
+ }
370
+
371
+ .main-content {
372
+ margin-left: 220px;
373
+ }
374
+ }
375
+
376
+ @media (max-width: 600px) {
377
+ .sidebar {
378
+ position: relative;
379
+ width: 100%;
380
+ height: auto;
381
+ flex-direction: row;
382
+ overflow-x: auto;
383
+ padding: 15px 10px;
384
+ }
385
+
386
+ .sidebar h2 {
387
+ display: none;
388
+ }
389
+
390
+ .sidebar a {
391
+ margin-right: 10px;
392
+ margin-bottom: 0;
393
+ padding: 10px 12px;
394
+ font-size: 0.9em;
395
+ }
396
+
397
+ .main-content {
398
+ margin-left: 0;
399
+ padding: 20px 15px;
400
+ }
401
+
402
+ .header {
403
+ flex-direction: column;
404
+ align-items: flex-start;
405
+ }
406
+
407
+ .header h1 {
408
+ margin-bottom: 10px;
409
+ font-size: 1.5em;
410
+ }
411
+ }
412
+
413
+ /* Controls Container Styling */
414
+ #controls {
415
+ display: flex;
416
+ gap: 10px;
417
+ margin-bottom: 15px;
418
+ flex-wrap: wrap;
419
+ }
420
+
421
+ /* Initialize Button Styling */
422
+ #download {
423
+ flex: 0 0 auto;
424
+ background-color: #00796B;
425
+ border: none;
426
+ color: white;
427
+ padding: 10px 20px;
428
+ font-size: 1em;
429
+ border-radius: 8px;
430
+ cursor: pointer;
431
+ transition: background-color 0.3s, transform 0.2s;
432
+ }
433
+
434
+ #download:hover {
435
+ background-color: #005D56;
436
+ transform: translateY(-2px);
437
+ }
438
+
439
+ #download:disabled {
440
+ background-color: #A5D6A7;
441
+ cursor: not-allowed;
442
+ }
443
+
444
+ /* Enhanced Layout for Digital Human Mentor Voice Section */
445
+ #voice .card {
446
+ display: grid;
447
+ grid-template-columns: 1fr 1fr;
448
+ grid-gap: 20px;
449
+ }
450
+
451
+ /* Adjust controls and voice selection */
452
+ #model-selection-container,
453
+ #tts-voice-container {
454
+ display: flex;
455
+ flex-direction: column;
456
+ }
457
+
458
+ #model-selection-container label,
459
+ #tts-voice-container label {
460
+ margin-bottom: 5px;
461
+ font-weight: 500;
462
+ color: #555555;
463
+ }
464
+
465
+ /* Chat and Controls Layout */
466
+ #chat-container {
467
+ display: flex;
468
+ flex-direction: column;
469
+ }
470
+
471
+ /* Ensure chat-box takes full width */
472
+ #chat-box {
473
+ width: 100%;
474
+ }
475
+
476
+ /* Adjust microphone container */
477
+ #mic-container {
478
+ display: flex;
479
+ justify-content: center;
480
+ margin-bottom: 20px;
481
+ }
482
+
483
+ /* Configuration Info */
484
+ #configuration {
485
+ margin-top: 15px;
486
+ font-size: 0.9em;
487
+ color: #555555;
488
+ }
489
+
490
+ /* Responsive Grid Adjustments */
491
+ @media (max-width: 800px) {
492
+ #voice .card {
493
+ grid-template-columns: 1fr;
494
+ }
495
+ }
496
+ </style>
497
+ </head>
498
+ <body>
499
+
500
+ <!-- Sidebar -->
501
+ <div class="sidebar">
502
+ <h2>Aged Guru</h2>
503
+ <a href="#" class="active" data-content="voice">Digital Human Mentor Voice</a>
504
+ <a href="#" data-content="video">Digital Human Mentor Video</a>
505
+ <a href="#" data-content="math-assistant">Virtual Math Assistant</a>
506
+ <a href="#" data-content="advanced-math">Advanced Mathematics & Problem Solving</a>
507
+ <a href="#" data-content="interdisciplinary">Interdisciplinary Studies Assistant</a>
508
+ <a href="#" data-content="document-insights">Document Insights</a>
509
+ <a href="#" data-content="3d-explorer">3D Explorer</a>
510
+ <a href="#" data-content="knowledge-base">Knowledge Base</a>
511
+ <a href="#" data-content="">Digital Twin</a>
512
+ <a href="#" data-content="">Student</a>
513
+ <a href="#" data-content="">Teacher</a>
514
+ </div>
515
+
516
+ <!-- Main Content -->
517
+ <div class="main-content" id="main-content">
518
+ <div class="header">
519
+ <h1>Aged Guru Education Assistant</h1>
520
+ <!-- You can add user profile or settings here -->
521
+ </div>
522
+ <!-- Content will be loaded here -->
523
+ <div id="content-area">
524
+ <!-- Digital Human Mentor Voice Content Starts -->
525
+ <div id="voice" class="content-section">
526
+ <div class="card">
527
+ <!-- Model Selection Section -->
528
+ <div id="model-selection-container">
529
+ <label for="model-selection">Select Language Model:</label>
530
+ <select id="model-selection"></select>
531
+ <button id="download">Initialize</button>
532
+ </div>
533
+
534
+ <!-- Voice Selection Section -->
535
+ <div id="tts-voice-container">
536
+ <label for="voices">Select Voice:</label>
537
+ <select id="voices"></select>
538
+ </div>
539
+ </div>
540
+
541
+ <div id="chat-container">
542
+ <div id="configuration" class="hidden">
543
+ <div id="model-info">
544
+ <strong>LLM:</strong> <span id="selected-model">Not Initialized</span>
545
+ </div>
546
+ </div>
547
+ <div id="chat-box"></div>
548
+
549
+ <!-- Microphone button -->
550
+ <div id="mic-container">
551
+ <button id="start_button" disabled>
552
+ <svg class="mic-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
553
+ <path d="M12 14a3 3 0 003-3V5a3 3 0 00-6 0v6a3 3 0 003 3zm5-3a5 5 0 01-10 0H5a7 7 0 0014 0h-2z"/>
554
+ </svg>
555
+ </button>
556
+ </div>
557
+
558
+ <div id="chat-stats" class="hidden"></div>
559
+ </div>
560
+
561
+ <h3>Logs</h3>
562
+ <div id="logs">
563
+ <div id="download-status" class="hidden"></div>
564
+ </div>
565
+ <button id="clear-logs">Clear Logs</button>
566
+ </div>
567
+ <!-- Digital Human Mentor Voice Content Ends -->
568
+
569
+ <!-- Placeholder for other sections -->
570
+ <div id="video" class="content-section hidden">
571
+ <div class="card">
572
+ <h2>Interactive Digital Human Mentor Video</h2>
573
+ <p>Content for Video Mentor will go here.</p>
574
+ </div>
575
+ </div>
576
+
577
+ <div id="math-assistant" class="content-section hidden">
578
+ <div class="card">
579
+ <h2>Virtual Math Assistant</h2>
580
+ <p>Content for Virtual Math Assistant will go here.</p>
581
+ </div>
582
+ </div>
583
+
584
+ <div id="advanced-math" class="content-section hidden">
585
+ <div class="card">
586
+ <h2>Advanced Mathematics & Problem Solving</h2>
587
+ <p>Content for Advanced Mathematics & Problem Solving will go here.</p>
588
+ </div>
589
+ </div>
590
+
591
+ <div id="interdisciplinary" class="content-section hidden">
592
+ <div class="card">
593
+ <h2>Interdisciplinary Studies Assistant</h2>
594
+ <p>Content for Interdisciplinary Studies Assistant will go here.</p>
595
+ </div>
596
+ </div>
597
+
598
+ <div id="document-insights" class="content-section hidden">
599
+ <div class="card">
600
+ <h2>Document Insights</h2>
601
+ <p>Content for Document Insights will go here.</p>
602
+ </div>
603
+ </div>
604
+
605
+ <div id="3d-explorer" class="content-section hidden">
606
+ <div class="card">
607
+ <h2>3D Explorer</h2>
608
+ <p>Content for 3D Explorer will go here.</p>
609
+ </div>
610
+ </div>
611
+
612
+ <div id="knowledge-base" class="content-section hidden">
613
+ <div class="card">
614
+ <h2>Knowledge Base</h2>
615
+ <p>Content for Knowledge Base will go here.</p>
616
+ </div>
617
+ </div>
618
+ </div>
619
+ </div>
620
+
621
+ <!-- Include the necessary scripts -->
622
+ <script type="module">
623
+ import * as webllm from "https://esm.run/@mlc-ai/web-llm";
624
+
625
+ // Sidebar navigation
626
+ const sidebarLinks = document.querySelectorAll('.sidebar a');
627
+ const contentSections = document.querySelectorAll('.content-section');
628
+
629
+ sidebarLinks.forEach(link => {
630
+ link.addEventListener('click', (e) => {
631
+ e.preventDefault();
632
+ // Remove active class from all links
633
+ sidebarLinks.forEach(l => l.classList.remove('active'));
634
+ // Add active class to the clicked link
635
+ link.classList.add('active');
636
+
637
+ // Hide all content sections
638
+ contentSections.forEach(section => section.classList.add('hidden'));
639
+
640
+ // Show the selected content section
641
+ const target = link.getAttribute('data-content');
642
+ document.getElementById(target).classList.remove('hidden');
643
+ });
644
+ });
645
+
646
+ // Initialize the Digital Human Mentor Voice section
647
+ const messages = [
648
+ {
649
+ content: "You are Chatbot, a friendly, helpful robot called Aged Guru. Respond to what the user said in a creative and helpful way, but keep your responses brief.\n" +
650
+ "Keep responses brief and legible. Your output will be converted to audio.\n" +
651
+ "Your responses will converted to audio. Please do not include any special characters in your response other than '!' or '?'.",
652
+ role: "system"
653
+ }
654
+ ];
655
+
656
+ const availableModels = webllm.prebuiltAppConfig.model_list.map(
657
+ (m) => m.model_id
658
+ );
659
+ let selectedModel = "TinyLlama-1.1B-Chat-v0.4-q4f32_1-MLC-1k";
660
+
661
+ function updateEngineInitProgressCallback(report) {
662
+ console.log("initialize", report.progress);
663
+ document.getElementById("download-status").textContent = report.text;
664
+ }
665
+
666
+ const engine = new webllm.MLCEngine();
667
+ engine.setInitProgressCallback(updateEngineInitProgressCallback);
668
+
669
+ async function initializeWebLLMEngine() {
670
+ document.getElementById("download-status").classList.remove("hidden");
671
+ selectedModel = document.getElementById("model-selection").value;
672
+ const config = {
673
+ temperature: 1.0,
674
+ top_p: 1
675
+ };
676
+ await engine.reload(selectedModel, config);
677
+ document.getElementById("selected-model").textContent = selectedModel;
678
+ document.getElementById("start_button").disabled = false;
679
+ document.getElementById("configuration").classList.remove("hidden");
680
+ }
681
+
682
+ async function streamingGenerating(messages, onUpdate, onFinish, onError) {
683
+ try {
684
+ let curMessage = "";
685
+ const completion = await engine.chat.completions.create({
686
+ stream: true,
687
+ messages
688
+ });
689
+ for await (const chunk of completion) {
690
+ const curDelta = chunk.choices[0].delta.content;
691
+ if (curDelta) {
692
+ curMessage += curDelta;
693
+ }
694
+ onUpdate(curMessage);
695
+ }
696
+ const finalMessage = await engine.getMessage();
697
+ onFinish(finalMessage);
698
+ } catch (err) {
699
+ onError(err);
700
+ }
701
+ }
702
+
703
+ function appendMessage(message) {
704
+ const chatBox = document.getElementById("chat-box");
705
+ const container = document.createElement("div");
706
+ container.classList.add("message-container");
707
+ const newMessage = document.createElement("div");
708
+ newMessage.classList.add("message");
709
+ newMessage.textContent = message.content;
710
+
711
+ if (message.role === "user") {
712
+ container.classList.add("user");
713
+ } else {
714
+ container.classList.add("assistant");
715
+ }
716
+
717
+ container.appendChild(newMessage);
718
+ chatBox.appendChild(container);
719
+ chatBox.scrollTop = chatBox.scrollHeight;
720
+
721
+ // If the message is from the assistant and not a placeholder, trigger TTS
722
+ if (message.role === "assistant" && message.content !== "typing...") {
723
+ speak(message.content);
724
+ }
725
+ }
726
+
727
+ function updateLastMessage(content) {
728
+ const messageDoms = document.getElementById("chat-box").querySelectorAll(".message");
729
+ const lastMessageDom = messageDoms[messageDoms.length - 1];
730
+ lastMessageDom.textContent = content;
731
+ }
732
+
733
+ function onSpeechRecognized(transcript) {
734
+ const input = transcript.trim();
735
+ const message = {
736
+ content: input,
737
+ role: "user"
738
+ };
739
+ if (input.length === 0) {
740
+ return;
741
+ }
742
+ document.getElementById("start_button").disabled = true;
743
+
744
+ messages.push(message);
745
+ appendMessage(message);
746
+
747
+ // Append "typing..." placeholder
748
+ const aiPlaceholder = {
749
+ content: "typing...",
750
+ role: "assistant"
751
+ };
752
+ appendMessage(aiPlaceholder);
753
+
754
+ const onFinishGenerating = (finalMessage) => {
755
+ // Remove the "typing..." placeholder
756
+ const chatBox = document.getElementById("chat-box");
757
+ const lastMessageContainer = chatBox.lastElementChild;
758
+ if (lastMessageContainer && lastMessageContainer.querySelector(".message").textContent === "typing...") {
759
+ chatBox.removeChild(lastMessageContainer);
760
+ }
761
+
762
+ // Append the final message
763
+ const aiMessage = {
764
+ content: finalMessage,
765
+ role: "assistant"
766
+ };
767
+ appendMessage(aiMessage);
768
+
769
+ document.getElementById("start_button").disabled = false;
770
+ engine.runtimeStatsText().then((statsText) => {
771
+ document.getElementById("chat-stats").classList.remove("hidden");
772
+ document.getElementById("chat-stats").textContent = statsText;
773
+ });
774
+ };
775
+
776
+ streamingGenerating(
777
+ messages,
778
+ updateLastMessage,
779
+ onFinishGenerating,
780
+ console.error
781
+ );
782
+ }
783
+
784
+ // Speech recognition code
785
+ var recognizing = false;
786
+ var ignore_onend;
787
+ var final_transcript = '';
788
+ var recognition;
789
+
790
+ function startButton(event) {
791
+ if (recognizing) {
792
+ recognition.stop();
793
+ return;
794
+ }
795
+ final_transcript = '';
796
+ recognition.lang = 'en-US';
797
+ recognition.start();
798
+ ignore_onend = false;
799
+ document.getElementById("start_button").classList.add("mic-animate");
800
+ }
801
+
802
+ if (!('webkitSpeechRecognition' in window)) {
803
+ alert("Web Speech API is not supported by this browser.");
804
+ } else {
805
+ recognition = new webkitSpeechRecognition();
806
+ recognition.continuous = false; // Non-continuous recognition
807
+ recognition.interimResults = false; // Get only final results
808
+
809
+ recognition.onstart = function() {
810
+ recognizing = true;
811
+ };
812
+
813
+ recognition.onerror = function(event) {
814
+ if (event.error == 'no-speech') {
815
+ document.getElementById("start_button").classList.remove("mic-animate");
816
+ alert('No speech was detected.');
817
+ ignore_onend = true;
818
+ }
819
+ if (event.error == 'audio-capture') {
820
+ document.getElementById("start_button").classList.remove("mic-animate");
821
+ alert('No microphone was found.');
822
+ ignore_onend = true;
823
+ }
824
+ if (event.error == 'not-allowed') {
825
+ alert('Permission to use microphone was denied.');
826
+ ignore_onend = true;
827
+ }
828
+ };
829
+
830
+ recognition.onend = function() {
831
+ recognizing = false;
832
+ document.getElementById("start_button").classList.remove("mic-animate");
833
+ if (ignore_onend) {
834
+ return;
835
+ }
836
+ if (!final_transcript) {
837
+ return;
838
+ }
839
+ // Process the final transcript
840
+ onSpeechRecognized(final_transcript);
841
+ };
842
+
843
+ recognition.onresult = function(event) {
844
+ for (var i = event.resultIndex; i < event.results.length; ++i) {
845
+ if (event.results[i].isFinal) {
846
+ final_transcript += event.results[i][0].transcript;
847
+ }
848
+ }
849
+ final_transcript = final_transcript.trim();
850
+ };
851
+ }
852
+
853
+ document.getElementById("start_button").addEventListener("click", function(event) {
854
+ startButton(event);
855
+ });
856
+
857
+ // Initialize model selection
858
+ availableModels.forEach((modelId) => {
859
+ const option = document.createElement("option");
860
+ option.value = modelId;
861
+ option.textContent = modelId;
862
+ document.getElementById("model-selection").appendChild(option);
863
+ });
864
+ document.getElementById("model-selection").value = selectedModel;
865
+ document.getElementById("download").addEventListener("click", function () {
866
+ initializeWebLLMEngine().then(() => {
867
+ document.getElementById("start_button").disabled = false;
868
+ });
869
+ });
870
+
871
+ document.getElementById("clear-logs").addEventListener("click", function () {
872
+ document.getElementById("logs").innerHTML = '';
873
+ });
874
+
875
+ // ===== TTS Integration =====
876
+
877
+ // Initialize Speech Synthesis
878
+ let speech = new SpeechSynthesisUtterance();
879
+ speech.lang = "en";
880
+
881
+ let voices = [];
882
+ window.speechSynthesis.onvoiceschanged = () => {
883
+ voices = window.speechSynthesis.getVoices();
884
+ populateVoices();
885
+ };
886
+
887
+ function populateVoices() {
888
+ const voiceSelect = document.getElementById("voices");
889
+ voiceSelect.innerHTML = ''; // Clear existing options
890
+ voices.forEach((voice, i) => {
891
+ const option = new Option(voice.name, i);
892
+ voiceSelect.appendChild(option);
893
+ });
894
+ if (voices.length > 0) {
895
+ speech.voice = voices[0];
896
+ }
897
+ }
898
+
899
+ // Voice Selection Event Listener
900
+ document.getElementById("voices").addEventListener("change", () => {
901
+ const selectedVoiceIndex = document.getElementById("voices").value;
902
+ speech.voice = voices[selectedVoiceIndex];
903
+ });
904
+
905
+ // Function to speak text
906
+ function speak(text) {
907
+ if (window.speechSynthesis.speaking) {
908
+ window.speechSynthesis.cancel(); // Cancel previous speech
909
+ }
910
+ speech.text = text;
911
+ window.speechSynthesis.speak(speech);
912
+ }
913
+ </script>
914
+
915
+ </body>
916
+ </html>