You've already forked FrameTour-BE
Compare commits
7 Commits
24bbb63bf7
...
fe3bda28b4
| Author | SHA1 | Date | |
|---|---|---|---|
| fe3bda28b4 | |||
| 66775ea48b | |||
| 125fadd6c5 | |||
| 1f4a16f0e6 | |||
| e9916d6aca | |||
| b71452b3ed | |||
| 4a82ee6c4d |
@@ -220,6 +220,7 @@ public class OrderBiz {
|
|||||||
break;
|
break;
|
||||||
case 1: // 视频原素材
|
case 1: // 视频原素材
|
||||||
case 2: // 照片原素材
|
case 2: // 照片原素材
|
||||||
|
case 13: // AI微单
|
||||||
sourceRepository.setUserIsBuyItem(order.getMemberId(), item.getGoodsType(), item.getGoodsId(), order.getId());
|
sourceRepository.setUserIsBuyItem(order.getMemberId(), item.getGoodsType(), item.getGoodsId(), order.getId());
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
|
|||||||
@@ -16,7 +16,12 @@ public enum SourceType {
|
|||||||
/**
|
/**
|
||||||
* 图片类型
|
* 图片类型
|
||||||
*/
|
*/
|
||||||
IMAGE(2, "图片");
|
IMAGE(2, "图片"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI微单类型
|
||||||
|
*/
|
||||||
|
AI_CAM(3, "AI微单");
|
||||||
|
|
||||||
private final int code;
|
private final int code;
|
||||||
private final String description;
|
private final String description;
|
||||||
@@ -68,4 +73,14 @@ public enum SourceType {
|
|||||||
public static boolean isImage(Integer code) {
|
public static boolean isImage(Integer code) {
|
||||||
return code != null && code == IMAGE.code;
|
return code != null && code == IMAGE.code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断给定的代码是否为AI微单类型
|
||||||
|
*
|
||||||
|
* @param code 类型代码
|
||||||
|
* @return true-是AI微单,false-不是AI微单
|
||||||
|
*/
|
||||||
|
public static boolean isAiCam(Integer code) {
|
||||||
|
return code != null && code == AI_CAM.code;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package com.ycwl.basic.controller.mobile;
|
||||||
|
|
||||||
|
import com.ycwl.basic.model.mobile.goods.GoodsDetailVO;
|
||||||
|
import com.ycwl.basic.service.mobile.AppAiCamService;
|
||||||
|
import com.ycwl.basic.utils.ApiResponse;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI相机相关接口
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/mobile/ai_cam/v1")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AppAiCamController {
|
||||||
|
|
||||||
|
private final AppAiCamService appAiCamService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据faceId获取AI相机识别到的商品列表
|
||||||
|
* @param faceId 人脸ID
|
||||||
|
* @return 商品详情列表
|
||||||
|
*/
|
||||||
|
@GetMapping("/{faceId}/content")
|
||||||
|
public ApiResponse<List<GoodsDetailVO>> getAiCamGoods(@PathVariable Long faceId) {
|
||||||
|
try {
|
||||||
|
List<GoodsDetailVO> goods = appAiCamService.getAiCamGoodsByFaceId(faceId);
|
||||||
|
return ApiResponse.success(goods);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取AI相机商品失败: faceId={}", faceId, e);
|
||||||
|
return ApiResponse.fail("获取商品列表失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量添加会员与source的关联关系
|
||||||
|
* @param faceId 人脸ID
|
||||||
|
* @param sourceIds source ID列表
|
||||||
|
* @return 添加结果
|
||||||
|
*/
|
||||||
|
@PostMapping("/{faceId}/relations")
|
||||||
|
public ApiResponse<String> addMemberSourceRelations(
|
||||||
|
@PathVariable Long faceId,
|
||||||
|
@RequestBody List<Long> sourceIds
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
int count = appAiCamService.addMemberSourceRelations(faceId, sourceIds);
|
||||||
|
return ApiResponse.success("成功添加" + count + "条关联记录");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
log.warn("添加关联失败: faceId={}, error={}", faceId, e.getMessage());
|
||||||
|
return ApiResponse.fail(e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("添加关联失败: faceId={}", faceId, e);
|
||||||
|
return ApiResponse.fail("添加关联失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -86,7 +86,7 @@ public class AppOrderV2Controller {
|
|||||||
TaskEntity task = videoTaskRepository.getTaskById(video.getTaskId());
|
TaskEntity task = videoTaskRepository.getTaskById(video.getTaskId());
|
||||||
request.setFaceId(task.getFaceId());
|
request.setFaceId(task.getFaceId());
|
||||||
}
|
}
|
||||||
case RECORDING_SET, PHOTO_SET -> request.setFaceId(Long.valueOf(productItem.getProductId()));
|
case RECORDING_SET, PHOTO_SET, AI_CAM_PHOTO_SET -> request.setFaceId(Long.valueOf(productItem.getProductId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,6 +119,14 @@ public class AppOrderV2Controller {
|
|||||||
Integer count = sourceMapper.countUser(sourceReqQuery);
|
Integer count = sourceMapper.countUser(sourceReqQuery);
|
||||||
product.setQuantity(count);
|
product.setQuantity(count);
|
||||||
break;
|
break;
|
||||||
|
case AI_CAM_PHOTO_SET:
|
||||||
|
SourceReqQuery aiPhotoSetReqQuery = new SourceReqQuery();
|
||||||
|
aiPhotoSetReqQuery.setMemberId(currentUserId);
|
||||||
|
aiPhotoSetReqQuery.setType(13);
|
||||||
|
aiPhotoSetReqQuery.setFaceId(face.getId());
|
||||||
|
Integer _count = sourceMapper.countUser(aiPhotoSetReqQuery);
|
||||||
|
product.setQuantity(_count);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
log.warn("未知的商品类型,跳过重复购买检查: productType={}", product.getProductType());
|
log.warn("未知的商品类型,跳过重复购买检查: productType={}", product.getProductType());
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -3,10 +3,19 @@ package com.ycwl.basic.mapper;
|
|||||||
import com.ycwl.basic.model.pc.faceDetectLog.entity.FaceDetectLogAiCamEntity;
|
import com.ycwl.basic.model.pc.faceDetectLog.entity.FaceDetectLogAiCamEntity;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AI相机人脸识别日志Mapper
|
* AI相机人脸识别日志Mapper
|
||||||
*/
|
*/
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface FaceDetectLogAiCamMapper {
|
public interface FaceDetectLogAiCamMapper {
|
||||||
int add(FaceDetectLogAiCamEntity entity);
|
int add(FaceDetectLogAiCamEntity entity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据faceId查询所有识别记录
|
||||||
|
* @param faceId 人脸ID
|
||||||
|
* @return 识别记录列表
|
||||||
|
*/
|
||||||
|
List<FaceDetectLogAiCamEntity> listByFaceId(Long faceId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,4 +148,20 @@ public interface SourceMapper {
|
|||||||
* @return source实体
|
* @return source实体
|
||||||
*/
|
*/
|
||||||
SourceEntity getSourceByFaceAndDeviceId(Long faceId, Long deviceId, Integer type, String sortStrategy);
|
SourceEntity getSourceByFaceAndDeviceId(Long faceId, Long deviceId, Integer type, String sortStrategy);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据faceSampleId列表和type查询source列表
|
||||||
|
* @param faceSampleIds faceSampleId列表
|
||||||
|
* @param type 素材类型
|
||||||
|
* @return source实体列表
|
||||||
|
*/
|
||||||
|
List<SourceEntity> listByFaceSampleIdsAndType(List<Long> faceSampleIds, Integer type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除指定faceId和type的member_source关联记录
|
||||||
|
* @param faceId 人脸ID
|
||||||
|
* @param type 素材类型
|
||||||
|
* @return 删除的记录数
|
||||||
|
*/
|
||||||
|
int deleteRelationsByFaceIdAndType(Long faceId, Integer type);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ public enum ProductType {
|
|||||||
// 照片类
|
// 照片类
|
||||||
PHOTO("PHOTO", "照片", ProductCategory.PHOTO),
|
PHOTO("PHOTO", "照片", ProductCategory.PHOTO),
|
||||||
PHOTO_SET("PHOTO_SET", "照片集", ProductCategory.PHOTO),
|
PHOTO_SET("PHOTO_SET", "照片集", ProductCategory.PHOTO),
|
||||||
|
AI_CAM_PHOTO_SET("AI_CAM_PHOTO_SET", "照片集", ProductCategory.PHOTO),
|
||||||
PHOTO_LOG("PHOTO_LOG", "pLog图", ProductCategory.PHOTO),
|
PHOTO_LOG("PHOTO_LOG", "pLog图", ProductCategory.PHOTO),
|
||||||
|
|
||||||
// 视频类(素材视频)
|
// 视频类(素材视频)
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ public class SourceRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setUserIsBuyItem(Long memberId, int type, Long faceId, Long orderId) {
|
public void setUserIsBuyItem(Long memberId, int type, Long faceId, Long orderId) {
|
||||||
|
if (type == 13) {
|
||||||
|
type = 3; // compact
|
||||||
|
}
|
||||||
MemberSourceEntity memberSource = new MemberSourceEntity();
|
MemberSourceEntity memberSource = new MemberSourceEntity();
|
||||||
memberSource.setMemberId(memberId);
|
memberSource.setMemberId(memberId);
|
||||||
memberSource.setFaceId(faceId);
|
memberSource.setFaceId(faceId);
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ public class ZTSourceDataService {
|
|||||||
entity.setDeviceId(message.getDeviceId());
|
entity.setDeviceId(message.getDeviceId());
|
||||||
entity.setUrl(message.getSourceUrl()); // 使用sourceUrl,不使用缩略图
|
entity.setUrl(message.getSourceUrl()); // 使用sourceUrl,不使用缩略图
|
||||||
entity.setThumbUrl(message.getThumbnailUrl()); // 设置缩略图URL
|
entity.setThumbUrl(message.getThumbnailUrl()); // 设置缩略图URL
|
||||||
entity.setType(2); // 照片类型
|
entity.setType(message.getSourceType()); // 照片类型
|
||||||
|
|
||||||
// 人脸样本ID处理
|
// 人脸样本ID处理
|
||||||
entity.setFaceSampleId(message.getFaceSampleId());
|
entity.setFaceSampleId(message.getFaceSampleId());
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.ycwl.basic.service.mobile;
|
||||||
|
|
||||||
|
import com.ycwl.basic.model.mobile.goods.GoodsDetailVO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI相机相关服务
|
||||||
|
*/
|
||||||
|
public interface AppAiCamService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据faceId获取AI相机识别到的商品列表
|
||||||
|
* @param faceId 人脸ID
|
||||||
|
* @return 商品详情列表
|
||||||
|
*/
|
||||||
|
List<GoodsDetailVO> getAiCamGoodsByFaceId(Long faceId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量添加会员与source的关联关系
|
||||||
|
* @param faceId 人脸ID
|
||||||
|
* @param sourceIds source ID列表
|
||||||
|
* @return 添加成功的数量
|
||||||
|
*/
|
||||||
|
int addMemberSourceRelations(Long faceId, List<Long> sourceIds);
|
||||||
|
}
|
||||||
@@ -0,0 +1,275 @@
|
|||||||
|
package com.ycwl.basic.service.mobile.impl;
|
||||||
|
|
||||||
|
import com.ycwl.basic.facebody.entity.SearchFaceResp;
|
||||||
|
import com.ycwl.basic.facebody.entity.SearchFaceResultItem;
|
||||||
|
import com.ycwl.basic.integration.common.manager.DeviceConfigManager;
|
||||||
|
import com.ycwl.basic.mapper.FaceDetectLogAiCamMapper;
|
||||||
|
import com.ycwl.basic.mapper.FaceMapper;
|
||||||
|
import com.ycwl.basic.mapper.SourceMapper;
|
||||||
|
import com.ycwl.basic.model.mobile.goods.GoodsDetailVO;
|
||||||
|
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
|
||||||
|
import com.ycwl.basic.model.pc.faceDetectLog.entity.FaceDetectLogAiCamEntity;
|
||||||
|
import com.ycwl.basic.model.pc.source.entity.MemberSourceEntity;
|
||||||
|
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
|
||||||
|
import com.ycwl.basic.repository.DeviceRepository;
|
||||||
|
import com.ycwl.basic.service.mobile.AppAiCamService;
|
||||||
|
import com.ycwl.basic.utils.JacksonUtil;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI相机相关服务实现
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AppAiCamServiceImpl implements AppAiCamService {
|
||||||
|
|
||||||
|
private final FaceDetectLogAiCamMapper faceDetectLogAiCamMapper;
|
||||||
|
private final SourceMapper sourceMapper;
|
||||||
|
private final FaceMapper faceMapper;
|
||||||
|
private final DeviceRepository deviceRepository;
|
||||||
|
|
||||||
|
private static final float DEFAULT_SCORE_THRESHOLD = 0.8f;
|
||||||
|
private static final int DEFAULT_PHOTO_LIMIT = 10;
|
||||||
|
private static final int AI_CAM_SOURCE_TYPE = 3;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<GoodsDetailVO> getAiCamGoodsByFaceId(Long faceId) {
|
||||||
|
// 1. 查询该faceId的所有识别记录
|
||||||
|
List<FaceDetectLogAiCamEntity> detectLogs = faceDetectLogAiCamMapper.listByFaceId(faceId);
|
||||||
|
if (detectLogs == null || detectLogs.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 按设备分组并根据设备配置过滤faceSampleId
|
||||||
|
Map<Long, List<Long>> deviceFaceSampleMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
// 按设备分组识别记录
|
||||||
|
Map<Long, List<FaceDetectLogAiCamEntity>> deviceLogsMap = detectLogs.stream()
|
||||||
|
.collect(Collectors.groupingBy(FaceDetectLogAiCamEntity::getDeviceId));
|
||||||
|
|
||||||
|
// 遍历每个设备的识别记录
|
||||||
|
for (Map.Entry<Long, List<FaceDetectLogAiCamEntity>> entry : deviceLogsMap.entrySet()) {
|
||||||
|
Long deviceId = entry.getKey();
|
||||||
|
List<FaceDetectLogAiCamEntity> deviceLogs = entry.getValue();
|
||||||
|
|
||||||
|
// 获取设备配置
|
||||||
|
DeviceConfigManager configManager = deviceRepository.getDeviceConfigManager(deviceId);
|
||||||
|
|
||||||
|
// 获取该设备的分数阈值(百分制,需要转换为0-1)
|
||||||
|
float scoreThreshold = DEFAULT_SCORE_THRESHOLD;
|
||||||
|
if (configManager != null) {
|
||||||
|
Float thresholdPercent = configManager.getFloat("ai_cam_face_score_threshold");
|
||||||
|
if (thresholdPercent != null) {
|
||||||
|
scoreThreshold = thresholdPercent / 100.0f;
|
||||||
|
log.debug("设备{}使用配置的分数阈值: {}% ({})", deviceId, thresholdPercent, scoreThreshold);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取该设备的照片数量限制
|
||||||
|
int photoLimit = DEFAULT_PHOTO_LIMIT;
|
||||||
|
if (configManager != null) {
|
||||||
|
Integer limit = configManager.getInteger("ai_cam_photo_limit");
|
||||||
|
if (limit != null && limit > 0) {
|
||||||
|
photoLimit = limit;
|
||||||
|
log.debug("设备{}使用配置的照片限制: {}", deviceId, photoLimit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取该设备的时间范围限制(分钟)
|
||||||
|
Integer timeRangeMin = null;
|
||||||
|
if (configManager != null) {
|
||||||
|
Integer range = configManager.getInteger("ai_cam_time_range_min");
|
||||||
|
if (range != null && range > 0) {
|
||||||
|
timeRangeMin = range;
|
||||||
|
log.debug("设备{}使用配置的时间范围: {}分钟", deviceId, timeRangeMin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 收集该设备符合阈值的faceSampleId,同时记录分数和时间信息用于后续过滤
|
||||||
|
class DetectResult {
|
||||||
|
Long faceSampleId;
|
||||||
|
Float score;
|
||||||
|
Date detectTime;
|
||||||
|
|
||||||
|
DetectResult(Long faceSampleId, Float score, Date detectTime) {
|
||||||
|
this.faceSampleId = faceSampleId;
|
||||||
|
this.score = score;
|
||||||
|
this.detectTime = detectTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<DetectResult> detectResults = new ArrayList<>();
|
||||||
|
for (FaceDetectLogAiCamEntity detectLog : deviceLogs) {
|
||||||
|
if (detectLog.getMatchRawResult() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
SearchFaceResp resp = JacksonUtil.parseObject(detectLog.getMatchRawResult(), SearchFaceResp.class);
|
||||||
|
if (resp != null && resp.getResult() != null) {
|
||||||
|
for (SearchFaceResultItem item : resp.getResult()) {
|
||||||
|
// 使用设备配置的分数阈值
|
||||||
|
if (item.getScore() != null && item.getScore() >= scoreThreshold && item.getExtData() != null) {
|
||||||
|
try {
|
||||||
|
Long faceSampleId = Long.parseLong(item.getExtData());
|
||||||
|
detectResults.add(new DetectResult(
|
||||||
|
faceSampleId,
|
||||||
|
item.getScore(),
|
||||||
|
detectLog.getCreateTime()
|
||||||
|
));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.warn("解析faceSampleId失败: extData={}", item.getExtData());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("解析matchRawResult失败: logId={}", detectLog.getId(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用照片数量限制(保留前N个)
|
||||||
|
if (detectResults.size() > photoLimit) {
|
||||||
|
log.debug("设备{}的照片数量{}超过限制{},截取前{}张",
|
||||||
|
deviceId, detectResults.size(), photoLimit, photoLimit);
|
||||||
|
detectResults = detectResults.subList(0, photoLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用时间范围限制
|
||||||
|
List<Long> deviceFaceSampleIds;
|
||||||
|
if (timeRangeMin != null && !detectResults.isEmpty()) {
|
||||||
|
// 找到分数最高的照片
|
||||||
|
DetectResult highestScoreResult = detectResults.stream()
|
||||||
|
.max(Comparator.comparing(r -> r.score))
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
if (highestScoreResult != null && highestScoreResult.detectTime != null) {
|
||||||
|
Date baseTime = highestScoreResult.detectTime;
|
||||||
|
long halfRangeMillis = (long) timeRangeMin * 60 * 1000 / 2;
|
||||||
|
Date startTime = new Date(baseTime.getTime() - halfRangeMillis);
|
||||||
|
Date endTime = new Date(baseTime.getTime() + halfRangeMillis);
|
||||||
|
|
||||||
|
// 过滤出时间范围内的照片
|
||||||
|
List<DetectResult> filteredResults = detectResults.stream()
|
||||||
|
.filter(r -> r.detectTime != null
|
||||||
|
&& !r.detectTime.before(startTime)
|
||||||
|
&& !r.detectTime.after(endTime))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
log.debug("设备{}应用时间范围{}分钟过滤: {}张 -> {}张 (基准时间: {})",
|
||||||
|
deviceId, timeRangeMin, detectResults.size(), filteredResults.size(), baseTime);
|
||||||
|
|
||||||
|
deviceFaceSampleIds = filteredResults.stream()
|
||||||
|
.map(r -> r.faceSampleId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
} else {
|
||||||
|
// 没有时间信息,不过滤
|
||||||
|
deviceFaceSampleIds = detectResults.stream()
|
||||||
|
.map(r -> r.faceSampleId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 不限制时间范围
|
||||||
|
deviceFaceSampleIds = detectResults.stream()
|
||||||
|
.map(r -> r.faceSampleId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!deviceFaceSampleIds.isEmpty()) {
|
||||||
|
deviceFaceSampleMap.put(deviceId, deviceFaceSampleIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 合并所有设备的faceSampleId(去重)
|
||||||
|
Set<Long> faceSampleIds = new HashSet<>();
|
||||||
|
for (List<Long> ids : deviceFaceSampleMap.values()) {
|
||||||
|
faceSampleIds.addAll(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (faceSampleIds.isEmpty()) {
|
||||||
|
log.debug("没有符合条件的faceSampleId, faceId={}", faceId);
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("人脸{}在{}个设备上识别到{}个不重复的faceSampleId",
|
||||||
|
faceId, deviceFaceSampleMap.size(), faceSampleIds.size());
|
||||||
|
|
||||||
|
// 4. 根据faceSampleId列表查询type=3的source记录
|
||||||
|
List<SourceEntity> sources = sourceMapper.listByFaceSampleIdsAndType(
|
||||||
|
new ArrayList<>(faceSampleIds), AI_CAM_SOURCE_TYPE
|
||||||
|
);
|
||||||
|
|
||||||
|
if (sources == null || sources.isEmpty()) {
|
||||||
|
log.debug("未找到type=3的source记录, faceId={}", faceId);
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("查询到{}条AI相机图像记录, faceId={}", sources.size(), faceId);
|
||||||
|
|
||||||
|
// 5. 查询Face信息以获取scenicId
|
||||||
|
FaceEntity face = faceMapper.get(faceId);
|
||||||
|
if (face == null) {
|
||||||
|
log.warn("Face不存在: faceId={}", faceId);
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 转换为GoodsDetailVO
|
||||||
|
return sources.stream().map(source -> {
|
||||||
|
GoodsDetailVO vo = new GoodsDetailVO();
|
||||||
|
vo.setFaceId(faceId);
|
||||||
|
vo.setScenicId(face.getScenicId());
|
||||||
|
vo.setGoodsType(2); // 2表示原素材
|
||||||
|
vo.setGoodsId(source.getId());
|
||||||
|
vo.setUrl(source.getUrl());
|
||||||
|
vo.setVideoUrl(source.getVideoUrl());
|
||||||
|
vo.setCreateTime(source.getCreateTime());
|
||||||
|
vo.setIsBuy(source.getIsBuy() != null ? source.getIsBuy() : 0);
|
||||||
|
return vo;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int addMemberSourceRelations(Long faceId, List<Long> sourceIds) {
|
||||||
|
if (sourceIds == null || sourceIds.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询Face信息
|
||||||
|
FaceEntity face = faceMapper.get(faceId);
|
||||||
|
if (face == null) {
|
||||||
|
throw new IllegalArgumentException("Face不存在: faceId=" + faceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (face.getMemberId() == null) {
|
||||||
|
throw new IllegalArgumentException("Face未关联会员: faceId=" + faceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除该faceId对应的旧的type=3关系
|
||||||
|
int deleted = sourceMapper.deleteRelationsByFaceIdAndType(faceId, AI_CAM_SOURCE_TYPE);
|
||||||
|
log.info("删除faceId={}的旧AI相机关联记录: {}条", faceId, deleted);
|
||||||
|
|
||||||
|
// 构建MemberSourceEntity列表
|
||||||
|
List<MemberSourceEntity> relations = sourceIds.stream().map(sourceId -> {
|
||||||
|
MemberSourceEntity entity = new MemberSourceEntity();
|
||||||
|
entity.setMemberId(face.getMemberId());
|
||||||
|
entity.setScenicId(face.getScenicId());
|
||||||
|
entity.setFaceId(faceId);
|
||||||
|
entity.setSourceId(sourceId);
|
||||||
|
entity.setType(AI_CAM_SOURCE_TYPE);
|
||||||
|
entity.setIsBuy(0);
|
||||||
|
entity.setIsFree(0);
|
||||||
|
return entity;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
|
||||||
|
// 批量插入
|
||||||
|
int inserted = sourceMapper.addRelations(relations);
|
||||||
|
log.info("为faceId={}添加新AI相机关联记录: {}条", faceId, inserted);
|
||||||
|
|
||||||
|
return inserted;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -127,6 +127,8 @@ public class GoodsServiceImpl implements GoodsService {
|
|||||||
goodsNamePrefix = "录像";
|
goodsNamePrefix = "录像";
|
||||||
} else if (sourceType == 2) {
|
} else if (sourceType == 2) {
|
||||||
goodsNamePrefix = "图片";
|
goodsNamePrefix = "图片";
|
||||||
|
} else if (sourceType == 3) {
|
||||||
|
goodsNamePrefix = "AI微单";
|
||||||
} else {
|
} else {
|
||||||
goodsNamePrefix = "其他类型";
|
goodsNamePrefix = "其他类型";
|
||||||
}
|
}
|
||||||
@@ -573,7 +575,7 @@ public class GoodsServiceImpl implements GoodsService {
|
|||||||
if (query.getGoodsId() != null) {
|
if (query.getGoodsId() != null) {
|
||||||
list = list.stream().filter(source -> source.getId().equals(query.getGoodsId())).toList();
|
list = list.stream().filter(source -> source.getId().equals(query.getGoodsId())).toList();
|
||||||
}
|
}
|
||||||
if (!Integer.valueOf(2).equals(query.getSourceType())) {
|
if (Integer.valueOf(1).equals(query.getSourceType())) {
|
||||||
return list.stream().map(source -> {
|
return list.stream().map(source -> {
|
||||||
GoodsUrlVO goodsUrlVO = new GoodsUrlVO();
|
GoodsUrlVO goodsUrlVO = new GoodsUrlVO();
|
||||||
goodsUrlVO.setGoodsType(source.getType());
|
goodsUrlVO.setGoodsType(source.getType());
|
||||||
@@ -592,7 +594,7 @@ public class GoodsServiceImpl implements GoodsService {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}).count();
|
}).count();
|
||||||
IsBuyRespVO isBuy = orderBiz.isBuy(face.getScenicId(), face.getMemberId(), face.getId(), query.getSourceType(), face.getId());
|
IsBuyRespVO isBuy = orderBiz.isBuy(face.getScenicId(), face.getMemberId(), face.getId(), sourceType == 3 ? 13 : sourceType, face.getId());
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
if (!isBuy.isBuy()) {
|
if (!isBuy.isBuy()) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
@@ -829,6 +831,9 @@ public class GoodsServiceImpl implements GoodsService {
|
|||||||
} else if (type == 2) {
|
} else if (type == 2) {
|
||||||
goodsPageVO.setGoodsName("照片集");
|
goodsPageVO.setGoodsName("照片集");
|
||||||
goodsPageVO.setTemplateCoverUrl(scenicConfig.getString("photo_cover_url"));
|
goodsPageVO.setTemplateCoverUrl(scenicConfig.getString("photo_cover_url"));
|
||||||
|
} else if (type == 3) {
|
||||||
|
goodsPageVO.setGoodsName("AI微单");
|
||||||
|
goodsPageVO.setTemplateCoverUrl(scenicConfig.getString("ai_camera_cover_url"));
|
||||||
} else {
|
} else {
|
||||||
goodsPageVO.setGoodsName("未知商品");
|
goodsPageVO.setGoodsName("未知商品");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,11 +11,10 @@ public interface FaceDetectLogAiCamService {
|
|||||||
/**
|
/**
|
||||||
* 搜索人脸库并保存日志
|
* 搜索人脸库并保存日志
|
||||||
* @param scenicId 景区ID
|
* @param scenicId 景区ID
|
||||||
* @param deviceId 设备ID
|
* @param faceId 人脸样本ID
|
||||||
* @param faceSampleId 人脸样本ID
|
|
||||||
* @param faceUrl 人脸URL
|
* @param faceUrl 人脸URL
|
||||||
* @param adapter 人脸适配器
|
* @param adapter 人脸适配器
|
||||||
* @return 搜索结果
|
* @return 搜索结果
|
||||||
*/
|
*/
|
||||||
SearchFaceResp searchAndLog(Long scenicId, Long deviceId, Long faceSampleId, String faceUrl, IFaceBodyAdapter adapter);
|
void searchAndLog(Long scenicId, Long faceId, String faceUrl, IFaceBodyAdapter adapter);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ package com.ycwl.basic.service.pc.impl;
|
|||||||
|
|
||||||
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
|
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
|
||||||
import com.ycwl.basic.facebody.entity.SearchFaceResp;
|
import com.ycwl.basic.facebody.entity.SearchFaceResp;
|
||||||
|
import com.ycwl.basic.integration.device.dto.device.DeviceV2DTO;
|
||||||
import com.ycwl.basic.mapper.FaceDetectLogAiCamMapper;
|
import com.ycwl.basic.mapper.FaceDetectLogAiCamMapper;
|
||||||
import com.ycwl.basic.model.pc.faceDetectLog.entity.FaceDetectLogAiCamEntity;
|
import com.ycwl.basic.model.pc.faceDetectLog.entity.FaceDetectLogAiCamEntity;
|
||||||
|
import com.ycwl.basic.repository.DeviceRepository;
|
||||||
import com.ycwl.basic.service.pc.FaceDetectLogAiCamService;
|
import com.ycwl.basic.service.pc.FaceDetectLogAiCamService;
|
||||||
import com.ycwl.basic.utils.JacksonUtil;
|
import com.ycwl.basic.utils.JacksonUtil;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@@ -11,6 +13,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@@ -18,17 +21,28 @@ import java.util.Date;
|
|||||||
public class FaceDetectLogAiCamServiceImpl implements FaceDetectLogAiCamService {
|
public class FaceDetectLogAiCamServiceImpl implements FaceDetectLogAiCamService {
|
||||||
|
|
||||||
private final FaceDetectLogAiCamMapper faceDetectLogAiCamMapper;
|
private final FaceDetectLogAiCamMapper faceDetectLogAiCamMapper;
|
||||||
|
private final DeviceRepository deviceRepository;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SearchFaceResp searchAndLog(Long scenicId, Long deviceId, Long faceSampleId, String faceUrl, IFaceBodyAdapter adapter) {
|
public void searchAndLog(Long scenicId, Long faceId, String faceUrl, IFaceBodyAdapter adapter) {
|
||||||
|
List<DeviceV2DTO> devices = deviceRepository.getAllDeviceByScenicId(scenicId);
|
||||||
|
for (DeviceV2DTO device : devices) {
|
||||||
|
if (!device.getType().equals("AI_CAM")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
searchDeviceAndLog(scenicId, device.getId(), faceId, faceUrl, adapter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SearchFaceResp searchDeviceAndLog(Long scenicId, Long deviceId, Long faceId, String faceUrl, IFaceBodyAdapter adapter) {
|
||||||
String dbName = "AiCam" + deviceId;
|
String dbName = "AiCam" + deviceId;
|
||||||
|
|
||||||
SearchFaceResp resp = null;
|
SearchFaceResp resp = null;
|
||||||
try {
|
try {
|
||||||
// 调用适配器搜索人脸
|
// 调用适配器搜索人脸
|
||||||
resp = adapter.searchFace(dbName, faceUrl);
|
resp = adapter.searchFace(dbName, faceUrl);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("AI相机人脸搜索异常: scenicId={}, deviceId={}, faceSampleId={}", scenicId, deviceId, faceSampleId, e);
|
log.error("AI相机人脸搜索异常: scenicId={}, deviceId={}, faceId={}", scenicId, deviceId, faceId, e);
|
||||||
// 发生异常时记录空结果或错误信息,视业务需求而定。这里暂不中断流程,继续记录日志
|
// 发生异常时记录空结果或错误信息,视业务需求而定。这里暂不中断流程,继续记录日志
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +51,7 @@ public class FaceDetectLogAiCamServiceImpl implements FaceDetectLogAiCamService
|
|||||||
FaceDetectLogAiCamEntity logEntity = new FaceDetectLogAiCamEntity();
|
FaceDetectLogAiCamEntity logEntity = new FaceDetectLogAiCamEntity();
|
||||||
logEntity.setScenicId(scenicId);
|
logEntity.setScenicId(scenicId);
|
||||||
logEntity.setDeviceId(deviceId);
|
logEntity.setDeviceId(deviceId);
|
||||||
logEntity.setFaceId(faceSampleId);
|
logEntity.setFaceId(faceId);
|
||||||
logEntity.setDbName(dbName);
|
logEntity.setDbName(dbName);
|
||||||
logEntity.setFaceUrl(faceUrl);
|
logEntity.setFaceUrl(faceUrl);
|
||||||
logEntity.setCreateTime(new Date());
|
logEntity.setCreateTime(new Date());
|
||||||
@@ -47,17 +61,17 @@ public class FaceDetectLogAiCamServiceImpl implements FaceDetectLogAiCamService
|
|||||||
// SearchFaceResp 的 getOriginalFaceScore 通常是图片质量分,getFirstMatchRate 是最佳匹配分
|
// SearchFaceResp 的 getOriginalFaceScore 通常是图片质量分,getFirstMatchRate 是最佳匹配分
|
||||||
// 需根据 SearchFaceResp 定义确认。假设 getFirstMatchRate() 是匹配分
|
// 需根据 SearchFaceResp 定义确认。假设 getFirstMatchRate() 是匹配分
|
||||||
// 实际上 searchFace 返回的是匹配列表。
|
// 实际上 searchFace 返回的是匹配列表。
|
||||||
|
|
||||||
// 记录原始响应
|
// 记录原始响应
|
||||||
logEntity.setMatchRawResult(JacksonUtil.toJSONString(resp));
|
logEntity.setMatchRawResult(JacksonUtil.toJSONString(resp));
|
||||||
} else {
|
} else {
|
||||||
logEntity.setMatchRawResult("{\"error\": \"search failed or exception\"}");
|
logEntity.setMatchRawResult("{\"error\": \"search failed or exception\"}");
|
||||||
}
|
}
|
||||||
|
|
||||||
faceDetectLogAiCamMapper.add(logEntity);
|
faceDetectLogAiCamMapper.add(logEntity);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("保存AI相机人脸识别日志失败: faceSampleId={}", faceSampleId, e);
|
log.error("保存AI相机人脸识别日志失败: faceId={}", faceId, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return resp;
|
return resp;
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import com.ycwl.basic.constant.BaseContextHandler;
|
|||||||
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;
|
||||||
@@ -62,6 +61,7 @@ import com.ycwl.basic.repository.TemplateRepository;
|
|||||||
import com.ycwl.basic.repository.VideoRepository;
|
import com.ycwl.basic.repository.VideoRepository;
|
||||||
import com.ycwl.basic.repository.VideoTaskRepository;
|
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.FaceDetectLogAiCamService;
|
||||||
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.constant.SourceType;
|
||||||
@@ -71,7 +71,6 @@ import com.ycwl.basic.service.pc.helper.SearchResultMerger;
|
|||||||
import com.ycwl.basic.service.pc.helper.ScenicConfigFacade;
|
import com.ycwl.basic.service.pc.helper.ScenicConfigFacade;
|
||||||
import com.ycwl.basic.service.pc.orchestrator.FaceMatchingOrchestrator;
|
import com.ycwl.basic.service.pc.orchestrator.FaceMatchingOrchestrator;
|
||||||
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.SourceRelationProcessor;
|
import com.ycwl.basic.service.pc.processor.SourceRelationProcessor;
|
||||||
import com.ycwl.basic.service.pc.processor.VideoRecreationHandler;
|
import com.ycwl.basic.service.pc.processor.VideoRecreationHandler;
|
||||||
import com.ycwl.basic.service.pc.strategy.RematchContext;
|
import com.ycwl.basic.service.pc.strategy.RematchContext;
|
||||||
@@ -86,7 +85,8 @@ 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.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.commons.lang3.StringUtils;
|
||||||
|
import org.apache.commons.lang3.Strings;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
@@ -193,6 +193,8 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
private IPriceCalculationService iPriceCalculationService;
|
private IPriceCalculationService iPriceCalculationService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private PuzzleTemplateMapper puzzleTemplateMapper;
|
private PuzzleTemplateMapper puzzleTemplateMapper;
|
||||||
|
@Autowired
|
||||||
|
private FaceDetectLogAiCamService faceDetectLogAiCamService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ApiResponse<PageInfo<FaceRespVO>> pageQuery(FaceReqQuery faceReqQuery) {
|
public ApiResponse<PageInfo<FaceRespVO>> pageQuery(FaceReqQuery faceReqQuery) {
|
||||||
@@ -312,13 +314,16 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
Long finalFaceId = newFaceId;
|
Long finalFaceId = newFaceId;
|
||||||
Thread thread = new Thread(() -> printerService.autoAddPhotosToPreferPrint(finalFaceId), "auto-add-print-" + newFaceId);
|
Thread thread = new Thread(() -> printerService.autoAddPhotosToPreferPrint(finalFaceId), "auto-add-print-" + newFaceId);
|
||||||
thread.start();
|
thread.start();
|
||||||
if (org.apache.commons.lang3.Strings.CI.equals("print", scene)) {
|
if (Strings.CI.equals("print", scene)) {
|
||||||
try {
|
try {
|
||||||
thread.join();
|
thread.join();
|
||||||
} catch (InterruptedException ignore) {
|
} catch (InterruptedException ignore) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (Strings.CI.equals("aiCam", scene)) {
|
||||||
|
faceDetectLogAiCamService.searchAndLog(scenicId, newFaceId, faceUrl, faceBodyAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
@@ -531,20 +536,29 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
List<SourceRespVO> sourceList = sourceMapper.queryByRelation(sourceReqQuery);
|
List<SourceRespVO> sourceList = sourceMapper.queryByRelation(sourceReqQuery);
|
||||||
ContentPageVO sourceVideoContent = new ContentPageVO();
|
ContentPageVO sourceVideoContent = new ContentPageVO();
|
||||||
ContentPageVO sourceImageContent = new ContentPageVO();
|
ContentPageVO sourceImageContent = new ContentPageVO();
|
||||||
|
ContentPageVO sourceAiCamContent = new ContentPageVO();
|
||||||
sourceVideoContent.setName("录像集");
|
sourceVideoContent.setName("录像集");
|
||||||
sourceImageContent.setName("照片集");
|
sourceImageContent.setName("照片集");
|
||||||
|
sourceAiCamContent.setName("AI微单");
|
||||||
sourceVideoContent.setSort(9999);
|
sourceVideoContent.setSort(9999);
|
||||||
sourceImageContent.setSort(9999);
|
sourceImageContent.setSort(9999);
|
||||||
|
sourceAiCamContent.setSort(9999);
|
||||||
sourceVideoContent.setScenicId(face.getScenicId());
|
sourceVideoContent.setScenicId(face.getScenicId());
|
||||||
sourceImageContent.setScenicId(face.getScenicId());
|
sourceImageContent.setScenicId(face.getScenicId());
|
||||||
|
sourceAiCamContent.setScenicId(face.getScenicId());
|
||||||
sourceVideoContent.setGoodsType(1);
|
sourceVideoContent.setGoodsType(1);
|
||||||
sourceImageContent.setGoodsType(2);
|
sourceImageContent.setGoodsType(2);
|
||||||
|
sourceAiCamContent.setGoodsType(3);
|
||||||
sourceVideoContent.setContentType(2);
|
sourceVideoContent.setContentType(2);
|
||||||
sourceImageContent.setContentType(2);
|
sourceImageContent.setContentType(2);
|
||||||
|
sourceAiCamContent.setContentType(2);
|
||||||
sourceVideoContent.setLockType(-1);
|
sourceVideoContent.setLockType(-1);
|
||||||
sourceImageContent.setLockType(-1);
|
sourceImageContent.setLockType(-1);
|
||||||
|
sourceAiCamContent.setLockType(-1);
|
||||||
sourceVideoContent.setGroup("直出原片");
|
sourceVideoContent.setGroup("直出原片");
|
||||||
sourceImageContent.setGroup("直出原片");
|
sourceImageContent.setGroup("直出原片");
|
||||||
|
sourceAiCamContent.setGroup("直出原片");
|
||||||
|
ScenicConfigManager configManager = scenicRepository.getScenicConfigManager(face.getScenicId());
|
||||||
if (!scenicConfigFacade.isDisableSourceImage(face.getScenicId())) {
|
if (!scenicConfigFacade.isDisableSourceImage(face.getScenicId())) {
|
||||||
IsBuyRespVO isBuyRespVO = orderBiz.isBuy(face.getScenicId(), userId, faceId, SourceType.IMAGE.getCode(), faceId);
|
IsBuyRespVO isBuyRespVO = orderBiz.isBuy(face.getScenicId(), userId, faceId, SourceType.IMAGE.getCode(), faceId);
|
||||||
sourceImageContent.setSourceType(isBuyRespVO.getGoodsType());
|
sourceImageContent.setSourceType(isBuyRespVO.getGoodsType());
|
||||||
@@ -583,18 +597,40 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
sourceVideoContent.setFreeCount((int) freeCount);
|
sourceVideoContent.setFreeCount((int) freeCount);
|
||||||
contentList.add(sourceVideoContent);
|
contentList.add(sourceVideoContent);
|
||||||
}
|
}
|
||||||
|
// AI微单:只有存在type=3的数据时才添加
|
||||||
|
boolean hasAiCam = sourceList.stream().anyMatch(source -> source.getType() == 3);
|
||||||
|
if (hasAiCam) {
|
||||||
|
IsBuyRespVO isBuyRespVO = orderBiz.isBuy(face.getScenicId(), userId, faceId, 13, faceId);
|
||||||
|
sourceAiCamContent.setSourceType(isBuyRespVO.getGoodsType());
|
||||||
|
sourceAiCamContent.setContentId(isBuyRespVO.getGoodsId());
|
||||||
|
if (isBuyRespVO.isBuy()) {
|
||||||
|
sourceAiCamContent.setIsBuy(1);
|
||||||
|
} else {
|
||||||
|
sourceAiCamContent.setIsBuy(0);
|
||||||
|
}
|
||||||
|
// AI微单有数据才显示,所以lockType固定为-1
|
||||||
|
sourceAiCamContent.setLockType(-1);
|
||||||
|
List<MemberSourceEntity> relations = memberRelationRepository.listSourceByFaceRelation(faceId, 3);
|
||||||
|
long freeCount = relations.stream().filter(entity -> Integer.valueOf(1).equals(entity.getIsFree())).count();
|
||||||
|
sourceAiCamContent.setFreeCount((int) freeCount);
|
||||||
|
contentList.add(sourceAiCamContent);
|
||||||
|
}
|
||||||
sourceList.stream().collect(Collectors.groupingBy(SourceRespVO::getType)).forEach((type, list) -> {
|
sourceList.stream().collect(Collectors.groupingBy(SourceRespVO::getType)).forEach((type, list) -> {
|
||||||
if (type == 1) {
|
if (type == 1) {
|
||||||
sourceVideoContent.setSourceType(1);
|
sourceVideoContent.setSourceType(1);
|
||||||
sourceVideoContent.setLockType(-1);
|
sourceVideoContent.setLockType(-1);
|
||||||
sourceVideoContent.setTemplateCoverUrl(list.getFirst().getUrl());
|
sourceVideoContent.setTemplateCoverUrl(list.getFirst().getUrl());
|
||||||
} else {
|
} else if (type == 2) {
|
||||||
sourceImageContent.setSourceType(2);
|
sourceImageContent.setSourceType(2);
|
||||||
sourceImageContent.setLockType(-1);
|
sourceImageContent.setLockType(-1);
|
||||||
sourceImageContent.setTemplateCoverUrl(list.getFirst().getUrl());
|
sourceImageContent.setTemplateCoverUrl(list.getFirst().getUrl());
|
||||||
if (Strings.isBlank(sourceVideoContent.getTemplateCoverUrl())) {
|
if (StringUtils.isBlank(sourceVideoContent.getTemplateCoverUrl())) {
|
||||||
sourceVideoContent.setTemplateCoverUrl(list.getFirst().getUrl());
|
sourceVideoContent.setTemplateCoverUrl(list.getFirst().getUrl());
|
||||||
}
|
}
|
||||||
|
} else if (type == 3) {
|
||||||
|
sourceAiCamContent.setSourceType(13);
|
||||||
|
sourceAiCamContent.setLockType(-1);
|
||||||
|
sourceAiCamContent.setTemplateCoverUrl(configManager.getString("ai_camera_cover_url"));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return contentList;
|
return contentList;
|
||||||
@@ -803,7 +839,7 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
String matchResult = face.getMatchResult();
|
String matchResult = face.getMatchResult();
|
||||||
if (matchResult == null || Strings.isBlank(matchResult)) {
|
if (matchResult == null || StringUtils.isBlank(matchResult)) {
|
||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(face.getScenicId());
|
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(face.getScenicId());
|
||||||
@@ -1009,7 +1045,7 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
handleCustomFaceMatching(faceId, finalSampleList);
|
handleCustomFaceMatching(faceId, finalSampleList);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Strings.isNotBlank(req.getRemark())) {
|
if (StringUtils.isNotBlank(req.getRemark())) {
|
||||||
log.info("人脸识别人工调整备注:faceId={}, remark={}", faceId, req.getRemark());
|
log.info("人脸识别人工调整备注:faceId={}, remark={}", faceId, req.getRemark());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1035,7 +1071,7 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
detail.setLastMatchedAt(face.getUpdateAt() != null ? face.getUpdateAt() : face.getCreateAt());
|
detail.setLastMatchedAt(face.getUpdateAt() != null ? face.getUpdateAt() : face.getCreateAt());
|
||||||
|
|
||||||
String matchResultJson = face.getMatchResult();
|
String matchResultJson = face.getMatchResult();
|
||||||
if (Strings.isBlank(matchResultJson)) {
|
if (StringUtils.isBlank(matchResultJson)) {
|
||||||
detail.setAcceptedSamples(Collections.emptyList());
|
detail.setAcceptedSamples(Collections.emptyList());
|
||||||
detail.setFilteredSamples(Collections.emptyList());
|
detail.setFilteredSamples(Collections.emptyList());
|
||||||
return detail;
|
return detail;
|
||||||
@@ -1155,7 +1191,7 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<Long> parseMatchSampleIds(String matchSampleIds) {
|
private List<Long> parseMatchSampleIds(String matchSampleIds) {
|
||||||
if (Strings.isBlank(matchSampleIds)) {
|
if (StringUtils.isBlank(matchSampleIds)) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
String[] segments = matchSampleIds.split(",");
|
String[] segments = matchSampleIds.split(",");
|
||||||
@@ -1170,7 +1206,7 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Long parseLongSilently(String value) {
|
private Long parseLongSilently(String value) {
|
||||||
if (Strings.isBlank(value)) {
|
if (StringUtils.isBlank(value)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -1222,10 +1258,10 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
if (sourceEntity == null) {
|
if (sourceEntity == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (!Strings.isBlank(sourceEntity.getThumbUrl())) {
|
if (!StringUtils.isBlank(sourceEntity.getThumbUrl())) {
|
||||||
return sourceEntity.getThumbUrl();
|
return sourceEntity.getThumbUrl();
|
||||||
}
|
}
|
||||||
if (!Strings.isBlank(sourceEntity.getUrl())) {
|
if (!StringUtils.isBlank(sourceEntity.getUrl())) {
|
||||||
return sourceEntity.getUrl();
|
return sourceEntity.getUrl();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -177,6 +177,9 @@ public class OrderServiceImpl implements OrderService {
|
|||||||
} else if (Integer.valueOf(2).equals(orderItemList.getFirst().getGoodsType())) {
|
} else if (Integer.valueOf(2).equals(orderItemList.getFirst().getGoodsType())) {
|
||||||
item.setGoodsName("照片集");
|
item.setGoodsName("照片集");
|
||||||
item.setOrderType("照片集");
|
item.setOrderType("照片集");
|
||||||
|
} else if (Integer.valueOf(3).equals(orderItemList.getFirst().getGoodsType())) {
|
||||||
|
item.setGoodsName("AI微单");
|
||||||
|
item.setOrderType("AI微单");
|
||||||
} else if (Integer.valueOf(0).equals(orderItemList.getFirst().getGoodsType())) {
|
} else if (Integer.valueOf(0).equals(orderItemList.getFirst().getGoodsType())) {
|
||||||
item.setOrderType("旅行Vlog");
|
item.setOrderType("旅行Vlog");
|
||||||
item.setGoodsName(orderItemList.getFirst().getGoodsName());
|
item.setGoodsName(orderItemList.getFirst().getGoodsName());
|
||||||
@@ -237,6 +240,9 @@ public class OrderServiceImpl implements OrderService {
|
|||||||
} else if (Integer.valueOf(2).equals(orderItemList.getFirst().getGoodsType())) {
|
} else if (Integer.valueOf(2).equals(orderItemList.getFirst().getGoodsType())) {
|
||||||
item.setGoodsName("照片集");
|
item.setGoodsName("照片集");
|
||||||
item.setOrderType("照片集");
|
item.setOrderType("照片集");
|
||||||
|
} else if (Integer.valueOf(3).equals(orderItemList.getFirst().getGoodsType())) {
|
||||||
|
item.setGoodsName("AI微单");
|
||||||
|
item.setOrderType("AI微单");
|
||||||
} else if (Integer.valueOf(0).equals(orderItemList.getFirst().getGoodsType())) {
|
} else if (Integer.valueOf(0).equals(orderItemList.getFirst().getGoodsType())) {
|
||||||
item.setOrderType("旅行Vlog");
|
item.setOrderType("旅行Vlog");
|
||||||
item.setGoodsName(orderItemList.getFirst().getGoodsName());
|
item.setGoodsName(orderItemList.getFirst().getGoodsName());
|
||||||
@@ -940,11 +946,13 @@ public class OrderServiceImpl implements OrderService {
|
|||||||
case PHOTO_SET -> 2;
|
case PHOTO_SET -> 2;
|
||||||
case VLOG_VIDEO -> 0;
|
case VLOG_VIDEO -> 0;
|
||||||
case RECORDING_SET -> 1;
|
case RECORDING_SET -> 1;
|
||||||
|
case AI_CAM_PHOTO_SET -> 13;
|
||||||
default -> 0;
|
default -> 0;
|
||||||
};
|
};
|
||||||
Long goodsId = switch (productItem.getProductType()) {
|
Long goodsId = switch (productItem.getProductType()) {
|
||||||
case PHOTO_LOG -> Long.valueOf(productItem.getProductId());
|
case PHOTO_LOG -> Long.valueOf(productItem.getProductId());
|
||||||
case PHOTO_SET, RECORDING_SET -> face.getId();
|
case PHOTO_SET, RECORDING_SET -> face.getId();
|
||||||
|
case AI_CAM_PHOTO_SET -> face.getId();
|
||||||
case VLOG_VIDEO -> {
|
case VLOG_VIDEO -> {
|
||||||
List<MemberVideoEntity> videos = memberRelationRepository.listRelationByFaceAndTemplate(face.getId(), Long.valueOf(productItem.getProductId()));
|
List<MemberVideoEntity> videos = memberRelationRepository.listRelationByFaceAndTemplate(face.getId(), Long.valueOf(productItem.getProductId()));
|
||||||
yield videos.getFirst().getVideoId();
|
yield videos.getFirst().getVideoId();
|
||||||
|
|||||||
@@ -2,7 +2,16 @@
|
|||||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
<mapper namespace="com.ycwl.basic.mapper.FaceDetectLogAiCamMapper">
|
<mapper namespace="com.ycwl.basic.mapper.FaceDetectLogAiCamMapper">
|
||||||
<insert id="add" useGeneratedKeys="true" keyProperty="id">
|
<insert id="add" useGeneratedKeys="true" keyProperty="id">
|
||||||
insert into face_detect_log_ai_cam(scenic_id, device_id, face_sample_id, db_name, face_url, score, match_raw_result, create_time)
|
insert into face_detect_log_ai_cam(scenic_id, device_id, face_id, db_name, face_url, score, match_raw_result, create_time)
|
||||||
values (#{scenicId}, #{deviceId}, #{faceSampleId}, #{dbName}, #{faceUrl}, #{score}, #{matchRawResult}, #{createTime})
|
values (#{scenicId}, #{deviceId}, #{faceId}, #{dbName}, #{faceUrl}, #{score}, #{matchRawResult}, #{createTime})
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
|
<select id="listByFaceId" resultType="com.ycwl.basic.model.pc.faceDetectLog.entity.FaceDetectLogAiCamEntity">
|
||||||
|
select id, scenic_id as scenicId, device_id as deviceId, face_id as faceId,
|
||||||
|
db_name as dbName, face_url as faceUrl, score, match_raw_result as matchRawResult,
|
||||||
|
create_time as createTime
|
||||||
|
from face_detect_log_ai_cam
|
||||||
|
where face_id = #{faceId}
|
||||||
|
order by create_time desc
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
@@ -486,4 +486,19 @@
|
|||||||
</choose>
|
</choose>
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="listByFaceSampleIdsAndType" resultType="com.ycwl.basic.model.pc.source.entity.SourceEntity">
|
||||||
|
SELECT * FROM source
|
||||||
|
WHERE face_sample_id IN
|
||||||
|
<foreach collection="faceSampleIds" item="item" open="(" separator="," close=")">
|
||||||
|
#{item}
|
||||||
|
</foreach>
|
||||||
|
AND `type` = #{type}
|
||||||
|
ORDER BY create_time DESC
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<delete id="deleteRelationsByFaceIdAndType">
|
||||||
|
DELETE FROM member_source
|
||||||
|
WHERE face_id = #{faceId} AND `type` = #{type}
|
||||||
|
</delete>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
Reference in New Issue
Block a user