import os import gradio as gr import cv2 import numpy as np import mediapipe as mp from sklearn.linear_model import LinearRegression import random import base64 import joblib from datetime import datetime import shutil from reportlab.lib.pagesizes import letter from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib import colors # Initialize the face mesh model mp_face_mesh = mp.solutions.face_mesh face_mesh = mp_face_mesh.FaceMesh(static_image_mode=True, max_num_faces=1, refine_landmarks=True, min_detection_confidence=0.5) # Functions for feature extraction def extract_features(image, landmarks): red_channel = image[:, :, 2] green_channel = image[:, :, 1] blue_channel = image[:, :, 0] red_percent = 100 * np.mean(red_channel) / 255 green_percent = 100 * np.mean(green_channel) / 255 blue_percent = 100 * np.mean(blue_channel) / 255 return [red_percent, green_percent, blue_percent] def train_model(output_range): X = [[ random.uniform(0.2, 0.5), random.uniform(0.05, 0.2), random.uniform(0.05, 0.2), random.uniform(0.2, 0.5), random.uniform(0.2, 0.5), random.uniform(0.2, 0.5), random.uniform(0.2, 0.5) ] for _ in range(100)] y = [random.uniform(*output_range) for _ in X] model = LinearRegression().fit(X, y) return model # Load models try: hemoglobin_model = joblib.load("hemoglobin_model_from_anemia_dataset.pkl") spo2_model = joblib.load("spo2_model_simulated.pkl") hr_model = joblib.load("heart_rate_model.pkl") except FileNotFoundError: print("Error: One or more .pkl model files are missing. Please upload them.") exit(1) models = { "Hemoglobin": hemoglobin_model, "WBC Count": train_model((4.0, 11.0)), "Platelet Count": train_model((150, 450)), "Iron": train_model((60, 170)), "Ferritin": train_model((30, 300)), "TIBC": train_model((250, 400)), "Bilirubin": train_model((0.3, 1.2)), "Creatinine": train_model((0.6, 1.2)), "Urea": train_model((7, 20)), "Sodium": train_model((135, 145)), "Potassium": train_model((3.5, 5.1)), "TSH": train_model((0.4, 4.0)), "Cortisol": train_model((5, 25)), "FBS": train_model((70, 110)), "HbA1c": train_model((4.0, 5.7)), "Albumin": train_model((3.5, 5.5)), "BP Systolic": train_model((90, 120)), "BP Diastolic": train_model((60, 80)), "Temperature": train_model((97, 99)) } # Helper function for risk level color coding def get_risk_color(value, normal_range): low, high = normal_range if value < low: return ("Low", "๐Ÿ”ป", "#fff3cd") elif value > high: return ("High", "๐Ÿ”บ", "#f8d7da") else: return ("Normal", "โœ…", "#d4edda") # Function to build table for test results def build_table(title, rows): html = ( f'
' f'
' f'

{title}

' f'
' f'' f'' ) for i, (label, value, ref) in enumerate(rows): level, icon, bg = get_risk_color(value, ref) row_bg = "#f8f9fa" if i % 2 == 0 else "white" if level != "Normal": row_bg = bg # Format the value with appropriate units if "Count" in label or "Platelet" in label: value_str = f"{value:.0f}" else: value_str = f"{value:.2f}" html += f'' html += '
TestResultRangeLevel
{label}{value_str}{ref[0]} - {ref[1]}{icon} {level}
' return html # Function to save the health report to PDF def save_results_to_pdf(test_results, filename): try: # Create a PDF document doc = SimpleDocTemplate(filename, pagesize=letter) styles = getSampleStyleSheet() # Define custom styles title_style = ParagraphStyle( name='Title', fontSize=16, leading=20, alignment=1, # Center spaceAfter=20, textColor=colors.black, fontName='Helvetica-Bold' ) body_style = ParagraphStyle( name='Body', fontSize=12, leading=14, spaceAfter=10, textColor=colors.black, fontName='Helvetica' ) # Build the PDF content flowables = [] # Add title flowables.append(Paragraph("Health Report", title_style)) # Add test results to the report for label, value in test_results.items(): line = f"{label}: {value}" flowables.append(Paragraph(line, body_style)) flowables.append(Spacer(1, 12)) # Build the PDF doc.build(flowables) return f"PDF saved successfully as {filename}", filename except Exception as e: return f"Error saving PDF: {str(e)}", None # Build health card layout def build_health_card(profile_image, test_results, summary, patient_name="", patient_age="", patient_gender="", patient_id=""): from datetime import datetime current_date = datetime.now().strftime("%B %d, %Y") html = f"""

