You've already forked FrameTour-BE
feat(puzzle): 实现人脸匹配后异步生成拼图模板功能
- 移除查询规则时的景区ID参数,简化规则加载逻辑 - 为人脸匹配编排器添加拼图模板服务依赖 - 新增异步生成拼图模板方法,在人脸识别成功后触发 - 优化Mapper接口,添加@Mapper注解并移除冗余查询方法 - 更新文档说明,同步修改规则查询方式描述 - 清理SourceMapper中重复的deleted条件过滤逻辑
This commit is contained in:
@@ -1,4 +1,13 @@
|
||||
package com.ycwl.basic.service.pc.orchestrator;
|
||||
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
|
||||
import com.ycwl.basic.puzzle.dto.PuzzleGenerateRequest;
|
||||
import com.ycwl.basic.puzzle.dto.PuzzleGenerateResponse;
|
||||
import com.ycwl.basic.puzzle.dto.PuzzleTemplateDTO;
|
||||
import com.ycwl.basic.puzzle.service.IPuzzleGenerateService;
|
||||
import com.ycwl.basic.puzzle.service.IPuzzleTemplateService;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.ycwl.basic.biz.OrderBiz;
|
||||
import com.ycwl.basic.exception.BaseException;
|
||||
@@ -79,6 +88,10 @@ public class FaceMatchingOrchestrator {
|
||||
private BuyStatusProcessor buyStatusProcessor;
|
||||
@Autowired
|
||||
private VideoRecreationHandler videoRecreationHandler;
|
||||
@Autowired
|
||||
private IPuzzleTemplateService puzzleTemplateService;
|
||||
@Autowired
|
||||
private IPuzzleGenerateService puzzleGenerateService;
|
||||
|
||||
/**
|
||||
* 编排人脸匹配的完整流程
|
||||
@@ -106,7 +119,7 @@ public class FaceMatchingOrchestrator {
|
||||
SearchFaceRespVo searchResult = executeFaceRecognition(context);
|
||||
if (searchResult == null) {
|
||||
log.warn("人脸识别返回结果为空,faceId={}", faceId);
|
||||
throw new BaseException("人脸识别失败,请换一张试试把~");
|
||||
throw new BaseException("人脸识别失败,请换一张试试把~");
|
||||
}
|
||||
|
||||
// 执行补救逻辑
|
||||
@@ -119,6 +132,9 @@ public class FaceMatchingOrchestrator {
|
||||
// 步骤4-6: 处理源文件关联和业务逻辑
|
||||
processSourceRelations(context, searchResult, faceId, isNew);
|
||||
|
||||
// 步骤7: 异步生成拼图模板
|
||||
asyncGeneratePuzzleTemplate(context.face.getScenicId(), faceId, context.face.getMemberId());
|
||||
|
||||
return searchResult;
|
||||
|
||||
} catch (BaseException e) {
|
||||
@@ -321,6 +337,85 @@ public class FaceMatchingOrchestrator {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 步骤8: 异步生成拼图模板
|
||||
* 在人脸匹配完成后,异步为该景区的所有启用的拼图模板生成图片
|
||||
*/
|
||||
private void asyncGeneratePuzzleTemplate(Long scenicId, Long faceId, Long memberId) {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
log.info("开始异步生成景区拼图模板: scenicId={}, faceId={}", scenicId, faceId);
|
||||
|
||||
// 查询该景区所有启用状态的拼图模板
|
||||
List<PuzzleTemplateDTO> templateList = puzzleTemplateService.listTemplates(
|
||||
scenicId, null, 1); // 查询启用状态的模板
|
||||
|
||||
if (templateList == null || templateList.isEmpty()) {
|
||||
log.info("景区不存在启用的拼图模板,跳过生成: scenicId={}", scenicId);
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("景区存在 {} 个启用的拼图模板,开始逐个生成: scenicId={}", templateList.size(), scenicId);
|
||||
|
||||
// 获取人脸信息用于动态数据
|
||||
FaceEntity face = faceRepository.getFace(faceId);
|
||||
if (face == null) {
|
||||
log.warn("人脸信息不存在,无法生成拼图: faceId={}", faceId);
|
||||
return;
|
||||
}
|
||||
ScenicV2DTO scenicBasic = scenicRepository.getScenicBasic(face.getScenicId());
|
||||
// 准备公共动态数据
|
||||
Map<String, String> baseDynamicData = new HashMap<>();
|
||||
if (face.getFaceUrl() != null) {
|
||||
baseDynamicData.put("faceImage", face.getFaceUrl());
|
||||
baseDynamicData.put("userAvatar", face.getFaceUrl());
|
||||
}
|
||||
baseDynamicData.put("faceId", String.valueOf(faceId));
|
||||
baseDynamicData.put("scenicName", scenicBasic.getName());
|
||||
|
||||
// 遍历所有模板,逐个生成
|
||||
int successCount = 0;
|
||||
int failCount = 0;
|
||||
for (PuzzleTemplateDTO template : templateList) {
|
||||
try {
|
||||
log.info("开始生成拼图: scenicId={}, templateCode={}, templateName={}",
|
||||
scenicId, template.getCode(), template.getName());
|
||||
|
||||
// 构建生成请求
|
||||
PuzzleGenerateRequest generateRequest = new PuzzleGenerateRequest();
|
||||
generateRequest.setScenicId(scenicId);
|
||||
generateRequest.setUserId(memberId);
|
||||
generateRequest.setFaceId(faceId);
|
||||
generateRequest.setBusinessType("face_matching");
|
||||
generateRequest.setTemplateCode(template.getCode());
|
||||
generateRequest.setOutputFormat("PNG");
|
||||
generateRequest.setQuality(90);
|
||||
generateRequest.setDynamicData(new HashMap<>(baseDynamicData));
|
||||
|
||||
// 调用拼图生成服务
|
||||
PuzzleGenerateResponse response = puzzleGenerateService.generate(generateRequest);
|
||||
|
||||
log.info("拼图生成成功: scenicId={}, templateCode={}, imageUrl={}",
|
||||
scenicId, template.getCode(), response.getImageUrl());
|
||||
successCount++;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("拼图生成失败: scenicId={}, templateCode={}, templateName={}",
|
||||
scenicId, template.getCode(), template.getName(), e);
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
|
||||
log.info("景区拼图模板批量生成完成: scenicId={}, 总数={}, 成功={}, 失败={}",
|
||||
scenicId, templateList.size(), successCount, failCount);
|
||||
|
||||
} catch (Exception e) {
|
||||
// 异步任务失败不影响主流程,仅记录日志
|
||||
log.error("异步生成拼图模板失败: scenicId={}, faceId={}", scenicId, faceId, e);
|
||||
}
|
||||
}, "PuzzleTemplateGenerator-" + scenicId).start();
|
||||
}
|
||||
|
||||
/**
|
||||
* 匹配上下文
|
||||
* 封装匹配过程中需要的所有上下文信息
|
||||
|
||||
Reference in New Issue
Block a user