Krish Patel
commited on
Commit
·
8c24dde
1
Parent(s):
3088d34
Added deepfake video detection
Browse files- .gitignore +2 -1
- app.py +39 -9
- deepfake2/testing2.py +40 -0
- nexus-frontend/src/pages/deepfake.tsx +57 -16
.gitignore
CHANGED
|
@@ -1,3 +1,4 @@
|
|
| 1 |
__pycache__/
|
| 2 |
node_modules/
|
| 3 |
-
.env
|
|
|
|
|
|
| 1 |
__pycache__/
|
| 2 |
node_modules/
|
| 3 |
+
.env
|
| 4 |
+
.venv/
|
app.py
CHANGED
|
@@ -31,23 +31,53 @@ async def analyze_news(news: NewsInput):
|
|
| 31 |
}
|
| 32 |
|
| 33 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
@app.post("/detect-deepfake")
|
| 35 |
-
async def detect_deepfake(
|
| 36 |
try:
|
| 37 |
-
# Save uploaded
|
| 38 |
-
with NamedTemporaryFile(delete=False, suffix=
|
| 39 |
-
contents = await
|
| 40 |
temp_file.write(contents)
|
| 41 |
temp_file_path = temp_file.name
|
| 42 |
|
| 43 |
-
#
|
| 44 |
-
from deepfake2.testing2 import predict_image
|
| 45 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
|
| 47 |
# Clean up temp file
|
| 48 |
os.remove(temp_file_path)
|
| 49 |
|
| 50 |
-
return
|
| 51 |
-
|
|
|
|
|
|
|
|
|
|
| 52 |
except Exception as e:
|
| 53 |
return {"error": str(e)}, 500
|
|
|
|
| 31 |
}
|
| 32 |
|
| 33 |
|
| 34 |
+
# @app.post("/detect-deepfake")
|
| 35 |
+
# async def detect_deepfake(image: UploadFile = File(...)):
|
| 36 |
+
# try:
|
| 37 |
+
# # Save uploaded image temporarily
|
| 38 |
+
# with NamedTemporaryFile(delete=False, suffix='.jpg') as temp_file:
|
| 39 |
+
# contents = await image.read()
|
| 40 |
+
# temp_file.write(contents)
|
| 41 |
+
# temp_file_path = temp_file.name
|
| 42 |
+
|
| 43 |
+
# # Use your existing deepfake detection function
|
| 44 |
+
# from deepfake2.testing2 import predict_image # Use your existing function
|
| 45 |
+
# result = predict_image(temp_file_path)
|
| 46 |
+
|
| 47 |
+
# # Clean up temp file
|
| 48 |
+
# os.remove(temp_file_path)
|
| 49 |
+
|
| 50 |
+
# return result
|
| 51 |
+
# except Exception as e:
|
| 52 |
+
# return {"error": str(e)}, 500
|
| 53 |
+
|
| 54 |
@app.post("/detect-deepfake")
|
| 55 |
+
async def detect_deepfake(file: UploadFile = File(...)):
|
| 56 |
try:
|
| 57 |
+
# Save uploaded file temporarily
|
| 58 |
+
with NamedTemporaryFile(delete=False, suffix=os.path.splitext(file.filename)[1]) as temp_file:
|
| 59 |
+
contents = await file.read()
|
| 60 |
temp_file.write(contents)
|
| 61 |
temp_file_path = temp_file.name
|
| 62 |
|
| 63 |
+
# Import functions from testing2.py
|
| 64 |
+
from deepfake2.testing2 import predict_image, predict_video
|
| 65 |
+
|
| 66 |
+
# Use appropriate function based on file type
|
| 67 |
+
if file.filename.lower().endswith('.mp4'):
|
| 68 |
+
result = predict_video(temp_file_path)
|
| 69 |
+
file_type = "video"
|
| 70 |
+
else:
|
| 71 |
+
result = predict_image(temp_file_path)
|
| 72 |
+
file_type = "image"
|
| 73 |
|
| 74 |
# Clean up temp file
|
| 75 |
os.remove(temp_file_path)
|
| 76 |
|
| 77 |
+
return {
|
| 78 |
+
"result": result,
|
| 79 |
+
"file_type": file_type
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
except Exception as e:
|
| 83 |
return {"error": str(e)}, 500
|
deepfake2/testing2.py
CHANGED
|
@@ -24,6 +24,46 @@ def predict_image(img_path):
|
|
| 24 |
prediction = model.predict(img_array)
|
| 25 |
return "Fake" if prediction[0][0] > 0.5 else "Real"
|
| 26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
# Metadata analysis
|
| 28 |
def check_metadata(img_path):
|
| 29 |
try:
|
|
|
|
| 24 |
prediction = model.predict(img_array)
|
| 25 |
return "Fake" if prediction[0][0] > 0.5 else "Real"
|
| 26 |
|
| 27 |
+
# Add this function for video analysis
|
| 28 |
+
def predict_video(video_path):
|
| 29 |
+
if not os.path.exists(video_path):
|
| 30 |
+
return "Video path does not exist."
|
| 31 |
+
|
| 32 |
+
cap = cv2.VideoCapture(video_path)
|
| 33 |
+
fake_frames = 0
|
| 34 |
+
total_frames = 0
|
| 35 |
+
|
| 36 |
+
while cap.isOpened():
|
| 37 |
+
ret, frame = cap.read()
|
| 38 |
+
if not ret:
|
| 39 |
+
break
|
| 40 |
+
|
| 41 |
+
# Convert frame to RGB and resize
|
| 42 |
+
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
| 43 |
+
frame_resized = cv2.resize(frame_rgb, (img_height, img_width))
|
| 44 |
+
|
| 45 |
+
# Prepare frame for prediction
|
| 46 |
+
frame_array = image.img_to_array(frame_resized) / 255.0
|
| 47 |
+
frame_array = np.expand_dims(frame_array, axis=0)
|
| 48 |
+
|
| 49 |
+
# Predict frame
|
| 50 |
+
prediction = model.predict(frame_array)
|
| 51 |
+
if prediction[0][0] > 0.5:
|
| 52 |
+
fake_frames += 1
|
| 53 |
+
total_frames += 1
|
| 54 |
+
|
| 55 |
+
cap.release()
|
| 56 |
+
|
| 57 |
+
# Calculate percentage of fake frames
|
| 58 |
+
fake_percentage = (fake_frames / total_frames) * 100 if total_frames > 0 else 0
|
| 59 |
+
|
| 60 |
+
return {
|
| 61 |
+
"prediction": "Fake" if fake_percentage > 50 else "Real",
|
| 62 |
+
"confidence_score": round(fake_percentage / 100, 2),
|
| 63 |
+
"frames_analyzed": total_frames,
|
| 64 |
+
"fake_frames_detected": fake_frames
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
# Metadata analysis
|
| 68 |
def check_metadata(img_path):
|
| 69 |
try:
|
nexus-frontend/src/pages/deepfake.tsx
CHANGED
|
@@ -60,6 +60,14 @@ const DeepfakeDetection = () => {
|
|
| 60 |
const [selectedImage, setSelectedImage] = useState(null);
|
| 61 |
const [result, setResult] = useState(null);
|
| 62 |
const [loading, setLoading] = useState(false);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
|
| 64 |
const handleImageSelect = (event) => {
|
| 65 |
const file = event.target.files[0];
|
|
@@ -67,10 +75,12 @@ const DeepfakeDetection = () => {
|
|
| 67 |
};
|
| 68 |
|
| 69 |
const handleUpload = async () => {
|
| 70 |
-
|
|
|
|
|
|
|
| 71 |
setLoading(true);
|
| 72 |
const formData = new FormData();
|
| 73 |
-
formData.append('
|
| 74 |
|
| 75 |
try {
|
| 76 |
const response = await fetch('http://localhost:8000/detect-deepfake', {
|
|
@@ -99,21 +109,39 @@ const DeepfakeDetection = () => {
|
|
| 99 |
|
| 100 |
<div className="space-y-6">
|
| 101 |
<div className="flex flex-col items-center">
|
| 102 |
-
<
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 113 |
</div>
|
| 114 |
-
</label>
|
| 115 |
|
| 116 |
-
{selectedImage && (
|
| 117 |
<div className="mt-4 text-center">
|
| 118 |
<p className="text-blue-300">Selected: {selectedImage.name}</p>
|
| 119 |
<img
|
|
@@ -123,10 +151,23 @@ const DeepfakeDetection = () => {
|
|
| 123 |
/>
|
| 124 |
</div>
|
| 125 |
)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
|
| 127 |
<button
|
| 128 |
onClick={handleUpload}
|
| 129 |
-
disabled={!selectedImage || loading}
|
| 130 |
className="mt-4 px-6 py-2 rounded-lg bg-blue-500 hover:bg-blue-600 text-white disabled:opacity-50"
|
| 131 |
>
|
| 132 |
Analyze
|
|
|
|
| 60 |
const [selectedImage, setSelectedImage] = useState(null);
|
| 61 |
const [result, setResult] = useState(null);
|
| 62 |
const [loading, setLoading] = useState(false);
|
| 63 |
+
const [selectedVideo, setSelectedVideo] = useState(null);
|
| 64 |
+
const [fileType, setFileType] = useState(null);
|
| 65 |
+
|
| 66 |
+
const handleVideoSelect = (event) => {
|
| 67 |
+
const file = event.target.files[0];
|
| 68 |
+
setSelectedVideo(file);
|
| 69 |
+
setFileType('video');
|
| 70 |
+
};
|
| 71 |
|
| 72 |
const handleImageSelect = (event) => {
|
| 73 |
const file = event.target.files[0];
|
|
|
|
| 75 |
};
|
| 76 |
|
| 77 |
const handleUpload = async () => {
|
| 78 |
+
const fileToUpload = fileType === 'video' ? selectedVideo : selectedImage;
|
| 79 |
+
if (!fileToUpload) return;
|
| 80 |
+
|
| 81 |
setLoading(true);
|
| 82 |
const formData = new FormData();
|
| 83 |
+
formData.append('file', fileToUpload);
|
| 84 |
|
| 85 |
try {
|
| 86 |
const response = await fetch('http://localhost:8000/detect-deepfake', {
|
|
|
|
| 109 |
|
| 110 |
<div className="space-y-6">
|
| 111 |
<div className="flex flex-col items-center">
|
| 112 |
+
<div className="flex gap-4">
|
| 113 |
+
<input
|
| 114 |
+
accept="image/*"
|
| 115 |
+
className="hidden"
|
| 116 |
+
id="image-upload"
|
| 117 |
+
type="file"
|
| 118 |
+
onChange={(e) => {
|
| 119 |
+
handleImageSelect(e);
|
| 120 |
+
setFileType('image');
|
| 121 |
+
}}
|
| 122 |
+
/>
|
| 123 |
+
<label htmlFor="image-upload">
|
| 124 |
+
<div className="px-6 py-3 rounded-lg bg-blue-500 hover:bg-blue-600 text-white cursor-pointer flex items-center gap-2">
|
| 125 |
+
<CloudUploadIcon />
|
| 126 |
+
Upload Image
|
| 127 |
+
</div>
|
| 128 |
+
</label>
|
| 129 |
+
<input
|
| 130 |
+
accept="video/mp4"
|
| 131 |
+
className="hidden"
|
| 132 |
+
id="video-upload"
|
| 133 |
+
type="file"
|
| 134 |
+
onChange={handleVideoSelect}
|
| 135 |
+
/>
|
| 136 |
+
<label htmlFor="video-upload">
|
| 137 |
+
<div className="px-6 py-3 rounded-lg bg-green-500 hover:bg-green-600 text-white cursor-pointer flex items-center gap-2">
|
| 138 |
+
<CloudUploadIcon />
|
| 139 |
+
Upload MP4 Video
|
| 140 |
+
</div>
|
| 141 |
+
</label>
|
| 142 |
</div>
|
|
|
|
| 143 |
|
| 144 |
+
{selectedImage && fileType === 'image' && (
|
| 145 |
<div className="mt-4 text-center">
|
| 146 |
<p className="text-blue-300">Selected: {selectedImage.name}</p>
|
| 147 |
<img
|
|
|
|
| 151 |
/>
|
| 152 |
</div>
|
| 153 |
)}
|
| 154 |
+
|
| 155 |
+
{selectedVideo && fileType === 'video' && (
|
| 156 |
+
<div className="mt-4 text-center">
|
| 157 |
+
<p className="text-blue-300">Selected Video: {selectedVideo.name}</p>
|
| 158 |
+
<video
|
| 159 |
+
className="max-w-md mt-4 rounded-lg mx-auto"
|
| 160 |
+
controls
|
| 161 |
+
>
|
| 162 |
+
<source src={URL.createObjectURL(selectedVideo)} type={selectedVideo.type} />
|
| 163 |
+
Your browser does not support the video tag.
|
| 164 |
+
</video>
|
| 165 |
+
</div>
|
| 166 |
+
)}
|
| 167 |
|
| 168 |
<button
|
| 169 |
onClick={handleUpload}
|
| 170 |
+
disabled={!selectedImage && !selectedVideo || loading}
|
| 171 |
className="mt-4 px-6 py-2 rounded-lg bg-blue-500 hover:bg-blue-600 text-white disabled:opacity-50"
|
| 172 |
>
|
| 173 |
Analyze
|