""" Proxy Base handler
Module realize base class for all handlers.
"""
from typing import Iterable, Optional
from luna3.client import Client
from luna_plugins.matcher_plugins.base_struct import (
Candidate,
Descriptor,
ErrorMatchResult,
EventExternalIdReference,
EventTrackIdReference,
FaceExternalIdReference,
MatchRequest,
MatchResult,
MatchUnitType,
Reference,
)
from vlutils.descriptors.data import DescriptorType
from app_common.handlers.base_matcher_handler import CommonBaseMatcherHandler
from classes.descriptor_validator import DescriptorValidator, InvalidDescriptor
from classes.enums import ReferenceType
from classes.matching_storage import MatchingStorage
from crutches_on_wheels.cow.errors.errors import Error
from crutches_on_wheels.cow.errors.exception import VLException
[docs]class BaseMatcherHandler(CommonBaseMatcherHandler):
"""
Proxy Base handler for other handlers.
Attributes:
luna3Client (luna3.client.Client): luna3 client
"""
def __init__(self, request):
super().__init__(request)
self.luna3Client: Optional[Client] = self.app.ctx.luna3Session.getClient(self.requestId)
self.referenceLimit = self.app.ctx.serviceConfig.platformLimits.match.referenceLimit
[docs] async def getMatchRequests(
self,
inputJson: dict,
accountId: Optional[str] = None,
matchDescriptorType: DescriptorType = DescriptorType.face,
) -> MatchingStorage:
"""
Get match candidates and match references from the request.
Args:
inputJson: input json
accountId: account id
matchDescriptorType: match descriptor type - face or body
Raises:
VLException(Error.ReferencesLimitExceeded.format(REFERENCE_LIMIT), 400) in case a lot of refs was given
Returns:
tuple with match requests list and loading errors list
"""
storage = MatchingStorage()
candidates: tuple[Candidate] = tuple(self._getCandidates(inputJson["candidates"], accountId))
references: Iterable[tuple[Reference, Optional[ErrorMatchResult]]] = self._getReferences(
rawReferences=inputJson["references"], accountId=accountId, referenceDescriptorType=matchDescriptorType
)
dbReferenceCount = 0
async for reference, error in references:
if reference.type != MatchUnitType.descriptor:
dbReferenceCount += 1
if dbReferenceCount >= self.referenceLimit:
raise VLException(Error.ReferencesLimitExceeded.format(self.referenceLimit), 400, isCriticalError=False)
for candidate in candidates:
matchRequest = MatchRequest(
reference=reference,
candidate=candidate,
accountId=accountId,
matchDescriptorType=matchDescriptorType,
requestId=self.requestId,
)
if error:
storage.addMatchResult(MatchResult(matchRequest=matchRequest, results=error))
else:
storage.addMatchRequest(matchRequest)
return storage
[docs] def getDescriptor(self, inputReference: dict) -> Descriptor:
"""
Override getBinaryReference behaviour in part of returned type.
Args:
inputReference: a dict from the request
Returns:
Descriptor obj
"""
binaryDescriptor, version = self._getBinaryReference(inputReference)
return Descriptor(descriptor=binaryDescriptor, version=version)
async def _getReferences(
self, rawReferences: list[dict], referenceDescriptorType: DescriptorType, accountId: Optional[str] = None
) -> list[tuple[Reference, Optional[ErrorMatchResult]]]:
"""
Get references from request.
Args:
rawReferences: list with references from json
referenceDescriptorType: reference descriptor type - face or body
accountId: account id from request
Yields:
tuples of (Reference, ErrorMatchResult)
Raises:
VLException(Error.LunaEventsIsDisabled, 403, isCriticalError=False) if one of references is `event`, but
`luna-events` is disabled
"""
if referenceDescriptorType == DescriptorType.face:
validate = DescriptorValidator(self.config.defaultFaceDescriptorVersion)
else:
validate = DescriptorValidator(self.config.defaultHumanDescriptorVersion)
for inputReference in rawReferences:
referenceId, referenceStrType = inputReference["id"], inputReference["type"]
if not self.configLunaEventsUsage and referenceStrType == ReferenceType.event.value:
raise VLException(Error.LunaEventsIsDisabled, 403, isCriticalError=False)
if referenceStrType in self.ENTITY_REFERENCE:
yield Reference(type=MatchUnitType[referenceStrType], id=referenceId, descriptor=None), None
elif referenceStrType in self.BINARY_REFERENCE:
descriptor = self.getDescriptor(inputReference)
reference = Reference(type=MatchUnitType.descriptor, descriptor=descriptor, id=referenceId)
try:
validate(descriptor.descriptor, descriptor.version)
except InvalidDescriptor as exc:
errorInfo = exc.error
error = ErrorMatchResult(errorInfo.errorCode, errorInfo.description, errorInfo.detail)
yield reference, error
else:
yield reference, None
elif referenceStrType == ReferenceType.faceExternal.value:
faces = await self.facesDBContext.getFaces(
externalId=referenceId, accountId=accountId, targets=["face_id"]
)
if not faces:
errorInfo = Error.NoOneFaceFoundByExternalId.format(referenceId)
yield FaceExternalIdReference(type=MatchUnitType.face, id=referenceId), ErrorMatchResult(
errorInfo.errorCode, errorInfo.description, errorInfo.detail
)
for face in faces:
yield FaceExternalIdReference(
type=MatchUnitType.face, id=face["face_id"], externalObjectId=referenceId
), None
elif referenceStrType == ReferenceType.eventExternal.value:
eventIds = await self.eventsDBContext.getEventIdsByExternalFields(
externalId=referenceId, accountId=accountId
)
if not eventIds:
errorInfo = Error.NoOneEventFoundByExternalId.format(referenceId)
yield EventExternalIdReference(type=MatchUnitType.event, id=referenceId), ErrorMatchResult(
errorInfo.errorCode, errorInfo.description, errorInfo.detail
)
for eventId in eventIds:
yield EventExternalIdReference(
type=MatchUnitType.event, id=eventId, externalObjectId=referenceId
), None
elif referenceStrType == ReferenceType.eventTrack.value:
eventIds = await self.eventsDBContext.getEventIdsByExternalFields(
trackId=referenceId, accountId=accountId
)
if not eventIds:
errorInfo = Error.NoOneEventFoundByTrackId.format(referenceId)
yield EventTrackIdReference(type=MatchUnitType.event, id=referenceId), ErrorMatchResult(
errorInfo.errorCode, errorInfo.description, errorInfo.detail
)
for eventId in eventIds:
yield EventTrackIdReference(
type=MatchUnitType.event, id=eventId, externalObjectId=referenceId
), None
else:
raise ValueError(f'Unknown reference type "{referenceStrType}"')