CoolFace
Apppublic

Afeefa123/network-security-with-machine-learning

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
app.py251 linesDownload Raw Back to root
1"""2Gradio app for NSL-KDD binary intrusion detection demo (MVP)3Expecting these files in the same repo/root of the Space:4  - nsl_kdd_tf_model.h5       (optional; if present will be used)5  - scaler.pkl                (optional; sklearn StandardScaler, must match model training)6  - columns.json              (optional; list of feature column names used by the model)7 8If artifacts are missing, the app will instruct you how to add them and offers a quick fallback9where you can upload a CSV and the app will train a lightweight sklearn model for demo purposes.10"""11 12import os13import json14import tempfile15import traceback16from typing import Tuple, List17 18import numpy as np19import pandas as pd20 21import gradio as gr22 23# optional heavy import guarded24TF_AVAILABLE = True25try:26    import tensorflow as tf27except Exception:28    TF_AVAILABLE = False29 30from sklearn.preprocessing import StandardScaler31from sklearn.linear_model import LogisticRegression32import joblib33 34# artifact filenames35MODEL_FILE = "nsl_kdd_tf_model.h5"36SCALER_FILE = "scaler.pkl"37COLUMNS_FILE = "columns.json"38 39# helper: load artifacts if exist40def load_artifacts():41    model = None42    scaler = None43    columns = None44    model_type = None45 46    # load columns.json if present47    if os.path.exists(COLUMNS_FILE):48        with open(COLUMNS_FILE, "r", encoding="utf-8") as f:49            columns = json.load(f)50 51    # load scaler if present52    if os.path.exists(SCALER_FILE):53        try:54            scaler = joblib.load(SCALER_FILE)55        except Exception:56            try:57                scaler = joblib.load(open(SCALER_FILE, "rb"))58            except Exception:59                scaler = None60 61    # load TF model if present and TF available62    if os.path.exists(MODEL_FILE) and TF_AVAILABLE:63        try:64            model = tf.keras.models.load_model(MODEL_FILE)65            model_type = "tensorflow"66        except Exception:67            model = None68 69    return model, scaler, columns, model_type70 71MODEL, SCALER, COLUMNS, MODEL_TYPE = load_artifacts()72 73def model_available_message() -> str:74    if MODEL is not None and SCALER is not None and COLUMNS is not None:75        return "✅ Pretrained TensorFlow model and artifacts loaded. Ready to predict."76    pieces = []77    if MODEL is None:78        pieces.append(f"Missing `{MODEL_FILE}`")79    if SCALER is None:80        pieces.append(f"Missing `{SCALER_FILE}`")81    if COLUMNS is None:82        pieces.append(f"Missing `{COLUMNS_FILE}`")83    msg = "⚠️ Artifacts missing: " + ", ".join(pieces) + ".\n\n"84    msg += "To run the TF model, add those files to the Space repository (same folder as app.py).\n"85    msg += "Alternatively, upload a CSV of NSL-KDD records (the app will train a quick sklearn model for demo).\n\n"86    msg += "columns.json should be a JSON array of feature names that match the model input (same as X_train.columns).\n"87    return msg88 89# utility: preprocess input dataframe into model-ready X using columns & scaler90def prepare_X_from_df(df: pd.DataFrame, expected_columns: List[str], scaler_obj) -> np.ndarray:91    # Align columns: fill missing with 092    X = df.reindex(columns=expected_columns, fill_value=0)93    # Ensure numeric type94    X = X.apply(pd.to_numeric, errors="coerce").fillna(0.0)95    if scaler_obj is not None:96        Xs = scaler_obj.transform(X)97    else:98        # if no scaler provided, return raw numpy99        Xs = X.values.astype(np.float32)100    return Xs101 102def predict_batch_from_df(df: pd.DataFrame) -> Tuple[pd.DataFrame, str]:103    """104    returns (result_df, status_message)105    result_df contains prob and predicted class per row106    """107    try:108        if MODEL is not None and SCALER is not None and COLUMNS is not None and MODEL_TYPE == "tensorflow":109            Xs = prepare_X_from_df(df, COLUMNS, SCALER)110            probs = MODEL.predict(Xs).ravel()111            preds = (probs >= 0.5).astype(int)112            out = df.copy()113            out["_pred_prob"] = probs114            out["_pred_class"] = preds115            return out, "Predictions from TensorFlow model"116        else:117            # fallback: train a quick logistic regression on uploaded data if contains label118            if 'label' in df.columns or 'label_bin' in df.columns:119                # If label present, run quick preprocess similar to notebook: create X (one-hot for cats)120                # Identify expected categorical columns if present121                cats = ['protocol_type', 'service', 'flag']122                col_names = df.columns.tolist()123                # We'll try to mimic preprocess from notebook: numeric vs cats124                num_cols = [c for c in col_names if c not in cats + ['label','label_bin']]125                X_num = df[num_cols].apply(pd.to_numeric, errors='coerce').fillna(0.0)126                X_cat = pd.get_dummies(df[cats], drop_first=True)127                X = pd.concat([X_num, X_cat], axis=1)128                y = df['label_bin'] if 'label_bin' in df.columns else df['label'].apply(lambda s: 0 if str(s).strip().lower()=="normal" else 1)129                # minimal scaler + logistic130                scaler_local = StandardScaler()131                Xs = scaler_local.fit_transform(X)132                clf = LogisticRegression(max_iter=200)133                clf.fit(Xs, y)134                probs = clf.predict_proba(Xs)[:,1]135                preds = (probs >= 0.5).astype(int)136                out = df.copy()137                out["_pred_prob"] = probs138                out["_pred_class"] = preds139                return out, "Trained temporary LogisticRegression on uploaded CSV (used 'label' or 'label_bin' for training)."140            else:141                return pd.DataFrame(), "Cannot fallback: artifacts missing and uploaded CSV does not contain 'label' or 'label_bin' to train a temporary model."142    except Exception as e:143        tb = traceback.format_exc()144        return pd.DataFrame(), f"Prediction error: {e}\n\n{tb}"145 146def predict_single(sample_text: str) -> str:147    """148    sample_text: CSV row or JSON dict representing one row with same columns as columns.json149    returns a readable string with probability and class150    """151    try:152        if not sample_text:153            return "No input provided."154        # try JSON first155        try:156            d = json.loads(sample_text)157            if isinstance(d, dict):158                df = pd.DataFrame([d])159            else:160                return "JSON must represent an object/dict for single sample."161        except Exception:162            # try CSV row163            try:164                df = pd.read_csv(pd.compat.StringIO(sample_text), header=None)165                # if no header, user probably pasted values: cannot map to columns166                if COLUMNS is not None and df.shape[1] == len(COLUMNS):167                    df.columns = COLUMNS168                else:169                    return "CSV input detected but header/column count mismatch. Prefer JSON object keyed by column names."170            except Exception:171                return "Could not parse input. Paste a JSON object like {\"duration\":0, \"protocol_type\":\"tcp\", ...} or upload a CSV row with header."172 173        # Now we have df; run batch predict logic but for a single row174        if MODEL is not None and SCALER is not None and COLUMNS is not None and MODEL_TYPE == "tensorflow":175            Xs = prepare_X_from_df(df, COLUMNS, SCALER)176            prob = float(MODEL.predict(Xs)[0,0])177            pred = int(prob >= 0.5)178            return f"Pred prob: {prob:.4f} — predicted class: {pred} (0=normal, 1=attack)"179        else:180            return "Model artifacts not present in Space. Upload `nsl_kdd_tf_model.h5`, `scaler.pkl`, and `columns.json` to use the TensorFlow model. Alternatively upload a labelled CSV to train a quick demo model."181    except Exception as e:182        tb = traceback.format_exc()183        return f"Error: {e}\n\n{tb}"184 185# Gradio UI components186with gr.Blocks(title="NSL-KDD Intrusion Detection — Demo MVP") as demo:187    gr.Markdown("# NSL-KDD Intrusion Detection — Demo (MVP)\n"188                "Upload your artifacts (`nsl_kdd_tf_model.h5`, `scaler.pkl`, `columns.json`) to the Space to use the TensorFlow model.\n"189                "Or upload a labelled CSV (contains `label` or `label_bin`) and the app will train a quick logistic regression for demo.\n\n"190                "Columns expected: the original notebook used 41 numeric features with one-hot for `protocol_type`, `service`, `flag`.\n"191                )192    status = gr.Textbox(label="Status / Artifact check", value=model_available_message(), interactive=False)193    with gr.Row():194        with gr.Column(scale=2):195            file_input = gr.File(label="Upload CSV for batch prediction or for training fallback", file_types=['.csv'])196            sample_input = gr.Textbox(label="Single-sample input (JSON object)", placeholder='{"duration":0, "protocol_type":"tcp", ...}', lines=6)197            predict_button = gr.Button("Predict single sample")198            batch_button = gr.Button("Run batch (on uploaded CSV)")199 200        with gr.Column(scale=1):201            out_table = gr.Dataframe(label="Batch predictions (if any)")202 203            single_out = gr.Textbox(label="Single sample result", interactive=False)204 205    # Example / help206    example_text = json.dumps({207        "duration": 0,208        "protocol_type": "tcp",209        "service": "http",210        "flag": "SF",211        "src_bytes": 181,212        "dst_bytes": 5450213    }, indent=2)214    gr.Markdown("**Example single-sample JSON (fill in more NSL-KDD fields if you have them):**")215    gr.Code(example_text, language="json")216 217    # Callbacks218    def on_predict_single(sample_text):219        return predict_single(sample_text)220 221    def on_batch_predict(file_obj):222        if file_obj is None:223            return pd.DataFrame(), "No file uploaded."224        try:225            # read uploaded CSV into DataFrame226            df = pd.read_csv(file_obj.name)227        except Exception:228            try:229                # fallback: try bytes230                df = pd.read_csv(file_obj)231            except Exception as e:232                return pd.DataFrame(), f"Could not read CSV: {e}"233 234        out_df, msg = predict_batch_from_df(df)235        if out_df.empty:236            return pd.DataFrame(), msg237        # Limit columns shown for readability238        display_df = out_df.copy()239        # move prediction columns to front if present240        for c in ["_pred_prob", "_pred_class"]:241            if c in display_df.columns:242                cols = [c] + [x for x in display_df.columns if x != c]243                display_df = display_df[cols]244        return display_df, msg245 246    predict_button.click(on_predict_single, inputs=[sample_input], outputs=[single_out])247    batch_button.click(on_batch_predict, inputs=[file_input], outputs=[out_table, status])248 249if __name__ == "__main__":250    demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))251