File size: 6,018 Bytes
99c30b7
9358900
56225c5
bd55878
a448f8b
bd55878
bebc6f9
a448f8b
 
 
bd55878
9c93e59
 
 
 
9358900
342ea4d
a448f8b
bd55878
 
 
 
 
 
9358900
a448f8b
bd55878
 
 
 
a448f8b
bd55878
9358900
342ea4d
 
 
 
 
9358900
 
 
bd55878
342ea4d
9358900
 
 
342ea4d
 
bd55878
 
 
 
 
 
9358900
a448f8b
bebc6f9
 
 
 
a448f8b
bebc6f9
 
342ea4d
bebc6f9
 
342ea4d
bebc6f9
 
 
 
 
 
 
 
 
 
342ea4d
 
bd55878
 
 
 
 
 
 
9358900
bd55878
56225c5
 
 
 
 
bd55878
a448f8b
 
 
 
 
 
 
 
 
342ea4d
bd55878
342ea4d
 
 
bd55878
342ea4d
 
 
 
 
 
56225c5
9c93e59
 
342ea4d
 
 
 
 
 
 
 
9358900
 
 
 
 
342ea4d
9358900
 
 
342ea4d
bd55878
342ea4d
 
 
 
 
 
 
 
 
 
 
 
 
56225c5
bd55878
 
 
 
342ea4d
56225c5
 
342ea4d
 
 
bd55878
 
 
99c30b7
9c93e59
 
 
 
 
 
99c30b7
342ea4d
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
import gradio as gr
from reports.pdf_report import generate_pdf_report
from utils.youtube_utils import download_youtube_video
import modal

verify_faces_remote = modal.Function.lookup("deepface-agent", "verify_faces_remote")
verify_voices_remote = modal.Function.lookup("deepface-agent", "verify_voices_remote")
verify_faces_in_video_remote = modal.Function.lookup(
    "deepface-agent", "verify_faces_in_video_remote"
)


# Holds latest results
last_face_result = None
last_voice_result = None
last_video_results = None


def compare_faces(img1_path: str, img2_path: str) -> str:
    """Use this tool to compare to faces for a match
    Args:
        img1_path: The path to the first image
        img2_path: The path to the second image
    """
    global last_face_result

    # Read image files as bytes
    with open(img1_path, "rb") as f1, open(img2_path, "rb") as f2:
        img1_bytes = f1.read()
        img2_bytes = f2.read()

    result = verify_faces_remote.remote(img1_bytes, img2_bytes)
    result_text = ""

    if "error" in result:
        return f"❌ Error: {result['error']}"

    if result["verified"]:
        result_text = f"βœ… Match! Distance: {result['distance']:.4f} (Threshold: {result['threshold']})"
        last_face_result = result_text
        return result_text

    else:
        result_text = f"❌ No Match. Distance: {result['distance']:.4f} (Threshold: {result['threshold']})"
        last_face_result = result_text
        return result_text


def compare_voices(audio1: str, audio2: str) -> str:
    """Use this tool to compare two voices for a match
    Args:
        audio1: The path to the first audio file
        audio2: The path to the second audio file
    """
    global last_voice_result

    try:
        with open(audio1, "rb") as a1, open(audio2, "rb") as a2:
            audio1_bytes = a1.read()
            audio2_bytes = a2.read()

        result = verify_voices_remote.remote(audio1_bytes, audio2_bytes)
        result_text = ""

        if "error" in result:
            return f"❌ Error: {result['error']}"

        if result["match"]:
            result_text = f"βœ… Same speaker detected. Similarity: {result['similarity']} (Threshold: {result['threshold']})"
            last_voice_result = result_text
            return result_text
        else:
            result_text = f"❌ Different speakers. Similarity: {result['similarity']} (Threshold: {result['threshold']})"
            last_voice_result = result_text
            return result_text
    except Exception as e:
        return f"❌ Error reading audio files: {str(e)}"


def scan_video(video_file: str, ref_img: str, youtube_url="") -> str:
    """Use this tool to scan a video for deepfake face swaps
    Args:
        video_file: The path to the video file
        ref_img: The path to the reference image
        youtube_url: The YouTube URL (optional)
    """
    global last_video_results

    if youtube_url:
        try:
            video_file = download_youtube_video(youtube_url)
        except Exception as e:
            return f"❌ Error downloading YouTube video: {str(e)}"

    with open(video_file, "rb") as vf, open(ref_img, "rb") as rf:
        video_bytes = vf.read()
        ref_img_bytes = rf.read()
    try:
        results = verify_faces_in_video_remote.remote(video_bytes, ref_img_bytes, interval=30)
        
    except Exception as e:
        return f"❌ Error processing  video: {str(e)}"

    report = ""
    last_video_results = results
    for r in results:
        if "error" in r:
            report += f"\n⚠️ Frame {r['frame']}: {r['error']}"

        else:
            status = "βœ… Match" if r["verified"] else "❌ Mismatch"
            report += f"\nπŸ–Ό Frame {r['frame']}: {status} (Distance: {r['distance']})"

    return report


def generate_report():
    return generate_pdf_report(last_face_result, last_voice_result, last_video_results)


with gr.Blocks(title="Deepfake Watchdog") as demo:
    gr.Markdown("# πŸ›‘οΈDeepfake Watchdog πŸ€—")
    gr.Markdown("## Upload your image and/or voice to scan for deepfake misuse online.")

    # Face Verification
    with gr.Tab("Face Verification"):
        image1 = gr.Image(label="Upload your face", type="filepath")
        # audio = gr.Audio(label="Upload your voice (optional)", type="filepath")
        image2 = gr.Image(label="Upload another face", type="filepath")

        # face_btn = gr.Button("Compare Faces")

        run_button = gr.Button("Compare Faces")
        output_text = gr.Textbox(label="Result")
        # output_gallery = gr.Gallery(label="Matched Results")

        run_button.click(compare_faces, inputs=[image1, image2], outputs=[output_text])

    # Voice Verification
    with gr.Tab("🎀 Voice Verification"):
        gr.Markdown("Upload two audio files to check if the voices match.")

        audio1 = gr.Audio(type="filepath", label="Voice Sample 1")
        audio2 = gr.Audio(type="filepath", label="Voice Sample 2")

        voice_btn = gr.Button("Compare Voices")
        voice_output = gr.Textbox(label="Result")

        voice_btn.click(compare_voices, inputs=[audio1, audio2], outputs=voice_output)

    with gr.Tab("πŸ“Ή Video Deepfake Scan"):
        gr.Markdown(
            "πŸ” Upload a video or paste a YouTube link and we'll analyze it for deepfake face swaps."
        )

        ref_img = gr.Image(type="filepath", label="Reference Face")
        video_input = gr.Video(label="Video File (optional)")
        youtube_url = gr.Textbox(label="YouTube URL (optional)")
        scan_btn = gr.Button("Scan Video")
        scan_output = gr.Textbox(label="Scan Results", lines=10)

        scan_btn.click(
            scan_video, inputs=[video_input, ref_img, youtube_url], outputs=scan_output
        )

    with gr.Tab("πŸ“„ Generate Report"):
        report_btn = gr.Button("Generate PDF Report")
        report_output = gr.File(label="Download Report")

        report_btn.click(generate_report, outputs=report_output)


demo.launch(mcp_server=True)