Pant0x commited on
Commit
91c1466
·
verified ·
1 Parent(s): 350a1b3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +96 -77
app.py CHANGED
@@ -1,106 +1,125 @@
1
  import gradio as gr
2
  import torch
 
 
3
  import numpy as np
4
 
5
- # -----------------------------
6
- # 1. Load Model (Robust)
7
- # -----------------------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  MODEL_PATH = "models/phishing_rf_model.pt"
 
 
 
 
 
9
 
10
- print(f"Attempting to load model from {MODEL_PATH}...")
11
  try:
12
- # Load the model file
13
- model = torch.load(MODEL_PATH, map_location=torch.device('cpu'))
14
- print(f"✅ Model loaded successfully! Type: {type(model)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  except Exception as e:
16
- print(f"❌ Failed to load model: {e}")
17
- model = None
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
- # -----------------------------
20
- # 2. Prediction Logic (Universal)
21
- # -----------------------------
22
  def predict_phishing(url):
23
- # Safety checks
24
- if model is None:
25
- return {"Error": 0.0}, "Model failed to load. Check logs."
 
26
  if not url:
27
  return None, "Please enter a URL."
28
 
29
  try:
30
- # --- A. Extract Features ---
31
- length = len(url)
32
- dots = url.count('.')
33
- hyphens = url.count('-')
34
- digits = sum(c.isdigit() for c in url)
35
- at_sign = url.count('@')
36
 
37
- # Raw features list
38
- features_list = [length, dots, hyphens, digits, at_sign]
39
-
40
- # --- B. Smart Detection & Prediction ---
41
 
42
- # CASE 1: It is a Scikit-Learn Model (Random Forest, etc.)
43
- if hasattr(model, "predict_proba"):
44
- # Sklearn expects a Numpy Array
45
- input_data = np.array([features_list], dtype=float)
46
-
47
- pred_prob = model.predict_proba(input_data)[0]
48
- # Usually: Index 0 = Safe, Index 1 = Phishing
49
- safe_score = float(pred_prob[0])
50
- phish_score = float(pred_prob[1])
51
-
52
- # CASE 2: It is a PyTorch Neural Network
53
- elif isinstance(model, torch.nn.Module):
54
- model.eval() # Set to evaluation mode
55
-
56
- # PyTorch expects a Tensor
57
- input_tensor = torch.tensor([features_list], dtype=torch.float32)
58
-
59
- with torch.no_grad():
60
- logits = model(input_tensor)
61
-
62
- # Check output shape to decide between Softmax or Sigmoid
63
- if logits.shape[1] == 1:
64
- # Binary output (Sigmoid)
65
- phish_score = torch.sigmoid(logits).item()
66
- safe_score = 1.0 - phish_score
67
- else:
68
- # Multi-class output (Softmax)
69
- probs = torch.nn.functional.softmax(logits, dim=1)
70
- safe_score = float(probs[0][0])
71
- phish_score = float(probs[0][1])
72
 
73
- else:
74
- return {"Error": 0}, f"Unknown model type: {type(model)}"
 
 
 
 
 
 
75
 
76
- # Return results
77
- return {"✅ Safe": safe_score, "🚨 Phishing": phish_score}, "Success"
78
 
79
  except Exception as e:
80
- # This catches the specific error and shows it in the UI
81
- error_msg = f"Crash Error: {str(e)}"
82
- print(error_msg)
83
- return {"Error": 0}, error_msg
84
 
85
- # -----------------------------
86
- # 3. UI Setup
87
- # -----------------------------
88
  with gr.Blocks(theme=gr.themes.Soft()) as iface:
89
- gr.Markdown("# 🛡️ PhishGuard Debugger")
90
 
91
  with gr.Row():
92
- input_box = gr.Textbox(label="URL", placeholder="https://google.com")
93
- predict_btn = gr.Button("Scan", variant="primary")
94
-
95
  with gr.Row():
96
- # We use two outputs: one for the label, one for the error message
97
- output_label = gr.Label(label="Prediction")
98
- status_box = gr.Textbox(label="Debug Status (Read this if error)", interactive=False)
99
 
100
- predict_btn.click(
101
- fn=predict_phishing,
102
- inputs=input_box,
103
- outputs=[output_label, status_box]
104
  )
105
 
106
  iface.launch()
 
1
  import gradio as gr
2
  import torch
3
+ import torch.nn as nn
4
+ import pickle
5
  import numpy as np
6
 
7
+ # ---------------------------------------------------------
8
+ # 1. Define the Neural Network Architecture
9
+ # ---------------------------------------------------------
10
+ # Since your file is an OrderedDict, we must define the class
11
+ # that matches the layers inside it.
12
+ # I am assuming a standard 5-input architecture based on your feature extractor.
13
+ class PhishingNet(nn.Module):
14
+ def __init__(self, input_size=5, hidden_size=10, output_size=2):
15
+ super(PhishingNet, self).__init__()
16
+ self.fc1 = nn.Linear(input_size, hidden_size)
17
+ self.relu = nn.ReLU()
18
+ self.fc2 = nn.Linear(hidden_size, output_size)
19
+
20
+ def forward(self, x):
21
+ out = self.fc1(x)
22
+ out = self.relu(out)
23
+ out = self.fc2(out)
24
+ return out
25
+
26
+ # ---------------------------------------------------------
27
+ # 2. Load Resources (Model + Scaler)
28
+ # ---------------------------------------------------------
29
  MODEL_PATH = "models/phishing_rf_model.pt"
30
+ SCALER_PATH = "models/scaler.pkl"
31
+
32
+ model = None
33
+ scaler = None
34
+ load_status = ""
35
 
 
36
  try:
37
+ # --- Load Scaler ---
38
+ with open(SCALER_PATH, "rb") as f:
39
+ scaler = pickle.load(f)
40
+ load_status += "✅ Scaler loaded.\n"
41
+
42
+ # --- Load Model Weights ---
43
+ # We load the weights (OrderedDict)
44
+ state_dict = torch.load(MODEL_PATH, map_location=torch.device('cpu'))
45
+
46
+ # We create the structure.
47
+ # NOTE: If this crashes with "Shape Mismatch", we will catch it below.
48
+ model = PhishingNet()
49
+ model.load_state_dict(state_dict)
50
+ model.eval() # Set to evaluation mode
51
+ load_status += "✅ Model weights loaded into Neural Net.\n"
52
+
53
  except Exception as e:
54
+ load_status += f"❌ LOAD ERROR: {str(e)}\n"
55
+ print(load_status)
56
+
57
+ # ---------------------------------------------------------
58
+ # 3. Feature Extraction (Must match your Scaler!)
59
+ # ---------------------------------------------------------
60
+ def extract_features(url: str) -> np.ndarray:
61
+ length = len(url)
62
+ dots = url.count('.')
63
+ hyphens = url.count('-')
64
+ digits = sum(c.isdigit() for c in url)
65
+ at_sign = url.count('@')
66
+
67
+ # Return shape [1, 5]
68
+ return np.array([[length, dots, hyphens, digits, at_sign]], dtype=float)
69
 
70
+ # ---------------------------------------------------------
71
+ # 4. Prediction Logic
72
+ # ---------------------------------------------------------
73
  def predict_phishing(url):
74
+ # Check if things loaded correctly
75
+ if model is None or scaler is None:
76
+ return {"Error": 0}, f"System not ready.\n{load_status}"
77
+
78
  if not url:
79
  return None, "Please enter a URL."
80
 
81
  try:
82
+ # 1. Extract
83
+ features = extract_features(url)
 
 
 
 
84
 
85
+ # 2. Scale (Using your scaler)
86
+ features_scaled = scaler.transform(features)
 
 
87
 
88
+ # 3. Convert to Torch Tensor
89
+ features_tensor = torch.tensor(features_scaled, dtype=torch.float32)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
+ # 4. Predict
92
+ with torch.no_grad():
93
+ logits = model(features_tensor)
94
+ probs = torch.nn.functional.softmax(logits, dim=1)
95
+
96
+ # Assume Index 0 = Safe, Index 1 = Phishing
97
+ safe_conf = float(probs[0][0])
98
+ phish_conf = float(probs[0][1])
99
 
100
+ return {"✅ Safe": safe_conf, "🚨 Phishing": phish_conf}, "Success"
 
101
 
102
  except Exception as e:
103
+ return {"Error": 0}, f"Prediction Failed: {str(e)}"
 
 
 
104
 
105
+ # ---------------------------------------------------------
106
+ # 5. UI Setup
107
+ # ---------------------------------------------------------
108
  with gr.Blocks(theme=gr.themes.Soft()) as iface:
109
+ gr.Markdown("# 🛡️ PhishScope (Custom Model)")
110
 
111
  with gr.Row():
112
+ url_input = gr.Textbox(label="URL to Check", placeholder="https://example.com")
113
+ submit_btn = gr.Button("Analyze", variant="primary")
114
+
115
  with gr.Row():
116
+ label_output = gr.Label(label="Result")
117
+ debug_output = gr.Textbox(label="System Status", value=load_status, lines=4)
 
118
 
119
+ submit_btn.click(
120
+ fn=predict_phishing,
121
+ inputs=url_input,
122
+ outputs=[label_output, debug_output]
123
  )
124
 
125
  iface.launch()