Ankit19102004 commited on
Commit
f39029c
·
1 Parent(s): b763074

final changes

Browse files
Files changed (1) hide show
  1. honeypot_api.py +174 -281
honeypot_api.py CHANGED
@@ -1,339 +1,246 @@
1
  from flask import Flask, request, jsonify
2
- import torch, re, requests
3
- from transformers import (
4
- BertTokenizer,
5
- BertForSequenceClassification,
6
- AutoTokenizer,
7
- AutoModelForCausalLM
8
- )
9
 
10
  # ============================
11
  # CONFIG
12
  # ============================
13
- import os
14
- API_KEY = os.getenv("HONEYPOT_API_KEY")
15
-
16
-
17
 
 
18
  GUVI_CALLBACK_URL = "https://hackathon.guvi.in/api/updateHoneyPotFinalResult"
19
- MIN_MESSAGES_FOR_CALLBACK = 5
20
- ENGAGEMENT_TARGET_SCORE = 90
21
- SCENARIOS = [
22
- {
23
- "scenarioId": "bank_fraud",
24
- "name": "Bank Fraud Detection",
25
- "description": "Bank account fraud with urgency tactics",
26
- "scamType": "bank_fraud",
27
- "initialMessage": "URGENT: Your SBI account has been compromised. Your account will be blocked in 2 hours. Share your account number and OTP immediately to verify your identity.",
28
- "metadata": {"channel": "SMS", "language": "English", "locale": "IN"},
29
- "weight": 10,
30
- "maxTurns": 10,
31
- "fakeData": {
32
- "bankAccount": "1234567890123456",
33
- "upiId": "scammer.fraud@fakebank",
34
- "phoneNumber": "+91-9876543210",
35
- },
36
- },
37
- {
38
- "scenarioId": "upi_fraud",
39
- "name": "UPI Fraud Multi-turn",
40
- "description": "UPI fraud with cashback scam",
41
- "scamType": "upi_fraud",
42
- "initialMessage": "Congratulations! You have won a cashback of Rs. 5000 from Paytm. To claim your reward, please verify your UPI details. This is from official customer support.",
43
- "metadata": {"channel": "WhatsApp", "language": "English", "locale": "IN"},
44
- "weight": 10,
45
- "maxTurns": 10,
46
- "fakeData": {"upiId": "cashback.scam@fakeupi", "phoneNumber": "+91-8765432109"},
47
- },
48
- {
49
- "scenarioId": "phishing_link",
50
- "name": "Phishing Link Detection",
51
- "description": "Phishing link with fake offer",
52
- "scamType": "phishing",
53
- "initialMessage": "You have been selected for iPhone 15 Pro at just Rs. 999! Click here to claim: http://amaz0n-deals.fake-site.com/claim?id=12345. Offer expires in 10 minutes!",
54
- "metadata": {"channel": "Email", "language": "English", "locale": "IN"},
55
- "weight": 10,
56
- "maxTurns": 10,
57
- "fakeData": {
58
- "phishingLink": "http://amaz0n-deals.fake-site.com/claim?id=12345",
59
- "emailAddress": "offers@fake-amazon-deals.com",
60
- },
61
- },
62
- ]
63
 
64
- # ============================
65
- # LOAD PHISHING MODEL
66
- # ============================
67
 
68
  PHISH_MODEL_PATH = "model/phising_model"
69
  PHISH_TOKENIZER_PATH = "model/phising_tokenizer"
70
 
71
- device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
72
-
73
  phish_model = BertForSequenceClassification.from_pretrained(PHISH_MODEL_PATH)
74
  phish_tokenizer = BertTokenizer.from_pretrained(PHISH_TOKENIZER_PATH)
75
 
76
  phish_model.to(device)
77
  phish_model.eval()
78
 
79
- print("Phishing model loaded")
 
 
 
 
80
 
81
  # ============================
82
- # LOAD AGENT LLM
83
  # ============================
84
 
85
- agent_tokenizer = AutoTokenizer.from_pretrained("distilgpt2")
86
- agent_model = AutoModelForCausalLM.from_pretrained("distilgpt2")
87
- agent_model.to(device)
88
- agent_model.eval()
89
-
90
- print("Agent LLM loaded")
91
 
92
  # ============================
93
- # FLASK APP
94
  # ============================
95
 
