vineelagampa commited on
Commit
002e2dc
·
verified ·
1 Parent(s): 186c113

Update web/analyzer.html

Browse files
Files changed (1) hide show
  1. web/analyzer.html +167 -537
web/analyzer.html CHANGED
@@ -1,564 +1,194 @@
1
  <!DOCTYPE html>
2
  <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <title>Document Analyzer | CTRL + ALT + HEAL</title>
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <script src="https://cdn.tailwindcss.com"></script>
8
- <style>
9
- :root {
10
- --tropical-indigo: rgb(120, 187, 242);
11
- --wisteria: rgb(197, 217, 251);
12
- --latte-cream: #ffffff;
13
- }
14
-
15
- body {
16
- font-family: "Rubik", sans-serif;
17
- background-color: var(--latte-cream);
18
- color: #333;
19
- }
20
-
21
- nav a {
22
- color: #333;
23
- transition: color 0.3s ease;
24
- }
25
- nav a:hover {
26
- color: var(--tropical-indigo);
27
- }
28
-
29
- .rec-card {
30
- background-color: var(--latte-cream);
31
- border: 1px solid var(--wisteria);
32
- border-radius: 1rem;
33
- padding: 1.25rem;
34
- margin-bottom: 1.5rem;
35
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
36
- transition: all 0.3s ease;
37
- }
38
- .rec-card:hover {
39
- transform: translateY(-3px);
40
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
41
- }
42
-
43
- .rec-title {
44
- font-size: 1.125rem;
45
- font-weight: 700;
46
- color: var(--tropical-indigo);
47
- margin-bottom: 0.5rem;
48
- }
49
-
50
- .rec-badge {
51
- font-size: 0.75rem;
52
- font-weight: 600;
53
- padding: 0.25rem 0.75rem;
54
- border-radius: 9999px;
55
- }
56
- .badge-high {
57
- background-color: #fee2e2;
58
- color: #b91c1c;
59
- }
60
- .badge-medium {
61
- background-color: #fef3c7;
62
- color: #92400e;
63
- }
64
- .badge-low {
65
- background-color: #d1fae5;
66
- color: #065f46;
67
- }
68
-
69
- .rec-content {
70
- list-style-type: disc;
71
- margin-left: 1.25rem;
72
- font-size: 0.875rem;
73
- color: #374151;
74
- }
75
-
76
- .rec-link {
77
- color: var(--tropical-indigo);
78
- text-decoration: underline;
79
- }
80
- .rec-link:hover {
81
- color: #4b7bbd;
82
- }
83
-
84
- .btn-primary {
85
- background-color: var(--tropical-indigo);
86
- color: white;
87
- transition: background-color 0.3s ease;
88
- }
89
- .btn-primary:hover {
90
- background-color: #5ba5dd;
91
- }
92
-
93
- input,
94
- textarea {
95
- border: 1px solid var(--wisteria);
96
- background-color: #fafbfc;
97
- }
98
- input:focus,
99
- textarea:focus {
100
- outline: none;
101
- border-color: var(--tropical-indigo);
102
- box-shadow: 0 0 0 2px rgba(120, 187, 242, 0.3);
103
- }
104
-
105
- h2,
106
- h3 {
107
- color: var(--tropical-indigo);
108
- }
109
-
110
- #chat-output {
111
- background-color: #f7f9fc;
112
- border: 1px solid var(--wisteria);
113
- }
114
- </style>
115
- </head>
116
- <body class="bg-[var(--latte-cream)] font-sans text-gray-800 min-h-screen">
117
- <!-- NAVBAR -->
118
- <nav
119
- class="fixed top-0 left-0 w-full z-50 backdrop-blur-md bg-white/20 border-b border-white/30 shadow-md"
120
- >
121
- <div class="flex justify-between items-center w-full px-6 py-4">
122
- <!-- Logo -->
123
- <a
124
- href="index.html"
125
- class="text-2xl font-bold text-black hover:text-[var(--tropical-indigo)] transition"
126
- >
127
- CTRL + ALT + HEAL
128
- </a>
129
-
130
- <ul class="hidden md:flex space-x-6 font-medium text-gray-800">
131
- <li><a href="index.html" class="nav-link">Home</a></li>
132
- <li><a href="profile.html" class="nav-link">Profile</a></li>
133
- <li><a href="analyzer.html" class="nav-link">Analyzer</a></li>
134
- <li><a href="past_data.html" class="nav-link">Past Reports</a></li>
135
- <li><a href="login.html" class="nav-link">Login</a></li>
136
- </ul>
137
-
138
- <!-- Hamburger Menu -->
139
- <button
140
- id="hamburger"
141
- class="md:hidden text-[var(--latte-cream)] text-2xl"
142
- >
143
-
144
- </button>
145
- </div>
146
-
147
- <!-- Mobile Menu -->
148
- <ul
149
- id="mobile-menu"
150
- class="hidden flex-col space-y-4 bg-white/30 backdrop-blur-lg border border-white/20 rounded-xl shadow-lg mt-2 p-4 mx-6 md:hidden"
151
- >
152
- <li>
153
- <a
154
- href="index.html"
155
- class="block text-gray-800 hover:text-[var(--tropical-indigo)]"
156
- >Home</a
157
- >
158
- </li>
159
- <li>
160
- <a
161
- href="analyzer.html"
162
- class="block text-gray-800 hover:text-[var(--tropical-indigo)]"
163
- >Analyzer</a
164
- >
165
- </li>
166
- <li>
167
- <a
168
- href="profile.html"
169
- class="block text-gray-800 hover:text-[var(--tropical-indigo)]"
170
- >Profile</a
171
- >
172
- </li>
173
- <li>
174
- <a
175
- href="login.html"
176
- class="block text-gray-800 hover:text-[var(--tropical-indigo)]"
177
- >Login</a
178
- >
179
- </li>
180
- <li>
181
- <a
182
- href="about.html"
183
- class="block text-gray-800 hover:text-[var(--tropical-indigo)]"
184
- >About</a
185
- >
186
- </li>
187
-
188
- >
189
- </li>
190
  </ul>
