File size: 7,958 Bytes
df2470d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# === FASTAPI BACKEND (main.py) ===

from fastapi import FastAPI, UploadFile, File, HTTPException
from fastapi.responses import JSONResponse
from fastapi.middleware.cors import CORSMiddleware
from transformers import pipeline
from PIL import Image
import io
import torch
import numpy as np
import cv2
import base64

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

device = 0 if torch.cuda.is_available() else -1

MODELS_CONFIG = {
    "SwinV2 Based": {"path": "haywoodsloan/ai-image-detector-deploy", "weight": 0.15},
    "ViT Based": {"path": "Heem2/AI-vs-Real-Image-Detection", "weight": 0.15},
    "SDXL Dataset": {"path": "Organika/sdxl-detector", "weight": 0.15},
    "SDXL + FLUX": {"path": "cmckinle/sdxl-flux-detector_v1.1", "weight": 0.15},
    "DeepFake v2": {"path": "prithivMLmods/Deep-Fake-Detector-v2-Model", "weight": 0.15},
    "Midjourney/SDXL": {"path": "ideepankarsharma2003/AI_ImageClassification_MidjourneyV6_SDXL", "weight": 0.10},
    "ViT v4": {"path": "date3k2/vit-real-fake-classification-v4", "weight": 0.15},
}

models = {}
for name, config in MODELS_CONFIG.items():
    try:
        models[name] = pipeline("image-classification", model=config["path"], device=device)
    except Exception as e:
        print(f"Failed to load model {name}: {e}")

def pil_to_base64(image):
    buffered = io.BytesIO()
    image.save(buffered, format="JPEG")
    return "data:image/jpeg;base64," + base64.b64encode(buffered.getvalue()).decode("utf-8")

def gen_ela(img_array, quality=90):
    if img_array.shape[2] == 4:
        img_array = cv2.cvtColor(img_array, cv2.COLOR_RGBA2RGB)
    encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), quality]
    _, buffer = cv2.imencode('.jpg', img_array, encode_param)
    compressed_img = cv2.imdecode(buffer, cv2.IMREAD_COLOR)
    ela_img = cv2.absdiff(img_array, compressed_img)
    ela_img = cv2.convertScaleAbs(ela_img, alpha=10)
    return Image.fromarray(cv2.cvtColor(ela_img, cv2.COLOR_BGR2RGB))

def gradient_processing(image_array):
    gray_img = cv2.cvtColor(image_array, cv2.COLOR_BGR2GRAY)
    dx = cv2.Sobel(gray_img, cv2.CV_64F, 1, 0, ksize=3)
    dy = cv2.Sobel(gray_img, cv2.CV_64F, 0, 1, ksize=3)
    gradient_magnitude = cv2.magnitude(dx, dy)
    gradient_img = cv2.normalize(gradient_magnitude, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)
    return Image.fromarray(gradient_img)

@app.post("/detect")
async def detect(image: UploadFile = File(...)):
    try:
        import time
        start_time = time.time()

        image_bytes = await image.read()
        input_image = Image.open(io.BytesIO(image_bytes)).convert("RGB")

        img_np = np.array(input_image)
        img_bgr = cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR)

        individual_results = []
        weighted_ai_score = 0
        total_weight = 0

        aiModels = []
        colors = ["bg-red-500", "bg-orange-500", "bg-yellow-500", "bg-green-500", "bg-blue-500", "bg-purple-500", "bg-pink-500"]

        for i, (name, model_pipeline) in enumerate(models.items()):
            model_weight = MODELS_CONFIG[name]["weight"]
            predictions = model_pipeline(input_image)
            confidence = {p['label'].lower(): p['score'] for p in predictions}

            artificial_score = (
                confidence.get('artificial', 0) or confidence.get('ai image', 0) or
                confidence.get('ai', 0) or confidence.get('deepfake', 0) or
                confidence.get('ai_gen', 0) or confidence.get('fake', 0)
            )
            real_score = (
                confidence.get('real', 0) or confidence.get('real image', 0) or
                confidence.get('human', 0) or confidence.get('realism', 0)
            )

            if artificial_score > 0 and real_score == 0:
                real_score = 1.0 - artificial_score
            elif real_score > 0 and artificial_score == 0:
                artificial_score = 1.0 - real_score

            weighted_ai_score += artificial_score * model_weight
            total_weight += model_weight

            aiModels.append({
                "name": name,
                "percentage": round(artificial_score * 100, 2),
                "color": colors[i % len(colors)]
            })

        final_score = (weighted_ai_score / total_weight) * 100 if total_weight > 0 else 0
        verdict = final_score > 50
        processing_time = int((time.time() - start_time) * 1000)

        # Forensics
        ela_img = gen_ela(img_bgr)
        gradient_img = gradient_processing(img_bgr)

        return JSONResponse({
            "filename": image.filename,
            "isDeepfake": verdict,
            "confidence": round(final_score, 2),
            "aiModels": aiModels,
            "processingTime": processing_time,
            "forensics": {
                "original": pil_to_base64(input_image),
                "ela": pil_to_base64(ela_img),
                "gradient": pil_to_base64(gradient_img)
            },
            "verdictMessage": f"Consensus: {'Likely AI-Generated' if verdict else 'Likely Human-Made (Real)'}"
        })
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))



# === Add this new code to the bottom of your deepfake_api.py file ===
import os
import google.generativeai as genai
from pydantic import BaseModel, Field
from typing import List, Dict, Any

# Configure the Gemini API with the key from Hugging Face secrets
gemini_api_key = os.getenv("GOOGLE_API_KEY")
if gemini_api_key:
    genai.configure(api_key=gemini_api_key)

# Define Pydantic models to validate the incoming data structure
class AIModelResult(BaseModel):
    name: str
    percentage: float

class ForensicResult(BaseModel):
    original: str
    ela: str
    gradient: str

class DetectionResult(BaseModel):
    filename: str
    isDeepfake: bool
    confidence: float
    aiModels: List[AIModelResult]
    processingTime: int
    forensics: ForensicResult
    verdictMessage: str

# New endpoint to generate the report
@app.post("/generate-report")
async def generate_report(result: DetectionResult):
    if not gemini_api_key:
        raise HTTPException(status_code=500, detail="Google API key is not configured.")

    try:
        model = genai.GenerativeModel('gemini-1.5-flash')

        # Create a detailed prompt for the AI
        prompt = f"""
        You are an AI image forensics analyst. Your task is to generate a professional report based on the JSON data from a deepfake detection scan.

        The user has scanned the file: "{result.filename}".

        Here is the JSON data from the scan:
        {{
            "isDeepfake": {result.isDeepfake},
            "overall_confidence_score": {result.confidence}%,
            "verdict": "{result.verdictMessage}",
            "model_analysis": { {model.name: f"{model.percentage}%" for model in result.aiModels} }
        }}

        Please generate a report with the following structure using Markdown:

        ## Forensic Analysis Report: {result.filename}

        ### **Executive Summary**
        Provide a brief, high-level summary of the findings. State the final verdict clearly and the overall confidence score.

        ### **Detailed Model Analysis**
        Analyze the results from the individual AI models. Mention the models with the highest confidence scores (e.g., Midjourney/SDXL, SDXL Dataset) and explain what their findings imply.

        ### **Conclusion & Recommendation**
        Provide a final conclusion based on the combined evidence. Recommend next steps, such as whether the image can be trusted or if further manual analysis is required.
        """

        # Generate the report
        response = model.generate_content(prompt)

        return {"report": response.text}

    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Failed to generate report: {str(e)}")