vineelagampa commited on
Commit
2d79148
·
verified ·
1 Parent(s): 57a17af

Update web/analyzer.html

Browse files
Files changed (1) hide show
  1. web/analyzer.html +536 -167
web/analyzer.html CHANGED
@@ -1,194 +1,563 @@
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>
 
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: "AIzaSyAPhM_Ee7cLzyKHs5zyFy8g5ZOk9-pubRI",
316
+ authDomain: "login-tutorial-7a9e1.firebaseapp.com",
317
+ projectId: "login-tutorial-7a9e1",
318
+ storageBucket: "login-tutorial-7a9e1.firebasestorage.app",
319
+ messagingSenderId: "491093197824",
320
+ appId: "1:491093197824:web:9f866...",
321
+ };
322
+
323
+ const app = initializeApp(firebaseConfig);
324
+ const auth = getAuth(app);
325
+ const db = getFirestore(app);
326
+ window.firebaseAuth = auth;
327
+ window.onAuthStateChanged = onAuthStateChanged;
328
+ window.firestoreDb = db;
329
+ window.firestoreHelpers = { collection, doc, addDoc, serverTimestamp };
330
+
331
+ onAuthStateChanged(auth, (user) => {
332
+ const authNavItem = document.getElementById("authNavItem");
333
+ if (authNavItem) {
334
+ if (user) {
335
+ authNavItem.innerHTML =
336
+ '<button onclick="logout()" class="hover:text-[#6B9080] text-red-600">Logout</button>';
337
+ } else {
338
+ authNavItem.innerHTML =
339
+ '<a href="login.html" class="hover:text-[#6B9080]">Login</a>';
340
+ }
341
+ }
342
+ });
343
+
344
+ window.logout = async () => {
345
+ try {
346
+ await signOut(auth);
347
+ localStorage.clear();
348
+ window.location.href = "login.html";
349
+ } catch (error) {
350
+ console.error("Error signing out:", error);
351
+ }
352
+ };
353
+ </script>
354
+
355
+ <script type="module">
356
+ import {
357
+ pipeline,
358
+ env,
359
+ } from "https://cdn.jsdelivr.net/npm/@xenova/[email protected]";
360
+
361
+ const loadingEl = document.getElementById("loading");
362
+ const textOutput = document.getElementById("text-output");
363
+ const recsOutput = document.getElementById("recommendations-output");
364
+ const findingsOutput = document.getElementById(
365
+ "detected-measurement-results"
366
+ );
367
+ const authStatus = document.getElementById("auth-status");
368
+ let extractedText = "";
369
+ let currentUser = null;
370
+
371
+ document
372
+ .getElementById("pdf-upload")
373
+ .addEventListener("change", function () {
374
+ loadingEl.textContent = this.files.length
375
+ ? `File selected: ${this.files[0].name}`
376
+ : "No file uploaded yet.";
377
  });
378
+
379
+ const saveAnalysis = async (uid, payload) => {
380
+ try {
381
+ const docRef = await firebase
382
+ .firestore()
383
+ .collection("users")
384
+ .doc(uid)
385
+ .collection("analyses")
386
+ .add({
387
+ ...payload,
388
+ createdAt: serverTimestamp(),
389
+ });
390
+ return docRef.id;
391
+ } catch (e) {
392
+ console.error("Failed to save analysis:", e);
393
  }
394
+ };
395
 
396
+ const renderRecCard = (rec, idx) => {
397
+ const sev = (rec.severity || "").toLowerCase();
398
+ const sevClass = sev.includes("severe")
399
+ ? "badge-high"
400
+ : sev.includes("moderate")
401
+ ? "badge-medium"
402
+ : "badge-low";
403
+ return `
404
+ <div class="rec-card">
405
+ <div class="flex items-center justify-between">
406
+ <h4 class="rec-title">Finding ${idx + 1}: ${
407
+ rec.findings || "N/A"
408
+ }</h4>
409
+ <span class="rec-badge ${sevClass}">${rec.severity || "—"}</span>
410
+ </div>
411
+ <ul class="rec-content space-y-1">
412
+ <li><em>Recommendations:</em>
413
+ <ul class="list-disc list-inside ml-6">
414
+ ${(rec.recommendations || [])
415
+ .map((r) => `<li>${r}</li>`)
416
+ .join("")}
417
+ </ul>
418
+ </li>
419
+ <li><em>Treatment:</em> ${
420
+ rec.treatment_suggestions || "Not available"
421
+ }</li>
422
+ <li><em>Home Care:</em>
423
+ <ul class="list-disc list-inside ml-6">
424
+ ${(rec.home_care_guidance || [])
425
+ .map((r) => `<li>${r}</li>`)
426
+ .join("")}
427
+ </ul>
428
+ </li>
429
+ ${
430
+ rec.info_link
431
+ ? `<li><a href="${rec.info_link}" target="_blank" class="rec-link">Learn more</a></li>`
432
+ : ""
433
+ }
434
+ </ul>
435
+ </div>
436
+ `;
437
+ };
438
+
439
+ window.onAuthStateChanged(window.firebaseAuth, (user) => {
440
+ currentUser = user;
441
+ if (user) {
442
+ authStatus.textContent = `Signed in as ${user.email || user.uid}`;
443
  } else {
444
+ authStatus.textContent =
445
+ "Not signed in. Sign in to save and view past analyses.";
446
  }
447
+ });
448
 
