Muhammadidrees commited on
Commit
5c8b937
·
verified ·
1 Parent(s): a5b4042

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +84 -220
app.py CHANGED
@@ -3,47 +3,50 @@ import gradio as gr
3
  from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
4
  import os
5
  import torch
6
- import re
7
 
8
-
9
- MODEL_ID = "Muhammadidrees/my-biomed"
 
 
 
 
 
 
10
 
11
  # -----------------------
12
- # Load tokenizer + model safely (GPU or CPU)
 
13
  # -----------------------
14
  tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
15
 
16
- # Try a few loading strategies so this works on GPU or CPU Spaces
17
  try:
18
- # Preferred: let HF decide device placement (works for GPU-enabled Spaces)
19
- model = AutoModelForCausalLM.from_pretrained(MODEL_ID)
20
- except Exception:
21
- # Fallback: force CPU (slower but safe)
22
- model = AutoModelForCausalLM.from_pretrained(MODEL_ID, torch_dtype=torch.float32, low_cpu_mem_usage=True)
 
 
 
 
 
 
 
 
23
 
24
- # Create pipeline
25
- pipe = pipeline("text-generation", model=model, tokenizer=tokenizer, device=0 if torch.cuda.is_available() else -1)
 
 
 
 
26
 
27
  # -----------------------
28
- # Helper: robust section splitter
29
  # -----------------------
30
- def split_report(text):
31
- """
32
- Split model output into left (sections 1-4) and right (sections 5-6).
33
- Accepts various markers for robustness.
34
- """
35
- # Normalize whitespace
36
  text = text.strip()
37
- # Common markers that indicate tabular/insights section
38
- markers = [
39
- "5. Tabular Mapping",
40
- "5. Tabular",
41
- "Tabular Mapping",
42
- "Tabular & AI Insights",
43
- "📊 Tabular",
44
- "## 5",
45
- ]
46
- # Find earliest marker occurrence
47
  idx = None
48
  for m in markers:
49
  pos = text.find(m)
@@ -51,28 +54,16 @@ def split_report(text):
51
  if idx is None or pos < idx:
52
  idx = pos
53
  if idx is None:
54
- # fallback: try splitting at "Enhanced AI Insights" or "Enhanced AI"
55
- fallback = text.find("Enhanced AI Insights")
56
- if fallback == -1:
57
- fallback = text.find("Enhanced AI")
58
- idx = fallback if fallback != -1 else None
59
-
60
- if idx is None:
61
- # couldn't find a split marker -> put everything in left
62
  return text, ""
63
- left = text[:idx].strip()
64
- right = text[idx:].strip()
65
- return left, right
66
-
67
 
68
  # -----------------------
69
- # The analyze function
70
  # -----------------------
71
  def analyze(
72
  albumin, creatinine, glucose, crp, mcv, rdw, alp,
73
  wbc, lymph, age, gender, height, weight
74
  ):
75
- # Validate/constrain inputs
76
  try:
77
  age = int(age)
78
  except Exception:
