Detect AI-generated images and deepfake videos using a CNN + ViT ensemble pipeline.
DeepScan is a full-stack deepfake detection web application that analyses images and videos to determine whether they are AI-generated or authentic. It uses a fine-tuned MobileNetV2 CNN ensembled with a HuggingFace ViT (Wvolf/ViT_Deepfake_Detection) as its core classification models, served via a Flask + FastAPI backend hosted on Hugging Face Spaces, with a polished chat-style frontend deployed on Netlify.
The scoring pipeline differs by media type:
Image:
cnn_fake_prob = raw_sigmoid (IMAGE_INVERT_SIGMOID = False)
hf_fake_prob = ViT score for "fake" label
fake_prob = max(cnn_fake_prob, hf_fake_prob) β ensemble
threshold = 0.35
Video:
fake_prob = 1.0 β raw_sigmoid (VIDEO_INVERT_SIGMOID = True)
threshold = 0.50
- πΌοΈ Image analysis β Upload JPG / PNG / WebP images for CNN + ViT ensemble deepfake scoring
- π¬ Video analysis β Frame-by-frame CNN analysis (25 frames sampled) with per-frame thumbnails, timeline chart, and frame table
- π Probability bar β Visual fake probability gauge with threshold marker
- π€ AI explanations β Groq LLM (LLaMA 3.1 8B / 70B) generates human-readable forensic explanations per scan
- π PDF reports β Professional multi-page PDF report download (image & video variants)
- π History view β Local scan history with thumbnails and verdict pills
- βοΈ Settings panel β Configurable thresholds, Groq API key, Flask server URL
- π¬ Diagnose endpoint β
/diagnoseAPI to inspect raw sigmoid values and validate model inversion settings - π± Fully responsive β Mobile-first design with slide-in sidebar and touch-friendly UI
βββββββββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββ
β FRONTEND β β BACKEND β
β Netlify (Static HTML/CSS/JS) βββββββββΊβ Hugging Face Spaces β
β β REST β Flask (port 7860) β
β β’ app.html (chat UI) β API β + FastAPI (port 8000) β
β β’ static/style.css β β β’ /api/analyse/image β
β β’ static/app.js β β β’ /api/analyse/video β
β β’ index.html (landing page) β β β’ /api/groq/explain β
βββββββββββββββββββββββββββββββββββ β β’ /api/status β
β β’ /diagnose β
β β
β MobileNetV2 CNN β
β deepfake_model.h5 β
β + ViT (HuggingFace ensemble) β
ββββββββββββββββββββββββββββββββββββ
| Layer | Technology | Hosting |
|---|---|---|
| Frontend | Vanilla HTML / CSS / JavaScript | Netlify |
| Backend API | Flask + FastAPI (Python) | Hugging Face Spaces |
| ML Model (Image) | MobileNetV2 CNN + ViT ensemble (TensorFlow / Keras + HuggingFace) | Hugging Face Spaces |
| ML Model (Video) | MobileNetV2 CNN β batch frame inference | Hugging Face Spaces |
| AI Explanations | Groq API β LLaMA 3.1 8B / 70B | Client-side or Flask proxy |
| PDF Generation | jsPDF 2.5.1 (client-side) | Browser |
Deepscan/
βββ Backend/
β βββ flask_app.py
β βββ deepfake_model.h5
β βββ __init__.py
β βββ start.sh
β βββ video_api.py
β βββ requirements.txt
βββ Frontend/
β βββ static/
β β βββ style.css
β β βββ app.js
β βββ app.html
β βββ index.html
βββ README.md
| Detail | Value |
|---|---|
| Base model | MobileNetV2 (ImageNet pre-trained) |
| Ensemble model | ViT β Wvolf/ViT_Deepfake_Detection (HuggingFace, images only) |
| Fine-tuned on | Deepfake vs Real image/video dataset |
| Output | Sigmoid (behaviour differs by media type β see scoring above) |
| Image scoring | fake_prob = max(cnn_sigmoid, vit_score) Β· threshold 0.35 |
| Video scoring | fake_prob = 1.0 β raw_sigmoid Β· threshold 0.50 |
| Frames per video | 25 (evenly sampled) |
| Input size | 224 Γ 224 px |
| Preprocessing | mobilenet_v2.preprocess_input() β scales to [β1, 1] |
Deepfake vs Real β 60K Β· Prithiv Sakthiur Β· Kaggle
https://www.kaggle.com/datasets/prithivsakthiur/deepfake-vs-real-60k
A balanced dataset of 60,000 images split evenly between AI-generated deepfake faces and real photographs, used to train and validate the image classification head.
FaceForensics++ Β· ondyari Β· GitHub
https://github.com/ondyari/FaceForensics
A large-scale benchmark dataset of manipulated facial videos covering multiple manipulation methods (DeepFakes, Face2Face, FaceSwap, NeuralTextures). Video frames were extracted and used to extend the training set for video-mode inference.
python >= 3.10
pip
node (optional β for local frontend dev)
git clone https://github.com/Sanjay20057/Deepscan.git
cd Deepscanpip install -r Backend/requirements.txtPlace your trained deepfake_model.h5 in the Backend/ directory, or train from scratch:
python train.pyCreate a .env file in the Backend/ directory:
GROQ_API_KEY=gsk_your_groq_key_here
# Optional overrides (defaults shown)
FASTAPI_BASE_URL=http://localhost:8000
FLASK_PORT=7860
MAX_UPLOAD_MB=5
FRAMES_PER_VIDEO=25
IMAGE_FAKE_THRESHOLD=0.35
VIDEO_FAKE_THRESHOLD=0.50
IMAGE_INVERT_SIGMOID=false
VIDEO_INVERT_SIGMOID=true
PREPROCESS_MODE=mobilenetGroq API key is optional β without it, the AI explanation feature is disabled. Users can supply their own key in the UI settings panel.
# Option A β convenience script
bash Backend/start.sh
# Option B β manually in two terminals
python Backend/flask_app.py
uvicorn video_api:app --host 0.0.0.0 --port 8000 --reloadpython -m http.server 3000
# Then visit http://localhost:3000/app.htmlThe Flask + FastAPI backend is hosted as a Gradio SDK Space on Hugging Face:
https://huggingface.co/spaces/sanjay72005/deepscan
All CNN inference, ViT ensemble scoring, frame extraction (video), and Groq proxy calls are handled here. The frontend calls this origin directly via fetch.
The static frontend (app.html, static/, index.html) is deployed via Netlify:
https://deepscan.netlify.app
No build step required β Netlify serves the files as-is. Push to the connected GitHub repository or drag-and-drop the Frontend/ folder into the Netlify dashboard to redeploy.
All endpoints are served from https://sanjay72005-deepscan.hf.space.
Returns server health, model load status, pipeline info, and Groq configuration flag.
{
"fastapi_ok": true,
"model_loaded": true,
"groq_configured": true,
"pipeline": "cnn-only",
"fake_threshold": 0.5,
"max_upload_mb": 5
}Analyse a single image using the CNN + ViT ensemble.
Request: multipart/form-data β field file (JPG / PNG / WebP, max 5 MB)
Response:
{
"media_type": "image",
"verdict": "fake",
"fake_probability": 0.7823,
"confidence_pct": 78.2,
"cnn_label": "fake",
"cnn_confidence": 0.7823
}Analyse a video file frame-by-frame (25 frames sampled by default).
Request: multipart/form-data β field file (MP4 / MOV / AVI / MKV / WebM / FLV, max 5 MB)
Response:
{
"media_type": "video",
"verdict": "fake",
"fake_probability": 0.6541,
"fake_frame_count": 14,
"total_frames_analysed": 25,
"frame_results": [
{
"frame_index": 0,
"timestamp_sec": 0.0,
"cnn_label": "fake",
"cnn_confidence": 0.712,
"fake_prob": 0.712,
"verdict": "fake",
"thumbnail_b64": "..."
}
]
}Proxy endpoint for Groq LLM explanation generation (uses server-side API key).
Request:
{ "prompt": "...", "max_tokens": 460 }Debug endpoint β upload any image to inspect raw sigmoid values and verify INVERT_SIGMOID is set correctly for your model weights.
Response:
{
"raw_sigmoid": 0.123456,
"fake_prob_current": 0.876544,
"verdict_current": "FAKE",
"fake_prob_if_flipped": 0.123456,
"verdict_if_flipped": "REAL",
"advice": "If verdict_current is wrong for a KNOWN real image, set INVERT_SIGMOID=false..."
}| Step | Action |
|---|---|
| 1 | Click the π attach button or drag & drop a file (max 5 MB) |
| 2 | Select Image or Video mode |
| 3 | (Optional) Click βοΈ to enter your Groq API key for AI explanations |
| 4 | Press the π Analyse button (or press Enter) |
| 5 | View verdict, probability bar, signal table, and AI explanation |
| 6 | Download a Professional PDF Report |
If the Hugging Face backend is offline, the UI automatically falls back to a demo simulation so you can preview the full interface without a live server.
flask
flask-cors
fastapi
uvicorn
tensorflow / keras
opencv-python
numpy
pillow
python-dotenv
requests
transformers
jsPDF 2.5.1 β client-side PDF generation
- Image mode uses a CNN + ViT ensemble (max of both scores); video mode uses CNN only
- Preprocessing uses
mobilenet_v2.preprocess_input()β scales pixels to [β1, 1], not plain/255 IMAGE_INVERT_SIGMOID = False(sigmoid used directly for images);VIDEO_INVERT_SIGMOID = True(fake_prob = 1 β sigmoidfor video)- Image fake threshold is 0.35; video fake threshold is 0.50
- Video inference can take 30β90 seconds depending on file length and server load
- Results are probabilistic β not a certified forensic determination
- A 5 MB file size limit is enforced on both frontend and backend for all uploads
Pull requests are welcome. For major changes, please open an issue first to discuss what you'd like to change.
- Fork the repository
- Create your feature branch:
git checkout -b feature/my-feature - Commit your changes:
git commit -m 'Add my feature' - Push to the branch:
git push origin feature/my-feature - Open a pull request
This project is licensed under the MIT License β see LICENSE for details.
- Prithiv Sakthiur β Deepfake vs Real 60K image dataset
- ondyari / FaceForensics β FaceForensics++ video benchmark
- Google MobileNetV2 β Backbone CNN architecture
- Wvolf / ViT_Deepfake_Detection β HuggingFace ViT ensemble model
- Groq β Ultra-fast LLM inference for AI explanations
- Hugging Face Spaces β Free GPU-backed backend hosting
- Netlify β Zero-config static frontend hosting
Made with β€οΈ by Sanjay
π Live Demo Β· π€ Backend API Β· π¦ Dataset (Images) Β· π¦ Dataset (Videos)