191
- </nav>
192
-
193
- <script>
194
- const hamburger = document.getElementById("hamburger");
195
- const mobileMenu = document.getElementById("mobile-menu");
196
-
197
- hamburger.addEventListener("click", () => {
198
- mobileMenu.classList.toggle("hidden");
199
- });
200
-
201
- // Underline the active page only
202
- const currentPath = window.location.pathname.split("/").pop();
203
-
204
- document.querySelectorAll(".nav-link").forEach((link) => {
205
- if (link.getAttribute("href") === currentPath) {
206
- link.classList.add("active-page"); // we'll style this in CSS
207
- }
208
- });
209
-
210
- document.querySelectorAll("#mobile-menu a").forEach((link) => {
211
- if (link.getAttribute("href") === currentPath) {
212
- link.classList.add("active-page");
213
- }
214
- });
215
- </script>
216
-
217
- <!-- CHANGE MARKER TO USE THIS -->
218
- <!-- secound change marker-->
219
- <main class="max-w-5xl mx-auto px-4 mb-16 pt-24">
220
- <!-- Upload Section -->
221
- <div
222
- class="bg-[var(--latte-cream)] border border-[var(--wisteria)] rounded-lg p-6 mb-8"
223
- >
224
- <h2 class="text-xl font-semibold mb-4">
225
- Upload & Analyze Your Medical PDF or Image
226
- </h2>
227
- <input
228
- type="file"
229
- id="pdf-upload"
230
- accept=".pdf, image/*"
231
- class="w-full mb-4 rounded px-3 py-2"
232
- />
233
- <input
234
- type="date"
235
- id="report-date"
236
- class="w-full mb-4 rounded px-3 py-2"
237
- />
238
- <button id="analyze-btn" class="btn-primary px-4 py-2 rounded">
239
- Analyze with AI
240
- </button>
241
- <p id="loading" class="text-gray-600 mt-2">No file uploaded yet.</p>
242
- <p id="auth-status" class="text-sm text-gray-500 mt-1">
243
- Sign in to save and view past analyses.
244
- </p>
245
  </div>
 
246
 
