sheltonmaharesh commited on
Commit
0d5ae83
·
verified ·
1 Parent(s): e02d4ae

Deploy backend Flask app

Browse files
Files changed (1) hide show
  1. bot_detector_api.py +15 -22
bot_detector_api.py CHANGED
@@ -1,19 +1,18 @@
1
  import numpy as np
2
- import pandas as pd
3
  import joblib
 
4
  import shap
5
  from flask import Flask, request, jsonify
6
  from urllib.parse import urlparse, parse_qs
7
 
8
- # Initialize Flask
9
  app = Flask("Bot detector")
10
 
11
- # Health check
12
  @app.get('/')
13
  def home():
14
  return "✅ Welcome to the Bot Prediction API!"
15
 
16
- # Load models and utilities
17
  model = joblib.load("model.joblib")
18
  encoders = joblib.load("encoders.joblib")
19
  scaler = joblib.load("scaler.joblib")
@@ -21,7 +20,7 @@ if_model = joblib.load("best_if_model.joblib")
21
  svm_model = joblib.load("best_svm_model.joblib")
22
  feature_names = joblib.load("feature_names.joblib")
23
 
24
- # Initialize SHAP explainer
25
  explainer = shap.TreeExplainer(model)
26
 
27
  def parse_url_params(url):
@@ -70,7 +69,6 @@ def prepare_features(row_dict):
70
  return df[feature_names]
71
 
72
  def generate_shap_bot_attack_paragraph(index, shap_values, X, encoders=None, class_index=1, top_n=10):
73
- # Handle both single-output and multi-output SHAP format
74
  if isinstance(shap_values, list) and len(shap_values) > class_index:
75
  shap_vals = shap_values[class_index][index]
76
  base_val = explainer.expected_value[class_index]
