Spaces:
Running
Running
Commit
·
15fccb8
1
Parent(s):
fa55b66
Refactor forgery detection process and improve result aggregation in forgery_routes.py
Browse files- app/api/forgery_routes.py +63 -34
- app/services/deepfake_video_detection.py +43 -0
- models/deepfake_videos.h5 +3 -0
app/api/forgery_routes.py
CHANGED
@@ -6,8 +6,9 @@ from app.services.gan_detection_service import GANDetectionService
|
|
6 |
from app.utils.file_utils import download_file, remove_temp_file, get_file_content
|
7 |
from app.utils.forgery_image_utils import detect_face
|
8 |
from app.utils.forgery_video_utils import extract_audio, extract_frames, compress_and_process_video, detect_speech # Adjust the import path if necessary
|
9 |
-
|
10 |
import os
|
|
|
11 |
import logging
|
12 |
import traceback
|
13 |
from pydantic import BaseModel
|
@@ -22,6 +23,8 @@ image_manipulation_service = ImageManipulationService()
|
|
22 |
face_manipulation_service = FaceManipulationService()
|
23 |
audio_deepfake_service = AudioDeepfakeService()
|
24 |
gan_detection_service = GANDetectionService()
|
|
|
|
|
25 |
|
26 |
def parse_confidence(value):
|
27 |
if isinstance(value, str):
|
@@ -86,6 +89,17 @@ async def process_image(firebase_filename: str):
|
|
86 |
logging.info(f"Image processing completed for: {firebase_filename}")
|
87 |
return results
|
88 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
async def process_video(firebase_filename: str):
|
90 |
logging.info(f"Starting video processing for: {firebase_filename}")
|
91 |
try:
|
@@ -100,14 +114,13 @@ async def process_video(firebase_filename: str):
|
|
100 |
audio_content = get_file_content(audio_filename)
|
101 |
if detect_speech(audio_content):
|
102 |
logging.info("Speech detected in the audio")
|
103 |
-
|
104 |
-
is_audio_deepfake = audio_deepfake_result["prediction"] == "Fake"
|
105 |
else:
|
106 |
logging.info("No speech detected in the audio")
|
107 |
await remove_temp_file(audio_filename)
|
108 |
logging.info(f"Temporary audio file removed: {audio_filename}")
|
109 |
else:
|
110 |
-
logging.
|
111 |
|
112 |
results = {"is_audio_deepfake": is_audio_deepfake}
|
113 |
|
@@ -115,45 +128,61 @@ async def process_video(firebase_filename: str):
|
|
115 |
logging.info(f"Frames extracted: {len(frames)} frames")
|
116 |
|
117 |
results.update({
|
118 |
-
"image_manipulation":
|
119 |
-
|
120 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
121 |
})
|
122 |
|
123 |
face_frames = []
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
has_face = detect_face(frame_content)
|
129 |
-
logging.info(f"Face detection result for {frame_filename}: {'Face detected' if has_face else 'No face detected'}")
|
130 |
-
|
131 |
-
results["image_manipulation"].append(image_manipulation_service.detect_manipulation(frame_filename))
|
132 |
-
results["gan_detection"].append(gan_detection_service.detect_gan(frame_filename))
|
133 |
|
|
|
|
|
|
|
134 |
if has_face:
|
135 |
-
face_frames.append(
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
for
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
152 |
logging.info(f"Aggregated results: {results}")
|
153 |
|
154 |
await remove_temp_file(compressed_video_filename)
|
155 |
-
|
|
|
|
|
156 |
logging.info(f"Video processing completed for: {firebase_filename}")
|
|
|
157 |
return results
|
158 |
except Exception as e:
|
159 |
logging.error(f"Error processing video: {e}")
|
|
|
6 |
from app.utils.file_utils import download_file, remove_temp_file, get_file_content
|
7 |
from app.utils.forgery_image_utils import detect_face
|
8 |
from app.utils.forgery_video_utils import extract_audio, extract_frames, compress_and_process_video, detect_speech # Adjust the import path if necessary
|
9 |
+
from app.services.deepfake_video_detection import DeepfakeVideoDetectionService
|
10 |
import os
|
11 |
+
import numpy as np
|
12 |
import logging
|
13 |
import traceback
|
14 |
from pydantic import BaseModel
|
|
|
23 |
face_manipulation_service = FaceManipulationService()
|
24 |
audio_deepfake_service = AudioDeepfakeService()
|
25 |
gan_detection_service = GANDetectionService()
|
26 |
+
deepfake_video_detection_service = DeepfakeVideoDetectionService()
|
27 |
+
|
28 |
|
29 |
def parse_confidence(value):
|
30 |
if isinstance(value, str):
|
|
|
89 |
logging.info(f"Image processing completed for: {firebase_filename}")
|
90 |
return results
|
91 |
|
92 |
+
def convert_to_python_types(obj):
|
93 |
+
if isinstance(obj, np.generic):
|
94 |
+
return obj.item()
|
95 |
+
elif isinstance(obj, (list, tuple)):
|
96 |
+
return [convert_to_python_types(item) for item in obj]
|
97 |
+
elif isinstance(obj, dict):
|
98 |
+
return {key: convert_to_python_types(value) for key, value in obj.items()}
|
99 |
+
elif isinstance(obj, np.ndarray):
|
100 |
+
return obj.tolist()
|
101 |
+
return obj
|
102 |
+
|
103 |
async def process_video(firebase_filename: str):
|
104 |
logging.info(f"Starting video processing for: {firebase_filename}")
|
105 |
try:
|
|
|
114 |
audio_content = get_file_content(audio_filename)
|
115 |
if detect_speech(audio_content):
|
116 |
logging.info("Speech detected in the audio")
|
117 |
+
# Audio deepfake detection logic here if needed
|
|
|
118 |
else:
|
119 |
logging.info("No speech detected in the audio")
|
120 |
await remove_temp_file(audio_filename)
|
121 |
logging.info(f"Temporary audio file removed: {audio_filename}")
|
122 |
else:
|
123 |
+
logging.info("No audio detected or extracted from the video")
|
124 |
|
125 |
results = {"is_audio_deepfake": is_audio_deepfake}
|
126 |
|
|
|
128 |
logging.info(f"Frames extracted: {len(frames)} frames")
|
129 |
|
130 |
results.update({
|
131 |
+
"image_manipulation": {
|
132 |
+
"collective_detection": False,
|
133 |
+
"collective_confidence": 0.0
|
134 |
+
},
|
135 |
+
"face_manipulation": None,
|
136 |
+
"gan_detection": {
|
137 |
+
"collective_detection": False,
|
138 |
+
"collective_confidence": 0.0
|
139 |
+
}
|
140 |
})
|
141 |
|
142 |
face_frames = []
|
143 |
+
img_manip_detections = []
|
144 |
+
img_manip_confidences = []
|
145 |
+
gan_detections = []
|
146 |
+
gan_confidences = []
|
|
|
|
|
|
|
|
|
|
|
147 |
|
148 |
+
for frame in frames:
|
149 |
+
frame_content = get_file_content(frame)
|
150 |
+
has_face = detect_face(frame_content)
|
151 |
if has_face:
|
152 |
+
face_frames.append(frame)
|
153 |
+
|
154 |
+
img_manip_result = image_manipulation_service.detect_manipulation(frame)
|
155 |
+
gan_result = gan_detection_service.detect_gan(frame)
|
156 |
+
|
157 |
+
img_manip_detections.append(img_manip_result.get("is_manipulated", False))
|
158 |
+
img_manip_confidences.append(parse_confidence(img_manip_result.get("confidence", "0%")))
|
159 |
+
gan_detections.append(gan_result.get("is_gan", False))
|
160 |
+
gan_confidences.append(parse_confidence(gan_result.get("confidence", "0%")))
|
161 |
+
|
162 |
+
# Aggregate results for image manipulation and GAN detection
|
163 |
+
results["image_manipulation"]["collective_detection"] = any(img_manip_detections)
|
164 |
+
results["image_manipulation"]["collective_confidence"] = sum(img_manip_confidences) / len(img_manip_confidences) if img_manip_confidences else 0.0
|
165 |
+
|
166 |
+
results["gan_detection"]["collective_detection"] = any(gan_detections)
|
167 |
+
results["gan_detection"]["collective_confidence"] = sum(gan_confidences) / len(gan_confidences) if gan_confidences else 0.0
|
168 |
+
|
169 |
+
# Perform deepfake detection if faces were detected
|
170 |
+
if face_frames:
|
171 |
+
deepfake_result = deepfake_video_detection_service.detect_deepfake(face_frames)
|
172 |
+
deepfake_result = convert_to_python_types(deepfake_result)
|
173 |
+
results["face_manipulation"] = {
|
174 |
+
"collective_detection": bool(deepfake_result["is_deepfake"]),
|
175 |
+
"collective_confidence": deepfake_result['confidence']
|
176 |
+
}
|
177 |
+
|
178 |
logging.info(f"Aggregated results: {results}")
|
179 |
|
180 |
await remove_temp_file(compressed_video_filename)
|
181 |
+
for frame in frames:
|
182 |
+
await remove_temp_file(frame)
|
183 |
+
logging.info(f"Temporary files removed")
|
184 |
logging.info(f"Video processing completed for: {firebase_filename}")
|
185 |
+
|
186 |
return results
|
187 |
except Exception as e:
|
188 |
logging.error(f"Error processing video: {e}")
|
app/services/deepfake_video_detection.py
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import tensorflow as tf
|
2 |
+
import numpy as np
|
3 |
+
import cv2
|
4 |
+
from app.utils.file_utils import get_file_content
|
5 |
+
import io
|
6 |
+
|
7 |
+
class DeepfakeVideoDetectionService:
|
8 |
+
def __init__(self):
|
9 |
+
self.model = tf.keras.models.load_model("models\deepfake_videos.h5")
|
10 |
+
|
11 |
+
def process_frame(self, frame):
|
12 |
+
frame = cv2.resize(frame, (224, 224))
|
13 |
+
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
14 |
+
frame = tf.keras.applications.xception.preprocess_input(tf.convert_to_tensor(frame, dtype=tf.float32))
|
15 |
+
return np.expand_dims(frame, axis=0)
|
16 |
+
|
17 |
+
def calculate_weighted_average(self, predictions, threshold=0.5):
|
18 |
+
weights = np.maximum(predictions - threshold, 0)
|
19 |
+
if np.sum(weights) == 0:
|
20 |
+
return np.mean(predictions)
|
21 |
+
else:
|
22 |
+
return np.average(predictions, weights=weights)
|
23 |
+
|
24 |
+
def detect_deepfake(self, frame_filenames):
|
25 |
+
predictions = []
|
26 |
+
for filename in frame_filenames:
|
27 |
+
frame_content = get_file_content(filename)
|
28 |
+
frame = cv2.imdecode(np.frombuffer(frame_content, np.uint8), cv2.IMREAD_COLOR)
|
29 |
+
processed_frame = self.process_frame(frame)
|
30 |
+
prediction = float(self.model.predict(processed_frame, verbose=0)[0][0])
|
31 |
+
predictions.append(prediction)
|
32 |
+
|
33 |
+
predictions = np.array(predictions)
|
34 |
+
weighted_avg_confidence = self.calculate_weighted_average(predictions)
|
35 |
+
is_fake = weighted_avg_confidence > 0.5
|
36 |
+
|
37 |
+
return {
|
38 |
+
"is_deepfake": is_fake,
|
39 |
+
"confidence": float(weighted_avg_confidence),
|
40 |
+
"max_confidence": float(np.max(predictions)),
|
41 |
+
"min_confidence": float(np.min(predictions)),
|
42 |
+
"frames_analyzed": len(predictions)
|
43 |
+
}
|
models/deepfake_videos.h5
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:ab66e33cd80e38b3642994c16a271af3b2519ae1e189a792014e6607cb57beed
|
3 |
+
size 149835704
|