SHELLAPANDIANGANHUNGING commited on
Commit
67295b8
·
verified ·
1 Parent(s): 61e8a7f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +196 -3
app.py CHANGED
@@ -1719,9 +1719,6 @@ else:
1719
  st.exception(e)
1720
 
1721
  # =================== OBJECTIVE 6: Automated Insights & AI Recommendations =====================
1722
-
1723
- # =====================================================================
1724
- # =================== OBJECTIVE 6: Automated Insights & AI Recommendations =====================
1725
  st.subheader("OBJECTIVE 6: Instant Insights & Recommendations")
1726
 
1727
  # Membagi tampilan menjadi dua kolom
@@ -1789,3 +1786,199 @@ with col_insights:
1789
 
1790
  else:
1791
  st.info("Speed data not available for High-Speed Fatigue Analysis.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1719
  st.exception(e)
1720
 
1721
  # =================== OBJECTIVE 6: Automated Insights & AI Recommendations =====================
 
 
 
1722
  st.subheader("OBJECTIVE 6: Instant Insights & Recommendations")
1723
 
1724
  # Membagi tampilan menjadi dua kolom
 
1786
 
1787
  else:
1788
  st.info("Speed data not available for High-Speed Fatigue Analysis.")
1789
+
1790
+ # ===================== 3. Shift Pattern Analysis =====================
1791
+ if col_shift and col_shift in df.columns:
1792
+
1793
+ shift_counts = df[col_shift].value_counts()
1794
+ st.markdown(f"**Shift Pattern Risk**")
1795
+
1796
+ for shift_val in shift_counts.index:
1797
+ shift_pct = (shift_counts[shift_val] / len(df)) * 100
1798
+
1799
+ st.markdown(
1800
+ f"""
1801
+ <div style="font-size: 24px; font-weight: bold;">{shift_counts[shift_val]}</div>
1802
+ <div style="color: red; font-size: 14px; margin-top: -5px;">↑ {shift_pct:.1f}% of total alerts</div>
1803
+ """,
1804
+ unsafe_allow_html=True
1805
+ )
1806
+
1807
+ if shift_pct > 50:
1808
+ st.warning(
1809
+ f"Shift {shift_val} has disproportionately high alerts ({shift_pct:.1f}%). "
1810
+ f"Review shift scheduling and workload."
1811
+ )
1812
+ else:
1813
+ st.info(
1814
+ f"Shift {shift_val} alert distribution is acceptable ({shift_pct:.1f}%)."
1815
+ )
1816
+
1817
+ else:
1818
+ st.info("Shift data not available for Shift Pattern Analysis.")
1819
+
1820
+ # ===================== 4. Operator Risk Profiling =====================
1821
+ if col_operator and col_operator in df.columns:
1822
+
1823
+ operator_alerts = df[col_operator].value_counts()
1824
+ top_risk_operators = operator_alerts.head(5)
1825
+
1826
+ st.markdown("**High-Risk Operator Identification**")
1827
+ colors = ["#d32f2f", "#e57373", "#ef9a9a", "#ffcdd2", "#ffe1e4"]
1828
+
1829
+ for idx, (op_name, count) in enumerate(top_risk_operators.items()):
1830
+ op_pct = (count / len(df)) * 100
1831
+ color = colors[idx] if idx < len(colors) else colors[-1]
1832
+
1833
+ st.markdown(
1834
+ f"**Operator:** {op_name} \n**Alerts:** {count}"
1835
+ )
1836
+ st.markdown(
1837
+ f"<span style='font-weight:600'>Share:</span> "
1838
+ f"<span style='color:{color}; font-weight:700'>{op_pct:.1f}% of total alerts</span>",
1839
+ unsafe_allow_html=True
1840
+ )
1841
+
1842
+ if op_pct > 5:
1843
+ st.warning(
1844
+ f"Operator {op_name} has high fatigue risk ({op_pct:.1f}%). "
1845
+ f"Consider coaching or rest plan."
1846
+ )
1847
+ else:
1848
+ st.info(
1849
+ f"Operator {op_name} fatigue risk is within acceptable range ({op_pct:.1f}%)."
1850
+ )
1851
+
1852
+ else:
1853
+ st.info("Operator data not available for Operator Risk Profiling.")
1854
+
1855
+
1856
+ # =====================================================================
1857
+ # 🔹 KOLOM KANAN — AI RECOMMENDATIONS
1858
+ # =====================================================================
1859
+ with col_recs:
1860
+
1861
+ st.subheader("Recommendations")
1862
+ ai_recs = []
1863
+ insights_found = []
1864
+
1865
+ # Peak Hour
1866
+ if "hour" in df.columns and not df.empty:
1867
+ peak_hour = df["hour"].value_counts().idxmax()
1868
+ critical_hours = [2, 3, 4, 5]
1869
+
1870
+ if peak_hour in critical_hours:
1871
+ insights_found.append(
1872
+ f"Most fatigue risk occurs at **{peak_hour}:00** — during critical circadian low period (3-6 AM)."
1873
+ )
1874
+ else:
1875
+ insights_found.append(
1876
+ f"Most fatigue risk occurs at **{peak_hour}:00** — likely due to circadian drop."
1877
+ )
1878
+
1879
+ # Risk Shift
1880
+ if col_shift and col_shift in df.columns and not df.empty:
1881
+ worst_shift = df[col_shift].value_counts().idxmax()
1882
+ insights_found.append(
1883
+ f"Highest fatigue recorded in **Shift {worst_shift}** — review scheduling & workload."
1884
+ )
1885
+
1886
+ # Worst Operator
1887
+ if col_operator and col_operator in df.columns and not df.empty:
1888
+ worst_operator = df[col_operator].value_counts().idxmax()
1889
+ insights_found.append(
1890
+ f"Operator at highest risk: **{worst_operator}** — suggested coaching or rest plan."
1891
+ )
1892
+
1893
+ # Duration Risk
1894
+ if "duration_sec" in df.columns and not df.empty:
1895
+ avg_duration = df["duration_sec"].mean()
1896
+ if avg_duration > 10:
1897
+ insights_found.append(
1898
+ "Long fatigue event duration suggests slow response — improve alerting training."
1899
+ )
1900
+
1901
+ # ===================== AI DECISION ENGINE =====================
1902
+ if insights_found:
1903
+
1904
+ if any("circadian" in i.lower() for i in insights_found):
1905
+ ai_recs.append({
1906
+ "recommendation": "Deploy enhanced fatigue monitoring systems during 3-6 AM.",
1907
+ "data_point": f"Critical Hour Alerts: {len(critical_alerts)} ({critical_pct:.1f}%)",
1908
+ "reason": "High percentage of alerts during circadian low period."
1909
+ })
1910
+
1911
+ if any("shift" in i.lower() for i in insights_found):
1912
+ ai_recs.append({
1913
+ "recommendation": "Review shift rotation schedules.",
1914
+ "data_point": f"Shift {worst_shift}: {df[col_shift].value_counts()[worst_shift]} alerts",
1915
+ "reason": "This shift shows highest fatigue alerts."
1916
+ })
1917
+
1918
+ if any("operator" in i.lower() for i in insights_found):
1919
+ ai_recs.append({
1920
+ "recommendation": "Coaching or mandatory rest for the identified high-risk operator.",
1921
+ "data_point": f"Operator {worst_operator}: {df[col_operator].value_counts()[worst_operator]} alerts",
1922
+ "reason": "Operator has highest fatigue alerts."
1923
+ })
1924
+
1925
+ if any("duration" in i.lower() for i in insights_found):
1926
+ ai_recs.append({
1927
+ "recommendation": "Improve fatigue alert response training.",
1928
+ "data_point": f"Avg Duration: {avg_duration:.1f} sec",
1929
+ "reason": "Long fatigue event duration indicates slow response."
1930
+ })
1931
+
1932
+ # Render all recommendations
1933
+ import re
1934
+
1935
+ for rec in ai_recs:
1936
+
1937
+ data_point_colored = re.sub(
1938
+ r'(\d+\.?\d*%)',
1939
+ r'<span style="color: red;">\1</span>',
1940
+ rec['data_point']
1941
+ )
1942
+
1943
+ reason_colored = re.sub(
1944
+ r'(\d+\.?\d*%)',
1945
+ r'<span style="color: red;">\1</span>',
1946
+ rec['reason']
1947
+ )
1948
+
1949
+ st.markdown(
1950
+ f"""
1951
+ <div style="
1952
+ background: #f8f9fa;
1953
+ border: 1px solid #dee2e6;
1954
+ border-radius: 8px;
1955
+ padding: 15px;
1956
+ margin: 10px 0;
1957
+ ">
1958
+ <div style="font-weight: bold; background: #e9ecef; padding: 8px; border-radius: 5px;">
1959
+ AI Recommendation
1960
+ </div>
1961
+ <div style="padding-top: 8px;"><strong>Action:</strong> {rec['recommendation']}</div>
1962
+ <div style="padding: 8px; background: #e9ecef; border-radius: 5px;">
1963
+ <strong>Data Point:</strong> {data_point_colored}
1964
+ </div>
1965
+ <div style="padding: 8px; background: #f1f1f1; border-radius: 5px;">
1966
+ <strong>AI Reasoning:</strong> {reason_colored}
1967
+ </div>
1968
+ </div>
1969
+ """,
1970
+ unsafe_allow_html=True
1971
+ )
1972
+
1973
+ else:
1974
+ st.info(
1975
+ "No specific data points available for AI recommendations. "
1976
+ "Ensure relevant columns are present (hour, shift, operator, duration, speed)."
1977
+ )
1978
+
1979
+ # ================= FOOTER ===========================
1980
+ st.markdown("---")
1981
+ st.markdown(
1982
+ '<div class="footer">FatigueAnalyzer - Transforming Mining Safety with Intelligent Analytics | Contact: info@bukittechnology.com</div>',
1983
+ unsafe_allow_html=True
1984
+ )