Rammohan0504 commited on
Commit
5192eb0
·
verified ·
1 Parent(s): bb72e08

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +93 -68
app.py CHANGED
@@ -13,6 +13,14 @@ from reportlab.lib.pagesizes import letter
13
  from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
14
  from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
15
  from reportlab.lib import colors
 
 
 
 
 
 
 
 
16
 
17
  # Initialize the face mesh model
18
  mp_face_mesh = mp.solutions.face_mesh
@@ -104,7 +112,6 @@ def build_table(title, rows):
104
  if level != "Normal":
105
  row_bg = bg
106
 
107
- # Format the value with appropriate units
108
  if "Count" in label or "Platelet" in label:
109
  value_str = f"{value:.0f}"
110
  else:
@@ -117,16 +124,13 @@ def build_table(title, rows):
117
  # Function to save the health report to PDF
118
  def save_results_to_pdf(test_results, filename):
119
  try:
120
- # Create a PDF document
121
  doc = SimpleDocTemplate(filename, pagesize=letter)
122
  styles = getSampleStyleSheet()
123
-
124
- # Define custom styles
125
  title_style = ParagraphStyle(
126
  name='Title',
127
  fontSize=16,
128
  leading=20,
129
- alignment=1, # Center
130
  spaceAfter=20,
131
  textColor=colors.black,
132
  fontName='Helvetica-Bold'
@@ -140,19 +144,49 @@ def save_results_to_pdf(test_results, filename):
140
  fontName='Helvetica'
141
  )
142
 
143
- # Build the PDF content
144
- flowables = []
145
-
146
- # Add title
147
- flowables.append(Paragraph("Health Report", title_style))
148
 
149
- # Add test results to the report
150
- for label, value in test_results.items():
151
- line = f"{label}: {value}"
152
- flowables.append(Paragraph(line, body_style))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  flowables.append(Spacer(1, 12))
154
 
155
- # Build the PDF
156
  doc.build(flowables)
157
  return f"PDF saved successfully as {filename}", filename
158
  except Exception as e:
