SHELLAPANDIANGANHUNGING commited on
Commit
ddbd55e
·
verified ·
1 Parent(s): cb5c397

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +309 -4
app.py CHANGED
@@ -2024,6 +2024,308 @@ else:
2024
 
2025
  # )
2026
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2027
  # =================== OBJECTIVE 6: Automated Insights & AI Recommendations =====================
2028
  st.subheader("OBJECTIVE 6: Instant Insights & Recommendations")
2029
 
@@ -2031,7 +2333,7 @@ st.subheader("OBJECTIVE 6: Instant Insights & Recommendations")
2031
  col_insights, col_recs = st.columns(2)
2032
 
2033
  # =====================================================================
2034
- # 🔹 KOLOM KIRI — INSIGHTS BY ADVANCED ANALYTICS
2035
  # =====================================================================
2036
  with col_insights:
2037
  st.subheader("Insights by Advanced Analytics")
@@ -2146,14 +2448,17 @@ with col_insights:
2146
  f"Consider coaching or rest plan."
2147
  )
2148
  else:
2149
- st.info(
2150
- f"Operator {op_name} fatigue risk is within acceptable range ({op_pct:.1f}%)."
 
 
 
2151
  )
2152
  else:
2153
  st.info("Operator data not available for Operator Risk Profiling.")
2154
 
2155
  # =====================================================================
2156
- # 🔹 KOLOM KANAN — AI RECOMMENDATIONS
2157
  # =====================================================================
2158
  with col_recs:
2159
  st.subheader("Recommendations")
 
2024
 
2025
  # )
2026
 
