Spaces:
Sleeping
Sleeping
File size: 5,042 Bytes
34e78aa 3cbe2b7 de5fb2b 3cbe2b7 185bfc5 34e78aa 4d3e684 185bfc5 34e78aa 3cbe2b7 72ee068 3cbe2b7 2a9ddd1 185bfc5 3cbe2b7 3dfbd3d 3cbe2b7 f5e2953 3cbe2b7 |
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 |
import os, joblib
import streamlit as st
import pandas as pd, joblib, json
from pathlib import Path
st.set_page_config(page_title="VOβ Max & Training Readiness", page_icon="π", layout="centered")
st.title("π VOβ Max & Training Readiness (Synthetic, Demo)")
st.caption("CPU-only β’ Synthetic data β’ Not medical advice.")
#DATA_PATH = "assets/vo2_real_augmented.csv"
#MODEL_PATH = "model/vo2_predictor.joblib"
HERE = Path(__file__).resolve().parent
MODEL_PATH = HERE / "model" / "vo2_predictor.joblib" # src/model/...
# If your model is at repo_root/model, use: HERE.parent / "model" / "vo2_predictor.joblib"
DATA_PATH = HERE / ".." / "assets" / "vo2_real_augmented.csv"
assert MODEL_PATH.exists(), f"Model not found at: {MODEL_PATH}"
pipe = joblib.load(MODEL_PATH)
@st.cache_resource
def load_model():
return joblib.load(MODEL_PATH)
pipe = load_model()
@st.cache_data
def load_sample():
try:
df = pd.read_csv(DATA_PATH)
return df
except Exception:
return pd.DataFrame()
df = load_sample()
#with st.expander("Sample data (first 10 rows)"):
# if not df.empty:
# st.dataframe(df.head(10), use_container_width=True)
# else:
# st.info("Sample CSV not found.")
st.subheader("Enter runner metrics")
cols = st.columns(2)
sex = cols[0].selectbox("Sex (0=female, 1=male)", [0,1], index=1)
age = cols[1].slider("Age", 18, 70, 35)
height_cm = cols[0].slider("Height (cm)", 150, 200, 172)
weight_kg = cols[1].slider("Weight (kg)", 45, 120, 74)
total_lean_mass = cols[0].slider("Total Lean Mass", 30, 90, 55)
wbtpf = cols[1].slider("Whole Body Tissue Percent Fat", 12, 49, 28)
resting_hr = cols[0].slider("Resting HR (bpm)", 40, 100, 60)
max_hr = cols[1].slider("Max HR (bpm)", 150, 205, 185)
avg_hr_during_run = cols[0].slider("Avg HR During Run (bpm)", 95, 190, 150)
hr_recovery_1min = cols[1].slider("HR Recovery 1 min (bpm drop)", 10, 55, 30)
distance_km = cols[0].slider("Distance of last run (km)", 1, 30, 5)
duration_min = cols[1].slider("Duration of last run (min)", 10, 180, 30)
pace_min_per_km = max(3.5, min(12.0, duration_min / max(distance_km, 0.5)))
avg_speed_kmh = 60.0 / pace_min_per_km
elevation_gain_m = cols[0].slider("Elevation Gain (m)", 0, 600, 50)
training_hours_week = cols[1].slider("Training Hours / Week", 0, 12, 4)
avg_intensity = cols[0].slider("Avg Intensity (1β10)", 1, 10, 6)
rest_days = cols[1].slider("Rest Days (last 7d)", 0, 4, 1)
sleep_hours_last_night = cols[0].slider("Sleep Hours Last Night", 3, 10, 7)
avg_sleep_hours_week = cols[1].slider("Avg Sleep Hours / Week", 4, 9, 7)
sleep_quality_score = cols[0].slider("Sleep Quality (0β100)", 25, 95, 72)
resting_hr_delta = resting_hr - 60
temperature_C = cols[1].slider("Temperature (Β°C)", 0, 35, 18)
humidity_pct = cols[0].slider("Humidity (%)", 15, 95, 55)
altitude_m = cols[1].slider("Altitude (m)", 0, 2200, 200)
hr_ratio = avg_hr_during_run / max_hr if max_hr>0 else 0
training_load_index = distance_km * (avg_hr_during_run/100.0) / (duration_min/60.0 + 0.1)
speed_per_kg = avg_speed_kmh / (weight_kg/70.0)
features = {
"sex":sex,"age":age,"height_cm":height_cm,"weight_kg":weight_kg,
"bmi": weight_kg/((height_cm/100.0)**2),
"total_lean_mass":total_lean_mass,"wbtpf":wbtpf,
"resting_hr":resting_hr,"max_hr":max_hr,"avg_hr_during_run":avg_hr_during_run,
"hr_recovery_1min":hr_recovery_1min,
"distance_km":distance_km,"duration_min":duration_min,
"pace_min_per_km":pace_min_per_km,"avg_speed_kmh":avg_speed_kmh,
"elevation_gain_m":elevation_gain_m,
"training_hours_week":training_hours_week,"avg_intensity":avg_intensity,"rest_days":rest_days,
"sleep_hours_last_night":sleep_hours_last_night,"avg_sleep_hours_week":avg_sleep_hours_week,
"sleep_quality_score":sleep_quality_score,"resting_hr_delta":resting_hr_delta,
"temperature_C":temperature_C,"humidity_pct":humidity_pct,"altitude_m":altitude_m,
"hr_ratio":hr_ratio,"training_load_index":training_load_index,"speed_per_kg":speed_per_kg
}
def coaching_tip(vo2, sleep_quality, training_hours, hrr):
tips = []
if vo2 < 38: tips.append("Prioritize easy aerobic runs (Zone 2) 3β4x/week.")
elif vo2 < 48: tips.append("Add 1 weekly interval (e.g., 4Γ4min hard, full recovery).")
else: tips.append("Maintain with polarized training; 80% easy, 20% hard.")
if sleep_quality < 60: tips.append("Boost sleep hygiene to 7β8h; reduce late caffeine/screens.")
if training_hours > 8: tips.append("High load detected β deload 10β20% this week.")
if hrr < 20: tips.append("Low HRR β keep intensities sub-threshold for 2β3 days.")
return " ".join(tips) or "Keep up the good work!"
if st.button("Predict VOβ max"):
x = pd.DataFrame([features])
pipe = load_model()
vo2 = float(pipe.predict(x)[0])
tip = coaching_tip(vo2, sleep_quality_score, training_hours_week, hr_recovery_1min)
st.metric("Estimated VOβ max (ml/kg/min)", f"{vo2:.1f}")
st.success(tip)
st.divider()
st.caption("Limitations: Synthetic data; not a medical device; demo use only.")
|