@@ -84,206 +75,81 @@ def analyze(
84
  except Exception:
85
  bmi = "N/A"
86
 
87
- # Reference Ranges (used for comparison)
88
- reference_ranges = {
89
- "Albumin": (3.5, 5.0),
90
- "Creatinine": (0.6, 1.2),
91
- "Glucose": (70, 99),
92
- "CRP": (0, 3),
93
- "MCV": (80, 100),
94
- "RDW": (11.5, 14.5),
95
- "ALP": (44, 147),
96
- "WBC": (4.0, 11.0),
97
- "Lymphocytes": (20, 40),
98
- }
99
-
100
- # Function to classify biomarker status
101
- def classify_status(value, biomarker):
102
- low, high = reference_ranges[biomarker]
103
- if value < low:
104
- return "Low"
105
- elif value > high:
106
- return "High"
107
- else:
108
- return "Normal"
109
-
110
- # Biomarker status calculations
111
- biomarkers = {
112
- "Albumin": classify_status(float(albumin), "Albumin"),
113
- "Creatinine": classify_status(float(creatinine), "Creatinine"),
114
- "Glucose": classify_status(float(glucose), "Glucose"),
115
- "CRP": classify_status(float(crp), "CRP"),
116
- "MCV": classify_status(float(mcv), "MCV"),
117
- "RDW": classify_status(float(rdw), "RDW"),
118
- "ALP": classify_status(float(alp), "ALP"),
119
- "WBC": classify_status(float(wbc), "WBC"),
120
- "Lymphocytes": classify_status(float(lymph), "Lymphocytes"),
121
- }
122
-
123
- # Prepare the system prompt with biomarkers and patient info
124
  system_prompt = (
125
- "You are a professional AI Medical Assistant.\n"
126
- "You are analyzing patient demographics (age, height, weight) and Levine biomarker panel values.\n\n"
127
-
128
- "The Levine biomarker panel includes:\n"
129
- "- Albumin\n"
130
- "- Creatinine\n"
131
- "- Glucose\n"
132
- "- C-reactive protein (CRP)\n"
133
- "- Mean Cell Volume (MCV)\n"
134
- "- Red Cell Distribution Width (RDW)\n"
135
- "- Alkaline Phosphatase (ALP)\n"
136
- "- White Blood Cell count (WBC)\n"
137
- "- Lymphocyte percentage\n\n"
138
-
139
- "Reference Ranges (always use these as ground truth):\n"
140
- "- Albumin: 3.5 5.0 g/dL\n"
141
- "- Creatinine: 0.6 1.2 mg/dL\n"
142
- "- Glucose (fasting): 70 99 mg/dL\n"
143
- "- CRP: < 3 mg/L\n"
144
- "- MCV: 80 – 100 fL\n"
145
- "- RDW: 11.5 – 14.5 %\n"
146
- "- ALP: 44 – 147 U/L\n"
147
- "- WBC: 4.0 – 11.0 K/uL\n"
148
- "- Lymphocytes: 20 – 40 %\n\n"
149
-
150
- "Check input of the user according to these ranges and provide analysis in a structured format.\n"
151
- "Strict rules:\n"
152
- "- Use ONLY the 9 biomarkers above + age, height, weight.\n"
153
- "- DO NOT use or invent other lab results (e.g., cholesterol, vitamin D, ferritin, ALT, AST, urine results).\n"
154
- "- Status (Low/Normal/High) must be strictly defined by whether the value falls below, within, or above the provided reference ranges.\n"
155
- "- Analysis must always explain deviations with respect to these reference ranges.\n"
156
- "- If a section cannot be addressed with available data, explicitly state: 'Not available from current biomarkers.'\n"
157
- "- Nutrient status (Iron, B12, Folate) can only be suggested as possible IF supported by MCV + RDW patterns, but never stated as confirmed.\n"
158
- "- Interpret ALP cautiously: mention bone vs liver as possible sources, but highlight that more tests would be required to confirm.\n"
159
- "- Always highlight limitations where applicable.\n\n"
160
-
161
- "OUTPUT FORMAT (strict, structured, and professional):\n\n"
162
-
163
- "1. Executive Summary\n"
164
- " - Top Priority Issues (based only on provided biomarkers and their ranges)\n"
165
- " - Key Strengths\n\n"
166
-
167
- "2. System-Specific Analysis\n"
168
- " - Blood Health (MCV, RDW, Lymphocytes, WBC)\n"
169
- " - Protein & Liver Health (Albumin, ALP)\n"
170
- " - Kidney Health (Creatinine)\n"
171
- " - Metabolic Health (Glucose, CRP)\n"
172
- " - Anthropometrics (Age, Height, Weight, BMI)\n"
173
- " - Other systems: Always state 'Not available from current biomarkers.' if data is missing\n\n"
174
-
175
- "3. Personalized Action Plan\n"
176
- " - Medical (tests/consults related only to biomarkers — e.g., repeat CBC, iron studies if anemia suspected)\n"
177
- " - Nutrition (diet & supplements grounded ONLY in biomarker findings — e.g., protein intake if albumin low, anti-inflammatory foods if CRP elevated)\n"
178
- " - Lifestyle (hydration, exercise, sleep — general guidance contextualized by BMI and biomarkers)\n"
179
- " - Testing (only mention ferritin, B12, folate, GGT, etc. as follow-up — but clarify these are NOT part of current data)\n\n"
180
-
181
- "4. Interaction Alerts\n"
182
- " - Describe ONLY interactions among provided biomarkers (e.g., RDW with MCV for anemia trends, ALP bone/liver origin, WBC with CRP for infection/inflammation)\n\n"
183
-
184
- "5. Tabular Mapping\n"
185
- " - This section must always include a Markdown table.\n"
186
- " - The table must contain exactly five columns:\n"
187
- " - The Reference Range column must be populated with the ranges given in the Patient Summary.\n"
188
- " - The first row after the header must begin directly with 'Albumin'.\n"
189
- " - Do NOT add any index numbers (0,1,2...) or empty rows.\n"
190
- " - Each biomarker must appear exactly once as a separate row.\n\n"
191
-
192
- " - Each status column must be calculated by keeping the reference range in memory.\n"
193
- " - The table must contain the following structure:\n"
194
- " | Biomarker | Value | Reference Range |Status (Low/Normal/High)| AI-Inferred Insight |\n"
195
-
196
- "6. Enhanced AI Insights & Longitudinal Risk\n"
197
- " - Subclinical nutrient predictions ONLY if patterns (MCV + RDW) suggest it — state as possible, not confirmed.\n"
198
- " - ALP interpretation limited to bone vs liver origin (uncertain without further tests).\n"
199
- " - WBC & lymphocyte balance for immunity.\n"
200
- " - Risk framing: Highlight if biomarkers suggest resilience or potential stress, but avoid absolute longevity claims.\n\n"
201
-
202
- "STYLE REQUIREMENTS:\n"
203
- "- Use clear section headings and bullet points.\n"
204
- "- Keep language professional, concise, and client-friendly.\n"
205
- "- Format tables cleanly in Markdown.\n"
206
- "- Present output beautifully, like a polished medical summary.\n"
207
  )
208
 
209
  patient_input = (
210
- f"Patient Profile:\n"
211
- f"- Age: {age}\n"
212
- f"- Gender: {gender}\n"
213
- f"- Height: {height} cm\n"
214
- f"- Weight: {weight} kg\n"
215
- f"- BMI: {bmi}\n\n"
216
- "Lab Values (with Normal Ranges):\n"
217
- f"- Albumin: {albumin} g/dL (Normal: 3.5 – 5.0 g/dL)\n"
218
- f"- Creatinine: {creatinine} mg/dL (Normal: 0.6 – 1.2 mg/dL)\n"
219
- f"- Glucose: {glucose} mg/dL (Normal: 70 – 99 mg/dL, fasting)\n"
220
- f"- CRP: {crp} mg/L (Normal: < 3 mg/L)\n"
221
- f"- MCV: {mcv} fL (Normal: 80 – 100 fL)\n"
222
- f"- RDW: {rdw} % (Normal: 11.5 – 14.5 %)\n"
223
- f"- ALP: {alp} U/L (Normal: 44 – 147 U/L)\n"
224
- f"- WBC: {wbc} K/uL (Normal: 4.0 – 11.0 K/uL)\n"
225
- f"- Lymphocytes: {lymph} % (Normal: 20 – 40 %)\n"
226
  )
227
 
228
- # Prepare the final prompt
229
  prompt = system_prompt + "\n" + patient_input
230
 
231
- # Generate the analysis
232
- gen = pipe(prompt,
233
- max_new_tokens=2500,
234
- do_sample=True,
235
- temperature=0.3,
236
- top_p=0.9,
237
- return_full_text=False)
238
-
239
- # Extract generated text
240
- generated = gen[0].get("generated_text") or gen[0].get("text") or str(gen[0])
241
- generated = generated.strip()
242
 
243
- # Clean: some models repeat prompt — attempt to strip prompt if present
244
- # Remove leading prompt echo if it appears
245
- if patient_input.strip() in generated:
246
- generated = generated.split(patient_input.strip())[-1].strip()
247
- # Also remove repeated instructions
248
- if system_prompt.strip() in generated:
249
- generated = generated.split(system_prompt.strip())[-1].strip()
250
 
251
- # Split into left/right panels
252
  left_md, right_md = split_report(generated)
253
-
254
- # If the model output is empty or too short, return a helpful fallback
255
- if len(left_md) < 50 and len(right_md) < 50:
256
- fallback = (
257
- "⚠️ The model returned an unexpectedly short response. Try re-running the report.\n\n"
258
- "**Patient Profile:**\n" + patient_input
259
- )
260
- return fallback, ""
261
  return left_md, right_md
262
 
263
-
264
  # -----------------------
265
- # Build Gradio app
266
  # -----------------------
267
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
268
  gr.Markdown("# 🏥 AI Medical Biomarker Dashboard")
269
- gr.Markdown("Enter lab values and demographics — Report is generated in two panels (Summary & Table/Insights).")
270
 
271
  with gr.Row():
272
- with gr.Column(scale=1):
273
- gr.Markdown("### 👤 Demographics")
274
  age = gr.Number(label="Age", value=45)
275
  gender = gr.Dropdown(["Male", "Female"], label="Gender", value="Male")
276
  height = gr.Number(label="Height (cm)", value=174)
277
  weight = gr.Number(label="Weight (kg)", value=75)
278
 
279
- gr.Markdown("### 🩸 Blood Panel")
280
  wbc = gr.Number(label="WBC (K/uL)", value=6.5)
281
  lymph = gr.Number(label="Lymphocytes (%)", value=30)
282
  mcv = gr.Number(label="MCV (fL)", value=88)
283
  rdw = gr.Number(label="RDW (%)", value=13)
284
 
285
- with gr.Column(scale=1):
286
- gr.Markdown("### 🧬 Chemistry Panel")
287
  albumin = gr.Number(label="Albumin (g/dL)", value=4.2)
288
  creatinine = gr.Number(label="Creatinine (mg/dL)", value=0.9)
289
  glucose = gr.Number(label="Glucose (mg/dL)", value=92)
@@ -293,12 +159,12 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
293
  analyze_btn = gr.Button("🔬 Generate Report", variant="primary")
294
 
295
  with gr.Row():
296
- with gr.Column(scale=1):
297
  gr.Markdown("### 📝 Summary & Action Plan")
298
- left_output = gr.Markdown(value="Press *Generate Report* to create the analysis.")
299
- with gr.Column(scale=1):
300
  gr.Markdown("### 📊 Tabular & AI Insights")
301
- right_output = gr.Markdown(value="Tabular mapping and enhanced insights will appear here.")
302
 
303
  analyze_btn.click(
304
  fn=analyze,
@@ -306,7 +172,5 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
306
  outputs=[left_output, right_output]
307
  )
308
 
309
-
310
- # Launch (HF Spaces expects this pattern)
311
  if __name__ == "__main__":
312
  demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))
 
