import os import io import json import requests from flask import Flask, request, jsonify from flask_cors import CORS # Optional: but good for local debugging if you run this file directly try: from dotenv import load_dotenv load_dotenv() except ImportError: pass app = Flask(__name__) CORS(app) # ── Configuration (with Defaults to prevent crashes) ──────────────── TWILIO_ACCOUNT_SID = os.getenv("TWILIO_ACCOUNT_SID", "") TWILIO_AUTH_TOKEN = os.getenv("TWILIO_AUTH_TOKEN", "") TWILIO_FROM_NUMBER = os.getenv("TWILIO_FROM_NUMBER", "+17125825991") YOUR_PHONE_NUMBER = os.getenv("YOUR_PHONE_NUMBER", "+919047432845") AI_CONFIDENCE_THRESHOLD = float(os.getenv("AI_CONFIDENCE_THRESHOLD", 0.5)) # HuggingFace Inference API Config HF_API_URL = "https://api-inference.huggingface.co/models/umm-maybe/AI-image-detector" HF_API_TOKEN = os.getenv("HF_API_TOKEN", "") # ── Routes ────────────────────────────────────────────────── @app.route("/") def home(): return "VisionAI Backend is Live. Use /status or /analyze." @app.route("/status") def status(): return jsonify({ "status": "online", "deployment": "vercel", "alerts_configured": bool(TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN), "target_phone": YOUR_PHONE_NUMBER, "threshold": AI_CONFIDENCE_THRESHOLD * 100 }) @app.route("/analyze", methods=["POST"]) def analyze(): if "image" not in request.files: return jsonify({"error": "No image provided"}), 400 file = request.files["image"] img_data = file.read() # Call HuggingFace Inference API headers = {} if HF_API_TOKEN: headers["Authorization"] = f"Bearer {HF_API_TOKEN}" try: response = requests.post(HF_API_URL, headers=headers, data=img_data) results = response.json() # Handle API loading state (model taking time to boot) if isinstance(results, dict) and "estimated_time" in results: return jsonify({ "error": "Model is warming up on HuggingFace. Please try again in 20 seconds.", "wait_time": results["estimated_time"] }), 503 if isinstance(results, dict) and "error" in results: return jsonify({"error": results["error"]}), 502 # Parse results scores = {r["label"].lower(): r["score"] for r in results} art_score = scores.get("artificial", 0.0) real_score = scores.get("real", 1.0 - art_score) is_ai = art_score > AI_CONFIDENCE_THRESHOLD except Exception as e: return jsonify({"error": f"Analysis failed: {str(e)}"}), 502 # ── Twilio Alert ──────────────────────────────────────── call_placed = False call_sid = None call_error = None if is_ai and TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN: try: from twilio.rest import Client client = Client(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN) call = client.calls.create( twiml=f""" Alert! An AI generated image has been detected. Confidence is {round(art_score * 100)} percent. """, to=YOUR_PHONE_NUMBER, from_=TWILIO_FROM_NUMBER, ) call_placed = True call_sid = call.sid except Exception as e: call_error = str(e) return jsonify({ "filename": file.filename, "is_ai": is_ai, "artificial_score": round(art_score * 100, 1), "real_score": round(real_score * 100, 1), "all_scores": [{"label": r["label"], "score": round(r["score"] * 100, 1)} for r in results], "threshold": AI_CONFIDENCE_THRESHOLD * 100, "call_placed": call_placed, "call_sid": call_sid, "call_error": call_error }) # The 'app' object is automatically used by Vercel