Spaces:
Sleeping
Sleeping
| import pandas as pd | |
| import numpy as np | |
| import os | |
| import joblib | |
| from sklearn.feature_extraction.text import TfidfVectorizer | |
| from sklearn.linear_model import LogisticRegression | |
| from sklearn.model_selection import train_test_split | |
| from sklearn.metrics import classification_report, accuracy_score | |
| from sklearn.pipeline import Pipeline | |
| DATASET_PATH = "../datasets/SMSSpamCollection" | |
| MODEL_DIR = "." | |
| PHISHING_KEYWORDS = [ | |
| "otp", "kyc", "verify", "account", "bank", "credit", "debit", | |
| "password", "urgent", "winner", "prize", "claim", "free", | |
| "click", "link", "update", "expire", "suspend", "confirm", | |
| "transaction", "blocked", "alert", "immediate", "action required" | |
| ] | |
| def load_sms_data(): | |
| print("[*] Loading SMS dataset...") | |
| tried = [] | |
| paths_to_try = [ | |
| "../datasets/sms.tsv", | |
| DATASET_PATH, | |
| "../datasets/SMSSpamCollection", | |
| "../datasets/spam.csv", | |
| "../datasets/sms_spam.csv", | |
| ] | |
| df = None | |
| for path in paths_to_try: | |
| tried.append(path) | |
| if os.path.exists(path): | |
| try: | |
| if path.endswith(".csv"): | |
| df = pd.read_csv(path, encoding="latin-1") | |
| for col in df.columns: | |
| if df[col].nunique() == 2: | |
| label_col = col | |
| else: | |
| text_col = col | |
| df = df[[label_col, text_col]] | |
| df.columns = ["label", "text"] | |
| elif path.endswith(".tsv"): | |
| df = pd.read_csv(path, sep="\t", header=None, names=["label", "text"], encoding="latin-1") | |
| else: | |
| df = pd.read_csv(path, sep="\t", header=None, names=["label", "text"], encoding="latin-1") | |
| print(f"[+] Loaded from: {path}") | |
| break | |
| except Exception as e: | |
| print(f"[!] Failed to load {path}: {e}") | |
| if df is None: | |
| print(f"[!] Could not find SMS dataset. Tried: {tried}") | |
| print("[*] Generating synthetic dataset for demonstration...") | |
| df = generate_synthetic_data() | |
| df = df.dropna() | |
| label_map = {} | |
| for val in df["label"].unique(): | |
| v = str(val).lower() | |
| if any(x in v for x in ["spam", "phish", "1", "ham"]): | |
| label_map[val] = 1 if "spam" in v or "phish" in v else 0 | |
| else: | |
| label_map[val] = 0 | |
| df["label"] = df["label"].map(label_map).fillna(0).astype(int) | |
| print(f"[*] Total samples: {len(df)}") | |
| print(f"[*] Label distribution:\n{df['label'].value_counts()}") | |
| return df | |
| def generate_synthetic_data(): | |
| spam_msgs = [ | |
| "URGENT: Your bank account has been suspended. Click here to verify your KYC immediately.", | |
| "Congratulations! You have won Rs 50,000. Claim your prize now by clicking this link.", | |
| "Your OTP is expiring. Please update your account details to avoid suspension.", | |
| "FREE: Get a free iPhone now! Limited offer. Click the link to claim.", | |
| "Your SBI account is blocked. Verify your details immediately to unblock.", | |
| "Dear customer, your PAN card is not linked. Update now or account will be closed.", | |
| "You have a pending transaction of Rs 9999. Confirm your password to proceed.", | |
| "Alert: Suspicious login detected. Verify your identity now: http://fake-bank.com", | |
| ] * 50 | |
| ham_msgs = [ | |
| "Hey, are you coming to the meeting tomorrow?", | |
| "Can you pick up some groceries on your way home?", | |
| "The project deadline has been moved to Friday.", | |
| "Happy birthday! Hope you have a wonderful day.", | |
| "Please find attached the report you requested.", | |
| "Lunch at 1pm? Let me know if that works.", | |
| "The package has been delivered to your door.", | |
| "Reminder: Doctor appointment at 3pm today.", | |
| ] * 50 | |
| labels = [1] * len(spam_msgs) + [0] * len(ham_msgs) | |
| texts = spam_msgs + ham_msgs | |
| return pd.DataFrame({"label": labels, "text": texts}) | |
| def train_sms_model(df): | |
| X = df["text"].values | |
| y = df["label"].values | |
| X_train, X_test, y_train, y_test = train_test_split( | |
| X, y, test_size=0.2, random_state=42, stratify=y | |
| ) | |
| print(f"\n[*] Training set: {len(X_train)} | Test set: {len(X_test)}") | |
| print("[*] Training TF-IDF + Logistic Regression pipeline...") | |
| pipeline = Pipeline([ | |
| ("tfidf", TfidfVectorizer( | |
| max_features=5000, | |
| ngram_range=(1, 2), | |
| stop_words="english", | |
| lowercase=True, | |
| sublinear_tf=True | |
| )), | |
| ("clf", LogisticRegression( | |
| C=1.0, max_iter=1000, | |
| class_weight="balanced", | |
| random_state=42 | |
| )) | |
| ]) | |
| pipeline.fit(X_train, y_train) | |
| preds = pipeline.predict(X_test) | |
| acc = accuracy_score(y_test, preds) | |
| print(f"[+] SMS Classifier Accuracy: {acc:.4f} ({acc*100:.2f}%)") | |
| print(classification_report(y_test, preds, target_names=["Legitimate", "Phishing/Spam"])) | |
| os.makedirs(MODEL_DIR, exist_ok=True) | |
| joblib.dump(pipeline, os.path.join(MODEL_DIR, "sms_model.pkl")) | |
| print("[+] Model saved: sms_model.pkl") | |
| test_messages = [ | |
| "Your account has been suspended. Verify KYC immediately to avoid closure.", | |
| "Hey, are you free for lunch tomorrow?", | |
| "URGENT: OTP expires in 5 mins. Click link to update your bank details now.", | |
| "Meeting rescheduled to 3pm. Please confirm attendance.", | |
| ] | |
| print("\n[*] Quick test predictions:") | |
| for msg in test_messages: | |
| pred = pipeline.predict([msg])[0] | |
| prob = pipeline.predict_proba([msg])[0][1] | |
| status = "PHISHING/SPAM" if pred == 1 else "LEGITIMATE" | |
| print(f" [{status}] ({prob*100:.1f}% confidence) {msg[:60]}...") | |
| return pipeline | |
| if __name__ == "__main__": | |
| print("=" * 50) | |
| print(" SMS Phishing Classifier - Training Script") | |
| print("=" * 50) | |
| df = load_sms_data() | |
| train_sms_model(df) | |
| print("\n[✓] Training complete!") | |