Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -76,19 +76,62 @@ def extract_features(seg_path, high_risk_threshold_mm=5.0):
|
|
| 76 |
|
| 77 |
def calculate_risk_and_format(mask_path, no_chemo, pd_surgery):
|
| 78 |
"""Runs extraction, ML prediction, and formats UI output."""
|
|
|
|
| 79 |
mac, vev, aev, ttv = extract_features(mask_path)
|
| 80 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
if risk_model is not None:
|
| 82 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
prob_r1 = risk_model.predict_proba(features)[0][1]
|
| 84 |
else:
|
| 85 |
prob_r1 = 0.72 # Fallback dummy
|
| 86 |
|
|
|
|
| 87 |
risk_percentage = prob_r1 * 100
|
| 88 |
risk_color = "red" if risk_percentage > 50 else "green"
|
| 89 |
risk_display = f"<h2 style='color: {risk_color}; margin-top: 0;'>Predicted probability of R1 resection: {risk_percentage:.1f}%</h2>"
|
| 90 |
|
| 91 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
|
| 93 |
|
| 94 |
# PIPELINE HANDLERS
|
|
|
|
| 76 |
|
| 77 |
def calculate_risk_and_format(mask_path, no_chemo, pd_surgery):
|
| 78 |
"""Runs extraction, ML prediction, and formats UI output."""
|
| 79 |
+
# 1. Extract raw metrics
|
| 80 |
mac, vev, aev, ttv = extract_features(mask_path)
|
| 81 |
|
| 82 |
+
# Convert textboxes safely
|
| 83 |
+
try:
|
| 84 |
+
chemo_val = int(no_chemo)
|
| 85 |
+
pd_val = int(pd_surgery)
|
| 86 |
+
except ValueError:
|
| 87 |
+
error_msg = "**Error:** Clinical metadata fields must be numbers (1 or 0)."
|
| 88 |
+
return (gr.update(value=error_msg, visible=True), "", "", "", "", "")
|
| 89 |
+
|
| 90 |
+
# 2. Hardcode the Means and Stds from your training data
|
| 91 |
+
# Extracted from your means/stds arrays based on their index positions
|
| 92 |
+
TTV_MEAN, TTV_STD = 8980.23827, 8281.19811
|
| 93 |
+
MAC_MEAN, MAC_STD = 8.53567157, 8.92353600
|
| 94 |
+
AEV_MEAN, AEV_STD = 155.784393, 367.152035
|
| 95 |
+
VEV_MEAN, VEV_STD = 576.025386, 559.944824
|
| 96 |
+
|
| 97 |
+
# 3. Apply Z-score Normalization
|
| 98 |
+
scaled_ttv = (ttv - TTV_MEAN) / TTV_STD
|
| 99 |
+
scaled_mac = (mac - MAC_MEAN) / MAC_STD
|
| 100 |
+
scaled_aev = (aev - AEV_MEAN) / AEV_STD
|
| 101 |
+
scaled_vev = (vev - VEV_MEAN) / VEV_STD
|
| 102 |
+
|
| 103 |
+
# 4. Predict Risk
|
| 104 |
if risk_model is not None:
|
| 105 |
+
# STRICT ORDER MATCHING your column_order:
|
| 106 |
+
# ['Chemo_0', 'Surgery_1', 'Total_Tumor_Volume_mm3_arterial', 'Min_Distance_mm_arterial', 'High_Risk_Volume_mm3_5mm_arterial', 'High_Risk_Volume_mm3_5mm_venous']
|
| 107 |
+
features = np.array([[
|
| 108 |
+
chemo_val, # Chemo_0
|
| 109 |
+
pd_val, # Surgery_1
|
| 110 |
+
scaled_ttv, # Total_Tumor_Volume_mm3_arterial
|
| 111 |
+
scaled_mac, # Min_Distance_mm_arterial
|
| 112 |
+
scaled_aev, # High_Risk_Volume_mm3_5mm_arterial
|
| 113 |
+
scaled_vev # High_Risk_Volume_mm3_5mm_venous
|
| 114 |
+
]])
|
| 115 |
+
|
| 116 |
prob_r1 = risk_model.predict_proba(features)[0][1]
|
| 117 |
else:
|
| 118 |
prob_r1 = 0.72 # Fallback dummy
|
| 119 |
|
| 120 |
+
# 5. Format Outputs
|
| 121 |
risk_percentage = prob_r1 * 100
|
| 122 |
risk_color = "red" if risk_percentage > 50 else "green"
|
| 123 |
risk_display = f"<h2 style='color: {risk_color}; margin-top: 0;'>Predicted probability of R1 resection: {risk_percentage:.1f}%</h2>"
|
| 124 |
|
| 125 |
+
# Notice we still display the RAW un-normalized values to the user in the UI,
|
| 126 |
+
# but the model calculates risk using the SCALED values.
|
| 127 |
+
return (
|
| 128 |
+
gr.update(value="", visible=False),
|
| 129 |
+
f"{mac:.1f}",
|
| 130 |
+
f"{vev:.1f}",
|
| 131 |
+
f"{aev:.1f}",
|
| 132 |
+
f"{ttv:.1f}",
|
| 133 |
+
risk_display
|
| 134 |
+
)
|
| 135 |
|
| 136 |
|
| 137 |
# PIPELINE HANDLERS
|