예제 #1
0
        public async Task HandleAsync(CreateVisitor message, IRequestInfo requestInfo)
        {
            if (!await _userServiceClient.ContainsUserAsync(message.VisitingId))
            {
                _logger.LogWarning($"No user with id: {message.VisitingId} could be found");
                PublishFailure(requestInfo);
                return;
            }

            var site = await _siteServiceClient.GetSiteAsync(message.SiteId);

            if (site is null)
            {
                _logger.LogInformation($"No site found with id: {message.SiteId}");
                PublishFailure(requestInfo);
                return;
            }

            try
            {
                await _validatorService.Validate(site.BusinessId, message.Data);
            }
            catch (VmsException e)
            {
                _messagePublisher.PublishEvent(new CreateVisitorRejected(e.Code, e.Message), requestInfo);
                return;
            }

            //TODO: create service to validate data entrys

            var visitorData = new List <VisitorData>();

            foreach (var visitorDataEntry in message.Data)
            {
                visitorData.Add(_visitorAggregate.CreateData(visitorDataEntry.FieldId, visitorDataEntry.Value));
            }

            var visitor = _visitorAggregate.Create(message.VisitingId, site.BusinessId, message.SiteId, visitorData);

            await _visitorsRepository.AddAsync(visitor);

            _messagePublisher.PublishEvent(new VisitorCreated(), requestInfo);
        }
