ExistedYear commited on
Commit
fa9bd1a
·
1 Parent(s): 255a427

flask-themed UI with desktop/mobile tabs

Browse files
Files changed (1) hide show
  1. app.py +93 -31
app.py CHANGED
@@ -26,10 +26,29 @@ print("Loading SHAP explainer...")
26
  explainer = SmishingExplainer(predictor)
27
  print("Model loaded. Ready.")
28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  @spaces.GPU(duration=120)
30
  def analyze(message):
31
  if not message or not message.strip():
32
- return "⚠️ Please enter a message.", None, None
33
 
34
  result = predictor.predict(message)
35
 
@@ -114,36 +133,79 @@ examples = [
114
  "Mom, I landed safely. Will call from the hotel in an hour.",
115
  ]
116
 
117
- with gr.Blocks(title="ScamShield — Smishing Detector") as demo:
118
- gr.Markdown("# 🛡️ ScamShield — Multilingual Smishing Detector")
119
- gr.Markdown("Detect SMS phishing (smishing) in English, Hindi, and Hinglish. "
120
- "Powered by XLM-RoBERTa + hand-crafted URL/text features + Google Safe Browsing.")
121
-
122
- with gr.Row():
123
- with gr.Column(scale=2):
124
- inp = gr.Textbox(label="SMS Message", placeholder="Paste the SMS message here...",
125
- lines=4, max_lines=10)
126
- btn = gr.Button("🔍 Analyze", variant="primary", size="lg")
127
-
128
- with gr.Column(scale=3):
129
- verdict = gr.Markdown(label="Verdict")
130
- with gr.Tabs():
131
- with gr.TabItem("URL Analysis"):
132
- url_box = gr.Markdown()
133
- with gr.TabItem("Text Signals"):
134
- text_box = gr.Markdown()
135
- with gr.TabItem("SHAP Explainability"):
136
- shap_box = gr.Markdown()
137
-
138
- btn.click(fn=analyze, inputs=inp, outputs=[verdict, url_box, text_box, shap_box], api_name="predict")
139
- inp.submit(fn=analyze, inputs=inp, outputs=[verdict, url_box, text_box, shap_box])
140
-
141
- gr.Examples(examples=examples, inputs=inp, label="Try these examples")
142
-
143
- gr.Markdown("---\n"
144
- "**Model:** XLM-RoBERTa (xlm-roberta-base) | **Threshold:** 0.55 | "
145
- "**Languages:** English · Hindi · Hinglish | "
146
- "**Features:** 9 URL signals + 8 text signals | **F1:** 0.98")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
 
148
 
149
  if __name__ == "__main__":
 
26
  explainer = SmishingExplainer(predictor)
27
  print("Model loaded. Ready.")
28
 
29
+ CSS = """
30
+ @import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap');
31
+ .gradio-container { font-family: 'Plus Jakarta Sans', sans-serif !important; max-width: 920px !important; margin: 0 auto !important; }
32
+ .ss-hero { text-align: center; padding: 2rem 0 1.2rem; }
33
+ .ss-hero h1 { font-size: 2.3rem; font-weight: 800; letter-spacing: -0.5px; margin: 0; }
34
+ .ss-hero h1 span { color: #3b82f6; }
35
+ .ss-hero p { opacity: 0.65; font-size: 0.92rem; margin-top: 0.4rem; }
36
+ .ss-badge { display: inline-flex; align-items: center; gap: 0.35rem; background: rgba(59,130,246,.12);
37
+ border: 1px solid rgba(59,130,246,.35); color: #3b82f6; font-size: 0.72rem; font-weight: 700;
38
+ padding: 0.25rem 0.7rem; border-radius: 20px; margin-bottom: 0.8rem; }
39
+ .phone-frame { max-width: 392px !important; margin: 0 auto !important; border: 10px solid #0b0e13;
40
+ border-radius: 34px; padding: 1rem 0.9rem 1.3rem !important; box-shadow: 0 14px 44px rgba(0,0,0,.35); }
41
+ .phone-notch { width: 120px; height: 22px; background: #0b0e13; border-radius: 0 0 12px 12px; margin: -1rem auto 0.7rem; }
42
+ .phone-title { text-align: center; font-weight: 800; font-size: 1rem; margin-bottom: 0.2rem; }
43
+ .phone-sub { text-align: center; font-size: 0.72rem; opacity: 0.6; margin-bottom: 0.8rem; }
44
+ .ss-footer { text-align: center; font-size: 0.75rem; opacity: 0.6; margin-top: 1.6rem; line-height: 1.7; }
45
+ """
46
+
47
+
48
  @spaces.GPU(duration=120)
49
  def analyze(message):
50
  if not message or not message.strip():
