fmegahed commited on
Commit
b9c76ef
·
1 Parent(s): 8cbaaf6

Workflow for daily keep alive

Browse files
.github/workflows/daily-keepalive.yml ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Daily Keep-Alive
2
+
3
+ on:
4
+ schedule:
5
+ - cron: "0 6 * * *"
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: write
10
+
11
+ jobs:
12
+ keepalive:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - name: Checkout
16
+ uses: actions/checkout@v4
17
+ with:
18
+ fetch-depth: 0
19
+ lfs: true
20
+
21
+ - name: Update keep_alive.csv
22
+ run: |
23
+ python3 -c "
24
+ import datetime, csv
25
+ now = datetime.datetime.utcnow()
26
+ epoch = datetime.date(2022, 5, 26)
27
+ days = (now.date() - epoch).days
28
+ with open('keep_alive.csv', 'w', newline='') as f:
29
+ w = csv.writer(f)
30
+ w.writerow(['date', 'days_since_first_run', 'last_updated_utc'])
31
+ w.writerow([now.strftime('%Y-%m-%d'), days, now.strftime('%Y-%m-%dT%H:%M:%SZ')])
32
+ "
33
+
34
+ - name: Commit and push
35
+ env:
36
+ HF_TOKEN: ${{ secrets.HF_TOKEN }}
37
+ run: |
38
+ git config user.name "github-actions[bot]"
39
+ git config user.email "github-actions[bot]@users.noreply.github.com"
40
+ git add keep_alive.csv
41
+ git diff --cached --quiet && echo "No changes" && exit 0
42
+ git commit -m "chore: daily keep-alive $(date -u +%Y-%m-%d)"
43
+ git push origin main
44
+ git push https://fmegahed:$HF_TOKEN@huggingface.co/spaces/fmegahed/tavr_project main
.github/workflows/sync-to-hf.yml ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Sync to Hugging Face Spaces
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+
8
+ jobs:
9
+ sync:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - name: Checkout
13
+ uses: actions/checkout@v4
14
+ with:
15
+ fetch-depth: 0
16
+ lfs: true
17
+
18
+ - name: Push to Hugging Face
19
+ env:
20
+ HF_TOKEN: ${{ secrets.HF_TOKEN }}
21
+ run: |
22
+ git push https://fmegahed:$HF_TOKEN@huggingface.co/spaces/fmegahed/tavr_project main
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ .Claude.md
2
+ .claude/
CLAUDE.md ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ Medical prediction web app for TAVR (Transcatheter Aortic Valve Replacement) in-hospital mortality risk. Uses a pre-trained PyCaret logistic regression model (L2 penalty) trained on HCUP NIS data (2012-2019). Published in *Scientific Reports*: Alhwiti, T., Aldrugh, S., & Megahed, F. M. (2023).
8
+
9
+ **Primary repo:** GitHub. Auto-syncs to HF Spaces on every push to `main`.
10
+ **Deployed at:** `https://huggingface.co/spaces/fmegahed/tavr_project` (Docker-based Space)
11
+
12
+ ## Running the App
13
+
14
+ ```bash
15
+ # Local
16
+ python app.py
17
+
18
+ # Docker
19
+ docker build -t tavr-app .
20
+ docker run -p 7860:7860 tavr-app
21
+ ```
22
+
23
+ The app launches on port 7860 (configurable via `PORT` or `GRADIO_SERVER_PORT` env vars).
24
+
25
+ ## Architecture
26
+
27
+ Single-file application (`app.py`) with three layers:
28
+
29
+ 1. **Model loading** (`_ensure_model_file()` / `_get_model()`): Lazy-loads `final_model.pkl` with global caching. Falls back to downloading from GitHub if the local file is missing.
30
+
31
+ 2. **Prediction** (`predict()`): Takes 44 patient parameters (demographics, hospital info, 32 comorbidities), constructs a DataFrame with proper categorical types (including ordered categoricals for `zipinc_qrtl`), runs PyCaret's `predict_model()` with `raw_score=True`. Returns `{"Death": 0-1, "Survival": 0-1}` dict for `gr.Label`.
32
+
33
+ 3. **Gradio UI** (`gr.Blocks` with `gr.themes.Soft()`): 44 inputs organized in 4 tabs (Patient Demographics, Hospital Information, Comorbidities, Procedure). Explicit "Predict" button triggers prediction; output displayed as `gr.Label` with confidence bars.
34
+
35
+ ## GitHub Actions Workflows
36
+
37
+ - **`sync-to-hf.yml`**: Pushes to HF Spaces on every `main` push. Requires `HF_TOKEN` secret (write-access).
38
+ - **`daily-keepalive.yml`**: Runs daily at 06:00 UTC. Updates `keep_alive.csv` with current date/timestamp and pushes to both GitHub and HF to prevent Space from sleeping.
39
+
40
+ ## Key Constraints
41
+
42
+ - **Python 3.8** — pinned in the Dockerfile, all dependencies must be compatible
43
+ - **PyCaret 2.3.6** — requires `SKLEARN_ALLOW_DEPRECATED_SKLEARN_PACKAGE_INSTALL=True` env var for installation
44
+ - **All dependency versions are pinned** in `requirements.txt` — changing one may break others due to tight PyCaret/scikit-learn compatibility
45
+ - **`final_model.pkl`** is tracked via Git LFS (see `.gitattributes`)
46
+ - The model expects exact categorical column names and types; any change to input names in `predict()` will break predictions
47
+ - Gradio version is 3.50.2 (not 4.x) — API differs significantly from current Gradio
48
+
49
+ ## GitHub Setup
50
+
51
+ 1. Create a GitHub repo and add it as the `origin` remote
52
+ 2. Add `HF_TOKEN` secret (Settings > Secrets > Actions) with a write-access token from https://huggingface.co/settings/tokens
53
+ 3. Push to `main` — the sync workflow will mirror to HF Spaces automatically
README.md CHANGED
@@ -8,3 +8,14 @@ app_port: 7860
8
  pinned: false
