demo1 / src /streamlit_app.py
Sourudra's picture
Update src/streamlit_app.py
383490d verified
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("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:")
# Session state for pagination and prediction result
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
df_filtered = df
total_pages = max(1, (len(df_filtered) - 1) // rows_per_page + 1)
# CSS for table rows
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)
# Display scrollable table
with st.container():
#st.markdown('<div class="scrollable-table">', unsafe_allow_html=True)
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_filtered.iloc[
st.session_state.page * rows_per_page : (st.session_state.page + 1) * rows_per_page
]
for idx, row in page_data.iterrows():
row_style = "row-box"
col1, col2, col3, col4 = st.columns([3, 3, 3, 2])
with col1:
st.markdown(f'<div class="{row_style}">{row["HR"]}</div>', unsafe_allow_html=True)
with col2:
st.markdown(f'<div class="{row_style}">{row["HRV"]:.2f}</div>', unsafe_allow_html=True)
with col3:
st.markdown(f'<div class="{row_style}">{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
st.markdown('</div>', unsafe_allow_html=True)
# Tighter Pagination Controls
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
)
# Final prediction display at the end
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)