Spaces:
Sleeping
Sleeping
Upload 2 files
Browse files- app.py +149 -0
- requirements.txt +5 -0
app.py
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
import tensorflow as tf
|
| 3 |
+
import numpy as np
|
| 4 |
+
import cv2
|
| 5 |
+
import spaces # <-- NEW: Required for Hugging Face ZeroGPU
|
| 6 |
+
|
| 7 |
+
print("β³ System Engine Initialized (Dynamic lazy-loading active)...")
|
| 8 |
+
loaded_models = {
|
| 9 |
+
"MobileNetV2 (Lightweight)": None,
|
| 10 |
+
"ResNet50 (Deep Residual)": None
|
| 11 |
+
}
|
| 12 |
+
loss_object = tf.keras.losses.CategoricalCrossentropy()
|
| 13 |
+
NUM_CLASSES = 1000
|
| 14 |
+
|
| 15 |
+
# ====================================================================
|
| 16 |
+
# ADVANCED THREAT PACK ENGINE (FGSM + ITERATIVE PGD)
|
| 17 |
+
# ====================================================================
|
| 18 |
+
def run_pgd_attack(model_instance, input_image, target_class_idx, epsilon, steps=4, alpha=0.005):
|
| 19 |
+
adv_image = tf.identity(input_image)
|
| 20 |
+
for _ in range(steps):
|
| 21 |
+
with tf.GradientTape() as tape:
|
| 22 |
+
tape.watch(adv_image)
|
| 23 |
+
prediction = model_instance(adv_image)
|
| 24 |
+
one_hot = tf.reshape(tf.one_hot(target_class_idx, NUM_CLASSES), (1, NUM_CLASSES))
|
| 25 |
+
loss = loss_object(one_hot, prediction)
|
| 26 |
+
gradient = tape.gradient(loss, adv_image)
|
| 27 |
+
adv_image = adv_image + alpha * tf.sign(gradient)
|
| 28 |
+
eta = tf.clip_by_value(adv_image - input_image, -epsilon, epsilon)
|
| 29 |
+
adv_image = tf.clip_by_value(input_image + eta, -1.0, 1.0)
|
| 30 |
+
return adv_image - input_image
|
| 31 |
+
|
| 32 |
+
# <-- NEW: The decorator Hugging Face demands to pass the startup check
|
| 33 |
+
@spaces.GPU
|
| 34 |
+
def process_advanced_pipeline(input_img, model_choice, attack_choice, epsilon, defense_method, activate_defense):
|
| 35 |
+
if input_img is None:
|
| 36 |
+
return None, None, None, "Upload an image.", "Waiting...", ""
|
| 37 |
+
|
| 38 |
+
if loaded_models[model_choice] is None:
|
| 39 |
+
print(f"π¦ Dynamically caching weights for {model_choice}...")
|
| 40 |
+
if "MobileNet" in model_choice:
|
| 41 |
+
loaded_models[model_choice] = tf.keras.applications.mobilenet_v2.MobileNetV2(weights='imagenet')
|
| 42 |
+
else:
|
| 43 |
+
loaded_models[model_choice] = tf.keras.applications.resnet50.ResNet50(weights='imagenet')
|
| 44 |
+
|
| 45 |
+
selected_model = loaded_models[model_choice]
|
| 46 |
+
decoder = tf.keras.applications.mobilenet_v2.decode_predictions if "MobileNet" in model_choice else tf.keras.applications.resnet50.decode_predictions
|
| 47 |
+
|
| 48 |
+
# Preprocessing
|
| 49 |
+
resized_img = cv2.resize(input_img, (224, 224))
|
| 50 |
+
input_tensor = tf.expand_dims(tf.convert_to_tensor(resized_img, dtype=tf.float32), axis=0)
|
| 51 |
+
input_tensor = (input_tensor / 127.5) - 1.0
|
| 52 |
+
|
| 53 |
+
# 1. Baseline Prediction
|
| 54 |
+
base_preds = selected_model.predict(input_tensor)
|
| 55 |
+
base_idx = np.argmax(base_preds[0])
|
| 56 |
+
base_label = decoder(base_preds, top=1)[0][0][1].replace('_', ' ').title()
|
| 57 |
+
base_conf = base_preds[0][base_idx]
|
| 58 |
+
|
| 59 |
+
# 2. Attack Routing
|
| 60 |
+
if attack_choice == "FGSM (Single-Step Speed)":
|
| 61 |
+
one_hot = tf.reshape(tf.one_hot(base_idx, NUM_CLASSES), (1, NUM_CLASSES))
|
| 62 |
+
with tf.GradientTape() as tape:
|
| 63 |
+
tape.watch(input_tensor)
|
| 64 |
+
loss = loss_object(one_hot, selected_model(input_tensor))
|
| 65 |
+
noise_matrix = epsilon * tf.sign(tape.gradient(loss, input_tensor))
|
| 66 |
+
else: # PGD Iterative
|
| 67 |
+
noise_matrix = run_pgd_attack(selected_model, input_tensor, base_idx, epsilon)
|
| 68 |
+
|
| 69 |
+
adversarial_tensor = tf.clip_by_value(input_tensor + noise_matrix, -1.0, 1.0)
|
| 70 |
+
noise_visual = (noise_matrix[0].numpy() - noise_matrix[0].numpy().min()) / (noise_matrix[0].numpy().max() - noise_matrix[0].numpy().min() + 1e-8)
|
| 71 |
+
noise_visual = (noise_visual * 255).astype(np.uint8)
|
| 72 |
+
|
| 73 |
+
# 3. Defense Routing
|
| 74 |
+
img_np = ((adversarial_tensor[0].numpy() + 1) * 127.5).astype(np.uint8)
|
| 75 |
+
if activate_defense:
|
| 76 |
+
if defense_method == "Gaussian Blur": processed = cv2.GaussianBlur(img_np, (5, 5), 0)
|
| 77 |
+
elif defense_method == "Median Filter": processed = cv2.medianBlur(img_np, 5)
|
| 78 |
+
elif defense_method == "JPEG Compression":
|
| 79 |
+
_, res = cv2.imencode('.jpg', img_np, [int(cv2.IMWRITE_JPEG_QUALITY), 30])
|
| 80 |
+
processed = cv2.cvtColor(cv2.imdecode(res, 1), cv2.COLOR_BGR2RGB)
|
| 81 |
+
final_tensor = tf.expand_dims((tf.convert_to_tensor(processed, dtype=tf.float32) / 127.5) - 1.0, axis=0)
|
| 82 |
+
out_display = processed
|
| 83 |
+
else:
|
| 84 |
+
final_tensor = adversarial_tensor
|
| 85 |
+
out_display = img_np
|
| 86 |
+
|
| 87 |
+
# Evaluate final metrics
|
| 88 |
+
final_preds = selected_model.predict(final_tensor)
|
| 89 |
+
final_idx = np.argmax(final_preds[0])
|
| 90 |
+
final_label = decoder(final_preds, top=1)[0][0][1].replace('_', ' ').title()
|
| 91 |
+
final_conf = final_preds[0][final_idx]
|
| 92 |
+
|
| 93 |
+
# HTML formatting
|
| 94 |
+
clean_html = f"<div style='font-size:16px;'>π’ <b>Base:</b> {base_label}<br><b>Confidence:</b> {base_conf*100:.2f}%</div>"
|
| 95 |
+
state_prefix = "π‘οΈ Defended" if activate_defense else "π΄ Hacked"
|
| 96 |
+
final_html = f"<div style='font-size:16px;'><b>{state_prefix}:</b> {final_label}<br><b>Confidence:</b> {final_conf*100:.2f}%</div>"
|
| 97 |
+
|
| 98 |
+
if final_label != base_label:
|
| 99 |
+
summary_html = f"<div style='background-color: #ffe6e6; padding: 12px; border-radius: 8px; color: #b30000;'>β οΈ <b>CRITICAL VULNERABILITY:</b> The target network was successfully exploited. Model confidence dropped by <b>{(base_conf - final_conf)*100:.1f}%</b>.</div>"
|
| 100 |
+
else:
|
| 101 |
+
recovery_bonus = " (Defense Successful!)" if activate_defense else " (Attack Failed)"
|
| 102 |
+
summary_html = f"<div style='background-color: #e6ffe6; padding: 12px; border-radius: 8px; color: #006600;'>β
<b>SYSTEM RESILIENT:</b> Integrity preserved for target class {base_label}{recovery_bonus}.</div>"
|
| 103 |
+
|
| 104 |
+
return resized_img, noise_visual, out_display, clean_html, final_html, summary_html
|
| 105 |
+
|
| 106 |
+
# ====================================================================
|
| 107 |
+
# GRADIO ADVANCED DASHBOARD INTERFACE
|
| 108 |
+
# ====================================================================
|
| 109 |
+
with gr.Blocks() as demo:
|
| 110 |
+
gr.Markdown("# π¦
Enterprise AI Red-Teaming & Vulnerability Assessment Workspace")
|
| 111 |
+
|
| 112 |
+
with gr.Row():
|
| 113 |
+
with gr.Column(scale=1):
|
| 114 |
+
gr.Markdown("### βοΈ Target Settings")
|
| 115 |
+
model_dd = gr.Dropdown(choices=list(loaded_models.keys()), value="MobileNetV2 (Lightweight)", label="Target Model Brain")
|
| 116 |
+
|
| 117 |
+
gr.Markdown("### ποΈ Vector Attack Settings")
|
| 118 |
+
attack_dd = gr.Dropdown(choices=["FGSM (Single-Step Speed)", "PGD (Iterative Precision Hacking)"], value="FGSM (Single-Step Speed)", label="Exploitation Strategy")
|
| 119 |
+
src_image = gr.Image(label="Source Image", type="numpy")
|
| 120 |
+
eps_slider = gr.Slider(minimum=0.005, maximum=0.10, value=0.02, step=0.005, label="Exploit Radius (Ξ΅)")
|
| 121 |
+
|
| 122 |
+
gr.Markdown("### π‘οΈ Mitigation Configuration")
|
| 123 |
+
toggle_def = gr.Checkbox(label="Engage Defensive Sanitation Filters", value=False)
|
| 124 |
+
def_dd = gr.Dropdown(choices=["Gaussian Blur", "Median Filter", "JPEG Compression"], value="Gaussian Blur", label="Sanitation Protocol")
|
| 125 |
+
|
| 126 |
+
run_btn = gr.Button("β‘ Run Threat Assessment", variant="primary")
|
| 127 |
+
|
| 128 |
+
with gr.Column(scale=2):
|
| 129 |
+
gr.Markdown("### π Live Diagnostic Analytics")
|
| 130 |
+
summary_box = gr.HTML("<div style='padding:12px; border: 1px solid #ccc; border-radius:8px;'>Run an assessment to view spatial risk analysis logs.</div>")
|
| 131 |
+
|
| 132 |
+
with gr.Row():
|
| 133 |
+
with gr.Column():
|
| 134 |
+
out_clean = gr.Image(label="π’ Input Reference")
|
| 135 |
+
m_clean = gr.HTML()
|
| 136 |
+
with gr.Column():
|
| 137 |
+
out_noise = gr.Image(label="π₯ Isolated Threat Footprint")
|
| 138 |
+
with gr.Column():
|
| 139 |
+
out_adv = gr.Image(label="π System Terminal State")
|
| 140 |
+
m_adv = gr.HTML()
|
| 141 |
+
|
| 142 |
+
run_btn.click(
|
| 143 |
+
fn=process_advanced_pipeline,
|
| 144 |
+
inputs=[src_image, model_dd, attack_dd, eps_slider, def_dd, toggle_def],
|
| 145 |
+
outputs=[out_clean, out_noise, out_adv, m_clean, m_adv, summary_box]
|
| 146 |
+
)
|
| 147 |
+
|
| 148 |
+
if __name__ == "__main__":
|
| 149 |
+
demo.launch(ssr_mode=False)
|
requirements.txt
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio
|
| 2 |
+
tensorflow
|
| 3 |
+
opencv-python
|
| 4 |
+
numpy
|
| 5 |
+
spaces
|