2027
+ # # =================== OBJECTIVE 6: Automated Insights & AI Recommendations =====================
2028
+ # st.subheader("OBJECTIVE 6: Instant Insights & Recommendations")
2029
+
2030
+ # # Membagi tampilan menjadi dua kolom
2031
+ # col_insights, col_recs = st.columns(2)
2032
+
2033
+ # # =====================================================================
2034
+ # # 🔹 KOLOM KIRI — INSIGHTS BY ADVANCED ANALYTICS
2035
+ # # =====================================================================
2036
+ # with col_insights:
2037
+ # st.subheader("Insights by Advanced Analytics")
2038
+
2039
+ # # ===================== 1. Critical Hour Analysis =====================
2040
+ # critical_hours = [2, 3, 4, 5]
2041
+ # critical_alerts = df[df['hour'].isin(critical_hours)]
2042
+ # critical_pct = (len(critical_alerts) / len(df)) * 100 if len(df) > 0 else 0
2043
+
2044
+ # st.markdown(f"**Critical Hour Risk (3-6 AM)**")
2045
+ # bg_color = (
2046
+ # "#ffcccc" if critical_pct > 50 else
2047
+ # "#ffebcc" if critical_pct > 25 else
2048
+ # "#ffffcc" if critical_pct > 10 else
2049
+ # "#e6ffe6"
2050
+ # )
2051
+ # st.markdown(
2052
+ # f'<div style="background-color: {bg_color}; padding: 10px; border-radius: 5px;">'
2053
+ # f'Critical Hour Alerts: {len(critical_alerts)} ({critical_pct:.1f}% of total alerts)</div>',
2054
+ # unsafe_allow_html=True
2055
+ # )
2056
+
2057
+ # if critical_pct > 10:
2058
+ # st.warning(
2059
+ # f"High risk: {critical_pct:.1f}% of fatigue alerts occur during critical hours (3-6 AM). "
2060
+ # f"This is a known circadian dip period."
2061
+ # )
2062
+ # else:
2063
+ # st.info(
2064
+ # f"{critical_pct:.1f}% of alerts occur during critical hours. This is within acceptable range."
2065
+ # )
2066
+
2067
+ # # ===================== 2. High-Speed Fatigue Analysis =====================
2068
+ # if col_speed and col_speed in df.columns:
2069
+ # high_speed_threshold = 20
2070
+ # high_speed_fatigue = df[df[col_speed] >= high_speed_threshold]
2071
+ # high_speed_pct = (len(high_speed_fatigue) / len(df)) * 100 if len(df) > 0 else 0
2072
+
2073
+ # st.markdown(f"**High-Speed Fatigue Risk (Speed > {high_speed_threshold} km/h)**")
2074
+ # st.markdown(
2075
+ # f"""
2076
+ # <div style="font-size: 24px; font-weight: bold;">{len(high_speed_fatigue)}</div>
2077
+ # <div style="color: red; font-size: 14px; margin-top: -5px;">↑ {high_speed_pct:.1f}% of total alerts</div>
2078
+ # """,
2079
+ # unsafe_allow_html=True
2080
+ # )
2081
+
2082
+ # if high_speed_pct > 20:
2083
+ # st.warning(
2084
+ # f"High risk: {high_speed_pct:.1f}% of fatigue alerts occur at high speeds. "
2085
+ # f"This increases accident severity potential."
2086
+ # )
2087
+ # else:
2088
+ # st.info(
2089
+ # f"{high_speed_pct:.1f}% of alerts occur at high speeds. This is within acceptable range."
2090
+ # )
2091
+ # else:
2092
+ # st.info("Speed data not available for High-Speed Fatigue Analysis.")
2093
+
2094
+ # # ===================== 3. Shift Pattern Analysis =====================
2095
+ # if col_shift and col_shift in df.columns:
2096
+ # shift_counts = df[col_shift].value_counts()
2097
+ # st.markdown(f"**Shift Pattern Risk**")
2098
+
2099
+ # for shift_val in shift_counts.index:
2100
+ # shift_pct = (shift_counts[shift_val] / len(df)) * 100
2101
+
2102
+ # st.markdown(
2103
+ # f"""
2104
+ # <div style="font-size: 24px; font-weight: bold;">{shift_counts[shift_val]}</div>
2105
+ # <div style="color: red; font-size: 14px; margin-top: -5px;">↑ {shift_pct:.1f}% of total alerts</div>
2106
+ # """,
2107
+ # unsafe_allow_html=True
2108
+ # )
2109
+
2110
+ # if shift_pct > 50:
2111
+ # st.warning(
2112
+ # f"Shift {shift_val} has disproportionately high alerts ({shift_pct:.1f}%). "
2113
+ # f"Review shift scheduling and workload."
2114
+ # )
2115
+ # else:
2116
+ # st.info(
2117
+ # f"Shift {shift_val} alert distribution is acceptable ({shift_pct:.1f}%)."
2118
+ # )
2119
+ # else:
2120
+ # st.info("Shift data not available for Shift Pattern Analysis.")
2121
+
2122
+ # # ===================== 4. Operator Risk Profiling =====================
2123
+ # if col_operator and col_operator in df.columns:
2124
+ # operator_alerts = df[col_operator].value_counts()
2125
+ # top_risk_operators = operator_alerts.head(5)
2126
+
2127
+ # st.markdown("**High-Risk Operator Identification**")
2128
+ # colors = ["#d32f2f", "#e57373", "#ef9a9a", "#ffcdd2", "#ffe1e4"]
2129
+
2130
+ # for idx, (op_name, count) in enumerate(top_risk_operators.items()):
2131
+ # op_pct = (count / len(df)) * 100
2132
+ # color = colors[idx] if idx < len(colors) else colors[-1]
2133
+
2134
+ # st.markdown(
2135
+ # f"**Operator:** {op_name} \n**Alerts:** {count}"
2136
+ # )
2137
+ # st.markdown(
2138
+ # f"<span style='font-weight:600'>Share:</span> "
2139
+ # f"<span style='color:{color}; font-weight:700'>{op_pct:.1f}% of total alerts</span>",
2140
+ # unsafe_allow_html=True
2141
+ # )
2142
+
2143
+ # if op_pct > 5:
2144
+ # st.warning(
2145
+ # f"Operator {op_name} has high fatigue risk ({op_pct:.1f}%). "
2146
+ # f"Consider coaching or rest plan."
2147
+ # )
2148
+ # else:
2149
+ # st.info(
2150
+ # f"Operator {op_name} fatigue risk is within acceptable range ({op_pct:.1f}%)."
2151
+ # )
2152
+ # else:
2153
+ # st.info("Operator data not available for Operator Risk Profiling.")
2154
+
2155
+ # # =====================================================================
2156
+ # # 🔹 KOLOM KANAN — AI RECOMMENDATIONS
2157
+ # # =====================================================================
2158
+ # with col_recs:
2159
+ # st.subheader("Recommendations")
2160
+
2161
+ # ai_recommendations = []
2162
+
2163
+ # # 1. Critical Hour Insight → AI Rec
2164
+ # if "hour" in df.columns and not df.empty:
2165
+ # peak_hour = df["hour"].value_counts().idxmax()
2166
+ # critical_hours = [2, 3, 4, 5]
2167
+
2168
+ # if peak_hour in critical_hours:
2169
+ # ai_recommendations.append({
2170
+ # "type": "critical_hour",
2171
+ # "action": "Deploy enhanced fatigue monitoring systems during 3-6 AM.",
2172
+ # "data_point": f"Critical Hour Alerts: {len(critical_alerts)} ({critical_pct:.1f}%)",
2173
+ # "reasoning": "High percentage of alerts during circadian low period."
2174
+ # })
2175
+ # else:
2176
+ # ai_recommendations.append({
2177
+ # "type": "critical_hour",
2178
+ # "action": "Monitor fatigue patterns around peak hour (Hour {peak_hour}).",
2179
+ # "data_point": f"Peak Hour: {peak_hour}:00 — {df['hour'].value_counts()[peak_hour]} alerts",
2180
+ # "reasoning": "This hour shows highest fatigue occurrence."
2181
+ # })
2182
+
2183
+ # # 2. High-Speed Insight → AI Rec
2184
+ # if col_speed and col_speed in df.columns and not df.empty:
2185
+ # high_speed_threshold = 20
2186
+ # high_speed_fatigue = df[df[col_speed] >= high_speed_threshold]
2187
+ # high_speed_pct = (len(high_speed_fatigue) / len(df)) * 100 if len(df) > 0 else 0
2188
+
2189
+ # if high_speed_pct > 20:
2190
+ # ai_recommendations.append({
2191
+ # "type": "high_speed",
2192
+ # "action": "Implement speed-reduction protocols during fatigue-prone hours.",
2193
+ # "data_point": f"High-Speed Alerts: {len(high_speed_fatigue)} ({high_speed_pct:.1f}%)",
2194
+ # "reasoning": "High-speed alerts increase accident severity potential."
2195
+ # })
2196
+ # else:
2197
+ # ai_recommendations.append({
2198
+ # "type": "high_speed",
2199
+ # "action": "Maintain current speed monitoring — risk level is acceptable.",
2200
+ # "data_point": f"High-Speed Alerts: {len(high_speed_fatigue)} ({high_speed_pct:.1f}%)",
2201
+ # "reasoning": "Current high-speed fatigue rate is within acceptable range."
2202
+ # })
2203
+
2204
+ # # 3. Shift Pattern Insight → AI Rec
2205
+ # if col_shift and col_shift in df.columns and not df.empty:
2206
+ # worst_shift = df[col_shift].value_counts().idxmax()
2207
+ # shift_pct = (df[col_shift].value_counts()[worst_shift] / len(df)) * 100
2208
+
2209
+ # if shift_pct > 50:
2210
+ # ai_recommendations.append({
2211
+ # "type": "shift_pattern",
2212
+ # "action": "Review shift rotation schedules for Shift {worst_shift}.",
2213
+ # "data_point": f"Shift {worst_shift}: {df[col_shift].value_counts()[worst_shift]} alerts ({shift_pct:.1f}%)",
2214
+ # "reasoning": "Disproportionately high fatigue alerts indicate scheduling imbalance."
2215
+ # })
2216
+ # else:
2217
+ # ai_recommendations.append({
2218
+ # "type": "shift_pattern",
2219
+ # "action": "Continue monitoring all shifts — no dominant risk identified.",
2220
+ # "data_point": f"Shift {worst_shift}: {df[col_shift].value_counts()[worst_shift]} alerts ({shift_pct:.1f}%)",
2221
+ # "reasoning": "Shift distribution is balanced."
2222
+ # })
2223
+
2224
+ # # 4. Operator Risk Profiling → Simple Recommendations (No AI Reasoning, No Box)
2225
+ # if col_operator and col_operator in df.columns and not df.empty:
2226
+ # top_operators = df[col_operator].value_counts().head(5)
2227
+ # for op_name, count in top_operators.items():
2228
+ # op_pct = (count / len(df)) * 100
2229
+
2230
+ # if op_pct > 5:
2231
+ # ai_recommendations.append({
2232
+ # "type": "operator",
2233
+ # "action": f"Coaching or mandatory rest for Operator {op_name}.",
2234
+ # "data_point": f"Operator {op_name}: {count} alerts ({op_pct:.1f}%)"
2235
+ # })
2236
+ # else:
2237
+ # ai_recommendations.append({
2238
+ # "type": "operator",
2239
+ # "action": f"Continue general monitoring for Operator {op_name}.",
2240
+ # "data_point": f"Operator {op_name}: {count} alerts ({op_pct:.1f}%)"
2241
+ # })
2242
+
2243
+ # # Render each recommendation based on type
2244
+ # for rec in ai_recommendations:
2245
+ # if rec["type"] == "operator":
2246
+ # # Simple format: Action + Data Point only
2247
+ # data_point_colored = rec['data_point'].replace(
2248
+ # f"({rec['data_point'].split('(')[-1]}",
2249
+ # f"(<span style='color: red;'>{rec['data_point'].split('(')[-1]}"
2250
+ # ).replace(")", "</span>)")
2251
+
2252
+ # st.markdown(
2253
+ # f"""
2254
+ # <div style="margin: 10px 0; padding: 10px; background: #f8f9fa; border-left: 4px solid #495057; border-radius: 5px;">
2255
+ # <strong>Action:</strong> {rec['action']}<br>
2256
+ # <strong>Data Point:</strong> {data_point_colored}
2257
+ # </div>
2258
+ # """,
2259
+ # unsafe_allow_html=True
2260
+ # )
2261
+ # else:
2262
+ # # Standard format with AI Reasoning and box
2263
+ # data_point_colored = rec['data_point'].replace(
2264
+ # f"({rec['data_point'].split('(')[-1]}",
2265
+ # f"(<span style='color: red;'>{rec['data_point'].split('(')[-1]}"
2266
+ # ).replace(")", "</span>)")
2267
+
2268
+ # reasoning_colored = rec['reasoning'].replace(
2269
+ # f"({rec['reasoning'].split('(')[-1]}",
2270
+ # f"(<span style='color: red;'>{rec['reasoning'].split('(')[-1]}"
2271
+ # ).replace(")", "</span>)")
2272
+
2273
+ # st.markdown(
2274
+ # f"""
2275
+ # <div style="
2276
+ # background: #f8f9fa;
2277
+ # border: 1px solid #dee2e6;
2278
+ # border-radius: 8px;
2279
+ # padding: 15px;
2280
+ # margin: 10px 0;
2281
+ # box-shadow: 0 2px 8px rgba(0,0,0,0.05);
2282
+ # ">
2283
+ # <div style="
2284
+ # font-weight: bold;
2285
+ # background: #e9ecef;
2286
+ # padding: 8px;
2287
+ # border-radius: 5px;
2288
+ # margin-bottom: 8px;
2289
+ # border-left: 4px solid #495057;
2290
+ # ">
2291
+ # AI Recommendation
2292
+ # </div>
2293
+ # <div style="padding: 8px 0;">
2294
+ # <strong>Action:</strong> {rec['action']}
2295
+ # </div>
2296
+ # <div style="
2297
+ # padding: 8px;
2298
+ # background: #f1f1f1;
2299
+ # border-radius: 5px;
2300
+ # margin: 8px 0;
2301
+ # ">
2302
+ # <strong>Data Point:</strong> {data_point_colored}
2303
+ # </div>
2304
+ # <div style="
2305
+ # padding: 8px;
2306
+ # background: #f1f1f1;
2307
+ # border-radius: 5px;
2308
+ # ">
2309
+ # <strong>AI Reasoning:</strong> {reasoning_colored}
2310
+ # </div>
2311
+ # </div>
2312
+ # """,
2313
+ # unsafe_allow_html=True
2314
+ # )
2315
+
2316
+ # if not ai_recommendations:
2317
+ # st.info(
2318
+ # "No specific data points available for AI recommendations. "
2319
+ # "Ensure relevant columns are present (hour, shift, operator, duration, speed)."
2320
+ # )
2321
+
2322
+ # # ================= FOOTER ===========================
2323
+ # st.markdown("---")
2324
+ # st.markdown(
2325
+ # '<div class="footer">FatigueAnalyzer - Transforming Mining Safety with Intelligent Analytics | Contact: info@bukittechnology.com</div>',
2326
+ # unsafe_allow_html=True
2327
+ # )
2328
+
2329
  # =================== OBJECTIVE 6: Automated Insights & AI Recommendations =====================
