import gradio as gr
import torch
import torch.nn as nn
from PIL import Image
from torchvision import transforms
import os
from datetime import datetime
from fpdf import FPDF
class MyCNN(nn.Module):
def __init__(self, in_channel, dropout=0.4):
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(in_channel, 32, kernel_size=3, padding="same"), nn.ReLU(), nn.BatchNorm2d(32), nn.MaxPool2d(2),
nn.Conv2d(32, 64, kernel_size=3, padding="same"), nn.ReLU(), nn.BatchNorm2d(64), nn.MaxPool2d(2),
nn.Conv2d(64, 64, kernel_size=3, padding="same"), nn.ReLU(), nn.BatchNorm2d(64), nn.MaxPool2d(2),
nn.Conv2d(64, 64, kernel_size=3, padding="same"), nn.ReLU(), nn.BatchNorm2d(64), nn.MaxPool2d(2),
nn.Conv2d(64, 64, kernel_size=3, padding="same"), nn.ReLU(), nn.BatchNorm2d(64), nn.MaxPool2d(2)
)
self.classifier = nn.Sequential(
nn.Flatten(),
nn.Linear(7*7*64, 128), nn.ReLU(), nn.Dropout(dropout),
nn.Linear(128, 64), nn.ReLU(), nn.Dropout(dropout),
nn.Linear(64, 1)
)
def forward(self, x):
return self.classifier(self.features(x))
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = MyCNN(in_channel=3, dropout=0.4)
try:
model.load_state_dict(torch.load('model_epoch_10.pth', map_location=device))
model.to(device).eval()
except:
pass
transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
def generate_technical_report(verdict, real_conf, ai_conf):
pdf = FPDF()
pdf.add_page()
pdf.set_font("Courier", 'B', 16)
pdf.set_text_color(40, 40, 40)
pdf.cell(200, 10, txt="FORENSIC AUTHENTICITY ANALYSIS DATASHEET", ln=True, align='L')
pdf.set_draw_color(200, 200, 200)
pdf.line(10, 22, 200, 22)
pdf.ln(10)
pdf.set_font("Courier", size=10)
pdf.cell(200, 5, txt=f"Timestamp: {datetime.now().strftime('%Y-%m-%d %H:%M:%S UTC')}", ln=True)
pdf.cell(200, 5, txt=f"Neural Engine: MyCNN-v1.0", ln=True)
pdf.ln(10)
pdf.set_font("Courier", 'B', 12)
pdf.cell(200, 10, txt=f"ANALYSIS VERDICT: {verdict}", ln=True)
pdf.set_font("Courier", size=10)
pdf.cell(200, 7, txt=f"Probability Real: {real_conf:.4f}", ln=True)
pdf.cell(200, 7, txt=f"Probability AI: {ai_conf:.4f}", ln=True)
filename = f"Forensic_Report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf"
pdf.output(filename)
return filename
def analyze_image(image):
if image is None: return None, "", gr.update(visible=False)
img_tensor = transform(image.convert('RGB')).unsqueeze(0).to(device)
with torch.no_grad():
logits = model(img_tensor)
prob = torch.sigmoid(logits).item()
real_conf, ai_conf = prob, 1 - prob
verdict_text = "REAL" if real_conf > 0.5 else "AI GENERATED"
verdict_color = "#ffffff" if real_conf > 0.5 else "#f4812a"
verdict_html = f"""
"""
report_path = generate_technical_report(verdict_text, real_conf, ai_conf)
return {"Real Photo": real_conf, "AI Generated": ai_conf}, verdict_html, gr.update(value=report_path, visible=True)
def clear_all():
return None, None, "", gr.update(visible=False)
custom_css = """
@import url('https://fonts.googleapis.com/css2?family=Rajdhani:wght@400;500;700&display=swap');
body::-webkit-scrollbar { display: none; }
body {
-ms-overflow-style: none;
scrollbar-width: none;
background-color: #080a0c !important;
font-family: 'Rajdhani', sans-serif !important;
}
.gradio-container {
background-color: #080a0c !important;
font-family: 'Rajdhani', sans-serif !important;
}
#main-wrap { max-width: 1000px !important; margin: 40px auto !important; }
.outer-card {
background: #101214 !important;
border: 1px solid #1f2226 !important;
border-radius: 4px !important;
padding: 20px !important;
}
.inner-dotted {
border: 1px dashed #333 !important;
background: #0c0e10 !important;
border-radius: 2px !important;
padding: 15px !important;
margin-top: 10px;
}
.header-area { text-align: center; margin-bottom: 30px; border-bottom: 1px solid #1f2226; padding-bottom: 30px; }
.header-area h1 {
color: #ffffff;
font-family: 'Rajdhani', sans-serif !important;
font-weight: 700;
letter-spacing: 3px;
font-size: 42px;
margin-bottom: 0px;
text-transform: uppercase;
}
.tech-sub {
color: #aaaaaa;
font-family: 'Rajdhani', sans-serif !important;
font-size: 16px;
margin-top: 12px;
max-width: 800px;
margin-left: auto;
margin-right: auto;
line-height: 1.5;
}
#submit-btn { background: #f4812a !important; color: #000000 !important; font-weight: 700 !important; border-radius: 2px !important; border: none !important; cursor: pointer; transition: 0.2s; font-family: 'Rajdhani' !important; }
#submit-btn:hover { background: #cccccc !important; }
#clear-btn { background: #1a1c1e !important; color: #ffffff !important; font-weight: 700 !important; border-radius: 2px !important; border: 1px solid #2d3135 !important; cursor: pointer; font-family: 'Rajdhani' !important; }
.guide-box { margin-top: 20px; padding: 15px; background: #101214; border-radius: 4px; border: 1px solid #1f2226; }
.guide-text { color: #555; font-size: 13px; text-transform: uppercase; letter-spacing: 1px; font-weight: 600; font-family: 'Rajdhani' !important; }
.label-box span { display: none !important; }
.gradio-container .prose h2 {
margin: 0 !important;
color: #ffffff !important;
font-size: 16px !important;
letter-spacing: 1px;
text-transform: uppercase;
font-family: 'Rajdhani' !important;
}
.source-link { text-align: center; margin-top: 50px; }
.source-link a {
color: #ffffff;
text-decoration: none;
font-size: 20px;
letter-spacing: 1px;
transition: 0.3s;
font-family: 'Rajdhani', sans-serif !important;
font-weight: 500;
}
.source-link a:hover { color: #f4812a; }
"""
with gr.Blocks(css=custom_css) as demo:
with gr.Column(elem_id="main-wrap"):
gr.HTML("""
""")
with gr.Row(equal_height=True):
with gr.Column(scale=1, elem_classes="outer-card"):
gr.Markdown("## 01. SOURCE MATERIAL")
with gr.Column(elem_classes="inner-dotted"):
input_img = gr.Image(label="Source", type="pil", show_label=False, container=False)
with gr.Row():
clear_btn = gr.Button("CLEAR", elem_id="clear-btn")
submit_btn = gr.Button("SUBMIT ANALYSIS", elem_id="submit-btn")
with gr.Column(scale=1, elem_classes="outer-card"):
gr.Markdown("## 02. FORENSIC OUTPUT")
with gr.Column(elem_classes="inner-dotted"):
out_verdict = gr.HTML("Awaiting input analysis...
")
out_label = gr.Label(num_top_classes=2, label="Confidence", elem_classes="label-box")
gr.HTML("")
report_file = gr.File(label="DATASHEET", visible=False)
with gr.Row(elem_classes="guide-box"):
gr.HTML("""
STEP 1: UPLOAD TARGET IMAGE
|
STEP 2: INITIATE CNN SCAN
|
STEP 3: EXPORT TECHNICAL PDF
""")
gr.HTML("""
""")
gr.HTML("""
SYSTEM STATUS: OPERATIONAL • BUILD: 5.0.4 • HARDWARE: ACCELERATED
""")
submit_btn.click(
fn=analyze_image,
inputs=input_img,
outputs=[out_label, out_verdict, report_file],
show_progress="full"
)
clear_btn.click(
fn=clear_all,
outputs=[input_img, out_label, out_verdict, report_file]
)
if __name__ == "__main__":
demo.launch()