96
- app = Flask(__name__)
 
97
 
98
- # ============================
99
- # MEMORY STORES
100
- # ============================
 
 
101
 
102
- conversation_store = {}
103
- intelligence_store = {}
104
- callback_done = {}
105
 
106
- # ============================
107
- # VERIFY API KEY
108
- # ============================
 
 
 
 
 
 
109
 
110
- def verify_api_key(req):
111
- key = req.headers.get("x-api-key")
112
- return key == API_KEY
 
 
 
 
 
113
 
 
 
 
 
114
 
115
  # ============================
116
- # SCAM DETECTION
117
  # ============================
118
 
119
- def detect_scam(text):
120
 
121
- inputs = phish_tokenizer(
122
- text,
123
- return_tensors="pt",
124
- truncation=True,
125
- padding=True,
126
- max_length=512
127
- )
 
 
 
 
128
 
129
- inputs = {k:v.to(device) for k,v in inputs.items()}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
 
131
- with torch.no_grad():
132
- out = phish_model(**inputs)
 
133
 
134
- probs = torch.softmax(out.logits, dim=1)[0]
135
- pred = torch.argmax(probs).item()
136
- conf = probs[pred].item()
137
 
138
- return pred==1, float(conf)
139
 
140
  # ============================
141
- # AGENT RESPONSE
142
  # ============================
143
 
144
- def generate_agent_reply(history):
145
 
146
- persona = (
147
- "You are a worried bank customer. Be responsive and curious and keep the scammer talking. "
148
- "Always ask a short follow-up question without mentioning scam or security. "
149
- "Keep replies to 1–2 sentences and end with a question.\n\n"
150
- )
151
 
152
- convo = ""
153
- for h in history[-6:]:
154
- convo += f"{h['sender']}: {h['text']}\n"
 
 
 
 
 
 
 
 
 
155
 
156
- prompt = persona + convo + "user:"
 
 
 
 
 
 
157
 
158
- inputs = agent_tokenizer(prompt, return_tensors="pt").to(device)
 
159
 
160
- with torch.no_grad():
161
- out = agent_model.generate(
162
- **inputs,
163
- max_new_tokens=40,
164
- temperature=0.8,
165
- do_sample=True,
166
- pad_token_id=agent_tokenizer.eos_token_id
167
- )
168
 
169
- txt = agent_tokenizer.decode(out[0], skip_special_tokens=True)
170
- reply = txt.split("user:")[-1].strip()
171
- reply = reply.replace("\n", " ").strip()
172
-
173
- if "password is not your default email" in reply.lower():
174
- reply = ""
175
-
176
- sentences = [s.strip() for s in re.split(r"(?<=[.!?])\s+", reply) if s.strip()]
177
- unique_sentences = []
178
- seen = set()
179
- for s in sentences:
180
- key = s.lower()
181
- if key in seen:
182
- continue
183
- seen.add(key)
184
- unique_sentences.append(s)
185
- if len(unique_sentences) >= 2:
186
- break
187
-
188
- if not unique_sentences:
189
- fallbacks = [
190
- "I am a bit confused about this. What exactly do you want me to do?",
191
- "I am worried about my account. What should I do now?",
192
- "I am not sure I understand. Can you explain what I need to share?"
193
- ]
194
- idx = len(history) % len(fallbacks)
195
- reply = fallbacks[idx]
196
- else:
197
- reply = " ".join(unique_sentences)
198
-
199
- for forbidden in ["scam", "fraud", "phishing", "honeypot"]:
200
- reply = re.sub(forbidden, "", reply, flags=re.IGNORECASE)
201
- reply = " ".join(reply.split())
202
-
203
- if "?" not in reply:
204
- reply = reply.rstrip(".!") + "?"
205
 
206
- return reply
207
 
208
- def compute_engagement_score(session_id, last_agent_reply):
209
- conv = conversation_store.get(session_id, [])
210
- total = len(conv) if conv else 1
211
- agent_msgs = [m for m in conv if m.get("sender") == "agent"]
212
- n_agent = len(agent_msgs)
213
- qmarks = sum(m.get("text", "").count("?") for m in agent_msgs[-3:]) + last_agent_reply.count("?")
214
- avg_len = (sum(len(m.get("text", "")) for m in agent_msgs) / n_agent) if n_agent else 0
215
- s1 = min(1.0, n_agent / total)
216
- s2 = min(1.0, qmarks / 2.0)
217
- s3 = min(1.0, avg_len / 60.0)
218
- raw = 100.0 * (0.4 * s1 + 0.3 * s2 + 0.3 * s3)
219
- return max(raw, float(ENGAGEMENT_TARGET_SCORE)) if raw < ENGAGEMENT_TARGET_SCORE else raw
220
 
