""" Detector Handler
Module realize detector handler.
"""
from typing import Awaitable, List, Union
from sanic.response import HTTPResponse
from app.api_sdk_adaptors.base import LoopEstimationsAlwaysOn
from app.api_sdk_adaptors.detector import APISDKDetectorAdaptor
from app.api_sdk_adaptors.orientation import handleImageOrientation
from app.handlers.base_handler import BaseHandlerWithMultipart
from app.handlers.custom_query_getters import detectorImageTypeGetter, int0180Getter, multifacePolicyGetter
from classes.image_meta import InputImageData
from classes.multipart_processing import DetectorMultipartProcessor
from classes.schemas.detector import Detector
from crutches_on_wheels.errors.errors import ErrorInfo
from crutches_on_wheels.errors.exception import VLException
from crutches_on_wheels.monitoring.points import monitorTime
from crutches_on_wheels.web.query_getters import boolFrom01Getter, int01Getter, uuidGetter
from sdk.sdk_loop.enums import LoopEstimations, MultifacePolicy
from sdk.sdk_loop.models.image import ImageType
from sdk.sdk_loop.task import HandlersTask
from sdk.sdk_loop.tasks.filters import FaceDetectionFilters, Filters
from sdk.sdk_loop.tasks.task import TaskParams
[docs]class DetectorHandler(BaseHandlerWithMultipart):
"""
Handler for detecting faces on images.
Resource: "/{api_version}/detector"
"""
[docs] async def getDataFromMultipart(self, imageType: ImageType = ImageType.IMAGE) -> List[InputImageData]:
"""Description see :func:`~BaseHandlerWithMultipart.getDataFromMultipart`."""
dataFromRequest = await DetectorMultipartProcessor().getData(self.request)
estimationDataFromMultiPart = self._getDataFromMultipart(dataFromRequest.images, imageType)
return estimationDataFromMultiPart
def _getImagesFromSamples(
self, inputJson: dict, imageType: Union[ImageType, None], defaultDetectTime: str
) -> Awaitable[List[InputImageData]]:
"""
Stub unknown image type for face samples.
"""
sampleImageType = imageType
if imageType is None:
sampleImageType = ImageType.FACE_WARP
return super()._getImagesFromSamples(
inputJson=inputJson, imageType=sampleImageType, defaultDetectTime=defaultDetectTime
)
def _getImagesFromUrls(
self, inputJson: dict, imageType: Union[ImageType, None], defaultDetectTime: str
) -> Awaitable[List[InputImageData]]:
"""
Stub unknown image type for urls.
"""
urlImageType = imageType
if imageType is None:
urlImageType = ImageType.IMAGE
return super()._getImagesFromUrls(
inputJson=inputJson, imageType=urlImageType, defaultDetectTime=defaultDetectTime
)
[docs] async def post(self) -> HTTPResponse:
"""
Detect faces on images. See `spec_detector`_.
.. _spec_detector:
_static/api.html#operation/detectFaces
Returns:
response with succeeded processed images and failed processed images
"""
self.accountId = self.getQueryParam("account_id", uuidGetter, require=True)
targets = {LoopEstimations.faceDetection, LoopEstimationsAlwaysOn.faceLandmarks5}
if self.getQueryParam("detect_landmarks68", int01Getter, default=0):
targets.add(LoopEstimations.faceLandmarks68)
if self.getQueryParam("estimate_head_pose", int01Getter, default=0):
targets.add(LoopEstimations.headPose)
if self.getQueryParam("estimate_gaze", int01Getter, default=0):
targets.add(LoopEstimations.gaze)
if self.getQueryParam("estimate_eyes_attributes", int01Getter, default=0):
targets.add(LoopEstimations.eyes)
if self.getQueryParam("estimate_mouth_attributes", int01Getter, default=0):
targets.add(LoopEstimations.mouthAttributes)
if self.getQueryParam("estimate_emotions", int01Getter, default=0):
targets.add(LoopEstimations.emotions)
if self.getQueryParam("estimate_mask", int01Getter, default=0):
targets.add(LoopEstimations.mask)
if self.getQueryParam("estimate_quality", int01Getter, default=0):
targets.add(LoopEstimations.faceWarpQuality)
if self.getQueryParam("extract_exif", int01Getter, default=0):
targets.add(LoopEstimations.exif)
faceFilters = FaceDetectionFilters(
rollThreshold=self.getQueryParam("roll_threshold", int0180Getter),
yawThreshold=self.getQueryParam("yaw_threshold", int0180Getter),
pitchThreshold=self.getQueryParam("pitch_threshold", int0180Getter),
)
if faceFilters.rollFilter or faceFilters.yawFilter or faceFilters.pitchFilter:
targets.add(LoopEstimations.headPose)
multifacePolicy = self.getQueryParam("multiface_policy", multifacePolicyGetter, default=MultifacePolicy.allowed)
params = TaskParams(
targets=targets,
filters=Filters(faceDetection=faceFilters),
multifacePolicy=multifacePolicy,
useExifInfo=self.getQueryParam("use_exif_info", boolFrom01Getter, default=True),
autoRotation=self.config.useAutoRotation,
)
imageType = self.getQueryParam("warped_image", detectorImageTypeGetter)
with monitorTime(self.request.dataForMonitoring, "download_images_time"):
inputData = await self.getInputEstimationData(self.request, imageType=imageType, validationModel=Detector)
task = HandlersTask(data=[metaImage.image for metaImage in inputData], params=params)
await task.execute()
if task.result.error:
raise VLException(ErrorInfo.fromDict(task.result.error.asDict()), 400, isCriticalError=False)
if self.config.useAutoRotation:
handleImageOrientation(task.result.images)
detectorAdaptor = APISDKDetectorAdaptor(
estimationTargets=targets,
accountId=self.accountId,
sampleStore=self.luna3Client.lunaFaceSamplesStore,
sampleBucket=self.config.faceSamplesStorage.bucket,
)
result, monitoringData = await detectorAdaptor.buildResult(
task.result, meta=[metaImage.meta for metaImage in inputData]
)
self.handleMonitoringData(monitoringData)
return self.success(201, outputJson=result)