Anish commited on
Commit
0dab55c
·
1 Parent(s): 13b0169

[Feature Added] > Video Pipeline. Have to update the confidence and ai_analysis param for images, where they won't appear.

Browse files
backend/ai_detector.db ADDED
File without changes
backend/app/ai/video/frame_detector.py CHANGED
@@ -12,8 +12,8 @@ class FrameDetector:
12
 
13
  try:
14
  model_id = "prithivMLmods/Deep-Fake-Detector-Model"
15
- self.processor = ViTImageProcessor.from_pretrained(model_id)
16
- self.model = ViTForImageClassification.from_pretrained(model_id)
17
  self.model = self.model.to(self.device)
18
  self.model.eval()
19
 
 
12
 
13
  try:
14
  model_id = "prithivMLmods/Deep-Fake-Detector-Model"
15
+ self.processor = AutoImageProcessor.from_pretrained(model_id)
16
+ self.model = AutoModelForImageClassification.from_pretrained(model_id)
17
  self.model = self.model.to(self.device)
18
  self.model.eval()
19
 
backend/app/api/file_routes.py CHANGED
@@ -31,6 +31,8 @@ def list_user_files(
31
  "size": f.filesize,
32
  "status": f.status,
33
  "result": f.result,
 
 
34
  "uploaded_at": f.created_at
35
  }
36
  for f in files
@@ -57,6 +59,8 @@ def get_file(
57
  "size": file.filesize,
58
  "status": file.status,
59
  "result": file.result,
 
 
60
  "uploaded_at": file.created_at
61
  }
62
 
 
31
  "size": f.filesize,
32
  "status": f.status,
33
  "result": f.result,
34
+ "confidence": f.confidence,
35
+ "ai_explanation": f.ai_explanation,
36
  "uploaded_at": f.created_at
37
  }
38
  for f in files
 
59
  "size": file.filesize,
60
  "status": file.status,
61
  "result": file.result,
62
+ "confidence": file.confidence,
63
+ "ai_explanation": file.ai_explanation,
64
  "uploaded_at": file.created_at
65
  }
66
 
backend/app/models/file_model.py CHANGED
@@ -1,4 +1,4 @@
1
- from sqlalchemy import Column, Integer, String, DateTime, ForeignKey
2
  from datetime import datetime, UTC
3
  from app.db.database import Base
4
 
@@ -17,5 +17,7 @@ class File(Base):
17
 
18
  status = Column(String, default="uploaded")
19
  result = Column(String, nullable=True)
 
 
20
 
21
  model_version_used = Column(String, nullable=True)
 
1
+ from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Float
2
  from datetime import datetime, UTC
3
  from app.db.database import Base
4
 
 
17
 
18
  status = Column(String, default="uploaded")
19
  result = Column(String, nullable=True)
20
+ confidence = Column(Float, nullable=True)
21
+ ai_explanation = Column(String, nullable=True)
22
 
23
  model_version_used = Column(String, nullable=True)
backend/app/security/video_validator.py CHANGED
@@ -29,19 +29,23 @@ class VideoValidator:
29
 
30
  bytes_read = 0
31
 
32
- with tempfile.NamedTemporaryFile(delete=True, suffix=ext) as temp_video:
33
- while chunk := file.file.read(1024 * 1024): # Read 1 MB at a time
34
- bytes_read += len(chunk)
35
- if bytes_read > cls.MAX_FILE_BYTES:
36
- logger.warning(f"Security Alert: Blocked upload exceeding {cls.MAX_FILE_BYTES} bytes")
37
- return False, "File size exceeds the maximum allowed limit"
38
-
39
- temp_video.write(chunk)
 
 
 
 
 
40
 
41
- temp_video.flush()
42
  file.file.seek(0)
43
-
44
- cap = cv2.VideoCapture(temp_video.name)
45
 
46
  if not cap.isOpened():
47
  logger.warning("Security Alert: OpenCV failed to open the video container. File may be corrupted or disguised.")
@@ -55,6 +59,13 @@ class VideoValidator:
55
  logger.warning("Security Alert: OpenCV opened container but failed to extract any visual frames.")
56
  return False, "Video contains no readable visual frames."
57
 
 
 
 
 
 
 
 
58
  return True, "Valid"
59
 
60
  except Exception as e:
 
29
 
30
  bytes_read = 0
31
 
32
+ temp_path = None
33
+ try:
34
+ with tempfile.NamedTemporaryFile(delete=False, suffix=ext) as temp_video:
35
+ temp_path = temp_video.name
36
+ while chunk := file.file.read(1024 * 1024): # Read 1 MB at a time
37
+ bytes_read += len(chunk)
38
+ if bytes_read > cls.MAX_FILE_BYTES:
39
+ logger.warning(f"Security Alert: Blocked upload exceeding {cls.MAX_FILE_BYTES} bytes")
40
+ return False, "File size exceeds the maximum allowed limit"
41
+
42
+ temp_video.write(chunk)
43
+
44
+ temp_video.flush()
45
 
46
+ # File is safely closed by Python now, so OpenCV can gain read-access on Windows
47
  file.file.seek(0)
48
+ cap = cv2.VideoCapture(temp_path)
 
49
 
50
  if not cap.isOpened():
51
  logger.warning("Security Alert: OpenCV failed to open the video container. File may be corrupted or disguised.")
 
59
  logger.warning("Security Alert: OpenCV opened container but failed to extract any visual frames.")