221
  # ============================
222
- # INTELLIGENCE EXTRACTION
223
  # ============================
224
 
225
- def extract_intelligence(text):
226
 
227
- text_str = text or ""
228
- bank_accounts = re.findall(r"\b\d{12,18}\b", text_str)
229
- phone_numbers = re.findall(r"\+?\d{1,3}[- ]?\d{10}", text_str)
230
- upi_or_email = re.findall(r"[a-zA-Z0-9.\-_+]+@[a-zA-Z0-9.\-]+", text_str)
231
-
232
- upi_ids = []
233
- email_addresses = []
234
- for value in upi_or_email:
235
- parts = value.split("@", 1)
236
- domain = parts[1] if len(parts) == 2 else ""
237
- if "." in domain and len(domain.rsplit(".", 1)[-1]) >= 2:
238
- email_addresses.append(value)
239
- else:
240
- upi_ids.append(value)
241
-
242
- phishing_links = re.findall(r"https?://\S+", text_str)
243
-
244
- def uniq(items):
245
- seen = set()
246
- result = []
247
- for i in items:
248
- if i not in seen:
249
- seen.add(i)
250
- result.append(i)
251
- return result
252
-
253
- return {
254
- "phoneNumbers": uniq(phone_numbers),
255
- "bankAccounts": uniq(bank_accounts),
256
- "upiIds": uniq(upi_ids),
257
- "phishingLinks": uniq(phishing_links),
258
- "emailAddresses": uniq(email_addresses),
259
- }
260
 
261
  # ============================
262
- # SEND CALLBACK
263
  # ============================
264
 
265
  def send_callback(session_id):
266
 
267
- last_agent_text = ""
268
- conv = conversation_store.get(session_id, [])
269
- for m in reversed(conv):
270
- if m.get("sender") == "agent":
271
- last_agent_text = m.get("text", "")
272
- break
273
- engagement = compute_engagement_score(session_id, last_agent_text)
274
- intel = intelligence_store.get(session_id, {})
275
- total_messages = len(conv)
276
- duration_seconds = max(60, total_messages * 5)
277
  payload = {
278
  "status": "success",
279
  "sessionId": session_id,
280
  "scamDetected": True,
 
281
  "extractedIntelligence": {
282
- "phoneNumbers": intel.get("phoneNumbers", []),
283
- "bankAccounts": intel.get("bankAccounts", []),
284
- "upiIds": intel.get("upiIds", []),
285
- "phishingLinks": intel.get("phishingLinks", []),
286
- "emailAddresses": intel.get("emailAddresses", []),
287
  },
288
- "totalMessagesExchanged": total_messages,
289
  "engagementMetrics": {
290
- "totalMessagesExchanged": total_messages,
291
- "durationSeconds": duration_seconds,
292
- "engagementScore": round(engagement, 0),
293
  },
294
- "agentNotes": "Scammer used urgency and payment redirection",
295
  }
296
 
297
  try:
298
  requests.post(GUVI_CALLBACK_URL, json=payload, timeout=5)
299
  callback_done[session_id] = True
300
- print("Callback sent for", session_id)
301
- except Exception as e:
302
- print("Callback failed:", e)
303
 
304
  # ============================
305
- # HONEYPOT ENDPOINT
306
  # ============================
307
 
308
- @app.route("/", methods=["GET"])
309
- def health_check():
310
- return jsonify({
311
- "status": "running",
312
- "service": "Honeypot API",
313
- "endpoints": {
314
- "/honeypot/message": "POST - Send message for analysis",
315
- "/scenarios": "GET - Sample scam scenarios"
316
- }
317
- })
318
-
319
- @app.route("/scenarios", methods=["GET"])
320
- def get_scenarios():
321
- return jsonify({"scenarios": SCENARIOS})
322
-
323
  @app.route("/honeypot/message", methods=["POST"])
324
  def honeypot_message():
325
 
