๐ง AI Health Report Generator
Advanced face-based health analysis using AI technology
import streamlit as st
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 io
from reportlab.lib.pagesizes import A4
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer, PageBreak, PageTemplate, Frame, Image
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
from reportlab.lib import colors
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
from reportlab.graphics.shapes import Drawing, Line
from PIL import Image as PILImage
import tempfile
import os
import logging
import re
import pandas as pd
import torch
from torchvision import models, transforms
import PyPDF2
# Set up logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
# Configure Streamlit page
st.set_page_config(
page_title="AI Health Report Generator",
page_icon="๐ง ",
layout="wide",
initial_sidebar_state="expanded"
)
# Custom CSS for enhanced UI with DataFrame styling
st.markdown("""
""", unsafe_allow_html=True)
# Initialize MediaPipe
@st.cache_resource
def load_face_mesh():
try:
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
)
logger.info("MediaPipe FaceMesh initialized successfully")
return face_mesh
except Exception as e:
st.error(f"Failed to initialize MediaPipe: {str(e)}")
logger.error(f"MediaPipe initialization failed: {str(e)}")
return None
# Initialize MediaPipe drawing utilities
@st.cache_resource
def load_drawing_utils():
try:
mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
logger.info("MediaPipe drawing utilities initialized successfully")
return mp_drawing, mp_drawing_styles
except Exception as e:
logger.error(f"MediaPipe drawing utilities initialization failed: {str(e)}")
return None, None
# Load models
@st.cache_resource
def load_models():
try:
hemoglobin_model = joblib.load("hemoglobin_model_from_anemia_dataset.pkl")
except FileNotFoundError:
st.warning("Hemoglobin model not found. Training a temporary model.")
hemoglobin_model = train_model((13.5, 17.5))
try:
spo2_model = joblib.load("spo2_model_simulated.pkl")
except FileNotFoundError:
st.warning("SpO2 model not found. Training a temporary model.")
spo2_model = train_model((95, 100))
try:
hr_model = joblib.load("heart_rate_model.pkl")
except FileNotFoundError:
st.warning("Heart rate model not found. Training a temporary model.")
hr_model = train_model((60, 100))
logger.info("Models loaded or trained successfully")
return hemoglobin_model, spo2_model, hr_model
@st.cache_resource
def load_xray_model():
try:
model = models.densenet121(pretrained=True)
model.eval()
logger.info("X-ray model (DenseNet121) loaded successfully")
return model
except Exception as e:
st.error(f"Failed to load X-ray model: {str(e)}")
logger.error(f"X-ray model loading failed: {str(e)}")
return None
def train_model(output_range):
try:
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)
logger.info(f"Model trained for range {output_range}")
return model
except Exception as e:
st.error(f"Failed to train model: {str(e)}")
logger.error(f"Model training failed: {str(e)}")
return None
def extract_features(image, landmarks):
try:
if len(image.shape) < 3 or image.shape[2] != 3:
st.error("Invalid image format: Expected RGB image.")
logger.error("Invalid image format: Not RGB")
return None
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
logger.info("Features extracted successfully")
return [red_percent, green_percent, blue_percent]
except Exception as e:
st.error(f"Failed to extract features: {str(e)}")
logger.error(f"Feature extraction failed: {str(e)}")
return None
def get_risk_level(value, normal_range):
try:
low, high = normal_range
if value < low:
return "Low", "#ffca28"
elif value > high:
return "High", "#d32f2f"
else:
return "Normal", "#2E8B57"
except Exception as e:
st.error(f"Failed to determine risk level: {str(e)}")
logger.error(f"Risk level determination failed: {str(e)}")
return "Unknown", "#ffffff"
def draw_analyzed_image(image, landmarks):
try:
mp_drawing, mp_drawing_styles = load_drawing_utils()
if mp_drawing is None or mp_drawing_styles is None:
logger.error("Drawing utilities not initialized")
return image
annotated_image = image.copy()
h, w = annotated_image.shape[:2]
# Draw facial landmarks
mp_drawing.draw_landmarks(
image=annotated_image,
landmark_list=landmarks,
connections=mp.solutions.face_mesh.FACEMESH_TESSELATION,
landmark_drawing_spec=None,
connection_drawing_spec=mp_drawing_styles.get_default_face_mesh_tesselation_style()
)
# Highlight analysis regions (cheeks, forehead, nose)
cheek_left_points = [landmarks.landmark[i] for i in range(50, 151)]
cheek_right_points = [landmarks.landmark[i] for i in range(280, 381)]
forehead_points = [landmarks.landmark[i] for i in range(10, 51)]
nose_points = [landmarks.landmark[i] for i in range(1, 5)]
def normalize_to_pixel(landmark):
return (int(landmark.x * w), int(landmark.y * h))
def get_bounding_box(points):
x_coords = [p.x * w for p in points]
y_coords = [p.y * h for p in points]
x_min, x_max = int(min(x_coords)), int(max(x_coords))
y_min, y_max = int(min(y_coords)), int(max(y_coords))
return x_min, y_min, x_max, y_max
# Draw semi-transparent colored rectangles
overlay = annotated_image.copy()
# Left cheek (red)
x_min, y_min, x_max, y_max = get_bounding_box(cheek_left_points)
cv2.rectangle(overlay, (x_min, y_min), (x_max, y_max), (255, 0, 0), -1)
logger.debug(f"Left cheek box: ({x_min}, {y_min}, {x_max}, {y_max})")
# Right cheek (red)
x_min, y_min, x_max, y_max = get_bounding_box(cheek_right_points)
cv2.rectangle(overlay, (x_min, y_min), (x_max, y_max), (255, 0, 0), -1)
logger.debug(f"Right cheek box: ({x_min}, {y_min}, {x_max}, {y_max})")
# Forehead (green)
x_min, y_min, x_max, y_max = get_bounding_box(forehead_points)
cv2.rectangle(overlay, (x_min, y_min), (x_max, y_max), (0, 255, 0), -1)
logger.debug(f"Forehead box: ({x_min}, {y_min}, {x_max}, {y_max})")
# Nose (blue)
x_min, y_min, x_max, y_max = get_bounding_box(nose_points)
cv2.rectangle(overlay, (x_min, y_min), (x_max, y_max), (0, 0, 255), -1)
logger.debug(f"Nose box: ({x_min}, {y_min}, {x_max}, {y_max})")
# Apply transparency
alpha = 0.4 # 40% opacity
cv2.addWeighted(overlay, alpha, annotated_image, 1 - alpha, 0, annotated_image)
logger.info("Analyzed image generated with landmarks and region highlights")
return annotated_image
except Exception as e:
logger.error(f"Failed to draw analyzed image: {str(e)}")
st.error(f"Analyzed image generation failed: {str(e)}")
return image
def create_pdf_report(patient_data, test_results, profile_image):
try:
logger.info("Starting PDF generation")
buffer = io.BytesIO()
doc = SimpleDocTemplate(buffer, pagesize=A4, rightMargin=30, leftMargin=30, topMargin=50, bottomMargin=80)
elements = []
styles = getSampleStyleSheet()
# Define custom styles
header_logo_style = ParagraphStyle(
'HeaderLogoStyle',
parent=styles['Heading1'],
fontName='Helvetica-Bold',
fontSize=16,
spaceAfter=8,
alignment=TA_LEFT,
textColor=colors.HexColor('#2E8B57'),
leftIndent=0,
spaceBefore=0
)
test_report_badge_style = ParagraphStyle(
'TestReportBadgeStyle',
parent=styles['Normal'],
fontName='Helvetica-Bold',
fontSize=12,
alignment=TA_RIGHT,
textColor=colors.HexColor('#2E8B57'),
borderWidth=1,
borderColor=colors.HexColor('#2E8B57'),
borderPadding=8,
spaceBefore=0,
spaceAfter=0
)
patient_info_style = ParagraphStyle(
'PatientInfoStyle',
parent=styles['Normal'],
fontName='Helvetica',
fontSize=9,
spaceAfter=6,
textColor=colors.black,
alignment=TA_LEFT
)
section_header_style = ParagraphStyle(
'SectionHeaderStyle',
parent=styles['Heading2'],
fontName='Helvetica-Bold',
fontSize=12,
spaceAfter=8,
spaceBefore=12,
textColor=colors.black,
alignment=TA_CENTER,
backColor=colors.HexColor('#f0f0f0'),
borderWidth=1,
borderColor=colors.black,
borderPadding=6
)
footer_style = ParagraphStyle(
'FooterStyle',
parent=styles['Normal'],
fontName='Helvetica',
fontSize=8,
textColor=colors.black,
alignment=TA_CENTER,
spaceAfter=4
)
signatory_style = ParagraphStyle(
'SignatoryStyle',
parent=styles['Normal'],
fontName='Helvetica-Bold',
fontSize=9,
spaceAfter=6,
textColor=colors.black,
alignment=TA_RIGHT
)
# Footer content
footer_text = """
Sathkrutha Tech Solutions Pvt. Ltd Registered Office: H.No: 2-3-685/5/1, Flat N Venkateshwara Nagar, Amberpet, Hyderabad, Telangana 500013, INDIA
T: +91 4027264141 F: +91 4027263667 E: helpdesk@sathkrutha.com
"""
def add_page_footer(canvas, doc):
canvas.saveState()
canvas.setLineWidth(2)
canvas.setStrokeColor(colors.black)
canvas.rect(20, 20, A4[0]-40, A4[1]-40)
canvas.setFont('Helvetica', 8)
page_num = canvas.getPageNumber()
if hasattr(doc, '_total_pages'):
page_text = f"Page {page_num} of {doc._total_pages}"
else:
page_text = f"Page {page_num}"
canvas.drawRightString(A4[0]-40, 25, page_text)
footer_para = Paragraph(footer_text, footer_style)
w, h = footer_para.wrap(A4[0]-60, 40)
footer_para.drawOn(canvas, 30, 30)
canvas.restoreState()
doc.addPageTemplates([
PageTemplate(id='AllPages', frames=[Frame(30, 80, A4[0]-60, A4[1]-130)], onPage=add_page_footer)
])
# Header
header_table_data = [
[Paragraph("Sathkrutha
Clinical Diagnostics", header_logo_style),
Paragraph("Test Report", test_report_badge_style)]
]
header_table = Table(header_table_data, colWidths=[4*inch, 2*inch])
header_table.setStyle(TableStyle([
('VALIGN', (0, 0), (-1, -1), 'TOP'),
('ALIGN', (0, 0), (0, 0), 'LEFT'),
('ALIGN', (1, 0), (1, 0), 'RIGHT'),
('LEFTPADDING', (0, 0), (-1, -1), 0),
('RIGHTPADDING', (0, 0), (-1, -1), 0),
('TOPPADING', (0, 0), (-1, -1), 0),
('BOTTOMPADDING', (0, 0), (-1, -1), 12),
]))
elements.append(header_table)
elements.append(Spacer(1, 10))
# Issued to section
issued_to_data = [["Issued to :", ""]]
issued_table = Table(issued_to_data, colWidths=[1*inch, 5*inch])
issued_table.setStyle(TableStyle([
('FONT', (0, 0), (-1, -1), 'Helvetica-Bold', 9),
('GRID', (0, 0), (-1, -1), 1, colors.black),
('BACKGROUND', (0, 0), (-1, -1), colors.HexColor('#e6e6e6')),
('LEFTPADDING', (0, 0), (-1, -1), 4),
('TOPPADING', (0, 0), (-1, -1), 4),
('BOTTOMPADDING', (0, 0), (-1, -1), 4),
]))
elements.append(issued_table)
# Patient details with photo
img_buffer = io.BytesIO()
profile_image.save(img_buffer, format="PNG")
img_buffer.seek(0)
img = Image(img_buffer, width=1.5*inch, height=1.5*inch)
patient_details = [
[img, Paragraph(f"Name: {patient_data.get('name', 'Unknown Patient')}
"
f"Age: {patient_data.get('age', 'N/A')} Years
"
f"Gender: {patient_data.get('gender', 'Male')}
"
f"ID: {patient_data.get('id', 'N/A')}
"
f"Date: {datetime.now().strftime('%d-%b-%Y %H:%M')}", patient_info_style)]
]
patient_table = Table(patient_details, colWidths=[1.5*inch, 5.5*inch])
patient_table.setStyle(TableStyle([
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
('LEFTPADDING', (0, 0), (-1, -1), 10),
('RIGHTPADDING', (0, 0), (-1, -1), 10),
('TOPPADING', (0, 0), (-1, -1), 10),
('BOTTOMPADING', (0, 0), (-1, -1), 10),
]))
elements.append(patient_table)
elements.append(Spacer(1, 15))
# Test categories
for category_index, (category, tests) in enumerate(test_results.items()):
if category_index > 0:
elements.append(PageBreak())
clean_category = category.replace("โ ", "").strip().upper()
elements.append(Paragraph(clean_category, section_header_style))
elements.append(Spacer(1, 10))
table_data = [["Test Description", "Value Observed", "Unit", "Biological Reference Interval"]]
for test_name, result, range_val, level_info in tests:
level, _ = level_info
status_indicator = " L" if level == "Low" else " H" if level == "High" else ""
if "Count" in test_name or test_name == "Respiratory Rate":
value_str = f"{result:.0f}{status_indicator}"
elif test_name in ["Temperature", "SpO2"]:
value_str = f"{result:.1f}{status_indicator}"
else:
value_str = f"{result:.1f}{status_indicator}"
unit = "" if "BP" in test_name else ("g/dL" if "Hemoglobin" in test_name else
"cu/mm" if "WBC Count" in test_name else
"Thousand/ยตL" if "Platelet Count" in test_name else
"ยตg/dL" if "Iron" in test_name or "TIBC" in test_name else
"ng/mL" if "Ferritin" in test_name else
"mg/dL" if "Bilirubin" in test_name or "Creatinine" in test_name or "Urea" in test_name else
"mEq/L" if "Sodium" in test_name or "Potassium" in test_name else
"%" if "SpO2" in test_name else
"bpm" if "Heart Rate" in test_name else
"/min" if "Respiratory Rate" in test_name else
"ยฐF" if "Temperature" in test_name else "mmHg")
range_str = f"{range_val[0]:.0f} - {range_val[1]:.0f}" if "Count" in test_name or test_name == "Respiratory Rate" else f"{range_val[0]:.1f} - {range_val[1]:.1f}"
table_data.append([test_name, value_str, unit, range_str])
test_table = Table(table_data, colWidths=[2.5*inch, 1.2*inch, 0.8*inch, 1.5*inch])
test_table.setStyle(TableStyle([
('FONT', (0, 0), (-1, 0), 'Helvetica-Bold', 9),
('FONT', (0, 1), (-1, -1), 'Helvetica', 9),
('BACKGROUND', (0, 0), (-1, 0), colors.white),
('GRID', (0, 0), (-1, -1), 0.5, colors.black),
('BOX', (0, 0), (-1, -1), 1, colors.black),
('LEFTPADDING', (0, 0), (-1, -1), 6),
('RIGHTPADDING', (0, 0), (-1, -1), 6),
('TOPPADING', (0, 0), (-1, -1), 6),
('BOTTOMPADING', (0, 0), (-1, -1), 6),
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
('ALIGN', (0, 0), (0, -1), 'LEFT'),
('ALIGN', (1, 1), (-1, -1), 'CENTER'),
]))
elements.append(test_table)
elements.append(Spacer(1, 30))
signatory_table_data = [["", ""], ["", "DR.SATHAIAH BEGARI"], ["", "MBBS,DCP, Clinical Pathologist"], ["", "AUTHORISED SIGNATORY"]]
signatory_table = Table(signatory_table_data, colWidths=[4*inch, 2*inch])
signatory_table.setStyle(TableStyle([
('FONT', (1, 1), (1, -1), 'Helvetica-Bold', 9),
('ALIGN', (1, 1), (1, -1), 'RIGHT'),
('VALIGN', (1, 1), (1, -1), 'TOP'),
('LEFTPADDING', (0, 0), (-1, -1), 0),
('RIGHTPADDING', (0, 0), (-1, -1), 0),
('TOPPADING', (0, 0), (-1, -1), 2),
('BOTTOMPADING', (0, 0), (-1, -1), 2),
]))
elements.append(signatory_table)
try:
doc.build(elements)
except MemoryError as me:
st.error(f"PDF generation failed due to memory issue: {str(me)}")
logger.error(f"Memory error during PDF build: {str(me)}")
return None
except Exception as e:
st.error(f"PDF generation failed: {str(e)}")
logger.error(f"PDF building failed: {str(e)}")
return None
buffer.seek(0)
logger.info("PDF buffer ready")
return buffer
except Exception as e:
st.error(f"Unexpected error in PDF generation: {str(e)}")
logger.error(f"Unexpected PDF generation error: {str(e)}")
return None
def process_input(input_data):
if input_data is None:
return None, None
if input_data.name.endswith(('.jpg', '.jpeg', '.png')):
try:
image = PILImage.open(input_data)
logger.info("Image processed successfully")
return cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR), image
except Exception as e:
st.error(f"Failed to process image: {str(e)}")
logger.error(f"Image processing failed: {str(e)}")
return None, None
elif input_data.name.endswith(('.mp4', '.avi', '.mov')):
tmp_path = None
try:
with tempfile.NamedTemporaryFile(delete=False, suffix='.mp4') as tmp:
tmp.write(input_data.read())
tmp_path = tmp.name
cap = cv2.VideoCapture(tmp_path)
ret, frame = cap.read()
cap.release()
if ret:
image = PILImage.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
logger.info("Video frame extracted successfully")
return frame, image
else:
st.error("Failed to extract frame from video.")
logger.error("Failed to extract video frame")
return None, None
except Exception as e:
st.error(f"Failed to process video: {str(e)}")
logger.error(f"Video processing failed: {str(e)}")
return None, None
finally:
if tmp_path and os.path.exists(tmp_path):
try:
os.unlink(tmp_path)
logger.info(f"Temporary file {tmp_path} cleaned up")
except Exception as e:
logger.warning(f"Failed to clean up temporary file {tmp_path}: {str(e)}")
return None, None
def analyze_face(image, patient_data):
face_mesh = load_face_mesh()
if face_mesh is None:
return None, None, None, "Failed to initialize face mesh."
hemoglobin_model, spo2_model, hr_model = load_models()
try:
frame = cv2.resize(image, (640, 480))
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
result = face_mesh.process(frame_rgb)
logger.info("Image processed for face detection")
except Exception as e:
st.error(f"Image processing failed: {str(e)}")
logger.error(f"Image processing failed: {str(e)}")
return None, None, None, "Image processing error."
if not result.multi_face_landmarks:
return None, None, None, "Face not detected. Please try another image or video."
landmarks = result.multi_face_landmarks[0]
features = extract_features(frame_rgb, landmarks.landmark)
if features is None:
return None, None, None, "Failed to extract image features."
analyzed_image = draw_analyzed_image(frame_rgb, landmarks)
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)),
"Temperature": train_model((97, 99)),
"BP Systolic": train_model((90, 120)),
"BP Diastolic": train_model((60, 80))
}
test_values = {}
for label in models:
if models[label] is None:
st.error(f"Model for {label} is not initialized.")
logger.error(f"Model not initialized for {label}")
return None, None, None, f"Model error for {label}."
try:
if label == "Hemoglobin":
prediction = models[label].predict([features])[0]
test_values[label] = prediction
else:
value = models[label].predict([[random.uniform(0.2, 0.5) for _ in range(7)]])[0]
test_values[label] = value
except Exception as e:
st.error(f"Prediction failed for {label}: {str(e)}")
logger.error(f"Prediction failed for {label}: {str(e)}")
return None, None, None, f"Prediction error for {label}."
try:
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))
logger.info(f"Vitals calculated: heart_rate={heart_rate}, spo2={spo2}, rr={rr}")
except Exception as e:
st.error(f"Vitals calculation failed: {str(e)}")
logger.error(f"Vitals calculation failed: {str(e)}")
return None, None, None, "Vitals calculation error."
test_results = {
"Hematology": [
("Hemoglobin", test_values["Hemoglobin"], (13.5, 17.5), get_risk_level(test_values["Hemoglobin"], (13.5, 17.5))),
("WBC Count", test_values["WBC Count"], (4.0, 11.0), get_risk_level(test_values["WBC Count"], (4.0, 11.0))),
("Platelet Count", test_values["Platelet Count"], (150, 450), get_risk_level(test_values["Platelet Count"], (150, 450)))
],
"Iron Panel": [
("Iron", test_values["Iron"], (60, 170), get_risk_level(test_values["Iron"], (60, 170))),
("Ferritin", test_values["Ferritin"], (30, 300), get_risk_level(test_values["Ferritin"], (30, 300))),
("TIBC", test_values["TIBC"], (250, 400), get_risk_level(test_values["TIBC"], (250, 400)))
],
"Liver & Kidney": [
("Bilirubin", test_values["Bilirubin"], (0.3, 1.2), get_risk_level(test_values["Bilirubin"], (0.3, 1.2))),
("Creatinine", test_values["Creatinine"], (0.6, 1.2), get_risk_level(test_values["Creatinine"], (0.6, 1.2))),
("Urea", test_values["Urea"], (7, 20), get_risk_level(test_values["Urea"], (7, 20)))
],
"Electrolytes": [
("Sodium", test_values["Sodium"], (135, 145), get_risk_level(test_values["Sodium"], (135, 145))),
("Potassium", test_values["Potassium"], (3.5, 5.1), get_risk_level(test_values["Potassium"], (3.5, 5.1)))
],
"Vitals": [
("SpO2", spo2, (95, 100), get_risk_level(spo2, (95, 100))),
("Heart Rate", heart_rate, (60, 100), get_risk_level(heart_rate, (60, 100))),
("Respiratory Rate", rr, (12, 20), get_risk_level(rr, (12, 20))),
("Temperature", test_values["Temperature"], (97, 99), get_risk_level(test_values["Temperature"], (97, 99))),
("BP Systolic", test_values["BP Systolic"], (90, 120), get_risk_level(test_values["BP Systolic"], (90, 120))),
("BP Diastolic", test_values["BP Diastolic"], (60, 80), get_risk_level(test_values["BP Diastolic"], (60, 80)))
]
}
logger.info(f"Test results generated: {test_results}")
return test_results, frame_rgb, analyzed_image
def preprocess_image(image):
transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
])
return transform(image).unsqueeze(0)
def predict_xray(image):
xray_model = load_xray_model()
if xray_model is None:
return "Error: X-ray model not loaded.", "", ""
image_tensor = preprocess_image(image)
with torch.no_grad():
outputs = xray_model(image_tensor)
probs = torch.nn.functional.softmax(outputs[0], dim=0)
conditions = ["Normal", "Pneumonia", "Cancer", "TB", "Other"]
results = {conditions[i]: float(probs[i]) for i in range(len(conditions))}
most_likely_condition = max(results, key=results.get)
confidence = results[most_likely_condition] * 100
summary = f"**Summary**: Based on the X-ray analysis, the most likely diagnosis is: {most_likely_condition} with a confidence of {confidence:.2f}%."
condition_details = {
"Normal": {
"description": "The X-ray shows no abnormal signs, and the lungs appear healthy.",
"recommendation": "No further tests are required. Continue with regular health check-ups."
},
"Pneumonia": {
"description": "Pneumonia is an infection that causes inflammation in the lungs.",
"recommendation": "Consult a healthcare provider for treatment."
},
"Cancer": {
"description": "Lung cancer may appear as abnormal growths in the lungs.",
"recommendation": "Consult an oncologist for further diagnostic procedures."
},
"TB": {
"description": "Tuberculosis is a bacterial infection that affects the lungs.",
"recommendation": "Seek immediate medical attention for treatment."
},
"Other": {
"description": "There may be other conditions requiring investigation.",
"recommendation": "Consult a radiologist for further analysis."
}
}
detailed_results = "
Advanced face-based health analysis using AI technology
Use camera (with permission) or upload a file
๐ Health Summary (as of {current_date}):
Hemoglobin: {key_metrics.get('Hemoglobin', ('N/A', 'N/A'))[0]} g/dL ({key_metrics.get('Hemoglobin', ('N/A', 'N/A'))[1]})
SpO2: {key_metrics.get('SpO2', ('N/A', 'N/A'))[0]}% ({key_metrics.get('SpO2', ('N/A', 'N/A'))[1]})
Heart Rate: {key_metrics.get('Heart Rate', ('N/A', 'N/A'))[0]} bpm ({key_metrics.get('Heart Rate', ('N/A', 'N/A'))[1]})
Critical Values: {critical_count}
Overall Status: {overall_status}
๐ค Patient: {}
๐ Age: {}
โง Gender: {}
๐ ID: {}
๐ Date: {}
๐ค Name: {}
๐ Age: {}
โง Gender: {}
๐ ID: {}
๐ Date: {}
Additional Feedback: {additional_feedback}