247
- <!-- Extracted Text -->
248
- <div
249
- class="bg-[var(--latte-cream)] border border-[var(--wisteria)] rounded-lg p-6 mb-8"
250
- >
251
- <h3 class="text-lg font-semibold mb-3">Extracted Text</h3>
252
- <div
253
- id="text-output"
254
- class="whitespace-pre-wrap h-60 overflow-auto bg-[#FAFBFC] text-sm border border-[var(--wisteria)] rounded p-4"
255
- >
256
- OCR results will appear here.
257
- </div>
258
  </div>
 
259
 
260
- <!-- AI Findings -->
261
- <div
262
- class="bg-[var(--latte-cream)] border border-[var(--wisteria)] rounded-lg p-6 mb-8"
263
- >
264
- <h3 class="text-lg font-semibold mb-3">AI Findings</h3>
265
- <div
266
- id="recommendations-output"
267
- class="bg-[#F9FAFB] text-sm border border-[var(--wisteria)] rounded p-4 space-y-4"
268
- >
269
- Findings and Recommendations will appear here.
270
- </div>
271
  </div>
272
-
273
- <!-- Chatbot -->
274
- <div
275
- class="bg-[var(--latte-cream)] border border-[var(--wisteria)] rounded-lg p-6 mb-8"
276
- >
277
- <h3 class="text-lg font-semibold mb-3">Ask Chatbot</h3>
278
- <div
279
- id="chat-output"
280
- class="space-y-2 h-48 overflow-auto text-sm rounded p-4"
281
- >
282
- <p><strong>Chatbot:</strong> Ask me something about your report</p>
283
- </div>
284
- <div class="flex mt-4 gap-2">
285
- <input
286
- type="text"
287
- id="user-question"
288
- placeholder="Ask a question..."
289
- class="flex-1 rounded px-3 py-2 focus:outline-none"
290
- />
291
- <button id="ask-btn" class="btn-primary px-4 py-2 rounded">
292
- Ask
293
- </button>
294
- </div>
295
  </div>
296
- </main>
297
-
298
- <!-- Firebase -->
299
- <script type="module">
300
- import {
301
- getFirestore,
302
- collection,
303
- doc,
304
- addDoc,
305
- serverTimestamp,
306
- } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js";
307
- import { initializeApp } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-app.js";
308
- import {
309
- getAuth,
310
- onAuthStateChanged,
311
- signOut,
312
- } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-auth.js";
313
-
314
- const firebaseConfig = {
315
- apiKey: "AIzaSyAKWstCc7HqMgV8DmH2Sy6QwUP3JvZxu9g",
316
- authDomain: "appchallenge-c8fe3.firebaseapp.com",
317
- projectId: "appchallenge-c8fe3",
318
- storageBucket: "appchallenge-c8fe3.firebasestorage.app",
319
- messagingSenderId: "943791692455",
320
- appId: "1:943791692455:web:ae04d06bf09669b6bdd982",
321
- measurementId: "G-HJ7EHW8V4N"
322
- };
323
-
324
- const app = initializeApp(firebaseConfig);
325
- const auth = getAuth(app);
326
- const db = getFirestore(app);
327
- window.firebaseAuth = auth;
328
- window.onAuthStateChanged = onAuthStateChanged;
329
- window.firestoreDb = db;
330
- window.firestoreHelpers = { collection, doc, addDoc, serverTimestamp };
331
-
332
- onAuthStateChanged(auth, (user) => {
333
- const authNavItem = document.getElementById("authNavItem");
334
- if (authNavItem) {
335
- if (user) {
336
- authNavItem.innerHTML =
337
- '<button onclick="logout()" class="hover:text-[#6B9080] text-red-600">Logout</button>';
338
- } else {
339
- authNavItem.innerHTML =
340
- '<a href="login.html" class="hover:text-[#6B9080]">Login</a>';
341
- }
342
- }
343
- });
344
-
345
- window.logout = async () => {
346
- try {
347
- await signOut(auth);
348
- localStorage.clear();
349
- window.location.href = "login.html";
350
- } catch (error) {
351
- console.error("Error signing out:", error);
352
- }
353
- };
354
- </script>
355
-
356
- <script type="module">
357
- import {
358
- pipeline,
359
- env,
360
- } from "https://cdn.jsdelivr.net/npm/@xenova/[email protected]";
361
-
362
- const loadingEl = document.getElementById("loading");
363
- const textOutput = document.getElementById("text-output");
364
- const recsOutput = document.getElementById("recommendations-output");
365
- const findingsOutput = document.getElementById(
366
- "detected-measurement-results"
367
- );
368
- const authStatus = document.getElementById("auth-status");
369
- let extractedText = "";
370
- let currentUser = null;
371
-
372
- document
373
- .getElementById("pdf-upload")
374
- .addEventListener("change", function () {
375
- loadingEl.textContent = this.files.length
376
- ? `File selected: ${this.files[0].name}`
377
- : "No file uploaded yet.";
378
  });