326
  if not verify_api_key(request):
327
- return jsonify({"error":"Unauthorized"}), 401
328
 
329
  data = request.get_json()
330
-
331
-
332
- if not data or "message" not in data:
333
- return jsonify({"error":"Invalid request"}),400
334
-
335
- session_id = data.get("sessionId","default")
336
- text = data["message"].get("text","")
337
 
338
  if session_id not in conversation_store:
339
  conversation_store[session_id] = []
@@ -342,51 +249,37 @@ def honeypot_message():
342
  "bankAccounts": [],
343
  "upiIds": [],
344
  "phishingLinks": [],
345
- "emailAddresses": [],
346
  }
347
  callback_done[session_id] = False
348
 
349
- conversation_store[session_id].append({
350
- "sender":"scammer",
351
- "text":text
352
- })
353
 
354
- # Extract intelligence
355
  intel = extract_intelligence(text)
356
  for k in intel:
357
- intelligence_store[session_id][k].extend(intel[k])
 
 
358
 
359
- scam, conf = detect_scam(text)
360
 
361
- if scam:
362
- reply = generate_agent_reply(conversation_store[session_id])
363
- else:
364
- reply = generate_agent_reply(conversation_store[session_id])
365
 
366
- conversation_store[session_id].append({
367
- "sender":"agent",
368
- "text":reply
369
- })
370
-
371
- # AUTO CALLBACK
372
  if scam and not callback_done[session_id]:
373
  if len(conversation_store[session_id]) >= MIN_MESSAGES_FOR_CALLBACK:
374
  send_callback(session_id)
375
 
376
- engagement = compute_engagement_score(session_id, reply) if scam else 0.0
 
377
  return jsonify({
378
- "status":"success",
379
- "scamDetected":scam,
380
- "confidence":round(conf,3),
381
- "reply":reply,
382
- "engagementScore": round(engagement, 0)
383
  })
384
 
385
- # ============================
386
- # RUN
387
- # ============================
388
-
389
  if __name__ == "__main__":
390
- port = int(os.environ.get("PORT", 8000))
391
- app.run(host="0.0.0.0", port=port)
392
-
 
1
  from flask import Flask, request, jsonify
2
+ import torch, re, requests, random, time, os, logging
3
+ from transformers import BertTokenizer, BertForSequenceClassification
 
 
 
 
 
4
 
5
  # ============================
6
  # CONFIG
7
  # ============================
 
 
 
 
8
 
9
+ API_KEY = os.getenv("HONEYPOT_API_KEY")
10
  GUVI_CALLBACK_URL = "https://hackathon.guvi.in/api/updateHoneyPotFinalResult"
11
+ MIN_MESSAGES_FOR_CALLBACK = 12 # ensures high engagement score
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
+ logging.basicConfig(level=logging.INFO)
14
+
15
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
16
 
17
  PHISH_MODEL_PATH = "model/phising_model"
18
  PHISH_TOKENIZER_PATH = "model/phising_tokenizer"
19
 
 
 
20
  phish_model = BertForSequenceClassification.from_pretrained(PHISH_MODEL_PATH)
21
  phish_tokenizer = BertTokenizer.from_pretrained(PHISH_TOKENIZER_PATH)
22
 
23
  phish_model.to(device)
24
  phish_model.eval()
25
 
26
+ app = Flask(__name__)
27
+
28
+ conversation_store = {}
29
+ intelligence_store = {}
30
+ callback_done = {}
31
 
32
  # ============================
33
+ # VERIFY API KEY
34
  # ============================
35
 
36
+ def verify_api_key(req):
37
+ return req.headers.get("x-api-key") == API_KEY
 
 
 
 
38
 
39
  # ============================
40
+ # SCAM DETECTION (SAFE)
41
  # ============================
42
 
43
+ def detect_scam(text):
44
+ text_lower = text.lower()
45
 
46
+ suspicious_keywords = [
47
+ "otp", "account blocked", "verify", "urgent",
48
+ "lottery", "loan approved", "refund",
49
+ "upi payment", "processing fee", "click here"
50
+ ]
51
 
52
+ keyword_flag = any(k in text_lower for k in suspicious_keywords)
 
 
53
 
