File size: 6,428 Bytes
eb3d3f0
7e2c1f5
eb3d3f0
0983def
eb3d3f0
 
 
 
 
0983def
eb3d3f0
 
 
 
 
 
 
 
 
7e2c1f5
eb3d3f0
 
 
 
 
 
 
7e2c1f5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0983def
 
7e2c1f5
eb3d3f0
0983def
 
eb3d3f0
0983def
 
 
 
eb3d3f0
7e2c1f5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0983def
7e2c1f5
eb3d3f0
7e2c1f5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
eb3d3f0
0983def
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
# Face Detection-Based AI Automation of Lab Tests
# Gradio App with Mobile-Responsive UI and Risk-Level Coloring

import gradio as gr
import cv2
import numpy as np
import mediapipe as mp

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)

def estimate_heart_rate(frame, landmarks):
    h, w, _ = frame.shape
    forehead_pts = [landmarks[10], landmarks[338], landmarks[297], landmarks[332]]
    mask = np.zeros((h, w), dtype=np.uint8)
    pts = np.array([[int(pt.x * w), int(pt.y * h)] for pt in forehead_pts], np.int32)
    cv2.fillConvexPoly(mask, pts, 255)
    green_channel = cv2.split(frame)[1]
    mean_intensity = cv2.mean(green_channel, mask=mask)[0]
    heart_rate = int(60 + 30 * np.sin(mean_intensity / 255.0 * np.pi))
    return heart_rate

def estimate_spo2_rr(heart_rate):
    spo2 = min(100, max(90, 97 + (heart_rate % 5 - 2)))
    rr = int(12 + abs(heart_rate % 5 - 2))
    return spo2, rr

def get_risk_color(value, normal_range):
    low, high = normal_range
    if value < low:
        return "🔻 LOW"
    elif value > high:
        return "🔺 HIGH"
    else:
        return "✅ Normal"

def generate_flags_extended(params):
    hb, wbc, platelets, iron, ferritin, tibc, bilirubin, creatinine, tsh, cortisol, fbs, hba1c = params
    flags = []
    if hb < 13.5:
        flags.append("Hemoglobin Low - Possible Anemia")
    if wbc < 4.0 or wbc > 11.0:
        flags.append("Abnormal WBC Count - Possible Infection")
    if platelets < 150:
        flags.append("Platelet Drop Risk - Bruising Possible")
    if iron < 60:
        flags.append("Iron Deficiency Detected")
    if ferritin < 30:
        flags.append("Low Ferritin - Iron Store Low")
    if tibc > 400:
        flags.append("High TIBC - Iron Absorption Issue")
    if bilirubin > 1.2:
        flags.append("Jaundice Detected - Elevated Bilirubin")
    if creatinine > 1.2:
        flags.append("Kidney Function Concern - High Creatinine")
    if tsh < 0.4 or tsh > 4.0:
        flags.append("Thyroid Imbalance - Check TSH")
    if cortisol < 5 or cortisol > 25:
        flags.append("Stress Hormone Abnormality - Cortisol")
    if fbs > 110:
        flags.append("High Fasting Blood Sugar")
    if hba1c > 5.7:
        flags.append("Elevated HbA1c - Diabetes Risk")
    flags.append("Mood / Stress analysis requires separate behavioral model")
    return flags

def analyze_face(image):
    if image is None:
        return {}, None

    frame_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    result = face_mesh.process(frame_rgb)

    if result.multi_face_landmarks:
        landmarks = result.multi_face_landmarks[0].landmark
        heart_rate = estimate_heart_rate(frame_rgb, landmarks)
        spo2, rr = estimate_spo2_rr(heart_rate)

        hb, wbc, platelets = 12.3, 6.4, 210
        iron, ferritin, tibc = 55, 45, 340
        bilirubin, creatinine = 1.5, 1.3
        tsh, cortisol = 2.5, 18
        fbs, hba1c = 120, 6.2

        flags = generate_flags_extended([hb, wbc, platelets, iron, ferritin, tibc, bilirubin, creatinine, tsh, cortisol, fbs, hba1c])

        sections = {
            "🩸 Hematology": [
                f"Hemoglobin (Hb): {hb} g/dL - {get_risk_color(hb, (13.5, 17.5))}",
                f"WBC Count: {wbc} x10^3/uL - {get_risk_color(wbc, (4.0, 11.0))}",
                f"Platelet Count: {platelets} x10^3/uL - {get_risk_color(platelets, (150, 450))}"
            ],
            "🧬 Iron & Liver Panel": [
                f"Iron: {iron} µg/dL - {get_risk_color(iron, (60, 170))}",
                f"Ferritin: {ferritin} ng/mL - {get_risk_color(ferritin, (30, 300))}",
                f"TIBC: {tibc} µg/dL - {get_risk_color(tibc, (250, 400))}",
                f"Bilirubin: {bilirubin} mg/dL - {get_risk_color(bilirubin, (0.3, 1.2))}"
            ],
            "🧪 Kidney, Thyroid & Stress": [
                f"Creatinine: {creatinine} mg/dL - {get_risk_color(creatinine, (0.6, 1.2))}",
                f"TSH: {tsh} µIU/mL - {get_risk_color(tsh, (0.4, 4.0))}",
                f"Cortisol: {cortisol} µg/dL - {get_risk_color(cortisol, (5, 25))}"
            ],
            "🧁 Metabolic Panel": [
                f"Fasting Blood Sugar: {fbs} mg/dL - {get_risk_color(fbs, (70, 110))}",
                f"HbA1c: {hba1c}% - {get_risk_color(hba1c, (4.0, 5.7))}"
            ],
            "❤️ Vital Signs": [
                f"SpO2: {spo2}% - {get_risk_color(spo2, (95, 100))}",
                f"Heart Rate: {heart_rate} bpm - {get_risk_color(heart_rate, (60, 100))}",
                f"Respiratory Rate: {rr} breaths/min - {get_risk_color(rr, (12, 20))}",
                "Blood Pressure: Low (simulated)"
            ],
            "⚠️ Risk Flags": flags
        }
        return sections, frame_rgb
    else:
        return {"⚠️ Error": ["Face not detected"]}, None

# Mobile-optimized UI with styled labels
demo = gr.Blocks(css="""
@media only screen and (max-width: 768px) {
  .gr-block.gr-column { width: 100% !important; }
}
""")
with demo:
    gr.Markdown("""
    # 🧠 Face-Based AI Lab Test Inference
    Upload a clear face image to simulate categorized lab reports with visual grouping.
    """)

    with gr.Row():
        with gr.Column(scale=1):
            image_input = gr.Image(type="numpy", label="📸 Upload a Face Image")
            submit_btn = gr.Button("🔍 Analyze Now")
        with gr.Column(scale=2):
            accordion_output = gr.Accordion("📂 Diagnostic Summary", open=True)
            with accordion_output:
                result_html = gr.HighlightedText(label="📊 Grouped Report", combine_adjacent=True)
            result_image = gr.Image(label="🧍 Annotated Face Scan")

    def format_report(sections):
        lines = []
        for title, values in sections.items():
            lines.append((f"{title}",))
            for item in values:
                lines.append((f" - {item}",))
        return lines

    submit_btn.click(
        fn=analyze_face,
        inputs=image_input,
        outputs=[result_html, result_image],
        preprocess=False,
        postprocess=False,
        _js="(data) => [data]"
    ).then(
        fn=format_report,
        inputs=None,
        outputs=result_html
    )

    gr.Markdown("---\n✅ Optimized for Mobile · Risk Indicators: 🔻 Low, 🔺 High, ✅ Normal")

demo.launch()