File size: 10,414 Bytes
0983def
eb3d3f0
 
 
9905bc8
 
70542c8
 
eb3d3f0
70542c8
eb3d3f0
0983def
eb3d3f0
70542c8
9905bc8
39eef5a
 
 
 
71a8976
 
 
39eef5a
 
9905bc8
 
360e696
 
 
9905bc8
 
 
 
70542c8
edb3de6
f04f718
46d6884
f04f718
9905bc8
31ad924
9905bc8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70542c8
7e2c1f5
 
 
accfefd
7e2c1f5
accfefd
7e2c1f5
accfefd
 
70542c8
9e64c66
 
 
 
 
 
 
 
 
9905bc8
9e64c66
 
19e69ba
70542c8
 
 
 
 
 
 
 
 
 
 
 
 
c2d95e3
70542c8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9161fde
70542c8
19e69ba
 
 
 
 
 
 
 
 
e674980
f04f718
94e0da7
e674980
 
f04f718
 
70542c8
e674980
f04f718
 
 
94e0da7
46d6884
 
 
 
 
9161fde
f04f718
 
 
 
 
19e69ba
94e0da7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70542c8
94e0da7
e6d165e
 
 
 
94e0da7
e6d165e
c391431
19e69ba
70542c8
19e69ba
70542c8
19e69ba
bdf9b37
f8f4a14
10c366b
 
f8f4a14
bdf9b37
19e69ba
9161fde
f8f4a14
10c366b
c391431
 
10c366b
 
f8f4a14
19e69ba
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
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

# 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
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")

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", "πŸ”»", "#FFCCCC")
    elif value > high:
        return ("High", "πŸ”Ί", "#FFE680")
    else:
        return ("Normal", "βœ…", "#CCFFCC")

# Function to build table for test results
def build_table(title, rows):
    html = (
        f'<div style="margin-bottom: 24px;">'
        f'<h4 style="margin: 8px 0;">{title}</h4>'
        f'<table style="width:100%; border-collapse:collapse;">'
        f'<thead><tr style="background:#f0f0f0;"><th style="padding:8px;border:1px solid #ccc;">Test</th><th style="padding:8px;border:1px solid #ccc;">Result</th><th style="padding:8px;border:1px solid #ccc;">Expected Range</th><th style="padding:8px;border:1px solid #ccc;">Level</th></tr></thead><tbody>'
    )
    for label, value, ref in rows:
        level, icon, bg = get_risk_color(value, ref)
        html += f'<tr style="background:{bg};"><td style="padding:6px;border:1px solid #ccc;">{label}</td><td style="padding:6px;border:1px solid #ccc;">{value:.2f}</td><td style="padding:6px;border:1px solid #ccc;">{ref[0]} – {ref[1]}</td><td style="padding:6px;border:1px solid #ccc;">{icon} {level}</td></tr>'
    html += '</tbody></table></div>'
    return html

# Build health card layout
def build_health_card(profile_image, test_results, summary):
    html = f"""
    <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 20px auto; border-radius: 12px; background-color: #f3f8fc; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); padding: 20px; color: #333;">
        <div style="display: flex; align-items: center; margin-bottom: 20px;">
            <img src="data:image/png;base64,{profile_image}" alt="Profile" style="width: 80px; height: 80px; border-radius: 50%; margin-right: 15px;">
            <div>
                <h2 style="margin: 0; font-size: 24px;">Health Card</h2>
                <p style="margin: 5px 0; color: #777;">Lab Test Results</p>
            </div>
        </div>

        <div style="font-size: 16px; margin-bottom: 20px;">
            {test_results['Hematology']}  <!-- Single reference to Hematology -->
            {test_results['Iron Panel']}
            {test_results['Liver & Kidney']}
            {test_results['Electrolytes']}
            {test_results['Vitals']}
        </div>

        <div style="background-color: #ffffff; padding: 15px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
            <h4 style="margin: 0;">πŸ“ Summary for You</h4>
            <ul style="margin-top: 10px; color: #555;">
                {summary}
            </ul>
        </div>

        <div style="margin-top: 20px; text-align: center;">
            <h4>πŸ“ž Book a Lab Test</h4>
            <p style="color: #777;">Prefer confirmation? Find certified labs near you.</p>
            <button style="padding: 10px 20px; background-color: #007BFF; color: white; border: none; border-radius: 5px; cursor: pointer;">
                Find Labs Near Me
            </button>
        </div>
    </div>
    """
    return html

# Analyze face and return results
def analyze_face(image):
    if image is None:
        return "<div style='color:red;'>⚠️ Error: No image provided.</div>", None
    frame_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    result = face_mesh.process(frame_rgb)
    if not result.multi_face_landmarks:
        return "<div style='color:red;'>⚠️ Error: Face not detected.</div>", None
    landmarks = result.multi_face_landmarks[0].landmark
    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  # simulate other 7D inputs

    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))

    # Prepare the test results
    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 = "<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>"

    # Convert frame_rgb to base64 for profile picture (this is temporary placeholder)
    _, buffer = cv2.imencode('.png', frame_rgb)
    profile_image_base64 = base64.b64encode(buffer).decode('utf-8')

    # Generate Health Card HTML
    health_card_html = build_health_card(profile_image_base64, test_results, summary)
    return health_card_html, frame_rgb

# Create Gradio interface
with gr.Blocks() as demo:
    gr.Markdown("""# 🧠 Face-Based Lab Test AI Report (Video Mode)""")
    with gr.Row():
        with gr.Column():
            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_image = gr.Image(label="πŸ“· Key Frame Snapshot")

    def route_inputs(mode, image, video):
        health_card_html, frame_rgb = analyze_face(image) if mode == "Image" else analyze_face(video)
        return health_card_html, frame_rgb

    submit_btn.click(fn=route_inputs, inputs=[mode_selector, image_input, video_input], outputs=[result_html, result_image])

demo.launch()