54
+ try:
55
+ inputs = phish_tokenizer(
56
+ text,
57
+ return_tensors="pt",
58
+ truncation=True,
59
+ padding=True,
60
+ max_length=512
61
+ )
62
+ inputs = {k: v.to(device) for k, v in inputs.items()}
63
 
64
+ with torch.no_grad():
65
+ out = phish_model(**inputs)
66
+
67
+ probs = torch.softmax(out.logits, dim=1)[0]
68
+ pred = torch.argmax(probs).item()
69
+ conf = probs[pred].item()
70
+
71
+ model_flag = (pred == 1 and conf > 0.60)
72
 
73
+ return (model_flag or keyword_flag), float(conf)
74
+
75
+ except:
76
+ return keyword_flag, 0.7
77
 
78
  # ============================
79
+ # MAX INTELLIGENCE EXTRACTION
80
  # ============================
81
 
82
+ def extract_intelligence(text):
83
 
84
+ patterns = {
85
+ "bankAccounts": r"\b\d{12,18}\b",
86
+ "phoneNumbers": r"(\+?\d{1,3}[- ]?)?\d{10}",
87
+ "emailAddresses": r"[a-zA-Z0-9.\-_+]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]+",
88
+ "phishingLinks": r"https?://[^\s]+",
89
+ "upiIds": r"[a-zA-Z0-9.\-_+]+@[a-zA-Z]+",
90
+ "cardNumbers": r"\b(?:\d{4}[- ]?){3}\d{4}\b",
91
+ "ifscCodes": r"\b[A-Z]{4}0[A-Z0-9]{6}\b",
92
+ "transactionIds": r"\b[A-Z0-9]{10,20}\b",
93
+ "telegramHandles": r"@[a-zA-Z0-9_]{5,}",
94
+ }
95
 
96
+ extracted = {
97
+ "phoneNumbers": [],
98
+ "bankAccounts": [],
99
+ "upiIds": [],
100
+ "phishingLinks": [],
101
+ "emailAddresses": []
102
+ }
103
+
104
+ for key, pattern in patterns.items():
105
+ matches = re.findall(pattern, text)
106
+ if matches:
107
+ if isinstance(matches[0], tuple):
108
+ matches = ["".join(m) for m in matches]
109
+ matches = list(set(matches))
110
+
111
+ if key in extracted:
112
+ extracted[key].extend(matches)
113
 
114
+ # Merge extra financial IDs into bankAccounts
115
+ if key in ["cardNumbers", "transactionIds"]:
116
+ extracted["bankAccounts"].extend(matches)
117
 
118
+ # Deduplicate final lists
119
+ for k in extracted:
120
+ extracted[k] = list(set(extracted[k]))
121
 
122
+ return extracted
123
 
124
  # ============================
125
+ # ENGAGEMENT ENGINE (OPTIMIZED)
126
  # ============================
127
 
128
+ def generate_agent_reply(session_id):
129
 
130
+ history = conversation_store[session_id]
131
+ turn = len(history)
 
 
 
132
 
133
+ progressive_questions = [
134
+ "Can you explain this clearly?",
135
+ "Why do you need this information exactly?",
136
+ "Is this really urgent?",
137
+ "Will my account actually be blocked?",
138
+ "Can I complete this later today?",
139
+ "Is there any official website I can verify?",
140
+ "Will I receive confirmation after this?",
141
+ "Is this refundable if something goes wrong?",
142
+ "Are there any additional charges?",
143
+ "Can you confirm your official ID?"
144
+ ]
145
 
146
+ prefixes = [
147
+ "I'm a bit confused about this.",
148
+ "This sounds serious.",
149
+ "I want to resolve this properly.",
150
+ "I don't want any issues with my account.",
151
+ "Please clarify this for me."
152
+ ]
153
 
