优化是否能生成判断逻辑

This commit is contained in:
2025-01-11 16:13:19 +08:00
parent ad9e91cd7a
commit 0d2c92e8e1
18 changed files with 150 additions and 77 deletions

View File

@@ -0,0 +1,436 @@
package com.ycwl.basic.service.task.impl;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.facebody.model.v20191230.AddFaceEntityRequest;
import com.aliyuncs.facebody.model.v20191230.AddFaceRequest;
import com.aliyuncs.facebody.model.v20191230.AddFaceResponse;
import com.aliyuncs.facebody.model.v20191230.CreateFaceDbRequest;
import com.aliyuncs.facebody.model.v20191230.DeleteFaceDbRequest;
import com.aliyuncs.facebody.model.v20191230.DeleteFaceEntityRequest;
import com.aliyuncs.facebody.model.v20191230.ListFaceDbsRequest;
import com.aliyuncs.facebody.model.v20191230.ListFaceDbsResponse;
import com.aliyuncs.facebody.model.v20191230.ListFaceEntitiesRequest;
import com.aliyuncs.facebody.model.v20191230.ListFaceEntitiesResponse;
import com.aliyuncs.facebody.model.v20191230.SearchFaceRequest;
import com.aliyuncs.facebody.model.v20191230.SearchFaceResponse;
import com.ycwl.basic.config.FaceDetectConfig;
import com.ycwl.basic.constant.FaceConstant;
import com.ycwl.basic.exception.BaseException;
import com.ycwl.basic.mapper.FaceDetectLogMapper;
import com.ycwl.basic.mapper.FaceMapper;
import com.ycwl.basic.mapper.FaceSampleMapper;
import com.ycwl.basic.mapper.ScenicMapper;
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
import com.ycwl.basic.model.pc.faceDetectLog.entity.FaceDetectLog;
import com.ycwl.basic.model.pc.faceDetectLog.resp.MatchLocalRecord;
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
import com.ycwl.basic.model.pc.faceSample.req.FaceSampleReqQuery;
import com.ycwl.basic.model.pc.faceSample.resp.FaceSampleRespVO;
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
import com.ycwl.basic.model.task.resp.AddFaceSampleRespVo;
import com.ycwl.basic.model.task.resp.SearchFaceRespVo;
import com.ycwl.basic.service.task.TaskFaceService;
import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.utils.StorageUtil;
import com.ycwl.basic.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.profile.DefaultProfile;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j
@Service
public class TaskFaceServiceImpl implements TaskFaceService {
@Autowired
private FaceMapper faceMapper;
@Autowired
private FaceSampleMapper faceSampleMapper;
@Autowired
private ScenicMapper scenicMapper;
@Autowired
private FaceDetectConfig faceDetectConfig;
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Autowired
private FaceDetectLogMapper logMapper;
private IAcsClient getClient() {
DefaultProfile profile = DefaultProfile.getProfile(
faceDetectConfig.getRegion(),faceDetectConfig.getAccessKeyId(), faceDetectConfig.getAccessKeySecret());
IAcsClient client = new DefaultAcsClient(profile);
return client;
}
@Override
public SearchFaceRespVo searchFace(Long faceId) {
FaceRespVO faceRespVO = faceMapper.getById(faceId);
SearchFaceRespVo respVo = searchFace(faceRespVO.getScenicId().toString(), faceRespVO.getFaceUrl());
if (respVo != null) {
FaceEntity faceEntity = new FaceEntity();
faceEntity.setId(faceId);
faceEntity.setMatchResult(respVo.getSearchResultJson());
faceEntity.setFirstMatchRate(BigDecimal.valueOf(respVo.getFirstMatchRate()));
faceEntity.setScore(respVo.getScore());
faceEntity.setMatchSampleIds(StringUtils.join(respVo.getSampleListIds(), ","));
faceMapper.update(faceEntity);
}
return respVo;
}
@Override
public SearchFaceRespVo searchFace(Long scenicId, String faceUrl) {
return searchFace(scenicId.toString(), faceUrl);
}
@Override
public SearchFaceRespVo searchFace(String dbName, String faceUrl) {
assureFaceDB(dbName);
IAcsClient client = getClient();
SearchFaceRequest request = new SearchFaceRequest();
request.setDbName(dbName);
request.setImageUrl(faceUrl);
request.setLimit(100);
request.setQualityScoreThreshold(60f);
FaceDetectLog log = FaceDetectLog.quickCreate("预留字段", request);
try {
SearchFaceResponse response = client.getAcsResponse(request);
log.fillResponse(response);
List<SearchFaceResponse.Data.MatchListItem> matchList = response.getData().getMatchList();
if (matchList.isEmpty()) {
return null;
}
SearchFaceRespVo respVo = new SearchFaceRespVo();
respVo.setScore(matchList.get(0).getQualitieScore());
respVo.setSearchResultJson(JSON.toJSONString(matchList.get(0)));
if (matchList.get(0).getFaceItems().isEmpty()) {
return respVo;
}
List<MatchLocalRecord> records = matchList.get(0).getFaceItems().stream()
.map(item -> {
MatchLocalRecord record = new MatchLocalRecord();
record.setIdStr(item.getExtraData());
record.setFaceSampleId(Long.parseLong(item.getExtraData()));
if (StringUtils.isNumeric(item.getDbName())) {
record.setFaceUrl(getFaceSampleUrl(record.getFaceSampleId()));
} else {
record.setFaceUrl(getFaceUrl(record.getFaceSampleId()));
}
record.setScore(item.getScore());
record.setConfidence(item.getConfidence());
return record;
})
.collect(Collectors.toList());
log.matchLocalRecord(records);
List<Long> faceSampleIds = records.stream()
.filter(record -> record.getScore() > 0.6)
.map(MatchLocalRecord::getFaceSampleId)
.collect(Collectors.toList());
respVo.setFirstMatchRate(matchList.get(0).getFaceItems().get(0).getScore());
respVo.setSampleListIds(faceSampleIds);
return respVo;
} catch (Exception e) {
log.setMatchRawResult("识别错误,错误为:["+e.getLocalizedMessage()+"]");
e.printStackTrace();
throw new BaseException(e.getMessage());
} finally {
logMapper.insert(log);
}
}
@Override
public AddFaceSampleRespVo addFaceSample(Long faceSampleId) {
FaceSampleRespVO faceSampleRespVO = faceSampleMapper.getById(faceSampleId);
String entityId = generateEntityId(faceSampleRespVO);
AddFaceSampleRespVo respVo = addFaceSample(faceSampleRespVO.getScenicId().toString(), entityId, faceSampleRespVO.getFaceUrl(), faceSampleId.toString());
FaceSampleEntity faceSampleEntity = new FaceSampleEntity();
faceSampleEntity.setId(faceSampleId);
faceSampleEntity.setScore(respVo.getScore());
faceSampleEntity.setUpdateAt(new Date());
faceSampleMapper.update(faceSampleEntity);
addFaceSampleUrlCache(faceSampleId, faceSampleRespVO.getFaceUrl());
return respVo;
}
@Override
public AddFaceSampleRespVo addFaceSample(String dbName, String entityId, String faceUrl, String extData) {
AddFaceEntityRequest request = new AddFaceEntityRequest();
request.setDbName(dbName);
request.setEntityId(entityId);
IAcsClient client = getClient();
try {
client.getAcsResponse(request);
} catch (ClientException e) {
return null;
}
AddFaceRequest addFaceRequest = new AddFaceRequest();
addFaceRequest.setDbName(dbName);
addFaceRequest.setEntityId(entityId);
addFaceRequest.setImageUrl(faceUrl);
addFaceRequest.setExtraData(extData);
AddFaceSampleRespVo respVo = new AddFaceSampleRespVo();
try {
AddFaceResponse acsResponse = client.getAcsResponse(addFaceRequest);
respVo.setScore(acsResponse.getData().getQualitieScore());
return respVo;
} catch (ClientException e) {
return null;
}
}
@Override
public void batchDeleteExpiredFace(Long scenicId) {
FaceSampleReqQuery query = new FaceSampleReqQuery();
query.setDeviceId(scenicId);
faceSampleMapper.list(query);
ScenicConfigEntity scenicConfig = scenicMapper.getConfig(scenicId);
if (scenicConfig == null) {
return;
}
Integer sampleStoreDay = scenicConfig.getSampleStoreDay();
if (sampleStoreDay == null) {
sampleStoreDay = 3;
}
Date thatDay = DateUtil.offsetDay(new Date(), -sampleStoreDay);
Date dayStart = DateUtil.beginOfDay(thatDay);
Date dayEnd = DateUtil.endOfDay(thatDay);
query.setStartTime(dayStart);
query.setEndTime(dayEnd);
IAcsClient client = getClient();
faceSampleMapper.list(query).forEach(faceSampleEntity -> {
String entityId = generateEntityId(faceSampleEntity);
DeleteFaceEntityRequest request = new DeleteFaceEntityRequest();
request.setDbName(scenicId.toString());
request.setEntityId(entityId);
try {
client.getAcsResponse(request);
} catch (ClientException e) {
return;
}
});
}
@Override
public void deleteFaceDB(String dbName) {
ListFaceEntitiesRequest request = new ListFaceEntitiesRequest();
request.setDbName(dbName);
request.setLimit(200);
IAcsClient client = getClient();
try {
while (true) {
ListFaceEntitiesResponse response = client.getAcsResponse(request);
if (response.getData().getTotalCount() == 0) {
break;
}
response.getData().getEntities().forEach(entity -> {
DeleteFaceEntityRequest deleteFaceEntityRequest = new DeleteFaceEntityRequest();
deleteFaceEntityRequest.setDbName(entity.getDbName());
deleteFaceEntityRequest.setEntityId(entity.getEntityId());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
client.getAcsResponse(deleteFaceEntityRequest);
} catch (ClientException e) {
log.error("删除人脸数据失败!", e);
}
});
}
DeleteFaceDbRequest deleteFaceDbRequest = new DeleteFaceDbRequest();
deleteFaceDbRequest.setName(dbName);
client.getAcsResponse(deleteFaceDbRequest);
removeFaceDBCache(dbName);
} catch (ClientException e) {
log.error("删除人脸数据库失败!", e);
}
}
@Override
public void createFaceDB(String dbName) {
try {
CreateFaceDbRequest request = new CreateFaceDbRequest();
request.setName(dbName);
IAcsClient client = getClient();
client.getAcsResponse(request);
addFaceDBCache(dbName);
} catch (ClientException e) {
log.error("阿里云添加人脸数据库失败!", e);
}
}
@Override
public void assureFaceDB(String dbName) {
if (redisTemplate.hasKey(FaceConstant.FACE_DB_NAME_PFX + dbName)) {
return;
}
try {
long offset = 0;
List<ListFaceDbsResponse.Data.DbListItem> dbList = new ArrayList<>();
IAcsClient client = getClient();
while (true) {
ListFaceDbsRequest request = new ListFaceDbsRequest();
request.setLimit(200L);
request.setOffset(offset);
ListFaceDbsResponse response = client.getAcsResponse(request);
List<ListFaceDbsResponse.Data.DbListItem> list = response.getData().getDbList();
if (list == null || list.isEmpty()) {
break;
} else {
dbList.addAll(list);
offset += list.size();
}
}
boolean mismatch;
if (dbList.isEmpty()) {
clearFaceDBCache();
mismatch = true;
} else {
mismatch = dbList.stream().peek(item -> {
redisTemplate.opsForValue().set(FaceConstant.FACE_DB_NAME_PFX + dbName, "1");
}).noneMatch(db -> db.getName().equals(dbName));
}
if (mismatch) {
createFaceDB(dbName);
}
} catch (ClientException e) {
log.error("阿里云确保人脸数据库失败!", e);
}
}
@Override
public String uploadFile(MultipartFile file, Long userId) {
if (file.isEmpty()) {
throw new RuntimeException("文件不存在!");
}
String originalFilename = file.getOriginalFilename();
//获取文件名后缀
String suffix = originalFilename.split("\\.")[1];
if ("Jpeg".equals(suffix)) {
suffix = "jpg";
}
//文件储存路径
String filePath = StorageUtil.joinPath("user-faces", DateUtils.format(new Date(),"yyyy-MM-dd"));
// 生成文件名
String fileName= userId + "." + suffix;
IStorageAdapter adapter = StorageFactory.use("faces");
try {
return adapter.uploadFile(file.getInputStream(), filePath, fileName);
} catch (IOException e) {
log.error("文件上传失败!", e);
return null;
}
}
@Override
public boolean deleteFaceSample(String dbName, String entityId) {
DeleteFaceEntityRequest deleteFaceEntityRequest = new DeleteFaceEntityRequest();
deleteFaceEntityRequest.setDbName(dbName);
deleteFaceEntityRequest.setEntityId(entityId);
try {
IAcsClient client = getClient();
client.getAcsResponse(deleteFaceEntityRequest);
return true;
} catch (ClientException e) {
log.error("删除人脸样本失败!", e);
return false;
}
}
public void addFaceDBCache(String dbName) {
redisTemplate.opsForValue().set(FaceConstant.FACE_DB_NAME_PFX + dbName, "1");
}
public Boolean removeFaceDBCache(String dbName) {
return redisTemplate.delete(FaceConstant.FACE_DB_NAME_PFX + dbName);
}
public Boolean clearFaceDBCache() {
return redisTemplate.delete(FaceConstant.FACE_DB_NAME_PFX + "*");
}
private static final String DATE_FORMAT="yyyyMMddHHmmssSSS";
public static String generateEntityId(FaceSampleEntity entity) {
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
String entityId = entity.getDeviceId().toString() + "_" + sdf.format(entity.getCreateAt());
return entityId;
}
public static String generateEntityId(FaceSampleRespVO entity) {
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
String entityId = entity.getDeviceId().toString() + "_" + sdf.format(entity.getCreateAt());
return entityId;
}
public String getFaceUrl(Long faceId) {
if (faceId == null) {
return null;
}
if (redisTemplate.hasKey(FaceConstant.FACE_USER_URL_PFX + faceId)) {
return redisTemplate.opsForValue().get(FaceConstant.FACE_USER_URL_PFX + faceId);
}
FaceRespVO faceRespVO = faceMapper.getById(faceId);
if (faceRespVO == null) {
return null;
}
String faceUrl = faceRespVO.getFaceUrl();
if (StringUtils.isNotBlank(faceUrl)) {
addFaceUrlCache(faceId, faceUrl);
}
return faceUrl;
}
public void addFaceUrlCache(Long faceId, String faceUrl) {
if (faceId == null) {
return;
}
if (StringUtils.isBlank(faceUrl)) {
return;
}
redisTemplate.opsForValue().set(FaceConstant.FACE_USER_URL_PFX + faceId, faceUrl, 3, TimeUnit.DAYS);
}
public String getFaceSampleUrl(Long faceSampleId) {
if (faceSampleId == null) {
return null;
}
if (redisTemplate.hasKey(FaceConstant.FACE_SAMPLE_URL_PFX + faceSampleId)) {
return redisTemplate.opsForValue().get(FaceConstant.FACE_SAMPLE_URL_PFX + faceSampleId);
}
FaceSampleRespVO faceSampleRespVO = faceSampleMapper.getById(faceSampleId);
if (faceSampleRespVO == null) {
return null;
}
String faceUrl = faceSampleRespVO.getFaceUrl();
if (StringUtils.isNotBlank(faceUrl)) {
addFaceSampleUrlCache(faceSampleId, faceUrl);
}
return faceUrl;
}
public void addFaceSampleUrlCache(Long faceSampleId, String faceUrl) {
if (faceSampleId == null) {
return;
}
if (StringUtils.isBlank(faceUrl)) {
return;
}
redisTemplate.opsForValue().set(FaceConstant.FACE_SAMPLE_URL_PFX + faceSampleId, faceUrl, 3, TimeUnit.DAYS);
}
}