379
-
380
- const saveAnalysis = async (uid, payload) => {
381
- try {
382
- const docRef = await firebase
383
- .firestore()
384
- .collection("users")
385
- .doc(uid)
386
- .collection("analyses")
387
- .add({
388
- ...payload,
389
- createdAt: serverTimestamp(),
390
- });
391
- return docRef.id;
392
- } catch (e) {
393
- console.error("Failed to save analysis:", e);
394
  }
395
- };
396
 
397
- const renderRecCard = (rec, idx) => {
398
- const sev = (rec.severity || "").toLowerCase();
399
- const sevClass = sev.includes("severe")
400
- ? "badge-high"
401
- : sev.includes("moderate")
402
- ? "badge-medium"
403
- : "badge-low";
404
- return `
405
- <div class="rec-card">
406
- <div class="flex items-center justify-between">
407
- <h4 class="rec-title">Finding ${idx + 1}: ${
408
- rec.findings || "N/A"
409
- }</h4>
410
- <span class="rec-badge ${sevClass}">${rec.severity || "—"}</span>
411
- </div>
412
- <ul class="rec-content space-y-1">
413
- <li><em>Recommendations:</em>
414
- <ul class="list-disc list-inside ml-6">
415
- ${(rec.recommendations || [])
416
- .map((r) => `<li>${r}</li>`)
417
- .join("")}
418
- </ul>
419
- </li>
420
- <li><em>Treatment:</em> ${
421
- rec.treatment_suggestions || "Not available"
422
- }</li>
423
- <li><em>Home Care:</em>
424
- <ul class="list-disc list-inside ml-6">
425
- ${(rec.home_care_guidance || [])
426
- .map((r) => `<li>${r}</li>`)
427
- .join("")}
428
- </ul>
429
- </li>
430
- ${
431
- rec.info_link
432
- ? `<li><a href="${rec.info_link}" target="_blank" class="rec-link">Learn more</a></li>`
433
- : ""
434
- }
435
- </ul>
436
- </div>
437
- `;
438
- };
439
-
440
- window.onAuthStateChanged(window.firebaseAuth, (user) => {
441
- currentUser = user;
442
- if (user) {
443
- authStatus.textContent = `Signed in as ${user.email || user.uid}`;
444
  } else {
445
- authStatus.textContent =
446
- "Not signed in. Sign in to save and view past analyses.";
447
  }
448
- });
449
-
450
- document
451
- .getElementById("analyze-btn")
452
- .addEventListener("click", async () => {
453
- const file = document.getElementById("pdf-upload").files[0];
454
- const date = document.getElementById("report-date").value;
455
- if (!file) {
456
- loadingEl.textContent = "Please upload a file first.";
457
- return;
458
- }
459
- if (!date) {
460
- loadingEl.textContent = "Please select the report date.";
461
- return;
462
- }
463
-
464
- loadingEl.textContent = "Processing with AI...";
465
- textOutput.textContent = "";
466
- recsOutput.textContent = "";
467
 
468
- const formData = new FormData();
469
- formData.append("file", file);
470
- formData.append("model", "bert");
471
-
472
- let data;
473
- try {
474
- const res = await fetch("https://vineelagampa-prmschallenge.hf.space/analyze/", {
475
- method: "POST",
476
- body: formData,
477
- });
478
- if (!res.ok) throw new Error(await res.text());
479
- data = await res.json();
480
- } catch (err) {
481
- console.error(err);
482
- loadingEl.textContent = "Error during analysis: " + err.message;
483
- return;
484
- }
485
-
486
- extractedText = data.ocr_text || "";
487
- textOutput.textContent = extractedText;
488
-
489
- const recs = Array.isArray(data.Detected_Anomolies)
490
- ? data.Detected_Anomolies
491
- : data.Detected_Anomolies
492
- ? [data.Detected_Anomolies]
493
- : [];
494
- if (data.Detected_Anomolies) {
495
- recsOutput.innerHTML = recs
496
- .map((rec, i) => renderRecCard(rec, i))
497
- .join("");
498
- } else {
499
- recsOutput.textContent = "No recommendations found.";
500
- }
501
-
502
- const findings = Array.isArray(data.Detected_Measurement_Values)
503
- ? data.Detected_Measurement_Values
504
- : data.Detected_Measurement_Values
505
- ? [data.Detected_Measurement_Values]
506
- : [];
507
- if (data.Detected_Measurement_Values) {
508
- findingsOutput.innerHTML = findings
509
- .map((finding, i) => renderRecCard(finding, i))
510
- .join("");
511
- } else {
512
- findingsOutput.textContent = "No measurements found.";
513
- }
514
-
515
- if (currentUser) {
516
- await saveAnalysis(currentUser.uid, {
517
- reportDate: date,
518
- ocr_text: extractedText,
519
- resolutions: recs,
520
- measurements: findings,
521
- });
522
- }
523
 
524
- loadingEl.textContent = "Analysis complete.";
 
 
 
 
 
525
  });
 
 
 
