sheltonmaharesh commited on
Commit
488e534
·
verified ·
1 Parent(s): 20068d5

Deploy backend Flask app

Browse files
Files changed (1) hide show
  1. bot_detector_api.py +33 -25
bot_detector_api.py CHANGED
@@ -13,7 +13,7 @@ app = Flask("Bot detector")
13
  def home():
14
  return "✅ Welcome to the Bot Prediction API!"
15
 
16
- # Load models and artifacts
17
  model = joblib.load("model.joblib")
18
  encoders = joblib.load("encoders.joblib")
19
  scaler = joblib.load("scaler.joblib")
@@ -58,24 +58,31 @@ def prepare_features(row_dict):
58
  df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0)
59
 
60
  df_scaled = scaler.transform(df)
61
- iso_score = if_model.decision_function(df_scaled)
62
- svm_score = svm_model.decision_function(df_scaled)
63
 
64
- iso_prob = float(1 - iso_scaler.transform(iso_score.reshape(-1, 1))[0][0])
65
- svm_prob = float(1 - svm_scaler.transform(svm_score.reshape(-1, 1))[0][0])
 
 
 
66
 
67
  df['iso_anomaly_prob'] = iso_prob
68
  df['svm_anomaly_prob'] = svm_prob
69
 
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
- shap_vals = shap_values.values[index, :, class_index]
74
- base_val = shap_values.base_values[index, class_index]
 
 
 
 
 
 
 
75
  x_vals = X.iloc[index]
76
  feature_names = X.columns
77
 
78
- # Decode encoded values
79
  decoded_vals = {}
80
  for col in feature_names:
81
  val = x_vals[col]
@@ -87,51 +94,52 @@ def generate_shap_bot_attack_paragraph(index, shap_values, X, encoders=None, cla
87
  except:
88
  decoded_vals[col] = val
89
 
90
- feature_contribs = list(zip(feature_names, decoded_vals.values(), shap_vals))
91
  feature_contribs = sorted(feature_contribs, key=lambda x: abs(x[2]), reverse=True)[:top_n]
92
 
93
  positive_impacts = []
94
  negative_impacts = []
95
 
96
  for fname, fval, sval in feature_contribs:
97
- line = f" - {fname:20} = {str(fval):<20} contributed {abs(sval):.4f}"
98
  if sval > 0:
99
  positive_impacts.append(line)
100
  elif sval < 0:
101
  negative_impacts.append(line)
102
 
103
- final_pred_val = base_val + np.sum(shap_vals)
104
 
105
- explanation = f"\n==== SHAP Explanation for Bot Attack Classification ====\n"
106
- explanation += f"Base model prediction for class 1 (Bot Attack): {base_val:.4f}\n"
107
- explanation += f"Final model output for this instance : {final_pred_val:.4f}\n\n"
108
 
109
  if positive_impacts:
110
- explanation += "🔺 Factors that INCREASED the likelihood of Bot Attack:\n" + "\n".join(positive_impacts) + "\n\n"
111
 
112
  if negative_impacts:
113
- explanation += "🔻 Factors that DECREASED the likelihood of Bot Attack:\n" + "\n".join(negative_impacts) + "\n\n"
114
 
115
- explanation += "📝 These features collectively explain the model's classification of this session.\n"
116
- return explanation
117
 
118
  @app.post('/v1/predict')
119
  def predict():
120
  try:
121
  row = request.get_json()
122
  X = prepare_features(row)
123
- probs = model.predict_proba(X)[0]
124
- pred_label = model.classes_[np.argmax(probs)]
125
 
126
- shap_values = explainer(X)
127
- explanation = generate_shap_bot_attack_paragraph(0, shap_values, X, encoders)
128
 
129
  return jsonify({
130
- "Prediction": "Bot Attack" if pred_label == 1 else "Legitimate",
 
 
131
  "SHAP Explanation": explanation
132
  })
133
 
134
  except Exception as e:
135
  traceback.print_exc()
136
  return jsonify({"error": str(e)}), 500
137
-
 
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")
 
58
  df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0)