예제 #2
0
        public async Task <bool> UpdateDemographics()
        {
            var start = DateTime.UtcNow;

            //A flag to know if we would update/insert the demographics record
            bool isNewDemographics = false;

            //A flag to know that and updated demographics are needed
            bool isDemographicsChanged = false;

            var analysisTakenAt = frameAnalysis.Request.TakenAt;

            //As the system designed to handle multiple devices, analysis also should be conducted in
            //the context of DeviceId
            var deviceId = frameAnalysis.Request.DeviceId;

            //We need to retain our analysis relevant to the frame taken date
            var visitDate = frameAnalysis.Request.TakenAt;

            // aggregate window start from begging of the hour and continue aggregating till 59min:59sec.
            var demographicsWindowMins      = double.Parse(GlobalSettings.GetKeyValue("demographicsWindowMins")); //Default to 60mins
            var currentAggregateWindowStart = new DateTime(analysisTakenAt.Year, analysisTakenAt.Month, analysisTakenAt.Day, analysisTakenAt.Hour, 0, 0);
            var currentAggregateWindowEnd   = currentAggregateWindowStart.AddMinutes(demographicsWindowMins);
            //var currentTime = DateTime.UtcNow;

            var    passedTimeOfCurrentWindowMins = (currentAggregateWindowEnd - currentAggregateWindowStart).TotalMinutes;
            string crowdDemographicsId           = null;

            if (passedTimeOfCurrentWindowMins > demographicsWindowMins)
            {
                // Move the demographics to the next window
                currentAggregateWindowStart = currentAggregateWindowStart.AddMinutes(demographicsWindowMins);
                currentAggregateWindowEnd   = currentAggregateWindowStart.AddMinutes(demographicsWindowMins);
            }

            crowdDemographicsId = $"{currentAggregateWindowStart.ToString("yyyy-MM-dd-HH-mm-ss")}|{currentAggregateWindowEnd.ToString("yyyy-MM-dd-HH-mm-ss")}:{deviceId}";

            try
            {
                Demographics = await crowdDemographicsRepo.GetByIdAsync(crowdDemographicsId);
            }
            catch (Exception ex)
            {
                if (ex.Message == "Entity not found")
                {
                    Demographics = null;
                }
                else
                {
                    throw;
                }
            }

            if (Demographics == null)
            {
                isNewDemographics     = true;
                isDemographicsChanged = true;
                Demographics          = new CrowdDemographics
                {
                    Id            = crowdDemographicsId,
                    DeviceId      = deviceId,
                    WindowStart   = currentAggregateWindowStart,
                    WindowEnd     = currentAggregateWindowEnd,
                    CreatedAt     = DateTime.UtcNow,
                    LastUpdatedAt = DateTime.UtcNow,
                    Origin        = origin,
                    IsDeleted     = false
                };
            }

            if (frameAnalysis.SimilarFaces != null)
            {
                // Update the Visitor collection (either add new entry or update existing)
                log.LogWarning($"FUNC (CrowdAnalyzer): ({frameAnalysis.SimilarFaces.Count()}) detected faces is being processed.");
                foreach (var item in frameAnalysis.SimilarFaces)
                {
                    //Do we have that visitor in our db
                    Guid persistedFaceId = item.SimilarPersistedFace.PersistedFaceId.GetValueOrDefault();

                    Visitor visitor = null;
                    try
                    {
                        visitor = await visitorRepo.GetByIdAsync($"{persistedFaceId}:{item.Face.FaceAttributes.Gender}");
                    }
                    catch (Exception ex)
                    {
                        if (ex.Message == "Entity not found")
                        {
                            visitor = null;
                        }
                        else
                        {
                            throw;
                        }
                    }

                    //Visitor exists:
                    if (visitor != null)
                    {
                        //Check if the visit was already recorded before (new date is within the visit window)
                        var lastVisit = visitor.LastVisits.Where(v => v.DetectedOnDeviceId == frameAnalysis.Request.DeviceId).FirstOrDefault();

                        if (lastVisit != null)
                        {
                            if (!(lastVisit.VisitDate >= currentAggregateWindowStart && lastVisit.VisitDate <= currentAggregateWindowEnd))
                            {
                                //New visit of a returning customer :) update the counts
                                visitor.VisitsCount++;
                                lastVisit.Count++;
                                lastVisit.VisitDate = analysisTakenAt;

                                //This means also that the demographic for this window is changed as well.
                                isDemographicsChanged = true;
                                await visitorRepo.UpdateAsync(visitor);
                            }
                        }
                        else
                        {
                            visitor.VisitsCount++;
                            var newVisit = new Visit
                            {
                                Count = 1,
                                DetectedOnDeviceId = deviceId,
                                VisitDate          = analysisTakenAt
                            };
                            visitor.LastVisits.Add(newVisit);
                            isDemographicsChanged = true;
                            await visitorRepo.UpdateAsync(visitor);
                        }
                    }
                    //New Visitor
                    else
                    {
                        isDemographicsChanged = true;

                        visitor = new Visitor
                        {
                            Id          = $"{persistedFaceId}:{item.Face.FaceAttributes.Gender}",
                            VisitsCount = 1,
                            Age         = (int)item.Face.FaceAttributes.Age,
                            AgeGroup    = GetAgeGroupDescription((int)item.Face.FaceAttributes.Age),
                            Gender      = item.Face.FaceAttributes.Gender.ToString(),
                            CreatedAt   = DateTime.UtcNow,
                            IsDeleted   = false,
                            Origin      = origin,
                            LastVisits  = new List <Visit>
                            {
                                new Visit {
                                    Count = 1,
                                    DetectedOnDeviceId = deviceId,
                                    VisitDate          = analysisTakenAt
                                }
                            }
                        };

                        await visitorRepo.AddAsync(visitor);

                        isDemographicsChanged = true;
                        if (item.Face.FaceAttributes.Gender == Gender.Male)
                        {
                            Demographics.TotalNewMaleVisitors++;
                        }
                        else
                        {
                            Demographics.TotalNewFemaleVisitors++;
                        }
                    }

                    if (isDemographicsChanged)
                    {
                        UpdateVisitorDemographics(item);
                    }
                }

                Demographics.TotalVisitors       = Demographics.TotalMales + Demographics.TotalFemales;
                Demographics.TotalProcessingTime = (int)(DateTime.UtcNow - start).TotalMilliseconds;

                //if (isNewDemographics)
                //{
                //    await crowdDemographicsRepo.AddAsync(Demographics);
                //    return true;
                //}
                //else if (isDemographicsChanged)
                //{
                //    await crowdDemographicsRepo.UpdateAsync(Demographics);
                //    return true;
                //}
            }
            //No faces in the analysis request
            else
            {
                log.LogWarning($"FUNC (CrowdAnalyzer): crowd-analysis found no faces in the analysis request");
            }

            // Prepare Identified persons analytics
            try
            {
                if (frameAnalysis.IdentifiedPersons != null)
                {
                    log.LogWarning($"FUNC (CrowdAnalyzer): ({frameAnalysis.SimilarFaces.Count()}) identified persons is being processed.");
                    int identifiedPersonsCount = 0;
                    Demographics.IdentifiedPersonsIds = new List <string>();

                    foreach (var item in frameAnalysis.IdentifiedPersons)
                    {
                        //Check if the identification passed with acceptable confidence
                        if (item.Item2.Confidence >= AppConstants.IdentificationConfidence)
                        {
                            var result = await identifiedVisitorRepo.QueryDocuments(
                                "visitor",
                                "visitor.PersonDetails.personId=@personId",
                                new SqlParameterCollection {
                                new SqlParameter {
                                    Name = "@personId", Value = item.Item2.Person.PersonId.ToString()
                                }
                            });

                            if (result.Any())
                            {
                                var identifiedVisitor = result[0];
                                // Ignore already detected identified visitor if exists in the same window
                                if (Demographics.IdentifiedPersonsIds.Contains(identifiedVisitor.Id))
                                {
                                    continue;
                                }

                                Demographics.IdentifiedPersonsIds.Add(identifiedVisitor.Id);

                                //Update visit last visit date
                                identifiedVisitor.LastVisits.Add(new PersonIdentificationLib.Models.Visit
                                {
                                    Count = 1,
                                    DetectedOnDeviceId = Demographics.DeviceId,
                                    VisitDate          = DateTime.UtcNow
                                });

                                identifiedPersonsCount++;
                            }
                        }
                    }
                    Demographics.TotalIdentifiedPersons = identifiedPersonsCount;
                }
            }
            catch (Exception ex)
            {
                log.LogError($"FUNC (CrowdAnalyzer): crowd-analysis couldn't process identified visitors: {ex.Message}");
            }
            // Frame do not have any faces or identified persons
            if (frameAnalysis.SimilarFaces == null && frameAnalysis.IdentifiedPersons == null)
            {
                return(false);
            }

            if (isNewDemographics)
            {
                await crowdDemographicsRepo.AddAsync(Demographics);

                return(true);
            }
            else if (isDemographicsChanged)
            {
                await crowdDemographicsRepo.UpdateAsync(Demographics);

                return(true);
            }

            return(false);
        }