You've already forked FrameTour-BE
refactor(face): 重构人脸识别服务逻辑
- 优化了 faceId 参数校验和日志记录 - 重构了人脸识别主流程,增加了异常处理和日志记录 - 新增了人脸识别补救逻辑方法 - 优化了源文件关联、免费逻辑、购买状态处理等方法 - 重构了视频重切逻辑,使其更加清晰- 优化了时间范围筛选逻辑
This commit is contained in:
@@ -2,6 +2,7 @@ package com.ycwl.basic.service.task.impl;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.ycwl.basic.integration.common.manager.DeviceConfigManager;
|
||||
import com.ycwl.basic.integration.common.manager.ScenicConfigManager;
|
||||
import com.ycwl.basic.utils.JacksonUtil;
|
||||
import com.aliyuncs.facebody.model.v20191230.SearchFaceRequest;
|
||||
import com.ycwl.basic.biz.OrderBiz;
|
||||
@@ -168,26 +169,22 @@ public class TaskFaceServiceImpl implements TaskFaceService {
|
||||
request.setDbName(dbName);
|
||||
request.setImageUrl(faceUrl);
|
||||
request.setLimit(200);
|
||||
// request.setQualityScoreThreshold(60f);
|
||||
FaceDetectLog logEntity = FaceDetectLog.quickCreate(reason, request);
|
||||
float threshold = 0;
|
||||
int tourMinutes = -1;
|
||||
ScenicConfigManager scenicConfig = null;
|
||||
if (StringUtils.isNumeric(dbName)) {
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(Long.valueOf(dbName));
|
||||
scenicConfig = scenicRepository.getScenicConfigManager(Long.valueOf(dbName));
|
||||
if (scenicConfig != null) {
|
||||
if (scenicConfig.getFaceScoreThreshold() != null) {
|
||||
threshold = scenicConfig.getFaceScoreThreshold() / 100F;
|
||||
}
|
||||
if (scenicConfig.getTourTime() != null) {
|
||||
tourMinutes = scenicConfig.getTourTime();
|
||||
if (scenicConfig.getFloat("face_score_threshold") != null) {
|
||||
threshold = scenicConfig.getFloat("face_score_threshold") / 100F;
|
||||
}
|
||||
}
|
||||
} else if (StringUtils.isNumeric(dbName.replace(USER_FACE_DB_NAME, ""))) {
|
||||
Long scenicId = Long.valueOf(dbName.replace(USER_FACE_DB_NAME, ""));
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
|
||||
scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
|
||||
if (scenicConfig != null) {
|
||||
if (scenicConfig.getFaceScoreThreshold() != null) {
|
||||
threshold = scenicConfig.getFaceScoreThreshold() / 100F;
|
||||
if (scenicConfig.getFloat("face_score_threshold") != null) {
|
||||
threshold = scenicConfig.getFloat("face_score_threshold") / 100F;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -219,35 +216,8 @@ public class TaskFaceServiceImpl implements TaskFaceService {
|
||||
.filter(StringUtils::isNumeric)
|
||||
.map(Long::valueOf)
|
||||
.collect(Collectors.toList());
|
||||
List<FaceSampleEntity> allFaceSampleList = new ArrayList<>();
|
||||
if (StringUtils.isNumeric(dbName)) { // 景区
|
||||
allFaceSampleList = faceSampleMapper.listByIds(allFaceSampleIds);
|
||||
if (!acceptFaceSampleIds.isEmpty()) {
|
||||
List<Long> finalAcceptFaceSampleIds = acceptFaceSampleIds;
|
||||
Optional<FaceSampleEntity> firstFaceSample = allFaceSampleList.stream()
|
||||
.filter(faceSample -> finalAcceptFaceSampleIds.contains(faceSample.getId()))
|
||||
.sorted(Comparator.comparing(FaceSampleEntity::getCreateAt).reversed())
|
||||
.findAny();
|
||||
// Long firstFaceSampleId = acceptFaceSampleIds.getFirst();
|
||||
// Optional<FaceSampleEntity> firstFaceSample = allFaceSampleList.stream().filter(faceSample -> faceSample.getId().equals(firstFaceSampleId)).findAny();
|
||||
if (firstFaceSample.isPresent()) {
|
||||
if (tourMinutes > 0) {
|
||||
List<FaceSampleEntity> acceptFaceSampleList = faceSampleMapper.listByIds(acceptFaceSampleIds);
|
||||
Date startDate = DateUtil.offsetMinute(firstFaceSample.get().getCreateAt(), -tourMinutes);
|
||||
Date endDate = DateUtil.offsetMinute(firstFaceSample.get().getCreateAt(), 1);
|
||||
acceptFaceSampleIds = acceptFaceSampleList.stream()
|
||||
.filter(faceSample -> faceSample.getCreateAt().after(startDate) && faceSample.getCreateAt().before(endDate))
|
||||
.map(FaceSampleEntity::getId)
|
||||
.collect(Collectors.toList());
|
||||
log.info("时间范围逻辑:最高匹配:{},时间范围需要在:{}~{}间", firstFaceSample, startDate, endDate);
|
||||
} else {
|
||||
log.info("时间范围逻辑:景区未限制");
|
||||
}
|
||||
} else {
|
||||
log.info("时间范围逻辑:最高匹配ID:{},未找到", "--");
|
||||
}
|
||||
}
|
||||
}
|
||||
List<FaceSampleEntity> allFaceSampleList = faceSampleMapper.listByIds(allFaceSampleIds);
|
||||
acceptFaceSampleIds = applySampleFilters(acceptFaceSampleIds, allFaceSampleList, scenicConfig);
|
||||
List<MatchLocalRecord> collect = new ArrayList<>();
|
||||
for (SearchFaceResultItem item : records) {
|
||||
MatchLocalRecord record = new MatchLocalRecord();
|
||||
@@ -360,4 +330,97 @@ public class TaskFaceServiceImpl implements TaskFaceService {
|
||||
}
|
||||
redisTemplate.opsForValue().set(FaceConstant.FACE_USER_URL_PFX + faceId, faceUrl, 3, TimeUnit.DAYS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用样本筛选逻辑
|
||||
* 包含时间范围筛选和未来可能的其他筛选策略
|
||||
*
|
||||
* @param acceptedSampleIds 已接受的样本ID列表
|
||||
* @param allFaceSampleList 所有人脸样本实体列表
|
||||
* @param scenicConfig 景区配置,包含各种筛选策略的参数
|
||||
* @return 筛选后的样本ID列表
|
||||
*/
|
||||
private List<Long> applySampleFilters(List<Long> acceptedSampleIds,
|
||||
List<FaceSampleEntity> allFaceSampleList,
|
||||
ScenicConfigManager scenicConfig) {
|
||||
if (acceptedSampleIds == null || acceptedSampleIds.isEmpty()) {
|
||||
return acceptedSampleIds;
|
||||
}
|
||||
if (scenicConfig == null) {
|
||||
// 没有配置,不管
|
||||
return acceptedSampleIds;
|
||||
}
|
||||
|
||||
// 1. 找到最高匹配的样本(按创建时间倒序排列的第一个)
|
||||
Optional<FaceSampleEntity> firstFaceSample = allFaceSampleList.stream()
|
||||
.filter(faceSample -> acceptedSampleIds.contains(faceSample.getId())).max(Comparator.comparing(FaceSampleEntity::getCreateAt));
|
||||
|
||||
if (firstFaceSample.isEmpty()) {
|
||||
log.warn("样本筛选逻辑:未找到匹配的人脸样本,acceptedIds: {}", acceptedSampleIds);
|
||||
return acceptedSampleIds;
|
||||
}
|
||||
|
||||
FaceSampleEntity topMatchSample = firstFaceSample.get();
|
||||
log.debug("样本筛选逻辑:找到最高匹配样本 ID={}, 创建时间={}",
|
||||
topMatchSample.getId(), topMatchSample.getCreateAt());
|
||||
|
||||
List<Long> filteredIds = acceptedSampleIds;
|
||||
|
||||
// 2. 应用时间范围筛选(基于景区配置)
|
||||
if (scenicConfig.getInteger("tour_time", 0) > 0) {
|
||||
filteredIds = filterSampleIdsByTimeRange(filteredIds, topMatchSample, scenicConfig.getInteger("tour_time"));
|
||||
log.debug("应用时间范围筛选:游览时间限制={}分钟", scenicConfig.getInteger("tour_time"));
|
||||
} else {
|
||||
log.debug("时间范围逻辑:景区未设置游览时间限制");
|
||||
}
|
||||
|
||||
// 3. TODO: 基于景区配置的其他筛选策略
|
||||
// 可以根据 scenicConfig 中的配置来决定是否启用特定筛选
|
||||
// 示例:未来可能的筛选策略
|
||||
// if (scenicConfig.getEnableLocationFilter() != null && scenicConfig.getEnableLocationFilter()) {
|
||||
// filteredIds = applyLocationFilter(filteredIds, allFaceSampleList, scenicConfig);
|
||||
// }
|
||||
// if (scenicConfig.getEnableQualityFilter() != null && scenicConfig.getEnableQualityFilter()) {
|
||||
// filteredIds = applyQualityFilter(filteredIds, allFaceSampleList, scenicConfig);
|
||||
// }
|
||||
// if (scenicConfig.getMaxSampleCount() != null) {
|
||||
// filteredIds = applySampleCountLimit(filteredIds, scenicConfig.getMaxSampleCount());
|
||||
// }
|
||||
|
||||
log.debug("样本筛选完成:原始数量={}, 最终数量={}",
|
||||
acceptedSampleIds.size(), filteredIds.size());
|
||||
return filteredIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据时间范围过滤人脸样本ID
|
||||
* 基于最高匹配样本的时间,过滤出指定时间范围内的样本ID
|
||||
*/
|
||||
private List<Long> filterSampleIdsByTimeRange(List<Long> acceptedSampleIds,
|
||||
FaceSampleEntity firstMatch,
|
||||
int tourMinutes) {
|
||||
if (acceptedSampleIds == null || acceptedSampleIds.isEmpty() ||
|
||||
firstMatch == null || tourMinutes <= 0) {
|
||||
return acceptedSampleIds;
|
||||
}
|
||||
|
||||
List<FaceSampleEntity> acceptFaceSampleList = faceSampleMapper.listByIds(acceptedSampleIds);
|
||||
if (acceptFaceSampleList.isEmpty()) {
|
||||
return acceptedSampleIds;
|
||||
}
|
||||
|
||||
Date startDate = DateUtil.offsetMinute(firstMatch.getCreateAt(), -tourMinutes);
|
||||
Date endDate = DateUtil.offsetMinute(firstMatch.getCreateAt(), 1);
|
||||
|
||||
List<Long> filteredIds = acceptFaceSampleList.stream()
|
||||
.filter(faceSample -> faceSample.getCreateAt().after(startDate) &&
|
||||
faceSample.getCreateAt().before(endDate))
|
||||
.map(FaceSampleEntity::getId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
log.info("时间范围逻辑:最高匹配:{},时间范围:{}~{},原样本数:{},过滤后样本数:{}",
|
||||
firstMatch.getId(), startDate, endDate, acceptedSampleIds.size(), filteredIds.size());
|
||||
|
||||
return filteredIds;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user