Spaces:
Running on Zero
Running on Zero
Download deepverify/api.py from francisojeah/deep-verify: direct link, hf CLI and curl.
- Browser
- Download file 3.14 kB
-
https://huggingface.co/spaces/francisojeah/deep-verify/resolve/main/deepverify/api.py
- Command line
-
hf download hf://spaces/francisojeah/deep-verify/deepverify/api.py
-
curl -L -o api.py https://huggingface.co/spaces/francisojeah/deep-verify/resolve/main/deepverify/api.py
3.14 kB
| import io | |
| from fastapi import FastAPI, File, HTTPException, UploadFile | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from PIL import Image, UnidentifiedImageError | |
| from pydantic import BaseModel | |
| from .config import get_settings | |
| from .detector import NoFaceDetectedError, Prediction, get_detector | |
| settings = get_settings() | |
| app = FastAPI( | |
| title="DeepVerify detection service", | |
| description=( | |
| "Image deepfake detection using the pre-trained yermandy/deepfake-detection " | |
| "checkpoint (CLIP ViT-L/14 + LN-tuning, MIT). No model is trained here." | |
| ), | |
| version="1.0.0", | |
| ) | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=[o.strip() for o in settings.allowed_origins.split(",")], | |
| allow_methods=["GET", "POST"], | |
| allow_headers=["*"], | |
| ) | |
| def run_prediction(image: Image.Image) -> Prediction: | |
| """Detect and score, in-process. | |
| A seam, not indirection: on ZeroGPU the forward pass has to happen inside a | |
| GPU-scoped function, so the Space replaces this with its own implementation | |
| and the route below stays identical in both deployments. | |
| """ | |
| return get_detector().predict(image) | |
| class Health(BaseModel): | |
| status: str | |
| model_id: str | |
| weights_sha256: str | |
| device: str | |
| threshold: float | |
| class DetectionResponse(BaseModel): | |
| is_deepfake: bool | |
| label: str | |
| fake_probability: float | |
| real_probability: float | |
| threshold: float | |
| face_box: tuple[int, int, int, int] | |
| face_confidence: float | |
| model_id: str | |
| def health() -> Health: | |
| detector = get_detector() | |
| return Health( | |
| status="ok", | |
| model_id=detector.model_id, | |
| weights_sha256=detector.weights_sha256, | |
| device=str(detector.device), | |
| threshold=detector.threshold, | |
| ) | |
| async def detect(file: UploadFile = File(...)) -> DetectionResponse: | |
| contents = await file.read() | |
| if len(contents) > settings.max_upload_bytes: | |
| raise HTTPException( | |
| status_code=413, | |
| detail=f"file exceeds {settings.max_upload_bytes // (1024 * 1024)}MB limit", | |
| ) | |
| try: | |
| image = Image.open(io.BytesIO(contents)) | |
| image.load() | |
| except (UnidentifiedImageError, OSError): | |
| raise HTTPException(status_code=400, detail="file is not a readable image") | |
| detector = get_detector() | |
| try: | |
| prediction = run_prediction(image) | |
| except NoFaceDetectedError: | |
| raise HTTPException( | |
| status_code=422, | |
| detail=( | |
| "no face detected. This detector is trained on face crops, so a score " | |
| "on a face-free image would be meaningless." | |
| ), | |
| ) | |
| return DetectionResponse( | |
| is_deepfake=prediction.is_deepfake, | |
| label=prediction.label, | |
| fake_probability=prediction.fake_probability, | |
| real_probability=prediction.real_probability, | |
| threshold=prediction.threshold, | |
| face_box=prediction.face_box, | |
| face_confidence=prediction.face_confidence, | |
| model_id=detector.model_id, | |
| ) | |