59
 
60
  df_scaled = scaler.transform(df)
 
 
61
 
62
+ iso_score = if_model.decision_function(df_scaled).reshape(-1, 1)
63
+ svm_score = svm_model.decision_function(df_scaled).reshape(-1, 1)
64
+
65
+ iso_prob = 1 - iso_scaler.transform(iso_score)[0][0]
66
+ svm_prob = 1 - svm_scaler.transform(svm_score)[0][0]
67
 
68
  df['iso_anomaly_prob'] = iso_prob
69
  df['svm_anomaly_prob'] = svm_prob
70
 
71
  return df[feature_names]
72
 
73
+ def generate_shap_explanation(index, shap_values, X, encoders=None, class_index=1, top_n=10):
74
+ if isinstance(shap_values, list):
75
+ shap_vals = shap_values[class_index][index]
76
+ base_val = explainer.expected_value[class_index]
77
+ else:
78
+ shap_vals = shap_values[index]
79
+ base_val = explainer.expected_value if np.isscalar(explainer.expected_value) else explainer.expected_value[class_index]
80
+
81
+ shap_scalar_vals = [float(s[0]) if isinstance(s, np.ndarray) else float(s) for s in shap_vals]
82
+
83
  x_vals = X.iloc[index]
84
  feature_names = X.columns
85
 
 
86
  decoded_vals = {}
87
  for col in feature_names:
88
  val = x_vals[col]
 
94
  except:
95
  decoded_vals[col] = val
96
 
97
+ feature_contribs = list(zip(feature_names, decoded_vals.values(), shap_scalar_vals))
98
  feature_contribs = sorted(feature_contribs, key=lambda x: abs(x[2]), reverse=True)[:top_n]
99
 
100
  positive_impacts = []
101
  negative_impacts = []
102
 
103
  for fname, fval, sval in feature_contribs:
104
+ line = f" - {fname:20} = {str(fval):<25} contributed {sval:+.4f}"
105
  if sval > 0:
106
  positive_impacts.append(line)
107
  elif sval < 0:
108
  negative_impacts.append(line)
109
 
110
+ final_log_odds = base_val + sum(shap_scalar_vals)
111
 
112
+ explanation = f"==== SHAP Explanation for Bot Attack Classification ====\n\n"
113
+ explanation += f"Base value (log-odds for class 1) : {base_val:.4f}\n"
114
+ explanation += f"Predicted log-odds (class 1) : {final_log_odds:.4f}\n\n"
115
 
116
  if positive_impacts:
117
+ explanation += "🔺 Factors that INCREASED Bot Likelihood:\n" + "\n".join(positive_impacts) + "\n\n"
118
 
119
  if negative_impacts:
120
+ explanation += "🔻 Factors that DECREASED Bot Likelihood:\n" + "\n".join(negative_impacts) + "\n\n"
121
 
122
+ explanation += "📝 These features collectively explain the model's decision.\n"
123
+ return explanation, base_val, final_log_odds
124
 
125
  @app.post('/v1/predict')
126
  def predict():
127
  try:
128
  row = request.get_json()
129
  X = prepare_features(row)
130
+ pred_prob = model.predict_proba(X)[0][1]
131
+ pred_label = int(pred_prob >= 0.5)
132
 
133
+ shap_values = explainer.shap_values(X)
134
+ explanation, base_val, final_log_odds = generate_shap_explanation(0, shap_values, X, encoders)
135
 
136
  return jsonify({
137
+ "Prediction": "Bot Attack" if pred_label else "Legitimate",
138
+ "SHAP Base Value": round(base_val, 4),
139
+ "SHAP Predicted Value": round(final_log_odds, 4),
140
  "SHAP Explanation": explanation
141
  })
142
 
143
  except Exception as e:
144
  traceback.print_exc()
145
  return jsonify({"error": str(e)}), 500