"""Dashboard metrics and KPI components.""" import streamlit as st def render_kpi_row( total_nudge: int, high_count: int, medium_count: int, risk_score: float, citation_total: int, ) -> None: """Render key metrics row with 5 KPIs. Args: total_nudge: Total negative mentions high_count: HIGH tier count medium_count: MEDIUM tier count risk_score: Calculated risk score citation_total: Total citation sources """ kpi1, kpi2, kpi3, kpi4, kpi5 = st.columns(5) with kpi1: st.metric( label="총 부정 언급", value=f"{total_nudge}건", help="AI가 자사 브랜드를 부정적으로 언급한 답변 수", ) with kpi2: st.metric( label="🔴 HIGH (즉시 대응)", value=f"{high_count}건", help="≥85% 확신도 - 즉시 대응 권장", ) with kpi3: st.metric( label="🟡 MEDIUM (검토)", value=f"{medium_count}건", help="70-85% 확신도 - 검토 필요", ) with kpi4: st.metric( label="리스크 점수", value=f"{risk_score:.1f}", help="HIGH=100%, MEDIUM=50%, LOW=20% 가중 평균", ) with kpi5: st.metric( label="총 인용 소스", value=f"{citation_total}개", help="AI 답변에서 인용된 총 소스 수", ) def render_verification_stats( total_verified: int, false_positives_count: int, true_negatives_count: int, ) -> None: """Render LLM verification statistics row. Args: total_verified: Total verified items false_positives_count: False positive count true_negatives_count: True negative count """ stat_col1, stat_col2, stat_col3, stat_col4 = st.columns(4) with stat_col1: st.metric("검증 완료", f"{total_verified}건") with stat_col2: fp_rate = (false_positives_count / total_verified * 100) if total_verified > 0 else 0 st.metric("오탐 (False Positive)", f"{false_positives_count}건", f"{fp_rate:.1f}%") with stat_col3: tn_rate = (true_negatives_count / total_verified * 100) if total_verified > 0 else 0 st.metric("진음성 (True Negative)", f"{true_negatives_count}건", f"{tn_rate:.1f}%") with stat_col4: if total_verified > 0: st.metric("오탐률", f"{fp_rate:.1f}%", delta=None) else: st.metric("오탐률", "N/A") def render_polarity_stats( positive_count: int, neutral_count: int, negative_count: int, ) -> None: """Render polarity distribution statistics. Args: positive_count: Positive sentiment count neutral_count: Neutral sentiment count negative_count: Negative sentiment count """ total_answers = positive_count + neutral_count + negative_count pol_col1, pol_col2, pol_col3, pol_col4 = st.columns(4) with pol_col1: st.metric("전체 분석", f"{total_answers:,}건") with pol_col2: pos_rate = (positive_count / total_answers * 100) if total_answers > 0 else 0 st.metric("😊 긍정", f"{positive_count:,}건", f"{pos_rate:.1f}%") with pol_col3: neu_rate = (neutral_count / total_answers * 100) if total_answers > 0 else 0 st.metric("😐 중립", f"{neutral_count:,}건", f"{neu_rate:.1f}%") with pol_col4: neg_rate = (negative_count / total_answers * 100) if total_answers > 0 else 0 st.metric("😞 부정", f"{negative_count:,}건", f"{neg_rate:.1f}%") def render_feedback_stats(feedback_stats: dict) -> None: """Render feedback statistics row. Args: feedback_stats: Dict with feedback counts and accuracy """ fb_total = feedback_stats.get("total_feedback", 0) fb_correct = feedback_stats.get("correct_count", 0) fb_wrong = feedback_stats.get("wrong_count", 0) fb_ambiguous = feedback_stats.get("ambiguous_count", 0) accuracy = feedback_stats.get("accuracy_rate", 0) fb_col1, fb_col2, fb_col3, fb_col4, fb_col5 = st.columns(5) with fb_col1: st.metric( label="총 피드백", value=f"{fb_total}건", help="사용자가 제출한 총 피드백 수", ) with fb_col2: st.metric( label="👍 정확", value=f"{fb_correct}건", delta=f"{fb_correct/fb_total*100:.0f}%" if fb_total > 0 else None, delta_color="normal", help="정확하다고 평가된 분석 수", ) with fb_col3: st.metric( label="👎 오류", value=f"{fb_wrong}건", delta=f"{fb_wrong/fb_total*100:.0f}%" if fb_total > 0 else None, delta_color="inverse", help="틀렸다고 평가된 분석 수", ) with fb_col4: st.metric( label="🤔 애매", value=f"{fb_ambiguous}건", help="판단하기 어려운 경우", ) with fb_col5: st.metric( label="정확도", value=f"{accuracy:.1f}%", help="정확 / (정확 + 오류) 비율", )