3
  from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
4
  import os
5
  import torch
 
6
 
7
+ # -----------------------
8
+ # Recommended Biomedical Model (Swap here if needed)
9
+ # -----------------------
10
+ # Options:
11
+ # - "stanford-crfm/BioMedLM" (stable, PubMed-trained)
12
+ # - "BioMistral/BioMistral-7B" (newer, PubMed + PMC heavy)
13
+ # - "epfl-llm/ClinicalCamel" (clinical reporting style)
14
+ MODEL_ID = "Muhammadidrees/my-medgamma"
15
 
16
  # -----------------------
17
+
18
+ # Load tokenizer + model safely
19
  # -----------------------
20
  tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
21
 
 
22
  try:
23
+ model = AutoModelForCausalLM.from_pretrained(
24
+ MODEL_ID,
25
+ device_map="auto", # auto GPU/CPU placement
26
+ torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
27
+ low_cpu_mem_usage=True
28
+ )
29
+ except Exception as e:
30
+ print(f"⚠️ GPU load failed, using CPU. Error: {e}")
31
+ model = AutoModelForCausalLM.from_pretrained(
32
+ MODEL_ID,
33
+ torch_dtype=torch.float32,
34
+ low_cpu_mem_usage=True
35
+ )
36
 
37
+ pipe = pipeline(
38
+ "text-generation",
39
+ model=model,
40
+ tokenizer=tokenizer,
41
+ device=0 if torch.cuda.is_available() else -1
42
+ )
43
 
