Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,18 +1,18 @@
|
|
| 1 |
-
import
|
| 2 |
-
import os
|
| 3 |
-
import shutil
|
| 4 |
-
import base64
|
| 5 |
import gradio as gr
|
| 6 |
import cv2
|
| 7 |
import numpy as np
|
| 8 |
import mediapipe as mp
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
from reportlab.lib.pagesizes import letter
|
| 10 |
-
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
|
| 11 |
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
| 12 |
from reportlab.lib import colors
|
| 13 |
-
from datetime import datetime
|
| 14 |
-
import joblib
|
| 15 |
-
from sklearn.linear_model import LinearRegression
|
| 16 |
|
| 17 |
# Initialize the face mesh model
|
| 18 |
mp_face_mesh = mp.solutions.face_mesh
|
|
@@ -55,7 +55,8 @@ try:
|
|
| 55 |
spo2_model = joblib.load("spo2_model_simulated.pkl")
|
| 56 |
hr_model = joblib.load("heart_rate_model.pkl")
|
| 57 |
except FileNotFoundError:
|
| 58 |
-
print(
|
|
|
|
| 59 |
exit(1)
|
| 60 |
|
| 61 |
models = {
|
|
@@ -119,10 +120,11 @@ def build_table(title, rows):
|
|
| 119 |
return html
|
| 120 |
|
| 121 |
|
| 122 |
-
# Function to save health report
|
| 123 |
-
def save_results_to_pdf(
|
| 124 |
try:
|
| 125 |
-
|
|
|
|
| 126 |
styles = getSampleStyleSheet()
|
| 127 |
|
| 128 |
# Define custom styles
|
|
@@ -146,23 +148,19 @@ def save_results_to_pdf(patient_details, test_results, pdf_filename):
|
|
| 146 |
|
| 147 |
# Build the PDF content
|
| 148 |
flowables = []
|
| 149 |
-
|
| 150 |
-
#
|
| 151 |
-
flowables.append(Paragraph(
|
| 152 |
-
|
| 153 |
-
flowables.append(Spacer(1, 12))
|
| 154 |
-
|
| 155 |
# Add test results to the report
|
| 156 |
-
for
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
flowables.append(Paragraph(f"{test}: {result}", body_style))
|
| 160 |
-
flowables.append(Spacer(1, 6))
|
| 161 |
flowables.append(Spacer(1, 12))
|
| 162 |
-
|
| 163 |
# Build the PDF
|
| 164 |
doc.build(flowables)
|
| 165 |
-
return f"PDF saved successfully as {
|
| 166 |
except Exception as e:
|
| 167 |
return f"Error saving PDF: {str(e)}", None
|
| 168 |
|
|
@@ -174,30 +172,55 @@ def build_health_card(profile_image, test_results, summary, patient_name="", pat
|
|
| 174 |
|
| 175 |
html = f"""
|
| 176 |
<div id="health-card" style="font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; max-width: 700px; margin: 20px auto; border-radius: 16px; background: linear-gradient(135deg, #e3f2fd 0%, #f3e5f5 100%); border: 2px solid #ddd; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15); padding: 30px; color: #1a1a1a;">
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
<
|
| 181 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 182 |
</div>
|
| 183 |
-
<div>
|
| 184 |
-
<img src="data:image/png;base64,{profile_image}" style="width:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 185 |
</div>
|
| 186 |
</div>
|
| 187 |
|
| 188 |
-
<div style="margin-
|
| 189 |
-
{test_results}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 190 |
</div>
|
| 191 |
|
| 192 |
-
<div style="margin-
|
| 193 |
-
<h4>📝 Summary & Recommendations</h4>
|
| 194 |
-
<div>
|
|
|
|
|
|
|
| 195 |
</div>
|
| 196 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 197 |
</div>
|
| 198 |
"""
|
| 199 |
return html
|
| 200 |
|
|
|
|
| 201 |
# Initialize global variable for patient details
|
| 202 |
current_patient_details = {'name': '', 'age': '', 'gender': '', 'id': ''}
|
| 203 |
|
|
@@ -206,22 +229,22 @@ def analyze_face(input_data):
|
|
| 206 |
if isinstance(input_data, str): # Video input (file path in Replit)
|
| 207 |
cap = cv2.VideoCapture(input_data)
|
| 208 |
if not cap.isOpened():
|
| 209 |
-
return
|
| 210 |
ret, frame = cap.read()
|
| 211 |
cap.release()
|
| 212 |
if not ret:
|
| 213 |
-
return
|
| 214 |
else: # Image input
|
| 215 |
frame = input_data
|
| 216 |
if frame is None:
|
| 217 |
-
return
|
| 218 |
|
| 219 |
# Resize image to reduce processing time
|
| 220 |
frame = cv2.resize(frame, (640, 480)) # Adjust resolution for Replit
|
| 221 |
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
| 222 |
result = face_mesh.process(frame_rgb)
|
| 223 |
if not result.multi_face_landmarks:
|
| 224 |
-
return
|
| 225 |
landmarks = result.multi_face_landmarks[
|
| 226 |
0].landmark # Fixed: Use integer index
|
| 227 |
features = extract_features(frame_rgb, landmarks)
|
|
@@ -302,11 +325,9 @@ def analyze_face(input_data):
|
|
| 302 |
current_patient_details['id']
|
| 303 |
)
|
| 304 |
|
| 305 |
-
# Generate PDF
|
| 306 |
pdf_filename = f"Health_Report_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.pdf"
|
| 307 |
-
|
| 308 |
-
# Pass the pdf_filename along with test_results to save_results_to_pdf
|
| 309 |
-
pdf_result, pdf_filepath = save_results_to_pdf(current_patient_details, test_results, pdf_filename)
|
| 310 |
|
| 311 |
if pdf_filepath:
|
| 312 |
# Copy the PDF to a temporary directory for Gradio to serve it
|
|
|
|
| 1 |
+
import os # Import the os module
|
|
|
|
|
|
|
|
|
|
| 2 |
import gradio as gr
|
| 3 |
import cv2
|
| 4 |
import numpy as np
|
| 5 |
import mediapipe as mp
|
| 6 |
+
from sklearn.linear_model import LinearRegression
|
| 7 |
+
import random
|
| 8 |
+
import base64
|
| 9 |
+
import joblib
|
| 10 |
+
from datetime import datetime
|
| 11 |
+
import shutil
|
| 12 |
from reportlab.lib.pagesizes import letter
|
| 13 |
+
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
|
| 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
|
|
|
|
| 55 |
spo2_model = joblib.load("spo2_model_simulated.pkl")
|
| 56 |
hr_model = joblib.load("heart_rate_model.pkl")
|
| 57 |
except FileNotFoundError:
|
| 58 |
+
print(
|
| 59 |
+
"Error: One or more .pkl model files are missing. Please upload them.")
|
| 60 |
exit(1)
|
| 61 |
|
| 62 |
models = {
|
|
|
|
| 120 |
return html
|
| 121 |
|
| 122 |
|
| 123 |
+
# Function to save the health report to PDF
|
| 124 |
+
def save_results_to_pdf(test_results, filename):
|
| 125 |
try:
|
| 126 |
+
# Create a PDF document
|
| 127 |
+
doc = SimpleDocTemplate(filename, pagesize=letter)
|
| 128 |
styles = getSampleStyleSheet()
|
| 129 |
|
| 130 |
# Define custom styles
|
|
|
|
| 148 |
|
| 149 |
# Build the PDF content
|
| 150 |
flowables = []
|
| 151 |
+
|
| 152 |
+
# Add title
|
| 153 |
+
flowables.append(Paragraph("Health Report", title_style))
|
| 154 |
+
|
|
|
|
|
|
|
| 155 |
# Add test results to the report
|
| 156 |
+
for label, value in test_results.items():
|
| 157 |
+
line = f"{label}: {value}"
|
| 158 |
+
flowables.append(Paragraph(line, body_style))
|
|
|
|
|
|
|
| 159 |
flowables.append(Spacer(1, 12))
|
| 160 |
+
|
| 161 |
# Build the PDF
|
| 162 |
doc.build(flowables)
|
| 163 |
+
return f"PDF saved successfully as {filename}", filename
|
| 164 |
except Exception as e:
|
| 165 |
return f"Error saving PDF: {str(e)}", None
|
| 166 |
|
|
|
|
| 172 |
|
| 173 |
html = f"""
|
| 174 |
<div id="health-card" style="font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; max-width: 700px; margin: 20px auto; border-radius: 16px; background: linear-gradient(135deg, #e3f2fd 0%, #f3e5f5 100%); border: 2px solid #ddd; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15); padding: 30px; color: #1a1a1a;">
|
| 175 |
+
|
| 176 |
+
<div style="background-color: rgba(255, 255, 255, 0.9); border-radius: 12px; padding: 20px; margin-bottom: 25px; border: 1px solid #e0e0e0;">
|
| 177 |
+
<div style="display: flex; align-items: center; margin-bottom: 15px;">
|
| 178 |
+
<div style="background: linear-gradient(135deg, #64b5f6, #42a5f5); padding: 8px 16px; border-radius: 8px; margin-right: 20px;">
|
| 179 |
+
<h3 style="margin: 0; font-size: 16px; color: white; font-weight: 600;">HEALTH CARD</h3>
|
| 180 |
+
</div>
|
| 181 |
+
<div style="margin-left: auto; text-align: right; color: #666; font-size: 12px;">
|
| 182 |
+
<div>Report Date: {current_date}</div>
|
| 183 |
+
{f'<div>Patient ID: {patient_id}</div>' if patient_id else ''}
|
| 184 |
+
</div>
|
| 185 |
</div>
|
| 186 |
+
<div style="display: flex; align-items: center;">
|
| 187 |
+
<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);">
|
| 188 |
+
<div>
|
| 189 |
+
<h2 style="margin: 0; font-size: 28px; color: #2c3e50; font-weight: 700;">{patient_name if patient_name else "Lab Test Results"}</h2>
|
| 190 |
+
<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>
|
| 191 |
+
<p style="margin: 4px 0 0 0; color: #888; font-size: 12px;">Face-Based Health Analysis Report</p>
|
| 192 |
+
</div>
|
| 193 |
</div>
|
| 194 |
</div>
|
| 195 |
|
| 196 |
+
<div style="background-color: rgba(255, 255, 255, 0.95); border-radius: 12px; padding: 25px; margin-bottom: 25px; border: 1px solid #e0e0e0;">
|
| 197 |
+
{test_results['Hematology']}
|
| 198 |
+
{test_results['Iron Panel']}
|
| 199 |
+
{test_results['Liver & Kidney']}
|
| 200 |
+
{test_results['Electrolytes']}
|
| 201 |
+
{test_results['Vitals']}
|
| 202 |
</div>
|
| 203 |
|
| 204 |
+
<div style="background-color: rgba(255, 255, 255, 0.95); padding: 20px; border-radius: 12px; border: 1px solid #e0e0e0; margin-bottom: 25px;">
|
| 205 |
+
<h4 style="margin: 0 0 15px 0; color: #2c3e50; font-size: 18px; font-weight: 600;">📝 Summary & Recommendations</h4>
|
| 206 |
+
<div style="color: #444; line-height: 1.6;">
|
| 207 |
+
{summary}
|
| 208 |
+
</div>
|
| 209 |
</div>
|
| 210 |
|
| 211 |
+
<div style="display: flex; gap: 15px; justify-content: center; flex-wrap: wrap;">
|
| 212 |
+
<button onclick="window.print()" style="padding: 12px 24px; background: linear-gradient(135deg, #4caf50, #45a049); color: white; border: none; border-radius: 8px; cursor: pointer; font-weight: 600; font-size: 14px; box-shadow: 0 4px 12px rgba(76, 175, 80, 0.3); transition: all 0.3s;">
|
| 213 |
+
📥 Download Report
|
| 214 |
+
</button>
|
| 215 |
+
<button style="padding: 12px 24px; background: linear-gradient(135deg, #2196f3, #1976d2); color: white; border: none; border-radius: 8px; cursor: pointer; font-weight: 600; font-size: 14px; box-shadow: 0 4px 12px rgba(33, 150, 243, 0.3);">
|
| 216 |
+
📞 Find Labs Near Me
|
| 217 |
+
</button>
|
| 218 |
+
</div>
|
| 219 |
</div>
|
| 220 |
"""
|
| 221 |
return html
|
| 222 |
|
| 223 |
+
|
| 224 |
# Initialize global variable for patient details
|
| 225 |
current_patient_details = {'name': '', 'age': '', 'gender': '', 'id': ''}
|
| 226 |
|
|
|
|
| 229 |
if isinstance(input_data, str): # Video input (file path in Replit)
|
| 230 |
cap = cv2.VideoCapture(input_data)
|
| 231 |
if not cap.isOpened():
|
| 232 |
+
return "<div style='color:red;'>⚠️ Error: Could not open video.</div>", None
|
| 233 |
ret, frame = cap.read()
|
| 234 |
cap.release()
|
| 235 |
if not ret:
|
| 236 |
+
return "<div style='color:red;'>⚠️ Error: Could not read video frame.</div>", None
|
| 237 |
else: # Image input
|
| 238 |
frame = input_data
|
| 239 |
if frame is None:
|
| 240 |
+
return "<div style='color:red;'>⚠️ Error: No image provided.</div>", None
|
| 241 |
|
| 242 |
# Resize image to reduce processing time
|
| 243 |
frame = cv2.resize(frame, (640, 480)) # Adjust resolution for Replit
|
| 244 |
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
| 245 |
result = face_mesh.process(frame_rgb)
|
| 246 |
if not result.multi_face_landmarks:
|
| 247 |
+
return "<div style='color:red;'>⚠️ Error: Face not detected.</div>", None
|
| 248 |
landmarks = result.multi_face_landmarks[
|
| 249 |
0].landmark # Fixed: Use integer index
|
| 250 |
features = extract_features(frame_rgb, landmarks)
|
|
|
|
| 325 |
current_patient_details['id']
|
| 326 |
)
|
| 327 |
|
| 328 |
+
# Generate PDF and return for download
|
| 329 |
pdf_filename = f"Health_Report_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.pdf"
|
| 330 |
+
pdf_result, pdf_filepath = save_results_to_pdf(test_results, pdf_filename)
|
|
|
|
|
|
|
| 331 |
|
| 332 |
if pdf_filepath:
|
| 333 |
# Copy the PDF to a temporary directory for Gradio to serve it
|