@@ -81,16 +79,17 @@ def generate_shap_bot_attack_paragraph(index, shap_values, X, encoders=None, cla
81
  x_vals = X.iloc[index]
82
  feature_names = X.columns
83
 
84
- # Decode readable values
85
  decoded_vals = {}
86
  for col in feature_names:
87
  val = x_vals[col]
88
  try:
89
  if encoders and col in encoders:
 
 
90
  decoded_vals[col] = encoders[col].inverse_transform([int(val)])[0]
91
  else:
92
  decoded_vals[col] = val
93
- except:
94
  decoded_vals[col] = val
95
 
96
  feature_contribs = list(zip(feature_names, decoded_vals.values(), shap_vals))
@@ -98,6 +97,7 @@ def generate_shap_bot_attack_paragraph(index, shap_values, X, encoders=None, cla
98
 
99
  positive_impacts = []
100
  negative_impacts = []
 
101
  for fname, fval, sval in feature_contribs:
102
  line = f" • {fname} = {fval} (contributed {abs(sval):.4f})"
103
  if sval > 0:
@@ -105,26 +105,20 @@ def generate_shap_bot_attack_paragraph(index, shap_values, X, encoders=None, cla
105
  elif sval < 0:
106
  negative_impacts.append(line)
107
 
108
- def sigmoid(x):
109
- return 1 / (1 + np.exp(-x))
110
-
111
  final_log_odds = base_val + np.sum(shap_vals)
112
  final_pred_prob = sigmoid(final_log_odds)
113
 
114
- # Build paragraph-style explanation
115
  paragraph = f"🧠 **SHAP Explanation for Anomaly Classification**\n\n"
116
- paragraph += f"- The model starts with a baseline (SHAP base value) of **{base_val:.4f}**, representing the initial log-odds for class 1 (anomaly).\n"
117
- paragraph += f"- After considering all features, the final predicted probability of this session being an anomaly is **{final_pred_prob:.4f}**.\n\n"
118
 
119
  if positive_impacts:
120
- paragraph += "**🔺 Features that increased anomaly likelihood:**\n"
121
- paragraph += "\n".join(positive_impacts) + "\n\n"
122
-
123
  if negative_impacts:
124
- paragraph += "**🔻 Features that decreased anomaly likelihood:**\n"
125
- paragraph += "\n".join(negative_impacts) + "\n\n"
126
 
127
- paragraph += "These top features collectively influenced the model’s final prediction."
128
  return paragraph
129
 
130
  @app.post('/v1/predict')
@@ -136,14 +130,13 @@ def predict():
136
  pred_prob = float(pred_probs[0][1])
137
  pred_label = int(pred_prob >= 0.5)
138
 
139
- # SHAP Explanation
140
  shap_values = explainer.shap_values(X)
141
  explanation = generate_shap_bot_attack_paragraph(0, shap_values, X, encoders)
142
 
143
  return jsonify({
144
  "Prediction": "Bot Attack" if pred_label else "Legitimate",
145
- "Bot Probability": round(pred_prob, 4),
146
  "SHAP Explanation": explanation
147
  })
 
148
  except Exception as e:
149
  return jsonify({"error": str(e)}), 500
 
1
  import numpy as np
 
2
  import joblib
3
+ import pandas as pd
4
  import shap
5
  from flask import Flask, request, jsonify
6
  from urllib.parse import urlparse, parse_qs
7
 
8
+ # Initialize Flask app
9
  app = Flask("Bot detector")
10
 
 
11
  @app.get('/')
12
  def home():
13
  return "✅ Welcome to the Bot Prediction API!"
14
 
15
+ # Load models and artifacts
16
  model = joblib.load("model.joblib")
17
  encoders = joblib.load("encoders.joblib")
18
  scaler = joblib.load("scaler.joblib")
 
20
  svm_model = joblib.load("best_svm_model.joblib")
21
  feature_names = joblib.load("feature_names.joblib")
22
 
23
+ # SHAP explainer
24
  explainer = shap.TreeExplainer(model)
25
 
26
  def parse_url_params(url):
 
69
  return df[feature_names]
70
 
71
  def generate_shap_bot_attack_paragraph(index, shap_values, X, encoders=None, class_index=1, top_n=10):
 
72
  if isinstance(shap_values, list) and len(shap_values) > class_index:
73
  shap_vals = shap_values[class_index][index]
74
  base_val = explainer.expected_value[class_index]
 
79
  x_vals = X.iloc[index]
80
  feature_names = X.columns
81
 
 
82
  decoded_vals = {}
83
  for col in feature_names:
84
  val = x_vals[col]
85
  try:
86
  if encoders and col in encoders:
87
+ if isinstance(val, (np.ndarray, list)):
88
+ val = val[0]
89
  decoded_vals[col] = encoders[col].inverse_transform([int(val)])[0]
90
  else:
91
  decoded_vals[col] = val
92
+ except Exception:
93
  decoded_vals[col] = val
94
 
95
  feature_contribs = list(zip(feature_names, decoded_vals.values(), shap_vals))
 
97
 
98
  positive_impacts = []
99
  negative_impacts = []
100
+
101
  for fname, fval, sval in feature_contribs:
102
  line = f" • {fname} = {fval} (contributed {abs(sval):.4f})"
103
  if sval > 0:
 
105
  elif sval < 0:
106
  negative_impacts.append(line)
107
 
108
+ def sigmoid(x): return 1 / (1 + np.exp(-x))
 
 
109
  final_log_odds = base_val + np.sum(shap_vals)
110
  final_pred_prob = sigmoid(final_log_odds)
111
 
 
112
  paragraph = f"🧠 **SHAP Explanation for Anomaly Classification**\n\n"
113
+ paragraph += f"- SHAP base value (log-odds for class 1): **{base_val:.4f}**\n"
114
+ paragraph += f"- Final predicted probability (Anomaly): **{final_pred_prob:.4f}**\n\n"
115
 
116
  if positive_impacts:
117
+ paragraph += "**🔺 Features that increased anomaly likelihood:**\n" + "\n".join(positive_impacts) + "\n\n"
 
 
118
  if negative_impacts:
119
+ paragraph += "**🔻 Features that decreased anomaly likelihood:**\n" + "\n".join(negative_impacts) + "\n\n"
 
120
 
121
+ paragraph += "These top features collectively influenced the model’s decision."
122
  return paragraph
123
 
124
  @app.post('/v1/predict')
 
130
  pred_prob = float(pred_probs[0][1])
131
  pred_label = int(pred_prob >= 0.5)
132
 
 
133
  shap_values = explainer.shap_values(X)
134
  explanation = generate_shap_bot_attack_paragraph(0, shap_values, X, encoders)
135
 
136
  return jsonify({
137
  "Prediction": "Bot Attack" if pred_label else "Legitimate",
 
138
  "SHAP Explanation": explanation
139
  })
140
+
141
  except Exception as e:
142
  return jsonify({"error": str(e)}), 500