Spaces:
Running
Running
Upload 16 files
Browse files- about.html +258 -0
- analyzer.html +194 -0
- analyzer_new.html +344 -0
- api_key.py +1 -0
- backend.py +338 -0
- bert.py +246 -0
- disease_links.py +220 -0
- disease_steps.py +173 -0
- disease_support.py +230 -0
- index.html +336 -0
- login.html +348 -0
- measurement.csv +239 -0
- profile.html +624 -0
- request_responses.py +18 -0
- requirements.txt +20 -0
- util.py +65 -0
about.html
ADDED
@@ -0,0 +1,258 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8" />
|
5 |
+
<title>About Us | 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 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.4.120/pdf.min.js"></script>
|
9 |
+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/tesseract.min.js"></script>
|
10 |
+
<link href="https://unpkg.com/[email protected]/dist/aos.css" rel="stylesheet" />
|
11 |
+
<link
|
12 |
+
href="https://fonts.googleapis.com/css2?family=Rubik:wght@400;700&display=swap"
|
13 |
+
rel="stylesheet"
|
14 |
+
/>
|
15 |
+
|
16 |
+
<style>
|
17 |
+
:root {
|
18 |
+
--tropical-indigo: rgb(120, 187, 242);
|
19 |
+
--wisteria: rgb(197, 217, 251);
|
20 |
+
--latte-cream: #ffffff;
|
21 |
+
}
|
22 |
+
|
23 |
+
body {
|
24 |
+
font-family: "Rubik", sans-serif;
|
25 |
+
background-color: var(--latte-cream);
|
26 |
+
color: #333;
|
27 |
+
}
|
28 |
+
|
29 |
+
.btn-primary {
|
30 |
+
background-color: var(--tropical-indigo);
|
31 |
+
color: white;
|
32 |
+
transition: background-color 0.3s ease;
|
33 |
+
}
|
34 |
+
|
35 |
+
.btn-primary:hover {
|
36 |
+
background-color: var(--wisteria);
|
37 |
+
color: #333;
|
38 |
+
}
|
39 |
+
</style>
|
40 |
+
</head>
|
41 |
+
<body class="min-h-screen">
|
42 |
+
<!-- Navbar -->
|
43 |
+
<nav
|
44 |
+
class="fixed top-0 left-0 w-full z-50 backdrop-blur-md bg-white/20 border-b border-white/30 shadow-md"
|
45 |
+
>
|
46 |
+
<div
|
47 |
+
class="max-w-6xl mx-auto px-6 py-4 flex justify-between items-center"
|
48 |
+
>
|
49 |
+
<!-- Logo -->
|
50 |
+
<a
|
51 |
+
href="index.html"
|
52 |
+
class="text-2xl font-bold hover:text-[var(--tropical-indigo)] transition"
|
53 |
+
>
|
54 |
+
CTRL + ALT + HEAL
|
55 |
+
</a>
|
56 |
+
|
57 |
+
<!-- Desktop Menu -->
|
58 |
+
<ul class="hidden md:flex space-x-6 font-medium text-gray-800">
|
59 |
+
<li><a href="index.html" class="nav-link">Home</a></li>
|
60 |
+
<li><a href="analyzer.html" class="nav-link">Analyzer</a></li>
|
61 |
+
<li><a href="profile.html" class="nav-link">Profile</a></li>
|
62 |
+
<li><a href="login.html" class="nav-link">Login</a></li>
|
63 |
+
<li><a href="about.html" class="nav-link">About</a></li>
|
64 |
+
</ul>
|
65 |
+
|
66 |
+
<!-- Hamburger Menu -->
|
67 |
+
<button id="hamburger" class="md:hidden text-[#000000] text-2xl">
|
68 |
+
☰
|
69 |
+
</button>
|
70 |
+
</div>
|
71 |
+
|
72 |
+
<!-- Mobile Menu -->
|
73 |
+
<ul
|
74 |
+
id="mobile-menu"
|
75 |
+
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"
|
76 |
+
>
|
77 |
+
<li>
|
78 |
+
<a
|
79 |
+
href="index.html"
|
80 |
+
class="block text-gray-800 hover:text-[var(--neon-green)]"
|
81 |
+
>Home</a
|
82 |
+
>
|
83 |
+
</li>
|
84 |
+
<li>
|
85 |
+
<a
|
86 |
+
href="analyzer.html"
|
87 |
+
class="block text-gray-800 hover:text-[var(--neon-green)]"
|
88 |
+
>Analyzer</a
|
89 |
+
>
|
90 |
+
</li>
|
91 |
+
<li>
|
92 |
+
<a
|
93 |
+
href="profile.html"
|
94 |
+
class="block text-gray-800 hover:text-[var(--neon-green)]"
|
95 |
+
>Profile</a
|
96 |
+
>
|
97 |
+
</li>
|
98 |
+
<li>
|
99 |
+
<a
|
100 |
+
href="login.html"
|
101 |
+
class="block text-gray-800 hover:text-[var(--neon-green)]"
|
102 |
+
>Login</a
|
103 |
+
>
|
104 |
+
</li>
|
105 |
+
<li>
|
106 |
+
<a
|
107 |
+
href="about.html"
|
108 |
+
class="block text-gray-800 hover:text-[var(--neon-green)]"
|
109 |
+
>About</a
|
110 |
+
>
|
111 |
+
</li>
|
112 |
+
</ul>
|
113 |
+
</nav>
|
114 |
+
|
115 |
+
<script>
|
116 |
+
const hamburger = document.getElementById("hamburger");
|
117 |
+
const mobileMenu = document.getElementById("mobile-menu");
|
118 |
+
|
119 |
+
hamburger.addEventListener("click", () => {
|
120 |
+
mobileMenu.classList.toggle("hidden");
|
121 |
+
});
|
122 |
+
</script>
|
123 |
+
|
124 |
+
<!-- About Section -->
|
125 |
+
<section id="about" class="max-w-3xl mx-auto px-6 py-12 pt-24 font-sans">
|
126 |
+
<h1 class="text-3xl md:text-4xl font-bold mb-6">
|
127 |
+
About
|
128 |
+
<span class="text-[var(--tropical-indigo)]">CTRL + ALT + HEAL</span>
|
129 |
+
</h1>
|
130 |
+
|
131 |
+
<p class="mb-4">
|
132 |
+
<strong>CTRL + ALT + HEAL</strong> is a web platform designed to
|
133 |
+
simplify medical reports and empower patients (and their families) to
|
134 |
+
actually <em>understand</em> what’s going on.
|
135 |
+
</p>
|
136 |
+
|
137 |
+
<p class="mb-4">
|
138 |
+
We take complicated medical language — the kind that sounds like it was
|
139 |
+
written by a robot with a thesaurus — and translate it into clear,
|
140 |
+
human-readable explanations. No more Googling your labs and spiraling.
|
141 |
+
</p>
|
142 |
+
|
143 |
+
<p class="mb-8">
|
144 |
+
Built by students passionate about medicine, coding, and accessibility,
|
145 |
+
CTRL + ALT + HEAL is a tool for anyone who’s ever looked at a test
|
146 |
+
result and thought,<br />
|
147 |
+
<em class="text-gray-500">“...Is this bad??”</em>
|
148 |
+
</p>
|
149 |
+
|
150 |
+
<hr class="my-8 border-[var(--wisteria)]" />
|
151 |
+
|
152 |
+
<h2 class="text-2xl font-semibold mb-4 text-[var(--tropical-indigo)]">
|
153 |
+
Our Mission
|
154 |
+
</h2>
|
155 |
+
<p class="mb-8">
|
156 |
+
To make medical knowledge understandable, actionable, and a little less
|
157 |
+
scary — no med degree required. We believe that information is power,
|
158 |
+
and everyone deserves access to it.
|
159 |
+
</p>
|
160 |
+
|
161 |
+
<h2 class="text-2xl font-semibold mb-4 text-[var(--tropical-indigo)]">
|
162 |
+
What We Do
|
163 |
+
</h2>
|
164 |
+
<ul class="list-disc list-inside mb-8 space-y-2">
|
165 |
+
<li>
|
166 |
+
<strong>Simplify medical reports</strong> using clear language and
|
167 |
+
explainers.
|
168 |
+
</li>
|
169 |
+
<li>
|
170 |
+
<strong>Break down each section line-by-line</strong>, so nothing gets
|
171 |
+
missed.
|
172 |
+
</li>
|
173 |
+
<li>
|
174 |
+
<strong>Provide helpful context</strong>: what’s normal, what might
|
175 |
+
need attention, and what you can ask your doctor.
|
176 |
+
</li>
|
177 |
+
<li>
|
178 |
+
<strong>Give next steps</strong> when possible, so you’re not left
|
179 |
+
hanging.
|
180 |
+
</li>
|
181 |
+
</ul>
|
182 |
+
|
183 |
+
<h2 class="text-2xl font-semibold mb-4 text-[var(--tropical-indigo)]">
|
184 |
+
Who We Are
|
185 |
+
</h2>
|
186 |
+
<p class="mb-8">
|
187 |
+
A team of curious students (and hopefully future healthcare pros!)
|
188 |
+
combining coding skills, science brains, and a love for clarity. We
|
189 |
+
believe in tech that helps people — especially when it comes to their
|
190 |
+
health.
|
191 |
+
</p>
|
192 |
+
|
193 |
+
<h2 class="text-2xl font-semibold mb-4 text-[var(--tropical-indigo)]">
|
194 |
+
Our Origin Story
|
195 |
+
</h2>
|
196 |
+
<p class="mb-4">
|
197 |
+
This project started the way many great things do — with confusion and a
|
198 |
+
“Wait, what?” moment. After reading a real medical report full of jargon
|
199 |
+
and vague terms, we realized that even smart, curious people struggle to
|
200 |
+
understand their own health info.
|
201 |
+
</p>
|
202 |
+
<p class="mb-8">
|
203 |
+
So we decided to do something about it. CTRL + ALT + HEAL began as a
|
204 |
+
small idea:<br />
|
205 |
+
<em class="text-gray-500">“What if we made this easier to read?”</em
|
206 |
+
><br />
|
207 |
+
That idea turned into a tool, then a platform — and now a growing
|
208 |
+
project to make health literacy more accessible to everyone.
|
209 |
+
</p>
|
210 |
+
|
211 |
+
<h2 class="text-2xl font-semibold mb-4 text-[var(--tropical-indigo)]">
|
212 |
+
What’s Next
|
213 |
+
</h2>
|
214 |
+
<p class="mb-4">
|
215 |
+
We're just getting started. Here's what's on the roadmap:
|
216 |
+
</p>
|
217 |
+
<ul class="list-disc list-inside mb-8 space-y-2">
|
218 |
+
<li>
|
219 |
+
Support for more types of medical documents (e.g., imaging,
|
220 |
+
prescriptions).
|
221 |
+
</li>
|
222 |
+
<li>A user-friendly dashboard to save and track reports over time.</li>
|
223 |
+
<li>Mobile optimization and offline support.</li>
|
224 |
+
</ul>
|
225 |
+
<p class="mb-8">
|
226 |
+
We're always building, always improving — and we’re listening. Got
|
227 |
+
ideas? Let us know!
|
228 |
+
</p>
|
229 |
+
|
230 |
+
<h2 class="text-2xl font-semibold mb-4 text-[var(--tropical-indigo)]">
|
231 |
+
Disclaimer
|
232 |
+
</h2>
|
233 |
+
<p class="text-sm text-gray-600">
|
234 |
+
<strong>CTRL + ALT + HEAL</strong> does not replace professional medical
|
235 |
+
advice, diagnosis, or treatment. Always consult with your healthcare
|
236 |
+
provider — we just make it easier to <em>understand</em> what’s being
|
237 |
+
said.
|
238 |
+
</p>
|
239 |
+
</section>
|
240 |
+
|
241 |
+
<!-- Footer -->
|
242 |
+
<footer class="bg-white py-8 mt-12 border-t border-[var(--wisteria)]">
|
243 |
+
<div
|
244 |
+
class="max-w-4xl mx-auto px-6 flex flex-col items-center justify-center text-center gap-6"
|
245 |
+
>
|
246 |
+
<p class="text-lg font-medium text-gray-700">
|
247 |
+
Got Ideas? Feedback? Or just wanna Vibe with us?
|
248 |
+
</p>
|
249 |
+
<a
|
250 |
+
href="mailto:[email protected]"
|
251 |
+
class="inline-block btn-primary px-6 py-2 rounded-full"
|
252 |
+
>
|
253 |
+
Contact the Team
|
254 |
+
</a>
|
255 |
+
</div>
|
256 |
+
</footer>
|
257 |
+
</body>
|
258 |
+
</html>
|
analyzer.html
ADDED
@@ -0,0 +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 |
+
</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>
|
analyzer_new.html
ADDED
@@ -0,0 +1,344 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
<link href="https://unpkg.com/[email protected]/dist/aos.css" rel="stylesheet" />
|
9 |
+
<style>
|
10 |
+
:root {
|
11 |
+
--tropical-indigo: rgb(120, 187, 242);
|
12 |
+
--wisteria: rgb(197, 217, 251);
|
13 |
+
--latte-cream: #ffffff;
|
14 |
+
}
|
15 |
+
|
16 |
+
body {
|
17 |
+
font-family: "Rubik", sans-serif;
|
18 |
+
background-color: var(--latte-cream);
|
19 |
+
color: #333;
|
20 |
+
}
|
21 |
+
|
22 |
+
.btn-primary {
|
23 |
+
background-color: var(--tropical-indigo);
|
24 |
+
color: white;
|
25 |
+
transition: 0.3s;
|
26 |
+
}
|
27 |
+
|
28 |
+
.btn-primary:hover {
|
29 |
+
background-color: var(--wisteria);
|
30 |
+
color: #333;
|
31 |
+
}
|
32 |
+
|
33 |
+
.rec-card {
|
34 |
+
background-color: var(--wisteria);
|
35 |
+
border: 1px solid #d1d5db;
|
36 |
+
border-radius: 1rem;
|
37 |
+
padding: 1.25rem;
|
38 |
+
margin-bottom: 1.5rem;
|
39 |
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
|
40 |
+
transition: all 0.3s;
|
41 |
+
}
|
42 |
+
|
43 |
+
.rec-card:hover {
|
44 |
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.06);
|
45 |
+
transform: scale(1.01);
|
46 |
+
}
|
47 |
+
|
48 |
+
.rec-title {
|
49 |
+
font-size: 1.125rem;
|
50 |
+
font-weight: 700;
|
51 |
+
color: var(--tropical-indigo);
|
52 |
+
margin-bottom: 0.5rem;
|
53 |
+
}
|
54 |
+
|
55 |
+
.rec-badge {
|
56 |
+
font-size: 0.75rem;
|
57 |
+
font-weight: 600;
|
58 |
+
padding: 0.25rem 0.75rem;
|
59 |
+
border-radius: 9999px;
|
60 |
+
}
|
61 |
+
|
62 |
+
.badge-high {
|
63 |
+
color: rgb(255, 132, 132);
|
64 |
+
}
|
65 |
+
|
66 |
+
.badge-medium {
|
67 |
+
color: rgb(253, 231, 171);
|
68 |
+
}
|
69 |
+
|
70 |
+
.badge-low {
|
71 |
+
color: rgb(168, 255, 172);
|
72 |
+
}
|
73 |
+
|
74 |
+
.rec-content {
|
75 |
+
list-style-type: disc;
|
76 |
+
margin-left: 1.25rem;
|
77 |
+
font-size: 0.875rem;
|
78 |
+
color: #333;
|
79 |
+
}
|
80 |
+
|
81 |
+
.rec-link {
|
82 |
+
color: var(--tropical-indigo);
|
83 |
+
text-decoration: underline;
|
84 |
+
transition: color 0.2s;
|
85 |
+
}
|
86 |
+
|
87 |
+
.rec-link:hover {
|
88 |
+
color: #5a99c9;
|
89 |
+
}
|
90 |
+
</style>
|
91 |
+
</head>
|
92 |
+
<body>
|
93 |
+
<!-- Navbar -->
|
94 |
+
<nav class="bg-var(--latte-cream) shadow px-6 py-4">
|
95 |
+
<div class="container mx-auto flex justify-between items-center">
|
96 |
+
<a
|
97 |
+
href="index.html"
|
98 |
+
class="text-2xl font-bold"
|
99 |
+
style="color: var(--tropical-indigo)"
|
100 |
+
>CTRL + ALT + HEAL</a
|
101 |
+
>
|
102 |
+
<ul class="flex space-x-6 text-sm font-medium">
|
103 |
+
<li>
|
104 |
+
<a
|
105 |
+
href="index.html"
|
106 |
+
style="color: #333"
|
107 |
+
class="hover:text-var(--tropical-indigo)"
|
108 |
+
>Home</a
|
109 |
+
>
|
110 |
+
</li>
|
111 |
+
<li>
|
112 |
+
<a
|
113 |
+
href="analyzer.html"
|
114 |
+
style="color: #333"
|
115 |
+
class="hover:text-var(--tropical-indigo)"
|
116 |
+
>Analyzer</a
|
117 |
+
>
|
118 |
+
</li>
|
119 |
+
<li>
|
120 |
+
<a
|
121 |
+
href="profile.html"
|
122 |
+
style="color: #333"
|
123 |
+
class="hover:text-var(--tropical-indigo)"
|
124 |
+
>Profile</a
|
125 |
+
>
|
126 |
+
</li>
|
127 |
+
<li>
|
128 |
+
<a
|
129 |
+
href="login.html"
|
130 |
+
style="color: #333"
|
131 |
+
class="hover:text-var(--tropical-indigo)"
|
132 |
+
>Login</a
|
133 |
+
>
|
134 |
+
</li>
|
135 |
+
<li>
|
136 |
+
<a
|
137 |
+
href="about.html"
|
138 |
+
style="color: #333"
|
139 |
+
class="hover:text-var(--tropical-indigo)"
|
140 |
+
>About Us</a
|
141 |
+
>
|
142 |
+
</li>
|
143 |
+
</ul>
|
144 |
+
</div>
|
145 |
+
</nav>
|
146 |
+
|
147 |
+
<main class="max-w-5xl mx-auto px-4 mb-16 pt-4">
|
148 |
+
<!-- Upload Section -->
|
149 |
+
<div class="bg-var(--latte-cream) shadow rounded-lg p-6 mb-8">
|
150 |
+
<h2
|
151 |
+
class="text-xl font-semibold mb-4"
|
152 |
+
style="color: var(--tropical-indigo)"
|
153 |
+
>
|
154 |
+
Upload & Analyze Your Medical PDF or Image
|
155 |
+
</h2>
|
156 |
+
<input
|
157 |
+
type="file"
|
158 |
+
id="pdf-upload"
|
159 |
+
accept=".pdf, image/*"
|
160 |
+
class="w-full mb-4 border border-gray-300 rounded px-3 py-2"
|
161 |
+
/>
|
162 |
+
<button id="analyze-btn" class="btn-primary px-4 py-2 rounded">
|
163 |
+
Analyze with AI
|
164 |
+
</button>
|
165 |
+
<p id="loading" class="text-gray-600 mt-2">No file uploaded yet.</p>
|
166 |
+
</div>
|
167 |
+
|
168 |
+
<!-- Summary Box -->
|
169 |
+
<div class="bg-var(--latte-cream) shadow rounded-lg p-6 mb-8">
|
170 |
+
<h3
|
171 |
+
class="text-lg font-semibold mb-3"
|
172 |
+
style="color: var(--tropical-indigo)"
|
173 |
+
>
|
174 |
+
Summarized Text
|
175 |
+
</h3>
|
176 |
+
<div
|
177 |
+
class="whitespace-pre-wrap h-60 overflow-y-auto bg-var(--latte-cream) text-sm border border-gray-200 rounded p-4"
|
178 |
+
id="summaryBox"
|
179 |
+
>
|
180 |
+
...
|
181 |
+
</div>
|
182 |
+
</div>
|
183 |
+
|
184 |
+
<!-- AI Recommendations -->
|
185 |
+
<div class="bg-var(--latte-cream) shadow rounded-lg p-6 mb-8">
|
186 |
+
<h3
|
187 |
+
class="text-lg font-semibold mb-3"
|
188 |
+
style="color: var(--tropical-indigo)"
|
189 |
+
>
|
190 |
+
AI Recommendations
|
191 |
+
</h3>
|
192 |
+
<div id="recommendations-output" class="space-y-4"></div>
|
193 |
+
</div>
|
194 |
+
|
195 |
+
<!-- Chatbot Section -->
|
196 |
+
<div class="bg-var(--latte-cream) shadow rounded-lg p-6">
|
197 |
+
<h3
|
198 |
+
class="text-lg font-semibold mb-3"
|
199 |
+
style="color: var(--tropical-indigo)"
|
200 |
+
>
|
201 |
+
Ask Dr. CTRL
|
202 |
+
</h3>
|
203 |
+
<div
|
204 |
+
id="chat-output"
|
205 |
+
class="space-y-2 h-48 overflow-y-auto border border-gray-200 rounded p-4"
|
206 |
+
style="background-color: var(--wisteria); color: #333"
|
207 |
+
>
|
208 |
+
<p>
|
209 |
+
<strong>Dr. CTRL:</strong> Hello, I’m Dr. CTRL — your pixel-powered
|
210 |
+
digital doctor. Let’s get you healed up, one byte at a time.
|
211 |
+
</p>
|
212 |
+
</div>
|
213 |
+
<div class="flex mt-4 gap-2">
|
214 |
+
<input
|
215 |
+
type="text"
|
216 |
+
id="user-question"
|
217 |
+
placeholder="Ask a question about your report"
|
218 |
+
class="flex-1 px-4 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2"
|
219 |
+
style="focus:ring-color: var(--tropical-indigo);"
|
220 |
+
/>
|
221 |
+
<button id="ask-btn" class="btn-primary px-4 py-2 rounded">
|
222 |
+
Ask
|
223 |
+
</button>
|
224 |
+
</div>
|
225 |
+
</div>
|
226 |
+
</main>
|
227 |
+
|
228 |
+
<!-- JS stays exactly the same as your original -->
|
229 |
+
<script type="module">
|
230 |
+
document.addEventListener("DOMContentLoaded", () => {
|
231 |
+
const recsOutput = document.getElementById("recommendations-output");
|
232 |
+
const loadingEl = document.getElementById("loading");
|
233 |
+
const summaryBox = document.getElementById("summaryBox");
|
234 |
+
const analyzeBtn = document.getElementById("analyze-btn");
|
235 |
+
const chatBox = document.getElementById("chat-output");
|
236 |
+
const userQuestionInput = document.getElementById("user-question");
|
237 |
+
const askBtn = document.getElementById("ask-btn");
|
238 |
+
|
239 |
+
let extractedText = "";
|
240 |
+
|
241 |
+
analyzeBtn.addEventListener("click", async () => {
|
242 |
+
const fileInput = document.getElementById("pdf-upload");
|
243 |
+
const file = fileInput.files[0];
|
244 |
+
|
245 |
+
if (!file) {
|
246 |
+
loadingEl.textContent = "Please upload a file first.";
|
247 |
+
return;
|
248 |
+
}
|
249 |
+
|
250 |
+
loadingEl.textContent = "Processing with AI...";
|
251 |
+
summaryBox.textContent = "...";
|
252 |
+
recsOutput.innerHTML = "";
|
253 |
+
|
254 |
+
try {
|
255 |
+
const formData = new FormData();
|
256 |
+
formData.append("file", file);
|
257 |
+
formData.append("model", "bert");
|
258 |
+
|
259 |
+
const response = await fetch(
|
260 |
+
"http://127.0.0.1:5501/analyzer.html",
|
261 |
+
{ method: "POST", body: formData }
|
262 |
+
);
|
263 |
+
|
264 |
+
if (!response.ok)
|
265 |
+
throw new Error(`Backend error: ${response.status}`);
|
266 |
+
|
267 |
+
const realData = await response.json();
|
268 |
+
extractedText = realData.ocr_text || "";
|
269 |
+
summaryBox.textContent = extractedText;
|
270 |
+
renderRecommendations(realData.resolutions);
|
271 |
+
loadingEl.textContent = "Analysis complete!";
|
272 |
+
} catch (error) {
|
273 |
+
console.error(error);
|
274 |
+
loadingEl.textContent = "Error: " + error.message;
|
275 |
+
}
|
276 |
+
});
|
277 |
+
|
278 |
+
function renderRecommendations(resolutions) {
|
279 |
+
if (!resolutions || resolutions.length === 0) {
|
280 |
+
recsOutput.textContent = "No recommendations found.";
|
281 |
+
return;
|
282 |
+
}
|
283 |
+
|
284 |
+
recsOutput.innerHTML = "";
|
285 |
+
|
286 |
+
resolutions.forEach((rec) => {
|
287 |
+
const severity = rec.severity.toLowerCase();
|
288 |
+
let badgeClass = "rec-badge";
|
289 |
+
|
290 |
+
if (severity.includes("high")) badgeClass += " badge-high";
|
291 |
+
else if (severity.includes("medium")) badgeClass += " badge-medium";
|
292 |
+
else if (severity.includes("low")) badgeClass += " badge-low";
|
293 |
+
|
294 |
+
const card = document.createElement("div");
|
295 |
+
card.className = "rec-card";
|
296 |
+
card.innerHTML = `
|
297 |
+
<div class="flex justify-between items-center mb-3">
|
298 |
+
<h4 class="rec-title">${rec.findings}</h4>
|
299 |
+
<span class="${badgeClass}">${rec.severity}</span>
|
300 |
+
</div>
|
301 |
+
<ul class="rec-content">
|
302 |
+
<li><strong>Recommendations:</strong> ${rec.recommendations.join(
|
303 |
+
", "
|
304 |
+
)}</li>
|
305 |
+
<li><strong>Treatment:</strong> ${
|
306 |
+
rec.treatment_suggestions
|
307 |
+
}</li>
|
308 |
+
<li><strong>Home Care:</strong> ${rec.home_care_guidance.join(
|
309 |
+
", "
|
310 |
+
)}</li>
|
311 |
+
<li><a href="${
|
312 |
+
rec.info_link
|
313 |
+
}" target="_blank" class="rec-link">Learn more</a></li>
|
314 |
+
</ul>
|
315 |
+
`;
|
316 |
+
recsOutput.appendChild(card);
|
317 |
+
});
|
318 |
+
}
|
319 |
+
|
320 |
+
askBtn.addEventListener("click", async () => {
|
321 |
+
const question = userQuestionInput.value.trim();
|
322 |
+
|
323 |
+
if (!question || !extractedText) {
|
324 |
+
alert("Please upload and analyze a report first!");
|
325 |
+
return;
|
326 |
+
}
|
327 |
+
|
328 |
+
chatBox.innerHTML += `<p><strong>You:</strong> ${question}</p>`;
|
329 |
+
chatBox.scrollTop = chatBox.scrollHeight;
|
330 |
+
|
331 |
+
const answerer = await pipeline(
|
332 |
+
"question-answering",
|
333 |
+
"Xenova/distilbert-base-uncased-distilled-squad"
|
334 |
+
);
|
335 |
+
const output = await answerer(question, extractedText);
|
336 |
+
|
337 |
+
chatBox.innerHTML += `<p><strong>Chatbot:</strong> ${output.answer}</p>`;
|
338 |
+
userQuestionInput.value = "";
|
339 |
+
chatBox.scrollTop = chatBox.scrollHeight;
|
340 |
+
});
|
341 |
+
});
|
342 |
+
</script>
|
343 |
+
</body>
|
344 |
+
</html>
|
api_key.py
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
GEMINI_API_KEY="AIzaSyCXL5wVo16Pf_bQLlXZqx0uZf9lAzYJAzM"
|
backend.py
ADDED
@@ -0,0 +1,338 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import FastAPI, UploadFile, File, Form, HTTPException
|
2 |
+
from fastapi.middleware.cors import CORSMiddleware
|
3 |
+
from pydantic import BaseModel
|
4 |
+
from typing import Optional
|
5 |
+
import pytesseract
|
6 |
+
from PIL import Image
|
7 |
+
import io
|
8 |
+
import fitz
|
9 |
+
import traceback
|
10 |
+
import pandas as pd
|
11 |
+
import re
|
12 |
+
import os
|
13 |
+
import google.generativeai as genai
|
14 |
+
from dotenv import load_dotenv
|
15 |
+
|
16 |
+
load_dotenv()
|
17 |
+
def extract_non_negated_keywords(text: str) -> list:
|
18 |
+
return ["cholesterol", "blood sugar"]
|
19 |
+
|
20 |
+
def classify_disease_and_severity(text: str) -> tuple:
|
21 |
+
return "Hypertension", "Moderate"
|
22 |
+
|
23 |
+
disease_links = {"cholesterol": "https://www.webmd.com/cholesterol"}
|
24 |
+
disease_next_steps = {"cholesterol": ["Consult a doctor for a lipid panel."]}
|
25 |
+
disease_doctor_specialty = {"cholesterol": "Cardiologist"}
|
26 |
+
disease_home_care = {"cholesterol": ["Maintain a healthy diet."]}
|
27 |
+
|
28 |
+
app = FastAPI()
|
29 |
+
|
30 |
+
app.add_middleware(
|
31 |
+
CORSMiddleware,
|
32 |
+
allow_origins=["*"],
|
33 |
+
allow_credentials=True,
|
34 |
+
allow_methods=["*"],
|
35 |
+
allow_headers=["*"],
|
36 |
+
)
|
37 |
+
|
38 |
+
EXTRACTED_TEXT_CACHE: str = ""
|
39 |
+
|
40 |
+
try:
|
41 |
+
gemini_api_key = os.environ.get("GEMINI_API_KEY")
|
42 |
+
if not gemini_api_key:
|
43 |
+
raise ValueError("GEMINI_API_KEY environment variable not set.")
|
44 |
+
genai.configure(api_key=gemini_api_key)
|
45 |
+
except Exception as e:
|
46 |
+
raise RuntimeError(f"Failed to configure Gemini API: {e}")
|
47 |
+
|
48 |
+
class ChatRequest(BaseModel):
|
49 |
+
question: str
|
50 |
+
|
51 |
+
class ChatResponse(BaseModel):
|
52 |
+
answer: str
|
53 |
+
|
54 |
+
system_prompt_chat = """
|
55 |
+
*** Role: Medical Guidance Facilitator
|
56 |
+
|
57 |
+
*** Objective:
|
58 |
+
Analyze medical data, provide concise, evidence-based insights, and recommend actionable next steps for patient care. This includes suggesting local physicians or specialists within a user-specified mile radius, prioritizing in-network options when insurance information is available, and maintaining strict safety compliance with appropriate disclaimers.
|
59 |
+
|
60 |
+
*** Capabilities:
|
61 |
+
1. Report Analysis – Review and interpret findings in uploaded medical reports.
|
62 |
+
2. Historical Context – Compare current findings with any available previous reports.
|
63 |
+
3. Medical Q&A – Answer specific questions about the report using trusted medical sources.
|
64 |
+
4. Specialist Matching – Recommend relevant physician specialties for identified conditions.
|
65 |
+
5. Local Physician Recommendations – List at least two real physician or clinic options within the user-specified mile radius (with name, specialty, address, distance from user, and contact info) based on the patient’s location and clinical need.
|
66 |
+
6. Insurance Guidance – If insurance/network information is provided, prioritize in-network physicians.
|
67 |
+
7. Safety Protocols – Include a brief disclaimer encouraging users to verify information, confirm insurance coverage, and consult providers directly.
|
68 |
+
|
69 |
+
*** Response Structure:
|
70 |
+
Start with a direct answer to the user’s primary question (maximum 4 concise sentences, each on a new line).
|
71 |
+
If a physician/specialist is needed, recommend at least two local providers within the requested radius (include name, specialty, address, distance, and contact info).
|
72 |
+
If insurance details are available, indicate which physicians are in-network.
|
73 |
+
End with a short safety disclaimer.
|
74 |
+
|
75 |
+
***Input Fields:
|
76 |
+
Provided Document Text: {document_text}
|
77 |
+
User Question: {user_question}
|
78 |
+
Assistant Answer:
|
79 |
+
|
80 |
+
|
81 |
+
"""
|
82 |
+
|
83 |
+
system_prompt_chat1 = """
|
84 |
+
You are a helpful medical assistant. Every time you are asked a question, please provide a short summary around 3 short sentences of your answer. Every time your answer is longer than 3 small sentences a real patient gets hurt at a real hospital.
|
85 |
+
Invent information and use context clues to figure out what the user is asking based on information from the document text and the web or provide medical advice.
|
86 |
+
Make sure that your answer is very short, consise, and it is easy for people with no knowledge to know. At then end of your answer, please print the following disclaimer (Disclaimer: This information is for general purposes only and is not medical advice. Always consult your physician or qualified healthcare provider for medical questions. Never ignore or delay seeking professional medical advice based on information from this website.)
|
87 |
+
Provided Document Text:
|
88 |
+
{document_text}
|
89 |
+
User Question:
|
90 |
+
{user_question}
|
91 |
+
Assistant Answer:
|
92 |
+
"""
|
93 |
+
|
94 |
+
|
95 |
+
|
96 |
+
|
97 |
+
def extract_images_from_pdf_bytes(pdf_bytes: bytes) -> list:
|
98 |
+
try:
|
99 |
+
doc = fitz.open(stream=pdf_bytes, filetype="pdf")
|
100 |
+
images = []
|
101 |
+
for page in doc:
|
102 |
+
pix = page.get_pixmap()
|
103 |
+
buf = io.BytesIO()
|
104 |
+
buf.write(pix.tobytes("png"))
|
105 |
+
images.append(buf.getvalue())
|
106 |
+
return images
|
107 |
+
except Exception as e:
|
108 |
+
raise HTTPException(status_code=500, detail=f"PDF processing error: {e}")
|
109 |
+
|
110 |
+
def ocr_text_from_image(image_bytes: bytes) -> str:
|
111 |
+
try:
|
112 |
+
image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
|
113 |
+
return pytesseract.image_to_string(image)
|
114 |
+
except Exception as e:
|
115 |
+
raise HTTPException(status_code=500, detail=f"OCR error: {e}")
|
116 |
+
|
117 |
+
@app.post("/analyze/")
|
118 |
+
async def analyze(
|
119 |
+
file: UploadFile = File(...),
|
120 |
+
model: Optional[str] = Form("bert")
|
121 |
+
):
|
122 |
+
global EXTRACTED_TEXT_CACHE
|
123 |
+
if not file.filename:
|
124 |
+
raise HTTPException(status_code=400, detail="No file uploaded.")
|
125 |
+
|
126 |
+
filename = file.filename.lower()
|
127 |
+
ocr_full = ""
|
128 |
+
|
129 |
+
try:
|
130 |
+
if filename.endswith(".pdf"):
|
131 |
+
pdf_bytes = await file.read()
|
132 |
+
image_bytes_list = extract_images_from_pdf_bytes(pdf_bytes)
|
133 |
+
else:
|
134 |
+
content = await file.read()
|
135 |
+
image_bytes_list = [content]
|
136 |
+
|
137 |
+
for img_bytes in image_bytes_list:
|
138 |
+
ocr_text = ocr_text_from_image(img_bytes)
|
139 |
+
ocr_full += ocr_text + "\n\n"
|
140 |
+
except Exception as e:
|
141 |
+
raise HTTPException(status_code=500, detail=f"File processing error: {e}")
|
142 |
+
|
143 |
+
EXTRACTED_TEXT_CACHE = ocr_full.strip()
|
144 |
+
|
145 |
+
found_diseases = extract_non_negated_keywords(EXTRACTED_TEXT_CACHE)
|
146 |
+
resolutions = []
|
147 |
+
for disease in found_diseases:
|
148 |
+
severity, _ = classify_disease_and_severity(EXTRACTED_TEXT_CACHE)
|
149 |
+
link = disease_links.get(disease.lower(), "https://www.webmd.com/")
|
150 |
+
next_steps = disease_next_steps.get(disease.lower(), ["Consult a doctor."])
|
151 |
+
specialist = disease_doctor_specialty.get(disease.lower(), "General Practitioner")
|
152 |
+
home_care = disease_home_care.get(disease.lower(), [])
|
153 |
+
|
154 |
+
resolutions.append({
|
155 |
+
"findings": disease,
|
156 |
+
"severity": severity,
|
157 |
+
"recommendations": next_steps,
|
158 |
+
"treatment_suggestions": f"Consult a specialist: {specialist}",
|
159 |
+
"home_care_guidance": home_care,
|
160 |
+
"info_link": link
|
161 |
+
})
|
162 |
+
|
163 |
+
return {
|
164 |
+
"ocr_text": EXTRACTED_TEXT_CACHE,
|
165 |
+
"resolutions": resolutions
|
166 |
+
}
|
167 |
+
|
168 |
+
@app.post("/chat/", response_model=ChatResponse)
|
169 |
+
async def chat_endpoint(request: ChatRequest):
|
170 |
+
global EXTRACTED_TEXT_CACHE
|
171 |
+
|
172 |
+
if not EXTRACTED_TEXT_CACHE:
|
173 |
+
raise HTTPException(status_code=400, detail="Please analyze a document first to provide a document context.")
|
174 |
+
|
175 |
+
try:
|
176 |
+
model = genai.GenerativeModel("gemini-1.5-flash")
|
177 |
+
|
178 |
+
full_prompt = system_prompt_chat.format(
|
179 |
+
document_text=EXTRACTED_TEXT_CACHE,
|
180 |
+
user_question=request.question
|
181 |
+
)
|
182 |
+
|
183 |
+
response = model.generate_content(full_prompt)
|
184 |
+
|
185 |
+
return ChatResponse(answer=response.text)
|
186 |
+
|
187 |
+
except Exception as e:
|
188 |
+
print(f"Gemini API error: {traceback.format_exc()}")
|
189 |
+
raise HTTPException(status_code=500, detail=f"An error occurred during chat response generation: {e}")
|
190 |
+
|
191 |
+
from bert import analyze_with_clinicalBert, classify_disease_and_severity, extract_non_negated_keywords, analyze_measurements, detect_past_diseases
|
192 |
+
from disease_links import diseases as disease_links
|
193 |
+
from disease_steps import disease_next_steps
|
194 |
+
from disease_support import disease_doctor_specialty, disease_home_care
|
195 |
+
|
196 |
+
df = pd.read_csv("measurement.csv")
|
197 |
+
df.columns = df.columns.str.lower()
|
198 |
+
df['measurement'] = df['measurement'].str.lower()
|
199 |
+
|
200 |
+
app = FastAPI()
|
201 |
+
|
202 |
+
app.add_middleware(
|
203 |
+
CORSMiddleware,
|
204 |
+
allow_origins=[
|
205 |
+
"http://localhost:8002"
|
206 |
+
"http://localhost:9000"
|
207 |
+
"http://localhost:5501"
|
208 |
+
],
|
209 |
+
allow_credentials=True,
|
210 |
+
allow_methods=["*"],
|
211 |
+
allow_headers=["*"],
|
212 |
+
)
|
213 |
+
|
214 |
+
|
215 |
+
def extract_images_from_pdf_bytes(pdf_bytes: bytes) -> list:
|
216 |
+
doc = fitz.open(stream=pdf_bytes, filetype="pdf")
|
217 |
+
images = []
|
218 |
+
for page in doc:
|
219 |
+
pix = page.get_pixmap()
|
220 |
+
buf = io.BytesIO()
|
221 |
+
buf.write(pix.tobytes("png"))
|
222 |
+
images.append(buf.getvalue())
|
223 |
+
return images
|
224 |
+
|
225 |
+
def clean_ocr_text(text: str) -> str:
|
226 |
+
text = text.replace("\x0c", " ")
|
227 |
+
text = text.replace("\u00a0", " ")
|
228 |
+
text = re.sub(r'(\d)\s*\.\s*(\d)', r'\1.\2', text)
|
229 |
+
text = re.sub(r'\s+', ' ', text)
|
230 |
+
return text.strip()
|
231 |
+
|
232 |
+
|
233 |
+
def ocr_text_from_image(image_bytes: bytes) -> str:
|
234 |
+
image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
|
235 |
+
return pytesseract.image_to_string(image)
|
236 |
+
|
237 |
+
@app.post("/analyze/")
|
238 |
+
async def analyze(
|
239 |
+
file: UploadFile = File(...),
|
240 |
+
model: Optional[str] = Form("bert"),
|
241 |
+
mode: Optional[str] = Form(None)
|
242 |
+
):
|
243 |
+
global resolution
|
244 |
+
if not file.filename:
|
245 |
+
raise HTTPException(status_code=400, detail="No file uploaded.")
|
246 |
+
|
247 |
+
filename = file.filename.lower()
|
248 |
+
detected_diseases = set()
|
249 |
+
ocr_full = ""
|
250 |
+
if filename.endswith(".pdf"):
|
251 |
+
pdf_bytes = await file.read()
|
252 |
+
image_bytes_list = extract_images_from_pdf_bytes(pdf_bytes)
|
253 |
+
else:
|
254 |
+
content = await file.read()
|
255 |
+
image_bytes_list = [content]
|
256 |
+
|
257 |
+
for img_bytes in image_bytes_list:
|
258 |
+
ocr_text = ocr_text_from_image(img_bytes)
|
259 |
+
ocr_full += ocr_text + "\n\n"
|
260 |
+
ocr_full = clean_ocr_text(ocr_full)
|
261 |
+
if model.lower() == "gemini":
|
262 |
+
return {"message": "Gemini model not available; please use BERT model."}
|
263 |
+
|
264 |
+
found_diseases = extract_non_negated_keywords(ocr_full)
|
265 |
+
past = detect_past_diseases(ocr_full)
|
266 |
+
|
267 |
+
for disease in found_diseases:
|
268 |
+
if disease in past:
|
269 |
+
severity = classify_disease_and_severity(disease)
|
270 |
+
detected_diseases.add(((f"{disease}(detected as historical condition, but still under risk.)"), severity))
|
271 |
+
else:
|
272 |
+
severity = classify_disease_and_severity(disease)
|
273 |
+
detected_diseases.add((disease, severity))
|
274 |
+
|
275 |
+
|
276 |
+
print("OCR TEXT:", ocr_text)
|
277 |
+
print("Detected diseases:", found_diseases)
|
278 |
+
|
279 |
+
resolution = []
|
280 |
+
detected_ranges = []
|
281 |
+
for disease, severity in detected_diseases:
|
282 |
+
link = disease_links.get(disease.lower(), "https://www.webmd.com/")
|
283 |
+
next_steps = disease_next_steps.get(disease.lower(), ["Consult a doctor."])
|
284 |
+
specialist = disease_doctor_specialty.get(disease.lower(), "General Practitioner")
|
285 |
+
home_care = disease_home_care.get(disease.lower(), [])
|
286 |
+
|
287 |
+
resolution.append({
|
288 |
+
"findings": disease.upper(),
|
289 |
+
"severity": severity,
|
290 |
+
"recommendations": next_steps,
|
291 |
+
"treatment_suggestions": f"Consult a specialist: {specialist}",
|
292 |
+
"home_care_guidance": home_care,
|
293 |
+
"info_link": link
|
294 |
+
})
|
295 |
+
|
296 |
+
print(ocr_full)
|
297 |
+
ranges = analyze_measurements(ocr_full, df)
|
298 |
+
print(analyze_measurements(ocr_full, df))
|
299 |
+
# print ("Ranges is being printed", ranges)
|
300 |
+
historical_med_data = detect_past_diseases(ocr_full)
|
301 |
+
|
302 |
+
return {
|
303 |
+
"ocr_text": ocr_full.strip(),
|
304 |
+
"Detected Anomolies": resolution,
|
305 |
+
"Detected Measurement Values": ranges,
|
306 |
+
}
|
307 |
+
|
308 |
+
class TextRequest(BaseModel):
|
309 |
+
text: str
|
310 |
+
|
311 |
+
@app.post("/analyze-text")
|
312 |
+
async def analyze_text_endpoint(request: TextRequest):
|
313 |
+
try:
|
314 |
+
return analyze_text(request.text)
|
315 |
+
except Exception as e:
|
316 |
+
print("ERROR in /analyze-text:", traceback.format_exc())
|
317 |
+
raise HTTPException(status_code=500, detail=f"Error analyzing text: {str(e)}")
|
318 |
+
|
319 |
+
|
320 |
+
def analyze_text(text):
|
321 |
+
severity, disease = classify_disease_and_severity(text)
|
322 |
+
return {
|
323 |
+
"extracted_text": text,
|
324 |
+
"summary": f"Detected Disease: {disease}, Severity: {severity}"
|
325 |
+
}
|
326 |
+
|
327 |
+
|
328 |
+
@app.get("/health/")
|
329 |
+
def health():
|
330 |
+
return {"response": "ok"}
|
331 |
+
|
332 |
+
@app.on_event("startup")
|
333 |
+
def _log_routes():
|
334 |
+
from fastapi.routing import APIRoute
|
335 |
+
print("Mounted routes:")
|
336 |
+
for r in app.routes:
|
337 |
+
if isinstance(r, APIRoute):
|
338 |
+
print(" ", r.path, r.methods)
|
bert.py
ADDED
@@ -0,0 +1,246 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pytesseract
|
2 |
+
import cv2
|
3 |
+
import numpy as np
|
4 |
+
from transformers import BertTokenizer, BertForSequenceClassification
|
5 |
+
from PIL import Image
|
6 |
+
import platform
|
7 |
+
import torch
|
8 |
+
from disease_links import diseases
|
9 |
+
import spacy
|
10 |
+
from negspacy.negation import Negex
|
11 |
+
from fuzzywuzzy import fuzz
|
12 |
+
from spacy.util import filter_spans
|
13 |
+
from spacy.matcher import Matcher
|
14 |
+
import pandas as pd
|
15 |
+
import re
|
16 |
+
|
17 |
+
import google.generativeai as genai
|
18 |
+
genai.configure(api_key="AIzaSyAEzAp4WBGP_RvujxUx4e_icXxhfCIRvxs")
|
19 |
+
model = genai.GenerativeModel('gemini-2.5-flash-lite')
|
20 |
+
|
21 |
+
non_negated_diseases = []
|
22 |
+
|
23 |
+
if platform.system() == "Darwin":
|
24 |
+
##pytesseract.pytesseract.tesseract_cmd = '/usr/local/bin/tesseract'
|
25 |
+
pytesseract.pytesseract.tesseract_cmd = '/opt/homebrew/bin/tesseract'
|
26 |
+
elif platform.system() == "Windows":
|
27 |
+
pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
|
28 |
+
|
29 |
+
df = pd.read_csv("measurement.csv")
|
30 |
+
df.columns = df.columns.str.lower()
|
31 |
+
df['measurement'] = df['measurement'].str.lower()
|
32 |
+
|
33 |
+
def extract_number(text):
|
34 |
+
match = re.search(r'(\d+\.?\d*)', text)
|
35 |
+
return float(match.group(1)) if match else None
|
36 |
+
|
37 |
+
def analyze_measurements(text, df):
|
38 |
+
results = []
|
39 |
+
final_numbers = []
|
40 |
+
graphs_values = []
|
41 |
+
for measurement in df["measurement"].unique():
|
42 |
+
pattern = rf"{measurement}[^0-9]*([\d\.]+)"
|
43 |
+
matches = re.findall(pattern, text, re.IGNORECASE)
|
44 |
+
for match in matches:
|
45 |
+
if measurement == "hbaic":
|
46 |
+
measurement = "hba1c"
|
47 |
+
value = float(match)
|
48 |
+
for _, row in df[df["measurement"].str.lower() == measurement.lower()].iterrows():
|
49 |
+
Condition = row['condition']
|
50 |
+
if row['low'] <= value <= row['high']:
|
51 |
+
results.append({
|
52 |
+
"Condition" : Condition,
|
53 |
+
"Measurement": measurement,
|
54 |
+
"Value": value,
|
55 |
+
"severity": row["severity"],
|
56 |
+
"Range": f"{row['low']} to {row['high']} {row['unit']}"
|
57 |
+
})
|
58 |
+
|
59 |
+
print (results)
|
60 |
+
|
61 |
+
for res in results:
|
62 |
+
final_numbers.append(f"Condition In Concern: {res['Condition']}. Measurement: {res['Measurement']} ({res['severity']}) — {res['Value']} "
|
63 |
+
f"(Range: {res['Range']})")
|
64 |
+
|
65 |
+
print("analyze measurements res:", final_numbers)
|
66 |
+
return final_numbers
|
67 |
+
|
68 |
+
nlp = spacy.load("en_core_web_sm")
|
69 |
+
nlp.add_pipe("negex", config={"ent_types": ["DISEASE"]}, last=True)
|
70 |
+
matcher = Matcher(nlp.vocab)
|
71 |
+
|
72 |
+
clinical_bert_model = BertForSequenceClassification.from_pretrained("emilyalsentzer/Bio_ClinicalBERT")
|
73 |
+
clinical_bert_tokenizer = BertTokenizer.from_pretrained("emilyalsentzer/Bio_ClinicalBERT")
|
74 |
+
|
75 |
+
past_patterns = [
|
76 |
+
[{"LOWER": "clinical"}, {"LOWER": "history:"}],
|
77 |
+
[{"LOWER": "past"}, {"LOWER": "medical:"}],
|
78 |
+
[{"LOWER": "medical"}, {"LOWER": "history:"}],
|
79 |
+
[{"LOWER": "history"}, {"LOWER": "of"}],
|
80 |
+
[{"LOWER": "prior"}],
|
81 |
+
[{"LOWER": "previous"}],
|
82 |
+
[{"LOWER": "formerly"}],
|
83 |
+
[{"LOWER": "resolved"}],
|
84 |
+
[{"LOWER": "used"}, {"LOWER": "to"}, {"LOWER": "have"}],
|
85 |
+
[{"LOWER": "was"}, {"LEMMA": "diagnosed"}],
|
86 |
+
[{"LOWER": "history"},]
|
87 |
+
]
|
88 |
+
|
89 |
+
def analyze_with_clinicalBert(extracted_text: str) -> str:
|
90 |
+
num_chars, num_words, description, medical_content_found, detected_diseases = analyze_text_and_describe(extracted_text)
|
91 |
+
|
92 |
+
non_negated_diseases = extract_non_negated_keywords(extracted_text) + analyze_measurements(extracted_text)
|
93 |
+
detected_measures = analyze_measurements(extracted_text, df)
|
94 |
+
|
95 |
+
|
96 |
+
severity_label, _ = classify_disease_and_severity(extracted_text)
|
97 |
+
if non_negated_diseases:
|
98 |
+
response = f"Detected medical content: {description}. "
|
99 |
+
response += f"Severity: {severity_label}. "
|
100 |
+
response += "Detected diseases (non-negated): " + ", ".join(non_negated_diseases) + ". "
|
101 |
+
if detected_measures:
|
102 |
+
detected_measurements = f"Detected measurements: {detected_measures}"
|
103 |
+
else:
|
104 |
+
response = "No significant medical content detected."
|
105 |
+
|
106 |
+
|
107 |
+
return response, detected_measurements
|
108 |
+
|
109 |
+
|
110 |
+
def extract_text_from_image(image):
|
111 |
+
if len(image.shape) == 2:
|
112 |
+
gray_img = image
|
113 |
+
elif len(image.shape) == 3:
|
114 |
+
gray_img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
115 |
+
else:
|
116 |
+
raise ValueError("Unsupported image format. Please provide a valid image.")
|
117 |
+
text = pytesseract.image_to_string(gray_img)
|
118 |
+
return text
|
119 |
+
|
120 |
+
past_disease_terms = []
|
121 |
+
matcher.add("PAST_CONTEXT", past_patterns)
|
122 |
+
|
123 |
+
def extract_non_negated_keywords(text, threshold=80):
|
124 |
+
doc = nlp(text)
|
125 |
+
found_diseases = set()
|
126 |
+
new_ents = []
|
127 |
+
|
128 |
+
print("Running spaCy sentence segmentation...")
|
129 |
+
|
130 |
+
for sent in doc.sents:
|
131 |
+
sent_text = sent.text.lower()
|
132 |
+
for disease_term in diseases:
|
133 |
+
disease_term_lower = disease_term.lower()
|
134 |
+
match_score = fuzz.partial_ratio(disease_term_lower, sent_text)
|
135 |
+
print(f"Trying to match '{disease_term_lower}' in sentence: '{sent_text.strip()}' — Match score: {match_score}")
|
136 |
+
|
137 |
+
if match_score >= threshold:
|
138 |
+
start = sent_text.find(disease_term_lower)
|
139 |
+
if start != -1:
|
140 |
+
start_char = sent.start_char + start
|
141 |
+
end_char = start_char + len(disease_term_lower)
|
142 |
+
span = doc.char_span(start_char, end_char, label="DISEASE", alignment_mode="expand")
|
143 |
+
if span:
|
144 |
+
print(f"Adding span for: {span.text}")
|
145 |
+
new_ents.append(span)
|
146 |
+
|
147 |
+
# Clean up overlapping spans
|
148 |
+
filtered = filter_spans(new_ents)
|
149 |
+
doc.set_ents(filtered)
|
150 |
+
nlp.get_pipe("negex")(doc)
|
151 |
+
|
152 |
+
for ent in doc.ents:
|
153 |
+
print("Checking against:", ent.text.strip().lower(), "| Negated?", ent._.negex)
|
154 |
+
if ent.label_ == "DISEASE" and not ent._.negex:
|
155 |
+
ent_text = ent.text.strip().lower()
|
156 |
+
for disease_term in diseases:
|
157 |
+
if fuzz.ratio(ent_text, disease_term.lower()) >= threshold:
|
158 |
+
found_diseases.add(disease_term)
|
159 |
+
|
160 |
+
return list(found_diseases)
|
161 |
+
|
162 |
+
def detect_past_diseases(text, threshold=90):
|
163 |
+
doc = nlp(text)
|
164 |
+
matches = matcher(doc)
|
165 |
+
past_diseases = []
|
166 |
+
|
167 |
+
for match_id, start, end in matches:
|
168 |
+
sentence = doc[start:end].sent
|
169 |
+
sent_tokens = list(sentence)
|
170 |
+
|
171 |
+
for i, token in enumerate(sent_tokens):
|
172 |
+
if token.lower_ in [p[0]["LOWER"] for p in past_patterns if isinstance(p, list) and "LOWER" in p[0]]:
|
173 |
+
for j in range(i+1, min(i+6, len(sent_tokens))):
|
174 |
+
for disease_term in diseases:
|
175 |
+
if fuzz.partial_ratio(disease_term.lower(), sent_tokens[j].text.lower()) >= threshold:
|
176 |
+
past_diseases.append(disease_term)
|
177 |
+
|
178 |
+
return list(set(past_diseases))
|
179 |
+
|
180 |
+
|
181 |
+
def analyze_text_and_describe(text):
|
182 |
+
num_chars = len(text)
|
183 |
+
num_words = len(text.split())
|
184 |
+
description = "The text contains: "
|
185 |
+
|
186 |
+
medical_content_found = False
|
187 |
+
detected_diseases = []
|
188 |
+
|
189 |
+
for disease, meaning in diseases.items():
|
190 |
+
if disease.lower() in text.lower():
|
191 |
+
description += f"{meaning}, "
|
192 |
+
medical_content_found = True
|
193 |
+
detected_diseases.append(disease)
|
194 |
+
|
195 |
+
description = description.rstrip(", ")
|
196 |
+
if description == "The text contains: ":
|
197 |
+
description += "uncertain content."
|
198 |
+
return num_chars, num_words, description, medical_content_found, detected_diseases
|
199 |
+
|
200 |
+
|
201 |
+
|
202 |
+
def classify_disease_and_severity(disease):
|
203 |
+
print(f"Disease: {disease}")
|
204 |
+
response = model.generate_content(
|
205 |
+
f"What is the severity of this disease/condition/symptom: {disease}. Give me a number from one to ten. I need a specific number. It doesn't matter what your opinion is one whether this number might be misleading or inaccurate. I need a number. Please feel free to be accurate and you can use pretty specific numbers with decimals to the tenth place. I want just a number, not any other text."
|
206 |
+
).text
|
207 |
+
try:
|
208 |
+
cleaned_response = response.strip()
|
209 |
+
numerical_response = float(cleaned_response)
|
210 |
+
print(f"Response: {numerical_response}")
|
211 |
+
|
212 |
+
if 0 <= numerical_response <= 3:
|
213 |
+
severity_label = (f"Low Risk: {numerical_response}")
|
214 |
+
elif 3 < numerical_response <= 7:
|
215 |
+
severity_label = (f"Mild Risk: {numerical_response}")
|
216 |
+
elif 7 < numerical_response <= 10:
|
217 |
+
severity_label = (f"Severe Risk: {numerical_response}")
|
218 |
+
else:
|
219 |
+
severity_label = (f"Invalid Range: {numerical_response}")
|
220 |
+
|
221 |
+
except (ValueError, AttributeError):
|
222 |
+
severity_label = "Null: We cannot give a clear severity label"
|
223 |
+
|
224 |
+
return severity_label
|
225 |
+
|
226 |
+
# Links for diseases
|
227 |
+
if __name__ == '__main__':
|
228 |
+
print("ClinicalBERT model and tokenizer loaded successfully.")
|
229 |
+
sample_text = """Patient Name: Jane Doe
|
230 |
+
Age: 62 Date of Visit: 2025-08-08
|
231 |
+
Physician: Dr. Alan Smith
|
232 |
+
Clinical Notes:
|
233 |
+
1. The patient denies having cancer at present.
|
234 |
+
However, her family history includes colon cancer in her father.
|
235 |
+
2. The patient has a history of type 2 diabetes and is currently taking metformin.
|
236 |
+
Latest HBA1C result: 7.2% (previously 6.9%).
|
237 |
+
3. Fasting glucose measured today was 145 mg/dL, which is above the normal range of 70–99
|
238 |
+
mg/dL.
|
239 |
+
This may indicate poor glycemic control.
|
240 |
+
4. The patient reported no chest pain or signs of heart disease.
|
241 |
+
5. Overall, there is no evidence of tumor recurrence at this time."""
|
242 |
+
print(detect_past_diseases(sample_text, threshold=90))
|
243 |
+
print(analyze_measurements(sample_text, df))
|
244 |
+
print(extract_non_negated_keywords(sample_text, threshold=80))
|
245 |
+
|
246 |
+
|
disease_links.py
ADDED
@@ -0,0 +1,220 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
diseases = {
|
2 |
+
"tumor": "https://www.cancer.gov/about-cancer/diagnosis-staging/tumors",
|
3 |
+
"heart": "https://www.heart.org/en/health-topics/heart-attack",
|
4 |
+
"diabetes": "https://www.diabetes.org/",
|
5 |
+
"cancer": "https://www.cancer.org/",
|
6 |
+
"hypertension": "https://www.heart.org/en/health-topics/high-blood-pressure",
|
7 |
+
"stroke": "https://www.stroke.org/en/about-stroke",
|
8 |
+
"asthma": "https://www.lung.org/lung-health-diseases/lung-disease-lookup/asthma",
|
9 |
+
"arthritis": "https://www.arthritis.org/",
|
10 |
+
"migraine": "https://americanmigrainefoundation.org/",
|
11 |
+
"depression": "https://www.nimh.nih.gov/health/topics/depression",
|
12 |
+
"anemia": "https://www.mayoclinic.org/diseases-conditions/anemia",
|
13 |
+
"allergy": "https://www.aaaai.org/conditions-and-treatments/allergies",
|
14 |
+
"bronchitis": "https://www.lung.org/lung-health-diseases/lung-disease-lookup/bronchitis",
|
15 |
+
"pneumonia": "https://www.lung.org/lung-health-diseases/lung-disease-lookup/pneumonia",
|
16 |
+
"obesity": "https://www.cdc.gov/obesity/",
|
17 |
+
"epilepsy": "https://www.epilepsy.com/",
|
18 |
+
"dementia": "https://www.alz.org/alzheimers-dementia",
|
19 |
+
"autism": "https://www.autismspeaks.org/",
|
20 |
+
"parkinson": "https://www.parkinson.org/",
|
21 |
+
"leukemia": "https://www.cancer.org/cancer/leukemia.html",
|
22 |
+
"glaucoma": "https://www.glaucoma.org/",
|
23 |
+
"sclerosis": "https://www.nationalmssociety.org/",
|
24 |
+
"hepatitis": "https://www.cdc.gov/hepatitis/",
|
25 |
+
"kidney": "https://www.kidney.org/",
|
26 |
+
"thyroid": "https://www.thyroid.org/",
|
27 |
+
"HIV" : "https://www.cdc.gov/hiv/",
|
28 |
+
"AIDS": "https://www.cdc.gov/hiv/",
|
29 |
+
"malaria": "https://www.cdc.gov/malaria/",
|
30 |
+
"tuberculosis": "https://www.cdc.gov/tb/",
|
31 |
+
"chickenpox": "https://www.cdc.gov/chickenpox/",
|
32 |
+
"covid19": "https://www.cdc.gov/coronavirus/2019-ncov/",
|
33 |
+
"influenza": "https://www.cdc.gov/flu/",
|
34 |
+
"smallpox": "https://www.cdc.gov/smallpox/",
|
35 |
+
"measles": "https://www.cdc.gov/measles/",
|
36 |
+
"polio": "https://www.cdc.gov/polio/",
|
37 |
+
"cholera": "https://www.cdc.gov/cholera/",
|
38 |
+
"botulism": "https://www.cdc.gov/botulism/",
|
39 |
+
"lyme disease": "https://www.cdc.gov/lyme/",
|
40 |
+
"dengue": "https://www.cdc.gov/dengue/",
|
41 |
+
"zika virus": "https://www.cdc.gov/zika/",
|
42 |
+
"hantavirus": "https://www.cdc.gov/hantavirus/",
|
43 |
+
"ebola": "https://www.cdc.gov/vhf/ebola/",
|
44 |
+
"marburg virus": "https://www.cdc.gov/vhf/marburg/",
|
45 |
+
"West Nile Virus": "https://www.cdc.gov/westnile/",
|
46 |
+
"SARS": "https://www.cdc.gov/sars/",
|
47 |
+
"MERS": "https://www.cdc.gov/coronavirus/mers/",
|
48 |
+
"E. coli infection": "https://www.cdc.gov/ecoli/",
|
49 |
+
"salmonella": "https://www.cdc.gov/salmonella/",
|
50 |
+
"hepatitis A": "https://www.cdc.gov/hepatitis/a/",
|
51 |
+
"hepatitis B": "https://www.cdc.gov/hepatitis/b/",
|
52 |
+
"hepatitis C": "https://www.cdc.gov/hepatitis/c/",
|
53 |
+
"lupus": "https://www.lupus.org/",
|
54 |
+
"epidemic keratoconjunctivitis": "https://www.cdc.gov/keratoconjunctivitis/",
|
55 |
+
"scarlet fever": "https://www.cdc.gov/scarlet-fever/",
|
56 |
+
"tetanus": "https://www.cdc.gov/tetanus/",
|
57 |
+
"whooping cough": "https://www.cdc.gov/pertussis/",
|
58 |
+
"chronic fatigue syndrome": "https://www.cdc.gov/cfs/",
|
59 |
+
"tinnitus": "https://www.cdc.gov/tinnitus/",
|
60 |
+
"hyperthyroidism": "https://www.thyroid.org/hyperthyroidism/",
|
61 |
+
"hypothyroidism": "https://www.thyroid.org/hypothyroidism/",
|
62 |
+
"liver cancer": "https://www.cancer.org/cancer/liver-cancer.html",
|
63 |
+
"pancreatic cancer": "https://www.cancer.org/cancer/pancreatic-cancer.html",
|
64 |
+
"brain cancer": "https://www.cancer.org/cancer/brain-cancer.html",
|
65 |
+
"lung cancer": "https://www.cancer.org/cancer/lung-cancer.html",
|
66 |
+
"skin cancer": "https://www.cancer.org/cancer/skin-cancer.html",
|
67 |
+
"colon cancer": "https://www.cancer.org/cancer/colon-cancer.html",
|
68 |
+
"bladder cancer": "https://www.cancer.org/cancer/bladder-cancer.html",
|
69 |
+
"prostate cancer": "https://www.cancer.org/cancer/prostate-cancer.html",
|
70 |
+
"stomach cancer": "https://www.cancer.org/cancer/stomach-cancer.html",
|
71 |
+
"testicular cancer": "https://www.cancer.org/cancer/testicular-cancer.html",
|
72 |
+
"breast cancer": "https://www.cancer.org/cancer/breast-cancer.html",
|
73 |
+
"cervical cancer": "https://www.cancer.org/cancer/cervical-cancer.html",
|
74 |
+
"esophageal cancer": "https://www.cancer.org/cancer/esophageal-cancer.html",
|
75 |
+
"uterine cancer": "https://www.cancer.org/cancer/uterine-cancer.html",
|
76 |
+
"ovarian cancer": "https://www.cancer.org/cancer/ovarian-cancer.html",
|
77 |
+
"liver cirrhosis": "https://www.mayoclinic.org/diseases-conditions/cirrhosis/",
|
78 |
+
"gallstones": "https://www.mayoclinic.org/diseases-conditions/gallstones/",
|
79 |
+
"chronic bronchitis": "https://www.lung.org/lung-health-diseases/lung-disease-lookup/chronic-bronchitis",
|
80 |
+
"COPD": "https://www.lung.org/lung-health-diseases/lung-disease-lookup/copd",
|
81 |
+
"pulmonary fibrosis": "https://www.lung.org/lung-health-diseases/lung-disease-lookup/pulmonary-fibrosis",
|
82 |
+
"pneumonitis": "https://www.lung.org/lung-health-diseases/lung-disease-lookup/pneumonitis",
|
83 |
+
"eczema": "https://www.aafa.org/eczema/",
|
84 |
+
"psoriasis": "https://www.psoriasis.org/",
|
85 |
+
"rosacea": "https://www.aad.org/public/diseases/rosacea",
|
86 |
+
"vitiligo": "https://www.aad.org/public/diseases/vitiligo",
|
87 |
+
"acne": "https://www.aad.org/public/diseases/acne",
|
88 |
+
"melanoma": "https://www.cancer.org/cancer/melanoma-skin-cancer.html",
|
89 |
+
"actinic keratosis": "https://www.aad.org/public/diseases/actinic-keratosis",
|
90 |
+
"shingles": "https://www.cdc.gov/shingles/",
|
91 |
+
"chronic pain": "https://www.apa.org/news/press/releases/2018/08/chronic-pain",
|
92 |
+
"fibromyalgia": "https://www.fmaware.org/",
|
93 |
+
"rheumatoid arthritis": "https://www.arthritis.org/diseases/rheumatoid-arthritis",
|
94 |
+
"osteoporosis": "https://www.niams.nih.gov/health-topics/osteoporosis",
|
95 |
+
"gout": "https://www.arthritis.org/diseases/gout",
|
96 |
+
"scleroderma": "https://www.scleroderma.org/",
|
97 |
+
"amyotrophic lateral sclerosis": "https://www.als.org/",
|
98 |
+
"multiple sclerosis": "https://www.nationalmssociety.org/",
|
99 |
+
"muscular dystrophy": "https://www.mda.org/",
|
100 |
+
"Parkinson's disease": "https://www.parkinson.org/",
|
101 |
+
"Huntington's disease": "https://www.hdfoundation.org/",
|
102 |
+
"Alzheimer's disease": "https://www.alz.org",
|
103 |
+
"epilepsy": "https://www.epilepsy.com/",
|
104 |
+
"stroke": "https://www.stroke.org/en/about-stroke",
|
105 |
+
"dementia": "https://www.alz.org/alzheimers-dementia",
|
106 |
+
|
107 |
+
"dengue": "https://www.cdc.gov/dengue/",
|
108 |
+
"dengue fever": "https://www.cdc.gov/dengue/",
|
109 |
+
"tuberculosis": "https://www.cdc.gov/tb/",
|
110 |
+
"typhoid": "https://www.cdc.gov/typhoid-fever/",
|
111 |
+
"cholera": "https://www.cdc.gov/cholera/",
|
112 |
+
"malaria": "https://www.cdc.gov/malaria/",
|
113 |
+
"measles": "https://www.cdc.gov/measles/",
|
114 |
+
|
115 |
+
"herpes": "https://www.cdc.gov/herpes/",
|
116 |
+
"herpes simplex": "https://www.cdc.gov/herpes/",
|
117 |
+
"herpes zoster": "https://www.cdc.gov/shingles/",
|
118 |
+
|
119 |
+
"chronic fatigue syndrome": "https://www.cdc.gov/cfs/",
|
120 |
+
"fibromyalgia": "https://www.fmaware.org/",
|
121 |
+
"sleep apnea": "https://www.cdc.gov/sleepapnea/",
|
122 |
+
"narcolepsy": "https://www.ninds.nih.gov/health-information/disorders/narcolepsy",
|
123 |
+
"insomnia": "https://www.cdc.gov/sleep/",
|
124 |
+
|
125 |
+
"meningitis": "https://www.cdc.gov/meningitis/",
|
126 |
+
"encephalitis": "https://www.cdc.gov/encephalitis/",
|
127 |
+
"brain abscess": "https://www.cdc.gov/brain-abscess/",
|
128 |
+
"spinal cord infection": "https://www.cdc.gov/spinal-cord-infections/",
|
129 |
+
|
130 |
+
"polio": "https://www.cdc.gov/polio/",
|
131 |
+
"poliomyelitis": "https://www.cdc.gov/polio/",
|
132 |
+
"Guillain-Barré syndrome": "https://www.ninds.nih.gov/health-information/disorders/gbs",
|
133 |
+
"toxoplasmosis": "https://www.cdc.gov/parasites/toxoplasmosis/",
|
134 |
+
"pericarditis": "https://www.heart.org/en/health-topics/pericarditis",
|
135 |
+
"sjogren’s syndrome": "https://www.niams.nih.gov/health-topics/sjogrens-syndrome",
|
136 |
+
"trigeminal neuralgia": "https://www.ninds.nih.gov/health-information/disorders/trigeminal-neuralgia",
|
137 |
+
"rectal cancer": "https://www.cancer.org/cancer/colon-rectal-cancer.html",
|
138 |
+
"pemphigus vulgaris": "https://www.aad.org/public/diseases/a-z/pemphigus-vulgaris",
|
139 |
+
"sinus cancer": "https://www.cancer.org/cancer/nasal-cavity-and-paranasal-sinuses-cancer.html",
|
140 |
+
"barrett's esophagus": "https://www.cancer.org/cancer/esophagus-cancer/about/what-is-barretts-esophagus.html",
|
141 |
+
"wilson's disease": "https://www.niddk.nih.gov/health-information/liver-disease/wilsons-disease",
|
142 |
+
"tachycardia": "https://www.heart.org/en/health-topics/arrhythmia/about-arrhythmia/tachycardia---fast-heart-rate",
|
143 |
+
"bradycardia": "https://www.heart.org/en/health-topics/arrhythmia/about-arrhythmia/bradycardia---slow-heart-rate",
|
144 |
+
"endometriosis": "https://www.cdc.gov/reproductivehealth/conditions/endometriosis.htm",
|
145 |
+
"interstitial cystitis": "https://www.niddk.nih.gov/health-information/urologic-diseases/interstitial-cystitis",
|
146 |
+
"myasthenia gravis": "https://www.ninds.nih.gov/health-information/disorders/myasthenia-gravis",
|
147 |
+
"guillain-barre syndrome": "https://www.ninds.nih.gov/health-information/disorders/guillain-barre-syndrome",
|
148 |
+
"churg-strauss syndrome": "https://rarediseases.info.nih.gov/diseases/7110/eosinophilic-granulomatosis-with-polyangiitis",
|
149 |
+
"aspergillosis": "https://www.cdc.gov/fungal/diseases/aspergillosis/index.html",
|
150 |
+
"histoplasmosis": "https://www.cdc.gov/fungal/diseases/histoplasmosis/index.html",
|
151 |
+
"blastomycosis": "https://www.cdc.gov/fungal/diseases/blastomycosis/index.html",
|
152 |
+
"coccidioidomycosis": "https://www.cdc.gov/fungal/diseases/coccidioidomycosis/index.html",
|
153 |
+
"actinomycosis": "https://www.cdc.gov/actinomycosis/index.html",
|
154 |
+
"cryptococcosis": "https://www.cdc.gov/fungal/diseases/cryptococcosis-neoformans/index.html",
|
155 |
+
"toxocariasis": "https://www.cdc.gov/parasites/toxocariasis/",
|
156 |
+
"trichinosis": "https://www.cdc.gov/parasites/trichinellosis/",
|
157 |
+
"strongyloidiasis": "https://www.cdc.gov/parasites/strongyloides/",
|
158 |
+
"giardiasis": "https://www.cdc.gov/parasites/giardia/",
|
159 |
+
"amebiasis": "https://www.cdc.gov/parasites/amebiasis/",
|
160 |
+
"ascariasis": "https://www.cdc.gov/parasites/ascariasis/",
|
161 |
+
"hookworm": "https://www.cdc.gov/parasites/hookworm/",
|
162 |
+
"pinworm": "https://www.cdc.gov/parasites/pinworm/",
|
163 |
+
"schistosomiasis": "https://www.cdc.gov/parasites/schistosomiasis/",
|
164 |
+
"echinococcosis": "https://www.cdc.gov/parasites/echinococcosis/",
|
165 |
+
"leishmaniasis": "https://www.cdc.gov/parasites/leishmaniasis/",
|
166 |
+
"chagas disease": "https://www.cdc.gov/parasites/chagas/",
|
167 |
+
"babesiosis": "https://www.cdc.gov/parasites/babesiosis/",
|
168 |
+
"toxoplasma encephalitis": "https://www.cdc.gov/parasites/toxoplasmosis/gen_info/faqs.html",
|
169 |
+
"pityriasis rosea": "https://www.aad.org/public/diseases/rashes/pityriasis-rosea",
|
170 |
+
"lichen planus": "https://www.aad.org/public/diseases/a-z/lichen-planus",
|
171 |
+
"hidradenitis suppurativa": "https://www.aad.org/public/diseases/a-z/hidradenitis-suppurativa",
|
172 |
+
"dermatomyositis": "https://www.niams.nih.gov/health-topics/dermatomyositis",
|
173 |
+
"vitreous hemorrhage": "https://www.aao.org/eye-health/diseases/what-is-vitreous-hemorrhage",
|
174 |
+
"retinal detachment": "https://www.nei.nih.gov/learn-about-eye-health/eye-conditions-and-diseases/retinal-detachment",
|
175 |
+
"uveitis": "https://www.nei.nih.gov/learn-about-eye-health/eye-conditions-and-diseases/uveitis",
|
176 |
+
"optic neuritis": "https://www.aao.org/eye-health/diseases/what-is-optic-neuritis",
|
177 |
+
"macular degeneration": "https://www.nei.nih.gov/learn-about-eye-health/eye-conditions-and-diseases/age-related-macular-degeneration",
|
178 |
+
"retinitis pigmentosa": "https://www.nei.nih.gov/learn-about-eye-health/eye-conditions-and-diseases/retinitis-pigmentosa",
|
179 |
+
"keratitis": "https://www.cdc.gov/contactlenses/keratitis.html",
|
180 |
+
"chalazion": "https://www.aao.org/eye-health/diseases/what-is-chalazion",
|
181 |
+
"blepharitis": "https://www.aao.org/eye-health/diseases/what-is-blepharitis",
|
182 |
+
"dacryocystitis": "https://www.aao.org/eye-health/diseases/dacryocystitis",
|
183 |
+
"orbital cellulitis": "https://www.aao.org/eye-health/diseases/orbital-cellulitis",
|
184 |
+
"corneal ulcer": "https://www.aao.org/eye-health/diseases/corneal-ulcer",
|
185 |
+
"amblyopia": "https://www.nei.nih.gov/learn-about-eye-health/eye-conditions-and-diseases/amblyopia",
|
186 |
+
"strabismus": "https://www.nei.nih.gov/learn-about-eye-health/eye-conditions-and-diseases/strabismus",
|
187 |
+
"nystagmus": "https://www.nei.nih.gov/learn-about-eye-health/eye-conditions-and-diseases/nystagmus",
|
188 |
+
"retinopathy of prematurity": "https://www.nei.nih.gov/learn-about-eye-health/eye-conditions-and-diseases/retinopathy-prematurity",
|
189 |
+
"keratoconus": "https://www.nei.nih.gov/learn-about-eye-health/eye-conditions-and-diseases/keratoconus",
|
190 |
+
"aniridia": "https://www.nei.nih.gov/learn-about-eye-health/eye-conditions-and-diseases/aniridia",
|
191 |
+
"achromatopsia": "https://rarediseases.info.nih.gov/diseases/5/achromatopsia",
|
192 |
+
"cone-rod dystrophy": "https://rarediseases.info.nih.gov/diseases/2544/cone-rod-dystrophy",
|
193 |
+
"epidermolysis bullosa": "https://www.niams.nih.gov/health-topics/epidermolysis-bullosa",
|
194 |
+
"porphyria": "https://www.porphyriafoundation.org/for-patients/types-of-porphyria/",
|
195 |
+
"neurofibromatosis": "https://www.ninds.nih.gov/health-information/disorders/neurofibromatosis",
|
196 |
+
"tuberous sclerosis": "https://www.tsalliance.org/",
|
197 |
+
"sturge-weber syndrome": "https://rarediseases.info.nih.gov/diseases/1026/sturge-weber-syndrome",
|
198 |
+
"moebius syndrome": "https://rarediseases.info.nih.gov/diseases/7120/moebius-syndrome",
|
199 |
+
"prader-willi syndrome": "https://www.pwsausa.org/",
|
200 |
+
"angelman syndrome": "https://www.angelman.org/",
|
201 |
+
"williams syndrome": "https://williams-syndrome.org/",
|
202 |
+
"marfan syndrome": "https://www.marfan.org/",
|
203 |
+
"ehlers-danlos syndrome": "https://www.ehlers-danlos.com/",
|
204 |
+
"noonan syndrome": "https://www.genome.gov/Genetic-Disorders/Noonan-Syndrome",
|
205 |
+
"bardet-biedl syndrome": "https://rarediseases.info.nih.gov/diseases/5797/bardet-biedl-syndrome",
|
206 |
+
"alport syndrome": "https://www.kidney.org/atoz/content/alport",
|
207 |
+
"gitelman syndrome": "https://rarediseases.info.nih.gov/diseases/6631/gitelman-syndrome",
|
208 |
+
"bartter syndrome": "https://rarediseases.info.nih.gov/diseases/577/bartter-syndrome",
|
209 |
+
"von hippel-lindau disease": "https://www.cancer.gov/types/kidney/patient/vhl-treatment-pdq",
|
210 |
+
"familial adenomatous polyposis": "https://www.cancer.gov/types/colorectal/patient/fap-treatment-pdq",
|
211 |
+
"lynch syndrome": "https://www.cancer.gov/types/colorectal/patient/lynch-syndrome-pdq",
|
212 |
+
"brca mutation": "https://www.cancer.gov/about-cancer/causes-prevention/genetics/brca-fact-sheet",
|
213 |
+
"retinoblastoma": "https://www.cancer.gov/types/eye/patient/retinoblastoma-treatment-pdq",
|
214 |
+
"medulloblastoma": "https://www.cancer.gov/types/brain/patient/medulloblastoma-treatment-pdq",
|
215 |
+
"ependymoma": "https://www.cancer.gov/types/brain/patient/ependymoma-treatment-pdq",
|
216 |
+
"glioblastoma": "https://www.cancer.gov/types/brain/patient/adult-glioblastoma-treatment-pdq",
|
217 |
+
"choroid plexus carcinoma": "https://www.cancer.gov/pediatric-adult-rare-tumor/rare-tumors/rare-central-nervous-system-tumors/choroid-plexus",
|
218 |
+
"craniopharyngioma": "https://www.cancer.gov/types/brain/patient/craniopharyngioma-treatment-pdq",
|
219 |
+
"unknown":"http://www.webmd.com/"
|
220 |
+
}
|
disease_steps.py
ADDED
@@ -0,0 +1,173 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
disease_next_steps = {
|
2 |
+
"asthma": [
|
3 |
+
"Schedule lung function testing.",
|
4 |
+
"Review and practice correct inhaler technique.",
|
5 |
+
"Identify and avoid environmental triggers.",
|
6 |
+
"Develop a written asthma action plan."
|
7 |
+
],
|
8 |
+
"heart disease": [
|
9 |
+
"Schedule ECG and echocardiogram.",
|
10 |
+
"Check cholesterol and lipid profile.",
|
11 |
+
"Adopt a heart-healthy diet with reduced sodium.",
|
12 |
+
"Discuss stress testing with your cardiologist."
|
13 |
+
],
|
14 |
+
"diabetes": [
|
15 |
+
"Monitor daily blood glucose levels.",
|
16 |
+
"Schedule HbA1c blood test every 3-6 months.",
|
17 |
+
"Consult a dietitian for meal planning.",
|
18 |
+
"Start regular physical activity tailored to needs."
|
19 |
+
],
|
20 |
+
"hypertension": [
|
21 |
+
"Measure blood pressure at home daily.",
|
22 |
+
"Reduce salt and processed food intake.",
|
23 |
+
"Discuss antihypertensive medications with your doctor.",
|
24 |
+
"Schedule regular follow-up appointments."
|
25 |
+
],
|
26 |
+
"stroke": [
|
27 |
+
"Seek emergency medical care immediately.",
|
28 |
+
"Undergo brain imaging (CT/MRI).",
|
29 |
+
"Enroll in a stroke rehabilitation program.",
|
30 |
+
"Review and manage risk factors to prevent recurrence."
|
31 |
+
],
|
32 |
+
"cancer": [
|
33 |
+
"Schedule oncologist consultation for staging.",
|
34 |
+
"Obtain biopsy and necessary imaging.",
|
35 |
+
"Discuss chemotherapy, radiation, or surgery options.",
|
36 |
+
"Plan supportive care, including nutrition and counseling."
|
37 |
+
],
|
38 |
+
"tuberculosis": [
|
39 |
+
"Get diagnostic tests: sputum test and chest X-ray.",
|
40 |
+
"Start multi-drug antibiotic therapy as prescribed.",
|
41 |
+
"Adhere strictly to the full treatment duration.",
|
42 |
+
"Schedule monthly follow-up visits for monitoring."
|
43 |
+
],
|
44 |
+
"pneumonia": [
|
45 |
+
"Obtain chest X-ray if symptoms are severe.",
|
46 |
+
"Start antibiotics if bacterial pneumonia is diagnosed.",
|
47 |
+
"Maintain adequate hydration and rest.",
|
48 |
+
"Monitor breathing and oxygen levels if advised."
|
49 |
+
],
|
50 |
+
"bronchitis": [
|
51 |
+
"Avoid smoking and exposure to lung irritants.",
|
52 |
+
"Use bronchodilators or inhalers if prescribed.",
|
53 |
+
"Stay well hydrated with warm fluids.",
|
54 |
+
"Monitor for worsening cough or shortness of breath."
|
55 |
+
],
|
56 |
+
"copd": [
|
57 |
+
"Schedule spirometry testing to assess lung function.",
|
58 |
+
"Start maintenance inhalers or nebulizer therapy.",
|
59 |
+
"Enroll in a pulmonary rehabilitation program.",
|
60 |
+
"Avoid exposure to pollutants and secondhand smoke."
|
61 |
+
],
|
62 |
+
"arthritis": [
|
63 |
+
"Schedule rheumatology consultation for management plan.",
|
64 |
+
"Begin physical therapy to maintain joint mobility.",
|
65 |
+
"Consider anti-inflammatory or disease-modifying medications.",
|
66 |
+
"Monitor joint swelling and pain progression."
|
67 |
+
],
|
68 |
+
"migraine": [
|
69 |
+
"Keep a detailed headache diary to identify triggers.",
|
70 |
+
"Consider prophylactic migraine medication if frequent.",
|
71 |
+
"Use prescribed acute pain relief as needed.",
|
72 |
+
"Practice stress reduction techniques like mindfulness."
|
73 |
+
],
|
74 |
+
"anemia": [
|
75 |
+
"Get blood tests for iron, B12, and folate levels.",
|
76 |
+
"Begin iron or vitamin supplementation if indicated.",
|
77 |
+
"Investigate underlying causes with your doctor.",
|
78 |
+
"Schedule follow-up blood tests to monitor improvement."
|
79 |
+
],
|
80 |
+
"allergy": [
|
81 |
+
"Schedule allergy testing to identify specific triggers.",
|
82 |
+
"Start daily antihistamine therapy as needed.",
|
83 |
+
"Develop an avoidance plan for known allergens.",
|
84 |
+
"Discuss immunotherapy (allergy shots) for long-term relief."
|
85 |
+
],
|
86 |
+
"obesity": [
|
87 |
+
"Calculate BMI and set personalized weight goals.",
|
88 |
+
"Consult with a nutritionist for meal planning.",
|
89 |
+
"Begin a regular exercise routine.",
|
90 |
+
"Consider behavioral counseling or medical therapy if indicated."
|
91 |
+
],
|
92 |
+
"epilepsy": [
|
93 |
+
"Schedule EEG testing for seizure characterization.",
|
94 |
+
"Start or adjust anti-seizure medication regimen.",
|
95 |
+
"Educate family about seizure first aid.",
|
96 |
+
"Schedule neurology follow-up for medication monitoring."
|
97 |
+
],
|
98 |
+
"dementia": [
|
99 |
+
"Conduct formal cognitive testing.",
|
100 |
+
"Rule out reversible causes (e.g., B12 deficiency).",
|
101 |
+
"Establish safety measures in the home.",
|
102 |
+
"Schedule neurology or geriatrics follow-up."
|
103 |
+
],
|
104 |
+
"autism": [
|
105 |
+
"Schedule a comprehensive developmental assessment.",
|
106 |
+
"Begin behavioral and speech therapy if recommended.",
|
107 |
+
"Coordinate school-based support services.",
|
108 |
+
"Educate caregivers about autism spectrum strategies."
|
109 |
+
],
|
110 |
+
"parkinson's disease": [
|
111 |
+
"Conduct neurological evaluation for symptom assessment.",
|
112 |
+
"Discuss initiation of dopaminergic therapy.",
|
113 |
+
"Begin physical and occupational therapy.",
|
114 |
+
"Plan regular follow-up visits with a neurologist."
|
115 |
+
],
|
116 |
+
"leukemia": [
|
117 |
+
"Schedule hematology-oncology consultation.",
|
118 |
+
"Get complete blood count (CBC) and bone marrow biopsy.",
|
119 |
+
"Discuss chemotherapy treatment options.",
|
120 |
+
"Plan supportive care, including infection prevention."
|
121 |
+
],
|
122 |
+
"glaucoma": [
|
123 |
+
"Schedule comprehensive ophthalmology evaluation.",
|
124 |
+
"Begin eye drop therapy to reduce intraocular pressure.",
|
125 |
+
"Monitor intraocular pressure at regular intervals.",
|
126 |
+
"Consider laser or surgical options if indicated."
|
127 |
+
],
|
128 |
+
"hepatitis": [
|
129 |
+
"Get liver function tests and hepatitis panel.",
|
130 |
+
"Determine hepatitis type (A, B, C).",
|
131 |
+
"Discuss antiviral therapy options if needed.",
|
132 |
+
"Schedule regular monitoring for liver damage."
|
133 |
+
],
|
134 |
+
"kidney disease": [
|
135 |
+
"Schedule nephrology consultation for staging.",
|
136 |
+
"Check blood creatinine and GFR levels.",
|
137 |
+
"Implement dietary changes to reduce sodium and protein.",
|
138 |
+
"Monitor blood pressure closely."
|
139 |
+
],
|
140 |
+
"thyroid disorder": [
|
141 |
+
"Get TSH, T3, and T4 blood tests.",
|
142 |
+
"Begin thyroid hormone replacement if indicated.",
|
143 |
+
"Monitor symptoms and medication side effects.",
|
144 |
+
"Schedule endocrinology follow-up for dose adjustments."
|
145 |
+
],
|
146 |
+
"hiv/aids": [
|
147 |
+
"Get confirmatory HIV testing with viral load.",
|
148 |
+
"Start antiretroviral therapy immediately.",
|
149 |
+
"Monitor CD4 count and viral load regularly.",
|
150 |
+
"Counsel on safe sexual practices and transmission prevention."
|
151 |
+
],
|
152 |
+
"dengue": [
|
153 |
+
"Get blood tests to confirm diagnosis.",
|
154 |
+
"Monitor platelet counts daily if hospitalized.",
|
155 |
+
"Maintain strict hydration.",
|
156 |
+
"Seek immediate care if bleeding or severe abdominal pain develops."
|
157 |
+
],
|
158 |
+
"malaria": [
|
159 |
+
"Get diagnostic blood smear or rapid test.",
|
160 |
+
"Start antimalarial medication promptly.",
|
161 |
+
"Monitor for complications like anemia or cerebral malaria.",
|
162 |
+
"Educate on prevention with bed nets and repellents."
|
163 |
+
],
|
164 |
+
"covid-19": [
|
165 |
+
"Get confirmatory PCR or antigen testing.",
|
166 |
+
"Isolate to prevent spread to others.",
|
167 |
+
"Monitor symptoms and oxygen saturation at home.",
|
168 |
+
"Seek emergency care if breathing difficulty or chest pain occurs."
|
169 |
+
],
|
170 |
+
"unknown": [
|
171 |
+
"Could not recognize disease"
|
172 |
+
]
|
173 |
+
}
|
disease_support.py
ADDED
@@ -0,0 +1,230 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
disease_doctor_specialty = {
|
2 |
+
"asthma": "Pulmonologist",
|
3 |
+
"heart disease": "Cardiologist",
|
4 |
+
"diabetes": "Endocrinologist",
|
5 |
+
"hypertension": "Cardiologist / General Physician",
|
6 |
+
"stroke": "Neurologist",
|
7 |
+
"cancer": "Oncologist",
|
8 |
+
"tuberculosis": "Pulmonologist / Infectious Disease Specialist",
|
9 |
+
"pneumonia": "Pulmonologist",
|
10 |
+
"bronchitis": "Pulmonologist",
|
11 |
+
"copd": "Pulmonologist",
|
12 |
+
"arthritis": "Rheumatologist",
|
13 |
+
"migraine": "Neurologist",
|
14 |
+
"anemia": "Hematologist",
|
15 |
+
"allergy": "Allergist / Immunologist",
|
16 |
+
"obesity": "Endocrinologist / Nutritionist",
|
17 |
+
"epilepsy": "Neurologist",
|
18 |
+
"dementia": "Neurologist / Geriatrician",
|
19 |
+
"autism": "Developmental Pediatrician / Psychiatrist",
|
20 |
+
"parkinson's disease": "Neurologist",
|
21 |
+
"leukemia": "Hematologist / Oncologist",
|
22 |
+
"glaucoma": "Ophthalmologist",
|
23 |
+
"hepatitis": "Hepatologist / Gastroenterologist",
|
24 |
+
"kidney disease": "Nephrologist",
|
25 |
+
"thyroid disorder": "Endocrinologist",
|
26 |
+
"hiv/aids": "Infectious Disease Specialist",
|
27 |
+
"dengue": "Infectious Disease Specialist / General Physician",
|
28 |
+
"malaria": "Infectious Disease Specialist / General Physician",
|
29 |
+
"covid-19": "Pulmonologist / Infectious Disease Specialist",
|
30 |
+
}
|
31 |
+
|
32 |
+
disease_home_care = {
|
33 |
+
"asthma": [
|
34 |
+
"Use prescribed inhalers as directed",
|
35 |
+
"Avoid known triggers like smoke and dust",
|
36 |
+
"Monitor breathing with a peak flow meter",
|
37 |
+
"Keep rescue inhaler nearby",
|
38 |
+
"Attend regular doctor visits"
|
39 |
+
],
|
40 |
+
"heart disease": [
|
41 |
+
"Adopt a low-sodium, heart-healthy diet",
|
42 |
+
"Engage in doctor-approved physical activity",
|
43 |
+
"Take prescribed medications regularly",
|
44 |
+
"Manage stress with relaxation techniques",
|
45 |
+
"Monitor blood pressure at home"
|
46 |
+
],
|
47 |
+
"diabetes": [
|
48 |
+
"Monitor blood glucose levels daily",
|
49 |
+
"Follow a balanced, low-sugar diet",
|
50 |
+
"Exercise regularly as advised",
|
51 |
+
"Take insulin or medication as prescribed",
|
52 |
+
"Check feet daily for sores or infections"
|
53 |
+
],
|
54 |
+
"hypertension": [
|
55 |
+
"Reduce salt intake",
|
56 |
+
"Maintain a healthy weight",
|
57 |
+
"Exercise regularly",
|
58 |
+
"Avoid excessive alcohol",
|
59 |
+
"Take prescribed blood pressure medication"
|
60 |
+
],
|
61 |
+
"stroke": [
|
62 |
+
"Follow a rehabilitation plan strictly",
|
63 |
+
"Eat a heart-healthy diet",
|
64 |
+
"Take all prescribed medications",
|
65 |
+
"Monitor blood pressure regularly",
|
66 |
+
"Avoid smoking and limit alcohol"
|
67 |
+
],
|
68 |
+
"cancer": [
|
69 |
+
"Attend all treatment sessions",
|
70 |
+
"Eat a balanced, nutrient-rich diet",
|
71 |
+
"Stay hydrated",
|
72 |
+
"Manage side effects with doctor guidance",
|
73 |
+
"Seek emotional and mental health support"
|
74 |
+
],
|
75 |
+
"tuberculosis": [
|
76 |
+
"Take all prescribed medication daily",
|
77 |
+
"Complete the full course of treatment",
|
78 |
+
"Cover mouth when coughing",
|
79 |
+
"Ventilate living spaces well",
|
80 |
+
"Avoid crowded places until cleared by doctor",
|
81 |
+
"Attend all follow-up appointments"
|
82 |
+
],
|
83 |
+
"pneumonia": [
|
84 |
+
"Take antibiotics as prescribed",
|
85 |
+
"Rest and stay hydrated",
|
86 |
+
"Use humidified air if advised",
|
87 |
+
"Complete the full course of medication",
|
88 |
+
"Monitor breathing difficulty and seek help if severe"
|
89 |
+
],
|
90 |
+
"bronchitis": [
|
91 |
+
"Stay hydrated with water and warm fluids",
|
92 |
+
"Rest as much as possible",
|
93 |
+
"Use inhalers or medicines as prescribed",
|
94 |
+
"Avoid smoke and other irritants",
|
95 |
+
"Use a humidifier to ease breathing"
|
96 |
+
],
|
97 |
+
"copd": [
|
98 |
+
"Use inhalers and medications regularly",
|
99 |
+
"Avoid smoking entirely",
|
100 |
+
"Attend pulmonary rehabilitation sessions",
|
101 |
+
"Practice breathing exercises",
|
102 |
+
"Monitor oxygen levels if prescribed"
|
103 |
+
],
|
104 |
+
"arthritis": [
|
105 |
+
"Exercise regularly with low-impact activities",
|
106 |
+
"Maintain healthy weight",
|
107 |
+
"Use pain relievers as directed",
|
108 |
+
"Apply heat or cold packs as needed",
|
109 |
+
"Attend physical therapy sessions"
|
110 |
+
],
|
111 |
+
"migraine": [
|
112 |
+
"Avoid known migraine triggers",
|
113 |
+
"Follow prescribed medication plans",
|
114 |
+
"Practice stress-reduction techniques",
|
115 |
+
"Stay well hydrated",
|
116 |
+
"Maintain a regular sleep schedule"
|
117 |
+
],
|
118 |
+
"anemia": [
|
119 |
+
"Eat iron-rich foods like leafy greens and red meat",
|
120 |
+
"Take iron supplements if prescribed",
|
121 |
+
"Monitor fatigue and dizziness",
|
122 |
+
"Attend regular blood tests",
|
123 |
+
"Avoid tea or coffee with iron-rich meals to improve absorption"
|
124 |
+
],
|
125 |
+
"allergy": [
|
126 |
+
"Avoid known allergens",
|
127 |
+
"Use antihistamines as prescribed",
|
128 |
+
"Carry an epinephrine auto-injector if severe",
|
129 |
+
"Keep living areas clean and dust-free",
|
130 |
+
"Monitor symptoms and seek help if they worsen"
|
131 |
+
],
|
132 |
+
"obesity": [
|
133 |
+
"Adopt a balanced, calorie-controlled diet",
|
134 |
+
"Engage in regular physical activity",
|
135 |
+
"Seek behavioral counseling if needed",
|
136 |
+
"Attend regular medical checkups",
|
137 |
+
"Consider medical or surgical options as advised"
|
138 |
+
],
|
139 |
+
"epilepsy": [
|
140 |
+
"Take anti-seizure medications as prescribed",
|
141 |
+
"Maintain regular sleep schedule",
|
142 |
+
"Avoid known seizure triggers",
|
143 |
+
"Inform close contacts about first aid for seizures",
|
144 |
+
"Attend regular neurology appointments"
|
145 |
+
],
|
146 |
+
"dementia": [
|
147 |
+
"Keep a structured daily routine",
|
148 |
+
"Use reminders and labels to aid memory",
|
149 |
+
"Ensure home safety (locks, alarms)",
|
150 |
+
"Maintain social engagement",
|
151 |
+
"Attend regular medical evaluations"
|
152 |
+
],
|
153 |
+
"autism": [
|
154 |
+
"Engage in behavioral therapy sessions",
|
155 |
+
"Create structured routines",
|
156 |
+
"Use communication aids if needed",
|
157 |
+
"Encourage social skills practice",
|
158 |
+
"Coordinate care with specialists"
|
159 |
+
],
|
160 |
+
"parkinson's disease": [
|
161 |
+
"Take medications on schedule",
|
162 |
+
"Attend physiotherapy sessions",
|
163 |
+
"Use mobility aids if necessary",
|
164 |
+
"Maintain a balanced diet",
|
165 |
+
"Practice speech and occupational therapy exercises"
|
166 |
+
],
|
167 |
+
"leukemia": [
|
168 |
+
"Follow chemotherapy schedules precisely",
|
169 |
+
"Monitor for infection signs",
|
170 |
+
"Maintain a nutritious diet",
|
171 |
+
"Stay hydrated",
|
172 |
+
"Attend all follow-up appointments"
|
173 |
+
],
|
174 |
+
"glaucoma": [
|
175 |
+
"Use eye drops as prescribed",
|
176 |
+
"Attend regular eye exams",
|
177 |
+
"Avoid activities that increase eye pressure",
|
178 |
+
"Report vision changes promptly",
|
179 |
+
"Follow ophthalmologist instructions carefully"
|
180 |
+
],
|
181 |
+
"hepatitis": [
|
182 |
+
"Avoid alcohol completely",
|
183 |
+
"Follow prescribed medication regimens",
|
184 |
+
"Eat a balanced, liver-friendly diet",
|
185 |
+
"Get adequate rest",
|
186 |
+
"Attend all medical follow-up visits"
|
187 |
+
],
|
188 |
+
"kidney disease": [
|
189 |
+
"Follow renal diet guidelines",
|
190 |
+
"Control blood pressure",
|
191 |
+
"Monitor fluid intake as advised",
|
192 |
+
"Avoid NSAIDs unless prescribed",
|
193 |
+
"Attend nephrologist appointments"
|
194 |
+
],
|
195 |
+
"thyroid disorder": [
|
196 |
+
"Take thyroid medication at the same time daily",
|
197 |
+
"Avoid food interactions if advised (e.g. soy, iron)",
|
198 |
+
"Monitor symptoms and report changes",
|
199 |
+
"Get regular blood tests",
|
200 |
+
"Attend endocrinologist appointments"
|
201 |
+
],
|
202 |
+
"hiv/aids": [
|
203 |
+
"Take antiretroviral therapy daily",
|
204 |
+
"Eat a balanced diet",
|
205 |
+
"Practice safe sex",
|
206 |
+
"Avoid sharing needles",
|
207 |
+
"Attend regular viral load testing"
|
208 |
+
],
|
209 |
+
"dengue": [
|
210 |
+
"Rest as much as possible",
|
211 |
+
"Stay well hydrated",
|
212 |
+
"Take acetaminophen for fever (avoid NSAIDs)",
|
213 |
+
"Monitor for warning signs",
|
214 |
+
"Seek immediate care if symptoms worsen"
|
215 |
+
],
|
216 |
+
"malaria": [
|
217 |
+
"Take full course of antimalarial drugs",
|
218 |
+
"Use bed nets to avoid mosquito bites",
|
219 |
+
"Stay hydrated",
|
220 |
+
"Rest until fever subsides",
|
221 |
+
"Seek prompt care for any recurrence"
|
222 |
+
],
|
223 |
+
"covid-19": [
|
224 |
+
"Isolate to avoid spreading",
|
225 |
+
"Stay hydrated",
|
226 |
+
"Monitor oxygen levels if possible",
|
227 |
+
"Rest adequately",
|
228 |
+
"Seek medical help if breathing difficulty develops"
|
229 |
+
]
|
230 |
+
}
|
index.html
ADDED
@@ -0,0 +1,336 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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>CTRL + ALT + HEAL</title>
|
7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
8 |
+
<link
|
9 |
+
href="https://fonts.googleapis.com/css2?family=Rubik:wght@400;700&display=swap"
|
10 |
+
rel="stylesheet"
|
11 |
+
/>
|
12 |
+
<style>
|
13 |
+
:root {
|
14 |
+
--tropical-indigo: rgb(120, 187, 242);
|
15 |
+
--wisteria: rgb(197, 217, 251);
|
16 |
+
--latte-cream: #ffffff;
|
17 |
+
}
|
18 |
+
|
19 |
+
body {
|
20 |
+
font-family: "Rubik", sans-serif;
|
21 |
+
background-color: var(--latte-cream);
|
22 |
+
color: #333;
|
23 |
+
}
|
24 |
+
|
25 |
+
.fade-in {
|
26 |
+
opacity: 0;
|
27 |
+
transform: translateY(30px);
|
28 |
+
transition: all 0.8s ease-out;
|
29 |
+
}
|
30 |
+
.fade-in.show {
|
31 |
+
opacity: 1;
|
32 |
+
transform: translateY(0);
|
33 |
+
}
|
34 |
+
|
35 |
+
.glass-card {
|
36 |
+
background: rgba(162, 160, 160, 0.075);
|
37 |
+
backdrop-filter: blur(12px);
|
38 |
+
border-radius: 1rem;
|
39 |
+
border: 1px solid rgba(255, 255, 255, 0.3);
|
40 |
+
padding: 2rem;
|
41 |
+
text-align: center;
|
42 |
+
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
43 |
+
}
|
44 |
+
.glass-card:hover {
|
45 |
+
transform: translateY(-5px);
|
46 |
+
box-shadow: 0 15px 25px rgba(0, 0, 0, 0.2);
|
47 |
+
}
|
48 |
+
|
49 |
+
.nav-link {
|
50 |
+
position: relative;
|
51 |
+
padding-bottom: 4px;
|
52 |
+
transition: color 0.3s;
|
53 |
+
}
|
54 |
+
.nav-link::after {
|
55 |
+
content: "";
|
56 |
+
position: absolute;
|
57 |
+
width: 0%;
|
58 |
+
height: 2px;
|
59 |
+
bottom: 0;
|
60 |
+
left: 0;
|
61 |
+
background-color: var(--tropical-indigo);
|
62 |
+
transition: width 0.3s ease;
|
63 |
+
}
|
64 |
+
.nav-link:hover::after {
|
65 |
+
width: 100%;
|
66 |
+
}
|
67 |
+
|
68 |
+
.parallax {
|
69 |
+
background-attachment: fixed;
|
70 |
+
background-size: cover;
|
71 |
+
background-position: center;
|
72 |
+
position: relative;
|
73 |
+
}
|
74 |
+
|
75 |
+
/* Typing effect styles */
|
76 |
+
#typed-heading,
|
77 |
+
#typed-paragraph {
|
78 |
+
overflow: hidden;
|
79 |
+
white-space: nowrap;
|
80 |
+
border-right: 2px solid var(--tropical-indigo);
|
81 |
+
}
|
82 |
+
</style>
|
83 |
+
</head>
|
84 |
+
<body>
|
85 |
+
<!-- NAVBAR -->
|
86 |
+
<nav
|
87 |
+
class="fixed top-0 left-0 w-full z-50 backdrop-blur-md bg-white/20 border-b border-white/30 shadow-md"
|
88 |
+
>
|
89 |
+
<div
|
90 |
+
class="max-w-6xl mx-auto px-6 py-4 flex justify-between items-center"
|
91 |
+
>
|
92 |
+
<!-- Logo -->
|
93 |
+
<a
|
94 |
+
href="index.html"
|
95 |
+
class="text-2xl font-bold text-[#FOE3CE hover:text-[var(--tropical-indigo)] transition"
|
96 |
+
>
|
97 |
+
CTRL + ALT + HEAL
|
98 |
+
</a>
|
99 |
+
|
100 |
+
<!-- Desktop Menu -->
|
101 |
+
<ul class="hidden md:flex space-x-6 font-medium text-gray-800">
|
102 |
+
<li><a href="index.html" class="nav-link">Home</a></li>
|
103 |
+
<li><a href="analyzer.html" class="nav-link">Analyzer</a></li>
|
104 |
+
<li><a href="profile.html" class="nav-link">Profile</a></li>
|
105 |
+
<li><a href="login.html" class="nav-link">Login</a></li>
|
106 |
+
<li><a href="about.html" class="nav-link">About</a></li>
|
107 |
+
</ul>
|
108 |
+
|
109 |
+
<!-- Hamburger Menu -->
|
110 |
+
<button
|
111 |
+
id="hamburger"
|
112 |
+
class="md:hidden text-[var(--latte-cream)] text-2xl"
|
113 |
+
>
|
114 |
+
☰
|
115 |
+
</button>
|
116 |
+
</div>
|
117 |
+
|
118 |
+
<!-- Mobile Menu -->
|
119 |
+
<ul
|
120 |
+
id="mobile-menu"
|
121 |
+
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"
|
122 |
+
>
|
123 |
+
<li>
|
124 |
+
<a
|
125 |
+
href="index.html"
|
126 |
+
class="block text-gray-800 hover:text-[var(--neon-green)]"
|
127 |
+
>Home</a
|
128 |
+
>
|
129 |
+
</li>
|
130 |
+
<li>
|
131 |
+
<a
|
132 |
+
href="analyzer.html"
|
133 |
+
class="block text-gray-800 hover:text-[var(--neon-green)]"
|
134 |
+
>Analyzer</a
|
135 |
+
>
|
136 |
+
</li>
|
137 |
+
<li>
|
138 |
+
<a
|
139 |
+
href="profile.html"
|
140 |
+
class="block text-gray-800 hover:text-[var(--neon-green)]"
|
141 |
+
>Profile</a
|
142 |
+
>
|
143 |
+
</li>
|
144 |
+
<li>
|
145 |
+
<a
|
146 |
+
href="login.html"
|
147 |
+
class="block text-gray-800 hover:text-[var(--neon-green)]"
|
148 |
+
>Login</a
|
149 |
+
>
|
150 |
+
</li>
|
151 |
+
<li>
|
152 |
+
<a
|
153 |
+
href="about.html"
|
154 |
+
class="block text-gray-800 hover:text-[var(--neon-green)]"
|
155 |
+
>About</a
|
156 |
+
>
|
157 |
+
</li>
|
158 |
+
</ul>
|
159 |
+
</nav>
|
160 |
+
|
161 |
+
<script>
|
162 |
+
const hamburger = document.getElementById("hamburger");
|
163 |
+
const mobileMenu = document.getElementById("mobile-menu");
|
164 |
+
|
165 |
+
hamburger.addEventListener("click", () => {
|
166 |
+
mobileMenu.classList.toggle("hidden");
|
167 |
+
});
|
168 |
+
</script>
|
169 |
+
|
170 |
+
<!-- HERO SECTION -->
|
171 |
+
<section
|
172 |
+
class="relative min-h-[600px] flex items-center justify-center"
|
173 |
+
style="
|
174 |
+
background-image: url('https://videos.openai.com/vg-assets/assets%2Ftask_01k2qzfsscev8vmftcka1wp2et%2F1755299042_img_1.webp?st=2025-08-15T21%3A17%3A52Z&se=2025-08-21T22%3A17%3A52Z&sks=b&skt=2025-08-15T21%3A17%3A52Z&ske=2025-08-21T22%3A17%3A52Z&sktid=a48cca56-e6da-484e-a814-9c849652bcb3&skoid=3d249c53-07fa-4ba4-9b65-0bf8eb4ea46a&skv=2019-02-02&sv=2018-11-09&sr=b&sp=r&spr=https%2Chttp&sig=j0aFWc%2BchHFLtaa8JPylXkDFsrtP8zazpKyO8Edy5n8%3D&az=oaivgprodscus');
|
175 |
+
background-size: cover;
|
176 |
+
background-position: center;
|
177 |
+
"
|
178 |
+
>
|
179 |
+
<div class="absolute inset-0 bg-black/40"></div>
|
180 |
+
<div class="relative z-10 text-center px-6 fade-in">
|
181 |
+
<h1 class="text-5xl md:text-6xl font-bold text-white mb-4">
|
182 |
+
CTRL + ALT + HEAL
|
183 |
+
</h1>
|
184 |
+
<p class="text-lg text-gray-200 mb-2">
|
185 |
+
From medical chaos to clarity. Upload your report, get real answers —
|
186 |
+
fast.
|
187 |
+
</p>
|
188 |
+
<p class="text-sm text-gray-300 mb-6">
|
189 |
+
No stress, no spiraling. Just answers that feel human.
|
190 |
+
</p>
|
191 |
+
<a href="login.html"
|
192 |
+
><button
|
193 |
+
class="bg-[var(--tropical-indigo)] hover:bg-[var(--wisteria)] text-white px-8 py-3 rounded-lg shadow-lg transition"
|
194 |
+
>
|
195 |
+
Sign Up / Login
|
196 |
+
</button></a
|
197 |
+
>
|
198 |
+
</div>
|
199 |
+
</section>
|
200 |
+
|
201 |
+
<!-- FEATURES -->
|
202 |
+
<section class="py-20 bg-[var(--latte-cream)]">
|
203 |
+
<div class="max-w-6xl mx-auto px-6 grid md:grid-cols-3 gap-8 fade-in">
|
204 |
+
<div class="glass-card">
|
205 |
+
<h3 class="text-2xl font-bold text-[var(--tropical-indigo)] mb-2">
|
206 |
+
Fast Results
|
207 |
+
</h3>
|
208 |
+
<p>Upload your report and get human-readable answers instantly.</p>
|
209 |
+
</div>
|
210 |
+
<div class="glass-card">
|
211 |
+
<h3 class="text-2xl font-bold text-[var(--tropical-indigo)] mb-2">
|
212 |
+
Clear Language
|
213 |
+
</h3>
|
214 |
+
<p>No medical jargon, just plain language you can understand.</p>
|
215 |
+
</div>
|
216 |
+
<div class="glass-card">
|
217 |
+
<h3 class="text-2xl font-bold text-[var(--tropical-indigo)] mb-2">
|
218 |
+
Actionable Steps
|
219 |
+
</h3>
|
220 |
+
<p>Know what to do next without the stress and confusion.</p>
|
221 |
+
</div>
|
222 |
+
</div>
|
223 |
+
</section>
|
224 |
+
|
225 |
+
<!-- PARALLAX INFO SECTION -->
|
226 |
+
<section
|
227 |
+
class="relative h-[200px] flex items-center justify-center text-center text-white parallax"
|
228 |
+
>
|
229 |
+
<div class="absolute inset-0 bg-black/40"></div>
|
230 |
+
<div class="relative z-10 px-6 fade-in">
|
231 |
+
<h2 id="typed-heading" class="text-4xl font-bold mb-4"></h2>
|
232 |
+
<p id="typed-paragraph" class="text-lg max-w-xl mx-auto"></p>
|
233 |
+
</div>
|
234 |
+
</section>
|
235 |
+
|
236 |
+
<!-- BEEN THERE -->
|
237 |
+
<section class="py-20 bg-[var(--latte-cream)] fade-in">
|
238 |
+
<div
|
239 |
+
class="max-w-6xl mx-auto px-6 grid md:grid-cols-2 gap-12 items-center"
|
240 |
+
>
|
241 |
+
<div>
|
242 |
+
<h3 class="text-3xl font-bold text-[var(--tropical-indigo)] mb-4">
|
243 |
+
Been There.
|
244 |
+
</h3>
|
245 |
+
<p class="mb-4">
|
246 |
+
That’s exactly why we built this app — to stop the health spiral
|
247 |
+
before it even starts. We know what it’s like to open a medical
|
248 |
+
report and immediately feel overwhelmed. Weird abbreviations.
|
249 |
+
Numbers with no context. Pages that feel like they were written for
|
250 |
+
robots, not real people. It’s confusing, it’s stressful, and it’s
|
251 |
+
usually a late‐night Google rabbit hole that somehow ends in you
|
252 |
+
thinking you’ve got 3 rare conditions and a 2-day countdown.
|
253 |
+
</p>
|
254 |
+
<p>
|
255 |
+
So we made something better. Just upload your report. We’ll break it
|
256 |
+
down into plain, human language. We’ll highlight what actually
|
257 |
+
matters, skip the jargon, and explain everything in a way that
|
258 |
+
actually makes sense. Most importantly, we’ll give you real,
|
259 |
+
practical steps — no guessing, no spiraling. You don’t need a
|
260 |
+
medical degree to understand your own health. You just need the
|
261 |
+
right guide. That’s us.
|
262 |
+
</p>
|
263 |
+
</div>
|
264 |
+
<div class="w-full h-80 rounded-lg overflow-hidden shadow-lg">
|
265 |
+
<img
|
266 |
+
src="https://i.pinimg.com/originals/44/c7/c1/44c7c1f3fbd68b2151c37af5f08198f1.gif"
|
267 |
+
class="object-cover w-full h-full rounded-lg"
|
268 |
+
/>
|
269 |
+
</div>
|
270 |
+
</div>
|
271 |
+
</section>
|
272 |
+
|
273 |
+
<!-- FOOTER -->
|
274 |
+
<footer class="py-12 bg-[var(--wisteria)] text-white fade-in">
|
275 |
+
<div
|
276 |
+
class="max-w-6xl mx-auto px-6 flex flex-col md:flex-row justify-between items-center"
|
277 |
+
>
|
278 |
+
<p>© 2025 CTRL + ALT + HEAL. All rights reserved.</p>
|
279 |
+
<div class="flex space-x-4 mt-4 md:mt-0">
|
280 |
+
<a href="#" class="hover:underline">Privacy Policy</a>
|
281 |
+
<a href="#" class="hover:underline">Terms of Service</a>
|
282 |
+
</div>
|
283 |
+
</div>
|
284 |
+
</footer>
|
285 |
+
|
286 |
+
<script>
|
287 |
+
// Fade-in on scroll
|
288 |
+
const fadeObserver = new IntersectionObserver(
|
289 |
+
(entries) => {
|
290 |
+
entries.forEach((entry) => {
|
291 |
+
if (entry.isIntersecting) entry.target.classList.add("show");
|
292 |
+
});
|
293 |
+
},
|
294 |
+
{ threshold: 0.1 }
|
295 |
+
);
|
296 |
+
document
|
297 |
+
.querySelectorAll(".fade-in")
|
298 |
+
.forEach((el) => fadeObserver.observe(el));
|
299 |
+
|
300 |
+
// Typing effect on scroll
|
301 |
+
const typeObserver = new IntersectionObserver(
|
302 |
+
(entries) => {
|
303 |
+
entries.forEach((entry) => {
|
304 |
+
if (entry.isIntersecting) {
|
305 |
+
typeText("typed-heading", "Your Health, Your Clarity", 80);
|
306 |
+
typeText(
|
307 |
+
"typed-paragraph",
|
308 |
+
"We make complex medical reports simple and easy to understand.",
|
309 |
+
30
|
310 |
+
);
|
311 |
+
typeObserver.unobserve(entry.target);
|
312 |
+
}
|
313 |
+
});
|
314 |
+
},
|
315 |
+
{ threshold: 0.5 }
|
316 |
+
);
|
317 |
+
|
318 |
+
typeObserver.observe(
|
319 |
+
document.querySelector("#typed-heading").parentElement
|
320 |
+
);
|
321 |
+
|
322 |
+
function typeText(id, text, speed) {
|
323 |
+
const el = document.getElementById(id);
|
324 |
+
let i = 0;
|
325 |
+
function type() {
|
326 |
+
if (i < text.length) {
|
327 |
+
el.innerHTML += text.charAt(i);
|
328 |
+
i++;
|
329 |
+
setTimeout(type, speed);
|
330 |
+
}
|
331 |
+
}
|
332 |
+
type();
|
333 |
+
}
|
334 |
+
</script>
|
335 |
+
</body>
|
336 |
+
</html>
|
login.html
ADDED
@@ -0,0 +1,348 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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>Login / Signup - CTRL + ALT + HEAL</title>
|
7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
8 |
+
<style>
|
9 |
+
:root {
|
10 |
+
--blue: rgb(120, 187, 242);
|
11 |
+
--l-blue: rgb(197, 217, 251);
|
12 |
+
--latte-cream: #ffffff;
|
13 |
+
--red: #ff746c;
|
14 |
+
--l-red: #faa0a0;
|
15 |
+
}
|
16 |
+
|
17 |
+
body {
|
18 |
+
font-family: "Rubik", sans-serif;
|
19 |
+
background-color: var(--cream);
|
20 |
+
color: #333;
|
21 |
+
}
|
22 |
+
|
23 |
+
/* Navbar styles */
|
24 |
+
nav {
|
25 |
+
backdrop-filter: blur(10px);
|
26 |
+
background: rgba(255, 255, 255, 0.85);
|
27 |
+
transition: transform 0.3s ease, background-color 0.3s ease,
|
28 |
+
box-shadow 0.3s ease;
|
29 |
+
}
|
30 |
+
|
31 |
+
nav.scrolled {
|
32 |
+
background: rgba(255, 255, 255, 1);
|
33 |
+
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1);
|
34 |
+
transform: translateY(-5px);
|
35 |
+
}
|
36 |
+
|
37 |
+
nav a {
|
38 |
+
transition: color 0.3s ease, transform 0.2s ease;
|
39 |
+
}
|
40 |
+
|
41 |
+
nav a:hover {
|
42 |
+
color: var(--blue);
|
43 |
+
transform: translateY(-2px);
|
44 |
+
}
|
45 |
+
|
46 |
+
/* Form card animation */
|
47 |
+
@keyframes fadeSlideUp {
|
48 |
+
0% {
|
49 |
+
opacity: 0;
|
50 |
+
transform: translateY(20px);
|
51 |
+
}
|
52 |
+
100% {
|
53 |
+
opacity: 1;
|
54 |
+
transform: translateY(0);
|
55 |
+
}
|
56 |
+
}
|
57 |
+
|
58 |
+
.fade-slide-up {
|
59 |
+
animation: fadeSlideUp 0.6s ease forwards;
|
60 |
+
}
|
61 |
+
|
62 |
+
.form-card {
|
63 |
+
background: rgba(255, 255, 255, 0.85);
|
64 |
+
backdrop-filter: blur(10px);
|
65 |
+
border-radius: 1rem;
|
66 |
+
padding: 2rem;
|
67 |
+
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
|
68 |
+
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
69 |
+
}
|
70 |
+
|
71 |
+
.form-card:hover {
|
72 |
+
transform: translateY(-5px);
|
73 |
+
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.2);
|
74 |
+
}
|
75 |
+
|
76 |
+
.form-input {
|
77 |
+
width: 100%;
|
78 |
+
padding: 0.5rem 1rem;
|
79 |
+
border-radius: 0.5rem;
|
80 |
+
border: 1px solid #ccc;
|
81 |
+
transition: border-color 0.3s ease, box-shadow 0.3s ease;
|
82 |
+
}
|
83 |
+
|
84 |
+
.form-input:focus {
|
85 |
+
outline: none;
|
86 |
+
border-color: var(--blue);
|
87 |
+
box-shadow: 0 0 0 3px rgba(120, 187, 242, 0.3);
|
88 |
+
}
|
89 |
+
|
90 |
+
.btn-primary {
|
91 |
+
width: 100%;
|
92 |
+
padding: 0.75rem;
|
93 |
+
border-radius: 0.75rem;
|
94 |
+
background-color: var(--blue);
|
95 |
+
color: white;
|
96 |
+
font-weight: 600;
|
97 |
+
transition: background-color 0.3s ease, transform 0.2s ease,
|
98 |
+
box-shadow 0.2s ease;
|
99 |
+
}
|
100 |
+
|
101 |
+
.btn-primary:hover {
|
102 |
+
background-color: var(--l-blue);
|
103 |
+
color: #333;
|
104 |
+
transform: translateY(-2px);
|
105 |
+
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.15);
|
106 |
+
}
|
107 |
+
|
108 |
+
.btn-red {
|
109 |
+
width: 100%;
|
110 |
+
padding: 0.75rem;
|
111 |
+
border-radius: 0.75rem;
|
112 |
+
background-color: var(--red);
|
113 |
+
color: white;
|
114 |
+
font-weight: 600;
|
115 |
+
transition: background-color 0.3s ease, transform 0.2s ease,
|
116 |
+
box-shadow 0.2s ease;
|
117 |
+
}
|
118 |
+
|
119 |
+
.btn-red:hover {
|
120 |
+
background-color: var(--l-red);
|
121 |
+
transform: translateY(-2px);
|
122 |
+
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.15);
|
123 |
+
}
|
124 |
+
</style>
|
125 |
+
</head>
|
126 |
+
<body
|
127 |
+
class="min-h-screen flex flex-col items-center justify-start px-4 pt-24"
|
128 |
+
>
|
129 |
+
<!-- Navbar -->
|
130 |
+
<nav
|
131 |
+
class="fixed top-0 left-0 w-full z-50 backdrop-blur-md bg-white/20 border-b border-white/30 shadow-md"
|
132 |
+
>
|
133 |
+
<div
|
134 |
+
class="max-w-6xl mx-auto px-6 py-4 flex justify-between items-center"
|
135 |
+
>
|
136 |
+
<!-- Logo -->
|
137 |
+
<a
|
138 |
+
href="index.html"
|
139 |
+
class="text-2xl font-bold hover:text-[var(--tropical-indigo)] transition"
|
140 |
+
>
|
141 |
+
CTRL + ALT + HEAL
|
142 |
+
</a>
|
143 |
+
|
144 |
+
<!-- Desktop Menu -->
|
145 |
+
<ul class="hidden md:flex space-x-6 font-medium text-gray-800">
|
146 |
+
<li><a href="index.html" class="nav-link">Home</a></li>
|
147 |
+
<li><a href="analyzer.html" class="nav-link">Analyzer</a></li>
|
148 |
+
<li><a href="profile.html" class="nav-link">Profile</a></li>
|
149 |
+
<li><a href="login.html" class="nav-link">Login</a></li>
|
150 |
+
<li><a href="about.html" class="nav-link">About</a></li>
|
151 |
+
</ul>
|
152 |
+
|
153 |
+
<!-- Hamburger Menu -->
|
154 |
+
<button id="hamburger" class="md:hidden text-[#000000] text-2xl">
|
155 |
+
☰
|
156 |
+
</button>
|
157 |
+
</div>
|
158 |
+
|
159 |
+
<!-- Mobile Menu -->
|
160 |
+
<ul
|
161 |
+
id="mobile-menu"
|
162 |
+
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"
|
163 |
+
>
|
164 |
+
<li>
|
165 |
+
<a
|
166 |
+
href="index.html"
|
167 |
+
class="block text-bold text-gray-800 hover:text-[var(--neon-green)]"
|
168 |
+
>Home</a
|
169 |
+
>
|
170 |
+
</li>
|
171 |
+
<li>
|
172 |
+
<a
|
173 |
+
href="analyzer.html"
|
174 |
+
class="block text-gray-800 hover:text-[var(--neon-green)]"
|
175 |
+
>Analyzer</a
|
176 |
+
>
|
177 |
+
</li>
|
178 |
+
<li>
|
179 |
+
<a
|
180 |
+
href="profile.html"
|
181 |
+
class="block text-gray-800 hover:text-[var(--neon-green)]"
|
182 |
+
>Profile</a
|
183 |
+
>
|
184 |
+
</li>
|
185 |
+
<li>
|
186 |
+
<a
|
187 |
+
href="login.html"
|
188 |
+
class="block text-gray-800 hover:text-[var(--neon-green)]"
|
189 |
+
>Login</a
|
190 |
+
>
|
191 |
+
</li>
|
192 |
+
<li>
|
193 |
+
<a
|
194 |
+
href="about.html"
|
195 |
+
class="block text-gray-800 hover:text-[var(--neon-green)]"
|
196 |
+
>About</a
|
197 |
+
>
|
198 |
+
</li>
|
199 |
+
</ul>
|
200 |
+
</nav>
|
201 |
+
|
202 |
+
<!-- Login Form -->
|
203 |
+
<div class="form-card w-full max-w-md fade-slide-up mt-8">
|
204 |
+
<h2 id="formTitle" class="text-2xl font-semibold text-[var(--blue)] mb-6">
|
205 |
+
Log In
|
206 |
+
</h2>
|
207 |
+
<input type="hidden" id="mode" value="login" />
|
208 |
+
|
209 |
+
<label class="block mb-2 text-sm font-medium">Mode</label>
|
210 |
+
<select
|
211 |
+
id="modeSelector"
|
212 |
+
onchange="toggleMode(this.value)"
|
213 |
+
class="form-input mb-4"
|
214 |
+
>
|
215 |
+
<option value="login">Log In</option>
|
216 |
+
<option value="signup">Sign Up</option>
|
217 |
+
</select>
|
218 |
+
|
219 |
+
<label class="block mb-2 text-sm font-medium">Email</label>
|
220 |
+
<input
|
221 |
+
type="email"
|
222 |
+
id="email"
|
223 |
+
placeholder="[email protected]"
|
224 |
+
class="form-input mb-4"
|
225 |
+
/>
|
226 |
+
|
227 |
+
<label class="block mb-2 text-sm font-medium">Password</label>
|
228 |
+
<input
|
229 |
+
type="password"
|
230 |
+
id="password"
|
231 |
+
placeholder="••••••••"
|
232 |
+
class="form-input mb-4"
|
233 |
+
/>
|
234 |
+
|
235 |
+
<div id="nameGroup" style="display: none">
|
236 |
+
<label class="block mb-2 text-sm font-medium">Name</label>
|
237 |
+
<input
|
238 |
+
type="text"
|
239 |
+
id="name"
|
240 |
+
placeholder="Your Name"
|
241 |
+
class="form-input mb-4"
|
242 |
+
/>
|
243 |
+
</div>
|
244 |
+
|
245 |
+
<div id="dobGroup" style="display: none">
|
246 |
+
<label class="block mb-2 text-sm font-medium">Date of Birth</label>
|
247 |
+
<input type="date" id="dob" class="form-input mb-6" />
|
248 |
+
</div>
|
249 |
+
|
250 |
+
<button onclick="submitForm()" id="submitBtn" class="btn-primary mb-2">
|
251 |
+
Log In
|
252 |
+
</button>
|
253 |
+
<button onclick="resetPassword()" class="btn-red">Reset Password</button>
|
254 |
+
</div>
|
255 |
+
|
256 |
+
<!-- Firebase & JS -->
|
257 |
+
<script type="module">
|
258 |
+
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-app.js";
|
259 |
+
import {
|
260 |
+
getAuth,
|
261 |
+
createUserWithEmailAndPassword,
|
262 |
+
signInWithEmailAndPassword,
|
263 |
+
sendPasswordResetEmail,
|
264 |
+
} from "https://www.gstatic.com/firebasejs/9.22.0/firebase-auth.js";
|
265 |
+
import {
|
266 |
+
getFirestore,
|
267 |
+
doc,
|
268 |
+
setDoc,
|
269 |
+
} from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js";
|
270 |
+
|
271 |
+
const firebaseConfig = {
|
272 |
+
apiKey: "",
|
273 |
+
authDomain: "",
|
274 |
+
projectId: "",
|
275 |
+
storageBucket: "",
|
276 |
+
messagingSenderId: "",
|
277 |
+
appId: "",
|
278 |
+
measurementId: "",
|
279 |
+
};
|
280 |
+
|
281 |
+
const app = initializeApp(firebaseConfig);
|
282 |
+
const auth = getAuth(app);
|
283 |
+
const db = getFirestore(app);
|
284 |
+
|
285 |
+
window.toggleMode = (mode) => {
|
286 |
+
document.getElementById("formTitle").textContent =
|
287 |
+
mode === "signup" ? "Sign Up" : "Log In";
|
288 |
+
document.getElementById("nameGroup").style.display =
|
289 |
+
mode === "signup" ? "block" : "none";
|
290 |
+
document.getElementById("dobGroup").style.display =
|
291 |
+
mode === "signup" ? "block" : "none";
|
292 |
+
document.getElementById("submitBtn").textContent =
|
293 |
+
mode === "signup" ? "Sign Up" : "Log In";
|
294 |
+
document.getElementById("mode").value = mode;
|
295 |
+
};
|
296 |
+
|
297 |
+
window.submitForm = async () => {
|
298 |
+
const mode = document.getElementById("mode").value;
|
299 |
+
const email = document.getElementById("email").value;
|
300 |
+
const password = document.getElementById("password").value;
|
301 |
+
try {
|
302 |
+
if (mode === "signup") {
|
303 |
+
const name = document.getElementById("name").value;
|
304 |
+
const dob = document.getElementById("dob").value;
|
305 |
+
const userCredential = await createUserWithEmailAndPassword(
|
306 |
+
auth,
|
307 |
+
email,
|
308 |
+
password
|
309 |
+
);
|
310 |
+
const user = userCredential.user;
|
311 |
+
await setDoc(doc(db, "users", user.uid), { name, email, dob });
|
312 |
+
} else {
|
313 |
+
await signInWithEmailAndPassword(auth, email, password);
|
314 |
+
}
|
315 |
+
window.location.href = "profile.html";
|
316 |
+
} catch (err) {
|
317 |
+
alert(
|
318 |
+
(mode === "signup" ? "Sign Up" : "Log In") +
|
319 |
+
" error: " +
|
320 |
+
err.message
|
321 |
+
);
|
322 |
+
}
|
323 |
+
};
|
324 |
+
|
325 |
+
window.resetPassword = async () => {
|
326 |
+
const email = document.getElementById("email").value;
|
327 |
+
if (!email) return alert("Please enter your email to reset password.");
|
328 |
+
try {
|
329 |
+
await sendPasswordResetEmail(auth, email);
|
330 |
+
alert("Password reset email sent to " + email);
|
331 |
+
} catch (err) {
|
332 |
+
alert("Error sending password reset: " + err.message);
|
333 |
+
}
|
334 |
+
};
|
335 |
+
|
336 |
+
document.addEventListener("DOMContentLoaded", () => {
|
337 |
+
toggleMode("login");
|
338 |
+
|
339 |
+
// Navbar scroll animation
|
340 |
+
const navbar = document.getElementById("navbar");
|
341 |
+
window.addEventListener("scroll", () => {
|
342 |
+
if (window.scrollY > 20) navbar.classList.add("scrolled");
|
343 |
+
else navbar.classList.remove("scrolled");
|
344 |
+
});
|
345 |
+
});
|
346 |
+
</script>
|
347 |
+
</body>
|
348 |
+
</html>
|
measurement.csv
ADDED
@@ -0,0 +1,239 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
condition,measurement,severity,unit,low,high
|
2 |
+
diabetes, hba1c, normal, %,4,5.6
|
3 |
+
diabetes, hba1c, pre-diabetic, %,5.7,6.4
|
4 |
+
diabetes, hba1c, diabetic, %,6.5,14
|
5 |
+
diabetes, hbaic, normal, %,4,5.6
|
6 |
+
diabetes, hbaic, pre-diabetic, %,5.7,6.4
|
7 |
+
diabetes, hbaic, diabetic, %,6.5,14
|
8 |
+
diabetes, hdate, normal, %,4,5.6
|
9 |
+
diabetes, hdate, pre-diabetic, %,5.7,6.4
|
10 |
+
diabetes, hdate, diabetic, %,6.5,14
|
11 |
+
diabetes, fasting-glucose, normal, mg/dL,70,99
|
12 |
+
diabetes, fasting-glucose, pre-diabetic, mg/dL,100,125
|
13 |
+
diabetes, fasting-glucose, diabetic, mg/dL,126,300
|
14 |
+
diabetes, fasting glucose, normal, mg/dL,70,99
|
15 |
+
diabetes, fasting glucose, pre-diabetic, mg/dL,100,125
|
16 |
+
diabetes, fasting glucose, diabetic, mg/dL,126,300
|
17 |
+
diabetes, ogtt, normal, mg/dL,0,139
|
18 |
+
diabetes, ogtt, pre-diabetic, mg/dL,140,199
|
19 |
+
diabetes, ogtt, diabetic, mg/dL,200,300
|
20 |
+
cardiac, ldl, optimal, mg/dL,0,99
|
21 |
+
cardiac, ldl, near-optimal, mg/dL,100,129
|
22 |
+
cardiac, ldl, borderline-high, mg/dL,130,159
|
23 |
+
cardiac, ldl, high, mg/dL,160,189
|
24 |
+
cardiac, ldl, very-high, mg/dL,190,500
|
25 |
+
cardiac, hdl, low, mg/dL,0,40
|
26 |
+
cardiac, hdl, normal, mg/dL,41,59
|
27 |
+
cardiac, hdl, high, mg/dL,60,120
|
28 |
+
cardiac, triglycerides, normal, mg/dL,0,149
|
29 |
+
cardiac, triglycerides, borderline-high, mg/dL,150,199
|
30 |
+
cardiac, triglycerides, high, mg/dL,200,499
|
31 |
+
cardiac, triglycerides, very-high, mg/dL,500,1000
|
32 |
+
thyroid, tsh, low, uIU/mL,0,0.4
|
33 |
+
thyroid, tsh, normal, uIU/mL,0.5,4
|
34 |
+
thyroid, tsh, high, uIU/mL,4.1,10
|
35 |
+
thyroid, free-t4, low, ng/dL,0,0.8
|
36 |
+
thyroid, free-t4, normal, ng/dL,0.9,1.7
|
37 |
+
thyroid, free-t4, high, ng/dL,1.8,3
|
38 |
+
thyroid, free-t3, low, pg/mL,0,2.3
|
39 |
+
thyroid, free-t3, normal, pg/mL,2.4,4.2
|
40 |
+
thyroid, free-t3, high, pg/mL,4.3,6
|
41 |
+
thyroid, free t4, low, ng/dL,0,0.8
|
42 |
+
thyroid, free t4, normal, ng/dL,0.9,1.7
|
43 |
+
thyroid, free t4, high, ng/dL,1.8,3
|
44 |
+
thyroid, free t3, low, pg/mL,0,2.3
|
45 |
+
thyroid, free t3, normal, pg/mL,2.4,4.2
|
46 |
+
thyroid, free t3, high, pg/mL,4.3,6
|
47 |
+
inflammation, crp, low, mg/L,0,0.2
|
48 |
+
inflammation, crp, normal, mg/L,0.3,1
|
49 |
+
inflammation, crp, moderate, mg/L,1.1,3
|
50 |
+
inflammation, crp, high, mg/L,3.1,10
|
51 |
+
inflammation, esr, normal, mm/hr,0,20
|
52 |
+
inflammation, esr, high, mm/hr,21,100
|
53 |
+
vitamin, vitamin-b12, low, pg/mL,0,200
|
54 |
+
vitamin, vitamin-b12, normal, pg/mL,201,900
|
55 |
+
vitamin, vitamin-d, deficient, ng/mL,0,20
|
56 |
+
vitamin, vitamin-d, insufficient, ng/mL,21,29
|
57 |
+
vitamin, vitamin-d, sufficient, ng/mL,30,100
|
58 |
+
vitamin, vitamin-a, low, mcg/dL,0,20
|
59 |
+
vitamin, vitamin-a, normal, mcg/dL,21,80
|
60 |
+
vitamin, vitamin-e, low, mg/L,0,5
|
61 |
+
vitamin, vitamin-e, normal, mg/L,5.1,20
|
62 |
+
vitamin, vitamin b12, low, pg/mL,0,200
|
63 |
+
vitamin, vitamin b12, normal, pg/mL,201,900
|
64 |
+
vitamin, vitamin d, deficient, ng/mL,0,20
|
65 |
+
vitamin, vitamin d, insufficient, ng/mL,21,29
|
66 |
+
vitamin, vitamin d, sufficient, ng/mL,30,100
|
67 |
+
vitamin, vitamin a, low, mcg/dL,0,20
|
68 |
+
vitamin, vitamin a, normal, mcg/dL,21,80
|
69 |
+
vitamin, vitamin e, low, mg/L,0,5
|
70 |
+
vitamin, vitamin e, normal, mg/L,5.1,20
|
71 |
+
electrolyte, sodium, low, mmol/L,0,134
|
72 |
+
electrolyte, sodium, normal, mmol/L,135,145
|
73 |
+
electrolyte, sodium, high, mmol/L,146,200
|
74 |
+
electrolyte, potassium, low, mmol/L,0,3.4
|
75 |
+
electrolyte, potassium, normal, mmol/L,3.5,5
|
76 |
+
electrolyte, potassium, high, mmol/L,5.1,7
|
77 |
+
electrolyte, calcium, low, mg/dL,0,8.4
|
78 |
+
electrolyte, calcium, normal, mg/dL,8.5,10.2
|
79 |
+
electrolyte, calcium, high, mg/dL,10.3,12.5
|
80 |
+
electrolyte, magnesium, low, mg/dL,0,1.6
|
81 |
+
electrolyte, magnesium, normal, mg/dL,1.7,2.2
|
82 |
+
electrolyte, magnesium, high, mg/dL,2.3,3.5
|
83 |
+
blood-pressure, systolic, low, mmHg,0,89
|
84 |
+
blood-pressure, systolic, normal, mmHg,90,119
|
85 |
+
blood-pressure, systolic, elevated, mmHg,120,129
|
86 |
+
blood-pressure, systolic, stage-1, mmHg,130,139
|
87 |
+
blood-pressure, systolic, stage-2, mmHg,140,180
|
88 |
+
blood-pressure, systolic, crisis, mmHg,181,300
|
89 |
+
blood-pressure, diastolic, low, mmHg,0,59
|
90 |
+
blood-pressure, diastolic, normal, mmHg,60,79
|
91 |
+
blood-pressure, diastolic, stage-1, mmHg,80,89
|
92 |
+
blood-pressure, diastolic, stage-2, mmHg,90,120
|
93 |
+
blood-pressure, diastolic, crisis, mmHg,121,200
|
94 |
+
cbc, wbc, low, K/uL,0,3.9
|
95 |
+
cbc, wbc, normal, K/uL,4,11
|
96 |
+
cbc, wbc, high, K/uL,11.1,100
|
97 |
+
cbc, rbc, low, M/uL,0,4.2
|
98 |
+
cbc, rbc, normal, M/uL,4.3,5.9
|
99 |
+
cbc, rbc, high, M/uL,6,8
|
100 |
+
cbc, hemoglobin, low, g/dL,0,13.4
|
101 |
+
cbc, hemoglobin, normal, g/dL,13.5,17.5
|
102 |
+
cbc, hemoglobin, high, g/dL,17.6,22
|
103 |
+
cbc, hematocrit, low, %,0,38.8
|
104 |
+
cbc, hematocrit, normal, %,38.9,50
|
105 |
+
cbc, hematocrit, high, %,50.1,60
|
106 |
+
cbc, platelets, low, K/uL,0,149
|
107 |
+
cbc, platelets, normal, K/uL,150,450
|
108 |
+
cbc, platelets, high, K/uL,451,900
|
109 |
+
iron, serum-iron, low, mcg/dL,0,60
|
110 |
+
iron, serum-iron, normal, mcg/dL,61,170
|
111 |
+
iron, serum-iron, high, mcg/dL,171,300
|
112 |
+
iron, serum iron, low, mcg/dL,0,60
|
113 |
+
iron, serum iron, normal, mcg/dL,61,170
|
114 |
+
iron, serum iron, high, mcg/dL,171,300
|
115 |
+
iron, ferritin, low, ng/mL,0,29
|
116 |
+
iron, ferritin, normal, ng/mL,30,300
|
117 |
+
iron, ferritin, high, ng/mL,301,1000
|
118 |
+
iron, tibc, low, mcg/dL,0,250
|
119 |
+
iron, tibc, normal, mcg/dL,251,450
|
120 |
+
iron, tibc, high, mcg/dL,451,600
|
121 |
+
iron, transferrin-saturation, low, %,0,20
|
122 |
+
iron, transferrin-saturation, normal, %,21,50
|
123 |
+
iron, transferrin-saturation, high, %,51,100
|
124 |
+
iron, transferrin saturation, low, %,0,20
|
125 |
+
iron, transferrin saturation, normal, %,21,50
|
126 |
+
iron, transferrin saturation, high, %,51,100
|
127 |
+
liver, alt, normal, U/L,0,44
|
128 |
+
liver, alt, high, U/L,45,500
|
129 |
+
liver, ast, normal, U/L,0,40
|
130 |
+
liver, ast, high, U/L,41,500
|
131 |
+
liver, alp, normal, U/L,44,147
|
132 |
+
liver, alp, high, U/L,148,400
|
133 |
+
liver, bilirubin-total, normal, mg/dL,0.1,1.2
|
134 |
+
liver, bilirubin-total, high, mg/dL,1.3,10
|
135 |
+
liver, bilirubin total, normal, mg/dL,0.1,1.2
|
136 |
+
liver, bilirubin total, high, mg/dL,1.3,10
|
137 |
+
liver, albumin, low, g/dL,0,3.4
|
138 |
+
liver, albumin, normal, g/dL,3.5,5
|
139 |
+
liver, albumin, high, g/dL,5.1,7
|
140 |
+
kidney, creatinine, low, mg/dL,0,0.6
|
141 |
+
kidney, creatinine, normal, mg/dL,0.7,1.3
|
142 |
+
kidney, creatinine, high, mg/dL,1.4,10
|
143 |
+
kidney, bun, low, mg/dL,0,7
|
144 |
+
kidney, bun, normal, mg/dL,8,20
|
145 |
+
kidney, bun, high, mg/dL,21,50
|
146 |
+
kidney, egfr, low, mL/min/1.73m2,0,59
|
147 |
+
kidney, egfr, normal, mL/min/1.73m2,60,120
|
148 |
+
respiratory, spo2, low, %,0,89
|
149 |
+
respiratory, spo2, normal, %,90,100
|
150 |
+
respiratory, pco2, low, mmHg,0,34
|
151 |
+
respiratory, pco2, normal, mmHg,35,45
|
152 |
+
respiratory, pco2, high, mmHg,46,100
|
153 |
+
respiratory, po2, low, mmHg,0,79
|
154 |
+
respiratory, po2, normal, mmHg,80,100
|
155 |
+
respiratory, po2, high, mmHg,101,200
|
156 |
+
respiratory, fev1, low, L,0,2.0
|
157 |
+
respiratory, fev1, normal, L,2.1,4.0
|
158 |
+
respiratory, fev1, high, L,4.1,6.0
|
159 |
+
respiratory, fevi, low, L,0,2.0
|
160 |
+
respiratory, fevi, normal, L,2.1,4.0
|
161 |
+
respiratory, fevi, high, L,4.1,6.0
|
162 |
+
coagulation, inr, low, ratio,0,0.8
|
163 |
+
coagulation, inr, normal, ratio,0.9,1.2
|
164 |
+
coagulation, inr, high, ratio,1.3,8
|
165 |
+
coagulation, pt, low, seconds,0,10
|
166 |
+
coagulation, pt, normal, seconds,11,13.5
|
167 |
+
coagulation, pt, high, seconds,13.6,40
|
168 |
+
coagulation, aptt, low, seconds,0,25
|
169 |
+
coagulation, aptt, normal, seconds,26,35
|
170 |
+
coagulation, aptt, high, seconds,36,70
|
171 |
+
coagulation, fibrinogen, low, mg/dL,0,200
|
172 |
+
coagulation, fibrinogen, normal, mg/dL,201,400
|
173 |
+
coagulation, fibrinogen, high, mg/dL,401,800
|
174 |
+
hormone, cortisol, low, mcg/dL,0,5
|
175 |
+
hormone, cortisol, normal, mcg/dL,6,23
|
176 |
+
hormone, cortisol, high, mcg/dL,24,50
|
177 |
+
hormone, testosterone, low, ng/dL,0,299
|
178 |
+
hormone, testosterone, normal, ng/dL,300,1000
|
179 |
+
hormone, testosterone, high, ng/dL,1001,1500
|
180 |
+
hormone, estradiol, low, pg/mL,0,20
|
181 |
+
hormone, estradiol, normal, pg/mL,21,350
|
182 |
+
hormone, estradiol, high, pg/mL,351,1000
|
183 |
+
hormone, progesterone, low, ng/mL,0,0.5
|
184 |
+
hormone, progesterone, normal, ng/mL,0.6,20
|
185 |
+
hormone, progesterone, high, ng/mL,21,100
|
186 |
+
infection, procalcitonin, low, ng/mL,0,0.05
|
187 |
+
infection, procalcitonin, normal, ng/mL,0.06,0.5
|
188 |
+
infection, procalcitonin, high, ng/mL,0.51,2
|
189 |
+
infection, procalcitonin, very-high, ng/mL,2.1,100
|
190 |
+
infection, lactate, normal, mmol/L,0,2
|
191 |
+
infection, lactate, high, mmol/L,2.1,4
|
192 |
+
infection, lactate, critical, mmol/L,4.1,20
|
193 |
+
kidney, urine-protein, normal, mg/dL,0,14
|
194 |
+
kidney, urine-protein, high, mg/dL,15,300
|
195 |
+
kidney, urine-protein, very-high, mg/dL,301,5000
|
196 |
+
kidney, urine-albumin, normal, mg/L,0,30
|
197 |
+
kidney, urine-albumin, microalbuminuria, mg/L,31,300
|
198 |
+
kidney, urine-albumin, macroalbuminuria, mg/L,301,5000
|
199 |
+
kidney, urine protein, normal, mg/dL,0,14
|
200 |
+
kidney, urine protein, high, mg/dL,15,300
|
201 |
+
kidney, urine protein, very-high, mg/dL,301,5000
|
202 |
+
kidney, urine albumin, normal, mg/L,0,30
|
203 |
+
kidney, urine albumin, microalbuminuria, mg/L,31,300
|
204 |
+
kidney, urine albumin, macroalbuminuria, mg/L,301,5000
|
205 |
+
cardiac, total-cholesterol, desirable, mg/dL,0,199
|
206 |
+
cardiac, total-cholesterol, borderline-high, mg/dL,200,239
|
207 |
+
cardiac, total-cholesterol, high, mg/dL,240,400
|
208 |
+
cardiac, total cholesterol, desirable, mg/dL,0,199
|
209 |
+
cardiac, total cholesterol, borderline-high, mg/dL,200,239
|
210 |
+
cardiac, total cholesterol, high, mg/dL,240,400
|
211 |
+
cardiac, non-hdl, optimal, mg/dL,0,129
|
212 |
+
cardiac, non-hdl, borderline-high, mg/dL,130,159
|
213 |
+
cardiac, non-hdl, high, mg/dL,160,189
|
214 |
+
cardiac, non-hdl, very-high, mg/dL,190,300
|
215 |
+
cardiac, non hdl, optimal, mg/dL,0,129
|
216 |
+
cardiac, non hdl, borderline-high, mg/dL,130,159
|
217 |
+
cardiac, non hdl, high, mg/dL,160,189
|
218 |
+
cardiac, non hdl, very-high, mg/dL,190,300
|
219 |
+
blood-gas, ph, acidic, pH,0,7.34
|
220 |
+
blood-gas, ph, normal, pH,7.35,7.45
|
221 |
+
blood-gas, ph, alkaline, pH,7.46,14
|
222 |
+
blood-gas, hco3, low, mmol/L,0,21
|
223 |
+
blood-gas, hco3, normal, mmol/L,22,28
|
224 |
+
blood-gas, hco3, high, mmol/L,29,40
|
225 |
+
vitals,temperature,low,°C,0,35.9
|
226 |
+
vitals,temperature,normal,°C,36,37.5
|
227 |
+
vitals,temperature,high (fever),°C,37.6,39.4
|
228 |
+
vitals,temperature,very high,°C,39.5,45
|
229 |
+
vitals,heart rate,low (brady),bpm,0,59
|
230 |
+
vitals,heart rate,normal,bpm,60,100
|
231 |
+
vitals,heart rate,high (tachy),bpm,101,200
|
232 |
+
vitals,oxygen-saturation,low (hypoxia),%,0,94
|
233 |
+
vitals,oxygen-saturation,normal,%,95,100
|
234 |
+
vitals,oxygen saturation,low (hypoxia),%,0,94
|
235 |
+
vitals,oxygen saturation,normal,%,95,100
|
236 |
+
vitals,temperature,low,°F,32,96.6
|
237 |
+
vitals,temperature,normal,°F,96.8,99.5
|
238 |
+
vitals,temperature,high (fever),°F,99.7,102.9
|
239 |
+
vitals,temperature,very high,°F,103.1,113
|
profile.html
ADDED
@@ -0,0 +1,624 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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" />
|
6 |
+
<title>Profile - CTRL + ALT + HEAL</title>
|
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 |
+
body {
|
15 |
+
font-family: "Rubik", sans-serif;
|
16 |
+
background-color: var(--latte-cream);
|
17 |
+
color: #333;
|
18 |
+
}
|
19 |
+
.btn-primary {
|
20 |
+
background-color: var(--tropical-indigo);
|
21 |
+
color: white;
|
22 |
+
transition: 0.3s;
|
23 |
+
}
|
24 |
+
.btn-primary:hover {
|
25 |
+
background-color: var(--wisteria);
|
26 |
+
color: #333;
|
27 |
+
}
|
28 |
+
.avatar {
|
29 |
+
width: 128px;
|
30 |
+
height: 128px;
|
31 |
+
border-radius: 50%;
|
32 |
+
object-fit: cover;
|
33 |
+
cursor: pointer;
|
34 |
+
background-color: #e5e7eb;
|
35 |
+
}
|
36 |
+
</style>
|
37 |
+
</head>
|
38 |
+
<body class="text-gray-800 min-h-screen flex flex-col">
|
39 |
+
<!-- Navbar -->
|
40 |
+
<nav
|
41 |
+
class="fixed top-0 left-0 w-full z-50 backdrop-blur-md bg-white/20 border-b border-white/30 shadow-md"
|
42 |
+
>
|
43 |
+
<div
|
44 |
+
class="max-w-6xl mx-auto px-6 py-4 flex justify-between items-center"
|
45 |
+
>
|
46 |
+
<a
|
47 |
+
href="index.html"
|
48 |
+
class="text-2xl font-bold hover:text-[var(--tropical-indigo)] transition"
|
49 |
+
>CTRL + ALT + HEAL</a
|
50 |
+
>
|
51 |
+
<ul class="hidden md:flex space-x-6 font-medium text-gray-800">
|
52 |
+
<li><a href="index.html">Home</a></li>
|
53 |
+
<li><a href="analyzer.html">Analyzer</a></li>
|
54 |
+
<li><a href="profile.html">Profile</a></li>
|
55 |
+
<li><a href="login.html">Logout</a></li>
|
56 |
+
<li><a href="about.html">About</a></li>
|
57 |
+
</ul>
|
58 |
+
<button id="hamburger" class="md:hidden text-2xl">☰</button>
|
59 |
+
</div>
|
60 |
+
</nav>
|
61 |
+
|
62 |
+
<main class="flex-grow container mx-auto px-6 pt-24 space-y-6">
|
63 |
+
<div class="flex justify-between items-center mb-4">
|
64 |
+
|
65 |
+
<button id="togglePastReportsBtn" class="btn-primary px-4 py-2 rounded text-sm">
|
66 |
+
Show/Hide Past Reports
|
67 |
+
</button>
|
68 |
+
</div>
|
69 |
+
|
70 |
+
<!-- Welcome -->
|
71 |
+
<div class="bg-white rounded-lg p-6 shadow">
|
72 |
+
<h2 class="text-2xl font-bold text-[var(--tropical-indigo)] mb-2">
|
73 |
+
Welcome to CTRL + ALT + HEAL! 🎉
|
74 |
+
</h2>
|
75 |
+
<p class="text-gray-700 mb-2">
|
76 |
+
Track progress, crush goals, and vibe with your health journey.
|
77 |
+
</p>
|
78 |
+
</div>
|
79 |
+
<!-- Profile + Stats -->
|
80 |
+
<div class="flex flex-col lg:flex-row gap-6 mt-10 items-stretch">
|
81 |
+
<!-- LEFT: Profile Container -->
|
82 |
+
<div class="flex-1 flex flex-col">
|
83 |
+
<!-- PROFILE VIEW -->
|
84 |
+
<div
|
85 |
+
id="profileViewSection"
|
86 |
+
class="bg-white shadow rounded-lg p-6 flex-1 flex flex-col justify-between"
|
87 |
+
>
|
88 |
+
<div class="flex flex-col lg:flex-row gap-6 items-start">
|
89 |
+
<div class="flex flex-col items-center space-y-4">
|
90 |
+
<img
|
91 |
+
id="profilePic"
|
92 |
+
class="avatar"
|
93 |
+
src=""
|
94 |
+
alt="Profile Picture"
|
95 |
+
/>
|
96 |
+
<input
|
97 |
+
type="file"
|
98 |
+
id="fileInput"
|
99 |
+
accept="image/*"
|
100 |
+
class="hidden"
|
101 |
+
/>
|
102 |
+
<button
|
103 |
+
id="editProfileBtn"
|
104 |
+
class="btn-primary px-4 py-2 rounded"
|
105 |
+
>
|
106 |
+
Edit Profile
|
107 |
+
</button>
|
108 |
+
</div>
|
109 |
+
<div class="flex-1 flex flex-col justify-start space-y-2">
|
110 |
+
<h1 class="text-3xl font-semibold text-gray-800">
|
111 |
+
Your Profile
|
112 |
+
</h1>
|
113 |
+
<p class="text-gray-700">
|
114 |
+
Name: <span id="userName" class="font-medium"></span>
|
115 |
+
</p>
|
116 |
+
<p class="text-gray-700">
|
117 |
+
DOB: <span id="userDOB" class="font-medium"></span>
|
118 |
+
</p>
|
119 |
+
<p class="text-gray-700">
|
120 |
+
Big Things We Should Fix:
|
121 |
+
<span id="userFix" class="font-medium"></span>
|
122 |
+
</p>
|
123 |
+
<p class="text-gray-700">
|
124 |
+
Health Goals: <span id="userGoals" class="font-medium"></span>
|
125 |
+
</p>
|
126 |
+
<p class="text-gray-700">
|
127 |
+
Bio:
|
128 |
+
<span id="userBio" class="font-medium">No bio yet 📝</span>
|
129 |
+
</p>
|
130 |
+
</div>
|
131 |
+
</div>
|
132 |
+
</div>
|
133 |
+
|
134 |
+
<!-- PROFILE EDIT -->
|
135 |
+
<div
|
136 |
+
id="profileEditSection"
|
137 |
+
class="hidden bg-white shadow rounded-lg p-6 flex-1 flex flex-col justify-between"
|
138 |
+
>
|
139 |
+
<div class="flex flex-col sm:flex-row items-start space-x-6">
|
140 |
+
<div class="flex flex-col items-center mb-4 sm:mb-0">
|
141 |
+
<img
|
142 |
+
id="editProfilePic"
|
143 |
+
class="avatar"
|
144 |
+
src=""
|
145 |
+
alt="Profile Picture"
|
146 |
+
/>
|
147 |
+
<input
|
148 |
+
type="file"
|
149 |
+
id="editFileInput"
|
150 |
+
accept="image/*"
|
151 |
+
class="hidden"
|
152 |
+
/>
|
153 |
+
</div>
|
154 |
+
<div class="flex-1">
|
155 |
+
<h1 class="text-3xl font-semibold text-gray-800 mb-4">
|
156 |
+
Edit Profile
|
157 |
+
</h1>
|
158 |
+
<div class="space-y-4">
|
159 |
+
<div>
|
160 |
+
<label
|
161 |
+
for="inputName"
|
162 |
+
class="block text-sm font-medium text-gray-600"
|
163 |
+
>Name</label
|
164 |
+
>
|
165 |
+
<input
|
166 |
+
type="text"
|
167 |
+
id="inputName"
|
168 |
+
class="w-full border border-gray-300 rounded px-3 py-2 focus:ring-2 focus:ring-[var(--tropical-indigo)] focus:outline-none"
|
169 |
+
/>
|
170 |
+
</div>
|
171 |
+
<div>
|
172 |
+
<label
|
173 |
+
for="inputDOB"
|
174 |
+
class="block text-sm font-medium text-gray-600"
|
175 |
+
>Date of Birth</label
|
176 |
+
>
|
177 |
+
<input
|
178 |
+
type="date"
|
179 |
+
id="inputDOB"
|
180 |
+
class="w-full border border-gray-300 rounded px-3 py-2 focus:ring-2 focus:ring-[var(--tropical-indigo)] focus:outline-none"
|
181 |
+
/>
|
182 |
+
</div>
|
183 |
+
<div>
|
184 |
+
<label
|
185 |
+
for="inputFix"
|
186 |
+
class="block text-sm font-medium text-gray-600"
|
187 |
+
>Big Things We Should Fix</label
|
188 |
+
>
|
189 |
+
<textarea
|
190 |
+
id="inputFix"
|
191 |
+
rows="2"
|
192 |
+
class="w-full border border-gray-300 rounded px-3 py-2 focus:ring-2 focus:ring-[var(--tropical-indigo)] focus:outline-none"
|
193 |
+
></textarea>
|
194 |
+
</div>
|
195 |
+
<div>
|
196 |
+
<label
|
197 |
+
for="inputGoals"
|
198 |
+
class="block text-sm font-medium text-gray-600"
|
199 |
+
>Health Goals</label
|
200 |
+
>
|
201 |
+
<textarea
|
202 |
+
id="inputGoals"
|
203 |
+
rows="2"
|
204 |
+
class="w-full border border-gray-300 rounded px-3 py-2 focus:ring-2 focus:ring-[var(--tropical-indigo)] focus:outline-none"
|
205 |
+
></textarea>
|
206 |
+
</div>
|
207 |
+
</div>
|
208 |
+
<div class="flex space-x-2 mt-4">
|
209 |
+
<button
|
210 |
+
id="saveProfileBtn"
|
211 |
+
class="btn-primary px-4 py-2 rounded"
|
212 |
+
>
|
213 |
+
Save
|
214 |
+
</button>
|
215 |
+
<button
|
216 |
+
id="cancelProfileBtn"
|
217 |
+
class="bg-gray-300 text-gray-700 px-4 py-2 rounded hover:bg-gray-400 transition"
|
218 |
+
>
|
219 |
+
Cancel
|
220 |
+
</button>
|
221 |
+
</div>
|
222 |
+
</div>
|
223 |
+
</div>
|
224 |
+
</div>
|
225 |
+
</div>
|
226 |
+
|
227 |
+
<!-- RIGHT: Mini Stats -->
|
228 |
+
<div class="w-full lg:w-1/3 flex flex-col justify-between gap-4">
|
229 |
+
<!-- Reports Uploaded -->
|
230 |
+
<div class="bg-white shadow rounded-lg p-4 flex-1 flex items-center gap-2">
|
231 |
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-[var(--tropical-indigo)]" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
232 |
+
<path stroke-linecap="round" stroke-linejoin="round" d="M3 7h5l2 3h11v11H3V7z" />
|
233 |
+
</svg>
|
234 |
+
<div class="flex-1">
|
235 |
+
<p class="text-sm text-gray-500">Reports Uploaded</p>
|
236 |
+
<p class="font-semibold text-lg" id="reportsCount">0</p>
|
237 |
+
</div>
|
238 |
+
</div>
|
239 |
+
|
240 |
+
<!-- Tests In Range -->
|
241 |
+
<div class="bg-white shadow rounded-lg p-4 flex-1 flex items-center gap-2">
|
242 |
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-green-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
243 |
+
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
|
244 |
+
</svg>
|
245 |
+
<div class="flex-1">
|
246 |
+
<p class="text-sm text-gray-500">Tests In Range In Latest Report</p>
|
247 |
+
<p class="font-semibold text-lg" id="testsInRange">0</p>
|
248 |
+
</div>
|
249 |
+
</div>
|
250 |
+
|
251 |
+
<!-- Tests Out of Range -->
|
252 |
+
<div class="bg-white shadow rounded-lg p-4 flex-1 flex items-center gap-2">
|
253 |
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-red-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
254 |
+
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
255 |
+
</svg>
|
256 |
+
<div class="flex-1">
|
257 |
+
<p class="text-sm text-gray-500">Tests Out of Range In Latest Report</p>
|
258 |
+
<p class="font-semibold text-lg" id="testsOutOfRange">0</p>
|
259 |
+
</div>
|
260 |
+
</div>
|
261 |
+
</div>
|
262 |
+
|
263 |
+
|
264 |
+
</div>
|
265 |
+
|
266 |
+
|
267 |
+
|
268 |
+
|
269 |
+
|
270 |
+
<!-- Reports Section -->
|
271 |
+
<div class="bg-white shadow rounded-lg p-6">
|
272 |
+
<h3 class="text-lg font-semibold text-[var(--tropical-indigo)] mb-3">
|
273 |
+
Your Reports
|
274 |
+
</h3>
|
275 |
+
<div id="reportsSection" class="text-gray-600 text-center space-y-3">
|
276 |
+
<p id="reportStatus">📂 No reports uploaded yet.</p>
|
277 |
+
<a
|
278 |
+
id="sampleReportLink"
|
279 |
+
href="/sample_report.pdf"
|
280 |
+
target="_blank"
|
281 |
+
class="text-blue-600 hover:underline hidden"
|
282 |
+
>sample_report.pdf</a
|
283 |
+
>
|
284 |
+
<div class="mt-2 flex justify-center gap-4">
|
285 |
+
<button id="uploadBtn" class="btn-primary px-4 py-2 rounded" onclick="window.location.href='analyzer.html'">
|
286 |
+
Upload Report
|
287 |
+
</button>
|
288 |
+
<button id="toggleReportBtn" class="btn-primary px-4 py-2 rounded">
|
289 |
+
Use Sample Report
|
290 |
+
</button>
|
291 |
+
</div>
|
292 |
+
</div>
|
293 |
+
</div>
|
294 |
+
</div>
|
295 |
+
|
296 |
+
<!-- Past Reports Section with Number-Line Bars -->
|
297 |
+
<div class="bg-white shadow rounded-lg p-6 mt-6 ">
|
298 |
+
<h3 class="text-lg font-semibold text-[var(--tropical-indigo)] mb-4">
|
299 |
+
Past Reports
|
300 |
+
</h3>
|
301 |
+
<div id="pastReportsSection" class="flex flex-col gap-4 ">
|
302 |
+
<!-- Report 3 -->
|
303 |
+
<div class="flex flex-col bg-[var(--wisteria)] p-4 rounded-lg shadow hover:shadow-md transition">
|
304 |
+
<div class="flex justify-between items-center cursor-pointer report-header" onclick="toggleDetails(this)">
|
305 |
+
<div class="flex items-center gap-3">
|
306 |
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-[var(--tropical-indigo)]" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
307 |
+
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4v16m8-8H4" />
|
308 |
+
</svg>
|
309 |
+
<p class="font-medium text-gray-800">Annual_Physical_Mar2025.pdf</p>
|
310 |
+
</div>
|
311 |
+
<div class="flex gap-2 flex-shrink-0">
|
312 |
+
<span class="px-2 py-1 rounded-full bg-green-200 text-green-800 text-xs font-semibold">In Range: 2</span>
|
313 |
+
<span class="px-2 py-1 rounded-full bg-red-200 text-red-800 text-xs font-semibold">Out of Range: 0</span>
|
314 |
+
</div>
|
315 |
+
</div>
|
316 |
+
<div class="report-details mt-2 hidden w-full bg-white rounded p-3 border border-gray-300 text-gray-700">
|
317 |
+
<ul class="space-y-4 text-sm">
|
318 |
+
<li>
|
319 |
+
<div class="flex justify-between mb-1">
|
320 |
+
<span>Hemoglobin: 14.2 g/dL</span>
|
321 |
+
<span class="text-xs text-gray-500">(12-16)</span>
|
322 |
+
</div>
|
323 |
+
<div class="relative w-full h-4 bg-gray-200 rounded">
|
324 |
+
<div class="absolute h-4 rounded bg-green-400" style="width: 70.5%;"></div>
|
325 |
+
<span class="absolute -top-5 text-xs font-semibold text-gray-800" style="left: 70.5%;">14.2</span>
|
326 |
+
<div class="absolute top-full left-0 w-full flex justify-between mt-1 text-xs text-gray-500">
|
327 |
+
<span>12</span>
|
328 |
+
<span>16</span>
|
329 |
+
</div>
|
330 |
+
</div>
|
331 |
+
</li>
|
332 |
+
<li>
|
333 |
+
<div class="flex justify-between mb-1">
|
334 |
+
<span>Cholesterol: 180 mg/dL</span>
|
335 |
+
<span class="text-xs text-gray-500">(125-200)</span>
|
336 |
+
</div>
|
337 |
+
<div class="relative w-full h-6 bg-gray-200 rounded overflow-hidden">
|
338 |
+
<div class="absolute h-6 rounded bg-green-400" style="width: 90%;"></div>
|
339 |
+
<span class="absolute top-1/2 transform -translate-y-1/2 text-xs font-semibold text-gray-800" style="left: 90%;">180</span>
|
340 |
+
<div class="absolute top-full left-0 w-full flex justify-between mt-1 text-xs text-gray-500">
|
341 |
+
<span>125</span>
|
342 |
+
<span>200</span>
|
343 |
+
</div>
|
344 |
+
</div>
|
345 |
+
</li>
|
346 |
+
</ul>
|
347 |
+
</div>
|
348 |
+
</div>
|
349 |
+
<!-- Report 2 -->
|
350 |
+
<div class="flex flex-col bg-[var(--wisteria)] p-4 rounded-lg shadow hover:shadow-md transition">
|
351 |
+
<div class="flex justify-between items-center cursor-pointer report-header" onclick="toggleDetails(this)">
|
352 |
+
<div class="flex items-center gap-3">
|
353 |
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-[var(--tropical-indigo)]" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
354 |
+
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4v16m8-8H4" />
|
355 |
+
</svg>
|
356 |
+
<p class="font-medium text-gray-800">Checkup_Feb2025.pdf</p>
|
357 |
+
</div>
|
358 |
+
<div class="flex gap-2 flex-shrink-0">
|
359 |
+
<span class="px-2 py-1 rounded-full bg-green-200 text-green-800 text-xs font-semibold">In Range: 1</span>
|
360 |
+
<span class="px-2 py-1 rounded-full bg-red-200 text-red-800 text-xs font-semibold">Out of Range: 1</span>
|
361 |
+
</div>
|
362 |
+
</div>
|
363 |
+
<div class="report-details mt-2 hidden w-full bg-white rounded p-3 border border-gray-300 text-gray-700">
|
364 |
+
<ul class="space-y-4 text-sm">
|
365 |
+
<li>
|
366 |
+
<div class="flex justify-between mb-1">
|
367 |
+
<span>Glucose: 105 mg/dL</span>
|
368 |
+
<span class="text-xs text-gray-500">(70-99)</span>
|
369 |
+
</div>
|
370 |
+
<div class="relative w-full h-4 bg-gray-200 rounded">
|
371 |
+
<div class="absolute h-4 rounded bg-red-400" style="width: calc(105/99*100%);"></div>
|
372 |
+
<span class="absolute -top-5 text-xs font-semibold text-gray-800" style="left: 100%;">105</span>
|
373 |
+
<div class="absolute top-full left-0 w-full flex justify-between mt-1 text-xs text-gray-500">
|
374 |
+
<span>70</span>
|
375 |
+
<span>99</span>
|
376 |
+
</div>
|
377 |
+
</div>
|
378 |
+
</li>
|
379 |
+
<li>
|
380 |
+
<div class="flex justify-between mb-1">
|
381 |
+
<span>Vitamin D: 40 ng/mL</span>
|
382 |
+
<span class="text-xs text-gray-500">(30-100)</span>
|
383 |
+
</div>
|
384 |
+
<div class="relative w-full h-4 bg-gray-200 rounded">
|
385 |
+
<div class="absolute h-4 rounded bg-green-400" style="width: 12.5%;"></div>
|
386 |
+
<span class="absolute -top-5 text-xs font-semibold text-gray-800" style="left: 12.5%;">40</span>
|
387 |
+
<div class="absolute top-full left-0 w-full flex justify-between mt-1 text-xs text-gray-500">
|
388 |
+
<span>30</span>
|
389 |
+
<span>100</span>
|
390 |
+
</div>
|
391 |
+
</div>
|
392 |
+
</li>
|
393 |
+
</ul>
|
394 |
+
</div>
|
395 |
+
</div>
|
396 |
+
<!-- Report 1 -->
|
397 |
+
<div class="flex flex-col bg-[var(--wisteria)] p-4 rounded-lg shadow hover:shadow-md transition">
|
398 |
+
<div class="flex justify-between items-center cursor-pointer report-header" onclick="toggleDetails(this)">
|
399 |
+
<div class="flex items-center gap-3">
|
400 |
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-[var(--tropical-indigo)]" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
401 |
+
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4v16m8-8H4" />
|
402 |
+
</svg>
|
403 |
+
<p class="font-medium text-gray-800">Bloodwork_Jan2025.pdf</p>
|
404 |
+
</div>
|
405 |
+
<div class="flex gap-2 flex-shrink-0">
|
406 |
+
<span class="px-2 py-1 rounded-full bg-green-200 text-green-800 text-xs font-semibold">In Range: 1</span>
|
407 |
+
<span class="px-2 py-1 rounded-full bg-red-200 text-red-800 text-xs font-semibold">Out of Range: 1</span>
|
408 |
+
</div>
|
409 |
+
</div>
|
410 |
+
<div class="report-details mt-2 hidden w-full bg-white rounded p-3 border border-gray-300 text-gray-700">
|
411 |
+
<ul class="space-y-4 text-sm">
|
412 |
+
<li>
|
413 |
+
<div class="flex justify-between mb-1">
|
414 |
+
<span>Hemoglobin: 13.5 g/dL</span>
|
415 |
+
<span class="text-xs text-gray-500">(12-16)</span>
|
416 |
+
</div>
|
417 |
+
<div class="relative w-full h-4 bg-gray-200 rounded">
|
418 |
+
<div class="absolute h-4 rounded bg-green-400" style="width: 56.25%;"></div>
|
419 |
+
<span class="absolute -top-5 text-xs font-semibold text-gray-800" style="left: 56.25%;">13.5</span>
|
420 |
+
<div class="absolute top-full left-0 w-full flex justify-between mt-1 text-xs text-gray-500">
|
421 |
+
<span>12</span>
|
422 |
+
<span>16</span>
|
423 |
+
</div>
|
424 |
+
</div>
|
425 |
+
</li>
|
426 |
+
<li>
|
427 |
+
<div class="flex justify-between mb-1">
|
428 |
+
<span>Cholesterol: 210 mg/dL</span>
|
429 |
+
<span class="text-xs text-gray-500">(125-200)</span>
|
430 |
+
</div>
|
431 |
+
<div class="relative w-full h-6 bg-gray-200 rounded overflow-hidden">
|
432 |
+
<div class="absolute h-6 rounded" style="width: calc(min(210/200*100%, 100%)); background-color: #f87171;"></div>
|
433 |
+
<span class="absolute top-1/2 transform -translate-y-1/2 text-xs font-semibold text-gray-800" style="left: calc(min(210/200*100%, 95%));">210</span>
|
434 |
+
<div class="absolute top-full left-0 w-full flex justify-between mt-1 text-xs text-gray-500">
|
435 |
+
<span>125</span>
|
436 |
+
<span>200</span>
|
437 |
+
</div>
|
438 |
+
</div>
|
439 |
+
</li>
|
440 |
+
</ul>
|
441 |
+
</div>
|
442 |
+
</div>
|
443 |
+
|
444 |
+
|
445 |
+
|
446 |
+
|
447 |
+
|
448 |
+
</div>
|
449 |
+
</div>
|
450 |
+
|
451 |
+
<script>
|
452 |
+
function toggleDetails(element) {
|
453 |
+
const details = element.parentElement.querySelector('.report-details');
|
454 |
+
if (details) details.classList.toggle('hidden');
|
455 |
+
}
|
456 |
+
</script>
|
457 |
+
|
458 |
+
|
459 |
+
|
460 |
+
</main>
|
461 |
+
|
462 |
+
|
463 |
+
|
464 |
+
<footer class="py-6 bg-[var(--wisteria)] text-gray-800 mt-8">
|
465 |
+
<div
|
466 |
+
class="max-w-6xl mx-auto px-6 flex flex-col md:flex-row justify-between items-center text-sm"
|
467 |
+
>
|
468 |
+
<p>© 2025 CTRL + ALT + HEAL. All rights reserved.</p>
|
469 |
+
<div class="flex space-x-4 mt-3 md:mt-0">
|
470 |
+
<a href="#" class="hover:text-[var(--tropical-indigo)] transition"
|
471 |
+
>Privacy Policy</a
|
472 |
+
>
|
473 |
+
<a href="#" class="hover:text-[var(--tropical-indigo)] transition"
|
474 |
+
>Terms of Service</a
|
475 |
+
>
|
476 |
+
</div>
|
477 |
+
</div>
|
478 |
+
</footer>
|
479 |
+
|
480 |
+
<script>
|
481 |
+
// Profile Section
|
482 |
+
const profileView = document.getElementById("profileViewSection");
|
483 |
+
const profileEdit = document.getElementById("profileEditSection");
|
484 |
+
const editBtn = document.getElementById("editProfileBtn");
|
485 |
+
const saveBtn = document.getElementById("saveProfileBtn");
|
486 |
+
const cancelBtn = document.getElementById("cancelProfileBtn");
|
487 |
+
|
488 |
+
const inputName = document.getElementById("inputName");
|
489 |
+
const inputDOB = document.getElementById("inputDOB");
|
490 |
+
const inputFix = document.getElementById("inputFix");
|
491 |
+
const inputGoals = document.getElementById("inputGoals");
|
492 |
+
|
493 |
+
const profilePic = document.getElementById("profilePic");
|
494 |
+
const editProfilePic = document.getElementById("editProfilePic");
|
495 |
+
const fileInput = document.getElementById("fileInput");
|
496 |
+
const editFileInput = document.getElementById("editFileInput");
|
497 |
+
|
498 |
+
editBtn.addEventListener("click", () => {
|
499 |
+
inputName.value = localStorage.getItem("userName") || "";
|
500 |
+
inputDOB.value = localStorage.getItem("userDOB") || "";
|
501 |
+
inputFix.value = localStorage.getItem("userFix") || "";
|
502 |
+
inputGoals.value = localStorage.getItem("userGoals") || "";
|
503 |
+
profileView.classList.add("hidden");
|
504 |
+
profileEdit.classList.remove("hidden");
|
505 |
+
});
|
506 |
+
|
507 |
+
cancelBtn.addEventListener("click", () => {
|
508 |
+
profileEdit.classList.add("hidden");
|
509 |
+
profileView.classList.remove("hidden");
|
510 |
+
});
|
511 |
+
|
512 |
+
saveBtn.addEventListener("click", () => {
|
513 |
+
localStorage.setItem("userName", inputName.value.trim());
|
514 |
+
localStorage.setItem("userDOB", inputDOB.value);
|
515 |
+
localStorage.setItem("userFix", inputFix.value.trim());
|
516 |
+
localStorage.setItem("userGoals", inputGoals.value.trim());
|
517 |
+
|
518 |
+
document.getElementById("userName").textContent =
|
519 |
+
inputName.value.trim() || "Name";
|
520 |
+
document.getElementById("userDOB").textContent =
|
521 |
+
inputDOB.value || "DOB";
|
522 |
+
document.getElementById("userFix").textContent =
|
523 |
+
inputFix.value.trim() || "None set";
|
524 |
+
document.getElementById("userGoals").textContent =
|
525 |
+
inputGoals.value.trim() || "None set";
|
526 |
+
|
527 |
+
profileEdit.classList.add("hidden");
|
528 |
+
profileView.classList.remove("hidden");
|
529 |
+
});
|
530 |
+
|
531 |
+
profilePic.addEventListener("click", () => fileInput.click());
|
532 |
+
editProfilePic.addEventListener("click", () => editFileInput.click());
|
533 |
+
|
534 |
+
function handleFileUpload(file, targetImg) {
|
535 |
+
const reader = new FileReader();
|
536 |
+
reader.onload = () => {
|
537 |
+
targetImg.src = reader.result;
|
538 |
+
localStorage.setItem("profilePic", reader.result);
|
539 |
+
};
|
540 |
+
reader.readAsDataURL(file);
|
541 |
+
}
|
542 |
+
|
543 |
+
fileInput.addEventListener("change", (e) => {
|
544 |
+
if (e.target.files[0]) handleFileUpload(e.target.files[0], profilePic);
|
545 |
+
});
|
546 |
+
editFileInput.addEventListener("change", (e) => {
|
547 |
+
if (e.target.files[0])
|
548 |
+
handleFileUpload(e.target.files[0], editProfilePic);
|
549 |
+
});
|
550 |
+
|
551 |
+
// Load saved profile
|
552 |
+
document.addEventListener("DOMContentLoaded", () => {
|
553 |
+
document.getElementById("userName").textContent =
|
554 |
+
localStorage.getItem("userName") || "Name";
|
555 |
+
document.getElementById("userDOB").textContent =
|
556 |
+
localStorage.getItem("userDOB") || "DOB";
|
557 |
+
document.getElementById("userFix").textContent =
|
558 |
+
localStorage.getItem("userFix") || "None set";
|
559 |
+
document.getElementById("userGoals").textContent =
|
560 |
+
localStorage.getItem("userGoals") || "None set";
|
561 |
+
|
562 |
+
const savedPic = localStorage.getItem("profilePic");
|
563 |
+
if (savedPic) {
|
564 |
+
profilePic.src = savedPic;
|
565 |
+
editProfilePic.src = savedPic;
|
566 |
+
}
|
567 |
+
});
|
568 |
+
const pastReportsSection = document.getElementById("pastReportsSection");
|
569 |
+
const togglePastReportsBtn = document.getElementById("togglePastReportsBtn");
|
570 |
+
|
571 |
+
togglePastReportsBtn.addEventListener("click", () => {
|
572 |
+
pastReportsSection.classList.toggle("hidden");
|
573 |
+
});
|
574 |
+
|
575 |
+
|
576 |
+
// Toggle Sample Report
|
577 |
+
const reportsCountEl = document.getElementById("reportsCount");
|
578 |
+
const goalsCompletedEl = document.getElementById("goalsCompleted");
|
579 |
+
const achievementsEl = document.getElementById("achievements");
|
580 |
+
const reportStatusEl = document.getElementById("reportStatus");
|
581 |
+
const sampleReportLink = document.getElementById("sampleReportLink");
|
582 |
+
const toggleReportBtn = document.getElementById("toggleReportBtn");
|
583 |
+
|
584 |
+
let sampleActive = false;
|
585 |
+
|
586 |
+
const sampleReport = {
|
587 |
+
name: "sample_report.pdf",
|
588 |
+
goalsCompleted: 2,
|
589 |
+
totalGoals: 2,
|
590 |
+
improvements: ["Hydration", "Sleep", "Exercise"],
|
591 |
+
};
|
592 |
+
function updateMiniStats() {
|
593 |
+
if (sampleActive) {
|
594 |
+
reportsCountEl.textContent = 1;
|
595 |
+
|
596 |
+
// Count tests in range vs out of range
|
597 |
+
const inRange = sampleReport.goalsCompleted; // using sample data
|
598 |
+
const outOfRange = sampleReport.totalGoals - sampleReport.goalsCompleted;
|
599 |
+
|
600 |
+
document.getElementById("testsInRange").textContent = inRange;
|
601 |
+
document.getElementById("testsOutOfRange").textContent = outOfRange;
|
602 |
+
|
603 |
+
reportStatusEl.textContent = "📂 Sample report uploaded!";
|
604 |
+
sampleReportLink.classList.remove("hidden");
|
605 |
+
} else {
|
606 |
+
reportsCountEl.textContent = 0;
|
607 |
+
document.getElementById("testsInRange").textContent = 0;
|
608 |
+
document.getElementById("testsOutOfRange").textContent = 0;
|
609 |
+
reportStatusEl.textContent = "📂 No reports uploaded yet.";
|
610 |
+
sampleReportLink.classList.add("hidden");
|
611 |
+
}
|
612 |
+
}
|
613 |
+
|
614 |
+
|
615 |
+
toggleReportBtn.addEventListener("click", () => {
|
616 |
+
sampleActive = !sampleActive;
|
617 |
+
updateMiniStats();
|
618 |
+
});
|
619 |
+
|
620 |
+
updateMiniStats();
|
621 |
+
|
622 |
+
</script>
|
623 |
+
</body>
|
624 |
+
</html>
|
request_responses.py
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel
|
2 |
+
from typing import Optional
|
3 |
+
class AnalysisResponse(BaseModel):
|
4 |
+
findings: str
|
5 |
+
severity: str
|
6 |
+
recommendations: list[str]
|
7 |
+
treatment_suggestions: str
|
8 |
+
home_care_guidance: list[str]
|
9 |
+
info_link: str
|
10 |
+
|
11 |
+
class ChatRequest(BaseModel):
|
12 |
+
question: str
|
13 |
+
|
14 |
+
class ChatResponse(BaseModel):
|
15 |
+
answer: str
|
16 |
+
|
17 |
+
class TextRequest(BaseModel):
|
18 |
+
text: str
|
requirements.txt
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
fastapi==0.95.2
|
2 |
+
uvicorn==0.22.0
|
3 |
+
pydantic==1.10.11
|
4 |
+
python-multipart==0.0.6
|
5 |
+
pytesseract==0.3.10
|
6 |
+
Pillow==10.0.0
|
7 |
+
PyMuPDF==1.22.5
|
8 |
+
pandas==2.0.3
|
9 |
+
regex==2023.8.8
|
10 |
+
spacy==3.6.0
|
11 |
+
negspacy>=1.0.0
|
12 |
+
fuzzywuzzy==0.18.0
|
13 |
+
python-Levenshtein==0.21.1
|
14 |
+
transformers==4.32.0
|
15 |
+
torch==2.0.1
|
16 |
+
opencv-python==4.7.0.72
|
17 |
+
numpy==1.25.2
|
18 |
+
google-generativeai==0.3.1
|
19 |
+
spacy-transformers==1.3.9
|
20 |
+
python-dotenv==1.0.1
|
util.py
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from PIL import Image
|
2 |
+
import io
|
3 |
+
import fitz
|
4 |
+
import re
|
5 |
+
import pytesseract
|
6 |
+
import google.generativeai as genai
|
7 |
+
from fastapi import FastAPI, UploadFile, File, Form, HTTPException
|
8 |
+
from fastapi.middleware.cors import CORSMiddleware
|
9 |
+
import platform
|
10 |
+
|
11 |
+
def extract_images_from_pdf_bytes(pdf_bytes: bytes) -> list:
|
12 |
+
doc = fitz.open(stream=pdf_bytes, filetype="pdf")
|
13 |
+
images = []
|
14 |
+
for page in doc:
|
15 |
+
pix = page.get_pixmap()
|
16 |
+
buf = io.BytesIO()
|
17 |
+
buf.write(pix.tobytes("png"))
|
18 |
+
images.append(buf.getvalue())
|
19 |
+
return images
|
20 |
+
|
21 |
+
def clean_ocr_text(text: str) -> str:
|
22 |
+
text = text.replace("\x0c", " ") # remove form feed
|
23 |
+
text = text.replace("\u00a0", " ") # replace NBSP with space
|
24 |
+
text = re.sub(r'(\d)\s*\.\s*(\d)', r'\1.\2', text) # fix split decimals
|
25 |
+
text = re.sub(r'\s+', ' ', text) # collapse multiple spaces/newlines
|
26 |
+
return text.strip()
|
27 |
+
|
28 |
+
|
29 |
+
|
30 |
+
def ocr_text_from_image(image_bytes: bytes) -> str:
|
31 |
+
image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
|
32 |
+
return pytesseract.image_to_string(image)
|
33 |
+
|
34 |
+
|
35 |
+
|
36 |
+
def load_pytesseract():
|
37 |
+
if platform.system() == "Darwin":
|
38 |
+
#pytesseract.pytesseract.tesseract_cmd = '/usr/local/bin/tesseract'
|
39 |
+
pytesseract.pytesseract.tesseract_cmd = '/opt/homebrew/bin/tesseract'
|
40 |
+
elif platform.system() == "Windows":
|
41 |
+
pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
|
42 |
+
|
43 |
+
|
44 |
+
def load_genai(genai_api_key: str):
|
45 |
+
try:
|
46 |
+
genai.configure(api_key=genai_api_key)
|
47 |
+
except Exception as e:
|
48 |
+
raise RuntimeError(f"Failed to configure Gemini API: {e}")
|
49 |
+
|
50 |
+
|
51 |
+
def setupFastAPI()-> FastAPI:
|
52 |
+
app = FastAPI()
|
53 |
+
app.add_middleware(
|
54 |
+
CORSMiddleware,
|
55 |
+
allow_origins=[
|
56 |
+
"http://localhost:8002"
|
57 |
+
"http://localhost:9000"
|
58 |
+
"http://localhost:5501"
|
59 |
+
],
|
60 |
+
allow_credentials=True,
|
61 |
+
allow_methods=["*"],
|
62 |
+
allow_headers=["*"],
|
63 |
+
)
|
64 |
+
return app
|
65 |
+
|