Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -3,13 +3,15 @@ from flask_cors import CORS
|
|
| 3 |
import requests
|
| 4 |
import os
|
| 5 |
import re
|
|
|
|
| 6 |
import hashlib
|
| 7 |
import datetime
|
| 8 |
import base64
|
| 9 |
import time
|
| 10 |
import torch
|
| 11 |
import torch.nn as nn
|
| 12 |
-
from
|
|
|
|
| 13 |
|
| 14 |
app = Flask(__name__)
|
| 15 |
CORS(app)
|
|
@@ -71,6 +73,21 @@ except Exception as e:
|
|
| 71 |
print(f"β Text model failed to load: {type(e).__name__}: {e}")
|
| 72 |
|
| 73 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
def _ai_prob_for_chunk(chunk):
|
| 75 |
enc = _tokenizer(chunk, truncation=True, max_length=512, return_tensors="pt")
|
| 76 |
with torch.no_grad():
|
|
@@ -218,31 +235,31 @@ def build_signals(trust_score, ai_probability, used_hf):
|
|
| 218 |
|
| 219 |
|
| 220 |
def detect_image_deepfake(image_data):
|
|
|
|
|
|
|
|
|
|
|
|
|
| 221 |
try:
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
fake_score = scores[1]['score']
|
| 240 |
-
deepfake_prob = round(fake_score * 100)
|
| 241 |
-
real_prob = round(real_score * 100)
|
| 242 |
-
return {"success":True,"deepfake_probability":deepfake_prob,"real_probability":real_prob,"verdict":"DEEPFAKE" if deepfake_prob > 50 else "AUTHENTIC","confidence":max(deepfake_prob, real_prob),"model":"deepfake_vs_real_image_detection"}
|
| 243 |
except Exception as e:
|
| 244 |
print(f"Image detection error: {type(e).__name__}: {e}")
|
| 245 |
-
|
| 246 |
|
| 247 |
|
| 248 |
def detect_voice_deepfake(audio_data, content_type):
|
|
@@ -490,7 +507,10 @@ def detect_image():
|
|
| 490 |
return jsonify({"error": result.get("error", "Detection failed")}), 500
|
| 491 |
return jsonify({
|
| 492 |
"label": result["verdict"],
|
| 493 |
-
"confidence": result["confidence"] / 100
|
|
|
|
|
|
|
|
|
|
| 494 |
})
|
| 495 |
except Exception as e:
|
| 496 |
print(f"Image route error: {e}")
|
|
@@ -773,13 +793,15 @@ def network_test():
|
|
| 773 |
return jsonify(results)
|
| 774 |
|
| 775 |
|
| 776 |
-
# ββ MODEL STATUS (quick check that the
|
| 777 |
|
| 778 |
@app.route('/model-status', methods=['GET'])
|
| 779 |
def model_status():
|
| 780 |
return jsonify({
|
| 781 |
"text_model": TEXT_MODEL_NAME,
|
| 782 |
-
"
|
|
|
|
|
|
|
| 783 |
})
|
| 784 |
|
| 785 |
|
|
|
|
| 3 |
import requests
|
| 4 |
import os
|
| 5 |
import re
|
| 6 |
+
import io
|
| 7 |
import hashlib
|
| 8 |
import datetime
|
| 9 |
import base64
|
| 10 |
import time
|
| 11 |
import torch
|
| 12 |
import torch.nn as nn
|
| 13 |
+
from PIL import Image
|
| 14 |
+
from transformers import AutoTokenizer, AutoConfig, AutoModel, PreTrainedModel, pipeline
|
| 15 |
|
| 16 |
app = Flask(__name__)
|
| 17 |
CORS(app)
|
|
|
|
| 73 |
print(f"β Text model failed to load: {type(e).__name__}: {e}")
|
| 74 |
|
| 75 |
|
| 76 |
+
# ββ DEEPFAKE IMAGE MODEL (loaded locally inside the Space) ββ
|
| 77 |
+
# dima806/deepfake_vs_real_image_detection β a Vision Transformer for Real-vs-Fake
|
| 78 |
+
# classification. Loaded locally (standard image-classification pipeline) instead
|
| 79 |
+
# of the HF Inference API, which is what caused the old 500 errors.
|
| 80 |
+
# NOTE: this model is trained on an older dataset and works best on human FACE
|
| 81 |
+
# photos; it is less reliable on brand-new AI-generated images.
|
| 82 |
+
IMAGE_MODEL_NAME = "dima806/deepfake_vs_real_image_detection"
|
| 83 |
+
try:
|
| 84 |
+
image_classifier = pipeline("image-classification", model=IMAGE_MODEL_NAME)
|
| 85 |
+
print(f"β
Image model loaded: {IMAGE_MODEL_NAME}")
|
| 86 |
+
except Exception as e:
|
| 87 |
+
image_classifier = None
|
| 88 |
+
print(f"β Image model failed to load: {type(e).__name__}: {e}")
|
| 89 |
+
|
| 90 |
+
|
| 91 |
def _ai_prob_for_chunk(chunk):
|
| 92 |
enc = _tokenizer(chunk, truncation=True, max_length=512, return_tensors="pt")
|
| 93 |
with torch.no_grad():
|
|
|
|
| 235 |
|
| 236 |
|
| 237 |
def detect_image_deepfake(image_data):
|
| 238 |
+
"""Runs the locally-loaded ViT deepfake detector. No more HF Inference API,
|
| 239 |
+
so no more 500s from a dead endpoint."""
|
| 240 |
+
if image_classifier is None:
|
| 241 |
+
return {"success":False,"error":"Image model not loaded on server. Try again shortly.","deepfake_probability":0,"real_probability":0,"verdict":"UNKNOWN","confidence":0,"model":"error"}
|
| 242 |
try:
|
| 243 |
+
img = Image.open(io.BytesIO(image_data)).convert("RGB")
|
| 244 |
+
results = image_classifier(img) # list of {label, score}
|
| 245 |
+
fake_score = 0.0
|
| 246 |
+
real_score = 0.0
|
| 247 |
+
for item in results:
|
| 248 |
+
label = str(item.get('label', '')).lower()
|
| 249 |
+
score = item.get('score', 0)
|
| 250 |
+
if label in ['fake', 'deepfake', 'label_1', 'artificial']:
|
| 251 |
+
fake_score = score
|
| 252 |
+
elif label in ['real', 'genuine', 'label_0', 'authentic']:
|
| 253 |
+
real_score = score
|
| 254 |
+
if fake_score == 0 and real_score == 0 and len(results) >= 2:
|
| 255 |
+
real_score = results[0]['score']
|
| 256 |
+
fake_score = results[1]['score']
|
| 257 |
+
deepfake_prob = round(fake_score * 100)
|
| 258 |
+
real_prob = round(real_score * 100)
|
| 259 |
+
return {"success":True,"deepfake_probability":deepfake_prob,"real_probability":real_prob,"verdict":"DEEPFAKE" if deepfake_prob > 50 else "AUTHENTIC","confidence":max(deepfake_prob, real_prob),"model":IMAGE_MODEL_NAME}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 260 |
except Exception as e:
|
| 261 |
print(f"Image detection error: {type(e).__name__}: {e}")
|
| 262 |
+
return {"success":False,"error":"Could not analyze this image. Try a clear JPG/PNG.","deepfake_probability":0,"real_probability":0,"verdict":"UNKNOWN","confidence":0,"model":"error"}
|
| 263 |
|
| 264 |
|
| 265 |
def detect_voice_deepfake(audio_data, content_type):
|
|
|
|
| 507 |
return jsonify({"error": result.get("error", "Detection failed")}), 500
|
| 508 |
return jsonify({
|
| 509 |
"label": result["verdict"],
|
| 510 |
+
"confidence": result["confidence"] / 100,
|
| 511 |
+
"deepfake_probability": result["deepfake_probability"],
|
| 512 |
+
"real_probability": result["real_probability"],
|
| 513 |
+
"model": result["model"]
|
| 514 |
})
|
| 515 |
except Exception as e:
|
| 516 |
print(f"Image route error: {e}")
|
|
|
|
| 793 |
return jsonify(results)
|
| 794 |
|
| 795 |
|
| 796 |
+
# ββ MODEL STATUS (quick check that the models loaded) ββ
|
| 797 |
|
| 798 |
@app.route('/model-status', methods=['GET'])
|
| 799 |
def model_status():
|
| 800 |
return jsonify({
|
| 801 |
"text_model": TEXT_MODEL_NAME,
|
| 802 |
+
"text_loaded": _text_model is not None,
|
| 803 |
+
"image_model": IMAGE_MODEL_NAME,
|
| 804 |
+
"image_loaded": image_classifier is not None
|
| 805 |
})
|
| 806 |
|
| 807 |
|