Spaces:
Sleeping
Sleeping
Update detector.py
Browse files- detector.py +27 -11
detector.py
CHANGED
|
@@ -94,9 +94,6 @@ def extract_platform(url: str) -> str:
|
|
| 94 |
else:
|
| 95 |
return "Direct Link / Other"
|
| 96 |
|
| 97 |
-
# βββββββββββββββββββββββββββββββββββββββββββββ
|
| 98 |
-
# VIDEO DOWNLOAD
|
| 99 |
-
# βββββββββββββββββββββββββββββββββββββββββββββ
|
| 100 |
def download_video(url: str) -> tuple[bool, str]:
|
| 101 |
tmp = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False)
|
| 102 |
tmp.close()
|
|
@@ -130,6 +127,9 @@ def download_video(url: str) -> tuple[bool, str]:
|
|
| 130 |
# βββββββββββββββββββββββββββββββββββββββββββββ
|
| 131 |
@spaces.GPU(duration=120)
|
| 132 |
def encode_and_classify(windows: list) -> list:
|
|
|
|
|
|
|
|
|
|
| 133 |
if not windows:
|
| 134 |
return []
|
| 135 |
|
|
@@ -176,14 +176,17 @@ def encode_and_classify(windows: list) -> list:
|
|
| 176 |
"start_sec": window["start_sec"],
|
| 177 |
"end_sec": window["end_sec"],
|
| 178 |
})
|
| 179 |
-
|
|
|
|
|
|
|
| 180 |
return scores
|
| 181 |
|
| 182 |
# βββββββββββββββββββββββββββββββββββββββββββββ
|
| 183 |
# BACKGROUND DATA UPLOAD & ALERTS (Asynchronous)
|
| 184 |
# βββββββββββββββββββββββββββββββββββββββββββββ
|
| 185 |
def upload_and_notify_background(video_path: str, meta: dict):
|
| 186 |
-
|
|
|
|
| 187 |
try:
|
| 188 |
if not DATASET_REPO_ID or not HF_TOKEN:
|
| 189 |
return
|
|
@@ -232,22 +235,24 @@ def upload_and_notify_background(video_path: str, meta: dict):
|
|
| 232 |
except Exception as e:
|
| 233 |
print(f"Background task execution failed: {e}")
|
| 234 |
finally:
|
| 235 |
-
# File deletion safe-guards executed inside the thread after upload attempts complete
|
| 236 |
for f in glob.glob(video_path + "*") + [video_path]:
|
| 237 |
if os.path.exists(f):
|
| 238 |
try:
|
| 239 |
os.remove(f)
|
| 240 |
except Exception:
|
| 241 |
pass
|
|
|
|
| 242 |
|
| 243 |
# βββββββββββββββββββββββββββββββββββββββββββββ
|
| 244 |
# GRADIO PREDICT
|
| 245 |
# βββββββββββββββββββββββββββββββββββββββββββββ
|
| 246 |
def predict(url: str, uploaded_video: str, consent: bool, current_state: dict) -> tuple[str, str, str, dict]:
|
|
|
|
|
|
|
|
|
|
| 247 |
if not consent:
|
| 248 |
return "β Required: You must check the data collection consent box to process videos.", "", "", current_state
|
| 249 |
|
| 250 |
-
start_time = time.time()
|
| 251 |
url = (url or "").strip()
|
| 252 |
|
| 253 |
if current_state and "video_path" in current_state:
|
|
@@ -259,6 +264,7 @@ def predict(url: str, uploaded_video: str, consent: bool, current_state: dict) -
|
|
| 259 |
except Exception:
|
| 260 |
pass
|
| 261 |
|
|
|
|
| 262 |
if uploaded_video:
|
| 263 |
tmp = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False)
|
| 264 |
shutil.copy(uploaded_video, tmp.name)
|
|
@@ -275,6 +281,9 @@ def predict(url: str, uploaded_video: str, consent: bool, current_state: dict) -
|
|
| 275 |
else:
|
| 276 |
return "Please enter a URL or upload a video.", "", "", {}
|
| 277 |
|
|
|
|
|
|
|
|
|
|
| 278 |
try:
|
| 279 |
windows, total_frames, fps, duration_sec = get_video_windows(video_path)
|
| 280 |
except Exception as e:
|
|
@@ -282,7 +291,15 @@ def predict(url: str, uploaded_video: str, consent: bool, current_state: dict) -
|
|
| 282 |
os.remove(video_path)
|
| 283 |
return f"Video decode failed: {e}", "", "", {}
|
| 284 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 285 |
scores = encode_and_classify(windows)
|
|
|
|
|
|
|
|
|
|
| 286 |
|
| 287 |
if not scores:
|
| 288 |
if os.path.exists(video_path):
|
|
@@ -291,7 +308,7 @@ def predict(url: str, uploaded_video: str, consent: bool, current_state: dict) -
|
|
| 291 |
|
| 292 |
final_prob = max(s["prob"] for s in scores)
|
| 293 |
label = "β οΈ AI-GENERATED (FAKE)" if final_prob > 0.5 else "β
REAL"
|
| 294 |
-
elapsed_time = time.time() -
|
| 295 |
confidence = f"{final_prob * 100:.1f}%"
|
| 296 |
|
| 297 |
lines = [
|
|
@@ -312,14 +329,13 @@ def predict(url: str, uploaded_video: str, consent: bool, current_state: dict) -
|
|
| 312 |
"total_frames": total_frames
|
| 313 |
}
|
| 314 |
|
| 315 |
-
# SOLUTION: Dispatches upload tasks asynchronously to an detached thread.
|
| 316 |
-
# The application instantly proceeds to return the results to the user interface.
|
| 317 |
threading.Thread(
|
| 318 |
target=upload_and_notify_background,
|
| 319 |
args=(video_path, meta),
|
| 320 |
daemon=True
|
| 321 |
).start()
|
| 322 |
-
|
|
|
|
| 323 |
return label, confidence, "\n".join(lines), {}
|
| 324 |
|
| 325 |
# βββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
| 94 |
else:
|
| 95 |
return "Direct Link / Other"
|
| 96 |
|
|
|
|
|
|
|
|
|
|
| 97 |
def download_video(url: str) -> tuple[bool, str]:
|
| 98 |
tmp = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False)
|
| 99 |
tmp.close()
|
|
|
|
| 127 |
# βββββββββββββββββββββββββββββββββββββββββββββ
|
| 128 |
@spaces.GPU(duration=120)
|
| 129 |
def encode_and_classify(windows: list) -> list:
|
| 130 |
+
gpu_start_time = time.time()
|
| 131 |
+
print(f"\n[TIMING] --- GPU Allocated & Inference Started ---")
|
| 132 |
+
|
| 133 |
if not windows:
|
| 134 |
return []
|
| 135 |
|
|
|
|
| 176 |
"start_sec": window["start_sec"],
|
| 177 |
"end_sec": window["end_sec"],
|
| 178 |
})
|
| 179 |
+
|
| 180 |
+
gpu_end_time = time.time()
|
| 181 |
+
print(f"[TIMING] GPU execution completed in {gpu_end_time - gpu_start_time:.2f}s")
|
| 182 |
return scores
|
| 183 |
|
| 184 |
# βββββββββββββββββββββββββββββββββββββββββββββ
|
| 185 |
# BACKGROUND DATA UPLOAD & ALERTS (Asynchronous)
|
| 186 |
# βββββββββββββββββββββββββββββββββββββββββββββ
|
| 187 |
def upload_and_notify_background(video_path: str, meta: dict):
|
| 188 |
+
bg_start_time = time.time()
|
| 189 |
+
print("\n[TIMING] Background thread started for dataset upload...")
|
| 190 |
try:
|
| 191 |
if not DATASET_REPO_ID or not HF_TOKEN:
|
| 192 |
return
|
|
|
|
| 235 |
except Exception as e:
|
| 236 |
print(f"Background task execution failed: {e}")
|
| 237 |
finally:
|
|
|
|
| 238 |
for f in glob.glob(video_path + "*") + [video_path]:
|
| 239 |
if os.path.exists(f):
|
| 240 |
try:
|
| 241 |
os.remove(f)
|
| 242 |
except Exception:
|
| 243 |
pass
|
| 244 |
+
print(f"[TIMING] Background thread finished in {time.time() - bg_start_time:.2f}s")
|
| 245 |
|
| 246 |
# βββββββββββββββββββββββββββββββββββββββββββββ
|
| 247 |
# GRADIO PREDICT
|
| 248 |
# βββββββββββββββββββββββββββββββββββββββββββββ
|
| 249 |
def predict(url: str, uploaded_video: str, consent: bool, current_state: dict) -> tuple[str, str, str, dict]:
|
| 250 |
+
global_start_time = time.time()
|
| 251 |
+
print(f"\n{'='*30}\n[TIMING] Request Received.")
|
| 252 |
+
|
| 253 |
if not consent:
|
| 254 |
return "β Required: You must check the data collection consent box to process videos.", "", "", current_state
|
| 255 |
|
|
|
|
| 256 |
url = (url or "").strip()
|
| 257 |
|
| 258 |
if current_state and "video_path" in current_state:
|
|
|
|
| 264 |
except Exception:
|
| 265 |
pass
|
| 266 |
|
| 267 |
+
file_start_time = time.time()
|
| 268 |
if uploaded_video:
|
| 269 |
tmp = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False)
|
| 270 |
shutil.copy(uploaded_video, tmp.name)
|
|
|
|
| 281 |
else:
|
| 282 |
return "Please enter a URL or upload a video.", "", "", {}
|
| 283 |
|
| 284 |
+
file_ready_time = time.time()
|
| 285 |
+
print(f"[TIMING] File Acquisition (Download/Copy) took: {file_ready_time - file_start_time:.2f}s")
|
| 286 |
+
|
| 287 |
try:
|
| 288 |
windows, total_frames, fps, duration_sec = get_video_windows(video_path)
|
| 289 |
except Exception as e:
|
|
|
|
| 291 |
os.remove(video_path)
|
| 292 |
return f"Video decode failed: {e}", "", "", {}
|
| 293 |
|
| 294 |
+
cpu_decode_time = time.time()
|
| 295 |
+
print(f"[TIMING] CPU Video Decoding took: {cpu_decode_time - file_ready_time:.2f}s")
|
| 296 |
+
|
| 297 |
+
print(f"[TIMING] Requesting GPU Hardware from ZeroGPU Queue...")
|
| 298 |
+
queue_start_time = time.time()
|
| 299 |
scores = encode_and_classify(windows)
|
| 300 |
+
queue_and_gpu_time = time.time()
|
| 301 |
+
|
| 302 |
+
print(f"[TIMING] Total time spent requesting queue + GPU execution: {queue_and_gpu_time - queue_start_time:.2f}s")
|
| 303 |
|
| 304 |
if not scores:
|
| 305 |
if os.path.exists(video_path):
|
|
|
|
| 308 |
|
| 309 |
final_prob = max(s["prob"] for s in scores)
|
| 310 |
label = "β οΈ AI-GENERATED (FAKE)" if final_prob > 0.5 else "β
REAL"
|
| 311 |
+
elapsed_time = time.time() - global_start_time
|
| 312 |
confidence = f"{final_prob * 100:.1f}%"
|
| 313 |
|
| 314 |
lines = [
|
|
|
|
| 329 |
"total_frames": total_frames
|
| 330 |
}
|
| 331 |
|
|
|
|
|
|
|
| 332 |
threading.Thread(
|
| 333 |
target=upload_and_notify_background,
|
| 334 |
args=(video_path, meta),
|
| 335 |
daemon=True
|
| 336 |
).start()
|
| 337 |
+
|
| 338 |
+
print(f"[TIMING] Total Blocking Time Before UI Return: {elapsed_time:.2f}s")
|
| 339 |
return label, confidence, "\n".join(lines), {}
|
| 340 |
|
| 341 |
# βββββββββββββββββββββββββββββββββββββββββββββ
|