import streamlit as st import cv2, numpy as np from retinaface import RetinaFace from tensorflow.keras.models import load_model from tensorflow.keras.applications.efficientnet import preprocess_input from huggingface_hub import hf_hub_download import tempfile, os st.set_page_config( page_title="Deepfake Detector", page_icon="🎭", layout="centered" ) st.markdown("""

🎭 Deepfake Detection System

EfficientNetB0 + RetinaFace | Trained on FaceForensics++


""", unsafe_allow_html=True) @st.cache_resource def load_detector(): with st.spinner("Loading model..."): model_path = hf_hub_download( repo_id="yyouretoast/deepfake-detection", filename="deepfake_final_SUBMIT.keras" ) return load_model(model_path) try: model = load_detector() except Exception as e: st.error(f"❌ Model failed to load: {e}") st.stop() IMG_SIZE = 224 PADDING = 20 FRAMES_TO_SAMPLE = 8 def predict_video(video_path): cap = cv2.VideoCapture(video_path) total = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) if total == 0: return None, None, None, None, None step = max(total // FRAMES_TO_SAMPLE, 1) frame_preds = [] sample_frames = [] for i in range(FRAMES_TO_SAMPLE): cap.set(cv2.CAP_PROP_POS_FRAMES, i * step) ret, frame = cap.read() if not ret or frame is None: continue rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) try: faces = RetinaFace.detect_faces(rgb) except: continue if not isinstance(faces, dict) or len(faces) == 0: continue best_face = max(faces.keys(), key=lambda k: ( faces[k]["facial_area"][2] - faces[k]["facial_area"][0]) * (faces[k]["facial_area"][3] - faces[k]["facial_area"][1]) ) x1, y1, x2, y2 = faces[best_face]["facial_area"] x1 = max(0, x1 - PADDING) y1 = max(0, y1 - PADDING) x2 = min(rgb.shape[1], x2 + PADDING) y2 = min(rgb.shape[0], y2 + PADDING) face = rgb[y1:y2, x1:x2] if face.size == 0 or face.shape[0] < 10 or face.shape[1] < 10: continue face_resized = cv2.resize(face, (IMG_SIZE, IMG_SIZE)) img_array = preprocess_input( np.expand_dims(face_resized.astype("float32"), axis=0) ) pred = model.predict(img_array, verbose=0)[0][0] frame_preds.append(pred) if len(sample_frames) < 4: label = "Real" if pred > 0.5 else "Fake" conf = pred * 100 if pred > 0.5 else (1 - pred) * 100 sample_frames.append((face_resized, label, conf)) cap.release() if not frame_preds: return None, None, None, None, None avg_pred = np.mean(frame_preds) final_label = "Real" if avg_pred > 0.5 else "Fake" final_conf = avg_pred * 100 if avg_pred > 0.5 else (1 - avg_pred) * 100 fake_frames = sum(1 for p in frame_preds if p <= 0.5) real_frames = len(frame_preds) - fake_frames return final_label, final_conf, real_frames, fake_frames, sample_frames # Upload st.markdown("### 📤 Upload a Video") uploaded = st.file_uploader( "Choose a video file (max 50MB)", type=["mp4", "avi", "mov"] ) if uploaded: if uploaded.size > 50 * 1024 * 1024: st.error("❌ File too large — please upload a video under 50MB") st.stop() content = uploaded.read() with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp: tmp.write(content) tmp_path = tmp.name st.video(content) with st.spinner("🔍 Analyzing video..."): final_label, final_conf, real_frames, fake_frames, sample_frames = predict_video(tmp_path) os.unlink(tmp_path) if final_label is None: st.error("❌ No faces detected in video") else: st.markdown("
", unsafe_allow_html=True) color = "#e53935" if final_label == "Fake" else "#43a047" icon = "🚨" if final_label == "Fake" else "✅" st.markdown(f"""

{icon} {final_label.upper()}

Confidence: {final_conf:.1f}%

""", unsafe_allow_html=True) st.markdown("
", unsafe_allow_html=True) col1, col2, col3 = st.columns(3) col1.metric("Frames Analyzed", real_frames + fake_frames) col2.metric("Real Frames", real_frames) col3.metric("Fake Frames", fake_frames) st.markdown("### 📊 Confidence Score") st.progress(min(int(final_conf), 100)) if sample_frames: st.markdown("### 🖼️ Sample Frame Predictions") cols = st.columns(len(sample_frames)) for col, (face_img, label, conf) in zip(cols, sample_frames): with col: st.image(face_img, width=150) c = "green" if label == "Real" else "red" st.markdown( f"

{label}
{conf:.1f}%

", unsafe_allow_html=True ) st.markdown("
", unsafe_allow_html=True) st.markdown("""

Powered by EfficientNetB0 + RetinaFace | Trained on FaceForensics++ | 90.4% Accuracy

""", unsafe_allow_html=True)