File size: 2,849 Bytes
46d358c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
818dddb
 
46d358c
a434b46
818dddb
46d358c
 
818dddb
46d358c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1ec99ee
 
46d358c
 
 
 
 
a61cc17
 
 
 
818dddb
 
a61cc17
818dddb
46d358c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
818dddb
 
46d358c
818dddb
46d358c
818dddb
46d358c
 
 
 
 
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
"""
Explainability utilities for deepfake detection.

Provides structured risk explanations with evidence summaries
for image, video, audio, and multimodal analysis.
"""


def explain_risk(score, model_scores=None):
    """
    Generate structured risk explanation for image/video analysis.

    Args:
        score: Final risk score (0.0 - 1.0).
        model_scores: Optional dict of per-model scores for evidence.

    Returns:
        str with detailed risk explanation.
    """
    if score >= 0.60:
        level = "AI-GENERATED"
        desc = "Strong indicators of AI generation or manipulation"
    else:
        level = "AUTHENTIC"
        desc = "No significant manipulation indicators"

    explanation = f"{level}{desc}"

    if model_scores:
        evidence = []
        if model_scores.get("vit_prob", 0) > 0.6:
            evidence.append("ViT detected deepfake patterns")
        if model_scores.get("face_prob", 0) > 0.6:
            evidence.append("facial manipulation artifacts found")
        if model_scores.get("forensic_prob", 0) > 0.5:
            evidence.append("noise/ELA inconsistency detected")
        if model_scores.get("frequency_prob", 0) > 0.5:
            evidence.append("frequency-domain anomalies")
        if model_scores.get("eff_prob", 0) > 0.6:
            evidence.append("EfficientNet flagged AI generation")
        if model_scores.get("dino_prob", 0) > 0.6:
            evidence.append("DINOv2 detected synthetic features")
        if model_scores.get("clip_prob", 0) > 0.6:
            evidence.append("CLIP vision-language model detected manipulation signatures")

        if evidence:
            explanation += f". Evidence: {'; '.join(evidence)}"

    return explanation


def explain_audio_risk(fake_prob):
    """Explain audio deepfake risk level."""
    if fake_prob >= 0.60:
        return "AI-GENERATED — AI-generated speech detected (voice cloning / TTS)"
    else:
        return "AUTHENTIC — Audio appears authentic"


def explain_multimodal(modality_scores, final_score):
    """
    Generate explanation for multimodal fusion result.

    Args:
        modality_scores: dict with image/video/audio scores.
        final_score: fused risk score.

    Returns:
        str explanation.
    """
    active = {k: v for k, v in modality_scores.items() if v is not None}

    if not active:
        return "No modalities analyzed"

    parts = []
    for mod, score in active.items():
        if score >= 60:
            parts.append(f"{mod}: AI-generated ({score}%)")
        else:
            parts.append(f"{mod}: authentic ({score}%)")

    if final_score >= 0.60:
        verdict = "Strong evidence of manipulation across modalities"
    else:
        verdict = "Content appears authentic across analyzed modalities"

    return f"{verdict}. Per-modality: {'; '.join(parts)}"