526
 
527
- async function postReportToBackend(report) {
528
- try {
529
- const response = await fetch('http://localhost:9000/save_report/', {
530
- method: 'POST',
531
- headers: {
532
- 'Content-Type': 'application/json',
533
- },
534
- body: JSON.stringify(report),
535
- });
536
- if (!response.ok) {
537
- throw new Error(`HTTP error! status: ${response.status}`);
538
- }
539
- const data = await response.json();
540
- console.log('Report successfully sent to backend:', data);
541
- } catch (error) {
542
- console.error('Error sending report to backend:', error);
543
- }
544
- }
545
 
546
- document.getElementById("ask-btn").onclick = async () => {
547
- const q = document.getElementById("user-question").value.trim();
 
548
  if (!q) return;
549
- const chat = document.getElementById("chat-output");
550
  chat.innerHTML += `<p><strong>You:</strong> ${q}</p>`;
551
  chat.scrollTop = chat.scrollHeight;
552
  env.allowLocalModels = false;
553
- const qa = await pipeline(
554
- "question-answering",
555
- "Xenova/distilbert-base-uncased-distilled-squad"
556
- );
557
  const out = await qa(q, extractedText);
558
  chat.innerHTML += `<p><strong>Chatbot:</strong> ${out.answer}</p>`;
559
- document.getElementById("user-question").value = "";
560
  chat.scrollTop = chat.scrollHeight;
561
  };
562
- </script>
563
- </body>
564
- </html>
 
 
1
  <!DOCTYPE html>
