Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import numpy as np | |
| import pandas as pd | |
| import joblib | |
| # Set page config | |
| st.set_page_config(page_title="Stress Detection using One-Class SVM", layout="centered") | |
| # Custom CSS for background and styles | |
| st.markdown( | |
| """ | |
| <style> | |
| .stApp { | |
| background-image: url("https://i.postimg.cc/vZb3ymYT/360-F-1375669005-ebg3mldxps5-ZYr-QFl-Y6-EX3e-CINw-VDeo-F.jpg"); | |
| background-size: cover; | |
| background-repeat: no-repeat; | |
| background-attachment: fixed; | |
| } | |
| .block-container { | |
| background-color: rgba(0, 0, 0, 0.6); | |
| color: white; | |
| padding: 2rem; | |
| border-radius: 15px; | |
| max-width: 800px; | |
| margin: 2rem auto; | |
| box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5); | |
| backdrop-filter: blur(8px); | |
| -webkit-backdrop-filter: blur(8px); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| } | |
| .sensor-row { | |
| display: flex; | |
| justify-content: space-around; | |
| font-size: 1.1rem; | |
| margin-top: 1.2rem; | |
| margin-bottom: 1rem; | |
| } | |
| .sensor-row > div { | |
| padding: 0.5rem 1rem; | |
| background-color: rgba(255, 255, 255, 0.1); | |
| border-radius: 8px; | |
| } | |
| .scroll-box { | |
| max-height: 400px; | |
| overflow-y: auto; | |
| border: 1px solid #ccc; | |
| padding: 1rem; | |
| background-color: rgba(255,255,255,0.05); | |
| border-radius: 10px; | |
| } | |
| h1, h2, h3, p, div { | |
| color: white !important; | |
| } | |
| section.main > div:first-child { | |
| padding-top: 0rem; | |
| } | |
| header[data-testid="stHeader"] { | |
| height: 0rem; | |
| visibility: hidden; | |
| } | |
| </style> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |
| st.title("Stress Detection") | |
| st.markdown("Select a mode to detect stress from sensor readings:") | |
| # Load model and scaler | |
| try: | |
| model = joblib.load("one_class_svm_stress_model.pkl") | |
| scaler = joblib.load("scaler.pkl") | |
| except Exception as e: | |
| st.error(f"Error loading model or scaler: {e}") | |
| st.stop() | |
| # Load or create hardcoded dataset | |
| try: | |
| df = pd.read_csv("src/simulated_stress_data.csv") | |
| df = df[['HR', 'HRV', 'EDA']].head(100) | |
| except: | |
| df = pd.DataFrame({ | |
| "HR": np.random.randint(60, 120, 100), | |
| "HRV": np.random.uniform(20, 80, 100), | |
| "EDA": np.random.uniform(0.1, 5.0, 100) | |
| }) | |
| # Radio button selection | |
| mode = st.radio("Choose input mode:", ["Manual Readings", "Generate Readings", "Test Dataset"], horizontal=True) | |
| # Manual Input | |
| if mode == "Manual Readings": | |
| hr = st.number_input("Heart Rate (HR)", min_value=60, max_value=120, value=80) | |
| hrv = st.number_input("Heart Rate Variability (HRV)", min_value=20.0, max_value=80.0, value=50.0) | |
| eda = st.number_input("Electrodermal Activity (EDA)", min_value=0.1, max_value=5.0, value=2.0) | |
| if st.button("Predict"): | |
| sample = np.array([[hr, hrv, eda]]) | |
| scaled = scaler.transform(sample) | |
| pred = model.predict(scaled) | |
| label = "Stress" if pred[0] == -1 else "No Stress" | |
| st.markdown( | |
| f""" | |
| <div class="sensor-row"> | |
| <div><strong>HR:</strong> {hr} bpm</div> | |
| <div><strong>HRV:</strong> {hrv:.2f} ms</div> | |
| <div><strong>EDA:</strong> {eda:.2f} µS</div> | |
| </div> | |
| """, unsafe_allow_html=True | |
| ) | |
| st.subheader("Prediction") | |
| if label == "No Stress": | |
| st.success(label) | |
| else: | |
| st.error(label) | |
| # Generate Random Input | |
| elif mode == "Generate Readings": | |
| if st.button("Generate and Predict"): | |
| hr = np.random.randint(60, 120) | |
| hrv = np.random.uniform(20, 80) | |
| eda = np.random.uniform(0.1, 5.0) | |
| sample = np.array([[hr, hrv, eda]]) | |
| scaled = scaler.transform(sample) | |
| pred = model.predict(scaled) | |
| label = "Stress" if pred[0] == -1 else "No Stress" | |
| st.markdown( | |
| f""" | |
| <div class="sensor-row"> | |
| <div><strong>HR:</strong> {hr} bpm</div> | |
| <div><strong>HRV:</strong> {hrv:.2f} ms</div> | |
| <div><strong>EDA:</strong> {eda:.2f} µS</div> | |
| </div> | |
| """, unsafe_allow_html=True | |
| ) | |
| st.subheader("Prediction") | |
| if label == "No Stress": | |
| st.success(label) | |
| else: | |
| st.error(label) | |
| # Test Dataset (Scrollable) | |
| elif mode == "Test Dataset": | |
| st.markdown("### Select a row from test dataset for prediction:") | |
| if "page" not in st.session_state: | |
| st.session_state.page = 0 | |
| if "last_prediction" not in st.session_state: | |
| st.session_state.last_prediction = None | |
| st.session_state.last_row = None | |
| rows_per_page = 5 | |
| total_pages = max(1, (len(df) - 1) // rows_per_page + 1) | |
| st.markdown(""" | |
| <style> | |
| .scrollable-table { | |
| max-height: 350px; | |
| overflow-y: auto; | |
| padding: 10px; | |
| background-color: rgba(255,255,255,0.05); | |
| border-radius: 10px; | |
| border: 1px solid #ccc; | |
| } | |
| .row-box { | |
| border-radius: 8px; | |
| padding: 6px; | |
| margin-bottom: 4px; | |
| background-color: rgba(0, 128, 255, 0.15); | |
| height: 40px; | |
| display: flex; | |
| align-items: center; | |
| transition: background-color 0.3s ease; | |
| } | |
| .row-box:hover { | |
| background-color: rgba(0, 128, 255, 0.3); | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| with st.container(): | |
| col1, col2, col3, col4 = st.columns([3, 3, 3, 2]) | |
| col1.markdown("**HR**") | |
| col2.markdown("**HRV**") | |
| col3.markdown("**EDA**") | |
| col4.markdown("**Predict**") | |
| page_data = df.iloc[ | |
| st.session_state.page * rows_per_page : (st.session_state.page + 1) * rows_per_page | |
| ] | |
| for idx, row in page_data.iterrows(): | |
| col1, col2, col3, col4 = st.columns([3, 3, 3, 2]) | |
| with col1: | |
| st.markdown(f'<div class="row-box">{row["HR"]}</div>', unsafe_allow_html=True) | |
| with col2: | |
| st.markdown(f'<div class="row-box">{row["HRV"]:.2f}</div>', unsafe_allow_html=True) | |
| with col3: | |
| st.markdown(f'<div class="row-box">{row["EDA"]:.2f}</div>', unsafe_allow_html=True) | |
| with col4: | |
| if st.button("Select", key=f"select_{idx}"): | |
| sample = np.array([[row['HR'], row['HRV'], row['EDA']]]) | |
| sample_scaled = scaler.transform(sample) | |
| pred = model.predict(sample_scaled) | |
| label = "Stress" if pred[0] == -1 else "No Stress" | |
| st.session_state.last_prediction = label | |
| st.session_state.last_row = row | |
| col1, col2, col3 = st.columns([1.2, 1.2, 3]) | |
| with col1: | |
| if st.button("⬅️ Previous"): | |
| if st.session_state.page > 0: | |
| st.session_state.page -= 1 | |
| with col2: | |
| if st.button("Next ➡️"): | |
| if st.session_state.page < total_pages - 1: | |
| st.session_state.page += 1 | |
| with col3: | |
| st.markdown( | |
| f"<div style='text-align:left; margin-top: 0.5rem;'>Page {st.session_state.page + 1} of {total_pages}</div>", | |
| unsafe_allow_html=True | |
| ) | |
| if st.session_state.last_prediction and st.session_state.last_row is not None: | |
| row = st.session_state.last_row | |
| label = st.session_state.last_prediction | |
| st.markdown("---") | |
| st.markdown("### Prediction") | |
| st.markdown( | |
| f""" | |
| <div class="sensor-row"> | |
| <div><strong>HR:</strong> {row['HR']} bpm</div> | |
| <div><strong>HRV:</strong> {row['HRV']:.2f} ms</div> | |
| <div><strong>EDA:</strong> {row['EDA']:.2f} µS</div> | |
| </div> | |
| """, unsafe_allow_html=True | |
| ) | |
| if label == "No Stress": | |
| st.success(label) | |
| else: | |
| st.error(label) | |