File size: 3,712 Bytes
cf86c3a
dd8c606
4881b97
 
 
 
dd8c606
4881b97
 
dd8c606
4881b97
 
 
 
 
 
 
 
cf86c3a
4881b97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235d85c
4881b97
 
 
 
 
235d85c
4881b97
 
 
 
 
 
c41e114
4881b97
 
235d85c
4881b97
 
 
 
8b0c3b4
4881b97
 
 
c6d403e
4881b97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5d337dd
 
4881b97
5d337dd
4881b97
 
 
8bab071
4881b97
 
5d337dd
4881b97
 
dd8c606
4881b97
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
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)