51
+ return "⚠️ Please enter a message.", None, None, None
52
 
53
  result = predictor.predict(message)
54
 
 
133
  "Mom, I landed safely. Will call from the hotel in an hour.",
134
  ]
135
 
136
+ seed_labels = ["Seed 1 · EN spam (KYC)", "Seed 2 · EN ham (bank)", "Seed 3 · Hinglish spam (bijli)",
137
+ "Seed 4 · EN ham (recharge)", "Seed 5 · Hinglish spam (CBI)", "Seed 6 · EN ham (UPI)",
138
+ "Seed 7 · Hindi spam (lottery)", "Seed 8 · EN ham (OTP)", "Seed 9 · EN spam (UPI)",
139
+ "Seed 10 · EN ham (personal)"]
140
+
141
+
142
+ def _pick_seed(choice):
143
+ try:
144
+ idx = seed_labels.index(choice)
145
+ except ValueError:
146
+ idx = 0
147
+ return examples[idx]
148
+
149
+
150
+ with gr.Blocks(title="ScamShield — Smishing Detector", css=CSS,
151
+ theme=gr.themes.Soft(primary_hue="blue", neutral_hue="slate")) as demo:
152
+ gr.HTML("""<div class="ss-hero">
153
+ <div class="ss-badge">🛡️ AI · Cybersecurity — Smishing Detection</div>
154
+ <h1>Detect <span>Scams</span> Before They Strike</h1>
155
+ <p>XLM-RoBERTa + URL fusion + SHAP · English · Hindi · Hinglish · Threshold 0.55</p>
156
+ </div>""")
157
+
158
+ with gr.Tabs():
159
+ with gr.TabItem("Desktop"):
160
+ with gr.Row():
161
+ with gr.Column(scale=2):
162
+ inp = gr.Textbox(label="SMS Message", placeholder="Paste the SMS message here...",
163
+ lines=4, max_lines=10)
164
+ btn = gr.Button("🔍 Analyze", variant="primary", size="lg")
165
+ gr.Examples(examples=examples, inputs=inp, label="Try these examples")
166
+
167
+ with gr.Column(scale=3):
168
+ verdict = gr.Markdown(label="Verdict")
169
+ with gr.Tabs():
170
+ with gr.TabItem("URL Analysis"):
171
+ url_box = gr.Markdown()
172
+ with gr.TabItem("Text Signals"):
173
+ text_box = gr.Markdown()
174
+ with gr.TabItem("SHAP Explainability"):
175
+ shap_box = gr.Markdown()
176
+
177
+ btn.click(fn=analyze, inputs=inp,
178
+ outputs=[verdict, url_box, text_box, shap_box], api_name="predict")
179
+ inp.submit(fn=analyze, inputs=inp,
180
+ outputs=[verdict, url_box, text_box, shap_box])
181
+
182
+ with gr.TabItem("Mobile"):
183
+ gr.Markdown("Phone-style scanner — same live model. Full app adds the 100-message seeded inbox + Scan All; "
184
+ "pick a seed below or paste any SMS.")
185
+ with gr.Column(elem_classes="phone-frame"):
186
+ gr.HTML('<div class="phone-notch"></div><div class="phone-title">🛡️ ScamShield</div>'
187
+ '<div class="phone-sub">Seeded inbox preview · live analysis</div>')
188
+ seed = gr.Dropdown(choices=seed_labels, value=seed_labels[0], label="Seeded message")
189
+ minp = gr.Textbox(label="SMS Message", lines=3, max_lines=6)
190
+ mbtn = gr.Button("🔍 Scan", variant="primary")
191
+ mverdict = gr.Markdown(label="Verdict")
192
+ with gr.Tabs():
193
+ with gr.TabItem("URLs"):
194
+ murl = gr.Markdown()
195
+ with gr.TabItem("Signals"):
196
+ mtext = gr.Markdown()
197
+ with gr.TabItem("SHAP"):
198
+ mshap = gr.Markdown()
199
+
200
+ seed.change(fn=_pick_seed, inputs=seed, outputs=minp, api_name=False)
201
+ mbtn.click(fn=analyze, inputs=minp,
202
+ outputs=[mverdict, murl, mtext, mshap], api_name="predict_mobile")
203
+
204
+ gr.HTML("""<div class="ss-footer">
205
+ <b>Model:</b> XLM-RoBERTa (xlm-roberta-base) · <b>Threshold:</b> 0.55 ·
206
+ <b>Languages:</b> English · Hindi · Hinglish · <b>Features:</b> 9 URL + 8 text signals · <b>Spam F1:</b> 0.94<br/>
207
+ Full Android app (.apk) via EAS build — same API underneath.
208
+ </div>""")
209
 
210
 
211
  if __name__ == "__main__":