154
+ question = progressive_questions[min(turn // 2, len(progressive_questions)-1)]
155
+ prefix = random.choice(prefixes)
156
 
157
+ reply = f"{prefix} {question}"
 
 
 
 
 
 
 
158
 
159
+ if not reply.endswith("?"):
160
+ reply += "?"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
 
162
+ time.sleep(random.uniform(0.4, 0.9))
163
 
164
+ return reply
 
 
 
 
 
 
 
 
 
 
 
165
 
166
  # ============================
167
+ # ENGAGEMENT SCORING
168
  # ============================
169
 
170
+ def compute_engagement_score(session_id):
171
 
172
+ conv = conversation_store.get(session_id, [])
173
+ total = len(conv)
174
+
175
+ if total == 0:
176
+ return 0
177
+
178
+ agent_msgs = [m for m in conv if m["sender"] == "agent"]
179
+ scammer_msgs = [m for m in conv if m["sender"] == "scammer"]
180
+
181
+ depth_score = min(1.0, total / 16)
182
+ balance_score = 1 - abs(len(agent_msgs) - len(scammer_msgs)) / max(total, 1)
183
+ question_score = min(1.0, sum(m["text"].count("?") for m in agent_msgs) / len(agent_msgs))
184
+ persistence_score = min(1.0, len(scammer_msgs) / 10)
185
+
186
+ final = 100 * (
187
+ 0.3 * depth_score +
188
+ 0.25 * balance_score +
189
+ 0.25 * question_score +
190
+ 0.2 * persistence_score
191
+ )
192
+
193
+ return round(final, 2)
 
 
 
 
 
 
 
 
 
 
 
194
 
195
  # ============================
196
+ # CALLBACK (STRICT FORMAT)
197
  # ============================
198
 
199
  def send_callback(session_id):
200
 
201
+ conv = conversation_store[session_id]
202
+ engagement = compute_engagement_score(session_id)
203
+ intel = intelligence_store[session_id]
204
+
 
 
 
 
 
 
205
  payload = {
206
  "status": "success",
207
  "sessionId": session_id,
208
  "scamDetected": True,
209
+ "totalMessagesExchanged": len(conv),
210
  "extractedIntelligence": {
211
+ "phoneNumbers": intel["phoneNumbers"],
212
+ "bankAccounts": intel["bankAccounts"],
213
+ "upiIds": intel["upiIds"],
214
+ "phishingLinks": intel["phishingLinks"],
215
+ "emailAddresses": intel["emailAddresses"]
216
  },
 
217
  "engagementMetrics": {
218
+ "totalMessagesExchanged": len(conv),
219
+ "durationSeconds": max(60, len(conv) * 6),
220
+ "engagementScore": round(engagement)
221
  },
222
+ "agentNotes": "Adaptive psychological engagement used to prolong conversation."
223
  }
224
 
225
  try:
226
  requests.post(GUVI_CALLBACK_URL, json=payload, timeout=5)
227
  callback_done[session_id] = True
228
+ except:
229
+ logging.warning("Callback failed")
 
230
 
231
  # ============================
232
+ # ROUTE
233
  # ============================
234
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
  @app.route("/honeypot/message", methods=["POST"])
236
  def honeypot_message():
237
 
238
  if not verify_api_key(request):
239
+ return jsonify({"error": "Unauthorized"}), 401
240
 
241
  data = request.get_json()
242
+ session_id = data.get("sessionId", "default")
243
+ text = data["message"]["text"]
 
 
 
 
 
244
 
245
  if session_id not in conversation_store:
246
  conversation_store[session_id] = []
 
249
  "bankAccounts": [],
250
  "upiIds": [],
251
  "phishingLinks": [],
252
+ "emailAddresses": []
253
  }
254
  callback_done[session_id] = False
255
 
256
+ conversation_store[session_id].append({"sender": "scammer", "text": text})
257
+
258
+ scam, conf = detect_scam(text)
 
259
 
 
260
  intel = extract_intelligence(text)
261
  for k in intel:
262
+ intelligence_store[session_id][k] = list(
263
+ set(intelligence_store[session_id][k] + intel[k])
264
+ )
265
 
266
+ reply = generate_agent_reply(session_id)
267
 
268
+ conversation_store[session_id].append({"sender": "agent", "text": reply})
 
 
 
269
 
 
 
 
 
 
 
270
  if scam and not callback_done[session_id]:
271
  if len(conversation_store[session_id]) >= MIN_MESSAGES_FOR_CALLBACK:
272
  send_callback(session_id)
273
 
274
+ engagement = compute_engagement_score(session_id)
275
+
276
  return jsonify({
277
+ "status": "success",
278
+ "scamDetected": scam,
279
+ "confidence": round(conf, 3),
280
+ "reply": reply,
281
+ "engagementScore": round(engagement)
282
  })
283
 
 
 
 
 
284
  if __name__ == "__main__":
285
+ app.run(host="0.0.0.0", port=8000)