File size: 3,760 Bytes
a972d65
 
717222a
a972d65
 
 
717222a
 
 
 
 
 
a972d65
 
 
 
 
 
 
 
 
 
 
 
 
717222a
 
 
a972d65
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
717222a
 
a972d65
 
 
 
 
 
717222a
a972d65
 
 
 
 
717222a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a972d65
 
 
 
 
 
 
717222a
a972d65
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import torch
from torchvision import transforms
from PIL import Image, ImageOps
import tempfile
import os

from detector_config import (
    ALLOW_LOCAL_MODEL_FALLBACK,
    IMAGE_DETECTOR_BACKEND,
    IMAGE_FAKE_THRESHOLD,
    IMAGE_UNCERTAIN_MARGIN,
)
from model_loader import get_image_model


def build_image_insight(result, confidence, fake_score, real_score):
    margin = abs(fake_score - real_score) * 100

    if confidence >= 90:
        certainty = "High"
    elif confidence >= 70:
        certainty = "Moderate"
    else:
        certainty = "Low"

    if result == "Uncertain":
        summary = "The detector did not find a large enough gap between fake and real evidence."
    elif certainty == "Low":
        summary = "The model is not strongly confident. Treat this as a signal, not a final judgement."
    elif result == "Fake":
        summary = "The image contains patterns the model associates with manipulated or synthetic content."
    else:
        summary = "The image looks closer to authentic content based on the model's learned patterns."

    return {
        "certainty": certainty,
        "summary": summary,
        "scores": {
            "fake": round(fake_score * 100, 2),
            "real": round(real_score * 100, 2),
        },
        "metrics": {
            "confidence": round(confidence, 2),
            "score_gap": round(margin, 2),
            "uncertainty": round(100 - confidence, 2),
            "consistency": 100,
        },
        "risk_level": "High" if result == "Fake" and confidence >= 80 else "Medium" if result == "Fake" else "Low",
    }


transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(
        [0.485, 0.456, 0.406],
        [0.229, 0.224, 0.225]
    )
])

def detect_deepfake(file):
    with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as temp:
        file.save(temp.name)
        path = temp.name

    try:
        image = ImageOps.exif_transpose(Image.open(path)).convert("RGB")

        if IMAGE_DETECTOR_BACKEND == "huggingface":
            try:
                from hf_detectors import get_hf_image_detector

                result = get_hf_image_detector().predict(
                    image,
                    threshold=IMAGE_FAKE_THRESHOLD,
                    uncertain_margin=IMAGE_UNCERTAIN_MARGIN,
                )
                result["insight"] = build_image_insight(
                    result["result"],
                    result["confidence"],
                    result["fake_score"] / 100,
                    result["real_score"] / 100,
                )
                return result
            except Exception as error:
                if not ALLOW_LOCAL_MODEL_FALLBACK:
                    return {"error": f"Hugging Face image detector failed: {error}"}

        img = transform(image).unsqueeze(0)

        with torch.no_grad():
            output = get_image_model()(img)
            fake_score = torch.sigmoid(output).item()
            real_score = 1 - fake_score

        THRESHOLD = IMAGE_FAKE_THRESHOLD

        if fake_score > THRESHOLD:
            result = "Fake"
            confidence = fake_score
        else:
            result = "Real"
            confidence = real_score

        return {
            "result": result,
            "confidence": round(confidence * 100, 2),
            "fake_score": round(fake_score * 100, 2),
            "real_score": round(real_score * 100, 2),
            "raw_probability": round(fake_score, 6),
            "insight": build_image_insight(result, confidence * 100, fake_score, real_score),
        }

    except Exception as e:
        return {"error": str(e)}

    finally:
        if os.path.exists(path):
            os.remove(path)