HEALTH CARD

Report Date: {current_date}
{f'
Patient ID: {patient_id}
' if patient_id else ''}
Profile

{patient_name if patient_name else "Lab Test Results"}

{f"Age: {patient_age} | Gender: {patient_gender}" if patient_age and patient_gender else "AI-Generated Health Analysis"}

Face-Based Health Analysis Report

{test_results['Hematology']} {test_results['Iron Panel']} {test_results['Liver & Kidney']} {test_results['Electrolytes']} {test_results['Vitals']}

๐Ÿ“ Summary & Recommendations

{summary}
""" return html # Initialize global variable for patient details current_patient_details = {'name': '', 'age': '', 'gender': '', 'id': ''} # Modified analyze_face function def analyze_face(input_data): if isinstance(input_data, str): # Video input (file path in Replit) cap = cv2.VideoCapture(input_data) if not cap.isOpened(): return "
โš ๏ธ Error: Could not open video.
", None ret, frame = cap.read() cap.release() if not ret: return "
โš ๏ธ Error: Could not read video frame.
", None else: # Image input frame = input_data if frame is None: return "
โš ๏ธ Error: No image provided.
", None # Resize image to reduce processing time frame = cv2.resize(frame, (640, 480)) # Adjust resolution for Replit frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) result = face_mesh.process(frame_rgb) if not result.multi_face_landmarks: return "
โš ๏ธ Error: Face not detected.
", None landmarks = result.multi_face_landmarks[0].landmark # Fixed: Use integer index features = extract_features(frame_rgb, landmarks) test_values = {} r2_scores = {} for label in models: if label == "Hemoglobin": prediction = models[label].predict([features])[0] test_values[label] = prediction r2_scores[label] = 0.385 else: value = models[label].predict([[random.uniform(0.2, 0.5) for _ in range(7)]])[0] test_values[label] = value r2_scores[label] = 0.0 gray = cv2.cvtColor(frame_rgb, cv2.COLOR_RGB2GRAY) green_std = np.std(frame_rgb[:, :, 1]) / 255 brightness_std = np.std(gray) / 255 tone_index = np.mean(frame_rgb[100:150, 100:150]) / 255 if frame_rgb[ 100:150, 100:150].size else 0.5 hr_features = [brightness_std, green_std, tone_index] heart_rate = float(np.clip(hr_model.predict([hr_features])[0], 60, 100)) skin_patch = frame_rgb[100:150, 100:150] skin_tone_index = np.mean(skin_patch) / 255 if skin_patch.size else 0.5 brightness_variation = np.std(cv2.cvtColor(frame_rgb, cv2.COLOR_RGB2GRAY)) / 255 spo2_features = [heart_rate, brightness_variation, skin_tone_index] spo2 = spo2_model.predict([spo2_features])[0] rr = int(12 + abs(heart_rate % 5 - 2)) test_results = { "Hematology": build_table("๐Ÿฉธ Hematology", [("Hemoglobin", test_values["Hemoglobin"], (13.5, 17.5)), ("WBC Count", test_values["WBC Count"], (4.0, 11.0)), ("Platelet Count", test_values["Platelet Count"], (150, 450))]), "Iron Panel": build_table("๐Ÿงฌ Iron Panel", [("Iron", test_values["Iron"], (60, 170)), ("Ferritin", test_values["Ferritin"], (30, 300)), ("TIBC", test_values["TIBC"], (250, 400))]), "Liver & Kidney": build_table("๐Ÿงฌ Liver & Kidney", [("Bilirubin", test_values["Bilirubin"], (0.3, 1.2)), ("Creatinine", test_values["Creatinine"], (0.6, 1.2)), ("Urea", test_values["Urea"], (7, 20))]), "Electrolytes": build_table("๐Ÿงช Electrolytes", [("Sodium", test_values["Sodium"], (135, 145)), ("Potassium", test_values["Potassium"], (3.5, 5.1))]), "Vitals": build_table("โค๏ธ Vitals", [("SpO2", spo2, (95, 100)), ("Heart Rate", heart_rate, (60, 100)), ("Respiratory Rate", rr, (12, 20)), ("Temperature", test_values["Temperature"], (97, 99)), ("BP Systolic", test_values["BP Systolic"], (90, 120)), ("BP Diastolic", test_values["BP Diastolic"], (60, 80))]) } summary = "" _, buffer = cv2.imencode('.png', frame_rgb) profile_image_base64 = base64.b64encode(buffer).decode('utf-8') # Use global patient details global current_patient_details health_card_html = build_health_card( profile_image_base64, test_results, summary, current_patient_details['name'], current_patient_details['age'], current_patient_details['gender'], current_patient_details['id'] ) # Generate PDF and return for download pdf_filename = f"Health_Report_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.pdf" pdf_result, pdf_filepath = save_results_to_pdf(test_results, pdf_filename) if pdf_filepath: # Copy the PDF to a temporary directory for Gradio to serve it temp_pdf_path = "/tmp/" + os.path.basename(pdf_filepath) shutil.copy(pdf_filepath, temp_pdf_path) return health_card_html, temp_pdf_path # Modified route_inputs function def route_inputs(mode, image, video, patient_name, patient_age, patient_gender, patient_id): if mode == "Image" and image is None: return "
โš ๏ธ Error: No image provided.
", None if mode == "Video" and video is None: return "
โš ๏ธ Error: No video provided.
", None # Store patient details globally for use in analyze_face global current_patient_details current_patient_details = { 'name': patient_name, 'age': patient_age, 'gender': patient_gender, 'id': patient_id } health_card_html, pdf_file_path = analyze_face(image if mode == "Image" else video) return health_card_html, pdf_file_path # Create Gradio interface with gr.Blocks() as demo: gr.Markdown("""# ๐Ÿง  Face-Based Lab Test AI Report (Video Mode)""") with gr.Row(): with gr.Column(): gr.Markdown("### Patient Information") patient_name = gr.Textbox(label="Patient Name", placeholder="Enter patient name") patient_age = gr.Number(label="Age", value=25, minimum=1, maximum=120) patient_gender = gr.Radio(label="Gender", choices=["Male", "Female", "Other"], value="Male") patient_id = gr.Textbox(label="Patient ID", placeholder="Enter patient ID (optional)") gr.Markdown("### Image/Video Input") mode_selector = gr.Radio(label="Choose Input Mode", choices=["Image", "Video"], value="Image") image_input = gr.Image(type="numpy", label="๐Ÿ“ธ Upload Face Image") video_input = gr.Video(label="Upload Face Video", sources=["upload", "webcam"]) submit_btn = gr.Button("๐Ÿ” Analyze") with gr.Column(): result_html = gr.HTML(label="๐Ÿงช Health Report Table") result_pdf = gr.File(label="Download Health Report PDF", interactive=False) submit_btn.click(fn=route_inputs, inputs=[mode_selector, image_input, video_input, patient_name, patient_age, patient_gender, patient_id], outputs=[result_html, result_pdf]) # Launch Gradio for Replit demo.launch(server_name="0.0.0.0", server_port=7860)