Muhammadidrees commited on
Commit
dad7343
·
verified ·
1 Parent(s): 4d72f2d

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +268 -0
app.py ADDED
@@ -0,0 +1,268 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from pydantic import BaseModel, Field
3
+ from dotenv import load_dotenv
4
+ import google.generativeai as genai
5
+ import os
6
+ import re
7
+ import gradio as gr
8
+ from typing import Dict, Any, Union, List
9
+
10
+
11
+ # ---------------- Initialize ----------------
12
+
13
+ app = FastAPI(title="LLM Model API + Gradio UI", version="4.0")
14
+
15
+ # ✅ Fetch Gemini API Key
16
+ GEMINI_API_KEY = "AIzaSyC0XU6yLCILZFUVhKoIcqoy2k5qwQmnDsc"
17
+ if not GEMINI_API_KEY:
18
+ raise ValueError("❌ GEMINI_API_KEY not found. Please set it in your .env file.")
19
+
20
+ genai.configure(api_key=GEMINI_API_KEY)
21
+ MODEL_ID = "gemini-2.5-flash"
22
+
23
+
24
+ # ---------------- Schema ----------------
25
+ class BiomarkerRequest(BaseModel):
26
+ albumin: float = Field(default=3.2)
27
+ creatinine: float = Field(default=1.4)
28
+ glucose: float = Field(default=145)
29
+ crp: float = Field(default=12.0)
30
+ mcv: float = Field(default=88)
31
+ rdw: float = Field(default=15.5)
32
+ alp: float = Field(default=120)
33
+ wbc: float = Field(default=11.8)
34
+ lymphocytes: float = Field(default=20)
35
+ hb: float = Field(default=13.0)
36
+ pv: float = Field(default=2.1)
37
+ age: int = Field(default=52)
38
+ gender: str = Field(default="female")
39
+ height: float = Field(default=165)
40
+ weight: float = Field(default=70)
41
+
42
+
43
+ # ---------------- Utilities ----------------
44
+ def clean_json(data: Union[Dict, List, str]) -> Union[Dict, List, str]:
45
+ if isinstance(data, str):
46
+ text = re.sub(r"-{3,}", "", data)
47
+ text = re.sub(r"\s+", " ", text)
48
+ text = text.strip(" -\n\t\r")
49
+ return text
50
+ elif isinstance(data, list):
51
+ return [clean_json(i) for i in data if i and clean_json(i)]
52
+ elif isinstance(data, dict):
53
+ return {k.strip(): clean_json(v) for k, v in data.items()}
54
+ return data
55
+
56
+
57
+ # ---------------- Parser ----------------
58
+ def parse_medical_report(text: str):
59
+ def clean_line(line: str) -> str:
60
+ return re.sub(r"[\-\*\u2022]+\s*", "", line.strip())
61
+
62
+ def parse_bold_entities(block: str) -> Dict[str, str]:
63
+ entities = {}
64
+ pattern = re.compile(r"\*\*(.*?)\*\*(.*?)(?=\*\*|###|$)", re.S)
65
+ for match in pattern.finditer(block):
66
+ key = match.group(1).strip().strip(":")
67
+ val = match.group(2).strip().replace("\n", " ")
68
+ val = re.sub(r"\s+", " ", val)
69
+ if key:
70
+ entities[key] = val
71
+ return entities
72
+
73
+ data = {
74
+ "executive_summary": {"top_priorities": [], "key_strengths": []},
75
+ "system_analysis": {},
76
+ "personalized_action_plan": {},
77
+ "interaction_alerts": [],
78
+ "normal_ranges": {},
79
+ "biomarker_table": []
80
+ }
81
+
82
+ exec_match = re.search(r"###\s*Executive Summary(.*?)(?=###|$)", text, re.S | re.I)
83
+ if exec_match:
84
+ block = exec_match.group(1)
85
+ priorities = re.findall(r"\d+\.\s*(.*?)\n", block)
86
+ if priorities:
87
+ data["executive_summary"]["top_priorities"] = [clean_line(p) for p in priorities]
88
+ strengths_match = re.search(r"\*\*Key Strengths:\*\*(.*)", block, re.S)
89
+ if strengths_match:
90
+ strengths_text = strengths_match.group(1)
91
+ strengths = [clean_line(s) for s in strengths_text.splitlines() if clean_line(s)]
92
+ data["executive_summary"]["key_strengths"] = strengths
93
+
94
+ sys_match = re.search(r"###\s*System[- ]Specific Analysis(.*?)(?=###|$)", text, re.S | re.I)
95
+ if sys_match:
96
+ sys_block = sys_match.group(1)
97
+ data["system_analysis"] = parse_bold_entities(sys_block)
98
+
99
+ plan_match = re.search(r"###\s*Personalized Action Plan(.*?)(?=###|$)", text, re.S | re.I)
100
+ if plan_match:
101
+ plan_block = plan_match.group(1)
102
+ data["personalized_action_plan"] = parse_bold_entities(plan_block)
103
+
104
+ alerts_match = re.search(r"###\s*Interaction Alerts(.*?)(?=###|$)", text, re.S | re.I)
105
+ if alerts_match:
106
+ alerts_block = alerts_match.group(1)
107
+ alerts = [clean_line(a) for a in alerts_block.splitlines() if clean_line(a)]
108
+ data["interaction_alerts"] = alerts
109
+
110
+ normal_match = re.search(r"###\s*Normal Ranges(.*?)(?=###|$)", text, re.S | re.I)
111
+ if normal_match:
112
+ normal_block = normal_match.group(1)
113
+ for match in re.findall(r"-\s*([^:]+):\s*([^\n]+)", normal_block):
114
+ biomarker, rng = match
115
+ data["normal_ranges"][biomarker.strip()] = rng.strip()
116
+
117
+ table_match = re.search(r"###\s*Tabular Mapping(.*)", text, re.S | re.I)
118
+ if table_match:
119
+ table_block = table_match.group(1)
120
+ table_pattern = r"\|\s*([^|]+)\s*\|\s*([^|]+)\s*\|\s*([^|]+)\s*\|\s*([^|]+)\s*\|\s*([^|]+)\s*\|"
121
+ for biomarker, value, status, insight, ref in re.findall(table_pattern, table_block):
122
+ if not any([biomarker, value, status, insight, ref]):
123
+ continue
124
+ data["biomarker_table"].append({
125
+ "biomarker": biomarker.strip(),
126
+ "value": value.strip(),
127
+ "status": status.strip(),
128
+ "insight": insight.strip(),
129
+ "reference_range": ref.strip(),
130
+ })
131
+
132
+ return data
133
+
134
+
135
+ # ---------------- Prediction Core ----------------
136
+ def generate_report(data: BiomarkerRequest) -> str:
137
+ """Main logic — uses Gemini to generate markdown medical report"""
138
+ prompt = """
139
+ You are an advanced **Medical Insight Generation AI** trained to analyze **biomarkers and lab results**.
140
+
141
+ ⚠️ IMPORTANT — OUTPUT FORMAT INSTRUCTIONS:
142
+ Return your report in this strict markdown structure.
143
+
144
+ ------------------------------
145
+ ### Executive Summary
146
+ **Top 3 Health Priorities:**
147
+ 1. ...
148
+ 2. ...
149
+ 3. ...
150
+
151
+ **Key Strengths:**
152
+ - ...
153
+ - ...
154
+
155
+ ------------------------------
156
+ ### System-Specific Analysis
157
+ **Cardiovascular System**
158
+ Status: Normal. Explanation: ...
159
+
160
+ **Liver Function**
161
+ Status: Elevated ALP. Explanation: ...
162
+
163
+ ------------------------------
164
+ ### Personalized Action Plan
165
+ **Nutrition:** ...
166
+ **Lifestyle:** ...
167
+ **Testing:** ...
168
+ **Medical Consultation:** ...
169
+
170
+ ------------------------------
171
+ ### Interaction Alerts
172
+ - ...
173
+ - ...
174
+
175
+ ------------------------------
176
+ ### Normal Ranges
177
+ - Albumin: 3.5–5.0 g/dL
178
+ - Creatinine: 0.7–1.3 mg/dL
179
+ - Glucose: 70–100 mg/dL
180
+ - CRP: 0–10 mg/L
181
+ - MCV: 80–100 fL
182
+ - RDW: 11.5–14.5 %
183
+ - ALP: 44–147 U/L
184
+ - WBC: 4.0–10.0 ×10^3/μL
185
+ - Lymphocytes: 20–40 %
186
+ - Hemoglobin: 13–17 g/dL
187
+ - PV: 2500–3000 mL
188
+
189
+ ------------------------------
190
+ ### Tabular Mapping
191
+ | Biomarker | Value | Status | Insight | Reference Range |
192
+ | Albumin | X | Normal | ... | 3.5–5.0 g/dL |
193
+ | Creatinine | X | High | ... | 0.7–1.3 mg/dL |
194
+ | Glucose | X | ... | ... | 70–100 mg/dL |
195
+ ------------------------------
196
+ """
197
+
198
+ user_message = f"""
199
+ Patient Info:
200
+ - Age: {data.age}
201
+ - Gender: {data.gender}
202
+ - Height: {data.height} cm
203
+ - Weight: {data.weight} kg
204
+
205
+ Biomarkers:
206
+ - Albumin: {data.albumin} g/dL
207
+ - Creatinine: {data.creatinine} mg/dL
208
+ - Glucose: {data.glucose} mg/dL
209
+ - CRP: {data.crp} mg/L
210
+ - MCV: {data.mcv} fL
211
+ - RDW: {data.rdw} %
212
+ - ALP: {data.alp} U/L
213
+ - WBC: {data.wbc} ×10^3/μL
214
+ - Lymphocytes: {data.lymphocytes} %
215
+ - Hemoglobin: {data.hb} g/dL
216
+ - Plasma Volume (PV): {data.pv} mL
217
+ """
218
+
219
+ model = genai.GenerativeModel(MODEL_ID)
220
+ response = model.generate_content(f"{prompt}\n\n{user_message}")
221
+
222
+ if not response or not getattr(response, "text", None):
223
+ return "⚠️ Gemini returned an empty response."
224
+
225
+ return response.text.strip()
226
+
227
+
228
+ # ---------------- Gradio Interface ----------------
229
+ def gradio_interface(albumin, creatinine, glucose, crp, mcv, rdw, alp, wbc,
230
+ lymphocytes, hb, pv, age, gender, height, weight):
231
+ req = BiomarkerRequest(
232
+ albumin=albumin, creatinine=creatinine, glucose=glucose, crp=crp,
233
+ mcv=mcv, rdw=rdw, alp=alp, wbc=wbc, lymphocytes=lymphocytes,
234
+ hb=hb, pv=pv, age=int(age), gender=gender, height=height, weight=weight
235
+ )
236
+ report = generate_report(req)
237
+ return report
238
+
239
+
240
+ iface = gr.Interface(
241
+ fn=gradio_interface,
242
+ inputs=[
243
+ gr.Number(label="Albumin (g/dL)", value=3.2),
244
+ gr.Number(label="Creatinine (mg/dL)", value=1.4),
245
+ gr.Number(label="Glucose (mg/dL)", value=145),
246
+ gr.Number(label="CRP (mg/L)", value=12.0),
247
+ gr.Number(label="MCV (fL)", value=88),
248
+ gr.Number(label="RDW (%)", value=15.5),
249
+ gr.Number(label="ALP (U/L)", value=120),
250
+ gr.Number(label="WBC (×10³/μL)", value=11.8),
251
+ gr.Number(label="Lymphocytes (%)", value=20),
252
+ gr.Number(label="Hemoglobin (g/dL)", value=13.0),
253
+ gr.Number(label="Plasma Volume (L)", value=2.1),
254
+ gr.Number(label="Age (years)", value=52),
255
+ gr.Radio(["male", "female"], label="Gender", value="female"),
256
+ gr.Number(label="Height (cm)", value=165),
257
+ gr.Number(label="Weight (kg)", value=70)
258
+ ],
259
+ outputs=gr.Markdown(label="🩺 AI Medical Report"),
260
+ title="LLM Biomarker Analyzer",
261
+ description="Enter your biomarker and demographic data to generate a detailed AI-based medical report (Gemini-powered).",
262
+ theme="soft",
263
+ allow_flagging="never"
264
+ )
265
+
266
+ # ---------------- Launch ----------------
267
+ if __name__ == "__main__":
268
+ iface.launch(server_name="0.0.0.0", server_port=7860)