Spaces:
Running
Running
| import gradio as gr | |
| from transformers import pipeline | |
| from PIL import Image, ExifTags | |
| import numpy as np | |
| import cv2 | |
| # ---------------------------- | |
| # Model Hugging Face AI detector (public) | |
| # ---------------------------- | |
| try: | |
| hf_detector = pipeline("image-classification", model="umm-maybe/AI-image-detector") | |
| except Exception as e: | |
| hf_detector = None | |
| print("Hugging Face model gagal dimuat, hanya analisis lokal yang dipakai:", e) | |
| # ---------------------------- | |
| # Analisis gambar lokal | |
| # ---------------------------- | |
| def calculate_blur(image): | |
| gray = np.array(image.convert("L")) | |
| return cv2.Laplacian(gray, cv2.CV_64F).var() | |
| def calculate_noise(image): | |
| img_gray = np.array(image.convert("L"), dtype=np.float32) | |
| h, w = img_gray.shape | |
| mean = np.mean(img_gray) | |
| noise_std = np.std(img_gray - mean) | |
| return noise_std | |
| def has_camera_exif(image): | |
| try: | |
| exif = image._getexif() | |
| if exif: | |
| for tag, value in exif.items(): | |
| decoded = ExifTags.TAGS.get(tag, tag) | |
| if decoded in ["Make", "Model"]: | |
| return True | |
| except: | |
| return False | |
| return False | |
| # ---------------------------- | |
| # Deteksi hybrid AI vs Foto Asli | |
| # ---------------------------- | |
| def detect_image(image): | |
| scores = [] | |
| # ---- HUGGING FACE ---- | |
| if hf_detector: | |
| try: | |
| result = hf_detector(image) | |
| label = result[0]['label'].lower() | |
| conf = result[0]['score'] * 100 | |
| if "fake" in label or "ai" in label or "artificial" in label: | |
| scores.append(conf) # AI score | |
| else: | |
| scores.append(0) # Foto asli = 0 AI score | |
| except: | |
| scores.append(0) | |
| else: | |
| scores.append(0) | |
| # ---- ANALISIS LOKAL ---- | |
| blur_score = calculate_blur(image) | |
| noise_score = calculate_noise(image) | |
| exif_present = has_camera_exif(image) | |
| # Blur & noise heuristics | |
| # Foto asli: blur tinggi (>100) atau noise > threshold | |
| # AI: blur rendah atau noise sangat rendah | |
| local_ai_score = 0 | |
| if blur_score < 100 or noise_score < 10: | |
| local_ai_score += 50 # menambah skor AI | |
| if not exif_present: | |
| local_ai_score += 10 # sedikit penalti jika metadata hilang | |
| scores.append(local_ai_score) | |
| # ---- Gabungkan skor ---- | |
| avg_score = sum(scores) / len(scores) | |
| # ---- Tentukan hasil final ---- | |
| if avg_score > 50: | |
| final_result = "π€ AI Detected" | |
| else: | |
| final_result = "β Foto Asli" | |
| output = f""" | |
| ### Hasil Deteksi: | |
| {final_result} | |
| **Skor rata-rata AI:** {avg_score:.2f} | |
| **Blur Score:** {blur_score:.2f} | |
| **Noise Score:** {noise_score:.2f} | |
| **Metadata Kamera:** {'Ada' if exif_present else 'Tidak Ada'} | |
| """ | |
| return output | |
| # ---------------------------- | |
| # Gradio Interface | |
| # ---------------------------- | |
| iface = gr.Interface( | |
| fn=detect_image, | |
| inputs=gr.Image(type="pil"), | |
| outputs="markdown", | |
| title="AI vs Foto Asli Detector (Hybrid, Gratis)", | |
| description="Unggah gambar, sistem hybrid akan mendeteksi apakah gambar kemungkinan besar asli atau dihasilkan AI." | |
| ) | |
| if __name__ == "__main__": | |
| iface.launch() | |