import gradio as gr import pandas as pd import json # Load KPIs with open("kpis.json", "r") as f: kpis = json.load(f) # Load tables audit_df = pd.read_csv("hiring_audit_results.csv") subgroup_df = pd.read_csv("subgroup_score_analysis.csv") kpi_text = f""" ### 📊 Dashboard KPIs - **Total Candidates:** {kpis.get('total_candidates', 'N/A')} - **Flagged for Audit:** {kpis.get('flagged_candidates', 'N/A')} ({kpis.get('flag_rate_pct', 'N/A')}%) - **Mean Hiring Score:** {kpis.get('mean_hiring_score', 'N/A')} - **Bias Flagged Candidates:** {kpis.get('bias_flagged', 'N/A')} """ with gr.Blocks(title="AI Hiring Decision Auditor") as demo: gr.Markdown("# 🤖 AI Hiring Decision Auditor Dashboard") gr.Markdown("Internal tool for HR compliance officers to audit automated hiring decisions.") gr.Markdown(kpi_text) with gr.Tabs(): with gr.Tab("📈 Score Distribution by Gender"): gr.Image("score_distribution_by_gender.png") with gr.Tab("🔥 Bias Heatmap"): gr.Image("bias_heatmap_gender_education.png") gr.Markdown("Red cells indicate subgroups scoring significantly below average — primary bias risk zones.") with gr.Tab("⚠️ Risk Distribution by Gender"): gr.Image("risk_distribution_by_gender.png") with gr.Tab("💬 Sentiment vs Risk Label"): gr.Image("sentiment_vs_risk_label.png") gr.Markdown("Contradictions between recruiter sentiment and automated risk label indicate fail-silent risks.") with gr.Tab("📋 Subgroup Score Analysis"): gr.Dataframe(subgroup_df) with gr.Tab("🗂️ Full Audit Results"): gr.Dataframe(audit_df[['gender', 'education_level', 'hiring_score', 'risk_label', 'note_sentiment', 'audit_result']].head(100)) demo.launch()