MahaTrabelsi commited on
Commit
3f20604
·
verified ·
1 Parent(s): bfa218d

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +157 -0
app.py ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import joblib
3
+ import numpy as np
4
+ import re
5
+
6
+ # ----------------------------
7
+ # Load the trained model
8
+ # ----------------------------
9
+ model = joblib.load("spam_model.joblib")
10
+
11
+ # ----------------------------
12
+ # Text normalization (optional but helps)
13
+ # ----------------------------
14
+ _url = re.compile(r'https?://\S+|www\.\S+')
15
+ _email = re.compile(r'\b[\w\.-]+@[\w\.-]+\.\w+\b')
16
+ _num = re.compile(r'\b\d[\d,.\-:/]*\b')
17
+
18
+ def normalize_text(t: str) -> str:
19
+ t = t.strip().lower()
20
+ t = _url.sub(' __url__ ', t)
21
+ t = _email.sub(' __email__ ', t)
22
+ t = _num.sub(' __number__ ', t)
23
+ return t
24
+
25
+ # ----------------------------
26
+ # Prediction function with confidence
27
+ # ----------------------------
28
+ def predict_with_confidence(text: str):
29
+ text_norm = normalize_text(text)
30
+ _input = [text_norm if text_norm else text]
31
+
32
+ pred = int(model.predict(_input)[0])
33
+
34
+ if hasattr(model, "predict_proba"):
35
+ proba = float(model.predict_proba(_input)[0][1]) # spam prob
36
+ else:
37
+ score = float(model.decision_function(_input)[0])
38
+ proba = 1 / (1 + np.exp(-score)) # sigmoid
39
+
40
+ label = "SPAM 🚨" if pred == 1 else "HAM ✅"
41
+ return label, proba
42
+
43
+ # ----------------------------
44
+ # Custom CSS
45
+ # ----------------------------
46
+ CUSTOM_CSS = """
47
+ :root {
48
+ --brand: #0ea5e9;
49
+ --brand-2: #0284c7;
50
+ --success: #22c55e;
51
+ --danger: #ef4444;
52
+ --card-bg: #0b1220;
53
+ --ink: #e5e7eb;
54
+ }
55
+ .gradio-container {max-width: 2100px !important;}
56
+ #app-card {
57
+ background: linear-gradient(135deg, #0b1220 0%, #0f172a 100%);
58
+ color: var(--ink);
59
+ border-radius: 18px;
60
+ padding: 28px;
61
+ box-shadow: 0 10px 30px rgba(0,0,0,0.35);
62
+ border: 1px solid rgba(255,255,255,0.08);
63
+ }
64
+ #title {font-size: 28px;font-weight: 800;letter-spacing: 0.2px;}
65
+ .subtitle {opacity: 0.85;margin-top: 2px;font-size: 14px;}
66
+ .badge {
67
+ display: inline-block;padding: 4px 10px;border-radius: 999px;
68
+ background: linear-gradient(135deg, var(--brand) 0%, var(--brand-2) 100%);
69
+ color: white;font-weight: 600;font-size: 12px;
70
+ }
71
+ #predict-btn > button {
72
+ background: linear-gradient(135deg, var(--brand) 0%, var(--brand-2) 100%) !important;
73
+ border: none !important;color: white !important;font-weight: 700 !important;
74
+ border-radius: 10px !important;
75
+ }
76
+ #clear-btn > button {
77
+ background: transparent !important;border: 1px solid rgba(255,255,255,0.15) !important;
78
+ color: var(--ink) !important;font-weight: 600 !important;border-radius: 10px !important;
79
+ }
80
+ .result-card {
81
+ border-radius: 14px;padding: 14px 16px;border: 1px solid rgba(255,255,255,0.08);
82
+ display: flex;align-items: center;gap: 10px;
83
+ }
84
+ .result-label {font-size: 18px;font-weight: 800;}
85
+ .confidence-wrap {display: flex;align-items: center;gap: 10px;}
86
+ .confidence-bar {
87
+ height: 10px;border-radius: 999px;flex: 1;
88
+ background: linear-gradient(90deg, var(--danger), var(--success));
89
+ position: relative;overflow: hidden;
90
+ }
91
+ .confidence-fill {
92
+ position: absolute;top: 0;left: 0;bottom: 0;
93
+ background: rgba(255,255,255,0.9);
94
+ mix-blend-mode: overlay;
95
+ }
96
+ .footer {opacity: 0.7;font-size: 12px;margin-top: 8px;}
97
+ """
98
+
99
+ # ----------------------------
100
+ # UI Prediction wrapper
101
+ # ----------------------------
102
+ def ui_predict(msg):
103
+ label, proba = predict_with_confidence(msg)
104
+ pct = int(round(proba * 100))
105
+ color = "var(--danger)" if "SPAM" in label else "var(--success)"
106
+ styled_label = f"<span style='color:{color}'>{label}</span>"
107
+ html = f"""
108
+ <div class="result-card">
109
+ <div class="result-label">{styled_label}</div>
110
+ <div class="confidence-wrap" style="flex:1">
111
+ <div style="min-width:120px; text-align:right; font-weight:700;">{pct}%</div>
112
+ <div class="confidence-bar">
113
+ <div class="confidence-fill" style="width:{pct}%;"></div>
114
+ </div>
115
+ </div>
116
+ </div>
117
+ """
118
+ return html
119
+
120
+ # ----------------------------
121
+ # Gradio App
122
+ # ----------------------------
123
+ with gr.Blocks(css=CUSTOM_CSS, theme=gr.themes.Soft()) as demo:
124
+ with gr.Column(elem_id="app-card"):
125
+ gr.HTML("""
126
+ <div id="title">📩 SMS Spam Classifier <span class="badge">TF-IDF + Logistic Regression</span></div>
127
+ <div class="subtitle">Type an SMS below and get an instant prediction with confidence.</div>
128
+ """)
129
+ with gr.Row():
130
+ msg = gr.Textbox(
131
+ label="Your message",
132
+ placeholder="e.g., Congratulations! You have won a FREE vacation. Text WIN to 90909 now!",
133
+ lines=5
134
+ )
135
+ with gr.Row():
136
+ predict_btn = gr.Button("Predict", elem_id="predict-btn")
137
+ clear_btn = gr.Button("Clear", elem_id="clear-btn")
138
+ result = gr.HTML(label="Result")
139
+
140
+ with gr.Accordion("Try examples", open=False):
141
+ gr.Examples(
142
+ examples=[
143
+ ["Hey, are we still meeting at 7 tonight?"],
144
+ ["Don’t forget to bring your homework tomorrow."],
145
+ ["URGENT! Claim your ��1000 cash prize by calling 0800-123-456."],
146
+ ["Free entry in 2 a weekly comp for a chance to win an iPhone. Text WIN to 88888."]
147
+ ],
148
+ inputs=[msg]
149
+ )
150
+ gr.Markdown('<div class="footer">Tip: spam words like "free", "win", "claim", "prize" increase the spam score.</div>')
151
+
152
+ predict_btn.click(fn=ui_predict, inputs=msg, outputs=result)
153
+ clear_btn.click(lambda: "", [], [msg])
154
+ msg.submit(fn=ui_predict, inputs=msg, outputs=result)
155
+
156
+ if __name__ == "__main__":
157
+ demo.launch()