import gradio as gr import pandas as pd import joblib import matplotlib.pyplot as plt import seaborn as sns import io # Load trained model model = joblib.load("anomaly_detector_rf_model.pkl") # Features used during training feature_cols = [ "amount", "hour", "day_of_week", "is_weekend", "merchant_avg_amount", "amount_zscore", "log_amount", "type_atm_withdrawal", "type_credit", "type_debit", "merchant_encoded" ] # Function to detect anomalies def detect_anomalies(df): original_df = df.copy() for col in ["transaction_id", "merchant", "location", "amount"]: if col not in original_df.columns: original_df[col] = "N/A" if col != "amount" else 0.0 model_input = df.reindex(columns=feature_cols, fill_value=0) preds = model.predict(model_input) original_df["is_anomalous"] = preds anomalies = original_df[original_df["is_anomalous"] == 1] return original_df, anomalies[["transaction_id", "merchant", "location", "amount", "is_anomalous"]] # Function to plot charts def plot_charts(df): fig, axes = plt.subplots(2, 2, figsize=(12, 10)) if "amount" in df.columns: sns.histplot(df["amount"], bins=30, kde=True, ax=axes[0, 0]) axes[0, 0].set_title("Amount Distribution") sns.boxplot(x=df["amount"], ax=axes[0, 1]) axes[0, 1].set_title("Amount Box Plot") else: axes[0, 0].text(0.5, 0.5, "No 'amount' column", ha='center') axes[0, 1].text(0.5, 0.5, "No 'amount' column", ha='center') if "day_of_week" in df.columns: sns.countplot(x=df["day_of_week"], ax=axes[1, 0]) axes[1, 0].set_title("Transactions by Day of Week") else: axes[1, 0].text(0.5, 0.5, "No 'day_of_week' column", ha='center') if "merchant" in df.columns: top_merchants = df.groupby("merchant")["amount"].sum().nlargest(5).reset_index() sns.barplot(data=top_merchants, x="merchant", y="amount", ax=axes[1, 1]) axes[1, 1].set_title("Top 5 Merchants by Amount") else: axes[1, 1].text(0.5, 0.5, "No 'merchant' column", ha='center') plt.tight_layout() return fig # Function to generate summary + charts + file def app_interface(csv_file): df = pd.read_csv(csv_file) full_df, anomalies = detect_anomalies(df) total = len(full_df) anom_count = len(anomalies) percent = (anom_count / total) * 100 if total > 0 else 0 summary = ( f"🔢 **Total Transactions**: {total}\n" f"⚠️ **Anomalies Detected**: {anom_count}\n" f"📊 **Anomaly Percentage**: {percent:.2f}%" ) # Convert anomalies to CSV bytes for download csv_bytes = anomalies.to_csv(index=False).encode() download = io.BytesIO(csv_bytes) fig = plot_charts(full_df) return summary, anomalies, fig, download # Gradio App with UI with gr.Blocks(theme=gr.themes.Soft()) as interface: gr.Markdown("# 🛡️ Financial Abuse & Anomaly Detection App") gr.Markdown("Upload your **transaction CSV** to detect anomalies and view insights.") with gr.Row(): file_input = gr.File(label="📁 Upload CSV File", file_types=[".csv"]) detect_button = gr.Button("🚨 Run Detection", variant="primary") with gr.Row(): summary_box = gr.Markdown("") with gr.Tab("📋 Anomalies Detected"): result_table = gr.Dataframe(label="🔴 Anomalies") download_btn = gr.File(label="⬇️ Download Detected Anomalies") with gr.Tab("📊 Transaction Charts"): chart_output = gr.Plot() detect_button.click(fn=app_interface, inputs=file_input, outputs=[summary_box, result_table, chart_output, download_btn]) interface.launch(share=True)