Compare commits

...

4 Commits

Author SHA1 Message Date
f87a4f2311 refactor(video): 移除模板占位符检查逻辑
All checks were successful
ZhenTu-BE/pipeline/head This commit looks good
- 删除了模板占位符验证相关代码
- 简化了设备计数逻辑
- 移除了不必要的模板占位符列表操作
2026-02-24 17:07:16 +08:00
47ae60b203 feat(task): 更新日期时间格式为包含时分显示
All checks were successful
ZhenTu-BE/pipeline/head This commit looks good
- 修改DownloadNotificationTasker中的videoShotTime格式为yyyy-MM-dd HH:mm
- 修改DownloadNotificationTasker中的expireDate格式为yyyy-MM-dd HH:mm
- 修改SourceNotificationTasker中的sourceVideoCreateTime格式为yyyy-MM-dd HH:mm
- 修改SourceNotificationTasker中的sourcePhotoCreateTime格式为yyyy-MM-dd HH:mm
2026-02-24 16:53:34 +08:00
703a5baf13 refactor(thread): 使用 threadId 替换 getId 方法
- 将 ai-cam-image-processor 线程命名中的 thread.getId() 替换为 thread.threadId()
- 将视频片段获取任务中的 Thread.currentThread().getId() 替换为 Thread.currentThread().threadId()
- 统一使用 threadId 方法提高代码一致性
- 保持线程标识符的唯一性和可读性
2026-02-24 14:30:31 +08:00
7454111615 feat(puzzle): 更新拼图生成中的日期显示逻辑
- 在PuzzleGenerationOrchestrator中注入SourceMapper依赖
- 新增getMaxCreateTimeByFaceId方法查询图片素材最大创建时间
- 修改拼图模板生成逻辑使用图片素材最大创建时间作为dateStr值
- 移除硬编码当前日期,改为基于实际素材时间
- 更新FaceMatchingOrchestrator中相同的日期处理逻辑
- 从跳过重复检测的元素键集合中移除dateStr字段
2026-02-20 20:11:11 +08:00
10 changed files with 37 additions and 15 deletions

View File