2
  <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <title>Document Analyzer | CTRL + ALT + HEAL</title>
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ </head>
9
+ <body class="bg-[#F7F8F9] font-sans text-gray-800 min-h-screen">
10
+
11
+ <!-- Navbar -->
12
+ <nav class="bg-white border border-gray-200 px-6 py-4 mb-8">
13
+ <div class="container mx-auto flex justify-between items-center">
14
+ <a href="index.html" class="text-2xl font-bold text-[#6B9080]">CTRL + ALT + HEAL</a>
15
+ <ul class="flex space-x-6 text-sm font-medium text-gray-700">
16
+ <li><a href="index.html" class="hover:text-[#6B9080]">Home</a></li>
17
+ <li><a href="analyzer.html" class="hover:text-[#6B9080]">Analyzer</a></li>
18
+ <li><a href="profile.html" class="hover:text-[#6B9080]">Profile</a></li>
19
+ <li><a href="login.html" class="hover:text-[#6B9080]">Login</a></li>
20
+ <li><a href="about.html" class="hover:text-[#6B9080]">About Us</a></li>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  </ul>
22
+ </div>
23
+ </nav>
24
+
25
+ <main class="max-w-5xl mx-auto px-4 mb-16">
26
+ <!-- Upload & Score Section -->
27
+ <div class="bg-white border border-gray-200 rounded-lg p-6 mb-8">
28
+ <h2 class="text-xl font-semibold text-[#6B9080] mb-4">Upload & Analyze Your Medical PDF or Image</h2>
29
+ <input type="file" id="pdf-upload" accept=".pdf, image/*"
30
+ class="w-full mb-4 border border-gray-300 rounded px-3 py-2" />
31
+ <input type="date" id="report-date"
32
+ class="w-full mb-4 border border-gray-300 rounded px-3 py-2"
33
+ placeholder="Report Date" />
34
+ <button id="analyze-btn"
35
+ class="bg-[#6B9080] text-white px-4 py-2 rounded hover:bg-[#5B7A6F]">
36
+ Analyze with AI
37
+ </button>
38
+ <p id="loading" class="text-gray-600 mt-2">No file uploaded yet.</p>
39
+ </div>
40
+
41
+ <!-- Extracted Text -->
42
+ <div class="bg-white border border-gray-200 rounded-lg p-6 mb-8">
43
+ <h3 class="text-lg font-semibold text-[#6B9080] mb-3">Extracted Text</h3>
44
+ <div id="text-output" class="whitespace-pre-wrap h-60 overflow-auto bg-[#FAFBFC] text-sm text-gray-800 border border-gray-200 rounded p-4">
45
+ OCR results will appear here.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  </div>
47
+ </div>
48
 
49
+ <!-- AI Recommendations -->
50
+ <div class="bg-white border border-gray-200 rounded-lg p-6 mb-8">
51
+ <h3 class="text-lg font-semibold text-[#6B9080] mb-3">AI Recommendations</h3>
52
+ <div id="recommendations-output" class="whitespace-pre-wrap h-60 overflow-auto bg-[#FAFBFC] text-sm text-gray-800 border border-gray-200 rounded p-4">
53
+ Recommendations will appear here.
 
 
 
 
 
 
54
  </div>
55
+ </div>
56
 
57
+ <!-- QA Chatbot -->
58
+ <div class="bg-white border border-gray-200 rounded-lg p-6 mb-8">
59
+ <h3 class="text-lg font-semibold text-[#6B9080] mb-3">Ask Chatbot</h3>
60
+ <div id="chat-output" class="space-y-2 h-48 overflow-auto bg-[#FAFBFC] text-sm text-gray-800 border border-gray-200 rounded p-4">
61
+ <p><strong>Chatbot:</strong> Ask me something about your report</p>
 
 
 
 
 
 
62
  </div>