449
+ document
450
+ .getElementById("analyze-btn")
451
+ .addEventListener("click", async () => {
452
+ const file = document.getElementById("pdf-upload").files[0];
453
+ const date = document.getElementById("report-date").value;
454
+ if (!file) {
455
+ loadingEl.textContent = "Please upload a file first.";
456
+ return;
457
+ }
458
+ if (!date) {
459
+ loadingEl.textContent = "Please select the report date.";
460
+ return;
461
+ }
462
 
463
+ loadingEl.textContent = "Processing with AI...";
464
+ textOutput.textContent = "";
465
+ recsOutput.textContent = "";
 
 
 
 
 
 
 
466
 
467
+ const formData = new FormData();
468
+ formData.append("file", file);
469
+ formData.append("model", "bert");
 
470
 
471
+ let data;
472
+ try {
473
+ const res = await fetch("http://localhost:9000/analyze/", {
474
+ method: "POST",
475
+ body: formData,
476
+ });
477
+ if (!res.ok) throw new Error(await res.text());
478
+ data = await res.json();
479
+ } catch (err) {
480
+ console.error(err);
481
+ loadingEl.textContent = "Error during analysis: " + err.message;
482
+ return;
483
+ }
484
+
485
+ extractedText = data.ocr_text || "";
486
+ textOutput.textContent = extractedText;
487
+
488
+ const recs = Array.isArray(data.Detected_Anomolies)
489
+ ? data.Detected_Anomolies
490
+ : data.Detected_Anomolies
491
+ ? [data.Detected_Anomolies]
492
+ : [];
493
+ if (data.Detected_Anomolies) {
494
+ recsOutput.innerHTML = recs
495
+ .map((rec, i) => renderRecCard(rec, i))
496
+ .join("");
497
+ } else {
498
+ recsOutput.textContent = "No recommendations found.";
499
+ }
500
+
501
+ const findings = Array.isArray(data.Detected_Measurement_Values)
502
+ ? data.Detected_Measurement_Values
503
+ : data.Detected_Measurement_Values
504
+ ? [data.Detected_Measurement_Values]
505
+ : [];
506
+ if (data.Detected_Measurement_Values) {
507
+ findingsOutput.innerHTML = findings
508
+ .map((finding, i) => renderRecCard(finding, i))
509
+ .join("");
510
+ } else {
511
+ findingsOutput.textContent = "No measurements found.";
512
+ }
513
+
514
+ if (currentUser) {
515
+ await saveAnalysis(currentUser.uid, {
516
+ reportDate: date,
517
+ ocr_text: extractedText,
518
+ resolutions: recs,
519
+ measurements: findings,
520
+ });
521
+ }
522
+
523
+ loadingEl.textContent = "Analysis complete.";
524
+ });
525
+
526
+ async function postReportToBackend(report) {
527
+ try {
528
+ const response = await fetch('http://localhost:9000/save_report/', {
529
+ method: 'POST',
530
+ headers: {
531
+ 'Content-Type': 'application/json',
532
+ },
533
+ body: JSON.stringify(report),
534
+ });
535
+ if (!response.ok) {
536
+ throw new Error(`HTTP error! status: ${response.status}`);
537
+ }
538
+ const data = await response.json();
539
+ console.log('Report successfully sent to backend:', data);
540
+ } catch (error) {
541
+ console.error('Error sending report to backend:', error);
542
+ }
543
+ }
544
 
545
+ document.getElementById("ask-btn").onclick = async () => {
546
+ const q = document.getElementById("user-question").value.trim();
 
547
  if (!q) return;
548
+ const chat = document.getElementById("chat-output");
549
  chat.innerHTML += `<p><strong>You:</strong> ${q}</p>`;
550
  chat.scrollTop = chat.scrollHeight;
551
  env.allowLocalModels = false;
552
+ const qa = await pipeline(
553
+ "question-answering",
554
+ "Xenova/distilbert-base-uncased-distilled-squad"
555
+ );
556
  const out = await qa(q, extractedText);
557
  chat.innerHTML += `<p><strong>Chatbot:</strong> ${out.answer}</p>`;
558
+ document.getElementById("user-question").value = "";
559
  chat.scrollTop = chat.scrollHeight;
560
  };
561
+ </script>
562
+ </body>
563
+ </html>