View File

@@ -0,0 +1,521 @@
package com.ycwl.basic.service.task.impl;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ycwl.basic.biz.OrderBiz;
import com.ycwl.basic.biz.TemplateBiz;
import com.ycwl.basic.constant.TaskConstant;
import com.ycwl.basic.mapper.FaceMapper;
import com.ycwl.basic.mapper.FaceSampleMapper;
import com.ycwl.basic.mapper.MemberMapper;
import com.ycwl.basic.mapper.RenderWorkerMapper;
import com.ycwl.basic.mapper.SourceMapper;
import com.ycwl.basic.mapper.TaskMapper;
import com.ycwl.basic.mapper.TemplateMapper;
import com.ycwl.basic.mapper.VideoMapper;
import com.ycwl.basic.model.mobile.order.PriceObj;
import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
import com.ycwl.basic.model.pc.faceSample.resp.FaceSampleRespVO;
import com.ycwl.basic.model.pc.member.resp.MemberRespVO;
import com.ycwl.basic.model.pc.mp.MpConfigEntity;
import com.ycwl.basic.model.pc.renderWorker.entity.RenderWorkerEntity;
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
import com.ycwl.basic.model.pc.scenic.entity.ScenicEntity;
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
import com.ycwl.basic.model.pc.source.resp.SourceRespVO;
import com.ycwl.basic.model.pc.task.entity.TaskEntity;
import com.ycwl.basic.model.pc.task.req.TaskReqQuery;
import com.ycwl.basic.model.pc.task.resp.TaskRespVO;
import com.ycwl.basic.model.pc.template.entity.TemplateConfigEntity;
import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
import com.ycwl.basic.model.pc.video.entity.MemberVideoEntity;
import com.ycwl.basic.model.pc.video.entity.VideoEntity;
import com.ycwl.basic.model.task.req.ClientStatusReqVo;
import com.ycwl.basic.model.task.req.TaskReqVo;
import com.ycwl.basic.model.task.req.TaskSuccessReqVo;
import com.ycwl.basic.model.task.req.WorkerAuthReqVo;
import com.ycwl.basic.model.task.resp.TaskSyncRespVo;
import com.ycwl.basic.notify.NotifyFactory;
import com.ycwl.basic.notify.adapters.INotifyAdapter;
import com.ycwl.basic.notify.entity.NotifyContent;
import com.ycwl.basic.notify.enums.NotifyType;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.repository.VideoTaskRepository;
import com.ycwl.basic.service.task.TaskService;
import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.task.VideoPieceGetter;
import com.ycwl.basic.repository.TemplateRepository;
import com.ycwl.basic.utils.SnowFlakeUtil;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j
@Service
public class TaskTaskServiceImpl implements TaskService {
@Autowired
private TemplateMapper templateMapper;
@Autowired
private RenderWorkerMapper renderWorkerMapper;
@Autowired
private TaskMapper taskMapper;
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Autowired
private FaceMapper faceMapper;
@Autowired
private FaceSampleMapper faceSampleMapper;
@Autowired
private SourceMapper sourceMapper;
@Autowired
private VideoMapper videoMapper;
@Autowired
private TemplateRepository templateRepository;
@Autowired
private VideoTaskRepository videoTaskRepository;
@Autowired
private OrderBiz orderBiz;
@Autowired
private MemberMapper memberMapper;
@Autowired
private ScenicRepository scenicRepository;
@Autowired
private TemplateBiz templateBiz;
private RenderWorkerEntity getWorker(@NonNull WorkerAuthReqVo req) {
String accessKey = req.getAccessKey();
if (accessKey == null) {
return null;
}
RenderWorkerEntity worker = renderWorkerMapper.findByAccessKey(accessKey);
return worker;
}
@Override
public TaskSyncRespVo handleSyncTask(@NonNull TaskReqVo req) {
RenderWorkerEntity worker = getWorker(req);
if (worker == null) {
return null;
}
worker.setOnline(1);
worker.setName(null);
worker.setStatus(null);
// get status
ClientStatusReqVo clientStatus = req.getClientStatus();
if (clientStatus != null) {
// 临时这么用下
worker.setCpuCount(clientStatus.getCpu_count());
worker.setCpuUsage(clientStatus.getCpu_usage());
// 上报的是字节,存储的是兆
worker.setMemoryAvailable(clientStatus.getMemory_available().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING));
worker.setMemoryTotal(clientStatus.getMemory_total().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING));
worker.setPlatform(clientStatus.getPlatform());
worker.setRuntimeVersion(clientStatus.getRuntime_version());
worker.setSupportFeature(String.join(",", clientStatus.getSupport_feature()));
worker.setVersion(clientStatus.getVersion());
worker.setUpdateAt(new Date());
redisTemplate.opsForValue().set(TaskConstant.TASK_ONLINE_WORKER_KEY_PFX + worker.getId(), JSON.toJSONString(clientStatus), 60, TimeUnit.SECONDS);
}
renderWorkerMapper.update(worker);
TaskSyncRespVo resp = new TaskSyncRespVo();
// Template
List<TaskRespVO> taskList = taskMapper.selectNotRunning();
resp.setTasks(taskList);
taskList.forEach(task -> {
taskMapper.assignToWorker(task.getId(), worker.getId());
videoTaskRepository.clearTaskCache(task.getId());
});
// return Task
return resp;
}
@Override
public void createRenderTask(Long scenicId, Long templateId, Long faceId) {
// 有人脸,找视频
if (faceId == null) {
return;
}
boolean canGenerate = templateBiz.determineTemplateCanGenerate(templateId, faceId);
if (!canGenerate) {
return;
}
TemplateConfigEntity config = templateRepository.getTemplateConfig(templateId);
FaceRespVO faceRespVO = faceMapper.getById(faceId);
if (faceRespVO == null) {
return;
}
Map<String, List<SourceRespVO>> sourcesMap = Arrays.stream(faceRespVO.getMatchSampleIds().split(","))
.map(Long::valueOf)
.map(sampleId -> faceSampleMapper.getById(sampleId))
.filter(Objects::nonNull)
.map(FaceSampleRespVO::getSourceId)
.map(sourceId -> sourceMapper.getById(sourceId))
.collect(Collectors.groupingBy(item -> item.getDeviceId().toString()));
if (config != null) {
if (config.getMinimalPlaceholderFill() > sourcesMap.size()) {
throw new RuntimeException("请先游玩后在来生成吧~");
}
}
TaskEntity taskEntity = new TaskEntity();
taskEntity.setId(SnowFlakeUtil.getLongId());
taskEntity.setFaceId(faceId);
taskEntity.setTemplateId(templateId);
taskEntity.setScenicId(scenicId);
taskEntity.setTaskParams(JSON.toJSONString(sourcesMap));
taskEntity.setStatus(0);
taskMapper.add(taskEntity);
}
@Override
public TemplateRespVO workerGetTemplate(@NonNull Long templateId, @NonNull WorkerAuthReqVo req) {
if (templateId == null) {
return null;
}
RenderWorkerEntity worker = getWorker(req);
if (worker == null) {
return null;
}
return templateRepository.getTemplate(templateId);
}
@Override
public void taskStart(@NonNull Long taskId, @NonNull WorkerAuthReqVo req) {
TaskRespVO task = taskMapper.getById(taskId);
if (task == null) {
return;
}
RenderWorkerEntity worker = getWorker(req);
if (worker == null) {
return;
}
TaskEntity taskUpdate = new TaskEntity();
taskUpdate.setId(taskId);
taskUpdate.setWorkerId(worker.getId());
taskMapper.setStart(taskUpdate);
videoTaskRepository.clearTaskCache(taskUpdate.getId());
}
@Override
public void autoCreateTaskByFaceId(Long faceId) {
FaceRespVO faceRespVO = faceMapper.getById(faceId);
if (faceRespVO == null) {
return;
}
if (!StringUtils.isNotBlank(faceRespVO.getMatchSampleIds())) {
return;
}
List<FaceSampleEntity> faceSampleList = faceSampleMapper.listByIds(Arrays.stream(faceRespVO.getMatchSampleIds().split(",")).map(Long::valueOf).collect(Collectors.toList()));
if (faceSampleList.isEmpty()) {
return;
}
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(faceRespVO.getScenicId());
List<TemplateRespVO> templateList = templateRepository.getTemplateListByScenicId(faceRespVO.getScenicId());
if (templateList == null || templateList.isEmpty()) {
return;
}
if (Integer.valueOf(3).equals(scenicConfig.getBookRoutine())) {
templateList.forEach(template -> {
createTaskByFaceIdAndTempalteId(faceId, template.getId(), 1);
});
} else {
createTaskByFaceIdAndTempalteId(faceId, templateList.get(0).getId(), 1);
}
}
@Override
public void createTaskByFaceIdAndTempalteId(Long faceId, Long templateId) {
createTaskByFaceIdAndTempalteId(faceId, templateId, 0);
}
@Override
public void createTaskByFaceIdAndTempalteId(Long faceId, Long templateId, int automatic) {
FaceRespVO faceRespVO = faceMapper.getById(faceId);
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(faceRespVO.getScenicId());
List<FaceSampleEntity> faceSampleList = faceSampleMapper.listByIds(Arrays.stream(faceRespVO.getMatchSampleIds().split(",")).map(Long::valueOf).collect(Collectors.toList()));
if (faceSampleList.isEmpty()) {
return;
}
List<Long> faceSampleIds = faceSampleList.stream().map(FaceSampleEntity::getId).collect(Collectors.toList());
List<SourceEntity> sourceList = sourceMapper.listBySampleIds(faceSampleIds);
if (sourceList.isEmpty()) {
return;
}
if (automatic > 0) {
TaskReqQuery taskReqQuery = new TaskReqQuery();
taskReqQuery.setFaceId(faceId);
taskReqQuery.setTemplateId(templateId);
List<TaskRespVO> list = taskMapper.list(taskReqQuery);
if (!list.isEmpty()) {
list.parallelStream().forEach(task -> {
MemberVideoEntity memberVideo = videoMapper.queryRelationByMemberTask(faceRespVO.getMemberId(), task.getId());
if (memberVideo == null) {
memberVideo = new MemberVideoEntity();
memberVideo.setMemberId(faceRespVO.getMemberId());
memberVideo.setScenicId(task.getScenicId());
memberVideo.setFaceId(faceId);
memberVideo.setTemplateId(task.getTemplateId());
if (Integer.valueOf(1).equals(scenicConfig.getAllFree())) {
memberVideo.setIsBuy(1);
} else {
memberVideo.setIsBuy(0);
}
memberVideo.setTaskId(task.getId());
VideoEntity video = videoMapper.findByTaskId(task.getId());
if (video != null) {
memberVideo.setVideoId(video.getId());
}
videoMapper.addRelation(memberVideo);
new Thread(() -> {
sendVideoGeneratedServiceNotification(list.get(0).getId(), faceRespVO.getMemberId());
}).start();
}
});
return;
}
}
VideoPieceGetter.Task task = new VideoPieceGetter.Task();
task.faceId = faceId;
task.faceSampleIds = faceSampleIds;
task.memberId = faceRespVO.getMemberId();
task.callback = () -> {
boolean canGenerate = templateBiz.determineTemplateCanGenerate(templateId, faceId);
if (!canGenerate) {
return;
}
List<SourceEntity> videoSourceList = sourceMapper.listVideoByFaceRelation(faceId);
Map<String, List<SourceEntity>> sourcesMap = videoSourceList.stream()
.peek(item -> item.setUrl(item.getVideoUrl()))
.collect(Collectors.groupingBy(item -> item.getDeviceId().toString()));
TaskReqQuery taskReqQuery = new TaskReqQuery();
taskReqQuery.setFaceId(faceId);
taskReqQuery.setTemplateId(templateId);
taskReqQuery.setTaskParams(JSON.toJSONString(sourcesMap));
List<TaskRespVO> list = taskMapper.list(taskReqQuery);
MemberVideoEntity memberVideoEntity = new MemberVideoEntity();
memberVideoEntity.setMemberId(faceRespVO.getMemberId());
memberVideoEntity.setScenicId(faceRespVO.getScenicId());
memberVideoEntity.setFaceId(faceId);
memberVideoEntity.setTemplateId(templateId);
memberVideoEntity.setIsBuy(0);
if (list.isEmpty()) {
TaskEntity taskEntity = new TaskEntity();
taskEntity.setId(SnowFlakeUtil.getLongId());
taskEntity.setScenicId(faceRespVO.getScenicId());
taskEntity.setFaceId(faceId);
taskEntity.setTemplateId(templateId);
taskEntity.setStatus(0);
taskEntity.setAutomatic(automatic);
taskEntity.setTaskParams(JSON.toJSONString(sourcesMap));
taskMapper.add(taskEntity);
memberVideoEntity.setTaskId(taskEntity.getId());
} else{
memberVideoEntity.setTaskId(list.get(0).getId());
VideoEntity video = videoMapper.findByTaskId(list.get(0).getId());
if (video != null) {
PriceObj priceObj = orderBiz.queryPrice(list.get(0).getScenicId(), 0, video.getId());
if (priceObj.isFree()) {
memberVideoEntity.setIsBuy(1);
}
memberVideoEntity.setVideoId(video.getId());
// 已经生成了
new Thread(() -> {
sendVideoGeneratedServiceNotification(list.get(0).getId(), faceRespVO.getMemberId());
}).start();
}
}
videoMapper.addRelation(memberVideoEntity);
};
VideoPieceGetter.addTask(task);
}
@Override
public void taskSuccess(@NonNull Long taskId, @NonNull TaskSuccessReqVo req) {
TaskRespVO task = taskMapper.getById(taskId);
if (task == null) {
return;
}
RenderWorkerEntity worker = getWorker(req);
if (worker == null) {
return;
}
TaskEntity taskUpdate = new TaskEntity();
taskUpdate.setId(taskId);
taskUpdate.setStatus(1);
taskUpdate.setWorkerId(worker.getId());
taskMapper.setSuccess(taskUpdate);
videoTaskRepository.clearTaskCache(taskUpdate.getId());
VideoEntity video = videoMapper.findByTaskId(taskId);
if (video != null) {
video.setVideoUrl(task.getVideoUrl());
if (req.getVideoInfo() != null) {
video.setHeight(req.getVideoInfo().getHeight());
video.setWidth(req.getVideoInfo().getWidth());
video.setDuration(req.getVideoInfo().getDuration());
}
videoMapper.update(video);
} else {
video = new VideoEntity();
video.setId(SnowFlakeUtil.getLongId());
video.setScenicId(task.getScenicId());
video.setTemplateId(task.getTemplateId());
video.setTaskId(taskId);
video.setWorkerId(worker.getId());
video.setVideoUrl(task.getVideoUrl());
video.setCreateTime(new Date());
if (req.getVideoInfo() != null) {
video.setHeight(req.getVideoInfo().getHeight());
video.setWidth(req.getVideoInfo().getWidth());
video.setDuration(req.getVideoInfo().getDuration());
}
videoMapper.add(video);
}
int isBuy = 0;
PriceObj priceObj = orderBiz.queryPrice(task.getScenicId(), 0, video.getId());
if (priceObj.isFree()) {
isBuy = 1;
}
videoMapper.updateRelationWhenTaskSuccess(taskId, video.getId(), isBuy);
new Thread(() -> {
sendVideoGeneratedServiceNotification(taskId);
}).start();
}
@Override
public void taskFail(Long taskId, WorkerAuthReqVo req) {
TaskRespVO task = taskMapper.getById(taskId);
if (task == null) {
return;
}
RenderWorkerEntity worker = getWorker(req);
if (worker == null) {
return;
}
TaskEntity taskUpdate = new TaskEntity();
taskUpdate.setId(taskId);
taskUpdate.setStatus(2);
taskUpdate.setWorkerId(worker.getId());
taskMapper.setFail(taskUpdate);
taskMapper.deassign(taskId);
videoTaskRepository.clearTaskCache(taskUpdate.getId());
}
@Override
public String getUploadUrl(Long taskId, WorkerAuthReqVo req) {
TaskRespVO task = taskMapper.getById(taskId);
if (task == null) {
return null;
}
IStorageAdapter adapter = StorageFactory.use("video");
String filename = task.getId() + "_" + task.getScenicId() + ".mp4";
if (StringUtils.isBlank(task.getVideoUrl())) {
// 生成
String url = adapter.getUrl(filename);
TaskEntity updateTask = new TaskEntity();
updateTask.setId(taskId);
updateTask.setVideoUrl(url);
taskMapper.update(updateTask);
videoTaskRepository.clearTaskCache(updateTask.getId());
}
return adapter.getUrlForUpload(filename);
}
public void sendVideoGeneratedServiceNotification(Long taskId) {
List<MemberVideoEntity> memberVideo = videoMapper.listRelationByTask(taskId);
memberVideo.forEach(item -> {
sendVideoGeneratedServiceNotification(taskId, item.getMemberId());
});
}
@Override
public Date getTaskShotDate(Long taskId) {
TaskRespVO taskRespVO = taskMapper.getById(taskId);
if (taskRespVO == null) {
return null;
}
Date shotTime = taskRespVO.getCreateTime();
JSONObject paramJson = JSON.parseObject(taskRespVO.getTaskParams());
if (paramJson != null) {
Optional<String> any = paramJson.keySet().stream().filter(StringUtils::isNumeric).findAny();
if (any.isPresent()) {
JSONArray jsonArray = paramJson.getJSONArray(any.get());
if (!jsonArray.isEmpty()) {
JSONObject jsonObject = jsonArray.getJSONObject(0);
if (jsonObject.containsKey("createTime")) {
shotTime = new Date(jsonObject.getLong("createTime"));
}
}
}
}
return shotTime;
}
@Override
public void sendVideoGeneratedServiceNotification(Long taskId, Long memberId) {
MemberVideoEntity item = videoMapper.queryRelationByMemberTask(memberId, taskId);
MemberRespVO member = memberMapper.getById(memberId);
String openId = member.getOpenId();
MpConfigEntity scenicMp = scenicRepository.getScenicMpConfig(member.getScenicId());
if (StringUtils.isNotBlank(openId) && scenicMp != null) {
String templateId = scenicRepository.getVideoGeneratedTemplateId(item.getScenicId());
if (StringUtils.isBlank(templateId)) {
log.warn("未配置视频生成通知模板");
return;
}
ScenicEntity scenic = scenicRepository.getScenic(item.getScenicId());
String title = "您在【" + scenic.getName() + "】的影像";
String page = "pages/videoSynthesis/buy?scenicId=" + item.getScenicId() + "&faceId=" + item.getFaceId() + "&id=" + item.getVideoId();
/**
* 景点 {{thing5.DATA}}
* 视频名称 {{thing1.DATA}}
* 游玩时间 {{time2.DATA}}
* 生成时间 {{time4.DATA}}
* 备注 {{thing3.DATA}}
*/
Map<String, Object> params = new HashMap<>();
Map<String, Object> dataParam = new HashMap<>();
Map<String, String> scenicMap = new HashMap<>();
scenicMap.put("value", scenic.getName());
dataParam.put("thing5", scenicMap);
Map<String, String> videoMap = new HashMap<>();
TemplateRespVO template = templateRepository.getTemplate(item.getTemplateId());
videoMap.put("value", template.getName());
dataParam.put("thing1", videoMap);
Map<String, String> timeMap = new HashMap<>();
timeMap.put("value", DateUtil.format(getTaskShotDate(taskId), "yyyy-MM-dd"));
dataParam.put("time2", timeMap);
Map<String, String> timeMap2 = new HashMap<>();
timeMap2.put("value", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm"));
dataParam.put("time4", timeMap2);
Map<String, String> remarkMap = new HashMap<>();
remarkMap.put("value", "您的游玩Vlog已经等候多时,快来看看吧");
dataParam.put("thing3", remarkMap);
params.put("data", dataParam);
params.put("page", page);
params.put("template_id", templateId);
log.info("视频生成通知模板参数:{},用户ID:{}", params, openId);
INotifyAdapter adapter = NotifyFactory.get(NotifyType.WX_MP_SRV, scenicMp.toMap());
adapter.sendTo(new NotifyContent(title, page, params), openId);
}
}
}

View File

@@ -0,0 +1,31 @@
package com.ycwl.basic.service.task.impl;
import com.alibaba.fastjson.JSON;
import com.ycwl.basic.mapper.TemplateMapper;
import com.ycwl.basic.model.pc.template.entity.TemplateConfigEntity;
import com.ycwl.basic.service.task.TaskTemplateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
@Service
public class TaskTemplateServiceImpl implements TaskTemplateService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Autowired
private TemplateMapper templateMapper;
private static final String TEMPLATE_KEY = "template:";
private static final String TEMPLATE_CONFIG_KEY = "template:config:";
private TemplateConfigEntity getTemplateConfig(Long templateId) {
if (redisTemplate.hasKey(TEMPLATE_CONFIG_KEY + templateId)) {
return JSON.parseObject(redisTemplate.opsForValue().get(TEMPLATE_CONFIG_KEY + templateId), TemplateConfigEntity.class);
}
TemplateConfigEntity config = templateMapper.getConfig(templateId);
if (config != null) {
redisTemplate.opsForValue().set(TEMPLATE_CONFIG_KEY + templateId, JSON.toJSONString(config));
}
return config;
}
}