2330
  st.subheader("OBJECTIVE 6: Instant Insights & Recommendations")
2331
 
 
2333
  col_insights, col_recs = st.columns(2)
2334
 
2335
  # =====================================================================
2336
+ # 🔹 KOLOM KIRI — INSIGHTS BY ADVANCED ANALYTICS (TANPA SEMUA KOTAK BIRU)
2337
  # =====================================================================
2338
  with col_insights:
2339
  st.subheader("Insights by Advanced Analytics")
 
2448
  f"Consider coaching or rest plan."
2449
  )
2450
  else:
2451
+ # ❌ HILANGKAN TEKS "is within acceptable range" DAN KOTAK BIRU
2452
+ # Hanya tampilkan nama operator + alert count — tanpa tambahan teks
2453
+ st.markdown(
2454
+ f"<span style='color: #2c3e50;'>Operator {op_name}: {count} alerts ({op_pct:.1f}%)</span>",
2455
+ unsafe_allow_html=True
2456
  )
2457
  else:
2458
  st.info("Operator data not available for Operator Risk Profiling.")
2459
 
2460
  # =====================================================================
2461
+ # 🔹 KOLOM KANAN — AI RECOMMENDATIONS (TIDAK BERUBAH)
2462
  # =====================================================================
2463
  with col_recs:
2464
  st.subheader("Recommendations")