Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -2,50 +2,103 @@ import streamlit as st
|
|
| 2 |
import pandas as pd
|
| 3 |
import plotly.express as px
|
| 4 |
|
| 5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
-
#
|
| 8 |
-
|
|
|
|
| 9 |
|
| 10 |
-
#
|
| 11 |
-
|
| 12 |
-
df["Timestamp"] = pd.to_datetime(df[timestamp_col])
|
| 13 |
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
-
#
|
| 17 |
-
|
| 18 |
-
unit_filter = st.sidebar.multiselect("Filter Unit", df['Fleet Number'].unique())
|
| 19 |
|
| 20 |
-
|
| 21 |
-
if
|
| 22 |
-
|
| 23 |
-
if
|
| 24 |
-
|
| 25 |
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
|
|
|
|
|
|
|
|
|
| 30 |
|
| 31 |
-
#
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
st.plotly_chart(fig, use_container_width=True)
|
| 35 |
|
| 36 |
-
|
| 37 |
-
fig2 = px.bar(filtered, x="Shift", title="β οΈ Distribusi Alert per Shift", color="Shift")
|
| 38 |
-
st.plotly_chart(fig2, use_container_width=True)
|
| 39 |
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
st.plotly_chart(fig3, use_container_width=True)
|
| 44 |
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
fig4 = px.bar(hourly, x='Hour', y='Count', title="π Peak Hour Fatigue Alerts")
|
| 49 |
-
st.plotly_chart(fig4, use_container_width=True)
|
| 50 |
|
| 51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
import pandas as pd
|
| 3 |
import plotly.express as px
|
| 4 |
|
| 5 |
+
# =============== STREAMLIT CONFIG ==================
|
| 6 |
+
st.set_page_config(
|
| 7 |
+
page_title="Fatigue Camera Dashboard",
|
| 8 |
+
layout="wide",
|
| 9 |
+
page_icon="π΄"
|
| 10 |
+
)
|
| 11 |
|
| 12 |
+
# =============== APP HEADER =========================
|
| 13 |
+
st.title("π΄π Fatigue & Distraction Camera Safety Dashboard")
|
| 14 |
+
st.write("Upload data dari fatigue monitoring system untuk analisis safety.")
|
| 15 |
|
| 16 |
+
# =============== FILE UPLOADER ======================
|
| 17 |
+
uploaded_file = st.file_uploader("π Upload File (Excel)", type=["xlsx", "xls"])
|
|
|
|
| 18 |
|
| 19 |
+
if uploaded_file:
|
| 20 |
+
df = pd.read_excel(uploaded_file)
|
| 21 |
+
|
| 22 |
+
st.subheader("π Data Preview")
|
| 23 |
+
st.dataframe(df, use_container_width=True)
|
| 24 |
|
| 25 |
+
# =============== CLEANING OTOMATIS ===============
|
| 26 |
+
df.columns = df.columns.str.lower().str.replace(" ", "_").str.strip()
|
|
|
|
| 27 |
|
| 28 |
+
# Deteksi kolom penting
|
| 29 |
+
col_time = next((c for c in df.columns if "time" in c or "timestamp" in c or "date" in c), None)
|
| 30 |
+
col_operator = next((c for c in df.columns if "operator" in c or "driver" in c or "employee" in c), None)
|
| 31 |
+
col_fatigue = next((c for c in df.columns if "fatigue" in c), None)
|
| 32 |
+
col_distraction = next((c for c in df.columns if "distract" in c), None)
|
| 33 |
|
| 34 |
+
st.write("π§ Kolom terdeteksi:")
|
| 35 |
+
st.code(f"""
|
| 36 |
+
Time Column: {col_time}
|
| 37 |
+
Operator Column: {col_operator}
|
| 38 |
+
Fatigue Column: {col_fatigue}
|
| 39 |
+
Distraction Column: {col_distraction}
|
| 40 |
+
""")
|
| 41 |
|
| 42 |
+
# =============== KPI SUMMARY =====================
|
| 43 |
+
st.divider()
|
| 44 |
+
st.subheader("π Safety Event Summary")
|
|
|
|
| 45 |
|
| 46 |
+
cols = st.columns(3)
|
|
|
|
|
|
|
| 47 |
|
| 48 |
+
if col_fatigue:
|
| 49 |
+
total_fatigue = df[col_fatigue].sum()
|
| 50 |
+
cols[0].metric("Total Fatigue Alerts", total_fatigue)
|
|
|
|
| 51 |
|
| 52 |
+
if col_distraction:
|
| 53 |
+
total_distraction = df[col_distraction].sum()
|
| 54 |
+
cols[1].metric("Total Distraction Alerts", total_distraction)
|
|
|
|
|
|
|
| 55 |
|
| 56 |
+
if col_operator:
|
| 57 |
+
operator_count = df[col_operator].nunique()
|
| 58 |
+
cols[2].metric("Operators Monitored", operator_count)
|
| 59 |
+
|
| 60 |
+
# =============== TREND CHART =====================
|
| 61 |
+
if col_time and col_fatigue:
|
| 62 |
+
df[col_time] = pd.to_datetime(df[col_time], errors="coerce")
|
| 63 |
+
|
| 64 |
+
fig = px.line(
|
| 65 |
+
df.sort_values(col_time),
|
| 66 |
+
x=col_time,
|
| 67 |
+
y=col_fatigue,
|
| 68 |
+
title="π Trend Fatigue Events Over Time"
|
| 69 |
+
)
|
| 70 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 71 |
+
|
| 72 |
+
# =============== OPERATOR RANKING =================
|
| 73 |
+
if col_operator and col_fatigue:
|
| 74 |
+
st.subheader("π Operator Ranking (Based on Fatigue Events)")
|
| 75 |
+
|
| 76 |
+
rank_df = df.groupby(col_operator)[col_fatigue].sum().sort_values(ascending=False)
|
| 77 |
+
st.bar_chart(rank_df)
|
| 78 |
+
|
| 79 |
+
# =============== AUTO INSIGHT =====================
|
| 80 |
+
st.divider()
|
| 81 |
+
st.subheader("π§© AI Insight (Auto Summary)")
|
| 82 |
+
|
| 83 |
+
insight = []
|
| 84 |
+
|
| 85 |
+
if col_time and col_fatigue:
|
| 86 |
+
peak_hour = df.groupby(df[col_time].dt.hour)[col_fatigue].sum().idxmax()
|
| 87 |
+
insight.append(f"β° **Jam paling rawan:** {peak_hour}:00")
|
| 88 |
+
|
| 89 |
+
if col_operator:
|
| 90 |
+
worst_operator = rank_df.index[0]
|
| 91 |
+
insight.append(f"οΏ½οΏ½οΈ Operator dengan alert tertinggi: **{worst_operator}** β perlu coaching / fatigue management.")
|
| 92 |
+
|
| 93 |
+
if col_distraction and df[col_distraction].sum() > df[col_fatigue].sum():
|
| 94 |
+
insight.append("π¨ Distraction lebih sering daripada fatigue β kemungkinan faktor lingkungan atau policy.")
|
| 95 |
+
|
| 96 |
+
for i in insight:
|
| 97 |
+
st.write(i)
|
| 98 |
+
|
| 99 |
+
# ================= HUGGING FACE FIX ==================
|
| 100 |
+
if __name__ == "__main__":
|
| 101 |
+
import streamlit.web.cli as stcli
|
| 102 |
+
import sys
|
| 103 |
+
sys.argv = ["streamlit", "run", "app.py", "--server.enableCORS=false", "--server.enableXsrfProtection=false"]
|
| 104 |
+
sys.exit(stcli.main())
|