Spaces:
No application file
No application file
from fastapi import FastAPI | |
from pydantic import BaseModel | |
import cv2 | |
from deepface import DeepFace | |
import tempfile | |
import requests | |
import shutil | |
import logging | |
from typing import Optional | |
# Configure logging | |
logging.basicConfig(level=logging.INFO) | |
logger = logging.getLogger(__name__) | |
app = FastAPI() | |
# Define the request model | |
class FaceVerificationRequest(BaseModel): | |
id_url: str | |
ref_url: str | |
def download_image(url: str) -> Optional[str]: | |
"""Downloads an image from a URL and saves it to a temporary file.""" | |
try: | |
response = requests.get(url, stream=True) | |
response.raise_for_status() | |
temp_path = tempfile.NamedTemporaryFile(delete=False, suffix=".jpg").name | |
with open(temp_path, "wb") as f: | |
shutil.copyfileobj(response.raw, f) | |
logger.info(f"Image downloaded successfully: {url}") | |
return temp_path | |
except requests.exceptions.RequestException as e: | |
logger.error(f"Failed to download image from {url}: {e}") | |
return None | |
def detect_and_crop_face(image_path, detector_backend="mtcnn") -> Optional[str]: | |
"""Detects and crops the face from an image.""" | |
try: | |
faces = DeepFace.extract_faces(img_path=image_path, detector_backend=detector_backend, enforce_detection=False) | |
if not faces: | |
logger.warning("No faces detected.") | |
return None | |
face_info = faces[0] | |
facial_area = face_info.get("facial_area", {}) | |
if not facial_area: | |
logger.warning("No valid facial area found.") | |
return None | |
x, y, w, h = facial_area["x"], facial_area["y"], facial_area["w"], facial_area["h"] | |
image = cv2.imread(image_path) | |
if image is None or w <= 0 or h <= 0: | |
logger.error("Invalid face cropping dimensions.") | |
return None | |
cropped_face = image[y:y+h, x:x+w] | |
temp_path = tempfile.NamedTemporaryFile(delete=False, suffix=".jpg").name | |
cv2.imwrite(temp_path, cropped_face) | |
logger.info(f"Face successfully cropped and saved at {temp_path}") | |
return temp_path | |
except Exception as e: | |
logger.error(f"Error during face detection: {e}") | |
return None | |
async def verify_face(request: FaceVerificationRequest): | |
"""Verifies whether two faces belong to the same person.""" | |
try: | |
id_path = download_image(request.id_url) | |
ref_path = download_image(request.ref_url) | |
if not id_path or not ref_path: | |
return {"error": "Failed to download images."} | |
cropped_face_path = detect_and_crop_face(id_path) | |
if cropped_face_path: | |
result = DeepFace.verify( | |
img1_path=cropped_face_path, | |
img2_path=ref_path, | |
model_name="Facenet", | |
detector_backend="mtcnn" | |
) | |
threshold = 0.6 | |
distance = result.get("distance", 1.0) | |
is_match = distance < threshold | |
logger.info(f"Face verification result: {result}") | |
return {"match": is_match} | |
else: | |
return {"error": "Face detection failed for ID card image."} | |
except Exception as e: | |
logger.error(f"Verification failed: {e}") | |
return {"error": str(e)} | |