MohitRajput45 commited on
Commit
be4f339
ยท
verified ยท
1 Parent(s): 08a0b7b

Update app/streamlit_app.py

Browse files
Files changed (1) hide show
  1. app/streamlit_app.py +100 -156
app/streamlit_app.py CHANGED
@@ -19,192 +19,136 @@ 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
  def generate_sample(is_fraud=False):
29
- """Fills the UI with either a normal transaction or a simulated fraud attack"""
30
  if is_fraud:
31
  fraud_database = [
32
- {
33
- "Time": 406.0, "Amount": 0.00,
34
- "V": [-2.312, 1.951, -1.609, 3.997, -0.522, -1.426, -2.537, 1.391, -2.770, -2.772,
35
- 3.202, -2.899, -0.595, -4.289, 0.389, -1.140, -2.830, -0.016, 0.416, 0.126,
36
- 0.517, -0.035, -0.465, 0.320, 0.044, 0.177, 0.261, -0.143]
37
- },
38
- {
39
- "Time": 12500.0, "Amount": 99.99,
40
- "V": [-0.95, 0.52, -1.53, 0.85, -0.21, 0.11, -0.45, 0.22, -0.63, -1.05,
41
- 1.20, -1.55, 0.30, -2.01, 0.10, -0.55, -1.22, 0.20, 0.45, -0.10,
42
- 0.25, 0.15, -0.12, 0.05, 0.22, -0.15, 0.02, 0.05]
43
- },
44
- {
45
- "Time": 4462.0, "Amount": 1.00,
46
- "V": [-2.303, 1.759, -0.359, 2.330, -0.821, -0.075, -0.560, 1.214, -1.385, -2.776,
47
- 3.231, -2.719, -1.059, -3.535, -1.583, -1.488, -2.573, -0.739, 0.380, -0.430,
48
- -0.294, -0.932, 0.172, -0.087, -0.156, -0.542, 0.039, -0.153]
49
- }
50
  ]
51
-
52
- chosen_fraud = random.choice(fraud_database)
53
-
54
- st.session_state.t_time = chosen_fraud["Time"]
55
- st.session_state.t_amount = chosen_fraud["Amount"]
56
- for i in range(1, 29):
57
- st.session_state[f"v_{i}"] = chosen_fraud["V"][i-1]
58
-
59
  else:
60
- st.session_state.t_time = random.uniform(100, 150000)
61
- st.session_state.t_amount = random.uniform(5, 150)
62
- for i in range(1, 29):
63
- st.session_state[f"v_{i}"] = random.uniform(-1.0, 1.0)
64
-
65
- # โœ… Cache ONLY heavy computation (safe)
66
- @st.cache_data(show_spinner=False)
67
- def get_prediction_and_shap(payload):
68
- response = requests.post(API_URL, json=payload, timeout=30)
69
- result = response.json()
70
-
71
- input_df = pd.DataFrame([payload])
72
- pipeline = PredictPipeline()
73
- processed_df = pipeline.preprocess(input_df)
74
-
75
- explainer = ShapExplainer()
76
- shap_values = explainer.explain(processed_df)
77
-
78
- return result, shap_values
79
-
80
- # --- UI Sidebar & Navigation ---
81
- page = st.sidebar.selectbox("๐Ÿ“Œ Choose Section", ["Prediction", "Drift Monitoring"])
82
 
 
 
 
 
 
 
83
  if page == "Prediction":
84
- st.markdown("""
85
- <div style='text-align: center; padding: 1rem 0;'>
86
- <h1 style='color: #1E3A8A;'>๐Ÿ’ณ Fraud Guard Intelligence</h1>
87
- <p style='color: #6B7280; font-size: 1.2rem;'>Real-Time Transaction Risk Analysis</p>
88
- </div>
89
- """, unsafe_allow_html=True)
90
 
91
- col1, col2 = st.columns([1, 2])
 
 
92
 
93
  with col1:
94
- st.markdown("### ๐Ÿ› ๏ธ Demo Controls")
95
- demo_col1, demo_col2 = st.columns(2)
96
- with demo_col1:
97
- if st.button("โœ… Simulate Normal User", use_container_width=True):
98
- generate_sample(is_fraud=False)
99
- with demo_col2:
100
- if st.button("๐Ÿšจ Simulate Fraud Attack", type="primary", use_container_width=True):
101
- generate_sample(is_fraud=True)
102
-
103
- st.markdown("### ๐Ÿ“ฅ Transaction Input")
104
- with st.container(border=True):
105
- with st.form("transaction_form"):
106
-
107
- t_time = st.slider("Time (Sec)", 0.0, 172800.0, key="t_time")
108
- t_amount = st.slider("Amount ($)", 0.0, 5000.0, key="t_amount")
109
-
110
- # โœ… Ensure v_data always exists
111
- v_data = {}
112
- with st.expander("PCA Feature Vectors (V1 - V28)", expanded=False):
113
- for i in range(1, 29):
114
- v_data[f"V{i}"] = st.number_input(f"V{i}", key=f"v_{i}", format="%.4f")
115
-
116
- st.markdown("---")
117
- threshold = st.slider("AI Sensitivity (Threshold)", 0.05, 0.95, 0.15)
118
- submit_btn = st.form_submit_button("๐Ÿ” Run Analysis", use_container_width=True)
119
 
