Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1981,25 +1981,21 @@ if not df_category.empty:
|
|
| 1981 |
else:
|
| 1982 |
st.info("No data available for non-positive issue categories with 100% coverage and positive trend.")
|
| 1983 |
# =================== OBJECTIVE 7 — Insight and Recommendation (Agentic AI LLM Style — Final) ===================
|
|
|
|
| 1984 |
st.markdown("<h3 class='section-title'>OBJECTIVE 7 — Insight and Recommendation</h3>", unsafe_allow_html=True)
|
| 1985 |
|
| 1986 |
-
def
|
| 1987 |
dev = {
|
| 1988 |
-
# 1. 9 lokasi rasio TERENDAH
|
| 1989 |
"lowest_ratio_9_locs": [],
|
| 1990 |
-
# 2a–2d: dari Obj 3a–3d
|
| 1991 |
"obj3a_lowest_div": None,
|
| 1992 |
"obj3b_slowest_executor": None,
|
| 1993 |
"obj3c_lowest_reporter": None,
|
| 1994 |
"obj3d_slowest_div": None,
|
| 1995 |
-
# 3. Non-Positive composition
|
| 1996 |
"obj4_unsafe_condition_pct": 0.0,
|
| 1997 |
"obj4_unsafe_action_pct": 0.0,
|
| 1998 |
"obj4_near_miss_pct": 0.0,
|
| 1999 |
-
# 4. Quadrant I & II
|
| 2000 |
"obj5_q1_divs": [],
|
| 2001 |
"obj5_q2_divs": [],
|
| 2002 |
-
# 5. Top 2 non-Positive categories
|
| 2003 |
"obj6_top2_categories": [],
|
| 2004 |
}
|
| 2005 |
|
|
@@ -2091,7 +2087,7 @@ def extract_agentic_insights_v4(df: pd.DataFrame):
|
|
| 2091 |
elif r['Finding Count'] < X_LIMIT and r['Avg Lead Time'] >= Y_LIMIT:
|
| 2092 |
dev["obj5_q2_divs"].append(r['nama'])
|
| 2093 |
|
| 2094 |
-
# === 5. Top 2 non-Positive category
|
| 2095 |
if {'kategori', 'temuan_kategori', 'created_at'}.issubset(df.columns):
|
| 2096 |
nonpos = df[df['temuan_kategori'] != 'Positive']
|
| 2097 |
if not nonpos.empty:
|
|
@@ -2103,64 +2099,49 @@ def extract_agentic_insights_v4(df: pd.DataFrame):
|
|
| 2103 |
|
| 2104 |
return dev
|
| 2105 |
|
| 2106 |
-
|
| 2107 |
-
dev = extract_agentic_insights_v4(df_filtered)
|
| 2108 |
|
| 2109 |
-
#
|
| 2110 |
insight_lines = []
|
| 2111 |
|
| 2112 |
-
# 1. 9 lokasi
|
| 2113 |
if dev["lowest_ratio_9_locs"]:
|
| 2114 |
loc_list = ", ".join([f"<strong>{loc}</strong> ({ratio})" for loc, ratio in dev["lowest_ratio_9_locs"]])
|
| 2115 |
-
insight_lines.append(f"1. Sembilan lokasi dengan rasio temuan/orang
|
| 2116 |
|
| 2117 |
-
# 2.
|
| 2118 |
-
|
| 2119 |
-
summary_parts = []
|
| 2120 |
if dev["obj3a_lowest_div"]:
|
| 2121 |
-
|
| 2122 |
if dev["obj3c_lowest_reporter"]:
|
| 2123 |
-
|
| 2124 |
if dev["obj3d_slowest_div"]:
|
| 2125 |
-
|
| 2126 |
if dev["obj3b_slowest_executor"]:
|
| 2127 |
-
|
| 2128 |
|
| 2129 |
-
if
|
| 2130 |
-
joined = "; ".join(
|
| 2131 |
insight_lines.append(
|
| 2132 |
-
"2. Sistem mendeteksi
|
| 2133 |
-
|
| 2134 |
-
"Ini menunjukkan ketidakseimbangan antara kapasitas pelaporan dan kapasitas resolusi — dua dimensi kritis dalam ekosistem *agentic safety*."
|
| 2135 |
)
|
| 2136 |
|
| 2137 |
-
# 2a–2d: detail
|
| 2138 |
-
if dev["obj3a_lowest_div"]:
|
| 2139 |
-
name, val = dev["obj3a_lowest_div"]
|
| 2140 |
-
insight_lines.append(f" 2a. Divisi <strong>{name}</strong> memiliki rasio temuan/orang terendah ({val}), indikasi *low agency* atau *high reporting barrier*.")
|
| 2141 |
-
|
| 2142 |
-
if dev["obj3b_slowest_executor"]:
|
| 2143 |
-
name, days = dev["obj3b_slowest_executor"]
|
| 2144 |
-
insight_lines.append(f" 2b. Eksekutor <strong>{name}</strong> memiliki lead time resolusi tertinggi ({days} hari), berisiko menjadi *bottleneck agent* dalam alur penutupan.")
|
| 2145 |
-
|
| 2146 |
-
if dev["obj3c_lowest_reporter"]:
|
| 2147 |
-
name, rate = dev["obj3c_lowest_reporter"]
|
| 2148 |
-
insight_lines.append(f" 2c. Reporter <strong>{name}</strong> memiliki frekuensi pelaporan terendah ({rate}/bulan), perlu *capacity uplift* melalui *nudge* atau *coaching*.")
|
| 2149 |
-
|
| 2150 |
-
if dev["obj3d_slowest_div"]:
|
| 2151 |
-
name, days = dev["obj3d_slowest_div"]
|
| 2152 |
-
insight_lines.append(f" 2d. Divisi <strong>{name}</strong> memiliki lead time rata-rata tertinggi ({days} hari), menunjukkan *systemic delay* dalam *execution loop*.")
|
| 2153 |
-
|
| 2154 |
# 3. Komposisi non-Positive
|
| 2155 |
uc, ua, nm = dev["obj4_unsafe_condition_pct"], dev["obj4_unsafe_action_pct"], dev["obj4_near_miss_pct"]
|
| 2156 |
if uc + ua + nm > 0:
|
| 2157 |
-
insight_lines.append(
|
|
|
|
|
|
|
|
|
|
| 2158 |
|
| 2159 |
# 4. Kuadran risiko
|
| 2160 |
if dev["obj5_q1_divs"] or dev["obj5_q2_divs"]:
|
| 2161 |
q1 = ", ".join([f"<strong>{d}</strong>" for d in dev["obj5_q1_divs"][:3]])
|
| 2162 |
q2 = ", ".join([f"<strong>{d}</strong>" for d in dev["obj5_q2_divs"][:3]])
|
| 2163 |
-
|
|
|
|
|
|
|
| 2164 |
|
| 2165 |
# 5. Top 2 kategori
|
| 2166 |
if dev["obj6_top2_categories"]:
|
|
@@ -2169,77 +2150,51 @@ if dev["obj6_top2_categories"]:
|
|
| 2169 |
|
| 2170 |
insight_text = "<br>".join(insight_lines)
|
| 2171 |
|
| 2172 |
-
#
|
| 2173 |
recs = []
|
| 2174 |
|
| 2175 |
-
# 1
|
| 2176 |
if dev["lowest_ratio_9_locs"]:
|
| 2177 |
recs.append({
|
| 2178 |
"point": "1",
|
| 2179 |
-
"rec": "Luncurkan
|
| 2180 |
-
"mit": "Aktifkan
|
| 2181 |
})
|
| 2182 |
|
| 2183 |
-
# 2 →
|
| 2184 |
-
if
|
| 2185 |
recs.append({
|
| 2186 |
"point": "2",
|
| 2187 |
-
"rec": "
|
| 2188 |
-
"mit": "
|
| 2189 |
-
})
|
| 2190 |
-
|
| 2191 |
-
# 2a–2d → rekomendasi individual
|
| 2192 |
-
if dev["obj3a_lowest_div"]:
|
| 2193 |
-
recs.append({
|
| 2194 |
-
"point": "2a",
|
| 2195 |
-
"rec": "Assign *Safety Buddy* dari divisi berkinerja tinggi ke divisi terendah untuk 2 minggu *shadowing & transfer knowledge*.",
|
| 2196 |
-
"mit": "Integrasikan *micro-reporting goal*: 1 temuan/minggu/orang. Sistem otomatis lacak progres & kirim apresiasi digital tiap goal tercapai."
|
| 2197 |
-
})
|
| 2198 |
-
if dev["obj3b_slowest_executor"]:
|
| 2199 |
-
recs.append({
|
| 2200 |
-
"point": "2b",
|
| 2201 |
-
"rec": "Aktifkan *Rapid Closure Protocol* untuk eksekutor terlambat: verifikasi via foto + approval satu tingkat → target ≤3 hari.",
|
| 2202 |
-
"mit": "Jika >5 hari, sistem auto-escalate ke Daily Safety Huddle & PIC Area via Telegram."
|
| 2203 |
-
})
|
| 2204 |
-
if dev["obj3c_lowest_reporter"]:
|
| 2205 |
-
recs.append({
|
| 2206 |
-
"point": "2c",
|
| 2207 |
-
"rec": "Terapkan *Nudge Agent Program*: PIC lokasi bertanggung jawab memastikan semua anggota tim minimal 1x inspeksi/minggu.",
|
| 2208 |
-
"mit": "Reward: point redeemable di kantin. Sistem kirim reminder 2x/minggu + contoh temuan sederhana (e.g., APD tidak lengkap)."
|
| 2209 |
-
})
|
| 2210 |
-
if dev["obj3d_slowest_div"]:
|
| 2211 |
-
recs.append({
|
| 2212 |
-
"point": "2d",
|
| 2213 |
-
"rec": "Lakukan *Process Mining*: petakan alur temuan dari buka → tutup, identifikasi *waste* (waiting, rework, approval bottleneck).",
|
| 2214 |
-
"mit": "Terapkan SLA berlapis: High Risk ≤3 hari, Medium/Low ≤7 hari. Jika breach ≥2x/bulan → picu *capacity intervention* otomatis."
|
| 2215 |
})
|
| 2216 |
|
| 2217 |
-
# 3
|
| 2218 |
if uc + ua + nm > 0:
|
| 2219 |
recs.append({
|
| 2220 |
"point": "3",
|
| 2221 |
-
"rec": "Luncurkan
|
| 2222 |
-
"mit": "Sistem blokir submit jika tidak memenuhi. Tampilkan
|
| 2223 |
})
|
| 2224 |
|
| 2225 |
-
# 4
|
| 2226 |
if dev["obj5_q1_divs"] or dev["obj5_q2_divs"]:
|
| 2227 |
recs.append({
|
| 2228 |
"point": "4",
|
| 2229 |
-
"rec": "Alokasikan
|
| 2230 |
-
"mit": "Jika masuk Kuadran I/II ≥2 bulan berturut-turut → sistem auto-generate
|
| 2231 |
})
|
| 2232 |
|
| 2233 |
-
# 5
|
| 2234 |
if dev["obj6_top2_categories"]:
|
| 2235 |
c1, c2 = dev["obj6_top2_categories"]
|
| 2236 |
recs.append({
|
| 2237 |
"point": "5",
|
| 2238 |
-
"rec": f"Bentuk
|
| 2239 |
"mit": "Revisi spesifikasi teknis & template tender: semua penawaran wajib menyertakan mitigasi berbasis temuan historis."
|
| 2240 |
})
|
| 2241 |
|
| 2242 |
-
#
|
| 2243 |
st.markdown(
|
| 2244 |
f"""
|
| 2245 |
<div class="card" style="
|
|
|
|
| 1981 |
else:
|
| 1982 |
st.info("No data available for non-positive issue categories with 100% coverage and positive trend.")
|
| 1983 |
# =================== OBJECTIVE 7 — Insight and Recommendation (Agentic AI LLM Style — Final) ===================
|
| 1984 |
+
# =================== OBJECTIVE 7 — Insight and Recommendation (Final — Agentic AI, No markdown bold) ===================
|
| 1985 |
st.markdown("<h3 class='section-title'>OBJECTIVE 7 — Insight and Recommendation</h3>", unsafe_allow_html=True)
|
| 1986 |
|
| 1987 |
+
def extract_agentic_insights_v5(df: pd.DataFrame):
|
| 1988 |
dev = {
|
|
|
|
| 1989 |
"lowest_ratio_9_locs": [],
|
|
|
|
| 1990 |
"obj3a_lowest_div": None,
|
| 1991 |
"obj3b_slowest_executor": None,
|
| 1992 |
"obj3c_lowest_reporter": None,
|
| 1993 |
"obj3d_slowest_div": None,
|
|
|
|
| 1994 |
"obj4_unsafe_condition_pct": 0.0,
|
| 1995 |
"obj4_unsafe_action_pct": 0.0,
|
| 1996 |
"obj4_near_miss_pct": 0.0,
|
|
|
|
| 1997 |
"obj5_q1_divs": [],
|
| 1998 |
"obj5_q2_divs": [],
|
|
|
|
| 1999 |
"obj6_top2_categories": [],
|
| 2000 |
}
|
| 2001 |
|
|
|
|
| 2087 |
elif r['Finding Count'] < X_LIMIT and r['Avg Lead Time'] >= Y_LIMIT:
|
| 2088 |
dev["obj5_q2_divs"].append(r['nama'])
|
| 2089 |
|
| 2090 |
+
# === 5. Top 2 non-Positive category ===
|
| 2091 |
if {'kategori', 'temuan_kategori', 'created_at'}.issubset(df.columns):
|
| 2092 |
nonpos = df[df['temuan_kategori'] != 'Positive']
|
| 2093 |
if not nonpos.empty:
|
|
|
|
| 2099 |
|
| 2100 |
return dev
|
| 2101 |
|
| 2102 |
+
dev = extract_agentic_insights_v5(df_filtered)
|
|
|
|
| 2103 |
|
| 2104 |
+
# === INSIGHT BUILD ===
|
| 2105 |
insight_lines = []
|
| 2106 |
|
| 2107 |
+
# 1. 9 lokasi terendah (semua)
|
| 2108 |
if dev["lowest_ratio_9_locs"]:
|
| 2109 |
loc_list = ", ".join([f"<strong>{loc}</strong> ({ratio})" for loc, ratio in dev["lowest_ratio_9_locs"]])
|
| 2110 |
+
insight_lines.append(f"1. Sembilan lokasi dengan rasio temuan/orang <em>terendah</em> (<0.5): {loc_list}.")
|
| 2111 |
|
| 2112 |
+
# 2. Gabungan 2a–2d → satu insight agentic AI
|
| 2113 |
+
parts = []
|
|
|
|
| 2114 |
if dev["obj3a_lowest_div"]:
|
| 2115 |
+
parts.append(f"divisi <strong>{dev['obj3a_lowest_div'][0]}</strong> (rasio {dev['obj3a_lowest_div'][1]})")
|
| 2116 |
if dev["obj3c_lowest_reporter"]:
|
| 2117 |
+
parts.append(f"reporter <strong>{dev['obj3c_lowest_reporter'][0]}</strong> ({dev['obj3c_lowest_reporter'][1]}/bln)")
|
| 2118 |
if dev["obj3d_slowest_div"]:
|
| 2119 |
+
parts.append(f"divisi <strong>{dev['obj3d_slowest_div'][0]}</strong> ({dev['obj3d_slowest_div'][1]} hari)")
|
| 2120 |
if dev["obj3b_slowest_executor"]:
|
| 2121 |
+
parts.append(f"eksekutor <strong>{dev['obj3b_slowest_executor'][0]}</strong> ({dev['obj3b_slowest_executor'][1]} hari)")
|
| 2122 |
|
| 2123 |
+
if parts:
|
| 2124 |
+
joined = "; ".join(parts)
|
| 2125 |
insight_lines.append(
|
| 2126 |
+
f"2. Sistem mendeteksi <em>agency-capacity mismatch</em>: {joined}. "
|
| 2127 |
+
"Ini menunjukkan ketidakseimbangan antara kapasitas pelaporan dan kapasitas resolusi — dua pilar utama ekosistem <em>agentic safety</em>."
|
|
|
|
| 2128 |
)
|
| 2129 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2130 |
# 3. Komposisi non-Positive
|
| 2131 |
uc, ua, nm = dev["obj4_unsafe_condition_pct"], dev["obj4_unsafe_action_pct"], dev["obj4_near_miss_pct"]
|
| 2132 |
if uc + ua + nm > 0:
|
| 2133 |
+
insight_lines.append(
|
| 2134 |
+
f"3. Komposisi non-Positive: Unsafe Condition ({uc}%), Unsafe Action ({ua}%), Near Miss ({nm}%). "
|
| 2135 |
+
"Proporsi Near Miss masih rendah — indikasi <em>under-reporting of close calls</em>."
|
| 2136 |
+
)
|
| 2137 |
|
| 2138 |
# 4. Kuadran risiko
|
| 2139 |
if dev["obj5_q1_divs"] or dev["obj5_q2_divs"]:
|
| 2140 |
q1 = ", ".join([f"<strong>{d}</strong>" for d in dev["obj5_q1_divs"][:3]])
|
| 2141 |
q2 = ", ".join([f"<strong>{d}</strong>" for d in dev["obj5_q2_divs"][:3]])
|
| 2142 |
+
q1_str = q1 if q1 else "—"
|
| 2143 |
+
q2_str = q2 if q2 else "—"
|
| 2144 |
+
insight_lines.append(f"4. Divisi risiko tinggi (Kuadran I): {q1_str}. Divisi risiko tersembunyi (Kuadran II): {q2_str}.")
|
| 2145 |
|
| 2146 |
# 5. Top 2 kategori
|
| 2147 |
if dev["obj6_top2_categories"]:
|
|
|
|
| 2150 |
|
| 2151 |
insight_text = "<br>".join(insight_lines)
|
| 2152 |
|
| 2153 |
+
# === REKOMENDASI & MITIGASI (Agentic AI Style) ===
|
| 2154 |
recs = []
|
| 2155 |
|
| 2156 |
+
# 1
|
| 2157 |
if dev["lowest_ratio_9_locs"]:
|
| 2158 |
recs.append({
|
| 2159 |
"point": "1",
|
| 2160 |
+
"rec": "Luncurkan <em>Agency Activation Sprint</em> di 9 lokasi terendah: PIC Area wajib lakukan 1 inspeksi spot/minggu.",
|
| 2161 |
+
"mit": "Aktifkan QR code checklist 3-menit + notifikasi WhatsApp otomatis. Target: rasio ≥0.5 dalam 45 hari."
|
| 2162 |
})
|
| 2163 |
|
| 2164 |
+
# 2 → gabungan 2a–2d
|
| 2165 |
+
if parts:
|
| 2166 |
recs.append({
|
| 2167 |
"point": "2",
|
| 2168 |
+
"rec": "Aktifkan <em>Agentic Capacity Dashboard</em>: monitor rasio & lead time per individu/divisi secara real-time.",
|
| 2169 |
+
"mit": "Jika deviasi >20% dari baseline → picu <em>auto-coaching alert</em> ke PIC Area & Safety Manager, disertai best practice dari division benchmark."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2170 |
})
|
| 2171 |
|
| 2172 |
+
# 3
|
| 2173 |
if uc + ua + nm > 0:
|
| 2174 |
recs.append({
|
| 2175 |
"point": "3",
|
| 2176 |
+
"rec": "Luncurkan <em>Near Miss Amplifier</em>: setiap laporan Unsafe Condition wajib diikuti ≥1 Near Miss terkait.",
|
| 2177 |
+
"mit": "Sistem blokir submit jika tidak memenuhi. Tampilkan <em>Near Miss Leaderboard</em> di dashboard tim."
|
| 2178 |
})
|
| 2179 |
|
| 2180 |
+
# 4
|
| 2181 |
if dev["obj5_q1_divs"] or dev["obj5_q2_divs"]:
|
| 2182 |
recs.append({
|
| 2183 |
"point": "4",
|
| 2184 |
+
"rec": "Alokasikan <em>dedicated safety crew</em> untuk Kuadran I; terapkan <em>One Finding, One Day</em> untuk Kuadran II.",
|
| 2185 |
+
"mit": "Jika masuk Kuadran I/II ≥2 bulan berturut-turut → sistem auto-generate <em>executive escalation report</em> ke VP Operasi."
|
| 2186 |
})
|
| 2187 |
|
| 2188 |
+
# 5
|
| 2189 |
if dev["obj6_top2_categories"]:
|
| 2190 |
c1, c2 = dev["obj6_top2_categories"]
|
| 2191 |
recs.append({
|
| 2192 |
"point": "5",
|
| 2193 |
+
"rec": f"Bentuk <em>RCA Task Force</em> lintas fungsi (SIPIL, ELEKTRIKAL, K3, Kontraktor) untuk {c1[0]} & {c2[0]}.",
|
| 2194 |
"mit": "Revisi spesifikasi teknis & template tender: semua penawaran wajib menyertakan mitigasi berbasis temuan historis."
|
| 2195 |
})
|
| 2196 |
|
| 2197 |
+
# === TAMPILKAN ===
|
| 2198 |
st.markdown(
|
| 2199 |
f"""
|
| 2200 |
<div class="card" style="
|