MohitRajput45 commited on
Commit
3cc09e8
Β·
verified Β·
1 Parent(s): f1e785b

Upload 5 files

Browse files
app/__init__.py ADDED
File without changes
app/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (142 Bytes). View file
 
app/__pycache__/main.cpython-310.pyc ADDED
Binary file (1.48 kB). View file
 
app/main.py ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ import pandas as pd
3
+ import sys
4
+ import os
5
+ from dotenv import load_dotenv
6
+
7
+ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
8
+ load_dotenv()
9
+
10
+ from src.pipeline.predict_pipeline import PredictPipeline
11
+ from src.monitoring.db import save_to_db, init_db
12
+
13
+ # Initialize Cloud DB connection on startup
14
+ init_db()
15
+
16
+ app = FastAPI(title="Fraud Detection API")
17
+
18
+ # Load pipeline into memory once (prevents reloading massive models on every API call)
19
+ pipeline = PredictPipeline()
20
+
21
+ @app.get("/")
22
+ def home():
23
+ return {"message": "Fraud Detection API is running πŸš€"}
24
+
25
+ @app.post("/predict")
26
+ def predict(data: dict):
27
+ # 1. Define the exact column order the model was trained on
28
+ expected_columns = ["Time"] + [f"V{i}" for i in range(1, 29)] + ["Amount"]
29
+
30
+ # 2. Convert the incoming JSON into a Pandas DataFrame and FORCE the column order
31
+ df = pd.DataFrame([data], columns=expected_columns)
32
+
33
+ # 3. Get predictions using the properly ordered data
34
+ pred, prob = pipeline.predict(df)
35
+
36
+ # 4. Save to Cloud DB for future drift detection and retraining
37
+ save_to_db(data, int(pred), float(prob))
38
+
39
+ # Business Logic Layer
40
+ if prob > 0.8:
41
+ action = "🚫 Block Transaction"
42
+ elif prob > 0.4:
43
+ action = "⚠️ Flag for Review"
44
+ else:
45
+ action = "βœ… Allow Transaction"
46
+
47
+ return {
48
+ "fraud_prediction": int(pred),
49
+ "fraud_probability": float(prob),
50
+ "recommended_action": action
51
+ }
app/streamlit_app.py ADDED
@@ -0,0 +1,215 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import sys
4
+ import os
5
+ import requests
6
+ import shap
7
+ import matplotlib.pyplot as plt
8
+ import streamlit.components.v1 as components
9
+ import random
10
+ from dotenv import load_dotenv
11
+
12
+ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
13
+ load_dotenv()
14
+ API_URL = os.getenv("API_URL", "http://127.0.0.1:8000/predict")
15
+
16
+ from src.pipeline.predict_pipeline import PredictPipeline
17
+ from src.explanability.shap_explainer import ShapExplainer
18
+ from src.monitoring.db import save_to_db
19
+
20
+ st.set_page_config(page_title="Fraud Guard", layout="wide")
21
+
22
+ # --- Initialize Session State for Auto-Fill Buttons ---
23
+ if "t_time" not in st.session_state: st.session_state.t_time = 10000.0
24
+ if "t_amount" not in st.session_state: st.session_state.t_amount = 100.0
25
+ for i in range(1, 29):
26
+ if f"v_{i}" not in st.session_state: st.session_state[f"v_{i}"] = 0.0
27
+
28
+ import random
29
+
30
+ def generate_sample(is_fraud=False):
31
+ """Fills the UI with either a normal transaction or a simulated fraud attack"""
32
+ if is_fraud:
33
+ # A mini-database of 3 completely different, real fraud signatures
34
+ fraud_database = [
35
+ {
36
+ "Time": 406.0, "Amount": 0.00,
37
+ "V": [-2.312, 1.951, -1.609, 3.997, -0.522, -1.426, -2.537, 1.391, -2.770, -2.772,
38
+ 3.202, -2.899, -0.595, -4.289, 0.389, -1.140, -2.830, -0.016, 0.416, 0.126,
39
+ 0.517, -0.035, -0.465, 0.320, 0.044, 0.177, 0.261, -0.143]
40
+ },
41
+ {
42
+ # A "Borderline" Fraud Signature to test the Threshold Slider
43
+ "Time": 12500.0, "Amount": 99.99,
44
+ "V": [-0.95, 0.52, -1.53, 0.85, -0.21, 0.11, -0.45, 0.22, -0.63, -1.05,
45
+ 1.20, -1.55, 0.30, -2.01, 0.10, -0.55, -1.22, 0.20, 0.45, -0.10,
46
+ 0.25, 0.15, -0.12, 0.05, 0.22, -0.15, 0.02, 0.05]
47
+ },
48
+ {
49
+ "Time": 4462.0, "Amount": 1.00,
50
+ "V": [-2.303, 1.759, -0.359, 2.330, -0.821, -0.075, -0.560, 1.214, -1.385, -2.776,
51
+ 3.231, -2.719, -1.059, -3.535, -1.583, -1.488, -2.573, -0.739, 0.380, -0.430,
52
+ -0.294, -0.932, 0.172, -0.087, -0.156, -0.542, 0.039, -0.153]
53
+ }
54
+ ]
55
+
56
+ # Randomly select one of the real fraud signatures
57
+ chosen_fraud = random.choice(fraud_database)
58
+
59
+ st.session_state.t_time = chosen_fraud["Time"]
60
+ st.session_state.t_amount = chosen_fraud["Amount"]
61
+ for i in range(1, 29):
62
+ st.session_state[f"v_{i}"] = chosen_fraud["V"][i-1]
63
+
64
+ else:
65
+ # Normal baseline simulation (This stays random because normal transactions are easy to mimic)
66
+ st.session_state.t_time = random.uniform(100, 150000)
67
+ st.session_state.t_amount = random.uniform(5, 150)
68
+ for i in range(1, 29):
69
+ st.session_state[f"v_{i}"] = random.uniform(-1.0, 1.0)
70
+
71
+ # --- UI Sidebar & Navigation ---
72
+ page = st.sidebar.selectbox("πŸ“Œ Choose Section", ["Prediction", "Drift Monitoring"])
73
+
74
+ if page == "Prediction":
75
+ st.markdown("""
76
+ <div style='text-align: center; padding: 1rem 0;'>
77
+ <h1 style='color: #1E3A8A;'>πŸ’³ Fraud Guard Intelligence</h1>
78
+ <p style='color: #6B7280; font-size: 1.2rem;'>Real-Time Transaction Risk Analysis</p>
79
+ </div>
80
+ """, unsafe_allow_html=True)
81
+
82
+ col1, col2 = st.columns([1, 2])
83
+
84
+ with col1:
85
+ st.markdown("### πŸ› οΈ Demo Controls")
86
+ # πŸ”₯ UI UPGRADE: One-click auto-fill buttons
87
+ demo_col1, demo_col2 = st.columns(2)
88
+ with demo_col1:
89
+ if st.button("βœ… Simulate Normal User", use_container_width=True):
90
+ generate_sample(is_fraud=False)
91
+ with demo_col2:
92
+ if st.button("🚨 Simulate Fraud Attack", type="primary", use_container_width=True):
93
+ generate_sample(is_fraud=True)
94
+
95
+ st.markdown("### πŸ“₯ Transaction Input")
96
+ with st.container(border=True):
97
+ with st.form("transaction_form"):
98
+
99
+ # Tie sliders to session state keys
100
+ t_time = st.slider("Time (Sec)", 0.0, 172800.0, key="t_time")
101
+ t_amount = st.slider("Amount ($)", 0.0, 5000.0, key="t_amount")
102
+
103
+ with st.expander("PCA Feature Vectors (V1 - V28)", expanded=False):
104
+ v_data = {}
105
+ for i in range(1, 29):
106
+ # Tie number inputs to session state, making them instantly update
107
+ v_data[f"V{i}"] = st.number_input(f"V{i}", key=f"v_{i}", format="%.4f")
108
+
109
+ st.markdown("---")
110
+ threshold = st.slider("AI Sensitivity (Threshold)", 0.05, 0.95, 0.15)
111
+ submit_btn = st.form_submit_button("πŸ” Run Analysis", use_container_width=True)
112
+
113
+ with col2:
114
+ st.markdown("### πŸ“Š Live Telemetry & Assessment")
115
+ if not submit_btn:
116
+ st.info("Awaiting transaction payload. Click 'Simulate' then 'Run Analysis'.")
117
+
118
+ if submit_btn:
119
+ payload = {"Time": st.session_state.t_time, "Amount": st.session_state.t_amount, **v_data}
120
+
121
+ try:
122
+ with st.spinner("Analyzing threat vectors..."):
123
+ response = requests.post(API_URL, json=payload, timeout=30)
124
+ result = response.json()
125
+
126
+ prob = result["fraud_probability"]
127
+ pred = 1 if prob > threshold else 0
128
+ action = "🚫 Block Transaction" if pred == 1 else "βœ… Allow Transaction"
129
+
130
+ if pred == 1:
131
+ st.error(f"🚨 FRAUD DETECTED: {action}")
132
+ else:
133
+ st.success(f"βœ… TRANSACTION SAFE: {action}")
134
+
135
+ m_col1, m_col2 = st.columns(2)
136
+ m_col1.metric("Risk Level", f"{prob:.4%}")
137
+ m_col2.metric("Prediction Output", pred)
138
+
139
+ st.progress(float(prob))
140
+ st.markdown("---")
141
+
142
+ st.subheader("🧠 Explainable AI (SHAP)")
143
+ with st.spinner("Generating explanations..."):
144
+ input_df = pd.DataFrame([payload])
145
+
146
+ pipeline = PredictPipeline()
147
+ processed_df = pipeline.preprocess(input_df)
148
+
149
+ explainer = ShapExplainer()
150
+ shap_values = explainer.explain(processed_df)
151
+
152
+ fig, ax = plt.subplots(figsize=(8, 4))
153
+ shap.plots.waterfall(shap_values[0], show=False)
154
+ st.pyplot(fig)
155
+
156
+ except Exception as e:
157
+ st.error(f"⏳ Error connecting to API: {e}")
158
+
159
+ elif page == "Drift Monitoring":
160
+ st.title("πŸ“‰ Data Drift Monitoring")
161
+ st.markdown("### Monitor model health & trigger verified retraining")
162
+
163
+ # πŸ”₯ UI UPGRADE: Drift Injection Button for easy testing
164
+ with st.expander("πŸ› οΈ Demo Tools: Force Data Drift", expanded=True):
165
+ st.write("Inject 50 heavily skewed transactions into the database to trigger a statistical drift warning.")
166
+ if st.button("πŸ’‰ Inject Synthetic Drift Data", type="primary"):
167
+ with st.spinner("Injecting bad data into Cloud DB..."):
168
+ for _ in range(50):
169
+ skewed_data = {"Time": random.uniform(10, 50000), "Amount": random.uniform(1000, 5000)}
170
+ for i in range(1, 29):
171
+ skewed_data[f"V{i}"] = random.uniform(-15.0, 15.0) # Massive deviation
172
+ save_to_db(skewed_data, pred=1, prob=0.99)
173
+ st.success("βœ… 50 Skewed rows injected! Now click 'Run Drift Detection' below.")
174
+
175
+ st.markdown("---")
176
+
177
+ try:
178
+ from src.monitoring.drift import detect_drift
179
+ from src.pipeline.retrain_pipeline import retrain
180
+ except:
181
+ st.error("⚠️ Drift feature not supported in this environment")
182
+ st.stop()
183
+
184
+ if st.button("πŸš€ Run Drift Detection"):
185
+ with st.spinner("Running statistical drift analysis..."):
186
+ try:
187
+ report_path = detect_drift("data/creditcard.csv")
188
+ if report_path:
189
+ st.success("βœ… Drift report generated!")
190
+ st.session_state["drift_done"] = True
191
+ else:
192
+ st.warning("⚠️ Not enough data in live DB (Needs 50 rows). Use the Demo Injector above!")
193
+ except Exception as e:
194
+ st.error(f"⚠️ Error running drift: {e}")
195
+
196
+ report_path = "reports/drift_report.html"
197
+ if os.path.exists(report_path):
198
+ with open(report_path, "r", encoding="utf-8") as f:
199
+ html = f.read()
200
+ components.html(html, height=800, scrolling=True)
201
+
202
+ st.markdown("---")
203
+ st.subheader("πŸ” Human-in-the-Loop Retraining")
204
+ st.write("Ensure database contains human-verified `Actual_Class` labels before retraining.")
205
+
206
+ if st.session_state.get("drift_done", False):
207
+ if st.button("⚑ Retrain Model (Requires Verified Data)"):
208
+ with st.spinner("Retraining model..."):
209
+ try:
210
+ retrain()
211
+ st.success("βœ… Model retrained successfully with verified data!")
212
+ except ValueError as ve:
213
+ st.error(f"❌ {ve}")
214
+ except Exception as e:
215
+ st.error(f"❌ Error: {e}")