Merge pull request #1004 from serengil/feat-task-0402-api-bug-and-api-tests

Feat task 0402 api bug and api tests
This commit is contained in:
Sefik Ilkin Serengil 2024-02-04 13:08:43 +00:00 committed by GitHub
commit 889d033d12
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 199 additions and 60 deletions

View File

@ -19,11 +19,8 @@ RUN apt-get install ffmpeg libsm6 libxext6 -y
# -----------------------------------
# Copy required files from repo into image
COPY ./deepface /app/deepface
COPY ./api/src/app.py /app/
COPY ./api/src/api.py /app/
COPY ./api/src/routes.py /app/
COPY ./api/src/service.py /app/
COPY ./requirements.txt /app/
COPY ./package_info.json /app/package_info.json
COPY ./setup.py /app/
COPY ./README.md /app/
@ -50,5 +47,6 @@ ENV PYTHONUNBUFFERED=1
# -----------------------------------
# run the app (re-configure port if necessary)
WORKDIR /app/deepface/api/src
EXPOSE 5000
CMD ["gunicorn", "--workers=1", "--timeout=3600", "--bind=0.0.0.0:5000", "app:create_app()"]

View File

@ -280,7 +280,7 @@ user
**API** - [`Demo`](https://youtu.be/HeKCQ6U9XmI)
DeepFace serves an API as well. You can clone [`/api`](https://github.com/serengil/deepface/tree/master/api) folder and run the api via gunicorn server. This will get a rest service up. In this way, you can call deepface from an external system such as mobile app or web.
DeepFace serves an API as well. You can clone deepface source code and run the api via gunicorn server with the following command. This will get a rest service up. In this way, you can call deepface from an external system such as mobile app or web.
```shell
cd scripts

View File

@ -1,42 +0,0 @@
from deepface import DeepFace
def represent(img_path, model_name, detector_backend, enforce_detection, align):
result = {}
embedding_objs = DeepFace.represent(
img_path=img_path,
model_name=model_name,
detector_backend=detector_backend,
enforce_detection=enforce_detection,
align=align,
)
result["results"] = embedding_objs
return result
def verify(
img1_path, img2_path, model_name, detector_backend, distance_metric, enforce_detection, align
):
obj = DeepFace.verify(
img1_path=img1_path,
img2_path=img2_path,
model_name=model_name,
detector_backend=detector_backend,
distance_metric=distance_metric,
align=align,
enforce_detection=enforce_detection,
)
return obj
def analyze(img_path, actions, detector_backend, enforce_detection, align):
result = {}
demographies = DeepFace.analyze(
img_path=img_path,
actions=actions,
detector_backend=detector_backend,
enforce_detection=enforce_detection,
align=align,
)
result["results"] = demographies
return result

0
deepface/api/__init__.py Normal file
View File

View File

View File

@ -1,7 +1,6 @@
# 3rd parth dependencies
from flask import Flask
from routes import blueprint
from deepface.api.src.modules.core.routes import blueprint
def create_app():
app = Flask(__name__)

View File

View File

@ -1,5 +1,8 @@
from flask import Blueprint, request
import service
from deepface.api.src.modules.core import service
from deepface.commons.logger import Logger
logger = Logger(module="api/src/routes.py")
blueprint = Blueprint("routes", __name__)
@ -16,7 +19,7 @@ def represent():
if input_args is None:
return {"message": "empty input set passed"}
img_path = input_args.get("img")
img_path = input_args.get("img") or input_args.get("img_path")
if img_path is None:
return {"message": "you must pass img_path input"}
@ -33,6 +36,8 @@ def represent():
align=align,
)
logger.debug(obj)
return obj
@ -43,8 +48,8 @@ def verify():
if input_args is None:
return {"message": "empty input set passed"}
img1_path = input_args.get("img1_path")
img2_path = input_args.get("img2_path")
img1_path = input_args.get("img1") or input_args.get("img1_path")
img2_path = input_args.get("img2") or input_args.get("img2_path")
if img1_path is None:
return {"message": "you must pass img1_path input"}
@ -68,7 +73,7 @@ def verify():
enforce_detection=enforce_detection,
)
verification["verified"] = str(verification["verified"])
logger.debug(verification)
return verification
@ -80,7 +85,7 @@ def analyze():
if input_args is None:
return {"message": "empty input set passed"}
img_path = input_args.get("img_path")
img_path = input_args.get("img") or input_args.get("img_path")
if img_path is None:
return {"message": "you must pass img_path input"}
@ -97,4 +102,6 @@ def analyze():
align=align,
)
logger.debug(demographies)
return demographies

View File

@ -0,0 +1,54 @@
from deepface import DeepFace
# pylint: disable=broad-except
def represent(img_path, model_name, detector_backend, enforce_detection, align):
try:
result = {}
embedding_objs = DeepFace.represent(
img_path=img_path,
model_name=model_name,
detector_backend=detector_backend,
enforce_detection=enforce_detection,
align=align,
)
result["results"] = embedding_objs
return result
except Exception as err:
return {"error": f"Exception while representing: {str(err)}"}, 400
def verify(
img1_path, img2_path, model_name, detector_backend, distance_metric, enforce_detection, align
):
try:
obj = DeepFace.verify(
img1_path=img1_path,
img2_path=img2_path,
model_name=model_name,
detector_backend=detector_backend,
distance_metric=distance_metric,
align=align,
enforce_detection=enforce_detection,
)
return obj
except Exception as err:
return {"error": f"Exception while verifying: {str(err)}"}, 400
def analyze(img_path, actions, detector_backend, enforce_detection, align):
try:
result = {}
demographies = DeepFace.analyze(
img_path=img_path,
actions=actions,
detector_backend=detector_backend,
enforce_detection=enforce_detection,
align=align,
silent=True,
)
result["results"] = demographies
return result
except Exception as err:
return {"error": f"Exception while analyzing: {str(err)}"}, 400

View File

@ -167,10 +167,10 @@ def extract_faces(
{
"face": img_pixels[:, :, ::-1] if human_readable is True else img_pixels,
"facial_area": {
"x": current_region.x,
"y": current_region.y,
"w": current_region.w,
"h": current_region.h,
"x": int(current_region.x),
"y": int(current_region.y),
"w": int(current_region.w),
"h": int(current_region.h),
},
"confidence": confidence,
}

View File

@ -1,3 +1,3 @@
#!/usr/bin/env bash
cd ../api/src
cd ../deepface/api/src
gunicorn --workers=1 --timeout=3600 --bind=0.0.0.0:5000 "app:create_app()"

123
tests/test_api.py Normal file
View File

@ -0,0 +1,123 @@
import unittest
from deepface.commons.logger import Logger
from deepface.api.src.app import create_app
logger = Logger("tests/test_api.py")
class TestVerifyEndpoint(unittest.TestCase):
def setUp(self):
app = create_app()
app.config["DEBUG"] = True
app.config["TESTING"] = True
self.app = app.test_client()
def test_tp_verify(self):
data = {
"img1_path": "dataset/img1.jpg",
"img2_path": "dataset/img2.jpg",
}
response = self.app.post("/verify", json=data)
assert response.status_code == 200
result = response.json
logger.debug(result)
assert result.get("verified") is not None
assert result.get("model") is not None
assert result.get("similarity_metric") is not None
assert result.get("detector_backend") is not None
assert result.get("distance") is not None
assert result.get("threshold") is not None
assert result.get("facial_areas") is not None
assert result.get("verified") is True
logger.info("✅ true-positive verification api test is done")
def test_tn_verify(self):
data = {
"img1_path": "dataset/img1.jpg",
"img2_path": "dataset/img2.jpg",
}
response = self.app.post("/verify", json=data)
assert response.status_code == 200
result = response.json
logger.debug(result)
assert result.get("verified") is not None
assert result.get("model") is not None
assert result.get("similarity_metric") is not None
assert result.get("detector_backend") is not None
assert result.get("distance") is not None
assert result.get("threshold") is not None
assert result.get("facial_areas") is not None
assert result.get("verified") is True
logger.info("✅ true-negative verification api test is done")
def test_represent(self):
data = {
"img": "dataset/img1.jpg",
}
response = self.app.post("/represent", json=data)
assert response.status_code == 200
result = response.json
logger.debug(result)
assert result.get("results") is not None
assert isinstance(result["results"], list) is True
assert len(result["results"]) > 0
for i in result["results"]:
assert i.get("embedding") is not None
assert isinstance(i.get("embedding"), list) is True
assert len(i.get("embedding")) == 4096
assert i.get("face_confidence") is not None
assert i.get("facial_area") is not None
logger.info("✅ representation api test is done")
def test_analyze(self):
data = {
"img": "dataset/img1.jpg",
}
response = self.app.post("/analyze", json=data)
assert response.status_code == 200
result = response.json
logger.debug(result)
assert result.get("results") is not None
assert isinstance(result["results"], list) is True
assert len(result["results"]) > 0
for i in result["results"]:
assert i.get("age") is not None
assert isinstance(i.get("age"), (int, float))
assert i.get("dominant_gender") is not None
assert i.get("dominant_gender") in ["Man", "Woman"]
assert i.get("dominant_emotion") is not None
assert i.get("dominant_race") is not None
logger.info("✅ analyze api test is done")
def test_invalid_verify(self):
data = {
"img1_path": "dataset/invalid_1.jpg",
"img2_path": "dataset/invalid_2.jpg",
}
response = self.app.post("/verify", json=data)
assert response.status_code == 400
logger.info("✅ invalid verification request api test is done")
def test_invalid_represent(self):
data = {
"img": "dataset/invalid_1.jpg",
}
response = self.app.post("/represent", json=data)
assert response.status_code == 400
logger.info("✅ invalid represent request api test is done")
def test_invalid_analyze(self):
data = {
"img": "dataset/invalid.jpg",
}
response = self.app.post("/analyze", json=data)
assert response.status_code == 400