Neurolingua commited on
Commit
8528d7b
·
verified ·
1 Parent(s): 04f3c79

Update templates/user-dashboard.html

Browse files
Files changed (1) hide show
  1. templates/user-dashboard.html +412 -156
templates/user-dashboard.html CHANGED
@@ -1,156 +1,412 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>User Dashboard - E. Coli Detection Portal</title>
7
- <link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
8
- <style>
9
- body {
10
- background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
11
- }
12
- .dashboard-card {
13
- backdrop-filter: blur(10px);
14
- background-color: rgba(255, 255, 255, 0.9);
15
- }
16
- </style>
17
- </head>
18
- <body class="min-h-screen flex items-center justify-center p-4">
19
- <div class="container mx-auto max-w-2xl">
20
- <div class="dashboard-card rounded-xl shadow-2xl p-8">
21
- <div class="text-center mb-6">
22
- <h1 class="text-3xl font-bold text-gray-800">User Dashboard</h1>
23
- <p class="text-gray-600 mt-2">E. Coli Detection Portal</p>
24
- </div>
25
-
26
- <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
27
- <div class="bg-blue-100 p-6 rounded-lg shadow-md">
28
- <h2 class="text-xl font-semibold text-blue-800 mb-4">Profile Information</h2>
29
- <div id="userProfileDetails">
30
- <p class="mb-2"><strong>Name:</strong> Sharvesh</p>
31
- <p class="mb-2"><strong>Phone:</strong> 9342540825</p>
32
- <p class="mb-2"><strong>State:</strong> Tamil Nadu</p>
33
- <p class="mb-2"><strong>Town:</strong> Pollachi</p>
34
- </div>
35
- </div>
36
-
37
- <div class="bg-green-100 p-6 rounded-lg shadow-md">
38
- <h2 class="text-xl font-semibold text-green-800 mb-4">Quick Actions</h2>
39
- <div class="space-y-4">
40
- <button onclick="startNewTest()" class="w-full bg-green-500 text-white p-3 rounded-lg hover:bg-green-600 transition duration-300">
41
- Start New E. Coli Test
42
- </button>
43
- <button onclick="toggleTestResults()" class="w-full bg-blue-500 text-white p-3 rounded-lg hover:bg-blue-600 transition duration-300">
44
- <span id="testResultsButtonText">View Previous Tests</span>
45
- </button>
46
- </div>
47
- </div>
48
- </div>
49
-
50
- <div id="testResults" class="mt-8 hidden">
51
- <h2 class="text-2xl font-bold text-gray-800 mb-4">Recent Test Results</h2>
52
- <div id="testResultsContent" class="bg-gray-100 p-4 rounded-lg">
53
- <!-- Test results will be dynamically populated here -->
54
- </div>
55
- </div>
56
- </div>
57
- </div>
58
-
59
- <script type="module">
60
- import { initializeApp } from "https://www.gstatic.com/firebasejs/11.0.2/firebase-app.js";
61
- import {
62
- getFirestore,
63
- collection,
64
- query,
65
- orderBy,
66
- limit,
67
- getDocs
68
- } from "https://www.gstatic.com/firebasejs/11.0.2/firebase-firestore.js";
69
-
70
- const firebaseConfig = {
71
- apiKey: "AIzaSyBVazIeGCASyfCka3nU_INuZytrTdSVmXo",
72
- authDomain: "snippetscript-37175.firebaseapp.com",
73
- projectId: "snippetscript-37175",
74
- storageBucket: "snippetscript-37175.appspot.com",
75
- messagingSenderId: "154274113551",
76
- appId: "1:154274113551:web:4e9582f3a24f7d12695b7a",
77
- measurementId: "G-PSR30H9GH6"
78
- };
79
-
80
- // Initialize Firebase
81
- const app = initializeApp(firebaseConfig);
82
- const db = getFirestore(app);
83
-
84
- // Load previous test results from Firestore
85
- async function loadPreviousTests() {
86
- try {
87
- const thingspeakQuery = query(
88
- collection(db, 'thingspeak_data'),
89
- orderBy('timestamp', 'desc'),
90
- limit(5)
91
- );
92
-
93
- const querySnapshot = await getDocs(thingspeakQuery);
94
- const testResultsContent = document.getElementById('testResultsContent');
95
-
96
- if (querySnapshot.empty) {
97
- testResultsContent.innerHTML = `<p class="text-gray-600">No previous test results available.</p>`;
98
- return;
99
- }
100
-
101
- let tableHTML = `
102
- <table class="w-full">
103
- <thead>
104
- <tr class="bg-gray-200">
105
- <th class="p-2 text-left">Entry ID</th>
106
- <th class="p-2 text-left">Field 1</th>
107
- <th class="p-2 text-left">Field 2</th>
108
- <th class="p-2 text-left">Timestamp</th>
109
- </tr>
110
- </thead>
111
- <tbody>
112
- `;
113
-
114
- querySnapshot.forEach((doc) => {
115
- const data = doc.data();
116
- const timestamp = data.timestamp ? new Date(data.timestamp.seconds * 1000).toLocaleString() : 'N/A';
117
-
118
- tableHTML += `
119
- <tr class="border-b">
120
- <td class="p-2">${data.entry_id || 'N/A'}</td>
121
- <td class="p-2">${data.field1 || 'N/A'}</td>
122
- <td class="p-2">${data.field2 || 'N/A'}</td>
123
- <td class="p-2">${timestamp}</td>
124
- </tr>
125
- `;
126
- });
127
-
128
- tableHTML += `</tbody></table>`;
129
- testResultsContent.innerHTML = tableHTML;
130
- } catch (error) {
131
- alert("Error loading test results: " + error.message);
132
- }
133
- }
134
-
135
- // Dashboard actions
136
- function startNewTest() {
137
- alert('Place the water sample in the kit. The results will be updated here shortly.');
138
- }
139
-
140
- function toggleTestResults() {
141
- const testResultsDiv = document.getElementById('testResults');
142
- testResultsDiv.classList.toggle('hidden');
143
- if (!testResultsDiv.classList.contains('hidden')) {
144
- document.getElementById('testResultsButtonText').textContent = 'Hide Previous Tests';
145
- loadPreviousTests();
146
- } else {
147
- document.getElementById('testResultsButtonText').textContent = 'View Previous Tests';
148
- }
149
- }
150
-
151
- // Attach functions to window for button actions
152
- window.startNewTest = startNewTest;
153
- window.toggleTestResults = toggleTestResults;
154
- </script>
155
- </body>
156
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>User Dashboard - E. Coli Detection Portal</title>
7
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
9
+ <style>
10
+ #background-video {
11
+ position: fixed;
12
+ top: 0;
13
+ left: 0;
14
+ width: 100%;
15
+ height: 100%;
16
+ object-fit: cover;
17
+ z-index: -1; /* Send the video to the background */
18
+ }
19
+
20
+ /* Container Styling */
21
+ body {
22
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
23
+ }
24
+
25
+ .dashboard-card {
26
+ backdrop-filter: blur(10px);
27
+ background-color: rgba(255, 255, 255, 0.2); /* Reduce opacity for transparency */
28
+ box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); /* Optional shadow for better contrast */
29
+ }
30
+
31
+ .chatbot-container {
32
+ display: flex;
33
+ height: 100vh;
34
+ }
35
+ .chat-sidebar {
36
+ width: 260px;
37
+ background-color: #1A1A1A;
38
+ padding: 20px;
39
+ }
40
+ .chat-main {
41
+ flex-grow: 1;
42
+ display: flex;
43
+ flex-direction: column;
44
+ }
45
+ .chat-messages {
46
+ flex-grow: 1;
47
+ overflow-y: auto;
48
+ padding: 20px;
49
+ background-color: #343541;
50
+ }
51
+ .chat-input-area {
52
+ padding: 20px;
53
+ background-color: #343541;
54
+ }
55
+ .chatbot-fab {
56
+ position: fixed;
57
+ bottom: 20px;
58
+ right: 20px;
59
+ z-index: 1000;
60
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
61
+ }
62
+ .speaker-icon {
63
+ cursor: pointer;
64
+ margin-left: 10px;
65
+ color: white;
66
+ }
67
+ </style>
68
+ </head>
69
+ <body class="min-h-screen flex items-center justify-center p-4">
70
+ <video autoplay loop muted id="background-video">
71
+ <source src="{{ url_for('static', filename='dashboard.mp4') }}" type="video/mp4">
72
+ Your browser does not support the video tag.
73
+ </video>
74
+ <div class="container mx-auto max-w-2xl">
75
+ <div class="dashboard-card rounded-xl shadow-2xl p-8">
76
+ <div class="text-center mb-6">
77
+ <h1 class="text-3xl font-bold text-gray-800">User Dashboard</h1>
78
+ <p class="text-gray-600 mt-2">E. Coli Detection Portal</p>
79
+ </div>
80
+
81
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
82
+ <div class="bg-blue-100 p-6 rounded-lg shadow-md">
83
+ <h2 class="text-xl font-semibold text-blue-800 mb-4">Profile Information</h2>
84
+ <div id="userProfileDetails">
85
+ <p class="mb-2"><strong>Name:</strong> Sharvesh</p>
86
+ <p class="mb-2"><strong>Phone:</strong> 9342540825</p>
87
+ <p class="mb-2"><strong>State:</strong> Tamil Nadu</p>
88
+ <p class="mb-2"><strong>Town:</strong> Pollachi</p>
89
+ </div>
90
+ </div>
91
+
92
+ <div class="bg-green-100 p-6 rounded-lg shadow-md">
93
+ <h2 class="text-xl font-semibold text-green-800 mb-4">Quick Actions</h2>
94
+ <div class="space-y-4">
95
+ <button onclick="startNewTest()" class="w-full bg-green-500 text-white p-3 rounded-lg hover:bg-green-600 transition duration-300">
96
+ Start New E. Coli Test
97
+ </button>
98
+ <button onclick="toggleTestResults()" class="w-full bg-blue-500 text-white p-3 rounded-lg hover:bg-blue-600 transition duration-300">
99
+ <span id="testResultsButtonText">View Previous Tests</span>
100
+ </button>
101
+ </div>
102
+ </div>
103
+ </div>
104
+
105
+ <div id="testResults" class="mt-8 hidden">
106
+ <h2 class="text-2xl font-bold text-gray-800 mb-4">Recent Test Results</h2>
107
+ <div id="testResultsContent" class="bg-gray-100 p-4 rounded-lg">
108
+ <!-- Test results will be dynamically populated here -->
109
+ </div>
110
+ </div>
111
+ </div>
112
+ </div>
113
+
114
+ <!-- Floating Chatbot Button -->
115
+ <button id="chatbotFab" class="chatbot-fab bg-blue-500 text-white p-3 rounded-full hover:bg-blue-600 transition duration-300">
116
+ <i class="fas fa-robot"></i>
117
+ </button>
118
+
119
+ <!-- Chatbot Modal -->
120
+ <div id="chatbotModal" class="fixed inset-0 z-50 bg-black bg-opacity-50 flex items-center justify-center hidden">
121
+ <div class="w-full h-full max-w-6xl max-h-[90vh] bg-white rounded-lg overflow-hidden">
122
+ <div class="chatbot-container">
123
+ <!-- Sidebar -->
124
+ <div class="chat-sidebar text-white">
125
+ <div class="mb-6">
126
+ <button id="newChatBtn" class="w-full bg-gray-700 text-white p-3 rounded-lg mb-4 hover:bg-gray-600 transition duration-300">
127
+ <i class="fas fa-plus mr-2"></i>New Chat
128
+ </button>
129
+ </div>
130
+ <div>
131
+ <h3 class="text-lg font-semibold mb-4">Chat History</h3>
132
+ <ul id="chatHistory">
133
+ <li class="p-2 hover:bg-gray-700 rounded cursor-pointer">Chat 1</li>
134
+ <li class="p-2 hover:bg-gray-700 rounded cursor-pointer">Chat 2</li>
135
+ </ul>
136
+ </div>
137
+ </div>
138
+
139
+ <!-- Main Chatbot Area -->
140
+ <div class="chat-main">
141
+ <div class="chat-messages" id="chatMessages">
142
+ <div class="text-white text-center py-10">
143
+ <h2 class="text-2xl mb-4">How can I help you today?</h2>
144
+ <p>Ask me anything about E. Coli detection or water quality</p>
145
+ </div>
146
+ </div>
147
+ <div class="chat-input-area">
148
+ <div class="relative">
149
+ <textarea
150
+ id="chatInput"
151
+ class="w-full p-4 pr-12 text-white bg-gray-700 rounded-lg focus:outline-none"
152
+ placeholder="Type your message..."
153
+ rows="3"></textarea>
154
+ <button id="sendMessageBtn" class="absolute right-4 top-4 bg-blue-600 text-white p-3 rounded-full hover:bg-blue-700">
155
+ <i class="fas fa-paper-plane"></i>
156
+ </button>
157
+ </div>
158
+ </div>
159
+ </div>
160
+ </div>
161
+ </div>
162
+ </div>
163
+
164
+ <script type="module">
165
+ import { initializeApp } from "https://www.gstatic.com/firebasejs/11.0.2/firebase-app.js";
166
+ import {
167
+ getFirestore,
168
+ collection,
169
+ query,
170
+ orderBy,
171
+ limit,
172
+ getDocs,
173
+ onSnapshot,
174
+ doc,
175
+ getDoc
176
+ } from "https://www.gstatic.com/firebasejs/11.0.2/firebase-firestore.js";
177
+
178
+ const firebaseConfig = {
179
+ apiKey: "AIzaSyBVazIeGCASyfCka3nU_INuZytrTdSVmXo",
180
+ authDomain: "snippetscript-37175.firebaseapp.com",
181
+ projectId: "snippetscript-37175",
182
+ storageBucket: "snippetscript-37175.appspot.com",
183
+ messagingSenderId: "154274113551",
184
+ appId: "1:154274113551:web:4e9582f3a24f7d12695b7a",
185
+ measurementId: "G-PSR30H9GH6"
186
+ };
187
+
188
+ // Initialize Firebase
189
+ const app = initializeApp(firebaseConfig);
190
+ const db = getFirestore(app);
191
+
192
+ // Dynamically load user profile
193
+ // Function to load user profile from Firestore using the phone number as the document ID
194
+ async function loadUserProfile(phone) {
195
+ try {
196
+ // Reference the document in the 'users' collection with the phone as the document ID
197
+ const userProfileRef = doc(db, 'users', phone);
198
+
199
+ // Fetch the document snapshot
200
+ const docSnap = await getDoc(userProfileRef);
201
+
202
+ // Check if the document exists
203
+ if (docSnap.exists()) {
204
+ // Extract the user data
205
+ const data = docSnap.data();
206
+
207
+ // Update the HTML content to display the user's profile
208
+ document.getElementById('userProfileDetails').innerHTML = `
209
+ <p class="mb-2"><strong>Name:</strong> ${data.name || 'N/A'}</p>
210
+ <p class="mb-2"><strong>Phone:</strong> ${data.phone || 'N/A'}</p>
211
+ <p class="mb-2"><strong>Pincode:</strong> ${data.pincode || 'N/A'}</p>
212
+ <p class="mb-2"><strong>State:</strong> ${data.state || 'N/A'}</p>
213
+ <p class="mb-2"><strong>Town:</strong> ${data.town || 'N/A'}</p>
214
+ `;
215
+ } else {
216
+ // If the document doesn't exist, show a "not found" message
217
+ document.getElementById('userProfileDetails').innerHTML = '<p class="text-gray-600">User profile not found.</p>';
218
+ }
219
+ } catch (error) {
220
+ // Log the error to the console and display an error message to the user
221
+ console.error("Error fetching user profile:", error);
222
+ document.getElementById('userProfileDetails').innerHTML = '<p class="text-red-600">An error occurred while fetching the user profile. Please try again later.</p>';
223
+ }
224
+
225
+ loadUserProfile('9342540825'); // Fetches the user profile for this phone number
226
+
227
+ }
228
+
229
+ // Dynamically load Thingspeak data
230
+ async function loadPreviousTests() {
231
+ const thingspeakQuery = query(
232
+ collection(db, 'thingspeak_data'),
233
+ orderBy('timestamp', 'desc'),
234
+ limit(5)
235
+ );
236
+
237
+ onSnapshot(thingspeakQuery, (querySnapshot) => {
238
+ const testResultsContent = document.getElementById('testResultsContent');
239
+
240
+ if (querySnapshot.empty) {
241
+ testResultsContent.innerHTML = `<p class="text-gray-600">No previous test results available.</p>`;
242
+ return;
243
+ }
244
+
245
+ let tableHTML = `
246
+ <table class="w-full">
247
+ <thead>
248
+ <tr class="bg-gray-200">
249
+ <th class="p-2 text-left">Entry ID</th>
250
+ <th class="p-2 text-left">Field 1</th>
251
+ <th class="p-2 text-left">Field 2</th>
252
+ <th class="p-2 text-left">Timestamp</th>
253
+ </tr>
254
+ </thead>
255
+ <tbody>
256
+ `;
257
+
258
+ querySnapshot.forEach((doc) => {
259
+ const data = doc.data();
260
+ const timestamp = data.timestamp ? new Date(data.timestamp.seconds * 1000).toLocaleString() : 'N/A';
261
+
262
+ tableHTML += `
263
+ <tr class="border-b">
264
+ <td class="p-2">${data.entry_id || 'N/A'}</td>
265
+ <td class="p-2">${data.field1 || 'N/A'}</td>
266
+ <td class="p-2">${data.field2 || 'N/A'}</td>
267
+ <td class="p-2">${timestamp}</td>
268
+ </tr>
269
+ `;
270
+ });
271
+
272
+ tableHTML += `</tbody></table>`;
273
+ testResultsContent.innerHTML = tableHTML;
274
+ });
275
+ }
276
+
277
+ // Dashboard actions
278
+ function startNewTest() {
279
+ alert('Place the water sample in the kit. The results will be updated here shortly.');
280
+ }
281
+
282
+ function toggleTestResults() {
283
+ const testResultsDiv = document.getElementById('testResults');
284
+ testResultsDiv.classList.toggle('hidden');
285
+ if (!testResultsDiv.classList.contains('hidden')) {
286
+ document.getElementById('testResultsButtonText').textContent = 'Hide Previous Tests';
287
+ loadPreviousTests();
288
+ } else {
289
+ document.getElementById('testResultsButtonText').textContent = 'View Previous Tests';
290
+ }
291
+ }
292
+
293
+ // Chatbot functionality
294
+ document.addEventListener('DOMContentLoaded', function() {
295
+ const chatbotFab = document.getElementById('chatbotFab');
296
+ const chatbotModal = document.getElementById('chatbotModal');
297
+ const newChatBtn = document.getElementById('newChatBtn');
298
+ const sendMessageBtn = document.getElementById('sendMessageBtn');
299
+ const chatInput = document.getElementById('chatInput');
300
+ const chatMessages = document.getElementById('chatMessages');
301
+
302
+ // Toggle Chatbot Modal
303
+ chatbotFab.addEventListener('click', function() {
304
+ chatbotModal.classList.toggle('hidden');
305
+ });
306
+
307
+ // Close Chatbot Modal on clicking outside
308
+ chatbotModal.addEventListener('click', function(event) {
309
+ if (event.target === chatbotModal) {
310
+ chatbotModal.classList.add('hidden');
311
+ }
312
+ });
313
+
314
+ // New Chat functionality
315
+ newChatBtn.addEventListener('click', function() {
316
+ chatMessages.innerHTML = `
317
+ <div class="text-white text-center py-10">
318
+ <h2 class="text-2xl mb-4">How can I help you today?</h2>
319
+ <p>Ask me anything about E. Coli detection or water quality</p>
320
+ </div>
321
+ `;
322
+ });
323
+
324
+ // Send Message functionality
325
+ sendMessageBtn.addEventListener('click', sendMessage);
326
+ chatInput.addEventListener('keypress', function(event) {
327
+ if (event.key === 'Enter' && !event.shiftKey) {
328
+ event.preventDefault();
329
+ sendMessage();
330
+ }
331
+ });
332
+
333
+ function sendMessage() {
334
+ const userMessage = chatInput.value.trim();
335
+ if (userMessage) {
336
+ // Add user message to chat
337
+ chatMessages.innerHTML += `
338
+ <div class="text-white mb-4 text-right">
339
+ <div class="inline-block bg-blue-600 p-3 rounded-lg max-w-[70%]">
340
+ ${userMessage}
341
+ </div>
342
+ </div>
343
+ `;
344
+
345
+ // Clear input
346
+ chatInput.value = '';
347
+
348
+ // Send message to backend
349
+ fetch('/chat', {
350
+ method: 'POST',
351
+ headers: {
352
+ 'Content-Type': 'application/json'
353
+ },
354
+ body: JSON.stringify({ query: userMessage })
355
+ })
356
+ .then(response => response.json())
357
+ .then(data => {
358
+ if (data.response) {
359
+ // Add bot response to chat with speaker icon
360
+ const botMessage = data.response;
361
+ chatMessages.innerHTML += `
362
+ <div class="text-white mb-4 text-left">
363
+ <div class="inline-block bg-gray-700 p-3 rounded-lg max-w-[70%]">
364
+ ${botMessage}
365
+ <i class="fas fa-volume-up speaker-icon" onclick="speakMessage('${botMessage}')"></i>
366
+ </div>
367
+ </div>
368
+ `;
369
+ } else {
370
+ chatMessages.innerHTML += `
371
+ <div class="text-white mb-4 text-left">
372
+ <div class="inline-block bg-red-600 p-3 rounded-lg max-w-[70%]">
373
+ Error: ${data.error || "Unable to process your request"}
374
+ </div>
375
+ </div>
376
+ `;
377
+ }
378
+
379
+ // Scroll to bottom
380
+ chatMessages.scrollTop = chatMessages.scrollHeight;
381
+ })
382
+ .catch(error => {
383
+ console.error("Error:", error);
384
+ chatMessages.innerHTML += `
385
+ <div class="text-white mb-4 text-left">
386
+ <div class="inline-block bg-red-600 p-3 rounded-lg max-w-[70%]">
387
+ An error occurred. Please try again later.
388
+ </div>
389
+ </div>
390
+ `;
391
+ });
392
+
393
+ // Scroll to bottom
394
+ chatMessages.scrollTop = chatMessages.scrollHeight;
395
+ }
396
+ }
397
+
398
+ // Function to read out the bot's message
399
+ window.speakMessage = function(message) {
400
+ const utterance = new SpeechSynthesisUtterance(message);
401
+ utterance.voice = speechSynthesis.getVoices()[0];
402
+ speechSynthesis.speak(utterance);
403
+ }
404
+ });
405
+
406
+ // Initialize dynamic content loading
407
+ loadUserProfile();
408
+ window.startNewTest = startNewTest;
409
+ window.toggleTestResults = toggleTestResults;
410
+ </script>
411
+ </body>
412
+ </html>