import gradio as gr import torch from PIL import Image from typing import Dict, Optional, Tuple from transformers import AutoImageProcessor, SiglipForImageClassification from trufor_runner import TruForEngine, TruForResult, TruForUnavailableError MODEL_ID = "Ateeqq/ai-vs-human-image-detector" # Use GPU when available so large batches stay responsive. device = torch.device("cuda" if torch.cuda.is_available() else "cpu") try: processor = AutoImageProcessor.from_pretrained(MODEL_ID) model = SiglipForImageClassification.from_pretrained(MODEL_ID) model.to(device) model.eval() except Exception as exc: # pragma: no cover - surface loading issues early. raise RuntimeError(f"Failed to load model from {MODEL_ID}") from exc try: TRUFOR_ENGINE: Optional[TruForEngine] = TruForEngine(device="cpu") TRUFOR_STATUS = TRUFOR_ENGINE.status_message except TruForUnavailableError as exc: TRUFOR_ENGINE = None TRUFOR_STATUS = str(exc) def analyze_ai_vs_human(image: Image.Image) -> Tuple[Dict[str, float], str]: """Run the Hugging Face detector and return confidences with a readable summary.""" if image is None: empty_scores = {label: 0.0 for label in model.config.id2label.values()} return empty_scores, "No image provided." image = image.convert("RGB") inputs = processor(images=image, return_tensors="pt").to(device) with torch.no_grad(): logits = model(**inputs).logits probabilities = torch.softmax(logits, dim=-1)[0] scores = { model.config.id2label[idx]: float(probabilities[idx]) for idx in range(probabilities.size(0)) } top_idx = int(probabilities.argmax().item()) top_label = model.config.id2label[top_idx] top_score = scores[top_label] summary = f"**Predicted Label:** {top_label} \ **Confidence:** {top_score:.4f}" return scores, summary def analyze_trufor(image: Image.Image) -> Tuple[str, Optional[Image.Image], Optional[Image.Image]]: """Run TruFor inference when available, otherwise return diagnostics.""" if TRUFOR_ENGINE is None: return TRUFOR_STATUS, None, None if image is None: return "Upload an image to run TruFor.", None, None try: result: TruForResult = TRUFOR_ENGINE.infer(image) except TruForUnavailableError as exc: return str(exc), None, None summary_lines = [] if result.score is not None: summary_lines.append(f"**Tamper Score:** {result.score:.4f}") extras_dict = result.raw_scores.copy() if result.score is not None: extras_dict.pop("tamper_score", None) if extras_dict: extras = " ".join(f"{key}: {value:.4f}" for key, value in extras_dict.items()) summary_lines.append(f"`{extras}`") if not summary_lines: summary_lines.append("TruFor returned no scores for this image.") return "\n".join(summary_lines), result.map_overlay, result.confidence_overlay def analyze_image(image: Image.Image) -> Tuple[Dict[str, float], str, str, Optional[Image.Image], Optional[Image.Image]]: ai_scores, ai_summary = analyze_ai_vs_human(image) trufor_summary, tamper_overlay, conf_overlay = analyze_trufor(image) return ai_scores, ai_summary, trufor_summary, tamper_overlay, conf_overlay with gr.Blocks() as demo: gr.Markdown( """# Image Authenticity Workbench\nUpload an image to compare the AI-vs-human classifier with the TruFor forgery detector.""" ) status_box = gr.Markdown(f"`{TRUFOR_STATUS}`") image_input = gr.Image(label="Input Image", type="pil") analyze_button = gr.Button("Analyze", variant="primary", size="sm") with gr.Tabs(): with gr.TabItem("AI vs Human"): ai_label_output = gr.Label(label="Prediction", num_top_classes=2) ai_summary_output = gr.Markdown("Upload an image to view the prediction.") with gr.TabItem("TruFor Forgery Detection"): trufor_summary_output = gr.Markdown("Configure TruFor assets to enable tamper analysis.") tamper_overlay_output = gr.Image(label="Tamper Heatmap", type="pil", interactive=False) conf_overlay_output = gr.Image(label="Confidence Heatmap", type="pil", interactive=False) output_components = [ ai_label_output, ai_summary_output, trufor_summary_output, tamper_overlay_output, conf_overlay_output, ] analyze_button.click( fn=analyze_image, inputs=image_input, outputs=output_components, ) image_input.change( fn=analyze_image, inputs=image_input, outputs=output_components, ) if __name__ == "__main__": demo.launch()