spideyhead commited on
Commit
30894d1
·
verified ·
1 Parent(s): abcece4

Delete main.py

Browse files
Files changed (1) hide show
  1. main.py +0 -160
main.py DELETED
@@ -1,160 +0,0 @@
1
- import os
2
- import cv2
3
- import torch
4
- import shutil
5
- from fastapi import FastAPI, UploadFile, File
6
- from fastapi.middleware.cors import CORSMiddleware
7
- from transformers import VideoMAEImageProcessor, VideoMAEForVideoClassification
8
- from facenet_pytorch import MTCNN
9
- from PIL import Image
10
-
11
- app = FastAPI()
12
-
13
- # Enable CORS for the React frontend
14
- app.add_middleware(
15
- CORSMiddleware,
16
- allow_origins=["*"],
17
- allow_credentials=True,
18
- allow_methods=["*"],
19
- allow_headers=["*"],
20
- )
21
-
22
- # Initialize Models globally so they load once on startup
23
- print("Loading MTCNN Face Detector...")
24
- mtcnn = MTCNN(keep_all=False, select_largest=True, post_process=False)
25
-
26
- print("Loading Hugging Face Temporal Deepfake Detector (VideoMAE)...")
27
- model_name = "Ammar2k/videomae-base-finetuned-deepfake-subset"
28
- processor = VideoMAEImageProcessor.from_pretrained(model_name)
29
- model = VideoMAEForVideoClassification.from_pretrained(model_name)
30
-
31
- # Ensure temp directory exists
32
- os.makedirs("temp", exist_ok=True)
33
-
34
- def extract_faces_sequence(video_path, sequence_length=16):
35
- """Extracts a sequence of continuous frames and tracks the face temporally."""
36
- cap = cv2.VideoCapture(video_path)
37
- frames_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
38
-
39
- if frames_count == 0:
40
- return []
41
-
42
- # Try to get frames from the middle of the video
43
- start_frame = max(0, (frames_count // 2) - (sequence_length // 2))
44
- cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame)
45
-
46
- faces = []
47
- last_box = None
48
-
49
- for _ in range(sequence_length):
50
- ret, frame = cap.read()
51
- if not ret:
52
- break
53
-
54
- # Convert BGR to RGB for MTCNN and PIL
55
- frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
56
- pil_img = Image.fromarray(frame_rgb)
57
-
58
- # Detect and crop face
59
- boxes, _ = mtcnn.detect(pil_img)
60
-
61
- # Bounding box smoothing: fallback to last known box if detection fails on a frame
62
- if boxes is not None and len(boxes) > 0:
63
- box = boxes[0]
64
- last_box = box
65
- elif last_box is not None:
66
- box = last_box
67
- else:
68
- continue # Skip if no face found yet
69
-
70
- # Add 30% padding around the face for better context
71
- w = box[2] - box[0]
72
- h = box[3] - box[1]
73
- pad_w = int(w * 0.3)
74
- pad_h = int(h * 0.3)
75
-
76
- x1 = max(0, int(box[0]) - pad_w)
77
- y1 = max(0, int(box[1]) - pad_h)
78
- x2 = min(pil_img.width, int(box[2]) + pad_w)
79
- y2 = min(pil_img.height, int(box[3]) + pad_h)
80
-
81
- if x2 > x1 and y2 > y1:
82
- face_crop = pil_img.crop((x1, y1, x2, y2))
83
- faces.append(face_crop)
84
-
85
- cap.release()
86
-
87
- # VideoMAE requires exactly `sequence_length` frames. Pad by duplicating last frame if short.
88
- if len(faces) == 0:
89
- return []
90
-
91
- while len(faces) < sequence_length:
92
- faces.append(faces[-1])
93
-
94
- return faces
95
-
96
- @app.post("/api/analyze")
97
- async def analyze_video(file: UploadFile = File(...)):
98
- print(f"Received file: {file.filename}")
99
-
100
- temp_video_path = os.path.join("temp", file.filename)
101
- with open(temp_video_path, "wb") as buffer:
102
- shutil.copyfileobj(file.file, buffer)
103
-
104
- try:
105
- print("Extracting facial sequence from video...")
106
- # Extract 16 consecutive frames
107
- faces = extract_faces_sequence(temp_video_path, sequence_length=16)
108
-
109
- if not faces:
110
- return {
111
- "isFake": False,
112
- "confidence": 0,
113
- "explanation": "Could not detect a clear face in the video sequence.",
114
- "details": []
115
- }
116
-
117
- print(f"Extracted {len(faces)} frame sequence. Running temporal inference...")
118
-
119
- # Prepare for VideoMAE 3D model
120
- inputs = processor(list(faces), return_tensors="pt")
121
-
122
- # Run inference
123
- with torch.no_grad():
124
- outputs = model(**inputs)
125
-
126
- # Video classification models return logits for the whole sequence
127
- probabilities = torch.nn.functional.softmax(outputs.logits[0], dim=-1)
128
-
129
- # Get highest probability label
130
- predicted_class_idx = probabilities.argmax(-1).item()
131
- label = model.config.id2label[predicted_class_idx].lower()
132
-
133
- is_fake = 'fake' in label
134
- confidence = round(probabilities[predicted_class_idx].item() * 100, 2)
135
-
136
- explanation = "Our 3D Temporal AI analyzed facial motion and detected unnatural movement, micro-expressions, or spatial inconsistencies typical of deepfakes." if is_fake else "Our 3D Temporal AI analyzed the facial movement and found natural micro-expressions and consistent temporal flow."
137
-
138
- print(f"Result: isFake={is_fake}, confidence={confidence}%")
139
-
140
- return {
141
- "isFake": is_fake,
142
- "confidence": confidence,
143
- "explanation": explanation,
144
- "details": [
145
- {"title": "Temporal Analysis", "desc": "Analyzed a continuous 16-frame clip using a VideoMAE 3D Transformer."},
146
- {"title": "Motion Tracking", "desc": "Tracked facial landmarks across time to detect jitter, blending artifacts, and lip-sync inconsistencies."}
147
- ]
148
- }
149
-
150
- except Exception as e:
151
- print(f"Error analyzing video: {e}")
152
- return {"error": str(e)}
153
-
154
- finally:
155
- if os.path.exists(temp_video_path):
156
- os.remove(temp_video_path)
157
-
158
- @app.get("/")
159
- def health_check():
160
- return {"status": "3D Temporal Backend is running!"}