Spaces:
Sleeping
Sleeping
Update src/streamlit_app.py
Browse files- src/streamlit_app.py +84 -60
src/streamlit_app.py
CHANGED
|
@@ -4,92 +4,116 @@ import numpy as np
|
|
| 4 |
import pandas as pd
|
| 5 |
|
| 6 |
# ------------------------------
|
| 7 |
-
# Load
|
| 8 |
# ------------------------------
|
| 9 |
MODEL_PATH = "src/voting_model.joblib"
|
| 10 |
SCALER_PATH = "src/scaler.joblib"
|
| 11 |
|
| 12 |
@st.cache_resource
|
| 13 |
-
def
|
| 14 |
try:
|
| 15 |
model = joblib.load(MODEL_PATH)
|
| 16 |
scaler = joblib.load(SCALER_PATH)
|
| 17 |
return model, scaler
|
| 18 |
except Exception as e:
|
| 19 |
-
st.error(f"Error loading model
|
| 20 |
return None, None
|
| 21 |
|
| 22 |
-
model, scaler =
|
| 23 |
-
|
| 24 |
-
st.title("π§ Stress Detection Model")
|
| 25 |
-
st.write("Enter the required parameters and get the prediction.")
|
| 26 |
|
| 27 |
# ------------------------------
|
| 28 |
-
#
|
| 29 |
-
# These MUST match the training dataset exactly
|
| 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 |
-
"stiffness_low",
|
| 55 |
-
"stiffness_high",
|
| 56 |
-
"stiffness_diff",
|
| 57 |
-
"strength_ratio",
|
| 58 |
-
"total_height",
|
| 59 |
-
"total_width",
|
| 60 |
-
"slenderness",
|
| 61 |
-
"total_area_low",
|
| 62 |
-
"seismic_power",
|
| 63 |
-
"fault_attenuation",
|
| 64 |
-
"total_mass",
|
| 65 |
-
"base_shear"
|
| 66 |
-
]
|
| 67 |
|
| 68 |
# ------------------------------
|
| 69 |
-
# User
|
| 70 |
# ------------------------------
|
| 71 |
-
|
| 72 |
-
st.
|
|
|
|
|
|
|
|
|
|
| 73 |
|
| 74 |
-
|
| 75 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
|
| 77 |
-
|
| 78 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
|
| 80 |
# ------------------------------
|
| 81 |
-
# Prediction
|
| 82 |
# ------------------------------
|
| 83 |
-
if
|
| 84 |
if model is None or scaler is None:
|
| 85 |
-
st.error("Model
|
| 86 |
else:
|
| 87 |
try:
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
|
| 92 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 93 |
|
| 94 |
except Exception as e:
|
| 95 |
-
st.error(f"
|
|
|
|
|
|
| 4 |
import pandas as pd
|
| 5 |
|
| 6 |
# ------------------------------
|
| 7 |
+
# 1. Load Model & Scaler
|
| 8 |
# ------------------------------
|
| 9 |
MODEL_PATH = "src/voting_model.joblib"
|
| 10 |
SCALER_PATH = "src/scaler.joblib"
|
| 11 |
|
| 12 |
@st.cache_resource
|
| 13 |
+
def load_artifacts():
|
| 14 |
try:
|
| 15 |
model = joblib.load(MODEL_PATH)
|
| 16 |
scaler = joblib.load(SCALER_PATH)
|
| 17 |
return model, scaler
|
| 18 |
except Exception as e:
|
| 19 |
+
st.error(f"Error loading model: {e}")
|
| 20 |
return None, None
|
| 21 |
|
| 22 |
+
model, scaler = load_artifacts()
|
|
|
|
|
|
|
|
|
|
| 23 |
|
| 24 |
# ------------------------------
|
| 25 |
+
# 2. Feature Engineering Function
|
|
|
|
| 26 |
# ------------------------------
|
| 27 |
+
def engineer_features(df):
|
| 28 |
+
data = df.copy()
|
| 29 |
+
epsilon = 1e-6
|
| 30 |
+
|
| 31 |
+
data['stiffness_low'] = data['Columns 1-3 I mm4*10^6'] / (data['Floor height m']**3 + epsilon)
|
| 32 |
+
data['stiffness_high'] = data['Columns 4-6 I mm4*10^6'] / (data['Floor height m']**3 + epsilon)
|
| 33 |
+
data['stiffness_diff'] = data['stiffness_low'] - data['stiffness_high']
|
| 34 |
+
|
| 35 |
+
data['strength_ratio'] = data['Column fy Mpa'] / (data['Beam fy Mpa'] + epsilon)
|
| 36 |
+
|
| 37 |
+
data['total_height'] = data['Number of floors'] * data['Floor height m']
|
| 38 |
+
data['total_width'] = data['Spans'] * data['Span width m']
|
| 39 |
+
data['slenderness'] = data['total_height'] / (data['total_width'] + epsilon)
|
| 40 |
+
data['total_area_low'] = data['Columns 1-3 A mm2'] * (data['Spans'] + 1)
|
| 41 |
+
|
| 42 |
+
data['seismic_power'] = data['PGA g'] * data['Magnitude']
|
| 43 |
+
data['fault_attenuation'] = data['Magnitude'] / np.log1p(data['Distance to fault km'])
|
| 44 |
+
|
| 45 |
+
data['total_mass'] = data['Floor mass kg'] * data['Number of floors']
|
| 46 |
+
data['base_shear'] = data['total_mass'] * data['PGA g']
|
| 47 |
+
|
| 48 |
+
data = data.replace([np.inf, -np.inf], 0)
|
| 49 |
+
return data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
|
| 51 |
# ------------------------------
|
| 52 |
+
# 3. User Input Section
|
| 53 |
# ------------------------------
|
| 54 |
+
st.title("π’ Seismic Building Safety Prediction")
|
| 55 |
+
st.write("""
|
| 56 |
+
This AI model predicts the **Maximum Interstorey Drift (mm)** a building might experience during an earthquake.
|
| 57 |
+
Lower drift values generally indicate safer buildings.
|
| 58 |
+
""")
|
| 59 |
|
| 60 |
+
RAW_INPUTS = [
|
| 61 |
+
"Column fy Mpa", "Beam fy Mpa",
|
| 62 |
+
"Columns 1-3 I mm4*10^6", "Columns 4-6 I mm4*10^6",
|
| 63 |
+
"Columns 1-3 A mm2", "Columns 4-6 A mm2", "Beam I mm4*10^6",
|
| 64 |
+
"Spans", "Number of floors", "Floor height m", "Span width m",
|
| 65 |
+
"LLRS tributary width m", "Floor mass kg", "Facade Load kN/m",
|
| 66 |
+
"PGA g", "Magnitude", "Distance to fault km", "Period s",
|
| 67 |
+
"Final Dead Load", "Final Live Load"
|
| 68 |
+
]
|
| 69 |
|
| 70 |
+
input_data = {}
|
| 71 |
+
|
| 72 |
+
with st.form("input_form"):
|
| 73 |
+
c1, c2 = st.columns(2)
|
| 74 |
+
|
| 75 |
+
for i, col_name in enumerate(RAW_INPUTS):
|
| 76 |
+
if i % 2 == 0:
|
| 77 |
+
with c1:
|
| 78 |
+
input_data[col_name] = st.number_input(col_name, value=0.0, format="%.2f")
|
| 79 |
+
else:
|
| 80 |
+
with c2:
|
| 81 |
+
input_data[col_name] = st.number_input(col_name, value=0.0, format="%.2f")
|
| 82 |
+
|
| 83 |
+
soil_class = st.selectbox("Soil Class", ["A (Other)", "B", "C"])
|
| 84 |
+
input_data['soil_class__B'] = 1.0 if soil_class == "B" else 0.0
|
| 85 |
+
input_data['soil_class__C'] = 1.0 if soil_class == "C" else 0.0
|
| 86 |
+
|
| 87 |
+
submitted = st.form_submit_button("Predict Max Drift")
|
| 88 |
|
| 89 |
# ------------------------------
|
| 90 |
+
# 4. Prediction Logic
|
| 91 |
# ------------------------------
|
| 92 |
+
if submitted:
|
| 93 |
if model is None or scaler is None:
|
| 94 |
+
st.error("Model could not be loaded!")
|
| 95 |
else:
|
| 96 |
try:
|
| 97 |
+
df_raw = pd.DataFrame([input_data])
|
| 98 |
+
|
| 99 |
+
df_engineered = engineer_features(df_raw)
|
| 100 |
+
|
| 101 |
+
X_scaled = scaler.transform(df_engineered)
|
| 102 |
+
|
| 103 |
+
log_pred = model.predict(X_scaled)
|
| 104 |
|
| 105 |
+
real_pred = np.expm1(log_pred)[0]
|
| 106 |
+
|
| 107 |
+
st.divider()
|
| 108 |
+
st.success(f"### π― Predicted Drift: **{real_pred:.2f} mm**")
|
| 109 |
+
|
| 110 |
+
if real_pred < 10:
|
| 111 |
+
st.info("Risk: π’ Low (Safe)")
|
| 112 |
+
elif real_pred < 50:
|
| 113 |
+
st.warning("Risk: π‘ Medium (Potential Damage)")
|
| 114 |
+
else:
|
| 115 |
+
st.error("Risk: π΄ High (Collapse Hazard)")
|
| 116 |
|
| 117 |
except Exception as e:
|
| 118 |
+
st.error(f"Calculation error: {e}")
|
| 119 |
+
st.write("Please ensure all values are entered correctly.")
|