Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import joblib | |
| import pandas as pd | |
| import numpy as np | |
| from tensorflow.keras.models import load_model | |
| MODEL_PATH = 'src/heart.h5' | |
| SCALER_PATH = 'src/scaler_heart.joblib' | |
| FEATURES_PATH = 'src/final_features.joblib' | |
| ORIGINAL_CATEGORICAL_COLS = ['sex', 'cp', 'fbs', 'restecg', 'exang', 'slope', 'ca', 'thal'] | |
| CONTINUOUS_COLS = ['age', 'trestbps', 'chol', 'thalach', 'oldpeak'] | |
| ORIGINAL_ALL_COLS = CONTINUOUS_COLS + ORIGINAL_CATEGORICAL_COLS | |
| def load_assets(): | |
| try: | |
| model = load_model(MODEL_PATH) | |
| scaler = joblib.load(SCALER_PATH) | |
| final_features_list = joblib.load(FEATURES_PATH) # Load the correct feature order | |
| return model, scaler, final_features_list | |
| except Exception as e: | |
| st.error(f"Error loading assets. Ensure all three files are uploaded. Error: {e}") | |
| return None, None, None | |
| def preprocess_and_predict(model, scaler, final_features_list, input_data): | |
| # 1. Create DataFrame from inputs | |
| df_input = pd.DataFrame([input_data]) | |
| # 2. One-Hot Encoding (OHE) for Categorical Features (drop_first=True) | |
| df_processed = pd.get_dummies(df_input, columns=ORIGINAL_CATEGORICAL_COLS, drop_first=True) | |
| # 3. Align Columns: Add missing dummy columns and reorder (CRITICAL STEP) | |
| for feature in final_features_list: | |
| if feature not in df_processed.columns: | |
| # Add missing dummy variables (e.g., cp_1, cp_2) with value 0 | |
| df_processed[feature] = 0 | |
| # Select and order the final feature array using the loaded list | |
| final_features_df = df_processed[final_features_list].copy() | |
| # 4. Scaling Numerical Data (CRITICAL STEP) | |
| numerical_part = final_features_df[CONTINUOUS_COLS] | |
| final_features_df[CONTINUOUS_COLS] = scaler.transform(numerical_part) | |
| # 5. Predict (The model expects a numpy array) | |
| prediction_proba = model.predict(final_features_df.values) | |
| return float(prediction_proba[0]) | |
| # --- Streamlit Interface --- | |
| st.set_page_config(page_title="Heart Disease Predictor", layout="centered") | |
| st.title("❤️ Heart Disease Prediction (Neural Network)") | |
| st.markdown("Enter patient data (all 13 features) to predict the probability of heart disease.") | |
| model, scaler, final_features_list = load_assets() | |
| if model is not None and scaler is not None and final_features_list is not None: | |
| st.sidebar.header("Patient Data Input (13 Features)") | |
| # Continuous Features | |
| age = st.sidebar.slider("Age:", min_value=18, max_value=100, value=50) | |
| trestbps = st.sidebar.number_input("Resting BP (trestbps):", min_value=90, max_value=200, value=120) | |
| chol = st.sidebar.number_input("Cholesterol (chol):", min_value=100, max_value=600, value=250) | |
| thalach = st.sidebar.number_input("Max Heart Rate (thalach):", min_value=60, max_value=220, value=150) | |
| oldpeak = st.sidebar.number_input("ST Depression (oldpeak):", min_value=0.0, max_value=6.2, value=1.0, step=0.1) | |
| # Categorical Features (Use indices matching the original dataset) | |
| sex = st.sidebar.selectbox("Sex (1=Male, 0=Female):", options=[1, 0]) | |
| cp = st.sidebar.selectbox("Chest Pain Type (cp):", options=[0, 1, 2, 3], index=0) | |
| fbs = st.sidebar.selectbox("Fasting Blood Sugar > 120 (fbs):", options=[0, 1]) | |
| restecg = st.sidebar.selectbox("Resting ECG (restecg):", options=[0, 1, 2], index=1) | |
| exang = st.sidebar.selectbox("Exercise Induced Angina (exang):", options=[0, 1]) | |
| slope = st.sidebar.selectbox("Slope of Peak ST (slope):", options=[0, 1, 2], index=1) | |
| ca = st.sidebar.selectbox("Major Vessels (ca):", options=[0, 1, 2, 3, 4], index=0) | |
| thal = st.sidebar.selectbox("Thal (thal):", options=[1, 2, 3], index=1) | |
| # Collect inputs | |
| input_data = { | |
| 'age': age, 'sex': sex, 'cp': cp, 'trestbps': trestbps, 'chol': chol, | |
| 'fbs': fbs, 'restecg': restecg, 'thalach': thalach, 'exang': exang, | |
| 'oldpeak': oldpeak, 'slope': slope, 'ca': ca, 'thal': thal | |
| } | |
| if st.button("Predict Probability"): | |
| with st.spinner('Calculating probability...'): | |
| prediction_proba = preprocess_and_predict(model, scaler, final_features_list, input_data) | |
| st.success("Prediction Successful!") | |
| st.markdown("### Predicted Heart Disease Probability:") | |
| st.markdown(f"**{prediction_proba * 100:.1f}%**") | |
| risk = "HIGH RISK" if prediction_proba > 0.5 else "LOW RISK" | |
| st.markdown(f"Outcome: **{risk}**") |