63
+ <div class="flex mt-4 gap-2">
64
+ <input type="text" id="user-question" placeholder="Ask a question..."
65
+ class="flex-1 border border-gray-300 rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-[#6B9080]" />
66
+ <button id="ask-btn" class="bg-[#6B9080] text-white px-4 py-2 rounded hover:bg-[#5B7A6F]">
67
+ Ask
68
+ </button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  </div>
70
+ </div>
71
+ </main>
72
+
73
+ <script type="module">
74
+ import { pipeline, env } from 'https://cdn.jsdelivr.net/npm/@xenova/[email protected]';
75
+
76
+ const loadingEl = document.getElementById('loading');
77
+ const textOutput = document.getElementById('text-output');
78
+ const recsOutput = document.getElementById('recommendations-output');
79
+ let extractedText = "";
80
+
81
+ document.getElementById('pdf-upload').addEventListener('change', function() {
82
+ loadingEl.textContent = this.files.length
83
+ ? `File selected: ${this.files[0].name}`
84
+ : 'No file uploaded yet.';
85
+ });
86
+
87
+ document.getElementById('analyze-btn').addEventListener('click', async () => {
88
+ const file = document.getElementById('pdf-upload').files[0];
89
+ const date = document.getElementById('report-date').value;
90
+ if (!file) { loadingEl.textContent = "Please upload a file first."; return; }
91
+ if (!date) { loadingEl.textContent = "Please select the report date."; return; }
92
+
93
+ loadingEl.textContent = "Processing with AI...";
94
+ textOutput.textContent = "";
95
+ recsOutput.textContent = "";
96
+
97
+ const formData = new FormData();
98
+ formData.append('file', file);
99
+ formData.append('model', 'bert');
100
+ try {
101
+ const res = await fetch('http://localhost:9000/analyze/', {
102
+ method: 'POST', body: formData
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  });
104
+ if (!res.ok) throw new Error(await res.text());
105
+ const data = await res.json();
106
+
107
+ // OCR text
108
+ extractedText = data.ocr_text || "";
109
+ textOutput.textContent = extractedText;
110
+
111
+
112
+ console.log("AI recs from backend:", data.resolutions);
113
+ let recs = [];
114
+ if (Array.isArray(data.resolutions)) {
115
+ recs = data.resolutions;
116
+ } else if (data.resolutions && typeof data.resolutions === 'object') {
117
+ recs = [data.resolutions];
 
118
  }
 
119
 
120
+ if (recs.length) {
121
+ recsOutput.innerHTML = `
122
+ <ul class="list-disc list-inside space-y-4">
123
+ ${recs.map((rec, i) => `
124
+ <li>
125
+ <strong>Finding ${i+1}:</strong> ${rec.findings} (Severity: ${rec.severity})
126
+ <ul class="list-disc list-inside ml-6 space-y-1">
127
+ <li><em>Recommendations:</em>
128
+ <ul class="list-disc list-inside ml-6">
129
+ ${(rec.recommendations || []).map(r=>`<li>${r}</li>`).join('')}
130
+ </ul>
131
+ </li>
132
+ <li><em>Treatment:</em> ${rec.treatment_suggestions || 'Not available'}</li>
133
+ <li><em>Home Care:</em>
134
+ <ul class="list-disc list-inside ml-6">
135
+ ${(rec.home_care_guidance || []).map(r=>`<li>${r}</li>`).join('')}
136
+ </ul>
137
+ </li>
138
+ ${rec.info_link
139
+ ? `<li><a href="${rec.info_link}" target="_blank" class="text-blue-600 underline">Learn more</a></li>`
140
+ : ''}
141
+ </ul>
142
+ </li>
143
+ `).join('')}
144
+ </ul>
145
+ `;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
  } else {
147
+ recsOutput.textContent = "No recommendations found.";
 
148
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
 
150
+ } catch (err) {
151
+ console.error(err);
152
+ loadingEl.textContent = "Error during analysis: " + err.message;
153
+ return;
154
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
 
156
+ // fake score(random)
157
+ try {
158
+ const scoreRes = await fetch('http://localhost:9000/api/analyze-health', {
159
+ method: 'POST',
160
+ headers: {'Content-Type':'application/json'},
161
+ body: JSON.stringify({ text: extractedText })
162
  });
163
+ if (!scoreRes.ok) throw new Error(await scoreRes.text());
164
+ const { score, rationale } = await scoreRes.json();
165
+ loadingEl.textContent = `Last health score: ${score} (${rationale})`;
166
 
167
+
168
+ const progressData = JSON.parse(localStorage.getItem('progressData') || '[]');
169
+ progressData.push({ date: new Date().toISOString().split('T')[0], score });
170
+ localStorage.setItem('progressData', JSON.stringify(progressData));
171
+
172
+ } catch (err) {
173
+ console.error(err);
174
+ loadingEl.textContent = "Error during scoring: " + err.message;
175
+ }
 
 
 
 
 
 
 
 
 
176
 
177
+ //q&a chatbo t
178
+ document.getElementById('ask-btn').onclick = async () => {
179
+ const q = document.getElementById('user-question').value.trim();
180
  if (!q) return;
181
+ const chat = document.getElementById('chat-output');
182
  chat.innerHTML += `<p><strong>You:</strong> ${q}</p>`;
183
  chat.scrollTop = chat.scrollHeight;
184
  env.allowLocalModels = false;
185
+ const qa = await pipeline('question-answering','Xenova/distilbert-base-uncased-distilled-squad');
 
 
 
186
  const out = await qa(q, extractedText);
187
  chat.innerHTML += `<p><strong>Chatbot:</strong> ${out.answer}</p>`;
188
+ document.getElementById('user-question').value = '';
189
  chat.scrollTop = chat.scrollHeight;
190
  };
191
+ });
192
+ </script>
193
+ </body>
194
+ </html>