Debdeep30 commited on
Commit
7c5873c
·
verified ·
1 Parent(s): 85d6f96

Upload pipeline/scam_filter.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. pipeline/scam_filter.py +116 -0
pipeline/scam_filter.py ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Lightweight scam detection for Lumi.
3
+
4
+ Two-stage approach:
5
+ 1. Keyword/pattern matching — fast, catches the obvious cases
6
+ 2. Embedding similarity — catches paraphrased variants
7
+
8
+ If scam_probability >= THRESHOLD, returns a gentle deflection response instead
9
+ of forwarding to the LLM. The deflection never alarms the patient.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import re
15
+
16
+ THRESHOLD = 0.7 # probability above which we deflect
17
+
18
+ # ---------------------------------------------------------------------------
19
+ # Stage 1 — keyword patterns
20
+ # ---------------------------------------------------------------------------
21
+
22
+ SCAM_PATTERNS = [
23
+ # urgent money requests
24
+ r"\b(send|transfer|wire|give|need)\b.{0,30}(money|cash|\$|pound|dollar)",
25
+ r"\burgent\b.{0,40}\b(payment|transfer|money|funds)",
26
+ # prize / lottery
27
+ r"\b(won|win|winner|lottery|prize|jackpot)\b",
28
+ r"\bcongratulations\b.{0,60}\b(prize|award|money|gift)",
29
+ # fake family emergency
30
+ r"\b(grandson|granddaughter|son|daughter|nephew|niece)\b.{0,40}\b(arrested|accident|hospital|trouble|jail|hurt)",
31
+ # bank / card details
32
+ r"\b(bank\s+account|account\s+number|sort\s+code|credit\s+card|debit\s+card|pin\b|password|social\s+security)",
33
+ # impersonation
34
+ r"\bthis\s+is\s+(your\s+bank|the\s+(police|irs|hmrc|government|medicare|social\s+security))",
35
+ # gift card scams
36
+ r"\b(gift\s+card|itunes|amazon\s+card|google\s+play)\b.{0,30}\b(buy|purchase|send|code)",
37
+ ]
38
+
39
+ _compiled = [re.compile(p, re.IGNORECASE) for p in SCAM_PATTERNS]
40
+
41
+
42
+ def _keyword_score(text: str) -> float:
43
+ """Returns a score 0-1 based on how many patterns match."""
44
+ hits = sum(1 for p in _compiled if p.search(text))
45
+ if hits >= 1:
46
+ return 1.0
47
+ return 0.0
48
+
49
+
50
+ # ---------------------------------------------------------------------------
51
+ # Stage 2 — embedding similarity (optional, loads lazily)
52
+ # ---------------------------------------------------------------------------
53
+
54
+ _embed_model = None
55
+ _scam_embeddings = None
56
+
57
+ SCAM_SEED_PHRASES = [
58
+ "Send me $500 immediately, I'm in trouble",
59
+ "You have won a lottery prize, claim now",
60
+ "Give me your bank account number",
61
+ "This is the IRS, you owe back taxes",
62
+ "Buy iTunes gift cards and send the codes",
63
+ "I'm your grandson and I had an accident",
64
+ "Your credit card has been compromised, verify details",
65
+ ]
66
+
67
+
68
+ def _load_embeddings():
69
+ global _embed_model, _scam_embeddings
70
+ if _embed_model is None:
71
+ try:
72
+ from sentence_transformers import SentenceTransformer
73
+ import numpy as np
74
+ _embed_model = SentenceTransformer("all-MiniLM-L6-v2")
75
+ _scam_embeddings = _embed_model.encode(SCAM_SEED_PHRASES, normalize_embeddings=True)
76
+ except ImportError:
77
+ _embed_model = False # flag: not available
78
+
79
+
80
+ def _embedding_score(text: str) -> float:
81
+ _load_embeddings()
82
+ if not _embed_model:
83
+ return 0.0
84
+ import numpy as np
85
+ emb = _embed_model.encode([text], normalize_embeddings=True)
86
+ similarities = (_scam_embeddings @ emb.T).flatten()
87
+ return float(similarities.max())
88
+
89
+
90
+ # ---------------------------------------------------------------------------
91
+ # Public API
92
+ # ---------------------------------------------------------------------------
93
+
94
+ DEFLECTION_RESPONSE = (
95
+ "That sounds like something we should check with your family first. "
96
+ "Let me make a note for them. "
97
+ "You don't need to do anything right now — you're completely safe."
98
+ )
99
+
100
+
101
+ def scam_probability(text: str) -> float:
102
+ kw = _keyword_score(text)
103
+ em = _embedding_score(text)
104
+ return max(kw, em * 0.8) # keyword takes precedence; embedding adds coverage
105
+
106
+
107
+ def check_and_deflect(user_text: str) -> tuple[bool, str]:
108
+ """
109
+ Returns (is_scam, response).
110
+ If is_scam is True, response is the safe deflection message.
111
+ If is_scam is False, response is empty — proceed normally to the LLM.
112
+ """
113
+ prob = scam_probability(user_text)
114
+ if prob >= THRESHOLD:
115
+ return True, DEFLECTION_RESPONSE
116
+ return False, ""