120
- with col2:
121
- st.markdown("### ๐Ÿ“Š Live Telemetry & Assessment")
122
- if not submit_btn:
123
- st.info("Awaiting transaction payload. Click 'Simulate' then 'Run Analysis'.")
 
 
 
124
 
125
- if submit_btn:
126
- payload = {"Time": st.session_state.t_time, "Amount": st.session_state.t_amount, **v_data}
127
-
 
 
 
128
  try:
129
- with st.spinner("Analyzing threat vectors..."):
130
- result, shap_values = get_prediction_and_shap(payload)
131
-
132
- prob = result["fraud_probability"]
133
- pred = 1 if prob > threshold else 0
134
- action = "๐Ÿšซ Block Transaction" if pred == 1 else "โœ… Allow Transaction"
135
-
136
- if pred == 1:
137
- st.error(f"๐Ÿšจ FRAUD DETECTED: {action}")
138
  else:
139
- st.success(f"โœ… TRANSACTION SAFE: {action}")
140
-
141
- m_col1, m_col2 = st.columns(2)
142
- m_col1.metric("Risk Level", f"{prob:.4%}")
143
- m_col2.metric("Prediction Output", pred)
144
-
145
  st.progress(float(prob))
146
- st.markdown("---")
147
-
148
- st.subheader("๐Ÿง  Explainable AI (SHAP)")
149
-
150
- # โœ… FIX: No caching here (prevents shap hashing error)
151
- fig, ax = plt.subplots(figsize=(8, 4))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  shap.plots.waterfall(shap_values[0], show=False)
153
  st.pyplot(fig)
154
 
155
  except Exception as e:
156
- st.error(f"โณ Error connecting to API: {e}")
157
 
 
 
 
 
158
  elif page == "Drift Monitoring":
159
- st.title("๐Ÿ“‰ Data Drift Monitoring")
160
- st.markdown("### Monitor model health & trigger verified retraining")
161
-
162
- with st.expander("๐Ÿ› ๏ธ Demo Tools: Force Data Drift", expanded=True):
163
- st.write("Inject 50 heavily skewed transactions into the database to trigger a statistical drift warning.")
164
- if st.button("๐Ÿ’‰ Inject Synthetic Drift Data", type="primary"):
165
- with st.spinner("Injecting bad data into Cloud DB..."):
166
- for _ in range(50):
167
- skewed_data = {"Time": random.uniform(10, 50000), "Amount": random.uniform(1000, 5000)}
168
- for i in range(1, 29):
169
- skewed_data[f"V{i}"] = random.uniform(-15.0, 15.0)
170
- save_to_db(skewed_data, pred=1, prob=0.99)
171
- st.success("โœ… 50 Skewed rows injected! Now click 'Run Drift Detection' below.")
172
-
173
- st.markdown("---")
174
 
175
  try:
176
  from src.monitoring.drift import detect_drift
177
  from src.pipeline.retrain_pipeline import retrain
178
  except:
179
- st.error("โš ๏ธ Drift feature not supported in this environment")
180
  st.stop()
181
 
182
- if st.button("๐Ÿš€ Run Drift Detection"):
183
- with st.spinner("Running statistical drift analysis..."):
184
- try:
185
- report_path = detect_drift("data/creditcard.csv")
186
- if report_path:
187
- st.success("โœ… Drift report generated!")
188
- st.session_state["drift_done"] = True
189
- else:
190
- st.warning("โš ๏ธ Not enough data in live DB (Needs 50 rows). Use the Demo Injector above!")
191
- except Exception as e:
192
- st.error(f"โš ๏ธ Error running drift: {e}")
193
-
194
- report_path = "reports/drift_report.html"
195
- if os.path.exists(report_path):
196
- with open(report_path, "r", encoding="utf-8") as f:
197
- html = f.read()
198
- components.html(html, height=800, scrolling=True)
199
-
200
- st.markdown("---")
201
- st.subheader("๐Ÿ” Human-in-the-Loop Retraining")
202
-
203
- if st.session_state.get("drift_done", False):
204
- if st.button("โšก Retrain Model (Requires Verified Data)"):
205
- with st.spinner("Retraining model..."):
206
- try:
207
- retrain()
208
- st.success("โœ… Model retrained successfully with verified data!")
209
- except Exception as e:
210
- st.error(f"โŒ Error: {e}")
 
19
 
20
  st.set_page_config(page_title="Fraud Guard", layout="wide")
21
 
22
+ # --- Initialize Session State ---
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
  def generate_sample(is_fraud=False):
 
29
  if is_fraud:
30
  fraud_database = [
31
+ {"Time": 406.0, "Amount": 0.00, "V": [-2.312,1.951,-1.609,3.997,-0.522,-1.426,-2.537,1.391,-2.770,-2.772,3.202,-2.899,-0.595,-4.289,0.389,-1.140,-2.830,-0.016,0.416,0.126,0.517,-0.035,-0.465,0.320,0.044,0.177,0.261,-0.143]}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  ]
33
+ chosen = random.choice(fraud_database)
34
+ st.session_state.t_time = chosen["Time"]
35
+ st.session_state.t_amount = chosen["Amount"]
36
+ for i in range(1,29):
37
+ st.session_state[f"v_{i}"] = chosen["V"][i-1]
 
 
 
38
  else:
39
+ st.session_state.t_time = random.uniform(100,150000)
40
+ st.session_state.t_amount = random.uniform(5,150)
41
+ for i in range(1,29):
42
+ st.session_state[f"v_{i}"] = random.uniform(-1,1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
+ # --- Sidebar Navigation ---
45
+ page = st.sidebar.selectbox("๐Ÿ“Œ Choose Section", ["Prediction", "Explainability (SHAP)", "Drift Monitoring"])
46
+
47
+ # =========================
48
+ # ๐Ÿ”น PREDICTION PAGE (NO SHAP)
49
+ # =========================
50
  if page == "Prediction":
 
 
 
 
 
 
51
 
52
+ st.markdown("## ๐Ÿ’ณ Fraud Guard Intelligence")
53
+
54
+ col1, col2 = st.columns([1,2])
55
 
56
  with col1:
57
+ if st.button("Simulate Normal"):
58
+ generate_sample(False)
59
+ if st.button("Simulate Fraud"):
60
+ generate_sample(True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
+ with st.form("form"):
63
+ t_time = st.slider("Time",0.0,172800.0,key="t_time")
64
+ t_amount = st.slider("Amount",0.0,5000.0,key="t_amount")
65
+
66
+ v_data = {}
67
+ for i in range(1,29):
68
+ v_data[f"V{i}"] = st.number_input(f"V{i}",key=f"v_{i}")
69
 
70
+ threshold = st.slider("Threshold",0.05,0.95,0.15)
71
+ submit = st.form_submit_button("Predict")
72
+
73
+ with col2:
74
+ if submit:
75
+ payload = {"Time":st.session_state.t_time,"Amount":st.session_state.t_amount,**v_data}
76
  try:
77
+ res = requests.post(API_URL,json=payload).json()
78
+ prob = res["fraud_probability"]
79
+ pred = 1 if prob>threshold else 0
80
+
81
+ if pred:
82
+ st.error("๐Ÿšจ FRAUD")
 
 
 
83
  else:
84
+ st.success("โœ… SAFE")
85
+
86
+ st.metric("Risk",f"{prob:.4%}")
 
 
 
87
  st.progress(float(prob))
88
+
89
+ # ๐Ÿ”ฅ Store payload for SHAP page
90
+ st.session_state["last_payload"] = payload
91
+
92
+ except Exception as e:
93
+ st.error(e)
94
+
95
+
96
+ # =========================
97
+ # ๐Ÿ”น SHAP PAGE (SEPARATE)
98
+ # =========================
99
+ elif page == "Explainability (SHAP)":
100
+
101
+ st.title("๐Ÿง  Explainable AI (SHAP)")
102
+
103
+ if "last_payload" not in st.session_state:
104
+ st.warning("Run prediction first")
105
+ else:
106
+ if st.button("Generate SHAP Explanation"):
107
+ try:
108
+ payload = st.session_state["last_payload"]
109
+
110
+ input_df = pd.DataFrame([payload])
111
+
112
+ pipeline = PredictPipeline()
113
+ processed = pipeline.preprocess(input_df)
114
+
115
+ explainer = ShapExplainer()
116
+ shap_values = explainer.explain(processed)
117
+
118
+ fig, ax = plt.subplots(figsize=(8,4))
119
  shap.plots.waterfall(shap_values[0], show=False)
120
  st.pyplot(fig)
121
 
122
  except Exception as e:
123
+ st.error(e)
124
 
125
+
126
+ # =========================
127
+ # ๐Ÿ”น DRIFT PAGE (UNCHANGED)
128
+ # =========================
129
  elif page == "Drift Monitoring":
130
+
131
+ st.title("๐Ÿ“‰ Drift Monitoring")
132
+
133
+ if st.button("Inject Drift"):
134
+ for _ in range(50):
135
+ data={"Time":random.uniform(10,50000),"Amount":random.uniform(1000,5000)}
136
+ for i in range(1,29):
137
+ data[f"V{i}"]=random.uniform(-15,15)
138
+ save_to_db(data,1,0.99)
139
+ st.success("Injected")
 
 
 
 
 
140
 
141
  try:
142
  from src.monitoring.drift import detect_drift
143
  from src.pipeline.retrain_pipeline import retrain
144
  except:
145
+ st.error("Not supported")
146
  st.stop()
147
 
148
+ if st.button("Run Drift"):
149
+ detect_drift("data/creditcard.csv")
150
+ st.success("Done")
151
+
152
+ if st.button("Retrain"):
153
+ retrain()
154
+ st.success("Retrained")