44
  # -----------------------
45
+ # Helper: split report into panels
46
  # -----------------------
47
+ def split_report(text: str):
 
 
 
 
 
48
  text = text.strip()
49
+ markers = ["5. Tabular", "📊 Tabular", "## 5"]
 
 
 
 
 
 
 
 
 
50
  idx = None
51
  for m in markers:
52
  pos = text.find(m)
 
54
  if idx is None or pos < idx:
55
  idx = pos
56
  if idx is None:
 
 
 
 
 
 
 
 
57
  return text, ""
58
+ return text[:idx].strip(), text[idx:].strip()
 
 
 
59
 
60
  # -----------------------
61
+ # Main analysis function
62
  # -----------------------
63
  def analyze(
64
  albumin, creatinine, glucose, crp, mcv, rdw, alp,
65
  wbc, lymph, age, gender, height, weight
66
  ):
 
67
  try:
68
  age = int(age)
69
  except Exception:
 
75
  except Exception:
76
  bmi = "N/A"
77
 
78
+ # -----------------------
79
+ # Strict System Prompt
80
+ # -----------------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  system_prompt = (
82
+ "You are a professional AI Medical Assistant.\n"
83
+ "You must ONLY analyze: 9 Levine biomarkers + Age + Height + Weight.\n"
84
+ "Forbidden: Any extra labs (cholesterol, vitamin D, ferritin, ALT, AST, urine, hormones, genetics).\n"
85
+ "If information is not derivable, state clearly: 'Not available from current biomarkers.'\n\n"
86
+ "Biomarkers allowed:\n"
87
+ "- Albumin\n- Creatinine\n- Glucose\n- C-reactive protein (CRP)\n"
88
+ "- Mean Cell Volume (MCV)\n- Red Cell Distribution Width (RDW)\n"
89
+ "- Alkaline Phosphatase (ALP)\n- White Blood Cell count (WBC)\n"
90
+ "- Lymphocyte percentage\n\n"
91
+ "Output format:\n"
92
+ "1. Executive Summary\n"
93
+ "2. System-Specific Analysis\n"
94
+ "3. Personalized Action Plan\n"
95
+ "4. Interaction Alerts\n"
96
+ "5. Tabular Mapping (Markdown table with Biomarker | Value | Range | Status | AI-Inferred Insight)\n"
97
+ "6. Enhanced AI Insights & Longitudinal Risk\n\n"
98
+ "Style: Professional, concise, structured, client-friendly. "
99
+ "No hallucinations. No extra biomarkers. No absolute longevity claims.\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  )
101
 
