kautilya286 commited on
Commit
b5b2f19
Β·
1 Parent(s): 5ff9f70

first commit

Browse files
.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ .venv
2
+ pyodide
3
+ venv/
Evaluation/visualize_tsne.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import matplotlib.pyplot as plt
2
+ from sklearn.manifold import TSNE
3
+ import numpy as np
4
+
5
+ # Load your embeddings (X) and labels (y)
6
+ X = np.load("../features/embeddings.npy") # FaceNet embeddings
7
+ y = np.load("../features/labels.npy") # Labels (real, fake, AI-generated)
8
+
9
+ # Ensure that the number of samples is greater than the perplexity value
10
+ n_samples = X.shape[0]
11
+ perplexity_value = min(30, n_samples - 1) # Set perplexity less than number of samples
12
+
13
+ # Apply t-SNE to reduce dimensionality to 2D
14
+ tsne = TSNE(n_components=2, random_state=42, perplexity=perplexity_value)
15
+ X_tsne = tsne.fit_transform(X)
16
+
17
+ # Plot the results
18
+ plt.figure(figsize=(8, 6))
19
+ plt.scatter(X_tsne[:, 0], X_tsne[:, 1], c=y, cmap='viridis', s=50, alpha=0.7)
20
+ plt.title("t-SNE Visualization of FaceNet Embeddings")
21
+ plt.colorbar(label='Class')
22
+
23
+ # Show the plot in a window
24
+ plt.show()
README.md CHANGED
@@ -1,11 +1 @@
1
- ---
2
- title: DeepscanAPI
3
- emoji: 🐠
4
- colorFrom: red
5
- colorTo: green
6
- sdk: docker
7
- pinned: false
8
- license: mit
9
- ---
10
-
11
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
+ Please create venv and install the requirementss.txt
 
 
 
 
 
 
 
 
 
 
app.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import torch
3
+ import numpy as np
4
+ import joblib
5
+ from PIL import Image
6
+ from flask import Flask, request, jsonify
7
+ from transformers import CLIPProcessor, CLIPModel
8
+ from io import BytesIO
9
+ from flask_cors import CORS
10
+ import base64
11
+ import io
12
+
13
+ # Flask app initialization
14
+ app = Flask(__name__)
15
+ CORS(app)
16
+
17
+ # Load models once at the start
18
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
19
+ print(f"[INFO] Using device: {device}")
20
+
21
+ # Load the CLIP model and processor
22
+ model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32").to(device)
23
+ processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
24
+
25
+ # Load the ensemble classifier model
26
+ ensemble_clf = joblib.load("model/random_forest_tuned_aug.pkl")
27
+
28
+ # Label mapping
29
+ label_map = {0: "real", 1: "deepfake", 2: "ai_gen"}
30
+
31
+ def extract_features(image):
32
+ image = image.resize((224, 224)) # Resize to the required input size (224x224)
33
+ inputs = processor(images=image, return_tensors="pt").to(device)
34
+
35
+ with torch.no_grad():
36
+ # Extract image features using CLIP
37
+ outputs = model.get_image_features(**inputs)
38
+
39
+ emb = outputs.cpu().numpy().squeeze()
40
+ return emb
41
+
42
+ @app.route("/predict", methods=["POST"])
43
+ def predict():
44
+ # Get the uploaded image
45
+ data = request.json
46
+ if 'image' not in data:
47
+ return jsonify({"error": "No image provided"}), 400
48
+
49
+ image_data = base64.b64decode(data['image'])
50
+ image = Image.open(io.BytesIO(image_data)).convert("RGB")
51
+
52
+ # Extract features and predict
53
+ features = extract_features(image)
54
+ probs = ensemble_clf.predict_proba([features])[0]
55
+ top_idx = np.argmax(probs)
56
+
57
+ # Prepare response
58
+ response = {
59
+ "prediction": label_map[top_idx],
60
+ "probabilities": probs.tolist()
61
+ }
62
+
63
+ return jsonify(response)
64
+
65
+ if __name__ == "__main__":
66
+ # Run Flask app
67
+ app.run(debug=True)
features/embeddings.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7021bc09baa1ad36ee9dbd765f3fc7332a3a7a9465b9c3369c2d20970d55ca1b
3
+ size 18560
features/labels.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:04df4e7bc4f3e3683b77f8deea9fd98ea9c1ca22959c6d40b442d192f3e6092c
3
+ size 164
model/random_forest.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d5da12754b9328bcee20fd05b4edb7c3252601f381f9accac2859e5305a416c8
3
+ size 85009
model/random_forest_aug.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:43e8f80fbe0c4e0c5a3e7c46105048c603bf65c8f9177a813fb1c03acfcf1e11
3
+ size 58425313
model/random_forest_tuned_aug.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:941c23b7a9dcaf45f37b9b978deb9b1aad27112a7db3da69ff26208a1c45bc2c
3
+ size 73887089
render.yaml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ services:
2
+ - type: web
3
+ name: deepfake-detector
4
+ env: python
5
+ plan: free
6
+ buildCommand: ""
7
+ startCommand: gunicorn app:app
requirements.txt ADDED
Binary file (1.79 kB). View file
 
