From 82b91c68892a2b0f2c831082bd576bbf9b8e606a Mon Sep 17 00:00:00 2001 From: liu Date: Thu, 20 Jun 2024 17:54:43 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E6=95=B0=E5=AD=97=E4=BA=BA?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker/v3.1.0/step1.sql | 3 + .../VirtualPatientManageApplication.java | 2 + .../human/HumanManageController.java | 20 ++++ .../manage/dto/HumanGenerateDTO.java | 15 +++ .../manage/dto/HumanStatusDTO.java | 28 +++++ .../manage/service/HumanManageService.java | 6 + .../service/impl/HumanManageServiceImpl.java | 97 +++++++++++++++ .../manage/task/HumanManageTask.java | 113 ++++++++++++++++++ .../java/com/supervision/model/Human.java | 11 +- .../src/main/resources/mapper/HumanMapper.xml | 4 +- 10 files changed, 295 insertions(+), 4 deletions(-) create mode 100644 virtual-patient-manage/src/main/java/com/supervision/manage/controller/human/HumanManageController.java create mode 100644 virtual-patient-manage/src/main/java/com/supervision/manage/dto/HumanGenerateDTO.java create mode 100644 virtual-patient-manage/src/main/java/com/supervision/manage/dto/HumanStatusDTO.java create mode 100644 virtual-patient-manage/src/main/java/com/supervision/manage/service/HumanManageService.java create mode 100644 virtual-patient-manage/src/main/java/com/supervision/manage/service/impl/HumanManageServiceImpl.java create mode 100644 virtual-patient-manage/src/main/java/com/supervision/manage/task/HumanManageTask.java diff --git a/docker/v3.1.0/step1.sql b/docker/v3.1.0/step1.sql index 00a4dd26..0fd0980b 100644 --- a/docker/v3.1.0/step1.sql +++ b/docker/v3.1.0/step1.sql @@ -132,6 +132,9 @@ create table vp_human primary key (id) ) comment '数字人表' collate = utf8mb4_bin row_format = DYNAMIC; +alter table vp_human + add status int default 2 null comment '1就绪 2生成中' after id; + alter table vp_medical_rec add human_id varchar(64) null comment '数字人id' after patient_id; diff --git a/virtual-patient-manage/src/main/java/com/supervision/manage/VirtualPatientManageApplication.java b/virtual-patient-manage/src/main/java/com/supervision/manage/VirtualPatientManageApplication.java index 52510975..e5273710 100644 --- a/virtual-patient-manage/src/main/java/com/supervision/manage/VirtualPatientManageApplication.java +++ b/virtual-patient-manage/src/main/java/com/supervision/manage/VirtualPatientManageApplication.java @@ -6,8 +6,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.ComponentScan; +import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication +@EnableScheduling @MapperScan(basePackages = {"com.supervision.**.mapper"}) @ComponentScan(basePackages = {"com.supervision.**"}) @EnableFeignClients(basePackages = "com.supervision") diff --git a/virtual-patient-manage/src/main/java/com/supervision/manage/controller/human/HumanManageController.java b/virtual-patient-manage/src/main/java/com/supervision/manage/controller/human/HumanManageController.java new file mode 100644 index 00000000..9cfea403 --- /dev/null +++ b/virtual-patient-manage/src/main/java/com/supervision/manage/controller/human/HumanManageController.java @@ -0,0 +1,20 @@ +package com.supervision.manage.controller.human; + +import com.supervision.manage.service.HumanManageService; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@Tag(name = "数字人管理") +public class HumanManageController { + + private final HumanManageService humanManageService; + + @GetMapping("generateHuman") + public void generateHuman(String humanId) throws Exception { + humanManageService.generateHuman(humanId); + } +} diff --git a/virtual-patient-manage/src/main/java/com/supervision/manage/dto/HumanGenerateDTO.java b/virtual-patient-manage/src/main/java/com/supervision/manage/dto/HumanGenerateDTO.java new file mode 100644 index 00000000..8971d0c7 --- /dev/null +++ b/virtual-patient-manage/src/main/java/com/supervision/manage/dto/HumanGenerateDTO.java @@ -0,0 +1,15 @@ +package com.supervision.manage.dto; + +import lombok.Data; + +@Data +public class HumanGenerateDTO { + + private Integer code; + + private String message; + + private String uid; + + private String video; +} diff --git a/virtual-patient-manage/src/main/java/com/supervision/manage/dto/HumanStatusDTO.java b/virtual-patient-manage/src/main/java/com/supervision/manage/dto/HumanStatusDTO.java new file mode 100644 index 00000000..ef9b4d02 --- /dev/null +++ b/virtual-patient-manage/src/main/java/com/supervision/manage/dto/HumanStatusDTO.java @@ -0,0 +1,28 @@ +package com.supervision.manage.dto; + +import lombok.Data; + +@Data +public class HumanStatusDTO { + + private Integer code; + + /** + * 任务状态(processing、completed、failed)。 + */ + private String status; + + private String message; + + private String video; + + @Override + public String toString() { + return "HumanStatusDTO{" + + "code=" + code + + ", status='" + status + '\'' + + ", message='" + message + '\'' + + ", videoSize='" + video.length() + '\'' + + '}'; + } +} diff --git a/virtual-patient-manage/src/main/java/com/supervision/manage/service/HumanManageService.java b/virtual-patient-manage/src/main/java/com/supervision/manage/service/HumanManageService.java new file mode 100644 index 00000000..e8e3c476 --- /dev/null +++ b/virtual-patient-manage/src/main/java/com/supervision/manage/service/HumanManageService.java @@ -0,0 +1,6 @@ +package com.supervision.manage.service; + +public interface HumanManageService { + + void generateHuman(String humanId) throws Exception; +} diff --git a/virtual-patient-manage/src/main/java/com/supervision/manage/service/impl/HumanManageServiceImpl.java b/virtual-patient-manage/src/main/java/com/supervision/manage/service/impl/HumanManageServiceImpl.java new file mode 100644 index 00000000..4791d879 --- /dev/null +++ b/virtual-patient-manage/src/main/java/com/supervision/manage/service/impl/HumanManageServiceImpl.java @@ -0,0 +1,97 @@ +package com.supervision.manage.service.impl; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpUtil; +import cn.hutool.json.JSONUtil; +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.FileResource; +import com.supervision.model.Human; +import com.supervision.service.HumanService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.File; +import java.util.Map; + +@Slf4j +@Service +@RequiredArgsConstructor +public class HumanManageServiceImpl implements HumanManageService { + + private final HumanService humanService; + private final FileManageService fileManageService; + @Value("${humanGenerate.baseUrl}") + private String humanBaseUrl; + @Value("${humanGenerate.silent}") + private String silent; + @Value("${humanGenerate.dynamic}") + private String dynamic; + @Value("${humanGenerate.status}") + private String status; + + @Override + @Transactional(rollbackFor = Exception.class) + public void generateHuman(String humanId) throws Exception { + Human human = humanService.getOptById(humanId).orElseThrow(() -> new BusinessException("数字人形象不存在")); + + File imageFile = fileManageService.downloadFile(human.getImageFileId()); + // 创建一个图片临时文件 + log.info("提交文件生成,文件名:{}", FileUtil.getName(imageFile)); + 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("生成数字人静态视频异常"); + } + + 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 (silentDTO.getCode() == 200) { + if (StrUtil.isNotBlank(silentDTO.getVideo())) { + // 如果已经生成了视频,那么直接拿到这个视频 + FileResource fileResource = convertBase64ToFile("silent", FileUtil.getName(imageFile), silentDTO.getVideo()); + human.setSilentVideoFileId(fileResource.getId()); + + } + human.setSilentTaskUid(silentDTO.getUid()); + } + + if (dynamicDTO.getCode() == 200) { + if (StrUtil.isNotBlank(dynamicDTO.getVideo())) { + // 如果已经生成了视频,那么直接拿到这个视频 + FileResource fileResource = convertBase64ToFile("dynamic", FileUtil.getName(imageFile), dynamicDTO.getVideo()); + human.setDynamicVideoFileId(fileResource.getId()); + + } + human.setDynamicTaskUid(silentDTO.getUid()); + } + humanService.updateById(human); + } + + 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); + } + + +} diff --git a/virtual-patient-manage/src/main/java/com/supervision/manage/task/HumanManageTask.java b/virtual-patient-manage/src/main/java/com/supervision/manage/task/HumanManageTask.java new file mode 100644 index 00000000..37fff07c --- /dev/null +++ b/virtual-patient-manage/src/main/java/com/supervision/manage/task/HumanManageTask.java @@ -0,0 +1,113 @@ +package com.supervision.manage.task; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpUtil; +import cn.hutool.json.JSONUtil; +import com.supervision.manage.dto.HumanStatusDTO; +import com.supervision.manage.service.FileManageService; +import com.supervision.model.FileResource; +import com.supervision.model.Human; +import com.supervision.service.HumanService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.util.List; +import java.util.Map; + +@Slf4j +@Component +@RequiredArgsConstructor +public class HumanManageTask { + + private final HumanService humanService; + private final FileManageService fileManageService; + @Value("${humanGenerate.baseUrl}") + private String humanBaseUrl; + @Value("${humanGenerate.status}") + private String status; + + @Scheduled(fixedDelay = 1000 * 60 * 2) + public void refreshHumanUid() { + log.info("定时任务检查数字人形象"); + List humanList = humanService.lambdaQuery().eq(Human::getStatus, 2).list(); + for (Human human : humanList) { + silent: + if (StrUtil.isBlank(human.getSilentVideoFileId())) { + if (StrUtil.isNotBlank(human.getSilentTaskUid())) { + // 如果任务不为空,就去更新任务的状态 + HumanStatusDTO silentDTO; + try { + String s = HttpUtil.get(humanBaseUrl + StrUtil.format(status, Map.of("uid", human.getSilentTaskUid()))); + silentDTO = JSONUtil.toBean(s, HumanStatusDTO.class); + log.info("获取静态视频:{}", silentDTO.toString()); + } catch (Exception e) { + log.error("数字人获取静态视频状态失败", e); + break silent; + } + // 任务完成,则进行保存 + try { + if (200 == silentDTO.getCode() && StrUtil.equals("completed", silentDTO.getStatus()) + && StrUtil.isNotBlank(silentDTO.getVideo())) { + FileResource fileResource = convertBase64ToFile("silent", human.getImageName(), silentDTO.getVideo()); + // 为最后更新状态准备 + human.setSilentVideoFileId(fileResource.getId()); + humanService.lambdaUpdate().set(Human::getSilentVideoFileId, fileResource.getId()).eq(Human::getId, human.getId()).update(); + } + } catch (Exception e) { + log.error("数字人保存静默视频失败", e); + } + } + } + + dynamic: + if (StrUtil.isBlank(human.getDynamicVideoFileId())) { + if (StrUtil.isNotBlank(human.getDynamicTaskUid())) { + // 如果任务不为空,就去更新任务的状态 + HumanStatusDTO dynamicDTO; + try { + String s = HttpUtil.get(humanBaseUrl + StrUtil.format(status, Map.of("uid", human.getDynamicTaskUid()))); + dynamicDTO = JSONUtil.toBean(s, HumanStatusDTO.class); + log.info("获取动态视频:{}", dynamicDTO.toString()); + } catch (Exception e) { + log.error("数字人获取动态视频状态失败", e); + break dynamic; + } + // 任务完成,则进行保存 + try { + if (200 == dynamicDTO.getCode() && StrUtil.equals("completed", dynamicDTO.getStatus()) + && StrUtil.isNotBlank(dynamicDTO.getVideo())) { + FileResource fileResource = convertBase64ToFile("dynamic", human.getImageName(), dynamicDTO.getVideo()); + // 为最后更新状态准备 + human.setDynamicVideoFileId(fileResource.getId()); + humanService.lambdaUpdate().set(Human::getDynamicVideoFileId, fileResource.getId()).eq(Human::getId, human.getId()).update(); + } + } catch (Exception e) { + log.error("数字人保存动态视频失败", e); + } + } + } + // 如果两者都走完了,校验如果全部有值,说明就完成了 + if (StrUtil.isAllNotBlank(human.getSilentVideoFileId(), human.getDynamicVideoFileId())) { + humanService.lambdaUpdate().set(Human::getStatus, 1).eq(Human::getId, human.getId()).update(); + } + } + log.info("定时任务检查数字人形象结束"); + + } + + 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); + } +} diff --git a/virtual-patient-model/src/main/java/com/supervision/model/Human.java b/virtual-patient-model/src/main/java/com/supervision/model/Human.java index d0c3f89d..07a7de2f 100644 --- a/virtual-patient-model/src/main/java/com/supervision/model/Human.java +++ b/virtual-patient-model/src/main/java/com/supervision/model/Human.java @@ -1,18 +1,18 @@ package com.supervision.model; -import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + import java.io.Serializable; import java.util.Date; -import lombok.Data; /** * 数字人表 * @TableName vp_human */ -@TableName(value ="vp_human") +@TableName(value = "vp_human") @Data public class Human implements Serializable { /** @@ -21,6 +21,11 @@ public class Human implements Serializable { @TableId private String id; + /** + * 数字人的状态,只有1才能被使用 1就绪 2生成中 + */ + private Integer status; + /** * 静态图片ID */ diff --git a/virtual-patient-model/src/main/resources/mapper/HumanMapper.xml b/virtual-patient-model/src/main/resources/mapper/HumanMapper.xml index 037b04ed..5416c159 100644 --- a/virtual-patient-model/src/main/resources/mapper/HumanMapper.xml +++ b/virtual-patient-model/src/main/resources/mapper/HumanMapper.xml @@ -6,6 +6,7 @@ + @@ -20,7 +21,8 @@ - id,image_file_id,silent_video_file_id, + id + ,status,image_file_id,silent_video_file_id, silent_task_uid,dynamic_video_file_id,dynamic_task_uid, image_name,description create_user_id,create_time,update_user_id,