|
|
@ -0,0 +1,279 @@
|
|
|
|
|
|
|
|
package com.supervision.manage.service.impl;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import cn.hutool.core.codec.Base64;
|
|
|
|
|
|
|
|
import cn.hutool.core.io.FileUtil;
|
|
|
|
|
|
|
|
import cn.hutool.core.lang.Assert;
|
|
|
|
|
|
|
|
import cn.hutool.core.thread.ThreadUtil;
|
|
|
|
|
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
|
|
|
|
|
import cn.hutool.http.HttpUtil;
|
|
|
|
|
|
|
|
import cn.hutool.json.JSONUtil;
|
|
|
|
|
|
|
|
import com.supervision.enums.EnumMedicalRec;
|
|
|
|
|
|
|
|
import com.supervision.exception.BusinessException;
|
|
|
|
|
|
|
|
import com.supervision.manage.dto.HumanGenerateDTO;
|
|
|
|
|
|
|
|
import com.supervision.manage.service.FileManageService;
|
|
|
|
|
|
|
|
import com.supervision.manage.service.HumanManageService;
|
|
|
|
|
|
|
|
import com.supervision.model.AskPatientAnswer;
|
|
|
|
|
|
|
|
import com.supervision.model.FileResource;
|
|
|
|
|
|
|
|
import com.supervision.model.Human;
|
|
|
|
|
|
|
|
import com.supervision.model.MedicalRec;
|
|
|
|
|
|
|
|
import com.supervision.service.AskPatientAnswerService;
|
|
|
|
|
|
|
|
import com.supervision.service.HumanService;
|
|
|
|
|
|
|
|
import com.supervision.service.MedicalRecService;
|
|
|
|
|
|
|
|
import com.supervision.util.UserUtil;
|
|
|
|
|
|
|
|
import com.supervision.vo.manage.HumanReqVo;
|
|
|
|
|
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
|
|
|
|
|
import lombok.SneakyThrows;
|
|
|
|
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
|
|
|
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import java.io.File;
|
|
|
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
import java.util.concurrent.LinkedBlockingQueue;
|
|
|
|
|
|
|
|
import java.util.concurrent.ThreadPoolExecutor;
|
|
|
|
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Slf4j
|
|
|
|
|
|
|
|
@Service
|
|
|
|
|
|
|
|
@RequiredArgsConstructor
|
|
|
|
|
|
|
|
public class HumanManageServiceImpl implements HumanManageService {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final HumanService humanService;
|
|
|
|
|
|
|
|
private final FileManageService fileManageService;
|
|
|
|
|
|
|
|
private final MedicalRecService medicalRecService;
|
|
|
|
|
|
|
|
private final AskPatientAnswerService askPatientAnswerService;
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 创建一个线程池,本意是用来异步调用数字人使用的
|
|
|
|
|
|
|
|
* 核心线程数:2
|
|
|
|
|
|
|
|
* 最大线程数:5
|
|
|
|
|
|
|
|
* 队列长度:20
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
ThreadPoolExecutor humanExecutor = new ThreadPoolExecutor(2, 5,
|
|
|
|
|
|
|
|
60L, TimeUnit.MILLISECONDS,
|
|
|
|
|
|
|
|
new LinkedBlockingQueue<>(20), ThreadUtil.newNamedThreadFactory("human", true),
|
|
|
|
|
|
|
|
new ThreadPoolExecutor.CallerRunsPolicy());
|
|
|
|
|
|
|
|
@Value("${humanGenerate.baseUrl}")
|
|
|
|
|
|
|
|
private String humanBaseUrl;
|
|
|
|
|
|
|
|
@Value("${humanGenerate.silent}")
|
|
|
|
|
|
|
|
private String silent;
|
|
|
|
|
|
|
|
@Value("${humanGenerate.dynamic}")
|
|
|
|
|
|
|
|
private String dynamic;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
|
|
|
public void generateHuman(String humanId, String medicalId) throws Exception {
|
|
|
|
|
|
|
|
Human human = humanService.getOptById(humanId).orElseThrow(() -> new BusinessException("数字人形象不存在"));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
File imageFile = fileManageService.downloadFile(human.getImageFileId());
|
|
|
|
|
|
|
|
// 创建一个图片临时文件
|
|
|
|
|
|
|
|
log.info("提交文件生成,文件名:{}", FileUtil.getName(imageFile));
|
|
|
|
|
|
|
|
generateSilent(human, imageFile, medicalId);
|
|
|
|
|
|
|
|
generateDynamic(human, imageFile, medicalId);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
humanService.updateById(human);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public List<Human> queryHumanList() {
|
|
|
|
|
|
|
|
return humanService.lambdaQuery().orderBy(true, false, Human::getCreateTime).list();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public boolean createHuman(HumanReqVo humanReqVo) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Assert.notEmpty(humanReqVo.getImageFileId(), "图片不能为空");
|
|
|
|
|
|
|
|
Human human = new Human();
|
|
|
|
|
|
|
|
human.setImageName(humanReqVo.getImageName());
|
|
|
|
|
|
|
|
human.setImageFileId(humanReqVo.getImageFileId());
|
|
|
|
|
|
|
|
human.setDescription(humanReqVo.getDescription());
|
|
|
|
|
|
|
|
humanService.save(human);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 异步调用生成数字人
|
|
|
|
|
|
|
|
humanExecutor.submit(() -> {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
generateHuman(human.getId(), null);
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
|
|
log.error("createHuman:生成数字人异常", e);
|
|
|
|
|
|
|
|
throw new BusinessException("生成数字人异常");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public boolean updateHuman(HumanReqVo human) {
|
|
|
|
|
|
|
|
Assert.notEmpty(human.getId(), "数字人id不能为空");
|
|
|
|
|
|
|
|
Assert.notEmpty(human.getImageFileId(), "图片不能为空");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Human dbHuman = humanService.getById(human.getId());
|
|
|
|
|
|
|
|
Assert.notEmpty(dbHuman.getId(), "数字人不存在");
|
|
|
|
|
|
|
|
if (StrUtil.equals(dbHuman.getImageFileId(), human.getImageFileId())) {
|
|
|
|
|
|
|
|
// 只更新描述信息
|
|
|
|
|
|
|
|
humanService.lambdaUpdate().eq(Human::getId, human.getId())
|
|
|
|
|
|
|
|
.set(Human::getDescription, human.getDescription())
|
|
|
|
|
|
|
|
.set(Human::getImageName, human.getImageName())
|
|
|
|
|
|
|
|
.update();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// 更新数字人状态
|
|
|
|
|
|
|
|
dbHuman.setImageFileId(human.getImageFileId());
|
|
|
|
|
|
|
|
dbHuman.setSilentTaskUid(null);
|
|
|
|
|
|
|
|
dbHuman.setDynamicTaskUid(null);
|
|
|
|
|
|
|
|
dbHuman.setDynamicVideoFileId(null);
|
|
|
|
|
|
|
|
dbHuman.setSilentVideoFileId(null);
|
|
|
|
|
|
|
|
dbHuman.setStatus(2);
|
|
|
|
|
|
|
|
dbHuman.setDescription(human.getDescription());
|
|
|
|
|
|
|
|
humanService.updateById(dbHuman);
|
|
|
|
|
|
|
|
// 异步调用生成数字人
|
|
|
|
|
|
|
|
humanExecutor.submit(() -> {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
generateHuman(human.getId(), null);
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
|
|
log.error("createHuman:生成数字人异常", e);
|
|
|
|
|
|
|
|
throw new BusinessException("生成数字人异常");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public boolean deleteHuman(String id) {
|
|
|
|
|
|
|
|
Assert.notEmpty(id, "数字人id不能为空");
|
|
|
|
|
|
|
|
Long count = medicalRecService.lambdaQuery().eq(MedicalRec::getHumanId, id).count();
|
|
|
|
|
|
|
|
Assert.isTrue(count == 0, "该数字已被使用,不能删除");
|
|
|
|
|
|
|
|
return humanService.removeById(id);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void generateSilent(Human human, File imageFile, String medicalId) throws Exception {
|
|
|
|
|
|
|
|
if (StrUtil.isAllBlank(human.getSilentVideoFileId(), human.getSilentTaskUid())) {
|
|
|
|
|
|
|
|
HumanGenerateDTO silentDTO;
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
String post = HttpUtil.post(humanBaseUrl + silent, Map.of("image", imageFile));
|
|
|
|
|
|
|
|
silentDTO = JSONUtil.toBean(post, HumanGenerateDTO.class);
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
|
|
throw new BusinessException("生成数字人静态视频异常");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// 保存静态视频
|
|
|
|
|
|
|
|
if (silentDTO.getCode() == 200) {
|
|
|
|
|
|
|
|
if (StrUtil.isNotBlank(silentDTO.getVideo())) {
|
|
|
|
|
|
|
|
// 如果已经生成了视频,那么直接拿到这个视频
|
|
|
|
|
|
|
|
FileResource fileResource = convertBase64ToFile("silent", FileUtil.getName(imageFile), silentDTO.getVideo());
|
|
|
|
|
|
|
|
human.setSilentVideoFileId(fileResource.getId());
|
|
|
|
|
|
|
|
human.setImageName(fileResource.getFileName());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 诊断闻讯绑定静态视频
|
|
|
|
|
|
|
|
AskPatientAnswer askPatientAnswer = askPatientAnswerService.queryAnswerIdByMedicalId(medicalId, "静态视频");
|
|
|
|
|
|
|
|
AskPatientAnswer patientAnswer = new AskPatientAnswer();
|
|
|
|
|
|
|
|
patientAnswer.setId(askPatientAnswer.getId());
|
|
|
|
|
|
|
|
patientAnswer.setAnswerResourceId(fileResource.getId());
|
|
|
|
|
|
|
|
askPatientAnswerService.updateById(patientAnswer);
|
|
|
|
|
|
|
|
// 完成
|
|
|
|
|
|
|
|
MedicalRec medicalRec1 = new MedicalRec();
|
|
|
|
|
|
|
|
medicalRec1.setMedicalStatus(EnumMedicalRec.ESTABLISHED_RECORD.getCode());
|
|
|
|
|
|
|
|
medicalRec1.setId(medicalId);
|
|
|
|
|
|
|
|
medicalRecService.updateById(medicalRec1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
human.setSilentTaskUid(silentDTO.getUid());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void generateDynamic(Human human, File imageFile, String medicalId) throws Exception {
|
|
|
|
|
|
|
|
if (StrUtil.isAllBlank(human.getDynamicVideoFileId(), human.getDynamicTaskUid())) {
|
|
|
|
|
|
|
|
HumanGenerateDTO dynamicDTO;
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
String post = HttpUtil.post(humanBaseUrl + dynamic, Map.of("image", imageFile));
|
|
|
|
|
|
|
|
dynamicDTO = JSONUtil.toBean(post, HumanGenerateDTO.class);
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
|
|
throw new BusinessException("生成数字人动态视频异常");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (dynamicDTO.getCode() == 200) {
|
|
|
|
|
|
|
|
if (StrUtil.isNotBlank(dynamicDTO.getVideo())) {
|
|
|
|
|
|
|
|
// 如果已经生成了视频,那么直接拿到这个视频
|
|
|
|
|
|
|
|
FileResource fileResource = convertBase64ToFile("dynamic", FileUtil.getName(imageFile), dynamicDTO.getVideo());
|
|
|
|
|
|
|
|
human.setDynamicVideoFileId(fileResource.getId());
|
|
|
|
|
|
|
|
human.setImageName(fileResource.getFileName());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 诊断闻讯绑定动态视频
|
|
|
|
|
|
|
|
AskPatientAnswer askPatientAnswer = askPatientAnswerService.queryAnswerIdByMedicalId(medicalId, "动态视频");
|
|
|
|
|
|
|
|
AskPatientAnswer patientAnswer = new AskPatientAnswer();
|
|
|
|
|
|
|
|
patientAnswer.setId(askPatientAnswer.getId());
|
|
|
|
|
|
|
|
patientAnswer.setAnswerResourceId(fileResource.getId());
|
|
|
|
|
|
|
|
askPatientAnswerService.updateById(patientAnswer);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 完成
|
|
|
|
|
|
|
|
MedicalRec medicalRec1 = new MedicalRec();
|
|
|
|
|
|
|
|
medicalRec1.setMedicalStatus(EnumMedicalRec.COMPLETE.getCode());
|
|
|
|
|
|
|
|
medicalRec1.setId(medicalId);
|
|
|
|
|
|
|
|
medicalRecService.updateById(medicalRec1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
human.setDynamicTaskUid(dynamicDTO.getUid());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private FileResource convertBase64ToFile(String prefixName, String imageFileName, String base64) throws Exception {
|
|
|
|
|
|
|
|
String prefix = FileUtil.getPrefix(imageFileName);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 创建一个图片临时文件
|
|
|
|
|
|
|
|
File tempFile = FileUtil.createTempFile(prefixName + "_" + prefix, ".mp4", true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Base64.decodeToFile(base64, tempFile);
|
|
|
|
|
|
|
|
return fileManageService.uploadFile(tempFile);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@SneakyThrows
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
@Transactional
|
|
|
|
|
|
|
|
public boolean createHuman(MultipartFile imageFile, String medicalId) {
|
|
|
|
|
|
|
|
// 查询病例状态
|
|
|
|
|
|
|
|
MedicalRec medicalRec = medicalRecService.lambdaQuery()
|
|
|
|
|
|
|
|
.eq(MedicalRec::getMedicalStatus, EnumMedicalRec.DIGITAL_HUMAN_CREATED.getCode())
|
|
|
|
|
|
|
|
.eq(MedicalRec::getId, medicalId)
|
|
|
|
|
|
|
|
.one();
|
|
|
|
|
|
|
|
Assert.isTrue(null == medicalRec, "请先导入病例后再操作");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 上传图片
|
|
|
|
|
|
|
|
FileResource fileResource = fileManageService.uploadFile(imageFile, imageFile.getContentType());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 生成数字人
|
|
|
|
|
|
|
|
Human human = new Human();
|
|
|
|
|
|
|
|
human.setImageFileId(fileResource.getId());
|
|
|
|
|
|
|
|
human.setImageName(fileResource.getFileName());
|
|
|
|
|
|
|
|
human.setCreateUserId(UserUtil.getUser().getId());
|
|
|
|
|
|
|
|
human.setUpdateUserId(UserUtil.getUser().getId());
|
|
|
|
|
|
|
|
humanService.save(human);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 异步调用生成数字人
|
|
|
|
|
|
|
|
humanExecutor.submit(() -> {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
generateHuman(human.getId(), medicalId);
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
|
|
log.error("createHuman:生成数字人异常", e);
|
|
|
|
|
|
|
|
throw new BusinessException("生成数字人异常");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 绑定病例
|
|
|
|
|
|
|
|
MedicalRec medicalRec1 = new MedicalRec();
|
|
|
|
|
|
|
|
medicalRec1.setMedicalStatus(EnumMedicalRec.ESTABLISHED_RECORD.getCode());
|
|
|
|
|
|
|
|
medicalRec1.setHumanId(human.getId());
|
|
|
|
|
|
|
|
medicalRec1.setId(medicalId);
|
|
|
|
|
|
|
|
medicalRecService.updateById(medicalRec1);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|