medtechdev commited on
Commit
a56569a
·
verified ·
1 Parent(s): a815584

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -595
app.py DELETED
@@ -1,595 +0,0 @@
1
- """
2
- NON-INVASIVE ANEMIA SCREENING WEBAPP
3
- =====================================
4
- Estimates hemoglobin from palpebral conjunctiva image + standardized form inputs.
5
-
6
- Deploy on Hugging Face Spaces (free).
7
- Collects anonymized data for model improvement.
8
-
9
- Author: JIPMER Anemia Screening Study
10
- """
11
-
12
- import gradio as gr
13
- import numpy as np
14
- import pandas as pd
15
- import pickle
16
- import cv2
17
- import uuid
18
- from datetime import datetime
19
- from pathlib import Path
20
-
21
- # ============================================================
22
- # CONFIGURATION
23
- # ============================================================
24
- MODEL_PATH = "model.pkl"
25
- YOLO_PATH = "best.pt"
26
- DATA_LOG_PATH = "collected_data.csv" # Local fallback; use Google Sheets in production
27
-
28
- # ============================================================
29
- # LOAD MODELS (done once at startup)
30
- # ============================================================
31
- def load_models():
32
- """Load ML model and YOLO segmentation model."""
33
- global ml_model, feature_names, yolo_model
34
-
35
- # Load ML model
36
- with open(MODEL_PATH, 'rb') as f:
37
- model_data = pickle.load(f)
38
- ml_model = model_data['model']
39
- feature_names = model_data['features']
40
- print(f"✅ Loaded ML model: {model_data.get('name', 'Unknown')}")
41
- print(f" Features: {len(feature_names)}")
42
-
43
- # Load YOLO
44
- from ultralytics import YOLO
45
- yolo_model = YOLO(YOLO_PATH)
46
- print(f"✅ Loaded YOLO model")
47
-
48
- return True
49
-
50
- # ============================================================
51
- # IMAGE PROCESSING
52
- # ============================================================
53
- def calibrate_image(img):
54
- """White balance calibration using grey card."""
55
- try:
56
- if img is None:
57
- return None
58
-
59
- # Convert to RGB if needed
60
- if len(img.shape) == 2:
61
- img_rgb = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
62
- elif img.shape[2] == 4:
63
- img_rgb = cv2.cvtColor(img, cv2.COLOR_RGBA2RGB)
64
- else:
65
- img_rgb = img.copy()
66
-
67
- gray = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2GRAY)
68
- _, thresh = cv2.threshold(gray, 180, 255, cv2.THRESH_BINARY)
69
- contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
70
-
71
- if not contours:
72
- _, thresh = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)
73
- contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
74
-
75
- if not contours:
76
- return img_rgb
77
-
78
- c = max(contours, key=cv2.contourArea)
79
- x, y, w, h = cv2.boundingRect(c)
80
-
81
- if w * h < 1000:
82
- return img_rgb
83
-
84
- patch = img_rgb[y+h//4:y+3*h//4, x+w//4:x+3*w//4]
85
- if patch.size == 0:
86
- return img_rgb
87
-
88
- avg = np.mean(patch, axis=(0, 1))
89
- if any(v < 10 for v in avg):
90
- return img_rgb
91
-
92
- scale = np.array([128, 128, 128]) / avg
93
- return np.clip(img_rgb * scale, 0, 255).astype(np.uint8)
94
- except Exception as e:
95
- print(f"Calibration error: {e}")
96
- return img
97
-
98
-
99
- def extract_image_features(img):
100
- """Run YOLO segmentation and extract color features."""
101
- try:
102
- # Calibrate
103
- img_cal = calibrate_image(img)
104
- if img_cal is None:
105
- return None
106
-
107
- # YOLO segmentation
108
- results = yolo_model(img_cal, verbose=False)
109
-
110
- if len(results) > 0 and results[0].masks is not None:
111
- masks = results[0].masks.data.cpu().numpy()
112
- confs = results[0].boxes.conf.cpu().numpy()
113
- if len(confs) > 0:
114
- m = masks[np.argmax(confs)]
115
- m = cv2.resize(m, (img_cal.shape[1], img_cal.shape[0]))
116
- roi_mask = (m > 0.5).astype(np.uint8) * 255
117
- else:
118
- # Fallback to center crop
119
- h, w = img_cal.shape[:2]
120
- roi_mask = np.zeros((h, w), dtype=np.uint8)
121
- roi_mask[h//4:3*h//4, w//4:3*w//4] = 255
122
- else:
123
- h, w = img_cal.shape[:2]
124
- roi_mask = np.zeros((h, w), dtype=np.uint8)
125
- roi_mask[h//4:3*h//4, w//4:3*w//4] = 255
126
-
127
- # Extract color features from ROI
128
- px = img_cal[roi_mask > 0]
129
- if len(px) == 0:
130
- return None
131
-
132
- R, G, B = [np.mean(px[:, i]) for i in range(3)]
133
-
134
- hsv = cv2.cvtColor(img_cal, cv2.COLOR_RGB2HSV)
135
- hpx = hsv[roi_mask > 0]
136
- H, S, V = [np.mean(hpx[:, i]) for i in range(3)]
137
-
138
- lab = cv2.cvtColor(img_cal, cv2.COLOR_RGB2LAB)
139
- lpx = lab[roi_mask > 0]
140
- L, A, Bc = [np.mean(lpx[:, i]) for i in range(3)]
141
-
142
- return {
143
- 'R': R, 'G': G, 'B': B,
144
- 'H': H, 'S': S, 'V': V,
145
- 'L_color': L, 'A_color': A, 'B_color': Bc
146
- }
147
- except Exception as e:
148
- print(f"Image processing error: {e}")
149
- return None
150
-
151
-
152
- # ============================================================
153
- # FORM INPUT → FEATURE VECTOR MAPPING
154
- # ============================================================
155
- def form_to_features(
156
- age, income_range, family_size, diet,
157
- food_grains, food_leafy, food_cereals, food_pulses,
158
- food_fish, food_eggs, food_meat, food_jaggery, food_nuts,
159
- fruit_freq, veg_freq, tea_coffee,
160
- comorb_dm, comorb_htn, comorb_thyroid,
161
- prev_anemia, family_anemia, hookworm, bleeding_disorder, deworming,
162
- menstrual, pads_per_day,
163
- gravida, para, live_births, abortions, stillbirths,
164
- family_dm, family_htn
165
- ):
166
- """Convert standardized form inputs to feature vector."""
167
-
168
- # Income mapping
169
- income_map = {
170
- "Below ₹5,000": 2500,
171
- "₹5,000 - ₹10,000": 7500,
172
- "₹10,000 - ₹15,000": 12500,
173
- "₹15,000 - ₹25,000": 20000,
174
- "₹25,000 - ₹50,000": 37500,
175
- "Above ₹50,000": 75000
176
- }
177
- income = income_map.get(income_range, 20000)
178
- income_per_capita = income / max(family_size, 1)
179
-
180
- # Diet one-hot
181
- diet_veg = 1 if diet == "Vegetarian" else 0
182
- diet_nonveg = 1 if diet == "Non-vegetarian" else 0
183
- diet_mixed = 1 if diet == "Mixed" else 0
184
-
185
- # Iron foods
186
- food_iron_count = sum([food_grains, food_leafy, food_cereals, food_pulses,
187
- food_fish, food_eggs, food_meat, food_jaggery, food_nuts])
188
-
189
- # Frequency mapping
190
- freq_map = {"Daily": 4, "Twice a week": 3, "Once a week": 2, "Rarely": 1, "Never": 0}
191
- fruit_freq_val = freq_map.get(fruit_freq, 2)
192
- veg_freq_val = freq_map.get(veg_freq, 2)
193
-
194
- # Binary mappings
195
- tea_coffee_val = 1 if tea_coffee == "Yes" else 0
196
- comorb_dm_val = 1 if comorb_dm else 0
197
- comorb_htn_val = 1 if comorb_htn else 0
198
- comorb_thyroid_val = 1 if comorb_thyroid else 0
199
- comorb_none = 1 if not any([comorb_dm, comorb_htn, comorb_thyroid]) else 0
200
- comorb_count = comorb_dm_val + comorb_htn_val + comorb_thyroid_val
201
-
202
- prev_anemia_val = 1 if prev_anemia == "Yes" else 0
203
- family_anemia_val = 1 if family_anemia == "Yes" else 0
204
- hookworm_val = 1 if hookworm == "Yes" else 0
205
- bleeding_val = 1 if bleeding_disorder == "Yes" else 0
206
- deworming_val = 1 if deworming == "Yes" else 0
207
-
208
- # Menstrual
209
- menstrual_regular = 1 if menstrual == "Regular" else 0
210
- menstrual_irregular = 1 if menstrual == "Irregular" else 0
211
-
212
- # Pads mapping
213
- pads_map = {"1-2": 1.5, "2-3": 2.5, "3-4": 3.5, "4-5": 4.5, "More than 5": 6, "Not applicable": 2.5}
214
- pads_val = pads_map.get(pads_per_day, 2.5)
215
-
216
- # Obstetric
217
- has_obstetric = 1 if gravida > 0 else 0
218
- pregnancy_loss = abortions + stillbirths
219
- parity_ratio = para / gravida if gravida > 0 else 0
220
-
221
- family_dm_val = 1 if family_dm == "Yes" else 0
222
- family_htn_val = 1 if family_htn == "Yes" else 0
223
-
224
- # Build feature dict (order must match training!)
225
- features = {
226
- 'age': age,
227
- 'income': income,
228
- 'family_size': family_size,
229
- 'income_per_capita': income_per_capita,
230
- 'diet_veg': diet_veg,
231
- 'diet_nonveg': diet_nonveg,
232
- 'diet_mixed': diet_mixed,
233
- 'food_whole_grains': 1 if food_grains else 0,
234
- 'food_green_leafy_vegetables': 1 if food_leafy else 0,
235
- 'food_cereals': 1 if food_cereals else 0,
236
- 'food_pulses': 1 if food_pulses else 0,
237
- 'food_fish': 1 if food_fish else 0,
238
- 'food_eggs': 1 if food_eggs else 0,
239
- 'food_meat': 1 if food_meat else 0,
240
- 'food_jaggery': 1 if food_jaggery else 0,
241
- 'food_nuts': 1 if food_nuts else 0,
242
- 'food_iron_count': food_iron_count,
243
- 'fruit_freq': fruit_freq_val,
244
- 'veg_freq': veg_freq_val,
245
- 'tea_coffee_daily': tea_coffee_val,
246
- 'tea_coffee_daily_missing': 0,
247
- 'comorb_dm': comorb_dm_val,
248
- 'comorb_htn': comorb_htn_val,
249
- 'comorb_thyroid': comorb_thyroid_val,
250
- 'comorb_none': comorb_none,
251
- 'comorb_count': comorb_count,
252
- 'prev_anemia': prev_anemia_val,
253
- 'prev_anemia_missing': 0,
254
- 'family_anemia': family_anemia_val,
255
- 'family_anemia_missing': 0,
256
- 'hookworm_history': hookworm_val,
257
- 'hookworm_history_missing': 0,
258
- 'bleeding_disorder': bleeding_val,
259
- 'bleeding_disorder_missing': 0,
260
- 'deworming_done': deworming_val,
261
- 'deworming_done_missing': 0,
262
- 'menstrual_regular': menstrual_regular,
263
- 'menstrual_irregular': menstrual_irregular,
264
- 'pads_per_day': pads_val,
265
- 'pads_missing': 0,
266
- 'gravida': gravida,
267
- 'para': para,
268
- 'live_births': live_births,
269
- 'abortions': abortions,
270
- 'stillbirths': stillbirths,
271
- 'has_obstetric_history': has_obstetric,
272
- 'pregnancy_loss': pregnancy_loss,
273
- 'parity_ratio': parity_ratio,
274
- 'family_dm': family_dm_val,
275
- 'family_dm_missing': 0,
276
- 'family_htn': family_htn_val,
277
- 'family_htn_missing': 0,
278
- }
279
-
280
- return features
281
-
282
-
283
- # ============================================================
284
- # DATA LOGGING
285
- # ============================================================
286
- def log_data(session_id, features, image_features, predicted_hb, actual_hb=None):
287
- """Log anonymized data for model improvement."""
288
- try:
289
- record = {
290
- 'session_id': session_id,
291
- 'timestamp': datetime.now().isoformat(),
292
- 'predicted_hb': predicted_hb,
293
- 'actual_hb': actual_hb,
294
- **features,
295
- **image_features
296
- }
297
-
298
- df = pd.DataFrame([record])
299
-
300
- # Append to CSV (or send to Google Sheets in production)
301
- if Path(DATA_LOG_PATH).exists():
302
- df.to_csv(DATA_LOG_PATH, mode='a', header=False, index=False)
303
- else:
304
- df.to_csv(DATA_LOG_PATH, index=False)
305
-
306
- return True
307
- except Exception as e:
308
- print(f"Logging error: {e}")
309
- return False
310
-
311
-
312
- # ============================================================
313
- # MAIN PREDICTION FUNCTION
314
- # ============================================================
315
- def predict_hb(
316
- image,
317
- age, income_range, family_size, diet,
318
- food_grains, food_leafy, food_cereals, food_pulses,
319
- food_fish, food_eggs, food_meat, food_jaggery, food_nuts,
320
- fruit_freq, veg_freq, tea_coffee,
321
- comorb_dm, comorb_htn, comorb_thyroid,
322
- prev_anemia, family_anemia, hookworm, bleeding_disorder, deworming,
323
- menstrual, pads_per_day,
324
- gravida, para, live_births, abortions, stillbirths,
325
- family_dm, family_htn,
326
- actual_hb_input
327
- ):
328
- """Main prediction function."""
329
-
330
- # Generate session ID
331
- session_id = str(uuid.uuid4())[:8]
332
-
333
- # Validate image
334
- if image is None:
335
- return "❌ Please upload an image of the palpebral conjunctiva with color card.", "", ""
336
-
337
- # Extract image features
338
- image_features = extract_image_features(image)
339
- if image_features is None:
340
- return "❌ Could not process image. Please ensure the palpebral conjunctiva is clearly visible.", "", ""
341
-
342
- # Convert form to features
343
- tabular_features = form_to_features(
344
- age, income_range, family_size, diet,
345
- food_grains, food_leafy, food_cereals, food_pulses,
346
- food_fish, food_eggs, food_meat, food_jaggery, food_nuts,
347
- fruit_freq, veg_freq, tea_coffee,
348
- comorb_dm, comorb_htn, comorb_thyroid,
349
- prev_anemia, family_anemia, hookworm, bleeding_disorder, deworming,
350
- menstrual, pads_per_day,
351
- gravida, para, live_births, abortions, stillbirths,
352
- family_dm, family_htn
353
- )
354
-
355
- # Combine features
356
- all_features = {**tabular_features, **image_features}
357
-
358
- # Create feature vector in correct order
359
- X = pd.DataFrame([all_features])[feature_names]
360
-
361
- # Predict
362
- hb_pred = ml_model.predict(X)[0]
363
- hb_pred = round(float(hb_pred), 1)
364
-
365
- # Classify severity
366
- if hb_pred >= 12:
367
- severity = "Normal"
368
- color = "🟢"
369
- recommendation = "No signs of anemia detected. Maintain a balanced diet."
370
- elif hb_pred >= 11:
371
- severity = "Mild Anemia"
372
- color = "🟡"
373
- recommendation = "Mild anemia indicated. Consider iron-rich foods and consult a healthcare provider."
374
- elif hb_pred >= 8:
375
- severity = "Moderate Anemia"
376
- color = "🟠"
377
- recommendation = "Moderate anemia detected. Please consult a healthcare provider for a confirmatory blood test."
378
- else:
379
- severity = "Severe Anemia"
380
- color = "🔴"
381
- recommendation = "Severe anemia indicated. Please seek immediate medical attention."
382
-
383
- # Log data
384
- actual_hb = float(actual_hb_input) if actual_hb_input and actual_hb_input > 0 else None
385
- log_data(session_id, tabular_features, image_features, hb_pred, actual_hb)
386
-
387
- # Format result
388
- result = f"""
389
- ## {color} Estimated Hemoglobin: {hb_pred} g/dL
390
-
391
- ### Status: {severity}
392
-
393
- {recommendation}
394
-
395
- ---
396
- *Session ID: {session_id}*
397
- *Save this ID if you want to provide actual Hb value later.*
398
- """
399
-
400
- return result, session_id, f"{hb_pred} g/dL"
401
-
402
-
403
- # ============================================================
404
- # GRADIO INTERFACE
405
- # ============================================================
406
- def create_interface():
407
- """Build the Gradio UI."""
408
-
409
- with gr.Blocks(title="Anemia Screening Tool", theme=gr.themes.Soft()) as app:
410
-
411
- gr.Markdown("""
412
- # 🩺 Non-Invasive Anemia Screening Tool
413
-
414
- Estimate hemoglobin levels from a photo of the palpebral conjunctiva (inner eyelid).
415
-
416
- **Instructions:**
417
- 1. Upload a clear photo of the lower inner eyelid WITH the color calibration card visible
418
- 2. Fill in the health information form
419
- 3. Click "Estimate Hemoglobin"
420
-
421
- ⚠️ *This is a screening tool, not a diagnosis. Please consult a healthcare provider for confirmation.*
422
-
423
- ---
424
- """)
425
-
426
- with gr.Row():
427
- # Left column - Image upload
428
- with gr.Column(scale=1):
429
- gr.Markdown("### 📷 Image Upload")
430
- image_input = gr.Image(
431
- label="Palpebral Conjunctiva Image (with color card)",
432
- type="numpy"
433
- )
434
- gr.Markdown("*Ensure the grey/white color card is visible in the image for accurate calibration.*")
435
-
436
- # Right column - Form
437
- with gr.Column(scale=2):
438
- gr.Markdown("### 📋 Health Information")
439
-
440
- with gr.Accordion("Demographics", open=True):
441
- with gr.Row():
442
- age = gr.Slider(minimum=10, maximum=80, value=25, step=1, label="Age (years)")
443
- family_size = gr.Slider(minimum=1, maximum=15, value=4, step=1, label="Family Size")
444
- income_range = gr.Dropdown(
445
- choices=["Below ₹5,000", "₹5,000 - ₹10,000", "₹10,000 - ₹15,000",
446
- "₹15,000 - ₹25,000", "₹25,000 - ₹50,000", "Above ₹50,000"],
447
- value="₹10,000 - ₹15,000",
448
- label="Monthly Family Income"
449
- )
450
-
451
- with gr.Accordion("Diet & Nutrition", open=True):
452
- diet = gr.Radio(
453
- choices=["Vegetarian", "Non-vegetarian", "Mixed"],
454
- value="Mixed",
455
- label="Dietary Habit"
456
- )
457
- gr.Markdown("**Iron-rich foods consumed regularly:**")
458
- with gr.Row():
459
- food_grains = gr.Checkbox(label="Whole Grains", value=True)
460
- food_leafy = gr.Checkbox(label="Leafy Vegetables", value=True)
461
- food_cereals = gr.Checkbox(label="Cereals", value=True)
462
- with gr.Row():
463
- food_pulses = gr.Checkbox(label="Pulses/Lentils", value=True)
464
- food_fish = gr.Checkbox(label="Fish", value=False)
465
- food_eggs = gr.Checkbox(label="Eggs", value=False)
466
- with gr.Row():
467
- food_meat = gr.Checkbox(label="Meat", value=False)
468
- food_jaggery = gr.Checkbox(label="Jaggery", value=False)
469
- food_nuts = gr.Checkbox(label="Nuts", value=False)
470
- with gr.Row():
471
- fruit_freq = gr.Dropdown(
472
- choices=["Daily", "Twice a week", "Once a week", "Rarely", "Never"],
473
- value="Twice a week",
474
- label="Fruit Consumption"
475
- )
476
- veg_freq = gr.Dropdown(
477
- choices=["Daily", "Twice a week", "Once a week", "Rarely", "Never"],
478
- value="Daily",
479
- label="Vegetable Consumption"
480
- )
481
- tea_coffee = gr.Radio(
482
- choices=["Yes", "No"],
483
- value="Yes",
484
- label="Daily Tea/Coffee Consumption"
485
- )
486
-
487
- with gr.Accordion("Medical History", open=False):
488
- gr.Markdown("**Current Conditions:**")
489
- with gr.Row():
490
- comorb_dm = gr.Checkbox(label="Diabetes", value=False)
491
- comorb_htn = gr.Checkbox(label="Hypertension", value=False)
492
- comorb_thyroid = gr.Checkbox(label="Thyroid Disorder", value=False)
493
- with gr.Row():
494
- prev_anemia = gr.Radio(choices=["Yes", "No"], value="No", label="Anemia in past 12 months")
495
- family_anemia = gr.Radio(choices=["Yes", "No"], value="No", label="Family history of anemia")
496
- with gr.Row():
497
- hookworm = gr.Radio(choices=["Yes", "No"], value="No", label="History of hookworm")
498
- bleeding_disorder = gr.Radio(choices=["Yes", "No"], value="No", label="Bleeding disorder")
499
- with gr.Row():
500
- deworming = gr.Radio(choices=["Yes", "No"], value="Yes", label="Deworming done")
501
- with gr.Row():
502
- family_dm = gr.Radio(choices=["Yes", "No"], value="No", label="Family history: Diabetes")
503
- family_htn = gr.Radio(choices=["Yes", "No"], value="No", label="Family history: Hypertension")
504
-
505
- with gr.Accordion("Menstrual & Obstetric History", open=False):
506
- with gr.Row():
507
- menstrual = gr.Radio(
508
- choices=["Regular", "Irregular", "Not applicable"],
509
- value="Regular",
510
- label="Menstrual Cycle"
511
- )
512
- pads_per_day = gr.Dropdown(
513
- choices=["1-2", "2-3", "3-4", "4-5", "More than 5", "Not applicable"],
514
- value="2-3",
515
- label="Pads per day (first 2-3 days)"
516
- )
517
- gr.Markdown("**Obstetric History (enter 0 if not applicable):**")
518
- with gr.Row():
519
- gravida = gr.Slider(minimum=0, maximum=10, value=0, step=1, label="Gravida (pregnancies)")
520
- para = gr.Slider(minimum=0, maximum=10, value=0, step=1, label="Para (deliveries)")
521
- live_births = gr.Slider(minimum=0, maximum=10, value=0, step=1, label="Live Births")
522
- with gr.Row():
523
- abortions = gr.Slider(minimum=0, maximum=5, value=0, step=1, label="Abortions")
524
- stillbirths = gr.Slider(minimum=0, maximum=5, value=0, step=1, label="Stillbirths")
525
-
526
- gr.Markdown("---")
527
-
528
- with gr.Row():
529
- with gr.Column():
530
- actual_hb_input = gr.Number(
531
- label="Already have a blood test result? Enter actual Hb (g/dL) — Optional",
532
- value=0,
533
- minimum=0,
534
- maximum=25
535
- )
536
- with gr.Column():
537
- submit_btn = gr.Button("🔬 Estimate Hemoglobin", variant="primary", size="lg")
538
-
539
- gr.Markdown("---")
540
-
541
- # Results
542
- with gr.Row():
543
- result_output = gr.Markdown(label="Result")
544
- with gr.Row():
545
- session_output = gr.Textbox(label="Session ID", interactive=False)
546
- hb_output = gr.Textbox(label="Estimated Hb", interactive=False)
547
-
548
- # Privacy notice
549
- gr.Markdown("""
550
- ---
551
- ### 🔒 Privacy Notice
552
-
553
- Your data is collected **anonymously** to improve this screening tool. We do NOT collect:
554
- - Name, address, phone number, or email
555
- - Raw images (only extracted color features are stored)
556
- - Any personally identifiable information
557
-
558
- By using this tool, you consent to anonymous data collection for research purposes.
559
-
560
- ---
561
- *Developed by for an Anemia Screening Study | For research use only | Contact gangadharananirudh@gmail.com for more info*
562
- """)
563
-
564
- # Connect button
565
- submit_btn.click(
566
- fn=predict_hb,
567
- inputs=[
568
- image_input,
569
- age, income_range, family_size, diet,
570
- food_grains, food_leafy, food_cereals, food_pulses,
571
- food_fish, food_eggs, food_meat, food_jaggery, food_nuts,
572
- fruit_freq, veg_freq, tea_coffee,
573
- comorb_dm, comorb_htn, comorb_thyroid,
574
- prev_anemia, family_anemia, hookworm, bleeding_disorder, deworming,
575
- menstrual, pads_per_day,
576
- gravida, para, live_births, abortions, stillbirths,
577
- family_dm, family_htn,
578
- actual_hb_input
579
- ],
580
- outputs=[result_output, session_output, hb_output]
581
- )
582
-
583
- return app
584
-
585
-
586
- # ============================================================
587
- # MAIN
588
- # ============================================================
589
- if __name__ == "__main__":
590
- print("Loading models...")
591
- load_models()
592
-
593
- print("Starting app...")
594
- app = create_interface()
595
- app.launch()