Commit ·
2a9c2e2
1
Parent(s): 4622f70
Update app.py with new UI changes
Browse files
app.py
CHANGED
|
@@ -9,52 +9,92 @@ from image_backend import predict_image_pil
|
|
| 9 |
# =========================
|
| 10 |
def analyze_image(image):
|
| 11 |
if image is None:
|
| 12 |
-
return "", "", "", None,
|
| 13 |
|
| 14 |
label, confidence, heatmap = predict_image_pil(image)
|
| 15 |
|
| 16 |
-
# Risk classification
|
| 17 |
if label == "Fake":
|
| 18 |
if confidence >= 90:
|
| 19 |
-
|
| 20 |
message = "High likelihood of deepfake"
|
| 21 |
elif confidence >= 60:
|
| 22 |
-
|
| 23 |
message = "Possibly deepfake"
|
| 24 |
else:
|
| 25 |
-
|
| 26 |
message = "Uncertain deepfake"
|
| 27 |
else:
|
| 28 |
if confidence >= 90:
|
| 29 |
-
|
| 30 |
message = "Likely real"
|
| 31 |
elif confidence >= 60:
|
| 32 |
-
|
| 33 |
message = "Possibly real"
|
| 34 |
else:
|
| 35 |
-
|
| 36 |
message = "Uncertain - review needed"
|
| 37 |
|
| 38 |
risk_html = f"""
|
| 39 |
-
<div class="risk-card {
|
| 40 |
<div class="risk-title">{label}</div>
|
| 41 |
<div class="risk-msg">{message}</div>
|
| 42 |
</div>
|
| 43 |
"""
|
| 44 |
|
| 45 |
-
return
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
|
| 53 |
|
| 54 |
# =========================
|
| 55 |
# UI
|
| 56 |
# =========================
|
| 57 |
-
with gr.Blocks() as demo:
|
| 58 |
|
| 59 |
# HEADER
|
| 60 |
gr.Markdown('<div class="header">AI Deepfake Detection Dashboard</div>')
|
|
@@ -65,26 +105,26 @@ with gr.Blocks() as demo:
|
|
| 65 |
gr.Markdown("""
|
| 66 |
### 🔍 System Overview
|
| 67 |
This system detects whether an uploaded image is **real or AI-generated (deepfake)**
|
| 68 |
-
using deep learning-based image forensics techniques. It focuses on
|
| 69 |
-
|
| 70 |
""")
|
| 71 |
|
| 72 |
# =========================
|
| 73 |
-
# MODEL
|
| 74 |
# =========================
|
| 75 |
gr.Markdown("""
|
| 76 |
### 🧠 Model Details
|
| 77 |
-
- Transformer/
|
| 78 |
-
- Learns fine-grained facial
|
| 79 |
-
- Trained on
|
| 80 |
-
- Uses attention mechanisms for explainability
|
| 81 |
""")
|
| 82 |
|
| 83 |
# STATUS
|
| 84 |
status = gr.HTML('<div class="status">Status: Idle</div>')
|
| 85 |
|
| 86 |
# =========================
|
| 87 |
-
# MAIN
|
| 88 |
# =========================
|
| 89 |
with gr.Row():
|
| 90 |
|
|
@@ -92,10 +132,7 @@ with gr.Blocks() as demo:
|
|
| 92 |
with gr.Column(scale=1):
|
| 93 |
gr.Markdown("### 📤 Upload Image")
|
| 94 |
|
| 95 |
-
image_input = gr.Image(
|
| 96 |
-
type="pil",
|
| 97 |
-
height=300
|
| 98 |
-
)
|
| 99 |
|
| 100 |
img_submit = gr.Button("Analyze", variant="primary")
|
| 101 |
img_clear = gr.Button("Reset")
|
|
@@ -119,14 +156,14 @@ with gr.Blocks() as demo:
|
|
| 119 |
# =========================
|
| 120 |
gr.Markdown("""
|
| 121 |
### 📖 How to Interpret Results
|
| 122 |
-
- **Prediction** → Real / Fake
|
| 123 |
-
- **Confidence** → Model certainty
|
| 124 |
- **Heatmap** → Highlights regions influencing the decision
|
| 125 |
-
- **Risk
|
| 126 |
- 🔴 High → Strong deepfake indication
|
| 127 |
- 🟡 Warning → Possible manipulation
|
| 128 |
-
- ⚪ Neutral → Uncertain (manual review
|
| 129 |
-
- 🟢 Real → Likely authentic
|
| 130 |
""")
|
| 131 |
|
| 132 |
# =========================
|
|
@@ -134,10 +171,10 @@ with gr.Blocks() as demo:
|
|
| 134 |
# =========================
|
| 135 |
gr.Markdown("""
|
| 136 |
### ⚠️ Limitations
|
| 137 |
-
-
|
| 138 |
-
- May struggle with
|
| 139 |
-
- Works best on face-centric
|
| 140 |
-
- Not a
|
| 141 |
""")
|
| 142 |
|
| 143 |
# =========================
|
|
@@ -145,9 +182,9 @@ with gr.Blocks() as demo:
|
|
| 145 |
# =========================
|
| 146 |
gr.Markdown("""
|
| 147 |
### 🔐 Privacy & Usage
|
| 148 |
-
- Images are processed temporarily and not stored
|
| 149 |
-
- Intended for
|
| 150 |
-
-
|
| 151 |
""")
|
| 152 |
|
| 153 |
# =========================
|
|
@@ -166,4 +203,4 @@ with gr.Blocks() as demo:
|
|
| 166 |
)
|
| 167 |
|
| 168 |
|
| 169 |
-
demo.launch(
|
|
|
|
| 9 |
# =========================
|
| 10 |
def analyze_image(image):
|
| 11 |
if image is None:
|
| 12 |
+
return "", "", "", None, "Idle"
|
| 13 |
|
| 14 |
label, confidence, heatmap = predict_image_pil(image)
|
| 15 |
|
|
|
|
| 16 |
if label == "Fake":
|
| 17 |
if confidence >= 90:
|
| 18 |
+
risk = "high"
|
| 19 |
message = "High likelihood of deepfake"
|
| 20 |
elif confidence >= 60:
|
| 21 |
+
risk = "warning"
|
| 22 |
message = "Possibly deepfake"
|
| 23 |
else:
|
| 24 |
+
risk = "neutral"
|
| 25 |
message = "Uncertain deepfake"
|
| 26 |
else:
|
| 27 |
if confidence >= 90:
|
| 28 |
+
risk = "real"
|
| 29 |
message = "Likely real"
|
| 30 |
elif confidence >= 60:
|
| 31 |
+
risk = "warning"
|
| 32 |
message = "Possibly real"
|
| 33 |
else:
|
| 34 |
+
risk = "neutral"
|
| 35 |
message = "Uncertain - review needed"
|
| 36 |
|
| 37 |
risk_html = f"""
|
| 38 |
+
<div class="risk-card {risk}">
|
| 39 |
<div class="risk-title">{label}</div>
|
| 40 |
<div class="risk-msg">{message}</div>
|
| 41 |
</div>
|
| 42 |
"""
|
| 43 |
|
| 44 |
+
return label, f"{confidence} %", risk_html, heatmap, "Completed"
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
# =========================
|
| 48 |
+
# CSS
|
| 49 |
+
# =========================
|
| 50 |
+
css = """
|
| 51 |
+
body { background-color: #0f172a; }
|
| 52 |
+
|
| 53 |
+
.header {
|
| 54 |
+
text-align: center;
|
| 55 |
+
padding: 10px;
|
| 56 |
+
font-size: 26px;
|
| 57 |
+
font-weight: bold;
|
| 58 |
+
color: white;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
.section {
|
| 62 |
+
color: #cbd5f5;
|
| 63 |
+
margin-bottom: 10px;
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
.gr-box {
|
| 67 |
+
border-radius: 12px !important;
|
| 68 |
+
background: #1e293b !important;
|
| 69 |
+
padding: 15px !important;
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
.risk-card {
|
| 73 |
+
padding: 15px;
|
| 74 |
+
border-radius: 10px;
|
| 75 |
+
color: white;
|
| 76 |
+
font-weight: bold;
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
.risk-card.real { background: #16a34a; }
|
| 80 |
+
.risk-card.high { background: #dc2626; }
|
| 81 |
+
.risk-card.warning { background: #f59e0b; }
|
| 82 |
+
.risk-card.neutral { background: #64748b; }
|
| 83 |
+
|
| 84 |
+
.status {
|
| 85 |
+
padding: 6px 12px;
|
| 86 |
+
border-radius: 20px;
|
| 87 |
+
background: #334155;
|
| 88 |
+
color: white;
|
| 89 |
+
display: inline-block;
|
| 90 |
+
}
|
| 91 |
+
"""
|
| 92 |
|
| 93 |
|
| 94 |
# =========================
|
| 95 |
# UI
|
| 96 |
# =========================
|
| 97 |
+
with gr.Blocks(css=css) as demo:
|
| 98 |
|
| 99 |
# HEADER
|
| 100 |
gr.Markdown('<div class="header">AI Deepfake Detection Dashboard</div>')
|
|
|
|
| 105 |
gr.Markdown("""
|
| 106 |
### 🔍 System Overview
|
| 107 |
This system detects whether an uploaded image is **real or AI-generated (deepfake)**
|
| 108 |
+
using deep learning-based image forensics techniques. It focuses on **facial artifact detection**
|
| 109 |
+
and spatial inconsistencies introduced during synthetic image generation.
|
| 110 |
""")
|
| 111 |
|
| 112 |
# =========================
|
| 113 |
+
# MODEL INFO
|
| 114 |
# =========================
|
| 115 |
gr.Markdown("""
|
| 116 |
### 🧠 Model Details
|
| 117 |
+
- Based on **Transformer/CNN hybrid architecture**
|
| 118 |
+
- Learns **fine-grained facial artifacts**
|
| 119 |
+
- Trained on deepfake datasets with real vs manipulated images
|
| 120 |
+
- Uses **attention mechanisms** for explainability
|
| 121 |
""")
|
| 122 |
|
| 123 |
# STATUS
|
| 124 |
status = gr.HTML('<div class="status">Status: Idle</div>')
|
| 125 |
|
| 126 |
# =========================
|
| 127 |
+
# MAIN UI
|
| 128 |
# =========================
|
| 129 |
with gr.Row():
|
| 130 |
|
|
|
|
| 132 |
with gr.Column(scale=1):
|
| 133 |
gr.Markdown("### 📤 Upload Image")
|
| 134 |
|
| 135 |
+
image_input = gr.Image(type="pil", height=300)
|
|
|
|
|
|
|
|
|
|
| 136 |
|
| 137 |
img_submit = gr.Button("Analyze", variant="primary")
|
| 138 |
img_clear = gr.Button("Reset")
|
|
|
|
| 156 |
# =========================
|
| 157 |
gr.Markdown("""
|
| 158 |
### 📖 How to Interpret Results
|
| 159 |
+
- **Prediction** → Final classification (Real / Fake)
|
| 160 |
+
- **Confidence** → Model certainty score
|
| 161 |
- **Heatmap** → Highlights regions influencing the decision
|
| 162 |
+
- **Risk Level**:
|
| 163 |
- 🔴 High → Strong deepfake indication
|
| 164 |
- 🟡 Warning → Possible manipulation
|
| 165 |
+
- ⚪ Neutral → Uncertain (manual review required)
|
| 166 |
+
- 🟢 Real → Likely authentic image
|
| 167 |
""")
|
| 168 |
|
| 169 |
# =========================
|
|
|
|
| 171 |
# =========================
|
| 172 |
gr.Markdown("""
|
| 173 |
### ⚠️ Limitations
|
| 174 |
+
- Performance may drop on **low-resolution or heavily compressed images**
|
| 175 |
+
- May struggle with **high-quality GAN-generated content**
|
| 176 |
+
- Works best on **face-centric images**
|
| 177 |
+
- Not a replacement for human forensic analysis
|
| 178 |
""")
|
| 179 |
|
| 180 |
# =========================
|
|
|
|
| 182 |
# =========================
|
| 183 |
gr.Markdown("""
|
| 184 |
### 🔐 Privacy & Usage
|
| 185 |
+
- Images are processed temporarily and not stored
|
| 186 |
+
- Intended for **educational and research purposes**
|
| 187 |
+
- Should be used as a **decision-support tool only**
|
| 188 |
""")
|
| 189 |
|
| 190 |
# =========================
|
|
|
|
| 203 |
)
|
| 204 |
|
| 205 |
|
| 206 |
+
demo.launch()
|
style.css
DELETED
|
@@ -1,129 +0,0 @@
|
|
| 1 |
-
/* =========================
|
| 2 |
-
GLOBAL BACKGROUND
|
| 3 |
-
========================= */
|
| 4 |
-
body {
|
| 5 |
-
background-color: #0f172a;
|
| 6 |
-
font-family: 'Segoe UI', sans-serif;
|
| 7 |
-
}
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
/* =========================
|
| 11 |
-
HEADER
|
| 12 |
-
========================= */
|
| 13 |
-
.header {
|
| 14 |
-
text-align: center;
|
| 15 |
-
padding: 12px;
|
| 16 |
-
font-size: 26px;
|
| 17 |
-
font-weight: 600;
|
| 18 |
-
color: #ffffff;
|
| 19 |
-
}
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
/* =========================
|
| 23 |
-
TEXT SECTIONS
|
| 24 |
-
========================= */
|
| 25 |
-
.section {
|
| 26 |
-
color: #cbd5f5;
|
| 27 |
-
margin-bottom: 10px;
|
| 28 |
-
line-height: 1.6;
|
| 29 |
-
}
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
/* =========================
|
| 33 |
-
CARD / CONTAINER STYLE
|
| 34 |
-
========================= */
|
| 35 |
-
.gr-box {
|
| 36 |
-
border-radius: 12px !important;
|
| 37 |
-
background: #1e293b !important;
|
| 38 |
-
padding: 15px !important;
|
| 39 |
-
border: 1px solid #334155;
|
| 40 |
-
}
|
| 41 |
-
|
| 42 |
-
.gr-row {
|
| 43 |
-
gap: 15px;
|
| 44 |
-
}
|
| 45 |
-
|
| 46 |
-
.gr-column {
|
| 47 |
-
gap: 10px;
|
| 48 |
-
}
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
/* =========================
|
| 52 |
-
BUTTONS
|
| 53 |
-
========================= */
|
| 54 |
-
button {
|
| 55 |
-
border-radius: 8px !important;
|
| 56 |
-
font-weight: 500;
|
| 57 |
-
}
|
| 58 |
-
|
| 59 |
-
button:hover {
|
| 60 |
-
opacity: 0.9;
|
| 61 |
-
}
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
/* =========================
|
| 65 |
-
RISK CARDS
|
| 66 |
-
========================= */
|
| 67 |
-
.risk-card {
|
| 68 |
-
padding: 15px;
|
| 69 |
-
border-radius: 10px;
|
| 70 |
-
color: white;
|
| 71 |
-
font-weight: 600;
|
| 72 |
-
margin-top: 10px;
|
| 73 |
-
}
|
| 74 |
-
|
| 75 |
-
.risk-title {
|
| 76 |
-
font-size: 18px;
|
| 77 |
-
margin-bottom: 5px;
|
| 78 |
-
}
|
| 79 |
-
|
| 80 |
-
.risk-msg {
|
| 81 |
-
font-size: 14px;
|
| 82 |
-
opacity: 0.9;
|
| 83 |
-
}
|
| 84 |
-
|
| 85 |
-
.risk-card.real {
|
| 86 |
-
background: #16a34a; /* Green */
|
| 87 |
-
}
|
| 88 |
-
|
| 89 |
-
.risk-card.high {
|
| 90 |
-
background: #dc2626; /* Red */
|
| 91 |
-
}
|
| 92 |
-
|
| 93 |
-
.risk-card.warning {
|
| 94 |
-
background: #f59e0b; /* Yellow */
|
| 95 |
-
}
|
| 96 |
-
|
| 97 |
-
.risk-card.neutral {
|
| 98 |
-
background: #64748b; /* Gray */
|
| 99 |
-
}
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
/* =========================
|
| 103 |
-
STATUS BADGE
|
| 104 |
-
========================= */
|
| 105 |
-
.status {
|
| 106 |
-
padding: 6px 12px;
|
| 107 |
-
border-radius: 20px;
|
| 108 |
-
background: #334155;
|
| 109 |
-
color: #ffffff;
|
| 110 |
-
display: inline-block;
|
| 111 |
-
font-size: 14px;
|
| 112 |
-
margin-bottom: 10px;
|
| 113 |
-
}
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
/* =========================
|
| 117 |
-
IMAGE + OUTPUT SPACING
|
| 118 |
-
========================= */
|
| 119 |
-
img {
|
| 120 |
-
border-radius: 10px;
|
| 121 |
-
}
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
/* =========================
|
| 125 |
-
HEADINGS
|
| 126 |
-
========================= */
|
| 127 |
-
h1, h2, h3 {
|
| 128 |
-
color: #ffffff;
|
| 129 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|