60
  return False, "Video contains no readable visual frames."
61
 
62
+ finally:
63
+ if temp_path and os.path.exists(temp_path):
64
+ try:
65
+ os.remove(temp_path)
66
+ except:
67
+ pass
68
+
69
  return True, "Valid"
70
 
71
  except Exception as e:
backend/app/services/video_processor.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+ import logging
3
+ import os
4
+ from sqlalchemy.orm import Session
5
+ from app.models.file_model import File
6
+ from app.ai.video.frame_extractor import extract_frames
7
+ from app.ai.video.frame_detector import analyze_frame
8
+ from app.ai.video.motion_detector import compute_motion_anomaly
9
+ from app.ai.video.noise_entropy_detector import compute_noise_entropy_anomaly
10
+ from app.ai.video.metadata_analyzer import analyze_metadata
11
+ from app.ai.video.aggregator import aggregate_scores
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+ def process_video_pipeline(file_id: int, file_path: str, db: Session):
16
+ start_time = time.time()
17
+ logger.info(f"Starting Video Pipeline for file_id: {file_id}")
18
+
19
+ try:
20
+ db_file = db.query(File).filter(File.id == file_id).first()
21
+ if not db_file:
22
+ logger.error(f"File ID {file_id} not found in DB.")
23
+ return
24
+
25
+ md_score, md_dict = analyze_metadata(file_path)
26
+
27
+ frame_scores = []
28
+ motion_scores = []
29
+ noise_scores = []
30
+
31
+ previous_frame = None
32
+
33
+ for frame in extract_frames(file_path, sample_rate=15, max_frames=50):
34
+
35
+ # Module A: ViT Image Forensic Analysis
36
+ f_score = analyze_frame(frame)
37
+ frame_scores.append(f_score)
38
+
39
+ # Module B: Microscopic Silicon Noise Analysis
40
+ n_score = compute_noise_entropy_anomaly(frame)
41
+ if n_score is not None:
42
+ noise_scores.append(n_score)
43
+
44
+ # Module C: Farneback Optical Flow
45
+ if previous_frame is not None:
46
+ m_score = compute_motion_anomaly(previous_frame, frame)
47
+
48
+ if m_score is not None:
49
+ motion_scores.append(m_score)
50
+
51
+ previous_frame = frame
52
+
53
+ avg_motion = sum(motion_scores)/len(motion_scores) if motion_scores else None
54
+ avg_noise = sum(noise_scores)/len(noise_scores) if noise_scores else None
55
+
56
+
57
+ final_verdict = aggregate_scores(
58
+ frame_scores=frame_scores,
59
+ motion_score=avg_motion,
60
+ noise_score=avg_noise,
61
+ metadata_score=md_score
62
+ )
63
+
64
+ db_file.status = "Completed"
65
+ db_file.result = f"{final_verdict['label']} ({final_verdict['probability']*100:.1f}%)"
66
+ db_file.confidence = final_verdict['probability']
67
+ db_file.ai_explanation = final_verdict['explanation']
68
+
69
+ db.commit()
70
+
71
+ elapsed = time.time() - start_time
72
+ logger.info(f"Successfully processed video {file_id} in {elapsed:.2f} seconds.")
73
+ logger.info(f"Verdict: {db_file.result}")
74
+
75
+ except Exception as e:
76
+ logger.error(f"FATAL Pipeline Crash for file_id {file_id}: {str(e)}")
77
+
78
+ try:
79
+ db_file = db.query(File).filter(File.id == file_id).first()
80
+
81
+ if db_file:
82
+ db_file.status = "Failed"
83
+ db_file.result = str(e)
84
+ db.commit()
85
+ except:
86
+ pass
backend/app/utils/file_handler.py CHANGED
@@ -26,8 +26,10 @@ def validate_file(file: UploadFile):
26
  if not is_valid:
27
  raise HTTPException(status_code=400, detail=validation_reason)
28
 
 
29
  return file.size or 0
30
 
 
31
  file_bytes = file.file.read()
32
  size = len(file_bytes)
33
 
 
26
  if not is_valid:
27
  raise HTTPException(status_code=400, detail=validation_reason)
28
 
29
+ file.file.seek(0) # CRITICAL: Reset the pointer after Video validation reads it!
30
  return file.size or 0
31
 
32
+ file.file.seek(0)
33
  file_bytes = file.file.read()
34
  size = len(file_bytes)
35
 
backend/app/worker/tasks.py CHANGED
@@ -41,7 +41,14 @@ def process_file_task(self, file_id: int):
41
 
42
  logger.info(f"Starting Celery worker process for file_id: {file_id}")
43
  try:
44
- process_file(file_id, db)
 
 
 
 
 
 
 
45
 
46
  job.status = "COMPLETED"
47
  job.finished_at = datetime.now(UTC)
 
41
 
42
  logger.info(f"Starting Celery worker process for file_id: {file_id}")
43
  try:
44
+ from app.models.file_model import File
45
+ db_file = db.query(File).filter(File.id == file_id).first()
46
+
47
+ if db_file and db_file.filetype and db_file.filetype.startswith('video/'):
48
+ from app.services.video_processor import process_video_pipeline
49
+ process_video_pipeline(file_id, db_file.filepath, db)
50
+ else:
51
+ process_file(file_id, db)
52
 
53
  job.status = "COMPLETED"
54
  job.finished_at = datetime.now(UTC)