You've already forked FrameTour-BE
refactor(face):优化人脸识别更新接口及样本展示逻辑
- 修改 updateRecognition 接口返回类型为 void,简化响应内容 - 移除 FaceRecognitionSampleVO 中冗余的字段(sourceType、faceUrl 等)- 删除与过滤原因相关的属性和处理逻辑 - 简化 buildSampleVO 方法参数及内部实现- 调整 resolveSourceUrl 方法中 URL 获取优先级 - 优化样本列表构建逻辑,提升性能与可读性
This commit is contained in:
@@ -111,10 +111,11 @@ public class AppFaceController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/{faceId}/recognition")
|
@PutMapping("/{faceId}/recognition")
|
||||||
public ApiResponse<FaceRecognitionDetailVO> updateRecognition(@PathVariable Long faceId,
|
public ApiResponse<?> updateRecognition(@PathVariable Long faceId,
|
||||||
@RequestBody FaceRecognitionUpdateReq req) {
|
@RequestBody FaceRecognitionUpdateReq req) {
|
||||||
req.setFaceId(faceId);
|
req.setFaceId(faceId);
|
||||||
return ApiResponse.success(faceService.updateRecognition(req));
|
faceService.updateRecognition(req);
|
||||||
|
return ApiResponse.success("OK");
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{faceId}/recognition/detail")
|
@GetMapping("/{faceId}/recognition/detail")
|
||||||
|
|||||||
@@ -17,9 +17,7 @@ public class FaceRecognitionSampleVO {
|
|||||||
private Boolean accepted;
|
private Boolean accepted;
|
||||||
|
|
||||||
private Long sourceId;
|
private Long sourceId;
|
||||||
private Integer sourceType;
|
|
||||||
private String sourceUrl;
|
private String sourceUrl;
|
||||||
private String faceUrl;
|
|
||||||
|
|
||||||
private Long deviceId;
|
private Long deviceId;
|
||||||
private String deviceName;
|
private String deviceName;
|
||||||
@@ -27,16 +25,4 @@ public class FaceRecognitionSampleVO {
|
|||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date shotAt;
|
private Date shotAt;
|
||||||
|
|
||||||
private Integer isFree;
|
|
||||||
private Integer isBuy;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 过滤原因列表,用于提示用户样本被过滤的原因。
|
|
||||||
*/
|
|
||||||
private List<FaceRecognitionFilterReason> filterReasons;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 过滤原因的描述集合,方便前端直接展示。
|
|
||||||
*/
|
|
||||||
private List<String> filterReasonTexts;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ public interface FaceService {
|
|||||||
|
|
||||||
void matchCustomFaceId(Long faceId, List<Long> faceSampleIds);
|
void matchCustomFaceId(Long faceId, List<Long> faceSampleIds);
|
||||||
|
|
||||||
FaceRecognitionDetailVO updateRecognition(FaceRecognitionUpdateReq req);
|
void updateRecognition(FaceRecognitionUpdateReq req);
|
||||||
|
|
||||||
FaceRecognitionDetailVO getRecognitionDetail(Long faceId);
|
FaceRecognitionDetailVO getRecognitionDetail(Long faceId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import com.ycwl.basic.model.mobile.scenic.content.ContentPageVO;
|
|||||||
import com.ycwl.basic.model.mobile.statistic.req.StatisticsRecordAddReq;
|
import com.ycwl.basic.model.mobile.statistic.req.StatisticsRecordAddReq;
|
||||||
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
|
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
|
||||||
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
|
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
|
||||||
import com.ycwl.basic.model.pc.face.enums.FaceRecognitionFilterReason;
|
|
||||||
import com.ycwl.basic.model.mobile.face.FaceRecognitionUpdateReq;
|
import com.ycwl.basic.model.mobile.face.FaceRecognitionUpdateReq;
|
||||||
import com.ycwl.basic.model.pc.face.req.FaceReqQuery;
|
import com.ycwl.basic.model.pc.face.req.FaceReqQuery;
|
||||||
import com.ycwl.basic.model.mobile.face.FaceRecognitionDetailVO;
|
import com.ycwl.basic.model.mobile.face.FaceRecognitionDetailVO;
|
||||||
@@ -80,7 +79,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
@@ -1264,7 +1262,7 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FaceRecognitionDetailVO updateRecognition(FaceRecognitionUpdateReq req) {
|
public void updateRecognition(FaceRecognitionUpdateReq req) {
|
||||||
if (req == null || req.getFaceId() == null) {
|
if (req == null || req.getFaceId() == null) {
|
||||||
throw new IllegalArgumentException("faceId 不能为空");
|
throw new IllegalArgumentException("faceId 不能为空");
|
||||||
}
|
}
|
||||||
@@ -1308,8 +1306,6 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
if (Strings.isNotBlank(req.getRemark())) {
|
if (Strings.isNotBlank(req.getRemark())) {
|
||||||
log.info("人脸识别人工调整备注:faceId={}, remark={}", faceId, req.getRemark());
|
log.info("人脸识别人工调整备注:faceId={}, remark={}", faceId, req.getRemark());
|
||||||
}
|
}
|
||||||
|
|
||||||
return getRecognitionDetail(faceId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1363,52 +1359,12 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
return detail;
|
return detail;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<FaceSampleEntity> allSamples = faceSampleMapper.listByIds(allSampleIds);
|
|
||||||
Map<Long, FaceSampleEntity> sampleEntityMap = allSamples.stream()
|
|
||||||
.collect(Collectors.toMap(FaceSampleEntity::getId, Function.identity(), (a, b) -> a, LinkedHashMap::new));
|
|
||||||
|
|
||||||
List<SourceEntity> sourceEntities = sourceMapper.listBySampleIds(allSampleIds);
|
List<SourceEntity> sourceEntities = sourceMapper.listBySampleIds(allSampleIds);
|
||||||
Map<Long, SourceEntity> sourceBySampleId = sourceEntities.stream()
|
Map<Long, SourceEntity> sourceBySampleId = sourceEntities.stream()
|
||||||
.collect(Collectors.toMap(SourceEntity::getFaceSampleId, Function.identity(), (a, b) -> a, LinkedHashMap::new));
|
.collect(Collectors.toMap(SourceEntity::getFaceSampleId, Function.identity(), (a, b) -> a, LinkedHashMap::new));
|
||||||
Map<Long, SourceEntity> sourceById = sourceEntities.stream()
|
Map<Long, SourceEntity> sourceById = sourceEntities.stream()
|
||||||
.collect(Collectors.toMap(SourceEntity::getId, Function.identity(), (a, b) -> a));
|
.collect(Collectors.toMap(SourceEntity::getId, Function.identity(), (a, b) -> a));
|
||||||
|
|
||||||
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(face.getScenicId());
|
|
||||||
Float thresholdConfig = scenicConfig != null ? scenicConfig.getFloat("face_score_threshold") : null;
|
|
||||||
float threshold = thresholdConfig != null ? thresholdConfig / 100F : 0F;
|
|
||||||
|
|
||||||
List<Long> initialAcceptedIds = allSampleIds.stream()
|
|
||||||
.filter(id -> {
|
|
||||||
SearchFaceResultItem item = itemBySampleId.get(id);
|
|
||||||
return item != null && item.getScore() != null && item.getScore() > threshold;
|
|
||||||
})
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
List<FaceSampleEntity> orderedSampleList = allSampleIds.stream()
|
|
||||||
.map(sampleEntityMap::get)
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
SampleFilterTrace filterTrace = faceService.applySampleFiltersWithTrace(initialAcceptedIds, orderedSampleList, scenicConfig);
|
|
||||||
List<Long> systemAcceptedIds = filterTrace.getAcceptedSampleIds() == null
|
|
||||||
? Collections.emptyList()
|
|
||||||
: filterTrace.getAcceptedSampleIds();
|
|
||||||
|
|
||||||
Set<Long> initialAcceptedSet = new HashSet<>(initialAcceptedIds);
|
|
||||||
for (Long sampleId : allSampleIds) {
|
|
||||||
if (!initialAcceptedSet.contains(sampleId) && !systemAcceptedIds.contains(sampleId)) {
|
|
||||||
filterTrace.addReason(sampleId, FaceRecognitionFilterReason.SCORE_BELOW_THRESHOLD);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<Long> systemAcceptedSet = new HashSet<>(systemAcceptedIds);
|
|
||||||
Set<Long> persistedAcceptedSet = new HashSet<>(persistedAcceptedIds);
|
|
||||||
for (Long sampleId : systemAcceptedSet) {
|
|
||||||
if (!persistedAcceptedSet.contains(sampleId)) {
|
|
||||||
filterTrace.addReason(sampleId, FaceRecognitionFilterReason.MANUAL_REJECTED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<MemberSourceEntity> relations = new ArrayList<>();
|
List<MemberSourceEntity> relations = new ArrayList<>();
|
||||||
List<MemberSourceEntity> videoRelations = memberRelationRepository.listSourceByFaceRelation(faceId, 1);
|
List<MemberSourceEntity> videoRelations = memberRelationRepository.listSourceByFaceRelation(faceId, 1);
|
||||||
if (videoRelations != null) {
|
if (videoRelations != null) {
|
||||||
@@ -1426,9 +1382,9 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<Long, EnumSet<FaceRecognitionFilterReason>> reasonMap = filterTrace.getFilteredReasonMap();
|
|
||||||
Map<Long, DeviceEntity> deviceCache = new HashMap<>();
|
Map<Long, DeviceEntity> deviceCache = new HashMap<>();
|
||||||
|
|
||||||
|
Set<Long> persistedAcceptedSet = new LinkedHashSet<>(persistedAcceptedIds);
|
||||||
List<Long> acceptedOrdered = new ArrayList<>();
|
List<Long> acceptedOrdered = new ArrayList<>();
|
||||||
for (Long sampleId : allSampleIds) {
|
for (Long sampleId : allSampleIds) {
|
||||||
if (persistedAcceptedSet.contains(sampleId)) {
|
if (persistedAcceptedSet.contains(sampleId)) {
|
||||||
@@ -1446,32 +1402,25 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
sampleId,
|
sampleId,
|
||||||
true,
|
true,
|
||||||
itemBySampleId.get(sampleId),
|
itemBySampleId.get(sampleId),
|
||||||
sampleEntityMap.get(sampleId),
|
|
||||||
sourceBySampleId.get(sampleId),
|
sourceBySampleId.get(sampleId),
|
||||||
relationBySampleId.get(sampleId),
|
deviceCache))
|
||||||
deviceCache,
|
|
||||||
Collections.emptyList()))
|
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
Set<Long> acceptedSet = new HashSet<>(acceptedOrdered);
|
Set<Long> acceptedSet = new LinkedHashSet<>(acceptedOrdered);
|
||||||
List<FaceRecognitionSampleVO> filteredSamples = new ArrayList<>();
|
List<FaceRecognitionSampleVO> filteredSamples = new ArrayList<>();
|
||||||
for (Long sampleId : allSampleIds) {
|
for (Long sampleId : allSampleIds) {
|
||||||
if (acceptedSet.contains(sampleId)) {
|
if (acceptedSet.contains(sampleId)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
EnumSet<FaceRecognitionFilterReason> reasons = reasonMap.get(sampleId);
|
FaceRecognitionSampleVO sampleVO = buildSampleVO(
|
||||||
List<FaceRecognitionFilterReason> reasonList = reasons == null
|
|
||||||
? Collections.emptyList()
|
|
||||||
: new ArrayList<>(reasons);
|
|
||||||
filteredSamples.add(buildSampleVO(
|
|
||||||
sampleId,
|
sampleId,
|
||||||
false,
|
false,
|
||||||
itemBySampleId.get(sampleId),
|
itemBySampleId.get(sampleId),
|
||||||
sampleEntityMap.get(sampleId),
|
|
||||||
sourceBySampleId.get(sampleId),
|
sourceBySampleId.get(sampleId),
|
||||||
relationBySampleId.get(sampleId),
|
deviceCache);
|
||||||
deviceCache,
|
if (sampleVO.getSourceId() != null) {
|
||||||
reasonList));
|
filteredSamples.add(sampleVO);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
detail.setAcceptedSamples(acceptedSamples);
|
detail.setAcceptedSamples(acceptedSamples);
|
||||||
@@ -1508,44 +1457,26 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
private FaceRecognitionSampleVO buildSampleVO(Long sampleId,
|
private FaceRecognitionSampleVO buildSampleVO(Long sampleId,
|
||||||
boolean accepted,
|
boolean accepted,
|
||||||
SearchFaceResultItem resultItem,
|
SearchFaceResultItem resultItem,
|
||||||
FaceSampleEntity sampleEntity,
|
|
||||||
SourceEntity sourceEntity,
|
SourceEntity sourceEntity,
|
||||||
MemberSourceEntity relation,
|
Map<Long, DeviceEntity> deviceCache) {
|
||||||
Map<Long, DeviceEntity> deviceCache,
|
|
||||||
List<FaceRecognitionFilterReason> reasons) {
|
|
||||||
FaceRecognitionSampleVO vo = new FaceRecognitionSampleVO();
|
FaceRecognitionSampleVO vo = new FaceRecognitionSampleVO();
|
||||||
vo.setSampleId(sampleId);
|
vo.setSampleId(sampleId);
|
||||||
vo.setAccepted(accepted);
|
vo.setAccepted(accepted);
|
||||||
if (resultItem != null) {
|
if (resultItem != null) {
|
||||||
vo.setScore(resultItem.getScore());
|
vo.setScore(resultItem.getScore());
|
||||||
}
|
}
|
||||||
if (sampleEntity != null) {
|
|
||||||
vo.setFaceUrl(sampleEntity.getFaceUrl());
|
|
||||||
vo.setDeviceId(sampleEntity.getDeviceId());
|
|
||||||
vo.setShotAt(sampleEntity.getCreateAt());
|
|
||||||
DeviceEntity device = getDeviceCached(sampleEntity.getDeviceId(), deviceCache);
|
|
||||||
if (device != null) {
|
|
||||||
vo.setDeviceName(device.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sourceEntity != null) {
|
if (sourceEntity != null) {
|
||||||
|
if (sourceEntity.getDeviceId() != null) {
|
||||||
|
vo.setDeviceId(sourceEntity.getDeviceId());
|
||||||
|
vo.setShotAt(sourceEntity.getCreateTime());
|
||||||
|
DeviceEntity device = getDeviceCached(sourceEntity.getDeviceId(), deviceCache);
|
||||||
|
if (device != null) {
|
||||||
|
vo.setDeviceName(device.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
vo.setSourceId(sourceEntity.getId());
|
vo.setSourceId(sourceEntity.getId());
|
||||||
vo.setSourceType(sourceEntity.getType());
|
|
||||||
vo.setSourceUrl(resolveSourceUrl(sourceEntity));
|
vo.setSourceUrl(resolveSourceUrl(sourceEntity));
|
||||||
}
|
}
|
||||||
if (relation != null) {
|
|
||||||
vo.setIsFree(relation.getIsFree());
|
|
||||||
vo.setIsBuy(relation.getIsBuy());
|
|
||||||
}
|
|
||||||
if (reasons != null && !reasons.isEmpty()) {
|
|
||||||
vo.setFilterReasons(new ArrayList<>(reasons));
|
|
||||||
vo.setFilterReasonTexts(reasons.stream()
|
|
||||||
.map(FaceRecognitionFilterReason::getDescription)
|
|
||||||
.collect(Collectors.toList()));
|
|
||||||
} else {
|
|
||||||
vo.setFilterReasons(Collections.emptyList());
|
|
||||||
vo.setFilterReasonTexts(Collections.emptyList());
|
|
||||||
}
|
|
||||||
return vo;
|
return vo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1565,15 +1496,12 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
if (sourceEntity == null) {
|
if (sourceEntity == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (!Strings.isBlank(sourceEntity.getUrl())) {
|
|
||||||
return sourceEntity.getUrl();
|
|
||||||
}
|
|
||||||
if (!Strings.isBlank(sourceEntity.getVideoUrl())) {
|
|
||||||
return sourceEntity.getVideoUrl();
|
|
||||||
}
|
|
||||||
if (!Strings.isBlank(sourceEntity.getThumbUrl())) {
|
if (!Strings.isBlank(sourceEntity.getThumbUrl())) {
|
||||||
return sourceEntity.getThumbUrl();
|
return sourceEntity.getThumbUrl();
|
||||||
}
|
}
|
||||||
|
if (!Strings.isBlank(sourceEntity.getUrl())) {
|
||||||
|
return sourceEntity.getUrl();
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user