9
  license: cc-by-4.0
10
  ---
 
 
 
 
 
 
 
 
 
 
 
 
8
  pinned: false
9
  license: cc-by-4.0
10
  ---
11
+
12
+ # Predicting In-Hospital Mortality After TAVR
13
+
14
+ A web app for predicting in-hospital mortality after Transcatheter Aortic Valve Replacement (TAVR) using a penalized logistic regression model trained on HCUP NIS data (2012-2019).
15
+
16
+ **Published paper:** [Alhwiti, T., Aldrugh, S., & Megahed, F. M. (2023), *Scientific Reports*](https://www.nature.com/articles/s41598-023-37358-9.pdf)
17
+
18
+ | | Link |
19
+ |---|---|
20
+ | GitHub | https://github.com/fmegahed/tavr_project |
21
+ | Hugging Face Space | https://huggingface.co/spaces/fmegahed/tavr_project |
app.py CHANGED
@@ -9,7 +9,6 @@ from pandas.api.types import CategoricalDtype
9
  from pycaret.classification import load_model, predict_model
10
 
11
  # Optional: load example data (not required for predictions, but kept since it exists in your repo)
12
- # If the file is missing, the app still runs.
13
  try:
14
  _ex_data = pd.read_csv("example_data2.csv")
15
  except Exception:
@@ -159,132 +158,179 @@ def predict(
159
  model = _get_model()
160
  pred = predict_model(model, df, raw_score=True)
161
 
162
- # These column names depend on how the model was trained and saved
163
- # This matches your original code: Score_Yes for death, Score_No for survival.
164
  return {
165
- "Death %": round(100 * float(pred["Score_Yes"].iloc[0]), 2),
166
- "Survival %": round(100 * float(pred["Score_No"].iloc[0]), 2),
167
- "Predicting Death Outcome": str(pred["Label"].iloc[0]),
168
  }
169
 
170
 
171
- inputs = [
172
- gr.Slider(minimum=18, maximum=100, value=80, label="Age"),
173
- gr.Dropdown(choices=["Female", "Male"], value="Female", label="Sex"),
174
- gr.Dropdown(
175
- choices=[
176
- "Asian or Pacific Islander",
177
- "Black",
178
- "Hispanic",
179
- "Native American",
180
- "White",
181
- "Other",
182
- ],
183
- value="White",
184
- label="Race",
185
- ),
186
- gr.Radio(choices=["Elective", "NonElective"], value="Elective", label="Elective"),
187
- gr.Radio(choices=["No", "Yes"], value="No", label="Weekend"),
188
- gr.Radio(
189
- choices=["FirstQ", "SecondQ", "ThirdQ", "FourthQ"],
190
- value="SecondQ",
191
- label="Zip Income Quartile",
192
- ),
193
- gr.Radio(
194
- choices=["Midwest", "Northeast", "South", "West"],
195
- value="South",
196
- label="Hospital Region",
197
- ),
198
- gr.Radio(
199
- choices=[
200
- "New England",
201
- "Middle Atlantic",
202
- "East North Central",
203
- "West North Central",
204
- "South Atlantic",
205
- "East South Central",
206
- "West South Central",
207
- "Mountain",
208
- "Pacific",
209
- ],
210
- value="South Atlantic",
211
- label="Hospital Division",
212
- ),
213
- gr.Radio(
214
- choices=["Urban teaching", "Urban nonteaching", "Rural"],
215
- value="Urban teaching",
216
- label="Hospital Location/Teaching",
217
- ),
218
- gr.Radio(choices=["Small", "Medium", "Large"], value="Large", label="Hospital Bedsize"),
219
- gr.Radio(
220
- choices=["Government_nonfederal", "Private_invest_own", "Private_not_profit"],
221
- value="Private_not_profit",
222
- label="Hospital Control",
223
- ),
224
- gr.Dropdown(
225
- choices=["Private insurance", "Medicare", "Medicaid", "Self-pay", "No charge", "Other"],
226
- value="Medicare",
227
- label="Payee",
228
- ),
229
- # Comorbidities
230
- gr.Radio(choices=["No", "Yes"], value="Yes", label="Anemia"),
231
- gr.Radio(choices=["No", "Yes"], value="Yes", label="Atrial Fibrillation"),
232
- gr.Radio(choices=["No", "Yes"], value="No", label="Cancer"),
233
- gr.Radio(choices=["No", "Yes"], value="Yes", label="Cardiac Arrhythmias"),
234
- gr.Radio(choices=["No", "Yes"], value="No", label="Carotid Artery Disease"),
235
- gr.Radio(choices=["No", "Yes"], value="Yes", label="Chronic Kidney Disease"),
236
- gr.Radio(choices=["No", "Yes"], value="Yes", label="Chronic Pulmonary Disease"),
237
- gr.Radio(choices=["No", "Yes"], value="No", label="Coagulopathy"),
238
- gr.Radio(choices=["No", "Yes"], value="No", label="Depression"),
239
- gr.Radio(choices=["No", "Yes"], value="Yes", label="Diabetes Mellitus"),
240
- gr.Radio(choices=["No", "Yes"], value="No", label="Drug Abuse"),
241
- gr.Radio(choices=["No", "Yes"], value="Yes", label="Dyslipidemia"),
242
- gr.Radio(choices=["No", "Yes"], value="No", label="Endocarditis"),
243
- gr.Radio(choices=["No", "Yes"], value="No", label="Family History"),
244
- gr.Radio(choices=["No", "Yes"], value="Yes", label="Fluid and Electrolyte Disorder"),
245
- gr.Radio(choices=["No", "Yes"], value="Yes", label="Heart Failure"),
246
- gr.Radio(choices=["No", "Yes"], value="Yes", label="Hypertension"),
247
- gr.Radio(choices=["No", "Yes"], value="Yes", label="Known CAD"),
248
- gr.Radio(choices=["No", "Yes"], value="No", label="Liver Disease"),
249
- gr.Radio(choices=["No", "Yes"], value="Yes", label="Obesity"),
250
- gr.Radio(choices=["No", "Yes"], value="Yes", label="Peripheral Vascular Disease"),
251
- gr.Radio(choices=["No", "Yes"], value="Yes", label="Prior CABG"),
252
- gr.Radio(choices=["No", "Yes"], value="Yes", label="Prior ICD"),
253
- gr.Radio(choices=["No", "Yes"], value="Yes", label="Prior MI"),
254
- gr.Radio(choices=["No", "Yes"], value="Yes", label="Prior PCI"),
255
- gr.Radio(choices=["No", "Yes"], value="Yes", label="Prior PPM"),
256
- gr.Radio(choices=["No", "Yes"], value="Yes", label="Prior TIA Stroke"),
257
- gr.Radio(choices=["No", "Yes"], value="No", label="Pulmonary Circulation Disorder"),
258
- gr.Radio(choices=["No", "Yes"], value="No", label="Smoker"),
259
- gr.Radio(choices=["No", "Yes"], value="Yes", label="Valvular Disease"),
260
- gr.Radio(choices=["No", "Yes"], value="No", label="Weight Loss"),
261
- gr.Radio(choices=["No", "Yes"], value="Yes", label="Endovascular TAVR"),
262
- gr.Radio(choices=["No", "Yes"], value="Yes", label="Transapical TAVR"),
263
- ]
264
 
265
- description_html = """
266
- <p style="font-size:16px; line-height:1.6;">
267
- This app predicts in-hospital mortality after TAVR using a finalized logistic regression model with L2 penalty,
268
- based on national inpatient data from 2012–2019 (HCUP NIS).<br>
269
- <br>
270
- Published paper:
271
- <a href="https://www.nature.com/articles/s41598-023-37358-9.pdf" target="_blank">
272
- Alhwiti, T., Aldrugh, S., & Megahed, F. M. (2023), <i>Scientific Reports</i>
273
- </a>
274
- </p>
275
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
276
 
277
- iface = gr.Interface(
278
- fn=predict,
279
- inputs=inputs,
280
- outputs="text",
281
- live=True,
282
- title="Predicting In-Hospital Mortality After TAVR Using Preoperative Variables and Penalized Logistic Regression",
283
- description=description_html,
284
- css="https://bootswatch.com/5/journal/bootstrap.css",
285
- )
286
 
287
  if __name__ == "__main__":
288
- # Works locally, in Docker, and on HF Spaces (PORT is commonly set by platforms)
289
  port = int(os.getenv("PORT", os.getenv("GRADIO_SERVER_PORT", "7860")))
290
- iface.launch(server_name="0.0.0.0", server_port=port)
 
9
  from pycaret.classification import load_model, predict_model
10
 
11
  # Optional: load example data (not required for predictions, but kept since it exists in your repo)
 
12
  try:
13
  _ex_data = pd.read_csv("example_data2.csv")
14
  except Exception:
 
158
  model = _get_model()
159
  pred = predict_model(model, df, raw_score=True)
160
 
161
+ # Return dict with 0-1 scale for gr.Label confidence bars
 
162
  return {
163
+ "Death": float(pred["Score_Yes"].iloc[0]),
164
+ "Survival": float(pred["Score_No"].iloc[0]),
 
165
  }
166
 
167
 
168
+ # ---------------------------------------------------------------------------
169
+ # UI — gr.Blocks with tabs
170
+ # ---------------------------------------------------------------------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
 
172
+ with gr.Blocks(theme=gr.themes.Soft(), title="TAVR Mortality Prediction") as demo:
173
+
174
+ gr.Markdown(
175
+ """
176
+ # Predicting In-Hospital Mortality After TAVR
177
+
178
+ This app predicts in-hospital mortality after Transcatheter Aortic Valve
179
+ Replacement (TAVR) using a logistic regression model (L2 penalty) trained
180
+ on national inpatient data from 2012-2019 (HCUP NIS).
181
+
182
+ **Paper:**
183
+ [Alhwiti, T., Aldrugh, S., & Megahed, F. M. (2023), *Scientific Reports*](https://www.nature.com/articles/s41598-023-37358-9.pdf)
184
+ """
185
+ )
186
+
187
+ with gr.Row():
188
+ # ---- Left: inputs ----
189
+ with gr.Column(scale=3):
190
+ with gr.Tab("Patient Demographics"):
191
+ with gr.Row():
192
+ age = gr.Slider(minimum=18, maximum=100, value=80, label="Age")
193
+ female = gr.Dropdown(choices=["Female", "Male"], value="Female", label="Sex")
194
+ with gr.Row():
195
+ race = gr.Dropdown(
196
+ choices=[
197
+ "Asian or Pacific Islander",
198
+ "Black",
199
+ "Hispanic",
200
+ "Native American",
201
+ "White",
202
+ "Other",
203
+ ],
204
+ value="White",
205
+ label="Race",
206
+ )
207
+ pay = gr.Dropdown(
208
+ choices=["Private insurance", "Medicare", "Medicaid", "Self-pay", "No charge", "Other"],
209
+ value="Medicare",
210
+ label="Payee",
211
+ )
212
+ with gr.Row():
213
+ elective = gr.Radio(choices=["Elective", "NonElective"], value="Elective", label="Elective")
214
+ aweekend = gr.Radio(choices=["No", "Yes"], value="No", label="Weekend Admission")
215
+ with gr.Row():
216
+ zipinc_qrtl = gr.Radio(
217
+ choices=["FirstQ", "SecondQ", "ThirdQ", "FourthQ"],
218
+ value="SecondQ",
219
+ label="Zip Income Quartile",
220
+ )
221
+
222
+ with gr.Tab("Hospital Information"):
223
+ with gr.Row():
224
+ hosp_region = gr.Radio(
225
+ choices=["Midwest", "Northeast", "South", "West"],
226
+ value="South",
227
+ label="Hospital Region",
228
+ )
229
+ hosp_bedsize = gr.Radio(
230
+ choices=["Small", "Medium", "Large"],
231
+ value="Large",
232
+ label="Hospital Bedsize",
233
+ )
234
+ with gr.Row():
235
+ hosp_division = gr.Radio(
236
+ choices=[
237
+ "New England",
238
+ "Middle Atlantic",
239
+ "East North Central",
240
+ "West North Central",
241
+ "South Atlantic",
242
+ "East South Central",
243
+ "West South Central",
244
+ "Mountain",
245
+ "Pacific",
246
+ ],
247
+ value="South Atlantic",
248
+ label="Hospital Division",
249
+ )
250
+ with gr.Row():
251
+ hosp_locteach = gr.Radio(
252
+ choices=["Urban teaching", "Urban nonteaching", "Rural"],
253
+ value="Urban teaching",
254
+ label="Hospital Location/Teaching",
255
+ )
256
+ h_contrl = gr.Radio(
257
+ choices=["Government_nonfederal", "Private_invest_own", "Private_not_profit"],
258
+ value="Private_not_profit",
259
+ label="Hospital Control",
260
+ )
261
+
262
+ with gr.Tab("Comorbidities"):
263
+ with gr.Row():
264
+ anemia = gr.Radio(choices=["No", "Yes"], value="Yes", label="Anemia")
265
+ atrial_fibrillation = gr.Radio(choices=["No", "Yes"], value="Yes", label="Atrial Fibrillation")
266
+ cancer = gr.Radio(choices=["No", "Yes"], value="No", label="Cancer")
267
+ with gr.Row():
268
+ cardiac_arrhythmias = gr.Radio(choices=["No", "Yes"], value="Yes", label="Cardiac Arrhythmias")
269
+ carotid_artery_disease = gr.Radio(choices=["No", "Yes"], value="No", label="Carotid Artery Disease")
270
+ chronic_kidney_disease = gr.Radio(choices=["No", "Yes"], value="Yes", label="Chronic Kidney Disease")
271
+ with gr.Row():
272
+ chronic_pulmonary_disease = gr.Radio(choices=["No", "Yes"], value="Yes", label="Chronic Pulmonary Disease")
273
+ coagulopathy = gr.Radio(choices=["No", "Yes"], value="No", label="Coagulopathy")
274
+ depression = gr.Radio(choices=["No", "Yes"], value="No", label="Depression")
275
+ with gr.Row():
276
+ diabetes_mellitus = gr.Radio(choices=["No", "Yes"], value="Yes", label="Diabetes Mellitus")
277
+ drug_abuse = gr.Radio(choices=["No", "Yes"], value="No", label="Drug Abuse")
278
+ dyslipidemia = gr.Radio(choices=["No", "Yes"], value="Yes", label="Dyslipidemia")
279
+ with gr.Row():
280
+ endocarditis = gr.Radio(choices=["No", "Yes"], value="No", label="Endocarditis")
281
+ family_history = gr.Radio(choices=["No", "Yes"], value="No", label="Family History")
282
+ fluid_and_electrolyte_disorder = gr.Radio(choices=["No", "Yes"], value="Yes", label="Fluid & Electrolyte Disorder")
283
+ with gr.Row():
284
+ heart_failure = gr.Radio(choices=["No", "Yes"], value="Yes", label="Heart Failure")
285
+ hypertension = gr.Radio(choices=["No", "Yes"], value="Yes", label="Hypertension")
286
+ known_cad = gr.Radio(choices=["No", "Yes"], value="Yes", label="Known CAD")
287
+ with gr.Row():
288
+ liver_disease = gr.Radio(choices=["No", "Yes"], value="No", label="Liver Disease")
289
+ obesity = gr.Radio(choices=["No", "Yes"], value="Yes", label="Obesity")
290
+ peripheral_vascular_disease = gr.Radio(choices=["No", "Yes"], value="Yes", label="Peripheral Vascular Disease")
291
+ with gr.Row():
292
+ prior_cabg = gr.Radio(choices=["No", "Yes"], value="Yes", label="Prior CABG")
293
+ prior_icd = gr.Radio(choices=["No", "Yes"], value="Yes", label="Prior ICD")
294
+ prior_mi = gr.Radio(choices=["No", "Yes"], value="Yes", label="Prior MI")
295
+ with gr.Row():
296
+ prior_pci = gr.Radio(choices=["No", "Yes"], value="Yes", label="Prior PCI")
297
+ prior_ppm = gr.Radio(choices=["No", "Yes"], value="Yes", label="Prior PPM")
298
+ prior_tia_stroke = gr.Radio(choices=["No", "Yes"], value="Yes", label="Prior TIA/Stroke")
299
+ with gr.Row():
300
+ pulmonary_circulation_disorder = gr.Radio(choices=["No", "Yes"], value="No", label="Pulmonary Circulation Disorder")
301
+ smoker = gr.Radio(choices=["No", "Yes"], value="No", label="Smoker")
302
+ valvular_disease = gr.Radio(choices=["No", "Yes"], value="Yes", label="Valvular Disease")
303
+ with gr.Row():
304
+ weight_loss = gr.Radio(choices=["No", "Yes"], value="No", label="Weight Loss")
305
+
306
+ with gr.Tab("Procedure"):
307
+ with gr.Row():
308
+ endovascular_tavr = gr.Radio(choices=["No", "Yes"], value="Yes", label="Endovascular TAVR")
309
+ transapical_tavr = gr.Radio(choices=["No", "Yes"], value="Yes", label="Transapical TAVR")
310
+
311
+ # ---- Right: output ----
312
+ with gr.Column(scale=1):
313
+ predict_btn = gr.Button("Predict", variant="primary")
314
+ output = gr.Label(label="Prediction", num_top_classes=2)
315
+
316
+ # Wire up the button
317
+ all_inputs = [
318
+ age, female, race, elective, aweekend, zipinc_qrtl,
319
+ hosp_region, hosp_division, hosp_locteach, hosp_bedsize, h_contrl, pay,
320
+ anemia, atrial_fibrillation, cancer, cardiac_arrhythmias,
321
+ carotid_artery_disease, chronic_kidney_disease, chronic_pulmonary_disease,
322
+ coagulopathy, depression, diabetes_mellitus, drug_abuse, dyslipidemia,
323
+ endocarditis, family_history, fluid_and_electrolyte_disorder,
324
+ heart_failure, hypertension, known_cad, liver_disease, obesity,
325
+ peripheral_vascular_disease, prior_cabg, prior_icd, prior_mi,
326
+ prior_pci, prior_ppm, prior_tia_stroke, pulmonary_circulation_disorder,
327
+ smoker, valvular_disease, weight_loss,
328
+ endovascular_tavr, transapical_tavr,
329
+ ]
330
+
331
+ predict_btn.click(fn=predict, inputs=all_inputs, outputs=output)
332
 
 
 
 
 
 
 
 
 
 
333
 
334
  if __name__ == "__main__":
 
335
  port = int(os.getenv("PORT", os.getenv("GRADIO_SERVER_PORT", "7860")))
336
+ demo.launch(server_name="0.0.0.0", server_port=port)
keep_alive.csv ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ date,days_since_first_run,last_updated_utc
2
+ 2026-02-10,1356,2026-02-10T00:00:00Z