mirror of
https://github.com/serengil/deepface.git
synced 2025-06-07 12:05:22 +00:00
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:
commit
889d033d12
@ -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()"]
|
||||
|
@ -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
|
||||
|
@ -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
0
deepface/api/__init__.py
Normal file
0
deepface/api/src/__init__.py
Normal file
0
deepface/api/src/__init__.py
Normal 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__)
|
0
deepface/api/src/modules/__init__.py
Normal file
0
deepface/api/src/modules/__init__.py
Normal file
0
deepface/api/src/modules/core/__init__.py
Normal file
0
deepface/api/src/modules/core/__init__.py
Normal 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
|
54
deepface/api/src/modules/core/service.py
Normal file
54
deepface/api/src/modules/core/service.py
Normal 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
|
@ -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,
|
||||
}
|
||||
|
@ -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
123
tests/test_api.py
Normal 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
|
Loading…
x
Reference in New Issue
Block a user