Spaces:
Running
Running
File size: 11,280 Bytes
b5d3a91 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 | # built-in dependencies
from typing import Union, cast, Any, Tuple, Dict
# 3rd party dependencies
from flask import Blueprint, request
from numpy.typing import NDArray
# project dependencies
from deepface import __version__
from deepface.api.src.modules.core import service
from deepface.api.src.dependencies.variables import Variables
from deepface.api.src.dependencies.container import Container
from deepface.commons import image_utils
from deepface.commons.logger import Logger
logger = Logger()
blueprint = Blueprint("routes", __name__)
# pylint: disable=no-else-return, broad-except
@blueprint.route("/")
def home() -> str:
return f"<h1>Welcome to DeepFace API v{__version__}!</h1>"
def extract_image_from_request(img_key: str) -> Union[str, NDArray[Any]]:
"""
Extracts an image from the request either from json or a multipart/form-data file.
Args:
img_key (str): The key used to retrieve the image data
from the request (e.g., 'img1').
Returns:
img (str or np.ndarray): Given image detail (base64 encoded string, image path or url)
or the decoded image as a numpy array.
"""
# Check if the request is multipart/form-data (file input)
if request.files:
# request.files is instance of werkzeug.datastructures.ImmutableMultiDict
# file is instance of werkzeug.datastructures.FileStorage
file = request.files.get(img_key)
if file is None:
raise ValueError(f"Request form data doesn't have {img_key}")
if file.filename == "":
raise ValueError(f"No file uploaded for '{img_key}'")
np_img: NDArray[Any] = image_utils.load_image_from_file_storage(file)
return np_img
# Check if the request is coming as base64, file path or url from json or form data
elif request.is_json or request.form:
input_args = request.get_json() or request.form.to_dict()
if input_args is None:
raise ValueError("empty input set passed")
# this can be base64 encoded image, and image path or url
str_img: str = cast(str, input_args.get(img_key))
if not str_img:
raise ValueError(f"'{img_key}' not found in either json or form data request")
return str_img
# If neither JSON nor file input is present
raise ValueError(f"'{img_key}' not found in request in either json or form data")
@blueprint.route("/represent", methods=["POST"])
def represent() -> Tuple[Dict[str, Any], int]:
# load injected container
container: Container = blueprint.container # type: ignore[attr-defined]
if not container.auth_service.validate(request.headers):
return {"message": "Invalid or missing authentication token"}, 401
input_args = (request.is_json and request.get_json()) or (
request.form and request.form.to_dict()
)
try:
img = extract_image_from_request("img")
except Exception as err:
return {"exception": str(err)}, 400
max_faces = input_args.get("max_faces")
obj, status_code = service.represent(
img_path=img,
model_name=input_args.get("model_name", "VGG-Face"),
detector_backend=input_args.get("detector_backend", "opencv"),
enforce_detection=bool(input_args.get("enforce_detection", True)),
align=bool(input_args.get("align", True)),
anti_spoofing=bool(input_args.get("anti_spoofing", False)),
max_faces=int(max_faces) if max_faces is not None else None,
)
logger.debug(obj)
return obj, status_code
@blueprint.route("/verify", methods=["POST"])
def verify() -> Tuple[Dict[str, Any], int]:
# load injected container
container: Container = blueprint.container # type: ignore[attr-defined]
if not container.auth_service.validate(request.headers):
return {"message": "Invalid or missing authentication token"}, 401
input_args = (request.is_json and request.get_json()) or (
request.form and request.form.to_dict()
)
try:
img1 = extract_image_from_request("img1")
except Exception as err:
return {"exception": str(err)}, 400
try:
img2 = extract_image_from_request("img2")
except Exception as err:
return {"exception": str(err)}, 400
verification, status_code = service.verify(
img1_path=img1,
img2_path=img2,
model_name=input_args.get("model_name", "VGG-Face"),
detector_backend=input_args.get("detector_backend", "opencv"),
distance_metric=input_args.get("distance_metric", "cosine"),
align=bool(input_args.get("align", True)),
enforce_detection=bool(input_args.get("enforce_detection", True)),
anti_spoofing=bool(input_args.get("anti_spoofing", False)),
)
logger.debug(verification)
return verification, status_code
@blueprint.route("/analyze", methods=["POST"])
def analyze() -> Tuple[Dict[str, Any], int]:
# load injected container
container: Container = blueprint.container # type: ignore[attr-defined]
if not container.auth_service.validate(request.headers):
return {"message": "Invalid or missing authentication token"}, 401
input_args = (request.is_json and request.get_json()) or (
request.form and request.form.to_dict()
)
try:
img = extract_image_from_request("img")
except Exception as err:
return {"exception": str(err)}, 400
actions = input_args.get("actions", ["age", "gender", "emotion", "race"])
# actions is the only argument instance of list or tuple
# if request is form data, input args can either be text or file
if isinstance(actions, str):
actions = (
actions.replace("[", "")
.replace("]", "")
.replace("(", "")
.replace(")", "")
.replace('"', "")
.replace("'", "")
.replace(" ", "")
.split(",")
)
demographies, status_code = service.analyze(
img_path=img,
actions=actions,
detector_backend=input_args.get("detector_backend", "opencv"),
enforce_detection=bool(input_args.get("enforce_detection", True)),
align=bool(input_args.get("align", True)),
anti_spoofing=bool(input_args.get("anti_spoofing", False)),
)
logger.debug(demographies)
return demographies, status_code
@blueprint.route("/register", methods=["POST"])
def register() -> Tuple[Dict[str, Any], int]:
# load injected variables and container
variables: Variables = blueprint.variables # type: ignore[attr-defined]
container: Container = blueprint.container # type: ignore[attr-defined]
if not container.auth_service.validate(request.headers):
return {"message": "Invalid or missing authentication token"}, 401
if variables.conection_details is None:
return {
"error": "Database connection details must be provided in `DEEPFACE_CONNECTION_DETAILS`"
" environment variables"
}, 500
input_args = (request.is_json and request.get_json()) or (
request.form and request.form.to_dict()
)
try:
img = extract_image_from_request("img")
except Exception as err:
return {"exception": str(err)}, 400
result, status_code = service.register(
img=img,
img_name=input_args.get("img_name"),
model_name=input_args.get("model_name", "VGG-Face"),
detector_backend=input_args.get("detector_backend", "opencv"),
enforce_detection=bool(input_args.get("enforce_detection", True)),
align=bool(input_args.get("align", True)),
l2_normalize=bool(input_args.get("l2_normalize", False)),
expand_percentage=int(input_args.get("expand_percentage", 0)),
normalization=input_args.get("normalization", "base"),
anti_spoofing=bool(input_args.get("anti_spoofing", False)),
database_type=variables.database_type,
connection_details=variables.conection_details,
)
if status_code == 200:
logger.info("An image has been registered to the database.")
else:
logger.error("An error occurred while registering an image to the database.")
return result, status_code
@blueprint.route("/search", methods=["POST"])
def search() -> Tuple[Dict[str, Any], int]:
# load injected variables and container
variables: Variables = blueprint.variables # type: ignore[attr-defined]
container: Container = blueprint.container # type: ignore[attr-defined]
if not container.auth_service.validate(request.headers):
return {"message": "Invalid or missing authentication token"}, 401
if variables.conection_details is None:
return {
"error": "Database connection details must be provided in `DEEPFACE_CONNECTION_DETAILS`"
" environment variables"
}, 500
input_args = (request.is_json and request.get_json()) or (
request.form and request.form.to_dict()
)
try:
img = extract_image_from_request("img")
except Exception as err:
return {"exception": str(err)}, 400
return service.search(
img=img,
model_name=input_args.get("model_name", "VGG-Face"),
detector_backend=input_args.get("detector_backend", "opencv"),
enforce_detection=bool(input_args.get("enforce_detection", True)),
align=bool(input_args.get("align", True)),
distance_metric=input_args.get("distance_metric", "cosine"),
l2_normalize=bool(input_args.get("l2_normalize", False)),
database_type=variables.database_type,
connection_details=variables.conection_details,
search_method=input_args.get("search_method", "exact"),
expand_percentage=int(input_args.get("expand_percentage", 0)),
normalization=input_args.get("normalization", "base"),
anti_spoofing=bool(input_args.get("anti_spoofing", False)),
similarity_search=bool(input_args.get("similarity_search", False)),
k=int(input_args.get("k", 5)) if input_args.get("k") is not None else None,
)
@blueprint.route("/build/index", methods=["POST"])
def build_index() -> Tuple[Dict[str, Any], int]:
# load injected variables and container
variables: Variables = blueprint.variables # type: ignore[attr-defined]
container: Container = blueprint.container # type: ignore[attr-defined]
if not container.auth_service.validate(request.headers):
return {"message": "Invalid or missing authentication token"}, 401
if variables.conection_details is None:
return {
"error": "Database connection details must be provided in `DEEPFACE_CONNECTION_DETAILS`"
" environment variables"
}, 500
input_args = (request.is_json and request.get_json()) or (
request.form and request.form.to_dict()
)
return service.build_index(
model_name=input_args.get("model_name", "VGG-Face"),
detector_backend=input_args.get("detector_backend", "opencv"),
align=bool(input_args.get("align", True)),
l2_normalize=bool(input_args.get("l2_normalize", False)),
database_type=variables.database_type,
connection_details=variables.conection_details,
)
|