scripts/augment_data.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import cv2
3
+ import numpy as np
4
+ import albumentations as A
5
+ from glob import glob
6
+
7
+ # Define the augmentation pipeline
8
+ AUG = A.Compose([
9
+ A.HorizontalFlip(p=0.5),
10
+ A.RandomBrightnessContrast(p=0.5),
11
+ A.GaussianBlur(blur_limit=3, p=0.3),
12
+ A.Rotate(limit=15, p=0.3),
13
+ A.RandomResizedCrop(160, 160, scale=(0.9, 1.0), p=0.3),
14
+ A.ElasticTransform(alpha=1.0, sigma=50, alpha_affine=50, p=0.3), # Elastic transformation
15
+ A.CoarseDropout(max_holes=1, max_height=8, max_width=8, p=0.3), # Random Erasing
16
+ A.PerspectiveTransform(scale=(0.01, 0.1), p=0.5) # Random perspective shift
17
+ ])
18
+
19
+ # Directory with input images
20
+ INPUT_DIR = "data"
21
+ CATEGORIES = ["real", "deepfake", "ai_gen"]
22
+ valid_extensions = ['.jpg', '.jpeg', '.png']
23
+
24
+ for cat in CATEGORIES:
25
+ os.makedirs(os.path.join(INPUT_DIR, cat, 'augmented'), exist_ok=True) # Create an 'augmented' folder inside each category
26
+ files = glob(f"{INPUT_DIR}/{cat}/*")
27
+
28
+ for i, file in enumerate(files):
29
+ # Skip non-image files
30
+ if not any(file.lower().endswith(ext) for ext in valid_extensions):
31
+ continue
32
+
33
+ img = cv2.imread(file)
34
+ if img is None:
35
+ continue
36
+ img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
37
+
38
+ # Generate 3 augmented images
39
+ for j in range(3):
40
+ aug = AUG(image=img)["image"]
41
+ save_path = os.path.join(INPUT_DIR, cat, 'augmented', f"aug_{i}_{j}.jpg")
42
+ cv2.imwrite(save_path, cv2.cvtColor(aug, cv2.COLOR_RGB2BGR))
43
+
44
+ print("βœ… Augmentation complete. You can now re-run feature extraction and model training.")
scripts/ensemble_model.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import numpy as np
3
+ from sklearn.ensemble import VotingClassifier
4
+ from sklearn.metrics import classification_report
5
+ from sklearn.ensemble import RandomForestClassifier
6
+ from sklearn.svm import SVC
7
+ from xgboost import XGBClassifier
8
+ import joblib
9
+ from sklearn.model_selection import train_test_split
10
+
11
+ # Load pre-extracted features and labels
12
+ print("πŸ“¦ Loading pre-extracted features and labels...")
13
+
14
+ # Load the features (X) and labels (y)
15
+ X = np.load("features/embeddings.npy")
16
+ y = np.load("features/labels.npy")
17
+
18
+ print(f"βœ… Loaded {len(X)} samples with {X.shape[1]} features each.")
19
+
20
+ # Split into training and testing sets
21
+ X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
22
+
23
+ # Initialize individual classifiers
24
+ rf = RandomForestClassifier(n_estimators=100, random_state=42)
25
+ svm = SVC(probability=True, kernel='linear') # Using probability=True for soft voting
26
+ xgb = XGBClassifier(use_label_encoder=False, eval_metric='mlogloss')
27
+
28
+ # Create the Voting Classifier ensemble
29
+ ensemble_clf = VotingClassifier(estimators=[('rf', rf), ('svm', svm), ('xgb', xgb)], voting='soft')
30
+
31
+ # Train the ensemble model
32
+ print("🧠 Training the ensemble classifier...")
33
+ ensemble_clf.fit(X_train, y_train)
34
+
35
+ # Evaluate the ensemble model
36
+ print("\nπŸ“Š Evaluation Report:")
37
+ y_pred = ensemble_clf.predict(X_test)
38
+ print(classification_report(y_test, y_pred, target_names=["real", "deepfake", "ai_gen"]))
39
+
40
+ # Save the trained ensemble model
41
+ os.makedirs("model", exist_ok=True)
42
+ joblib.dump(ensemble_clf, "model/ensemble_model.pkl")
43
+
44
+ print("\nβœ… Ensemble model trained and saved to model/ensemble_model.pkl")
scripts/extract_audio_features.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import librosa
3
+ import numpy as np
4
+
5
+ DATA_DIR = "data"
6
+ CATEGORIES = ["real_audio", "fake_audio"]
7
+ OUTPUT_DIR = "features_audio"
8
+ os.makedirs(OUTPUT_DIR, exist_ok=True)
9
+
10
+ X, y = [], []
11
+
12
+ # Data augmentation techniques
13
+ def augment_audio(audio, sr):
14
+ # Example: Shift pitch randomly within a range
15
+ pitch_shift = np.random.randint(-5, 5) # Random pitch shift between -5 and 5 semitones
16
+ audio = librosa.effects.pitch_shift(audio, sr, n_steps=pitch_shift)
17
+
18
+ # Example: Time stretch randomly between 0.8x and 1.2x speed
19
+ rate = np.random.uniform(0.8, 1.2)
20
+ audio = librosa.effects.time_stretch(audio, rate)
21
+
22
+ # Example: Add random noise
23
+ noise_factor = np.random.uniform(0.001, 0.005) # Random noise factor
24
+ noise = np.random.randn(len(audio)) * noise_factor
25
+ audio = audio + noise
26
+
27
+ return audio
28
+
29
+ def extract_mfcc(path):
30
+ try:
31
+ audio, sr = librosa.load(path, sr=16000) # Load the audio with 16kHz sampling rate
32
+
33
+ # Apply audio augmentation
34
+ audio = augment_audio(audio, sr)
35
+
36
+ # Extract MFCCs from the augmented audio
37
+ mfcc = librosa.feature.mfcc(y=audio, sr=sr, n_mfcc=13)
38
+ mfcc_mean = np.mean(mfcc.T, axis=0) # Average MFCC features
39
+ return mfcc_mean
40
+ except Exception as e:
41
+ print(f"[ERROR] Failed to process {path}: {e}")
42
+ return None
43
+
44
+ # Loop through each category and process audio files
45
+ for label, cat in enumerate(CATEGORIES):
46
+ folder = os.path.join(DATA_DIR, cat)
47
+ for fname in os.listdir(folder):
48
+ if not fname.endswith(".wav"): # Only process .wav files
49
+ continue
50
+ fpath = os.path.join(folder, fname)
51
+ features = extract_mfcc(fpath) # Extract MFCC features
52
+ if features is not None:
53
+ X.append(features)
54
+ y.append(label)
55
+
56
+ # Save the extracted features and labels
57
+ np.save(os.path.join(OUTPUT_DIR, "embeddings.npy"), np.array(X))
58
+ np.save(os.path.join(OUTPUT_DIR, "labels.npy"), np.array(y))
59
+
60
+ print(f"βœ… Extracted MFCC features for {len(X)} audio samples.")
scripts/extract_features.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import torch
3
+ import numpy as np
4
+ from PIL import Image
5
+ from tqdm import tqdm
6
+ from facenet_pytorch import InceptionResnetV1, MTCNN
7
+ from transformers import CLIPProcessor, CLIPModel
8
+ import albumentations as A
9
+ import cv2
10
+
11
+ # Set device
12
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
13
+ print(f"[INFO] Using device: {device}")
14
+
15
+ # Initialize models
16
+ mtcnn = MTCNN(image_size=160, device=device)
17
+ facenet = InceptionResnetV1(pretrained='vggface2').eval().to(device)
18
+
19
+ # Load CLIP model and processor
20
+ clip_model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32").to(device)
21
+ clip_processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
22
+
23
+ # Input data folders
24
+ DATA_DIR = "data"
25
+ CATEGORIES = ["real", "deepfake", "ai_gen"]
26
+
27
+ # Output path
28
+ os.makedirs("features", exist_ok=True)
29
+
30
+ # Data augmentation pipeline
31
+ augment = A.Compose([
32
+ A.RandomBrightnessContrast(p=0.2),
33
+ A.HorizontalFlip(p=0.5),
34
+ A.Rotate(limit=10, p=0.3),
35
+ A.MotionBlur(p=0.2),
36
+ A.Resize(160, 160), # For MTCNN size requirement
37
+ ])
38
+
39
+ def extract_facenet_features(img_path):
40
+ image = Image.open(img_path).convert("RGB")
41
+
42
+ # Resize image before passing it to MTCNN
43
+ img_np = np.array(image)
44
+ img_resized = cv2.resize(img_np, (160, 160)) # Resize image to 160x160
45
+
46
+ # Apply augmentation
47
+ augmented = augment(image=img_resized)["image"]
48
+ img_aug = Image.fromarray(augmented)
49
+
50
+ # Face detection using MTCNN
51
+ face = mtcnn(img_aug)
52
+ if face is None:
53
+ print(f"[WARN] No face detected in {img_path}")
54
+ return None
55
+ face = face.unsqueeze(0).to(device)
56
+
57
+ # Feature extraction using FaceNet
58
+ with torch.no_grad():
59
+ face_emb = facenet(face)
60
+
61
+ return face_emb.squeeze().cpu().numpy()
62
+
63
+ def extract_clip_features(img_path):
64
+ image = Image.open(img_path).convert("RGB")
65
+
66
+ # Apply the same augmentation to the image before passing to CLIP
67
+ img_np = np.array(image)
68
+ augmented = augment(image=img_np)["image"]
69
+ img_aug = Image.fromarray(augmented)
70
+
71
+ # Extract features using CLIP
72
+ inputs = clip_processor(images=img_aug, return_tensors="pt").to(device)
73
+ with torch.no_grad():
74
+ clip_outputs = clip_model.get_image_features(**inputs)
75
+
76
+ return clip_outputs.cpu().numpy().squeeze()
77
+
78
+ def extract_combined_features(img_path):
79
+ # Extract features from both FaceNet and CLIP
80
+ facenet_features = extract_facenet_features(img_path)
81
+ clip_features = extract_clip_features(img_path)
82
+
83
+ if facenet_features is None:
84
+ return None
85
+
86
+ # Combine (concatenate) the features from FaceNet and CLIP
87
+ combined_features = np.concatenate((facenet_features, clip_features))
88
+ return combined_features
89
+
90
+ def extract_all_features():
91
+ X, y = [], []
92
+ for label, category in enumerate(CATEGORIES):
93
+ folder = os.path.join(DATA_DIR, category)
94
+ if not os.path.isdir(folder):
95
+ print(f"[WARN] Missing folder: {folder}")
96
+ continue
97
+
98
+ print(f"\n🧠 Extracting from: {category} ({folder})")
99
+ for fname in tqdm(os.listdir(folder)):
100
+ if not fname.lower().endswith((".jpg", ".jpeg", ".png")):
101
+ continue
102
+ path = os.path.join(folder, fname)
103
+ combined_features = extract_combined_features(path)
104
+ if combined_features is not None:
105
+ X.append(combined_features)
106
+ y.append(label)
107
+
108
+ # Save the extracted features
109
+ np.save("../features/embeddings.npy", np.array(X))
110
+ np.save("../features/labels.npy", np.array(y))
111
+ print(f"\nβœ… Done: Saved {len(X)} embeddings.")
112
+
113
+ if __name__ == "__main__":
114
+ extract_all_features()
scripts/predict.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ import torch
3
+ import numpy as np
4
+ import joblib
5
+ from PIL import Image
6
+ from transformers import CLIPProcessor, CLIPModel
7
+ from io import BytesIO
8
+
9
+ # Load models
10
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
11
+ model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32").to(device)
12
+ processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
13
+ ensemble_clf = joblib.load("models/random_forest_aug.pkl")
14
+
15
+ label_map = {0: "real", 1: "deepfake", 2: "ai_gen"}
16
+
17
+ def extract_features(image):
18
+ image = image.resize((224, 224)) # Resize image
19
+ inputs = processor(images=image, return_tensors="pt").to(device)
20
+ with torch.no_grad():
21
+ outputs = model.get_image_features(**inputs)
22
+ emb = outputs.cpu().numpy().squeeze()
23
+ return emb
24
+
25
+ def predict(image_path):
26
+ image = Image.open(image_path).convert("RGB")
27
+ features = extract_features(image)
28
+ probs = ensemble_clf.predict_proba([features])[0]
29
+ top_idx = np.argmax(probs)
30
+ print(f"Prediction: {label_map[top_idx]}")
31
+ print(f"Probabilities: {probs}")
32
+
33
+ if __name__ == "__main__":
34
+ if len(sys.argv) != 2:
35
+ print("Usage: python predict.py <image_path>")
36
+ sys.exit(1)
37
+ predict(sys.argv[1])
38
+
39
+
scripts/predict_audio.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ import librosa
3
+ import numpy as np
4
+ import joblib
5
+
6
+ def extract_mfcc(path):
7
+ try:
8
+ audio, sr = librosa.load(path, sr=16000) # Load the audio with 16kHz sample rate
9
+ mfcc = librosa.feature.mfcc(y=audio, sr=sr, n_mfcc=13) # Extract MFCC features
10
+ return np.mean(mfcc.T, axis=0) # Return the mean of MFCCs across time
11
+ except Exception as e:
12
+ print(f"[ERROR] Failed to process {path}: {e}")
13
+ return None
14
+
15
+ def predict_audio(path):
16
+ # Extract features from the given audio path
17
+ features = extract_mfcc(path)
18
+ if features is None:
19
+ return # Exit if feature extraction fails
20
+
21
+ # Load pre-trained Random Forest model for audio prediction
22
+ model = joblib.load("model/audio_rf.pkl")
23
+
24
+ # Reshape the features to match the expected input shape (1, -1)
25
+ features = features.reshape(1, -1)
26
+
27
+ # Make prediction
28
+ pred = model.predict(features)[0]
29
+
30
+ # Map the prediction to class labels (real: 0, fake: 1)
31
+ label = "real" if pred == 0 else "fake"
32
+
33
+ # Print the prediction
34
+ print(f"🎧 Prediction: {label}")
35
+
36
+ if __name__ == "__main__":
37
+ if len(sys.argv) != 2:
38
+ print("Usage: python scripts/predict_audio.py <audio_path>")
39
+ sys.exit(1)
40
+
41
+ # Get the audio file path from command line argument
42
+ path = sys.argv[1]
43
+
44
+ # Predict the audio label
45
+ predict_audio(path)
scripts/predict_video.py ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import torch
3
+ import numpy as np
4
+ from PIL import Image
5
+ import joblib
6
+ from facenet_pytorch import MTCNN, InceptionResnetV1
7
+
8
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
9
+ print(f"[INFO] Using device: {device}")
10
+
11
+ # Load models
12
+ mtcnn = MTCNN(image_size=160, device=device)
13
+ facenet = InceptionResnetV1(pretrained='vggface2').eval().to(device)
14
+ clf = joblib.load("model/ensemble_model.pkl") # Example classifier model
15
+ label_map = {0: "real", 1: "deepfake", 2: "ai_gen"}
16
+
17
+ def extract_faces_from_video(video_path, time_interval_sec=10):
18
+ cap = cv2.VideoCapture(video_path)
19
+ embeddings = []
20
+
21
+ # Get the total number of frames in the video and the FPS
22
+ total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
23
+ fps = cap.get(cv2.CAP_PROP_FPS())
24
+ video_duration = total_frames / fps # Video duration in seconds
25
+ print(f"[INFO] Video duration: {video_duration} seconds, FPS: {fps}")
26
+
27
+ # Calculate the frame skip based on the desired time interval
28
+ frame_skip = int(fps * time_interval_sec) # Process frames every 'time_interval_sec' seconds
29
+ print(f"[INFO] Processing every {time_interval_sec} seconds. Skipping {frame_skip} frames.")
30
+
31
+ frame_idx = 0
32
+ while True:
33
+ ret, frame = cap.read()
34
+ if not ret:
35
+ break
36
+
37
+ # Process frames based on the calculated frame skip
38
+ if frame_idx % frame_skip == 0:
39
+ image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) # Convert to RGB
40
+ combined_features = extract_combined_features(image) # Assuming extract_combined_features() is defined
41
+
42
+ if combined_features is not None:
43
+ embeddings.append(combined_features)
44
+
45
+ frame_idx += 1
46
+
47
+ cap.release()
48
+ return embeddings
49
+
50
+ def extract_combined_features(image):
51
+ # Example: Combine features from FaceNet and CLIP (code for this is assumed to be defined already)
52
+ facenet_features = extract_facenet_features(image)
53
+ clip_features = extract_clip_features(image)
54
+
55
+ if facenet_features is None:
56
+ return None
57
+
58
+ # Combine (concatenate) the features from FaceNet and CLIP
59
+ combined_features = np.concatenate((facenet_features, clip_features))
60
+ return combined_features
61
+
62
+ def extract_facenet_features(image):
63
+ # Example function for FaceNet feature extraction
64
+ pass
65
+
66
+ def extract_clip_features(image):
67
+ # Example function for CLIP feature extraction
68
+ pass
69
+
70
+ def predict_video(video_path):
71
+ embeddings = extract_faces_from_video(video_path, time_interval_sec=10)
72
+
73
+ if not embeddings:
74
+ print("[WARN] No faces found in video.")
75
+ return
76
+
77
+ # Predict using the classifier
78
+ preds = clf.predict(embeddings)
79
+
80
+ # Majority voting for final prediction
81
+ final_pred = np.bincount(preds).argmax() # Most frequent label
82
+ print(f"\n🧠 Final Video Prediction: {label_map[final_pred]} ({len(preds)} frame(s) used)")
83
+
84
+ if __name__ == "__main__":
85
+ import sys
86
+ if len(sys.argv) != 2:
87
+ print("Usage: python scripts/predict_video.py <video_path>")
88
+ sys.exit(1)
89
+
90
+ # Run the video prediction function
91
+ predict_video(sys.argv[1])
scripts/random_forest.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import numpy as np
3
+ from sklearn.ensemble import RandomForestClassifier
4
+ from sklearn.metrics import classification_report
5
+ import joblib
6
+
7
+ # Load pre-extracted features and labels
8
+ print("πŸ“¦ Loading pre-extracted features and labels...")
9
+
10
+ # Load the features (X) and labels (y)
11
+ X = np.load("features/embeddings.npy")
12
+ y = np.load("features/labels.npy")
13
+
14
+ print(f"βœ… Loaded {len(X)} samples with {X.shape[1]} features each.")
15
+
16
+ # Split into training and testing sets
17
+ from sklearn.model_selection import train_test_split
18
+ X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
19
+
20
+ # Initialize and train RandomForestClassifier
21
+ print("🧠 Training RandomForestClassifier...")
22
+ rf = RandomForestClassifier(n_estimators=100, random_state=42)
23
+ rf.fit(X_train, y_train)
24
+
25
+ # Evaluate the model
26
+ print("\nπŸ“Š Evaluation Report:")
27
+ y_pred = rf.predict(X_test)
28
+ print(classification_report(y_test, y_pred, target_names=["real", "deepfake", "ai_gen"]))
29
+
30
+ # Save the trained model
31
+ os.makedirs("model", exist_ok=True)
32
+ joblib.dump(rf, "model/random_forest.pkl")
33
+
34
+ print("\nβœ… Model trained and saved to model/random_forest.pkl")
scripts/stacking_model.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import numpy as np
3
+ from sklearn.ensemble import RandomForestClassifier, StackingClassifier
4
+ from sklearn.svm import SVC
5
+ from xgboost import XGBClassifier
6
+ from sklearn.linear_model import LogisticRegression
7
+ from sklearn.metrics import classification_report
8
+ from sklearn.model_selection import train_test_split
9
+ import joblib
10
+
11
+ # Load the pre-extracted features and labels
12
+ print("πŸ“¦ Loading pre-extracted features and labels...")
13
+
14
+ # Load the features (X) and labels (y)
15
+ X = np.load("features/embeddings.npy")
16
+ y = np.load("features/labels.npy")
17
+
18
+ print(f"βœ… Loaded {len(X)} samples with {X.shape[1]} features each.")
19
+
20
+ # Split into training and testing sets
21
+ X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
22
+
23
+ # Initialize the base models
24
+ rf = RandomForestClassifier(n_estimators=100, random_state=42)
25
+ svm = SVC(probability=True, kernel='linear') # SVM with probability for soft voting
26
+ xgb = XGBClassifier(use_label_encoder=False, eval_metric='mlogloss')
27
+
28
+ # Create the meta-model (Logistic Regression)
29
+ meta_model = LogisticRegression()
30
+
31
+ # Create the Stacking Classifier
32
+ stacking_model = StackingClassifier(estimators=[('rf', rf), ('svm', svm), ('xgb', xgb)], final_estimator=meta_model)
33
+
34
+ # Train the stacking model
35
+ print("🧠 Training the stacking classifier...")
36
+ stacking_model.fit(X_train, y_train)
37
+
38
+ # Evaluate the model
39
+ print("\nπŸ“Š Evaluation Report:")
40
+ y_pred = stacking_model.predict(X_test)
41
+ print(classification_report(y_test, y_pred, target_names=["real", "deepfake", "ai_gen"]))
42
+
43
+ # Save the trained stacking model
44
+ os.makedirs("model", exist_ok=True)
45
+ joblib.dump(stacking_model, "model/stacking_model.pkl")
46
+
47
+ print("\nβœ… Stacking model trained and saved to model/stacking_model.pkl")
scripts/svm.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import numpy as np
3
+ from sklearn.svm import SVC
4
+ from sklearn.metrics import classification_report
5
+ import joblib
6
+
7
+ # Load pre-extracted features and labels
8
+ print("πŸ“¦ Loading pre-extracted features and labels...")
9
+
10
+ # Load the features (X) and labels (y)
11
+ X = np.load("features/embeddings.npy")
12
+ y = np.load("features/labels.npy")
13
+
14
+ print(f"βœ… Loaded {len(X)} samples with {X.shape[1]} features each.")
15
+
16
+ # Split into training and testing sets
17
+ from sklearn.model_selection import train_test_split
18
+ X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
19
+
20
+ # Initialize and train SVM Classifier
21
+ print("🧠 Training SVM Classifier...")
22
+ svm = SVC(probability=True, kernel='linear') # Using probability=True for soft voting
23
+ svm.fit(X_train, y_train)
24
+
25
+ # Evaluate the model
26
+ print("\nπŸ“Š Evaluation Report:")
27
+ y_pred = svm.predict(X_test)
28
+ print(classification_report(y_test, y_pred, target_names=["real", "deepfake", "ai_gen"]))
29
+
30
+ # Save the trained model
31
+ os.makedirs("model", exist_ok=True)
32
+ joblib.dump(svm, "model/svm.pkl")
33
+
34
+ print("\nβœ… Model trained and saved to model/svm.pkl")
scripts/xgboost.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import numpy as np
3
+ from xgboost import XGBClassifier
4
+ from sklearn.metrics import classification_report
5
+ import joblib
6
+
7
+ # Load pre-extracted features and labels
8
+ print("πŸ“¦ Loading pre-extracted features and labels...")
9
+
10
+ # Load the features (X) and labels (y)
11
+ X = np.load("features/embeddings.npy")
12
+ y = np.load("features/labels.npy")
13
+
14
+ print(f"βœ… Loaded {len(X)} samples with {X.shape[1]} features each.")
15
+
16
+ # Split into training and testing sets
17
+ from sklearn.model_selection import train_test_split
18
+ X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
19
+
20
+ # Initialize and train XGBoost Classifier
21
+ print("🧠 Training XGBoost Classifier...")
22
+ xgb = XGBClassifier(use_label_encoder=False, eval_metric='mlogloss')
23
+ xgb.fit(X_train, y_train)
24
+
25
+ # Evaluate the model
26
+ print("\nπŸ“Š Evaluation Report:")
27
+ y_pred = xgb.predict(X_test)
28
+ print(classification_report(y_test, y_pred, target_names=["real", "deepfake", "ai_gen"]))
29
+
30
+ # Save the trained model
31
+ os.makedirs("model", exist_ok=True)
32
+ joblib.dump(xgb, "model/xgboost.pkl")
33
+
34
+ print("\nβœ… Model trained and saved to model/xgboost.pkl")
space.yaml ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ # space.yaml
2
+ sdk: docker
3
+ app_port: 7860