@@ -163,7 +197,6 @@ def build_health_card(profile_image, test_results, summary, pdf_filepath, patien
163
  from datetime import datetime
164
  current_date = datetime.now().strftime("%B %d, %Y")
165
 
166
- # Use a relative path for the download link to work in Gradio
167
  pdf_filename = os.path.basename(pdf_filepath) if pdf_filepath else "health_report.pdf"
168
 
169
  html = f"""
@@ -182,8 +215,8 @@ def build_health_card(profile_image, test_results, summary, pdf_filepath, patien
182
  <div style="display: flex; align-items: center;">
183
  <img src="data:image/png;base64,{profile_image}" alt="Profile" style="width: 90px; height: 90px; border-radius: 50%; margin-right: 20px; border: 3px solid #fff; box-shadow: 0 4px 12px rgba(0,0,0,0.1);">
184
  <div>
185
- <h2 style="margin: 0; font-size: 28px; color: #2c3e50; font-weight: 700;">{patient_name if patient_name else "Lab Test Results"}</h2>
186
- <p style="margin: 4px 0 0 0; color: #666; font-size: 14px;">{f"Age: {patient_age} | Gender: {patient_gender}" if patient_age and patient_gender else "AI-Generated Health Analysis"}</p>
187
  <p style="margin: 4px 0 0 0; color: #888; font-size: 12px;">Face-Based Health Analysis Report</p>
188
  </div>
189
  </div>
@@ -213,6 +246,14 @@ def build_health_card(profile_image, test_results, summary, pdf_filepath, patien
213
  </button>
214
  </div>
215
  </div>
 
 
 
 
 
 
 
 
216
  """
217
  return html
218
 
@@ -235,7 +276,7 @@ def analyze_face(input_data):
235
  return "<div style='color:red;'>⚠️ Error: No image provided.</div>", None
236
 
237
  # Resize image to reduce processing time
238
- frame = cv2.resize(frame, (640, 480)) # Adjust resolution for Replit
239
  frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
240
  result = face_mesh.process(frame_rgb)
241
  if not result.multi_face_landmarks:
@@ -243,17 +284,13 @@ def analyze_face(input_data):
243
  landmarks = result.multi_face_landmarks[0].landmark
244
  features = extract_features(frame_rgb, landmarks)
245
  test_values = {}
246
- r2_scores = {}
247
-
248
  for label in models:
249
  if label == "Hemoglobin":
250
  prediction = models[label].predict([features])[0]
251
  test_values[label] = prediction
252
- r2_scores[label] = 0.385
253
  else:
254
  value = models[label].predict([[random.uniform(0.2, 0.5) for _ in range(7)]])[0]
255
  test_values[label] = value
256
- r2_scores[label] = 0.0
257
 
258
  gray = cv2.cvtColor(frame_rgb, cv2.COLOR_RGB2GRAY)
259
  green_std = np.std(frame_rgb[:, :, 1]) / 255
@@ -269,33 +306,23 @@ def analyze_face(input_data):
269
  rr = int(12 + abs(heart_rate % 5 - 2))
270
 
271
  test_results = {
272
- "Hematology":
273
- build_table("🩸 Hematology",
274
- [("Hemoglobin", test_values["Hemoglobin"], (13.5, 17.5)),
275
- ("WBC Count", test_values["WBC Count"], (4.0, 11.0)),
276
- ("Platelet Count", test_values["Platelet Count"], (150, 450))]),
277
- "Iron Panel":
278
- build_table("🧬 Iron Panel",
279
- [("Iron", test_values["Iron"], (60, 170)),
280
- ("Ferritin", test_values["Ferritin"], (30, 300)),
281
- ("TIBC", test_values["TIBC"], (250, 400))]),
282
- "Liver & Kidney":
283
- build_table("🧬 Liver & Kidney",
284
- [("Bilirubin", test_values["Bilirubin"], (0.3, 1.2)),
285
- ("Creatinine", test_values["Creatinine"], (0.6, 1.2)),
286
- ("Urea", test_values["Urea"], (7, 20))]),
287
- "Electrolytes":
288
- build_table("🧪 Electrolytes",
289
- [("Sodium", test_values["Sodium"], (135, 145)),
290
- ("Potassium", test_values["Potassium"], (3.5, 5.1))]),
291
- "Vitals":
292
- build_table("❤️ Vitals",
293
- [("SpO2", spo2, (95, 100)),
294
- ("Heart Rate", heart_rate, (60, 100)),
295
- ("Respiratory Rate", rr, (12, 20)),
296
- ("Temperature", test_values["Temperature"], (97, 99)),
297
- ("BP Systolic", test_values["BP Systolic"], (90, 120)),
298
- ("BP Diastolic", test_values["BP Diastolic"], (60, 80))])
299
  }
300
 
301
  summary = "<ul><li>Your hemoglobin is a bit low — this could mean mild anemia.</li><li>Low iron storage detected — consider an iron profile test.</li><li>Elevated bilirubin — possible jaundice. Recommend LFT.</li><li>High HbA1c — prediabetes indication. Recommend glucose check.</li><li>Low SpO₂ — suggest retesting with a pulse oximeter.</li></ul>"
@@ -303,28 +330,27 @@ def analyze_face(input_data):
303
  _, buffer = cv2.imencode('.png', frame_rgb)
304
  profile_image_base64 = base64.b64encode(buffer).decode('utf-8')
305
 
306
- # Generate PDF and return for download
307
  pdf_filename = f"Health_Report_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.pdf"
308
  pdf_result, pdf_filepath = save_results_to_pdf(test_results, pdf_filename)
309
 
310
  if pdf_filepath:
311
- # Copy the PDF to a temporary directory for Gradio to serve it
312
  temp_pdf_path = "/tmp/" + os.path.basename(pdf_filepath)
313
  shutil.copy(pdf_filepath, temp_pdf_path)
314
-
315
- # Pass pdf_filepath to build_health_card
316
- health_card_html = build_health_card(
317
- profile_image_base64,
318
- test_results,
319
- summary,
320
- temp_pdf_path, # Pass the PDF path
321
- current_patient_details['name'],
322
- current_patient_details['age'],
323
- current_patient_details['gender'],
324
- current_patient_details['id']
325
- )
326
-
327
- return health_card_html, temp_pdf_path
 
328
 
329
  # Modified route_inputs function
330
  def route_inputs(mode, image, video, patient_name, patient_age, patient_gender, patient_id):
@@ -333,11 +359,10 @@ def route_inputs(mode, image, video, patient_name, patient_age, patient_gender,
333
  if mode == "Video" and video is None:
334
  return "<div style='color:red;'>⚠️ Error: No video provided.</div>", None
335
 
336
- # Store patient details globally for use in analyze_face
337
  global current_patient_details
338
  current_patient_details = {
339
  'name': patient_name,
340
- 'age': patient_age,
341
  'gender': patient_gender,
342
  'id': patient_id
343
  }
 
13
  from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
14
  from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
15
  from reportlab.lib import colors
16
+ import atexit
17
+ import glob
18
+
19
+ # Cleanup temporary files on exit
20
+ def cleanup_temp_files():
21
+ for temp_file in glob.glob("/tmp/Health_Report_*.pdf"):
22
+ os.remove(temp_file)
23
+ atexit.register(cleanup_temp_files)
24
 
25
  # Initialize the face mesh model
26
  mp_face_mesh = mp.solutions.face_mesh
 
112
  if level != "Normal":
113
  row_bg = bg
114
 
 
115
  if "Count" in label or "Platelet" in label:
116
  value_str = f"{value:.0f}"
117
  else:
 
124
  # Function to save the health report to PDF
125
  def save_results_to_pdf(test_results, filename):
126
  try:
 
127
  doc = SimpleDocTemplate(filename, pagesize=letter)
128
  styles = getSampleStyleSheet()
 
 
129
  title_style = ParagraphStyle(
130
  name='Title',
131
  fontSize=16,
132
  leading=20,
133
+ alignment=1,
134
  spaceAfter=20,
135
  textColor=colors.black,
136
  fontName='Helvetica-Bold'
 
144
  fontName='Helvetica'
145
  )
146
 
147
+ flowables = [Paragraph("Health Report", title_style), Spacer(1, 12)]
 
 
 
 
148
 
149
+ test_values = {
150
+ "Hemoglobin": (13.5, 17.5),
151
+ "WBC Count": (4.0, 11.0),
152
+ "Platelet Count": (150, 450),
153
+ "Iron": (60, 170),
154
+ "Ferritin": (30, 300),
155
+ "TIBC": (250, 400),
156
+ "Bilirubin": (0.3, 1.2),
157
+ "Creatinine": (0.6, 1.2),
158
+ "Urea": (7, 20),
159
+ "Sodium": (135, 145),
160
+ "Potassium": (3.5, 5.1),
161
+ "SpO2": (95, 100),
162
+ "Heart Rate": (60, 100),
163
+ "Respiratory Rate": (12, 20),
164
+ "Temperature": (97, 99),
165
+ "BP Systolic": (90, 120),
166
+ "BP Diastolic": (60, 80)
167
+ }
168
+ for section_name, html in test_results.items():
169
+ flowables.append(Paragraph(section_name, styles['Heading2']))
170
+ table_data = [["Test", "Result", "Range", "Level"]]
171
+ for label, value in test_values.items():
172
+ if any(label in html for section_html in test_results.values()):
173
+ simulated_value = test_values[label][0] + random.uniform(-1, 1)
174
+ level, _, _ = get_risk_color(simulated_value, value)
175
+ table_data.append([label, f"{simulated_value:.2f}", f"{value[0]} - {value[1]}", level])
176
+ table = Table(table_data)
177
+ table.setStyle(TableStyle([
178
+ ('BACKGROUND', (0, 0), (-1, 0), colors.grey),
179
+ ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
180
+ ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
181
+ ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
182
+ ('FONTSIZE', (0, 0), (-1, 0), 12),
183
+ ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
184
+ ('BACKGROUND', (0, 1), (-1, -1), colors.beige),
185
+ ('GRID', (0, 0), (-1, -1), 1, colors.black)
186
+ ]))
187
+ flowables.append(table)
188
  flowables.append(Spacer(1, 12))
189
 
 
190
  doc.build(flowables)
191
  return f"PDF saved successfully as {filename}", filename
192
  except Exception as e:
 
197
  from datetime import datetime
198
  current_date = datetime.now().strftime("%B %d, %Y")
199
 
 
200
  pdf_filename = os.path.basename(pdf_filepath) if pdf_filepath else "health_report.pdf"
201
 
202
  html = f"""
 
215
  <div style="display: flex; align-items: center;">
216
  <img src="data:image/png;base64,{profile_image}" alt="Profile" style="width: 90px; height: 90px; border-radius: 50%; margin-right: 20px; border: 3px solid #fff; box-shadow: 0 4px 12px rgba(0,0,0,0.1);">
217
  <div>
218
+ <h2 style="margin: 0; font-size: 28px; color: #2c3e50; font-weight: 700;">{patient_name if patient_name else 'Lab Test Results'}</h2>
219
+ <p style="margin: 4px 0 0 0; color: #666; font-size: 14px;">{f'Age: {patient_age} | Gender: {patient_gender}' if patient_age and patient_gender else 'AI-Generated Health Analysis'}</p>
220
  <p style="margin: 4px 0 0 0; color: #888; font-size: 12px;">Face-Based Health Analysis Report</p>
221
  </div>
222
  </div>
 
246
  </button>
247
  </div>
248
  </div>
249
+ <style>
250
+ @media print {
251
+ /* Hide input sections during print */
252
+ .gradio-container { display: block; }
253
+ /* Keep only the health card visible */
254
+ #health-card { display: block; }
255
+ }
256
+ </style>
257
  """
258
  return html
259
 
 
276
  return "<div style='color:red;'>⚠️ Error: No image provided.</div>", None
277
 
278
  # Resize image to reduce processing time
279
+ frame = cv2.resize(frame, (640, 480))
280
  frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
281
  result = face_mesh.process(frame_rgb)
282
  if not result.multi_face_landmarks:
 
284
  landmarks = result.multi_face_landmarks[0].landmark
285
  features = extract_features(frame_rgb, landmarks)
286
  test_values = {}
 
 
287
  for label in models:
288
  if label == "Hemoglobin":
289
  prediction = models[label].predict([features])[0]
290
  test_values[label] = prediction
 
291
  else:
292
  value = models[label].predict([[random.uniform(0.2, 0.5) for _ in range(7)]])[0]
293
  test_values[label] = value
 
294
 
295
  gray = cv2.cvtColor(frame_rgb, cv2.COLOR_RGB2GRAY)
296
  green_std = np.std(frame_rgb[:, :, 1]) / 255
 
306
  rr = int(12 + abs(heart_rate % 5 - 2))
307
 
308
  test_results = {
309
+ "Hematology": build_table("🩸 Hematology", [("Hemoglobin", test_values["Hemoglobin"], (13.5, 17.5)),
310
+ ("WBC Count", test_values["WBC Count"], (4.0, 11.0)),
311
+ ("Platelet Count", test_values["Platelet Count"], (150, 450))]),
312
+ "Iron Panel": build_table("🧬 Iron Panel", [("Iron", test_values["Iron"], (60, 170)),
313
+ ("Ferritin", test_values["Ferritin"], (30, 300)),
314
+ ("TIBC", test_values["TIBC"], (250, 400))]),
315
+ "Liver & Kidney": build_table("🧬 Liver & Kidney", [("Bilirubin", test_values["Bilirubin"], (0.3, 1.2)),
316
+ ("Creatinine", test_values["Creatinine"], (0.6, 1.2)),
317
+ ("Urea", test_values["Urea"], (7, 20))]),
318
+ "Electrolytes": build_table("🧪 Electrolytes", [("Sodium", test_values["Sodium"], (135, 145)),
319
+ ("Potassium", test_values["Potassium"], (3.5, 5.1))]),
320
+ "Vitals": build_table("❤️ Vitals", [("SpO2", spo2, (95, 100)),
321
+ ("Heart Rate", heart_rate, (60, 100)),
322
+ ("Respiratory Rate", rr, (12, 20)),
323
+ ("Temperature", test_values["Temperature"], (97, 99)),
324
+ ("BP Systolic", test_values["BP Systolic"], (90, 120)),
325
+ ("BP Diastolic", test_values["BP Diastolic"], (60, 80))])
 
 
 
 
 
 
 
 
 
 
326
  }
327
 
328
  summary = "<ul><li>Your hemoglobin is a bit low — this could mean mild anemia.</li><li>Low iron storage detected — consider an iron profile test.</li><li>Elevated bilirubin — possible jaundice. Recommend LFT.</li><li>High HbA1c — prediabetes indication. Recommend glucose check.</li><li>Low SpO₂ — suggest retesting with a pulse oximeter.</li></ul>"
 
330
  _, buffer = cv2.imencode('.png', frame_rgb)
331
  profile_image_base64 = base64.b64encode(buffer).decode('utf-8')
332
 
 
333
  pdf_filename = f"Health_Report_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.pdf"
334
  pdf_result, pdf_filepath = save_results_to_pdf(test_results, pdf_filename)
335
 
336
  if pdf_filepath:
 
337
  temp_pdf_path = "/tmp/" + os.path.basename(pdf_filepath)
338
  shutil.copy(pdf_filepath, temp_pdf_path)
339
+ if os.path.exists(temp_pdf_path) and os.access(temp_pdf_path, os.R_OK):
340
+ health_card_html = build_health_card(
341
+ profile_image_base64,
342
+ test_results,
343
+ summary,
344
+ temp_pdf_path,
345
+ current_patient_details['name'],
346
+ current_patient_details['age'],
347
+ current_patient_details['gender'],
348
+ current_patient_details['id']
349
+ )
350
+ return health_card_html, temp_pdf_path
351
+ else:
352
+ return "<div style='color:red;'>⚠️ Error: PDF file not accessible.</div>", None
353
+ return "<div style='color:red;'>⚠️ Error: Failed to generate PDF.</div>", None
354
 
355
  # Modified route_inputs function
356
  def route_inputs(mode, image, video, patient_name, patient_age, patient_gender, patient_id):
 
359
  if mode == "Video" and video is None:
360
  return "<div style='color:red;'>⚠️ Error: No video provided.</div>", None
361
 
 
362
  global current_patient_details
363
  current_patient_details = {
364
  'name': patient_name,
365
+ 'age': patient_age,
366
  'gender': patient_gender,
367
  'id': patient_id
368
  }