You've already forked FrameTour-BE
2
This commit is contained in:
@@ -0,0 +1,214 @@
|
|||||||
|
package com.ycwl.basic.service.pc.helper;
|
||||||
|
|
||||||
|
import com.ycwl.basic.repository.ScenicRepository;
|
||||||
|
import com.ycwl.basic.integration.common.manager.ScenicConfigManager;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 景区配置门面类
|
||||||
|
* 提供类型安全的配置访问方法,避免配置键的字符串硬编码
|
||||||
|
* 集中管理所有景区配置项的访问逻辑
|
||||||
|
*
|
||||||
|
* @author Claude
|
||||||
|
* @since 2025-10-31
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class ScenicConfigFacade {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ScenicRepository scenicRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取景区配置管理器
|
||||||
|
*/
|
||||||
|
private ScenicConfigManager getConfig(Long scenicId) {
|
||||||
|
return scenicRepository.getScenicConfigManager(scenicId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 人脸识别相关配置 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否优先手动选择人脸
|
||||||
|
* 如果为 true,则不自动创建任务
|
||||||
|
*
|
||||||
|
* @param scenicId 景区ID
|
||||||
|
* @return true-需要手动选择,false-自动创建任务
|
||||||
|
*/
|
||||||
|
public boolean isFaceSelectFirst(Long scenicId) {
|
||||||
|
ScenicConfigManager config = getConfig(scenicId);
|
||||||
|
if (config == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Boolean value = config.getBoolean("face_select_first");
|
||||||
|
return Boolean.TRUE.equals(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取自定义人脸匹配的最大次数
|
||||||
|
* 用于限制用户手动重新匹配的次数
|
||||||
|
*
|
||||||
|
* @param scenicId 景区ID
|
||||||
|
* @return 最大匹配次数,null 或 0 表示不限制
|
||||||
|
*/
|
||||||
|
public Integer getFaceSelectMaxCount(Long scenicId) {
|
||||||
|
ScenicConfigManager config = getConfig(scenicId);
|
||||||
|
if (config == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return config.getInteger("face_select_max_count");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取人脸分数低阈值
|
||||||
|
* 低于此分数的匹配结果会被标记为低置信度
|
||||||
|
*
|
||||||
|
* @param scenicId 景区ID
|
||||||
|
* @return 分数阈值,默认 30.0
|
||||||
|
*/
|
||||||
|
public Float getFaceScoreLowThreshold(Long scenicId) {
|
||||||
|
ScenicConfigManager config = getConfig(scenicId);
|
||||||
|
if (config == null) {
|
||||||
|
return 30.0F;
|
||||||
|
}
|
||||||
|
return config.getFloat("face_score_low_threshold", 30.0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取人脸检测辅助阈值
|
||||||
|
* 当匹配结果数量少于此阈值时,会触发补救逻辑
|
||||||
|
*
|
||||||
|
* @param scenicId 景区ID
|
||||||
|
* @return 辅助阈值,默认 0(不启用)
|
||||||
|
*/
|
||||||
|
public Integer getFaceDetectHelperThreshold(Long scenicId) {
|
||||||
|
ScenicConfigManager config = getConfig(scenicId);
|
||||||
|
if (config == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return config.getInteger("face_detect_helper_threshold", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取人脸选择后处理模式
|
||||||
|
* 0-并集模式,1-交集模式
|
||||||
|
*
|
||||||
|
* @param scenicId 景区ID
|
||||||
|
* @return 后处理模式,默认 0
|
||||||
|
*/
|
||||||
|
public Integer getFaceSelectPostMode(Long scenicId) {
|
||||||
|
ScenicConfigManager config = getConfig(scenicId);
|
||||||
|
if (config == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return config.getInteger("face_select_post_mode", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取重新匹配模式
|
||||||
|
* 用于决定在什么条件下需要重新进行人脸匹配
|
||||||
|
*
|
||||||
|
* @param scenicId 景区ID
|
||||||
|
* @return 匹配模式,默认 0
|
||||||
|
*/
|
||||||
|
public Integer getRematchMode(Long scenicId) {
|
||||||
|
ScenicConfigManager config = getConfig(scenicId);
|
||||||
|
if (config == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return config.getInteger("re_match_mode", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 源文件相关配置 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否禁用源图片功能
|
||||||
|
*
|
||||||
|
* @param scenicId 景区ID
|
||||||
|
* @return true-禁用,false-启用
|
||||||
|
*/
|
||||||
|
public boolean isDisableSourceImage(Long scenicId) {
|
||||||
|
ScenicConfigManager config = getConfig(scenicId);
|
||||||
|
if (config == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Boolean value = config.getBoolean("disable_source_image");
|
||||||
|
return Boolean.TRUE.equals(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否禁用源视频功能
|
||||||
|
*
|
||||||
|
* @param scenicId 景区ID
|
||||||
|
* @return true-禁用,false-启用
|
||||||
|
*/
|
||||||
|
public boolean isDisableSourceVideo(Long scenicId) {
|
||||||
|
ScenicConfigManager config = getConfig(scenicId);
|
||||||
|
if (config == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Boolean value = config.getBoolean("disable_source_video");
|
||||||
|
return Boolean.TRUE.equals(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取免费照片数量
|
||||||
|
* 新用户首次识别时赠送的免费照片数量
|
||||||
|
*
|
||||||
|
* @param scenicId 景区ID
|
||||||
|
* @return 免费照片数量,null 或 0 表示不赠送
|
||||||
|
*/
|
||||||
|
public Integer getPhotoFreeNum(Long scenicId) {
|
||||||
|
ScenicConfigManager config = getConfig(scenicId);
|
||||||
|
if (config == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return config.getInteger("photo_free_num");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 游玩时间相关配置 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取最大游玩时间(分钟)
|
||||||
|
* 用于判断照片是否在合理的游玩时间范围内
|
||||||
|
*
|
||||||
|
* @param scenicId 景区ID
|
||||||
|
* @return 最大游玩时间(分钟),null 表示不限制
|
||||||
|
*/
|
||||||
|
public Integer getTourTime(Long scenicId) {
|
||||||
|
ScenicConfigManager config = getConfig(scenicId);
|
||||||
|
if (config == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return config.getInteger("tour_time");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取最小游玩时间(分钟)
|
||||||
|
* 用于判断照片是否在合理的游玩时间范围内
|
||||||
|
*
|
||||||
|
* @param scenicId 景区ID
|
||||||
|
* @return 最小游玩时间(分钟),null 表示不限制
|
||||||
|
*/
|
||||||
|
public Integer getTourMinTime(Long scenicId) {
|
||||||
|
ScenicConfigManager config = getConfig(scenicId);
|
||||||
|
if (config == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return config.getInteger("tour_min_time");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否配置了游玩时间限制
|
||||||
|
*
|
||||||
|
* @param scenicId 景区ID
|
||||||
|
* @return true-已配置,false-未配置
|
||||||
|
*/
|
||||||
|
public boolean hasTourTimeConfig(Long scenicId) {
|
||||||
|
Integer maxTime = getTourTime(scenicId);
|
||||||
|
Integer minTime = getTourMinTime(scenicId);
|
||||||
|
return maxTime != null && minTime != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,11 +6,9 @@ import com.github.pagehelper.PageInfo;
|
|||||||
import com.ycwl.basic.biz.OrderBiz;
|
import com.ycwl.basic.biz.OrderBiz;
|
||||||
import com.ycwl.basic.biz.TemplateBiz;
|
import com.ycwl.basic.biz.TemplateBiz;
|
||||||
import com.ycwl.basic.constant.BaseContextHandler;
|
import com.ycwl.basic.constant.BaseContextHandler;
|
||||||
import com.ycwl.basic.enums.StatisticEnum;
|
|
||||||
import com.ycwl.basic.exception.BaseException;
|
import com.ycwl.basic.exception.BaseException;
|
||||||
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
|
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
|
||||||
import com.ycwl.basic.facebody.entity.SearchFaceResultItem;
|
import com.ycwl.basic.facebody.entity.SearchFaceResultItem;
|
||||||
import com.ycwl.basic.integration.common.manager.DeviceConfigManager;
|
|
||||||
import com.ycwl.basic.mapper.FaceSampleMapper;
|
import com.ycwl.basic.mapper.FaceSampleMapper;
|
||||||
import com.ycwl.basic.mapper.ProjectMapper;
|
import com.ycwl.basic.mapper.ProjectMapper;
|
||||||
import com.ycwl.basic.mapper.SourceMapper;
|
import com.ycwl.basic.mapper.SourceMapper;
|
||||||
@@ -24,7 +22,6 @@ import com.ycwl.basic.model.mobile.face.FaceStatusResp;
|
|||||||
import com.ycwl.basic.model.mobile.goods.VideoTaskStatusVO;
|
import com.ycwl.basic.model.mobile.goods.VideoTaskStatusVO;
|
||||||
import com.ycwl.basic.model.mobile.order.IsBuyRespVO;
|
import com.ycwl.basic.model.mobile.order.IsBuyRespVO;
|
||||||
import com.ycwl.basic.model.mobile.scenic.content.ContentPageVO;
|
import com.ycwl.basic.model.mobile.scenic.content.ContentPageVO;
|
||||||
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.mobile.face.FaceRecognitionUpdateReq;
|
import com.ycwl.basic.model.mobile.face.FaceRecognitionUpdateReq;
|
||||||
@@ -58,8 +55,10 @@ import com.ycwl.basic.repository.VideoTaskRepository;
|
|||||||
import com.ycwl.basic.service.mobile.GoodsService;
|
import com.ycwl.basic.service.mobile.GoodsService;
|
||||||
import com.ycwl.basic.service.pc.FaceService;
|
import com.ycwl.basic.service.pc.FaceService;
|
||||||
import com.ycwl.basic.service.pc.ScenicService;
|
import com.ycwl.basic.service.pc.ScenicService;
|
||||||
|
import com.ycwl.basic.constant.SourceType;
|
||||||
import com.ycwl.basic.service.pc.helper.FaceMetricsRecorder;
|
import com.ycwl.basic.service.pc.helper.FaceMetricsRecorder;
|
||||||
import com.ycwl.basic.service.pc.helper.SearchResultMerger;
|
import com.ycwl.basic.service.pc.helper.SearchResultMerger;
|
||||||
|
import com.ycwl.basic.service.pc.helper.ScenicConfigFacade;
|
||||||
import com.ycwl.basic.service.pc.processor.BuyStatusProcessor;
|
import com.ycwl.basic.service.pc.processor.BuyStatusProcessor;
|
||||||
import com.ycwl.basic.service.pc.processor.FaceRecoveryStrategy;
|
import com.ycwl.basic.service.pc.processor.FaceRecoveryStrategy;
|
||||||
import com.ycwl.basic.service.pc.processor.SourceRelationProcessor;
|
import com.ycwl.basic.service.pc.processor.SourceRelationProcessor;
|
||||||
@@ -73,12 +72,10 @@ import com.ycwl.basic.storage.StorageFactory;
|
|||||||
import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||||||
import com.ycwl.basic.storage.enums.StorageAcl;
|
import com.ycwl.basic.storage.enums.StorageAcl;
|
||||||
import com.ycwl.basic.storage.utils.StorageUtil;
|
import com.ycwl.basic.storage.utils.StorageUtil;
|
||||||
import com.ycwl.basic.task.VideoPieceGetter;
|
|
||||||
import com.ycwl.basic.utils.*;
|
import com.ycwl.basic.utils.*;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.logging.log4j.util.Strings;
|
import org.apache.logging.log4j.util.Strings;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
@@ -86,10 +83,8 @@ import java.io.File;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -98,14 +93,9 @@ import java.util.Objects;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import static com.ycwl.basic.constant.FaceConstant.FACE_CUSTOM_MATCH_COUNT_PFX;
|
|
||||||
import static com.ycwl.basic.constant.FaceConstant.FACE_LOW_THRESHOLD_PFX;
|
|
||||||
import static com.ycwl.basic.constant.FaceConstant.FACE_RECOGNITION_COUNT_PFX;
|
|
||||||
import static com.ycwl.basic.constant.FaceConstant.USER_FACE_DB_NAME;
|
import static com.ycwl.basic.constant.FaceConstant.USER_FACE_DB_NAME;
|
||||||
import static com.ycwl.basic.constant.StorageConstant.USER_FACE;
|
import static com.ycwl.basic.constant.StorageConstant.USER_FACE;
|
||||||
|
|
||||||
@@ -138,8 +128,6 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ScenicService scenicService;
|
private ScenicService scenicService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private TemplateMapper templateMapper;
|
|
||||||
@Autowired
|
|
||||||
private VideoRepository videoRepository;
|
private VideoRepository videoRepository;
|
||||||
@Autowired
|
@Autowired
|
||||||
private VideoTaskRepository videoTaskRepository;
|
private VideoTaskRepository videoTaskRepository;
|
||||||
@@ -150,8 +138,6 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private OrderMapper orderMapper;
|
private OrderMapper orderMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
private RedisTemplate<String, String> redisTemplate;
|
|
||||||
@Autowired
|
|
||||||
private FaceSampleMapper faceSampleMapper;
|
private FaceSampleMapper faceSampleMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
private GoodsService goodsService;
|
private GoodsService goodsService;
|
||||||
@@ -169,6 +155,8 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
private SearchResultMerger resultMerger;
|
private SearchResultMerger resultMerger;
|
||||||
@Autowired
|
@Autowired
|
||||||
private RematchStrategyFactory rematchStrategyFactory;
|
private RematchStrategyFactory rematchStrategyFactory;
|
||||||
|
@Autowired
|
||||||
|
private ScenicConfigFacade scenicConfigFacade;
|
||||||
|
|
||||||
// 第二阶段的处理器
|
// 第二阶段的处理器
|
||||||
@Autowired
|
@Autowired
|
||||||
@@ -374,12 +362,12 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
|
|
||||||
if (!memberSourceEntityList.isEmpty()) {
|
if (!memberSourceEntityList.isEmpty()) {
|
||||||
// 5. 业务逻辑处理:免费逻辑、购买状态、任务创建
|
// 5. 业务逻辑处理:免费逻辑、购买状态、任务创建
|
||||||
List<Long> freeSourceIds = sourceRelationProcessor.processFreeSourceLogic(memberSourceEntityList, scenicConfig, isNew);
|
List<Long> freeSourceIds = sourceRelationProcessor.processFreeSourceLogic(memberSourceEntityList, face.getScenicId(), isNew);
|
||||||
buyStatusProcessor.processBuyStatus(memberSourceEntityList, freeSourceIds, face.getMemberId(),
|
buyStatusProcessor.processBuyStatus(memberSourceEntityList, freeSourceIds, face.getMemberId(),
|
||||||
face.getScenicId(), faceId);
|
face.getScenicId(), faceId);
|
||||||
|
|
||||||
// 处理视频重切逻辑
|
// 处理视频重切逻辑
|
||||||
videoRecreationHandler.handleVideoRecreation(scenicConfig, memberSourceEntityList, faceId,
|
videoRecreationHandler.handleVideoRecreation(face.getScenicId(), memberSourceEntityList, faceId,
|
||||||
face.getMemberId(), sampleListIds, isNew);
|
face.getMemberId(), sampleListIds, isNew);
|
||||||
|
|
||||||
// 过滤已存在的关联关系和无效的source引用,防止数据不一致
|
// 过滤已存在的关联关系和无效的source引用,防止数据不一致
|
||||||
@@ -395,8 +383,7 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
memberRelationRepository.clearSCacheByFace(faceId);
|
memberRelationRepository.clearSCacheByFace(faceId);
|
||||||
|
|
||||||
// 检查景区配置中的 face_select_first,如果为 true 则不自动创建任务
|
// 检查景区配置中的 face_select_first,如果为 true 则不自动创建任务
|
||||||
Boolean faceSelectFirst = scenicConfig != null ? scenicConfig.getBoolean("face_select_first") : null;
|
if (!scenicConfigFacade.isFaceSelectFirst(face.getScenicId())) {
|
||||||
if (!Boolean.TRUE.equals(faceSelectFirst)) {
|
|
||||||
taskTaskService.autoCreateTaskByFaceId(faceId);
|
taskTaskService.autoCreateTaskByFaceId(faceId);
|
||||||
} else {
|
} else {
|
||||||
log.debug("景区配置 face_select_first=true,跳过自动创建任务:faceId={}", faceId);
|
log.debug("景区配置 face_select_first=true,跳过自动创建任务:faceId={}", faceId);
|
||||||
@@ -573,8 +560,8 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
sourceVideoContent.setGroup("直出原片");
|
sourceVideoContent.setGroup("直出原片");
|
||||||
sourceImageContent.setGroup("直出原片");
|
sourceImageContent.setGroup("直出原片");
|
||||||
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(face.getScenicId());
|
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(face.getScenicId());
|
||||||
if (!Boolean.TRUE.equals(scenicConfig.getBoolean("disable_source_image"))) {
|
if (!scenicConfigFacade.isDisableSourceImage(face.getScenicId())) {
|
||||||
IsBuyRespVO isBuyRespVO = orderBiz.isBuy(userId, face.getScenicId(), 2, faceId);
|
IsBuyRespVO isBuyRespVO = orderBiz.isBuy(userId, face.getScenicId(), SourceType.IMAGE.getCode(), faceId);
|
||||||
sourceImageContent.setSourceType(isBuyRespVO.getGoodsType());
|
sourceImageContent.setSourceType(isBuyRespVO.getGoodsType());
|
||||||
sourceImageContent.setContentId(isBuyRespVO.getGoodsId());
|
sourceImageContent.setContentId(isBuyRespVO.getGoodsId());
|
||||||
if (isBuyRespVO.isBuy()) {
|
if (isBuyRespVO.isBuy()) {
|
||||||
@@ -592,8 +579,8 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
sourceImageContent.setFreeCount((int) freeCount);
|
sourceImageContent.setFreeCount((int) freeCount);
|
||||||
contentList.add(sourceImageContent);
|
contentList.add(sourceImageContent);
|
||||||
}
|
}
|
||||||
if (!Boolean.TRUE.equals(scenicConfig.getBoolean("disable_source_video"))) {
|
if (!scenicConfigFacade.isDisableSourceVideo(face.getScenicId())) {
|
||||||
IsBuyRespVO isBuyRespVO = orderBiz.isBuy(userId, face.getScenicId(), 1, faceId);
|
IsBuyRespVO isBuyRespVO = orderBiz.isBuy(userId, face.getScenicId(), SourceType.VIDEO.getCode(), faceId);
|
||||||
sourceVideoContent.setSourceType(isBuyRespVO.getGoodsType());
|
sourceVideoContent.setSourceType(isBuyRespVO.getGoodsType());
|
||||||
sourceVideoContent.setContentId(isBuyRespVO.getGoodsId());
|
sourceVideoContent.setContentId(isBuyRespVO.getGoodsId());
|
||||||
if (isBuyRespVO.isBuy()) {
|
if (isBuyRespVO.isBuy()) {
|
||||||
@@ -764,15 +751,15 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
long customMatchCount = metricsRecorder.getCustomMatchCount(faceId);
|
long customMatchCount = metricsRecorder.getCustomMatchCount(faceId);
|
||||||
boolean hasLowThreshold = metricsRecorder.hasLowThreshold(faceId);
|
boolean hasLowThreshold = metricsRecorder.hasLowThreshold(faceId);
|
||||||
|
|
||||||
Integer faceSelectMaxCount = scenicConfig.getInteger("face_select_max_count");
|
Integer faceSelectMaxCount = scenicConfigFacade.getFaceSelectMaxCount(face.getScenicId());
|
||||||
if (faceSelectMaxCount != null && faceSelectMaxCount > 0 && customMatchCount > faceSelectMaxCount) {
|
if (faceSelectMaxCount != null && faceSelectMaxCount > 0 && customMatchCount > faceSelectMaxCount) {
|
||||||
log.debug("自定义人脸匹配次数超过限制:faceId={}, customMatchCount={}, limit={}",
|
log.debug("自定义人脸匹配次数超过限制:faceId={}, customMatchCount={}, limit={}",
|
||||||
faceId, customMatchCount, faceSelectMaxCount);
|
faceId, customMatchCount, faceSelectMaxCount);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Integer maxTourTime = scenicConfig.getInteger("tour_time");
|
Integer maxTourTime = scenicConfigFacade.getTourTime(face.getScenicId());
|
||||||
Integer minTourTime = scenicConfig.getInteger("tour_min_time");
|
Integer minTourTime = scenicConfigFacade.getTourMinTime(face.getScenicId());
|
||||||
boolean tourMatch = false;
|
boolean tourMatch = false;
|
||||||
if (maxTourTime != null && minTourTime != null) {
|
if (maxTourTime != null && minTourTime != null) {
|
||||||
if ((new Date().getTime()) - face.getCreateAt().getTime() < maxTourTime * 60 * 1000
|
if ((new Date().getTime()) - face.getCreateAt().getTime() < maxTourTime * 60 * 1000
|
||||||
@@ -811,7 +798,7 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 使用策略模式替换switch语句
|
// 使用策略模式替换switch语句
|
||||||
Integer mode = scenicConfig.getInteger("re_match_mode", 0);
|
Integer mode = scenicConfigFacade.getRematchMode(face.getScenicId());
|
||||||
RematchContext context = RematchContext.builder()
|
RematchContext context = RematchContext.builder()
|
||||||
.recognitionCount(recognitionCount)
|
.recognitionCount(recognitionCount)
|
||||||
.hasLowThreshold(hasLowThreshold)
|
.hasLowThreshold(hasLowThreshold)
|
||||||
@@ -839,7 +826,7 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
if (scenicConfig == null) {
|
if (scenicConfig == null) {
|
||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
Float lowThreshold = scenicConfig.getFloat("face_score_low_threshold", 30.0F);
|
Float lowThreshold = scenicConfigFacade.getFaceScoreLowThreshold(face.getScenicId());
|
||||||
List<SearchFaceResultItem> resultItems = JacksonUtil.fromJsonToList(matchResult, SearchFaceResultItem.class);
|
List<SearchFaceResultItem> resultItems = JacksonUtil.fromJsonToList(matchResult, SearchFaceResultItem.class);
|
||||||
if (resultItems == null || resultItems.isEmpty()) {
|
if (resultItems == null || resultItems.isEmpty()) {
|
||||||
return List.of();
|
return List.of();
|
||||||
@@ -893,7 +880,7 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取face_select_post_mode配置,默认为0(并集)
|
// 获取face_select_post_mode配置,默认为0(并集)
|
||||||
Integer faceSelectPostMode = scenicConfig != null ? scenicConfig.getInteger("face_select_post_mode", 0) : 0;
|
Integer faceSelectPostMode = scenicConfigFacade.getFaceSelectPostMode(face.getScenicId());
|
||||||
log.debug("face_select_post_mode配置值: {}", faceSelectPostMode);
|
log.debug("face_select_post_mode配置值: {}", faceSelectPostMode);
|
||||||
|
|
||||||
SearchFaceRespVo mergedResult;
|
SearchFaceRespVo mergedResult;
|
||||||
@@ -958,11 +945,11 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
List<MemberSourceEntity> memberSourceEntityList = sourceRelationProcessor.processMemberSources(sampleListIds, face);
|
List<MemberSourceEntity> memberSourceEntityList = sourceRelationProcessor.processMemberSources(sampleListIds, face);
|
||||||
|
|
||||||
if (!memberSourceEntityList.isEmpty()) {
|
if (!memberSourceEntityList.isEmpty()) {
|
||||||
List<Long> freeSourceIds = sourceRelationProcessor.processFreeSourceLogic(memberSourceEntityList, scenicConfig, false);
|
List<Long> freeSourceIds = sourceRelationProcessor.processFreeSourceLogic(memberSourceEntityList, face.getScenicId(), false);
|
||||||
buyStatusProcessor.processBuyStatus(memberSourceEntityList, freeSourceIds, face.getMemberId(),
|
buyStatusProcessor.processBuyStatus(memberSourceEntityList, freeSourceIds, face.getMemberId(),
|
||||||
face.getScenicId(), faceId);
|
face.getScenicId(), faceId);
|
||||||
|
|
||||||
videoRecreationHandler.handleVideoRecreation(scenicConfig, memberSourceEntityList, faceId,
|
videoRecreationHandler.handleVideoRecreation(face.getScenicId(), memberSourceEntityList, faceId,
|
||||||
face.getMemberId(), sampleListIds, false);
|
face.getMemberId(), sampleListIds, false);
|
||||||
|
|
||||||
List<MemberSourceEntity> existingFiltered = sourceMapper.filterExistingRelations(memberSourceEntityList);
|
List<MemberSourceEntity> existingFiltered = sourceMapper.filterExistingRelations(memberSourceEntityList);
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.ycwl.basic.service.pc.processor;
|
package com.ycwl.basic.service.pc.processor;
|
||||||
|
|
||||||
import com.ycwl.basic.biz.OrderBiz;
|
import com.ycwl.basic.biz.OrderBiz;
|
||||||
|
import com.ycwl.basic.constant.BuyStatus;
|
||||||
|
import com.ycwl.basic.constant.FreeStatus;
|
||||||
import com.ycwl.basic.model.mobile.order.IsBuyRespVO;
|
import com.ycwl.basic.model.mobile.order.IsBuyRespVO;
|
||||||
import com.ycwl.basic.model.pc.source.entity.MemberSourceEntity;
|
import com.ycwl.basic.model.pc.source.entity.MemberSourceEntity;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -51,17 +53,17 @@ public class BuyStatusProcessor {
|
|||||||
// 设置购买状态
|
// 设置购买状态
|
||||||
if (isBuy.isBuy()) {
|
if (isBuy.isBuy()) {
|
||||||
// 如果用户买过
|
// 如果用户买过
|
||||||
memberSourceEntity.setIsBuy(1);
|
memberSourceEntity.setIsBuy(BuyStatus.BOUGHT.getCode());
|
||||||
} else if (isBuy.isFree()) {
|
} else if (isBuy.isFree()) {
|
||||||
// 全免费逻辑
|
// 全免费逻辑
|
||||||
memberSourceEntity.setIsBuy(1);
|
memberSourceEntity.setIsBuy(BuyStatus.BOUGHT.getCode());
|
||||||
} else {
|
} else {
|
||||||
memberSourceEntity.setIsBuy(0);
|
memberSourceEntity.setIsBuy(BuyStatus.NOT_BOUGHT.getCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置免费状态
|
// 设置免费状态
|
||||||
if (freeSourceIds.contains(memberSourceEntity.getSourceId())) {
|
if (freeSourceIds.contains(memberSourceEntity.getSourceId())) {
|
||||||
memberSourceEntity.setIsFree(1);
|
memberSourceEntity.setIsFree(FreeStatus.FREE.getCode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.ycwl.basic.integration.common.manager.ScenicConfigManager;
|
|||||||
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
|
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
|
||||||
import com.ycwl.basic.model.task.resp.SearchFaceRespVo;
|
import com.ycwl.basic.model.task.resp.SearchFaceRespVo;
|
||||||
import com.ycwl.basic.repository.FaceRepository;
|
import com.ycwl.basic.repository.FaceRepository;
|
||||||
|
import com.ycwl.basic.service.pc.helper.ScenicConfigFacade;
|
||||||
import com.ycwl.basic.service.task.TaskFaceService;
|
import com.ycwl.basic.service.task.TaskFaceService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -27,6 +28,9 @@ public class FaceRecoveryStrategy {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private TaskFaceService faceService;
|
private TaskFaceService faceService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ScenicConfigFacade scenicConfigFacade;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行人脸识别补救逻辑
|
* 执行人脸识别补救逻辑
|
||||||
* 当匹配结果数量少于阈值时,使用第一个匹配结果重新进行人脸搜索
|
* 当匹配结果数量少于阈值时,使用第一个匹配结果重新进行人脸搜索
|
||||||
@@ -51,7 +55,7 @@ public class FaceRecoveryStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否需要执行补救逻辑
|
// 检查是否需要执行补救逻辑
|
||||||
Integer helperThreshold = scenicConfig.getInteger("face_detect_helper_threshold", 0);
|
Integer helperThreshold = scenicConfigFacade.getFaceDetectHelperThreshold(scenicId);
|
||||||
if (helperThreshold == null || helperThreshold <= 0) {
|
if (helperThreshold == null || helperThreshold <= 0) {
|
||||||
return originalResult;
|
return originalResult;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.ycwl.basic.service.pc.processor;
|
package com.ycwl.basic.service.pc.processor;
|
||||||
|
|
||||||
|
import com.ycwl.basic.constant.FreeStatus;
|
||||||
|
import com.ycwl.basic.constant.SourceType;
|
||||||
import com.ycwl.basic.integration.common.manager.DeviceConfigManager;
|
import com.ycwl.basic.integration.common.manager.DeviceConfigManager;
|
||||||
import com.ycwl.basic.integration.common.manager.ScenicConfigManager;
|
import com.ycwl.basic.integration.common.manager.ScenicConfigManager;
|
||||||
import com.ycwl.basic.mapper.SourceMapper;
|
import com.ycwl.basic.mapper.SourceMapper;
|
||||||
@@ -7,6 +9,7 @@ import com.ycwl.basic.model.pc.face.entity.FaceEntity;
|
|||||||
import com.ycwl.basic.model.pc.source.entity.MemberSourceEntity;
|
import com.ycwl.basic.model.pc.source.entity.MemberSourceEntity;
|
||||||
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
|
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
|
||||||
import com.ycwl.basic.repository.DeviceRepository;
|
import com.ycwl.basic.repository.DeviceRepository;
|
||||||
|
import com.ycwl.basic.service.pc.helper.ScenicConfigFacade;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -32,6 +35,9 @@ public class SourceRelationProcessor {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private DeviceRepository deviceRepository;
|
private DeviceRepository deviceRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ScenicConfigFacade scenicConfigFacade;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理源文件关联逻辑
|
* 处理源文件关联逻辑
|
||||||
* 根据匹配的样本ID创建MemberSourceEntity列表
|
* 根据匹配的样本ID创建MemberSourceEntity列表
|
||||||
@@ -60,8 +66,8 @@ public class SourceRelationProcessor {
|
|||||||
if (configManager.getInteger("limit_video", 0) > 0) {
|
if (configManager.getInteger("limit_video", 0) > 0) {
|
||||||
// 优先保留所有图片,然后限制视频数量
|
// 优先保留所有图片,然后限制视频数量
|
||||||
return Stream.concat(
|
return Stream.concat(
|
||||||
entry.getValue().stream().filter(item -> item.getType() == 2),
|
entry.getValue().stream().filter(item -> SourceType.isImage(item.getType())),
|
||||||
entry.getValue().stream().filter(item -> item.getType() == 1)
|
entry.getValue().stream().filter(item -> SourceType.isVideo(item.getType()))
|
||||||
.limit(Math.min(entry.getValue().size(), configManager.getInteger("limit_video", 0)))
|
.limit(Math.min(entry.getValue().size(), configManager.getInteger("limit_video", 0)))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -79,19 +85,19 @@ public class SourceRelationProcessor {
|
|||||||
memberSourceEntity.setType(sourceEntity.getType());
|
memberSourceEntity.setType(sourceEntity.getType());
|
||||||
|
|
||||||
// 设置免费状态 - 默认收费
|
// 设置免费状态 - 默认收费
|
||||||
memberSourceEntity.setIsFree(0);
|
memberSourceEntity.setIsFree(FreeStatus.PAID.getCode());
|
||||||
|
|
||||||
if (deviceConfig != null) {
|
if (deviceConfig != null) {
|
||||||
// 视频类型检查
|
// 视频类型检查
|
||||||
if (sourceEntity.getType() == 1) {
|
if (SourceType.isVideo(sourceEntity.getType())) {
|
||||||
if (Integer.valueOf(1).equals(deviceConfig.getInteger("video_free"))) {
|
if (Integer.valueOf(1).equals(deviceConfig.getInteger("video_free"))) {
|
||||||
memberSourceEntity.setIsFree(1);
|
memberSourceEntity.setIsFree(FreeStatus.FREE.getCode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 图片类型检查
|
// 图片类型检查
|
||||||
else if (sourceEntity.getType() == 2) {
|
else if (SourceType.isImage(sourceEntity.getType())) {
|
||||||
if (Integer.valueOf(1).equals(deviceConfig.getInteger("image_free"))) {
|
if (Integer.valueOf(1).equals(deviceConfig.getInteger("image_free"))) {
|
||||||
memberSourceEntity.setIsFree(1);
|
memberSourceEntity.setIsFree(FreeStatus.FREE.getCode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -105,12 +111,12 @@ public class SourceRelationProcessor {
|
|||||||
* 根据景区配置和是否新用户决定哪些照片可以免费
|
* 根据景区配置和是否新用户决定哪些照片可以免费
|
||||||
*
|
*
|
||||||
* @param memberSourceEntityList 源文件关联列表
|
* @param memberSourceEntityList 源文件关联列表
|
||||||
* @param scenicConfig 景区配置
|
* @param scenicId 景区ID
|
||||||
* @param isNew 是否新用户
|
* @param isNew 是否新用户
|
||||||
* @return 免费的源文件ID列表
|
* @return 免费的源文件ID列表
|
||||||
*/
|
*/
|
||||||
public List<Long> processFreeSourceLogic(List<MemberSourceEntity> memberSourceEntityList,
|
public List<Long> processFreeSourceLogic(List<MemberSourceEntity> memberSourceEntityList,
|
||||||
ScenicConfigManager scenicConfig,
|
Long scenicId,
|
||||||
boolean isNew) {
|
boolean isNew) {
|
||||||
List<Long> freeSourceIds = new ArrayList<>();
|
List<Long> freeSourceIds = new ArrayList<>();
|
||||||
|
|
||||||
@@ -121,12 +127,12 @@ public class SourceRelationProcessor {
|
|||||||
if (isNew) {
|
if (isNew) {
|
||||||
// 新用户送照片逻辑
|
// 新用户送照片逻辑
|
||||||
List<MemberSourceEntity> photoSource = memberSourceEntityList.stream()
|
List<MemberSourceEntity> photoSource = memberSourceEntityList.stream()
|
||||||
.filter(item -> item.getIsFree() == 0) // 只考虑收费的
|
.filter(item -> FreeStatus.isPaid(item.getIsFree())) // 只考虑收费的
|
||||||
.filter(item -> Integer.valueOf(2).equals(item.getType())) // 只考虑照片类型
|
.filter(item -> SourceType.isImage(item.getType())) // 只考虑照片类型
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
Integer photoFreeNum = scenicConfig != null ? scenicConfig.getInteger("photo_free_num") : null;
|
Integer photoFreeNum = scenicConfigFacade.getPhotoFreeNum(scenicId);
|
||||||
if (scenicConfig != null && photoFreeNum != null && photoFreeNum > 0) {
|
if (photoFreeNum != null && photoFreeNum > 0) {
|
||||||
|
|
||||||
int freePhotoCount = Math.min(photoFreeNum, photoSource.size());
|
int freePhotoCount = Math.min(photoFreeNum, photoSource.size());
|
||||||
freeSourceIds.addAll(photoSource.stream()
|
freeSourceIds.addAll(photoSource.stream()
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
package com.ycwl.basic.service.pc.processor;
|
package com.ycwl.basic.service.pc.processor;
|
||||||
|
|
||||||
|
import com.ycwl.basic.constant.SourceType;
|
||||||
import com.ycwl.basic.integration.common.manager.DeviceConfigManager;
|
import com.ycwl.basic.integration.common.manager.DeviceConfigManager;
|
||||||
import com.ycwl.basic.integration.common.manager.ScenicConfigManager;
|
import com.ycwl.basic.integration.common.manager.ScenicConfigManager;
|
||||||
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
|
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
|
||||||
import com.ycwl.basic.model.pc.source.entity.MemberSourceEntity;
|
import com.ycwl.basic.model.pc.source.entity.MemberSourceEntity;
|
||||||
import com.ycwl.basic.repository.DeviceRepository;
|
import com.ycwl.basic.repository.DeviceRepository;
|
||||||
import com.ycwl.basic.repository.FaceRepository;
|
import com.ycwl.basic.repository.FaceRepository;
|
||||||
|
import com.ycwl.basic.service.pc.helper.ScenicConfigFacade;
|
||||||
import com.ycwl.basic.task.VideoPieceGetter;
|
import com.ycwl.basic.task.VideoPieceGetter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -32,18 +34,21 @@ public class VideoRecreationHandler {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private DeviceRepository deviceRepository;
|
private DeviceRepository deviceRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ScenicConfigFacade scenicConfigFacade;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理视频重切逻辑
|
* 处理视频重切逻辑
|
||||||
* 当非新用户且照片数量大于视频数量时,创建视频重切任务
|
* 当非新用户且照片数量大于视频数量时,创建视频重切任务
|
||||||
*
|
*
|
||||||
* @param scenicConfig 景区配置
|
* @param scenicId 景区ID
|
||||||
* @param memberSourceEntityList 源文件关联列表
|
* @param memberSourceEntityList 源文件关联列表
|
||||||
* @param faceId 人脸ID
|
* @param faceId 人脸ID
|
||||||
* @param memberId 会员ID
|
* @param memberId 会员ID
|
||||||
* @param sampleListIds 样本ID列表(用于日志)
|
* @param sampleListIds 样本ID列表(用于日志)
|
||||||
* @param isNew 是否新用户
|
* @param isNew 是否新用户
|
||||||
*/
|
*/
|
||||||
public void handleVideoRecreation(ScenicConfigManager scenicConfig,
|
public void handleVideoRecreation(Long scenicId,
|
||||||
List<MemberSourceEntity> memberSourceEntityList,
|
List<MemberSourceEntity> memberSourceEntityList,
|
||||||
Long faceId,
|
Long faceId,
|
||||||
Long memberId,
|
Long memberId,
|
||||||
@@ -55,18 +60,17 @@ public class VideoRecreationHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查景区是否禁用源视频功能
|
// 检查景区是否禁用源视频功能
|
||||||
Boolean disableSourceVideo = scenicConfig != null ? scenicConfig.getBoolean("disable_source_video") : null;
|
if (scenicConfigFacade.isDisableSourceVideo(scenicId)) {
|
||||||
if (scenicConfig == null || Boolean.TRUE.equals(disableSourceVideo)) {
|
|
||||||
log.debug("视频重切逻辑跳过:景区禁用了源视频功能");
|
log.debug("视频重切逻辑跳过:景区禁用了源视频功能");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 统计视频和照片数量
|
// 统计视频和照片数量
|
||||||
long videoCount = memberSourceEntityList.stream()
|
long videoCount = memberSourceEntityList.stream()
|
||||||
.filter(item -> Integer.valueOf(1).equals(item.getType()))
|
.filter(item -> SourceType.isVideo(item.getType()))
|
||||||
.count();
|
.count();
|
||||||
long photoCount = memberSourceEntityList.stream()
|
long photoCount = memberSourceEntityList.stream()
|
||||||
.filter(item -> Integer.valueOf(2).equals(item.getType()))
|
.filter(item -> SourceType.isImage(item.getType()))
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
List<FaceSampleEntity> faceSampleList = faceRepository.getFaceSampleList(faceId);
|
List<FaceSampleEntity> faceSampleList = faceRepository.getFaceSampleList(faceId);
|
||||||
|
|||||||
Reference in New Issue
Block a user