fikri0o0 commited on
Commit
d5cc4ff
·
verified ·
1 Parent(s): 13769e9

2026-06-05: UX polish — cleaner intro, distance slider, remove redundant button

Browse files
Files changed (1) hide show
  1. app.py +27 -23
app.py CHANGED
@@ -152,8 +152,7 @@ def _load_live():
152
  _LIVE["explainer"] = None
153
 
154
 
155
- def score_transaction(amt, category, hour, gender, state, home_lat, home_long,
156
- merch_lat, merch_long, city_pop, age_years):
157
  if not config.LGBM_MODEL.exists():
158
  return "Run training first.", None
159
  _load_live()
@@ -164,12 +163,18 @@ def score_transaction(amt, category, hour, gender, state, home_lat, home_long,
164
  unix_t = base.timestamp()
165
  dob = (base - dt.timedelta(days=int(age_years * 365.25))).strftime("%Y-%m-%d")
166
 
 
 
 
 
 
 
167
  txn = {
168
  "cc_num": 9999999999999999, "amt": float(amt), "unix_time": unix_t,
169
  "merchant": "demo_merchant", "category": category, "gender": gender,
170
- "state": state, "lat": float(home_lat), "long": float(home_long),
171
- "merch_lat": float(merch_lat), "merch_long": float(merch_long),
172
- "city_pop": float(city_pop), "dob": dob,
173
  }
174
 
175
  t0 = time.perf_counter()
@@ -231,7 +236,7 @@ def warmup_live_scoring():
231
  """
232
  try:
233
  _load_live()
234
- score_transaction(100, "shopping_net", 12, "F", "NY", 40.71, -74.0, 40.0, -74.0, 1000, 35)
235
  from src.online import OnlineFeatureStore
236
  _LIVE["store"] = OnlineFeatureStore()
237
  print("[warmup] live scoring + SHAP ready")
@@ -415,10 +420,13 @@ On **Sparkov** (strong engineered features) cost-sensitive weighting *dominates*
415
  _DESC = """
416
  # 🛡️ Real-Time Credit Card Fraud Detection
417
 
418
- End-to-end fraud system on the **Sparkov** dataset (1.85M transactions, ~0.5% fraud):
419
- rich feature engineering, an honest imbalance study, three modelling approaches
420
- (**LightGBM · GraphSAGE GNN · Autoencoder**), SHAP explainability, concept-drift
421
- monitoring, and a real-time scoring service.
 
 
 
422
  """
423
 
424
  with gr.Blocks(title="Fraud Detection",
@@ -427,17 +435,17 @@ with gr.Blocks(title="Fraud Detection",
427
  gr.Markdown(_DESC)
428
 
429
  with gr.Tab("1. Model Performance"):
430
- b1 = gr.Button("Load results", variant="primary")
431
  with gr.Row():
432
  p1 = gr.Plot()
433
  p2 = gr.Plot()
434
  md1 = gr.Markdown()
435
- b1.click(performance_view, outputs=[p1, p2, md1], scroll_to_output=False)
436
  demo.load(performance_view, outputs=[p1, p2, md1])
437
 
438
  with gr.Tab("2. Live Scoring"):
439
- gr.Markdown("### Score a transaction in real time\nAdjust the inputs and click Score. "
440
- "Score several in a row to build up the card's velocity history.")
 
 
441
  with gr.Row():
442
  with gr.Column():
443
  amt = gr.Slider(1, 5000, value=850, label="Amount ($)")
@@ -446,23 +454,19 @@ with gr.Blocks(title="Fraud Detection",
446
  "shopping_pos", "entertainment", "food_dining", "health_fitness",
447
  "travel", "kids_pets", "home", "personal_care"],
448
  value="shopping_net", label="Category")
449
- hour = gr.Slider(0, 23, value=2, step=1, label="Hour of day (0-23)")
 
 
 
450
  gender = gr.Dropdown(["F", "M"], value="F", label="Gender")
451
  state = gr.Dropdown(["NY", "CA", "TX", "FL", "PA", "OH", "IL"],
452
  value="NY", label="State")
453
- with gr.Column():
454
- home_lat = gr.Number(value=40.71, label="Cardholder home lat")
455
- home_long = gr.Number(value=-74.0, label="Cardholder home long")
456
- merch_lat = gr.Number(value=36.0, label="Merchant lat")
457
- merch_long = gr.Number(value=-90.0, label="Merchant long")
458
- city_pop = gr.Number(value=1000000, label="City population")
459
  age_years = gr.Slider(18, 90, value=35, step=1, label="Cardholder age")
460
  sbtn = gr.Button("Score Transaction", variant="primary")
461
  smd = gr.Markdown()
462
  splot = gr.Plot()
463
  sbtn.click(score_transaction,
464
- inputs=[amt, category, hour, gender, state, home_lat, home_long,
465
- merch_lat, merch_long, city_pop, age_years],
466
  outputs=[smd, splot], scroll_to_output=False)
467
 
468
  with gr.Tab("3. Explainability"):
 
152
  _LIVE["explainer"] = None
153
 
154
 
155
+ def score_transaction(amt, category, hour, distance_km, gender, state, age_years):
 
156
  if not config.LGBM_MODEL.exists():
157
  return "Run training first.", None
158
  _load_live()
 
163
  unix_t = base.timestamp()
164
  dob = (base - dt.timedelta(days=int(age_years * 365.25))).strftime("%Y-%m-%d")
165
 
166
+ # Place the merchant `distance_km` away from a fixed home location, so the
167
+ # user controls the geo-distance signal directly without typing coordinates.
168
+ home_lat, home_long = 40.71, -74.0 # fixed demo "home" (New York)
169
+ merch_lat = home_lat
170
+ merch_long = home_long + float(distance_km) / 85.0 # ~85 km per lon-degree at 40N
171
+
172
  txn = {
173
  "cc_num": 9999999999999999, "amt": float(amt), "unix_time": unix_t,
174
  "merchant": "demo_merchant", "category": category, "gender": gender,
175
+ "state": state, "lat": home_lat, "long": home_long,
176
+ "merch_lat": merch_lat, "merch_long": merch_long,
177
+ "city_pop": 500000.0, "dob": dob,
178
  }
179
 
180
  t0 = time.perf_counter()
 
236
  """
237
  try:
238
  _load_live()
239
+ score_transaction(100, "shopping_net", 12, 50, "F", "NY", 35)
240
  from src.online import OnlineFeatureStore
241
  _LIVE["store"] = OnlineFeatureStore()
242
  print("[warmup] live scoring + SHAP ready")
 
420
  _DESC = """
421
  # 🛡️ Real-Time Credit Card Fraud Detection
422
 
423
+ An end-to-end fraud system on the **Sparkov** dataset (1.85M transactions, ~0.5% fraud).
424
+
425
+ - **Model** — LightGBM (PR-AUC **0.97**) · plus a GraphSAGE GNN and an autoencoder baseline
426
+ - **Honest evaluation** — PR-AUC, cost-optimal thresholds, an imbalance study + real-data validation
427
+ - **Production-shaped** — leakage-safe features, SHAP explanations, drift monitoring, ~10 ms scoring
428
+
429
+ 👉 **Try it:** open the **Live Scoring** tab, set an amount / time / distance, and click *Score*.
430
  """
431
 
432
  with gr.Blocks(title="Fraud Detection",
 
435
  gr.Markdown(_DESC)
436
 
437
  with gr.Tab("1. Model Performance"):
 
438
  with gr.Row():
439
  p1 = gr.Plot()
440
  p2 = gr.Plot()
441
  md1 = gr.Markdown()
 
442
  demo.load(performance_view, outputs=[p1, p2, md1])
443
 
444
  with gr.Tab("2. Live Scoring"):
445
+ gr.Markdown("### Score a transaction in real time\n"
446
+ "Set the transaction details and click **Score**. Fraud rises with a high "
447
+ "amount, a late hour, and a large distance from home. Score several in a "
448
+ "row to build up the card's velocity history and watch the risk climb.")
449
  with gr.Row():
450
  with gr.Column():
451
  amt = gr.Slider(1, 5000, value=850, label="Amount ($)")
 
454
  "shopping_pos", "entertainment", "food_dining", "health_fitness",
455
  "travel", "kids_pets", "home", "personal_care"],
456
  value="shopping_net", label="Category")
457
+ hour = gr.Slider(0, 23, value=2, step=1, label="Hour of day (0 = midnight)")
458
+ distance_km = gr.Slider(0, 3000, value=600, step=10,
459
+ label="Distance from cardholder's home (km)")
460
+ with gr.Column():
461
  gender = gr.Dropdown(["F", "M"], value="F", label="Gender")
462
  state = gr.Dropdown(["NY", "CA", "TX", "FL", "PA", "OH", "IL"],
463
  value="NY", label="State")
 
 
 
 
 
 
464
  age_years = gr.Slider(18, 90, value=35, step=1, label="Cardholder age")
465
  sbtn = gr.Button("Score Transaction", variant="primary")
466
  smd = gr.Markdown()
467
  splot = gr.Plot()
468
  sbtn.click(score_transaction,
469
+ inputs=[amt, category, hour, distance_km, gender, state, age_years],
 
470
  outputs=[smd, splot], scroll_to_output=False)
471
 
472
  with gr.Tab("3. Explainability"):