From 473e7080a15a909e7ffc0ccb12a188d5046db08f Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Thu, 26 Dec 2024 15:32:41 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BA=BA=E8=84=B8=E8=AF=86=E5=88=AB=E6=97=A5?= =?UTF-8?q?=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ycwl/basic/constant/FaceConstant.java | 3 + .../controller/mobile/AppFaceController.java | 2 +- .../basic/mapper/FaceDetectLogMapper.java | 9 ++ .../faceDetectLog/entity/FaceDetectLog.java | 72 +++++++++++ .../faceDetectLog/resp/MatchLocalRecord.java | 11 ++ .../service/impl/pc/FaceServiceImpl.java | 61 +++++---- .../impl/task/TaskFaceServiceImpl.java | 121 ++++++++++++++++-- .../ycwl/basic/service/pc/FaceService.java | 2 +- .../basic/service/task/TaskFaceService.java | 1 + 9 files changed, 239 insertions(+), 43 deletions(-) create mode 100644 src/main/java/com/ycwl/basic/mapper/FaceDetectLogMapper.java create mode 100644 src/main/java/com/ycwl/basic/model/pc/faceDetectLog/entity/FaceDetectLog.java create mode 100644 src/main/java/com/ycwl/basic/model/pc/faceDetectLog/resp/MatchLocalRecord.java diff --git a/src/main/java/com/ycwl/basic/constant/FaceConstant.java b/src/main/java/com/ycwl/basic/constant/FaceConstant.java index 86e1d3b..2c6fdf0 100644 --- a/src/main/java/com/ycwl/basic/constant/FaceConstant.java +++ b/src/main/java/com/ycwl/basic/constant/FaceConstant.java @@ -2,4 +2,7 @@ package com.ycwl.basic.constant; public class FaceConstant { public static final String FACE_DB_NAME_PFX="face:db:"; + public static final String USER_FACE_DB_NAME="userFace"; + public static final String FACE_SAMPLE_URL_PFX="face:sample:url:"; + public static final String FACE_USER_URL_PFX="face:user:url:"; } diff --git a/src/main/java/com/ycwl/basic/controller/mobile/AppFaceController.java b/src/main/java/com/ycwl/basic/controller/mobile/AppFaceController.java index afebee9..da2d300 100644 --- a/src/main/java/com/ycwl/basic/controller/mobile/AppFaceController.java +++ b/src/main/java/com/ycwl/basic/controller/mobile/AppFaceController.java @@ -37,7 +37,7 @@ AppFaceController { @PostMapping("/faceUPload") public ApiResponse faceUPload(@RequestParam("file")MultipartFile file, @RequestParam("scenicId") Long scenicId) { - return faceService.faceUPload(file,scenicId); + return faceService.faceUpload(file,scenicId); } @ApiOperation("查询人脸照片信息") diff --git a/src/main/java/com/ycwl/basic/mapper/FaceDetectLogMapper.java b/src/main/java/com/ycwl/basic/mapper/FaceDetectLogMapper.java new file mode 100644 index 0000000..697ce53 --- /dev/null +++ b/src/main/java/com/ycwl/basic/mapper/FaceDetectLogMapper.java @@ -0,0 +1,9 @@ +package com.ycwl.basic.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ycwl.basic.model.pc.faceDetectLog.entity.FaceDetectLog; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface FaceDetectLogMapper extends BaseMapper { +} diff --git a/src/main/java/com/ycwl/basic/model/pc/faceDetectLog/entity/FaceDetectLog.java b/src/main/java/com/ycwl/basic/model/pc/faceDetectLog/entity/FaceDetectLog.java new file mode 100644 index 0000000..4aada80 --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/pc/faceDetectLog/entity/FaceDetectLog.java @@ -0,0 +1,72 @@ +package com.ycwl.basic.model.pc.faceDetectLog.entity; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.aliyuncs.facebody.model.v20191230.SearchFaceRequest; +import com.aliyuncs.facebody.model.v20191230.SearchFaceResponse; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.ycwl.basic.model.pc.faceDetectLog.resp.MatchLocalRecord; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +@Data +@TableName("face_detect_log") +public class FaceDetectLog { + @TableId(type = IdType.AUTO) + private Integer id; + + private Date createTime; + + private String reason; + + private String faceUrl; + + private String dbName; + + private String matchRawResult; + + private String matchLocalRecord; + + public static FaceDetectLog quickCreate(String reason) { + FaceDetectLog log = new FaceDetectLog(); + log.reason = reason; + return log; + } + public static FaceDetectLog quickCreate(String reason, SearchFaceRequest request) { + FaceDetectLog log = new FaceDetectLog(); + log.reason = reason; + return log.fillRequest(request); + } + + public FaceDetectLog fillRequest(SearchFaceRequest request) { + this.dbName = request.getDbName(); + this.faceUrl = request.getImageUrl(); + this.createTime = new Date(); + return this; + } + + public FaceDetectLog fillResponse(SearchFaceResponse response) { + this.matchRawResult = JSONObject.toJSONString(response.getData()); + return this; + } + + public List matchLocalRecord() { + if (matchLocalRecord == null) { + return null; + } + return JSONArray.parseArray(matchLocalRecord, MatchLocalRecord.class); + } + + public void matchLocalRecord(List matchLocalRecord) { + if (matchLocalRecord == null) { + this.matchLocalRecord = null; + } else { + this.matchLocalRecord = JSONArray.toJSONString(matchLocalRecord); + } + } + +} diff --git a/src/main/java/com/ycwl/basic/model/pc/faceDetectLog/resp/MatchLocalRecord.java b/src/main/java/com/ycwl/basic/model/pc/faceDetectLog/resp/MatchLocalRecord.java new file mode 100644 index 0000000..d5f2633 --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/pc/faceDetectLog/resp/MatchLocalRecord.java @@ -0,0 +1,11 @@ +package com.ycwl.basic.model.pc.faceDetectLog.resp; + +import lombok.Data; + +@Data +public class MatchLocalRecord { + private Long faceSampleId; + private String faceUrl; + private Float confidence; + private String idStr; +} diff --git a/src/main/java/com/ycwl/basic/service/impl/pc/FaceServiceImpl.java b/src/main/java/com/ycwl/basic/service/impl/pc/FaceServiceImpl.java index 01653a7..1e0df48 100644 --- a/src/main/java/com/ycwl/basic/service/impl/pc/FaceServiceImpl.java +++ b/src/main/java/com/ycwl/basic/service/impl/pc/FaceServiceImpl.java @@ -33,6 +33,8 @@ import java.util.List; import java.util.Objects; import java.util.stream.Collectors; +import static com.ycwl.basic.constant.FaceConstant.USER_FACE_DB_NAME; + /** * @Author:longbinbin * @Date:2024/12/2 16:39 @@ -51,6 +53,7 @@ public class FaceServiceImpl implements FaceService { @Value("${face.score}") private float faceScore; + private float strictScore = 90F; @Autowired private TaskService taskTaskService; @Autowired @@ -113,7 +116,7 @@ public class FaceServiceImpl implements FaceService { @Override // @Transactional(rollbackFor = Exception.class) - public ApiResponse faceUPload(MultipartFile file,Long scenicId) { + public ApiResponse faceUpload(MultipartFile file, Long scenicId) { //获取用户id JwtInfo worker = JwtTokenUtil.getWorker(); Long userId = worker.getUserId(); @@ -121,55 +124,57 @@ public class FaceServiceImpl implements FaceService { //1、上传人脸照片 String faceUrl = uploadFileALiOss(file, userId); - SearchFaceRespVo searchFaceRespVo = faceService.searchFace(scenicId, faceUrl); - if (searchFaceRespVo == null) { + SearchFaceRespVo scenicDbSearchResult = faceService.searchFace(scenicId, faceUrl); + if (scenicDbSearchResult == null) { ossUtil.deleteFileByUrl(faceUrl); throw new BaseException("人脸照片校验失败,请重新上传"); } - float score = searchFaceRespVo.getScore(); + float score = scenicDbSearchResult.getScore(); if (score redisTemplate; + @Autowired + private FaceDetectLogMapper logMapper; private IAcsClient getClient() { DefaultProfile profile = DefaultProfile.getProfile( @@ -69,7 +76,7 @@ public class TaskFaceServiceImpl implements TaskFaceService { @Override public SearchFaceRespVo searchFace(Long faceId) { FaceRespVO faceRespVO = faceMapper.getById(faceId); - SearchFaceRespVo respVo = searchFace(faceRespVO.getScenicId(), faceRespVO.getFaceUrl()); + SearchFaceRespVo respVo = searchFace(faceRespVO.getScenicId().toString(), faceRespVO.getFaceUrl()); if (respVo != null) { FaceEntity faceEntity = new FaceEntity(); faceEntity.setId(faceId); @@ -96,8 +103,10 @@ public class TaskFaceServiceImpl implements TaskFaceService { request.setImageUrl(faceUrl); request.setLimit(100); request.setQualityScoreThreshold(80F); + FaceDetectLog log = FaceDetectLog.quickCreate("预留字段", request); try { SearchFaceResponse response = client.getAcsResponse(request); + log.fillResponse(response); List matchList = response.getData().getMatchList(); if (matchList.isEmpty()) { return null; @@ -110,16 +119,33 @@ public class TaskFaceServiceImpl implements TaskFaceService { } List faceItems = matchList.get(0).getFaceItems().stream() .filter(faceItemsItem -> faceItemsItem.getConfidence() > 50).collect(Collectors.toList()); - List faceSampleIds = faceItems.stream() - .map(SearchFaceResponse.Data.MatchListItem.FaceItemsItem::getExtraData) - .map(Long::parseLong) + List records = faceItems.stream() + .map(item -> { + MatchLocalRecord record = new MatchLocalRecord(); + record.setIdStr(item.getExtraData()); + record.setFaceSampleId(Long.parseLong(item.getExtraData())); + if (StringUtils.isNumeric(item.getDbName())) { + record.setFaceUrl(getFaceSampleUrl(record.getFaceSampleId())); + } else { + record.setFaceUrl(getFaceUrl(record.getFaceSampleId())); + } + record.setConfidence(item.getConfidence()); + return record; + }) + .collect(Collectors.toList()); + log.matchLocalRecord(records); + List faceSampleIds = records.stream() + .map(MatchLocalRecord::getFaceSampleId) .collect(Collectors.toList()); respVo.setFirstMatchRate(matchList.get(0).getFaceItems().get(0).getConfidence()); respVo.setSampleListIds(faceSampleIds); return respVo; } catch (Exception e) { - log.error("人脸搜索失败:{}", e.getMessage()); + log.setMatchRawResult("识别错误,错误为:["+e.getLocalizedMessage()+"]"); + e.printStackTrace(); throw new BaseException(e.getMessage()); + } finally { + logMapper.insert(log); } } @@ -133,6 +159,7 @@ public class TaskFaceServiceImpl implements TaskFaceService { faceSampleEntity.setScore(respVo.getScore()); faceSampleEntity.setUpdateAt(new Date()); faceSampleMapper.update(faceSampleEntity); + addFaceSampleUrlCache(faceSampleId, faceSampleRespVO.getFaceUrl()); return respVo; } @@ -250,16 +277,31 @@ public class TaskFaceServiceImpl implements TaskFaceService { return; } try { - ListFaceDbsRequest request = new ListFaceDbsRequest(); - request.setLimit(Long.MAX_VALUE); + long offset = 0; + List dbList = new ArrayList<>(); IAcsClient client = getClient(); - ListFaceDbsResponse response = client.getAcsResponse(request); - if (response.getData().getDbList() == null) { - return; + while (true) { + ListFaceDbsRequest request = new ListFaceDbsRequest(); + request.setLimit(200L); + request.setOffset(offset); + ListFaceDbsResponse response = client.getAcsResponse(request); + List list = response.getData().getDbList(); + if (list == null || list.isEmpty()) { + break; + } else { + dbList.addAll(list); + offset += list.size(); + } + } + boolean mismatch; + if (dbList.isEmpty()) { + clearFaceDBCache(); + mismatch = true; + } else { + mismatch = dbList.stream().peek(item -> { + redisTemplate.opsForValue().set(FaceConstant.FACE_DB_NAME_PFX + dbName, "1"); + }).noneMatch(db -> db.getName().equals(dbName)); } - boolean mismatch = response.getData().getDbList().stream().peek(item -> { - redisTemplate.opsForValue().set(FaceConstant.FACE_DB_NAME_PFX + dbName, "1"); - }).noneMatch(db -> db.getName().equals(dbName)); if (mismatch) { createFaceDB(dbName); } @@ -293,4 +335,57 @@ public class TaskFaceServiceImpl implements TaskFaceService { String entityId = entity.getDeviceId().toString() + "_" + sdf.format(entity.getCreateAt()); return entityId; } + + public String getFaceUrl(Long faceId) { + if (faceId == null) { + return null; + } + if (redisTemplate.hasKey(FaceConstant.FACE_USER_URL_PFX + faceId)) { + return redisTemplate.opsForValue().get(FaceConstant.FACE_USER_URL_PFX + faceId); + } + FaceRespVO faceRespVO = faceMapper.getById(faceId); + if (faceRespVO == null) { + return null; + } + String faceUrl = faceRespVO.getFaceUrl(); + if (StringUtils.isNotBlank(faceUrl)) { + addFaceUrlCache(faceId, faceUrl); + } + return faceUrl; + } + public void addFaceUrlCache(Long faceId, String faceUrl) { + if (faceId == null) { + return; + } + if (StringUtils.isBlank(faceUrl)) { + return; + } + redisTemplate.opsForValue().set(FaceConstant.FACE_USER_URL_PFX + faceId, faceUrl, 3, TimeUnit.DAYS); + } + public String getFaceSampleUrl(Long faceSampleId) { + if (faceSampleId == null) { + return null; + } + if (redisTemplate.hasKey(FaceConstant.FACE_SAMPLE_URL_PFX + faceSampleId)) { + return redisTemplate.opsForValue().get(FaceConstant.FACE_SAMPLE_URL_PFX + faceSampleId); + } + FaceSampleRespVO faceSampleRespVO = faceSampleMapper.getById(faceSampleId); + if (faceSampleRespVO == null) { + return null; + } + String faceUrl = faceSampleRespVO.getFaceUrl(); + if (StringUtils.isNotBlank(faceUrl)) { + addFaceSampleUrlCache(faceSampleId, faceUrl); + } + return faceUrl; + } + public void addFaceSampleUrlCache(Long faceSampleId, String faceUrl) { + if (faceSampleId == null) { + return; + } + if (StringUtils.isBlank(faceUrl)) { + return; + } + redisTemplate.opsForValue().set(FaceConstant.FACE_SAMPLE_URL_PFX + faceSampleId, faceUrl, 3, TimeUnit.DAYS); + } } diff --git a/src/main/java/com/ycwl/basic/service/pc/FaceService.java b/src/main/java/com/ycwl/basic/service/pc/FaceService.java index f1edb52..d0e58ae 100644 --- a/src/main/java/com/ycwl/basic/service/pc/FaceService.java +++ b/src/main/java/com/ycwl/basic/service/pc/FaceService.java @@ -22,7 +22,7 @@ public interface FaceService { ApiResponse deleteByIds(List ids); ApiResponse update(FaceEntity face); - ApiResponse faceUPload(MultipartFile file,Long scrnicId); + ApiResponse faceUpload(MultipartFile file, Long scrnicId); ApiResponse getFaceByMemberId(Long memberId); } diff --git a/src/main/java/com/ycwl/basic/service/task/TaskFaceService.java b/src/main/java/com/ycwl/basic/service/task/TaskFaceService.java index c0d0f7a..c753a1f 100644 --- a/src/main/java/com/ycwl/basic/service/task/TaskFaceService.java +++ b/src/main/java/com/ycwl/basic/service/task/TaskFaceService.java @@ -8,6 +8,7 @@ public interface TaskFaceService { SearchFaceRespVo searchFace(Long faceId); SearchFaceRespVo searchFace(Long scenicId, String faceUrl); + SearchFaceRespVo searchFace(String dbName, String faceUrl); AddFaceSampleRespVo addFaceSample(Long faceSampleId);