axvg's picture
Upload app.py with huggingface_hub
6fec486 verified
Raw
History Blame Contribute Delete
3.58 kB
import os
import re
import joblib
import gradio as gr
import nltk
nltk.download("stopwords", quiet=True)
nltk.download("punkt_tab", quiet=True)
MODEL_PATH = os.path.join(os.path.dirname(__file__), "models", "best_model.joblib")
THRESHOLD = 0.55
URL_TOKEN = "url_token"
EMAIL_TOKEN = "email_token"
NUM_TOKEN = "num_token"
_RE_URL = re.compile(r"https?://\S+|www\.\S+", re.IGNORECASE)
_RE_EMAIL = re.compile(r"[\w.+-]+@[\w-]+\.[a-z]{2,}", re.IGNORECASE)
_RE_NUM = re.compile(r"\b\d[\d\s.,/-]*\d\b|\b\d\b")
_RE_PUNCT = re.compile(r"[^\w\s]")
_RE_WS = re.compile(r"\s+")
try:
from nltk.corpus import stopwords
_STOPWORDS = set(stopwords.words("english"))
except Exception:
_STOPWORDS = set()
def clean_text(text):
if not text:
return ""
text = str(text).lower()
text = _RE_URL.sub(f" {URL_TOKEN} ", text)
text = _RE_EMAIL.sub(f" {EMAIL_TOKEN} ", text)
text = _RE_NUM.sub(f" {NUM_TOKEN} ", text)
text = _RE_PUNCT.sub(" ", text)
tokens = [t for t in _RE_WS.sub(" ", text).strip().split() if t not in _STOPWORDS]
return " ".join(tokens)
_model = joblib.load(MODEL_PATH)
def classify(text, threshold):
if not text or not text.strip():
return "No input", "—", "—"
cleaned = clean_text(text)
proba = float(_model.predict_proba([cleaned])[:, 1][0])
label = int(proba >= threshold)
if label == 1:
veredicto = "PHISHING"
color = "color: #c0392b; font-weight: bold; font-size: 1.4em;"
else:
veredicto = "LEGITIMATE"
color = "color: #27ae60; font-weight: bold; font-size: 1.4em;"
return (
f'<span style="{color}">{veredicto}</span>',
f"{proba:.1%}",
f"{1 - proba:.1%}",
)
EXAMPLES = [
["Congratulations! You've been selected for a $1,000,000 prize. Click here to claim now: http://win-prize.xyz. Act fast, expires today!", 0.55],
["Hi team, please find attached the Q3 financial report for your review. Let me know if you have any questions. Best regards, Sarah.", 0.55],
["URGENT: Your account has been suspended. Verify your identity immediately at http://secure-bank-login.net or lose access permanently.", 0.55],
["Hey, are we still on for lunch tomorrow at 12:30? Let me know if the time works for you.", 0.55],
]
with gr.Blocks(theme=gr.themes.Soft(), title="Phishing Detector") as demo:
gr.Markdown(
"""
## Phishing Email Detector
Paste any email (subject + body) and the model will classify it as phishing or legitimate.
SVM classifier trained on ~47k emails (Enron, SpamAssassin, Nazario). F1 = 0.987 on held-out test set.
"""
)
with gr.Row():
with gr.Column(scale=2):
txt = gr.Textbox(
lines=10,
label="Email text",
placeholder="Paste email content here...",
)
threshold = gr.Slider(
0.1, 0.9, value=0.55, step=0.05,
label="Decision threshold (lower = more sensitive)",
)
btn = gr.Button("Classify", variant="primary")
with gr.Column(scale=1):
veredicto = gr.HTML(label="Result")
prob_phishing = gr.Textbox(label="Phishing probability")
prob_legit = gr.Textbox(label="Legitimate probability")
btn.click(classify, inputs=[txt, threshold], outputs=[veredicto, prob_phishing, prob_legit])
txt.submit(classify, inputs=[txt, threshold], outputs=[veredicto, prob_phishing, prob_legit])
gr.Examples(examples=EXAMPLES, inputs=[txt, threshold], label="Examples")
demo.launch()