Spaces:
Sleeping
Sleeping
| import torch | |
| from torchvision import transforms | |
| from PIL import Image, ImageOps | |
| import tempfile | |
| import os | |
| from detector_config import ( | |
| ALLOW_LOCAL_MODEL_FALLBACK, | |
| IMAGE_DETECTOR_BACKEND, | |
| IMAGE_FAKE_THRESHOLD, | |
| IMAGE_UNCERTAIN_MARGIN, | |
| ) | |
| from model_loader import get_image_model | |
| def build_image_insight(result, confidence, fake_score, real_score): | |
| margin = abs(fake_score - real_score) * 100 | |
| if confidence >= 90: | |
| certainty = "High" | |
| elif confidence >= 70: | |
| certainty = "Moderate" | |
| else: | |
| certainty = "Low" | |
| if result == "Uncertain": | |
| summary = "The detector did not find a large enough gap between fake and real evidence." | |
| elif certainty == "Low": | |
| summary = "The model is not strongly confident. Treat this as a signal, not a final judgement." | |
| elif result == "Fake": | |
| summary = "The image contains patterns the model associates with manipulated or synthetic content." | |
| else: | |
| summary = "The image looks closer to authentic content based on the model's learned patterns." | |
| return { | |
| "certainty": certainty, | |
| "summary": summary, | |
| "scores": { | |
| "fake": round(fake_score * 100, 2), | |
| "real": round(real_score * 100, 2), | |
| }, | |
| "metrics": { | |
| "confidence": round(confidence, 2), | |
| "score_gap": round(margin, 2), | |
| "uncertainty": round(100 - confidence, 2), | |
| "consistency": 100, | |
| }, | |
| "risk_level": "High" if result == "Fake" and confidence >= 80 else "Medium" if result == "Fake" else "Low", | |
| } | |
| transform = transforms.Compose([ | |
| transforms.ToTensor(), | |
| transforms.Normalize( | |
| [0.485, 0.456, 0.406], | |
| [0.229, 0.224, 0.225] | |
| ) | |
| ]) | |
| def detect_deepfake(file): | |
| with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as temp: | |
| file.save(temp.name) | |
| path = temp.name | |
| try: | |
| image = ImageOps.exif_transpose(Image.open(path)).convert("RGB") | |
| if IMAGE_DETECTOR_BACKEND == "huggingface": | |
| try: | |
| from hf_detectors import get_hf_image_detector | |
| result = get_hf_image_detector().predict( | |
| image, | |
| threshold=IMAGE_FAKE_THRESHOLD, | |
| uncertain_margin=IMAGE_UNCERTAIN_MARGIN, | |
| ) | |
| result["insight"] = build_image_insight( | |
| result["result"], | |
| result["confidence"], | |
| result["fake_score"] / 100, | |
| result["real_score"] / 100, | |
| ) | |
| return result | |
| except Exception as error: | |
| if not ALLOW_LOCAL_MODEL_FALLBACK: | |
| return {"error": f"Hugging Face image detector failed: {error}"} | |
| img = transform(image).unsqueeze(0) | |
| with torch.no_grad(): | |
| output = get_image_model()(img) | |
| fake_score = torch.sigmoid(output).item() | |
| real_score = 1 - fake_score | |
| THRESHOLD = IMAGE_FAKE_THRESHOLD | |
| if fake_score > THRESHOLD: | |
| result = "Fake" | |
| confidence = fake_score | |
| else: | |
| result = "Real" | |
| confidence = real_score | |
| return { | |
| "result": result, | |
| "confidence": round(confidence * 100, 2), | |
| "fake_score": round(fake_score * 100, 2), | |
| "real_score": round(real_score * 100, 2), | |
| "raw_probability": round(fake_score, 6), | |
| "insight": build_image_insight(result, confidence * 100, fake_score, real_score), | |
| } | |
| except Exception as e: | |
| return {"error": str(e)} | |
| finally: | |
| if os.path.exists(path): | |
| os.remove(path) | |