from fastapi import FastAPI, File, UploadFile, Body from fastapi.responses import RedirectResponse from fastapi.middleware.cors import CORSMiddleware from PIL import Image import io import numpy as np from structure import ImagePredictionResponse, TextPredictionRequest, TextPredictionResponse, PredictionEntry from textPreprocess import predict_text from imagePreprocess import CNNPredict, CLIPPredict import tensorflow as tf origins=[ "http://localhost:5173", "http://localhost", "https://authentica-ai.vercel.app", ] app = FastAPI( title="Authentica API", description=( "Simple demo API for image and text prediction. " "Upload an image to `/predict/image` or POST text to `/predict/text`." ), version="0.1.0", ) app.add_middleware( CORSMiddleware, allow_origins=origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) @app.get("/", include_in_schema=False) async def root(): # Redirect to the automatic Swagger UI provided by FastAPI return RedirectResponse(url="/docs") @app.post( "/predict/image", response_model=ImagePredictionResponse, summary="Predict image using all available models", description="Upload an image file (jpg/png). It is evaluated on all 3 models and class index/confidence is returned.", ) async def predict(image: UploadFile = File(...)): """Accept an image upload and return a prediction using loaded model.""" image_data = await image.read() pil_img = Image.open(io.BytesIO(image_data)).convert("RGB") predictions=[] cnnPred = CNNPredict(pil_img) if isinstance(cnnPred, str): # An error occurred during CNN prediction print("CNN preprocessing error:", cnnPred) predictions.append(PredictionEntry(model="CNN", error=cnnPred, predicted_class=-1, confidence=0.0)) else: cnn_class = 1 if cnnPred >= 0.5 else 0 cnn_conf = cnnPred if cnnPred >= 0.5 else 1 - cnnPred predictions.append( PredictionEntry(model="CNN", predicted_class=cnn_class, confidence=round(float(cnn_conf), 4))) clipPred = CLIPPredict(pil_img) if isinstance(clipPred, str): # An error occurred during CLIP prediction print("CLIP error:", clipPred) predictions.append(PredictionEntry(model="CLIP", error=clipPred, predicted_class=-1, confidence=0.0)) else: clip_class = 1 if clipPred > 0.5 else 0 clip_conf = clipPred if clipPred >= 0.5 else 1 - clipPred predictions.append( PredictionEntry(model="CLIP", predicted_class=clip_class, confidence=round(float(clip_conf), 4))) #print(f"CNN Prediction (AI prob): {cnnPred:.4f}") #print(f"ResNet Prediction (AI prob): {resnetPred:.4f}") #print(f"CLIP Prediction (AI prob): {clipPred:.4f}") #Predicted classes 1 is Real, 0 is AI return ImagePredictionResponse(predictions=predictions) @app.post( "/predict/text", response_model=TextPredictionResponse, summary="Predict text", description="POST a JSON body with `text` to get a predicted label and confidence.", ) async def predict_text_endpoint(payload: TextPredictionRequest = Body(...)): """Accept a text string and return a prediction of whether it's human or AI-generated.""" try: # Use the text prediction function from textPreprocess.py result = predict_text(payload.text) return TextPredictionResponse( predicted_class=result["predicted_class"], confidence=result["confidence"] ) except Exception as e: # Return a fallback response in case of error print(f"Error in text prediction: {e}") return TextPredictionResponse(predicted_class="Human", confidence=0.5)