@@ -2,6 +2,7 @@ package com.ycwl.basic.face.pipeline.helper;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO; import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
import com.ycwl.basic.mapper.SourceMapper;
import com.ycwl.basic.puzzle.dto.PuzzleGenerateRequest; import com.ycwl.basic.puzzle.dto.PuzzleGenerateRequest;
import com.ycwl.basic.puzzle.dto.PuzzleGenerateResponse; import com.ycwl.basic.puzzle.dto.PuzzleGenerateResponse;
import com.ycwl.basic.puzzle.dto.PuzzleTemplateDTO; import com.ycwl.basic.puzzle.dto.PuzzleTemplateDTO;
@@ -44,6 +45,9 @@ public class PuzzleGenerationOrchestrator {
@Autowired @Autowired
private ScenicRepository scenicRepository; private ScenicRepository scenicRepository;
@Autowired
private SourceMapper sourceMapper;
/** /**
* 异步生成景区所有启用的拼图模板 * 异步生成景区所有启用的拼图模板
* *
@@ -74,6 +78,11 @@ public class PuzzleGenerationOrchestrator {
// 3. 准备公共动态数据 // 3. 准备公共动态数据
Map<String, String> baseDynamicData = buildBaseDynamicData(faceId, faceUrl, scenicBasic); Map<String, String> baseDynamicData = buildBaseDynamicData(faceId, faceUrl, scenicBasic);
// 4. 设置dateStr为图片素材的最大创建时间
Date maxCreateTime = sourceMapper.getMaxCreateTimeByFaceId(faceId);
baseDynamicData.put("dateStr", DateUtil.format(
maxCreateTime != null ? maxCreateTime : new Date(), "yyyy.MM.dd"));
// 4. 使用虚拟线程池并行生成所有模板 // 4. 使用虚拟线程池并行生成所有模板
java.util.concurrent.atomic.AtomicInteger successCount = new java.util.concurrent.atomic.AtomicInteger(0); java.util.concurrent.atomic.AtomicInteger successCount = new java.util.concurrent.atomic.AtomicInteger(0);
java.util.concurrent.atomic.AtomicInteger failCount = new java.util.concurrent.atomic.AtomicInteger(0); java.util.concurrent.atomic.AtomicInteger failCount = new java.util.concurrent.atomic.AtomicInteger(0);
@@ -121,7 +130,6 @@ public class PuzzleGenerationOrchestrator {
baseDynamicData.put("faceId", String.valueOf(faceId)); baseDynamicData.put("faceId", String.valueOf(faceId));
baseDynamicData.put("scenicName", scenicBasic.getName()); baseDynamicData.put("scenicName", scenicBasic.getName());
baseDynamicData.put("scenicText", scenicBasic.getName()); baseDynamicData.put("scenicText", scenicBasic.getName());
baseDynamicData.put("dateStr", DateUtil.format(new Date(), "yyyy.MM.dd"));
return baseDynamicData; return baseDynamicData;
} }

View File

@@ -143,6 +143,13 @@ public interface SourceMapper {
*/ */
List<Long> getDeviceIdsByFaceId(Long faceId); List<Long> getDeviceIdsByFaceId(Long faceId);
/**
* 获取faceId关联的图片素材的最大创建时间
* @param faceId 人脸ID
* @return 最大创建时间,无记录时返回null
*/
Date getMaxCreateTimeByFaceId(Long faceId);
/** /**
* 根据faceId和设备ID获取source * 根据faceId和设备ID获取source
* @param faceId 人脸ID * @param faceId 人脸ID

View File

@@ -25,7 +25,7 @@ import java.util.stream.Collectors;
@Component @Component
@RequiredArgsConstructor @RequiredArgsConstructor
public class PuzzleDuplicationDetector { public class PuzzleDuplicationDetector {
private final Set<String> skippedElementKeys = Set.of("dateStr"); private final Set<String> skippedElementKeys = Set.of();
private final PuzzleGenerationRecordMapper recordMapper; private final PuzzleGenerationRecordMapper recordMapper;
/** /**

View File

@@ -40,7 +40,7 @@ public class SourceRepository {
Runtime.getRuntime().availableProcessors(), Runtime.getRuntime().availableProcessors(),
runnable -> { runnable -> {
Thread thread = new Thread(runnable); Thread thread = new Thread(runnable);
thread.setName("ai-cam-image-processor-" + thread.getId()); thread.setName("ai-cam-image-processor-" + thread.threadId());
thread.setDaemon(true); thread.setDaemon(true);
return thread; return thread;
} }

View File

@@ -91,17 +91,13 @@ public class VideoTaskRepository {
return 1; return 1;
} }
AtomicInteger deviceCount = new AtomicInteger(); AtomicInteger deviceCount = new AtomicInteger();
List<String> templatePlaceholder = templateRepository.getTemplatePlaceholder(task.getTemplateId());
paramJson.entrySet().stream() paramJson.entrySet().stream()
.filter(entry -> StringUtils.isNumeric(entry.getKey())) .filter(entry -> StringUtils.isNumeric(entry.getKey()))
.forEach(entry -> { .forEach(entry -> {
List<Object> jsonArray = JacksonUtil.parseArray(JacksonUtil.toJSONString(entry.getValue()), Object.class); List<Object> jsonArray = JacksonUtil.parseArray(JacksonUtil.toJSONString(entry.getValue()), Object.class);
if (jsonArray != null && !jsonArray.isEmpty()) { if (jsonArray != null && !jsonArray.isEmpty()) {
for (Object ignored : jsonArray) { for (Object ignored : jsonArray) {
if (templatePlaceholder.contains(entry.getKey())) { deviceCount.getAndIncrement();
deviceCount.getAndIncrement();
templatePlaceholder.remove(entry.getKey());
}
} }
} }
}); });

View File

@@ -405,7 +405,9 @@ public class FaceMatchingOrchestrator {
baseDynamicData.put("faceId", String.valueOf(faceId)); baseDynamicData.put("faceId", String.valueOf(faceId));
baseDynamicData.put("scenicName", scenicBasic.getName()); baseDynamicData.put("scenicName", scenicBasic.getName());
baseDynamicData.put("scenicText", scenicBasic.getName()); baseDynamicData.put("scenicText", scenicBasic.getName());
baseDynamicData.put("dateStr", DateUtil.format(new Date(), "yyyy.MM.dd")); Date maxCreateTime = sourceMapper.getMaxCreateTimeByFaceId(faceId);
baseDynamicData.put("dateStr", DateUtil.format(
maxCreateTime != null ? maxCreateTime : new Date(), "yyyy.MM.dd"));
templateList templateList
.forEach(template -> { .forEach(template -> {

View File

@@ -85,7 +85,7 @@ public class DownloadNotificationTasker {
} }
variables.put("videoDeviceCount", videoTaskRepository.getTaskDeviceNum(item.getTaskId())); variables.put("videoDeviceCount", videoTaskRepository.getTaskDeviceNum(item.getTaskId()));
variables.put("videoLensCount", videoTaskRepository.getTaskLensNum(item.getTaskId())); variables.put("videoLensCount", videoTaskRepository.getTaskLensNum(item.getTaskId()));
variables.put("videoShotTime", DateUtil.format(videoTaskRepository.getTaskShotDate(item.getTaskId()), "yyyy-MM-dd")); variables.put("videoShotTime", DateUtil.format(videoTaskRepository.getTaskShotDate(item.getTaskId()), "yyyy-MM-dd HH:mm"));
WechatSubscribeNotifyTriggerRequest request = WechatSubscribeNotifyTriggerRequest.builder() WechatSubscribeNotifyTriggerRequest request = WechatSubscribeNotifyTriggerRequest.builder()
.scenicId(item.getScenicId()) .scenicId(item.getScenicId())
.memberId(item.getMemberId()) .memberId(item.getMemberId())
@@ -137,7 +137,7 @@ public class DownloadNotificationTasker {
} else { } else {
variables.put("videoResultPage", "videoSynthesis"); variables.put("videoResultPage", "videoSynthesis");
} }
variables.put("expireDate", DateUtil.format(expireDate, "yyyy-MM-dd")); variables.put("expireDate", DateUtil.format(expireDate, "yyyy-MM-dd HH:mm"));
variables.put("videoDeviceCount", videoTaskRepository.getTaskDeviceNum(item.getTaskId())); variables.put("videoDeviceCount", videoTaskRepository.getTaskDeviceNum(item.getTaskId()));
variables.put("videoLensCount", videoTaskRepository.getTaskLensNum(item.getTaskId())); variables.put("videoLensCount", videoTaskRepository.getTaskLensNum(item.getTaskId()));
variables.put("videoShotTime", DateUtil.format(videoTaskRepository.getTaskShotDate(item.getTaskId()), "yyyy-MM-dd HH:mm")); variables.put("videoShotTime", DateUtil.format(videoTaskRepository.getTaskShotDate(item.getTaskId()), "yyyy-MM-dd HH:mm"));
@@ -191,7 +191,7 @@ public class DownloadNotificationTasker {
} else { } else {
variables.put("videoResultPage", "videoSynthesis"); variables.put("videoResultPage", "videoSynthesis");
} }
variables.put("expireDate", DateUtil.format(expireDate, "yyyy-MM-dd")); variables.put("expireDate", DateUtil.format(expireDate, "yyyy-MM-dd HH:mm"));
variables.put("videoDeviceCount", videoTaskRepository.getTaskDeviceNum(item.getTaskId())); variables.put("videoDeviceCount", videoTaskRepository.getTaskDeviceNum(item.getTaskId()));
variables.put("videoLensCount", videoTaskRepository.getTaskLensNum(item.getTaskId())); variables.put("videoLensCount", videoTaskRepository.getTaskLensNum(item.getTaskId()));
variables.put("videoShotTime", DateUtil.format(videoTaskRepository.getTaskShotDate(item.getTaskId()), "yyyy-MM-dd HH:mm")); variables.put("videoShotTime", DateUtil.format(videoTaskRepository.getTaskShotDate(item.getTaskId()), "yyyy-MM-dd HH:mm"));

View File

@@ -64,10 +64,10 @@ public class SourceNotificationTasker {
variables.put("faceId", item.getId()); variables.put("faceId", item.getId());
List<MemberSourceEntity> sourceVideoList = memberRelationRepository.listSourceByFaceRelation(item.getId(), 1); List<MemberSourceEntity> sourceVideoList = memberRelationRepository.listSourceByFaceRelation(item.getId(), 1);
variables.put("sourceVideoCount", sourceVideoList.size()); variables.put("sourceVideoCount", sourceVideoList.size());
variables.put("sourceVideoCreateTime", DateUtil.format(item.getCreateAt(), "yyyy-MM-dd")); variables.put("sourceVideoCreateTime", DateUtil.format(item.getCreateAt(), "yyyy-MM-dd HH:mm"));
List<MemberSourceEntity> sourcePhotoList = memberRelationRepository.listSourceByFaceRelation(item.getId(), 2); List<MemberSourceEntity> sourcePhotoList = memberRelationRepository.listSourceByFaceRelation(item.getId(), 2);
variables.put("sourcePhotoCount", sourcePhotoList.size()); variables.put("sourcePhotoCount", sourcePhotoList.size());
variables.put("sourcePhotoCreateTime", DateUtil.format(item.getCreateAt(), "yyyy-MM-dd")); variables.put("sourcePhotoCreateTime", DateUtil.format(item.getCreateAt(), "yyyy-MM-dd HH:mm"));
WechatSubscribeNotifyTriggerRequest request = WechatSubscribeNotifyTriggerRequest.builder() WechatSubscribeNotifyTriggerRequest request = WechatSubscribeNotifyTriggerRequest.builder()
.scenicId(item.getScenicId()) .scenicId(item.getScenicId())

View File

@@ -342,7 +342,7 @@ public class VideoPieceGetter {
ffmpegTask.setDuration(duration); ffmpegTask.setDuration(duration);
ffmpegTask.setOffsetStart(BigDecimal.valueOf(offset, 3)); ffmpegTask.setOffsetStart(BigDecimal.valueOf(offset, 3));
// 使用时间戳和线程ID确保输出文件名唯一性,避免并发冲突 // 使用时间戳和线程ID确保输出文件名唯一性,避免并发冲突
String uniqueSuffix = System.currentTimeMillis() + "_" + Thread.currentThread().getId(); String uniqueSuffix = System.currentTimeMillis() + "_" + Thread.currentThread().threadId();
File outFile = new File(deviceId.toString() + "_" + faceSampleId + "_" + uniqueSuffix + ".mp4"); File outFile = new File(deviceId.toString() + "_" + faceSampleId + "_" + uniqueSuffix + ".mp4");
ffmpegTask.setOutputFile(outFile.getAbsolutePath()); ffmpegTask.setOutputFile(outFile.getAbsolutePath());
boolean result = startFfmpegTask(ffmpegTask); boolean result = startFfmpegTask(ffmpegTask);

View File

@@ -464,6 +464,15 @@
ORDER BY s.device_id ASC ORDER BY s.device_id ASC
</select> </select>
<select id="getMaxCreateTimeByFaceId" resultType="java.util.Date">
SELECT MAX(s.create_time)
FROM member_source ms
INNER JOIN source s ON ms.source_id = s.id
WHERE ms.face_id = #{faceId}
AND s.type = 2
AND ms.deleted = 0
</select>
<select id="getSourceByFaceAndDeviceId" resultType="com.ycwl.basic.model.pc.source.entity.SourceEntity"> <select id="getSourceByFaceAndDeviceId" resultType="com.ycwl.basic.model.pc.source.entity.SourceEntity">
SELECT s.* SELECT s.*
FROM source s FROM source s