102
  patient_input = (
103
+ f"Patient Profile:\n- Age: {age}\n- Gender: {gender}\n"
104
+ f"- Height: {height} cm\n- Weight: {weight} kg\n- BMI: {bmi}\n\n"
105
+ "Lab Values:\n"
106
+ f"- Albumin: {albumin}\n- Creatinine: {creatinine}\n"
107
+ f"- Glucose: {glucose}\n- CRP: {crp}\n"
108
+ f"- MCV: {mcv}\n- RDW: {rdw}\n"
109
+ f"- ALP: {alp}\n- WBC: {wbc}\n- Lymphocytes: {lymph}\n"
 
 
 
 
 
 
 
 
 
110
  )
111
 
 
112
  prompt = system_prompt + "\n" + patient_input
113
 
114
+ gen = pipe(
115
+ prompt,
116
+ max_new_tokens=1500,
117
+ do_sample=True,
118
+ temperature=0.25, # lower temp = more factual
119
+ top_p=0.9,
120
+ repetition_penalty=1.05,
121
+ return_full_text=False
122
+ )
 
 
123
 
124
+ generated = gen[0].get("generated_text", "").strip()
125
+ if not generated:
126
+ return "⚠️ No valid response. Please try again.", ""
 
 
 
 
127
 
 
128
  left_md, right_md = split_report(generated)
 
 
 
 
 
 
 
 
129
  return left_md, right_md
130
 
 
131
  # -----------------------
132
+ # Gradio App
133
  # -----------------------
134
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
135
  gr.Markdown("# 🏥 AI Medical Biomarker Dashboard")
 
136
 
137
  with gr.Row():
138
+ with gr.Column():
139
+ gr.Markdown("### Demographics")
140
  age = gr.Number(label="Age", value=45)
141
  gender = gr.Dropdown(["Male", "Female"], label="Gender", value="Male")
142
  height = gr.Number(label="Height (cm)", value=174)
143
  weight = gr.Number(label="Weight (kg)", value=75)
144
 
145
+ gr.Markdown("### Blood Panel")
146
  wbc = gr.Number(label="WBC (K/uL)", value=6.5)
147
  lymph = gr.Number(label="Lymphocytes (%)", value=30)
148
  mcv = gr.Number(label="MCV (fL)", value=88)
149
  rdw = gr.Number(label="RDW (%)", value=13)
150
 
151
+ with gr.Column():
152
+ gr.Markdown("### Chemistry Panel")
153
  albumin = gr.Number(label="Albumin (g/dL)", value=4.2)
154
  creatinine = gr.Number(label="Creatinine (mg/dL)", value=0.9)
155
  glucose = gr.Number(label="Glucose (mg/dL)", value=92)
 
159
  analyze_btn = gr.Button("🔬 Generate Report", variant="primary")
160
 
161
  with gr.Row():
162
+ with gr.Column():
163
  gr.Markdown("### 📝 Summary & Action Plan")
164
+ left_output = gr.Markdown()
165
+ with gr.Column():
166
  gr.Markdown("### 📊 Tabular & AI Insights")
167
+ right_output = gr.Markdown()
168
 
169
  analyze_btn.click(
170
  fn=analyze,
 
172
  outputs=[left_output, right_output]
173
  )
174
 
 
 
175
  if __name__ == "__main__":
176
  demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))