Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -131,26 +131,24 @@ def predict_batch(texts: List[str], model_id: str = MODEL_ID_DEFAULT) -> List[Tu
|
|
| 131 |
results.append((top_label, float(top_conf), probs))
|
| 132 |
return results
|
| 133 |
|
| 134 |
-
|
| 135 |
-
# (left intentionally minimal — UI only request)
|
| 136 |
|
| 137 |
# ---------------- UI Callbacks ----------------
|
| 138 |
|
| 139 |
# Single predict wrapper for Gradio
|
| 140 |
def single_predict(text: str, model_id: str, threshold: float):
|
| 141 |
txt = _prepare_text(text)
|
|
|
|
| 142 |
if txt == "":
|
| 143 |
-
return "",
|
| 144 |
try:
|
| 145 |
probs, idx = predict_raw(txt, model_id)
|
| 146 |
# sort probs descending
|
| 147 |
probs_sorted = dict(sorted(probs.items(), key=lambda kv: kv[1], reverse=True))
|
| 148 |
top_label = list(probs_sorted.keys())[0]
|
| 149 |
top_conf = float(probs_sorted[top_label])
|
| 150 |
-
# format as percentage for UI
|
| 151 |
top_conf_pct = f"{top_conf * 100:.1f}%"
|
| 152 |
-
|
| 153 |
-
top_label_display = f"{top_label} ({top_conf_pct})"
|
| 154 |
warn = "" if top_conf >= threshold else f"Below threshold {threshold:.2f}"
|
| 155 |
|
| 156 |
# log (no-op if history disabled)
|
|
@@ -165,9 +163,9 @@ def single_predict(text: str, model_id: str, threshold: float):
|
|
| 165 |
except Exception:
|
| 166 |
pass
|
| 167 |
|
| 168 |
-
return
|
| 169 |
except Exception as e:
|
| 170 |
-
return "",
|
| 171 |
|
| 172 |
|
| 173 |
# Batch predict from uploaded CSV (expects column 'message' or 'text')
|
|
@@ -216,6 +214,10 @@ MODERN_CSS = """
|
|
| 216 |
.label-muted { color: #6b7280; font-size: 13px; }
|
| 217 |
.small-note { font-size: 13px; color: #6b7280; }
|
| 218 |
.warning-pill { background: #fff7ed; padding: 8px 12px; border-radius: 999px; display:inline-block; color: #92400e; font-weight:600; }
|
|
|
|
|
|
|
|
|
|
|
|
|
| 219 |
"""
|
| 220 |
|
| 221 |
|
|
@@ -223,7 +225,7 @@ def build_ui():
|
|
| 223 |
with gr.Blocks(title="Phishing Detector", css=MODERN_CSS) as demo:
|
| 224 |
with gr.Column():
|
| 225 |
# Header
|
| 226 |
-
gr.HTML("<div class='header-gradient'><h1 style='margin:0;'>🛡️ Phishing Detector</h1><p style='margin:6px 0 0 0;
|
| 227 |
|
| 228 |
with gr.Row(elem_id="main-row", variant="default"):
|
| 229 |
# Left: Main actions
|
|
@@ -236,7 +238,7 @@ def build_ui():
|
|
| 236 |
predict_btn = gr.Button("Analyze", variant="primary")
|
| 237 |
with gr.Row():
|
| 238 |
out_label = gr.Textbox(label="Top prediction", interactive=False)
|
| 239 |
-
out_conf = gr.
|
| 240 |
out_probs = gr.JSON(label="Probabilities (descending)")
|
| 241 |
warn_box = gr.Textbox(label="Warning", interactive=False)
|
| 242 |
|
|
|
|
| 131 |
results.append((top_label, float(top_conf), probs))
|
| 132 |
return results
|
| 133 |
|
| 134 |
+
|
|
|
|
| 135 |
|
| 136 |
# ---------------- UI Callbacks ----------------
|
| 137 |
|
| 138 |
# Single predict wrapper for Gradio
|
| 139 |
def single_predict(text: str, model_id: str, threshold: float):
|
| 140 |
txt = _prepare_text(text)
|
| 141 |
+
empty_bar = "<div class='conf-bar'><div class='conf-fill' style='width:0%'>0%</div></div>"
|
| 142 |
if txt == "":
|
| 143 |
+
return "", empty_bar, {}, "Empty input"
|
| 144 |
try:
|
| 145 |
probs, idx = predict_raw(txt, model_id)
|
| 146 |
# sort probs descending
|
| 147 |
probs_sorted = dict(sorted(probs.items(), key=lambda kv: kv[1], reverse=True))
|
| 148 |
top_label = list(probs_sorted.keys())[0]
|
| 149 |
top_conf = float(probs_sorted[top_label])
|
|
|
|
| 150 |
top_conf_pct = f"{top_conf * 100:.1f}%"
|
| 151 |
+
progress_html = f"<div class='conf-bar'><div class='conf-fill' style='width:{top_conf*100:.1f}%'>{top_conf_pct}</div></div>"
|
|
|
|
| 152 |
warn = "" if top_conf >= threshold else f"Below threshold {threshold:.2f}"
|
| 153 |
|
| 154 |
# log (no-op if history disabled)
|
|
|
|
| 163 |
except Exception:
|
| 164 |
pass
|
| 165 |
|
| 166 |
+
return top_label, progress_html, probs_sorted, warn
|
| 167 |
except Exception as e:
|
| 168 |
+
return "", empty_bar, {}, f"Error: {str(e)}"
|
| 169 |
|
| 170 |
|
| 171 |
# Batch predict from uploaded CSV (expects column 'message' or 'text')
|
|
|
|
| 214 |
.label-muted { color: #6b7280; font-size: 13px; }
|
| 215 |
.small-note { font-size: 13px; color: #6b7280; }
|
| 216 |
.warning-pill { background: #fff7ed; padding: 8px 12px; border-radius: 999px; display:inline-block; color: #92400e; font-weight:600; }
|
| 217 |
+
|
| 218 |
+
/* confidence bar */
|
| 219 |
+
.conf-bar { background: #e6f0ff; border-radius: 999px; padding: 4px; width: 200px; }
|
| 220 |
+
.conf-fill { display:inline-block; height:26px; line-height:26px; padding:0 10px; border-radius: 999px; background: linear-gradient(90deg,#60a5fa,#3b82f6); color: white; font-weight:700; transition: width 400ms ease; }
|
| 221 |
"""
|
| 222 |
|
| 223 |
|
|
|
|
| 225 |
with gr.Blocks(title="Phishing Detector", css=MODERN_CSS) as demo:
|
| 226 |
with gr.Column():
|
| 227 |
# Header
|
| 228 |
+
gr.HTML("<div class='header-gradient'><h1 style='margin:0;color:white;'>🛡️ Phishing Detector</h1><p style='margin:6px 0 0 0;color:rgba(255,255,255,0.95);'>Classify messages or URLs as phishing or legitimate — clean, modern interface.</p></div> ")
|
| 229 |
|
| 230 |
with gr.Row(elem_id="main-row", variant="default"):
|
| 231 |
# Left: Main actions
|
|
|
|
| 238 |
predict_btn = gr.Button("Analyze", variant="primary")
|
| 239 |
with gr.Row():
|
| 240 |
out_label = gr.Textbox(label="Top prediction", interactive=False)
|
| 241 |
+
out_conf = gr.HTML("<div class='conf-bar'><div class='conf-fill' style='width:0%'>0%</div></div>", label="Confidence")
|
| 242 |
out_probs = gr.JSON(label="Probabilities (descending)")
|
| 243 |
warn_box = gr.Textbox(label="Warning", interactive=False)
|
| 244 |
|