From b398796000c00386e056b8a5cd762f210abf4869 Mon Sep 17 00:00:00 2001 From: 康鲁杰 <60095866+KangLujie@users.noreply.github.com> Date: 星期一, 24 三月 2025 14:48:55 +0800 Subject: [PATCH] 数字人视频 --- yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/dal/dataobject/digitalhumans/DigitalHumansDO.java | 5 + yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/controller/admin/digitalhumans/vo/DigitalHumansSaveReqVO.java | 3 yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/digitalhumans/DigitalHumansServiceImpl.java | 5 + yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/digitalhumans/DigitalHumansServiceUtil.java | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 162 insertions(+), 6 deletions(-) diff --git a/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/controller/admin/digitalhumans/vo/DigitalHumansSaveReqVO.java b/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/controller/admin/digitalhumans/vo/DigitalHumansSaveReqVO.java index 4476d97..d8c8302 100644 --- a/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/controller/admin/digitalhumans/vo/DigitalHumansSaveReqVO.java +++ b/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/controller/admin/digitalhumans/vo/DigitalHumansSaveReqVO.java @@ -63,7 +63,6 @@ private String useModel; @Schema(description = "鐘舵��(0: 姝e父, 1: 寰呭鏍革紝2锛氬凡鍙楃悊锛�3锛氳缁冧腑锛�4锛氫笉閫氳繃锛�5锛氳缁冨け璐�)", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - @NotNull(message = "鐘舵�佷笉鑳戒负绌�") private Integer status; //淇鍥剧墖 @@ -71,4 +70,4 @@ //淇瑙嗛 private String fixVideoUrl; -} \ No newline at end of file +} diff --git a/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/dal/dataobject/digitalhumans/DigitalHumansDO.java b/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/dal/dataobject/digitalhumans/DigitalHumansDO.java index a6cbeca..89488d7 100644 --- a/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/dal/dataobject/digitalhumans/DigitalHumansDO.java +++ b/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/dal/dataobject/digitalhumans/DigitalHumansDO.java @@ -132,4 +132,7 @@ */ private Date expireDate; -} \ No newline at end of file + private String referenceAudioText; + private String asrFormatAudioUrl; + +} diff --git a/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/digitalhumans/DigitalHumansServiceImpl.java b/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/digitalhumans/DigitalHumansServiceImpl.java index 74ff20a..b7fece1 100644 --- a/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/digitalhumans/DigitalHumansServiceImpl.java +++ b/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/digitalhumans/DigitalHumansServiceImpl.java @@ -36,6 +36,7 @@ @Override public Long createDigitalHumans(DigitalHumansSaveReqVO createReqVO) { createReqVO.setCode(UUID.fastUUID().toString()); + createReqVO.setStatus(1); // 鎻掑叆 DigitalHumansDO digitalHumans = BeanUtils.toBean(createReqVO, DigitalHumansDO.class); digitalHumansMapper.insert(digitalHumans); @@ -61,7 +62,7 @@ //寮傛璁粌妯″瀷 if (updateObj.getStatus() == 3){ - digitalHumansServiceUtil.remoteTrain(transferVO(updateObj.getId())); + digitalHumansServiceUtil.remoteHeyGemTrain(transferVO(updateObj.getId())); } } @@ -118,4 +119,4 @@ return digitalHumansMapper.selectPage(pageReqVO); } -} \ No newline at end of file +} diff --git a/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/digitalhumans/DigitalHumansServiceUtil.java b/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/digitalhumans/DigitalHumansServiceUtil.java index 648f249..debbb40 100644 --- a/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/digitalhumans/DigitalHumansServiceUtil.java +++ b/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/digitalhumans/DigitalHumansServiceUtil.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.digitalcourse.dal.dataobject.digitalhumans.DigitalHumansDO; import cn.iocoder.yudao.module.digitalcourse.dal.mysql.digitalhumans.DigitalHumansMapper; import cn.iocoder.yudao.module.infra.api.config.ConfigApi; +import cn.iocoder.yudao.module.infra.api.file.FileApi; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; @@ -19,6 +20,14 @@ import org.springframework.validation.annotation.Validated; import org.springframework.scheduling.annotation.Async; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.List; @@ -31,6 +40,11 @@ @Validated public class DigitalHumansServiceUtil { + private static final String HEYGEM_CORE_URL = "heygem.core.url"; + private static final String HEYGEM_VOICE_DATA = "heygem.voice.data"; + private static final String HEYGEM_FACE2FACE = "heygem.face2face"; + private static final String EASEGEN_URL = "easegen.url"; + private static final String EASEGEN_CORE_URL = "easegen.core.url"; private static final String EASEGEN_CORE_KEY = "easegen.core.key"; @@ -41,9 +55,149 @@ @Resource private DigitalHumansMapper digitalHumansMapper; + @Resource private ConfigApi configApi; + public void remoteHeyGemTrain(DigitalHumansTrailVO digitalHumansTrailVo){ + String origin_audio = configApi.getConfigValueByKey(HEYGEM_VOICE_DATA) + "/origin_audio"; + String temp = configApi.getConfigValueByKey(HEYGEM_FACE2FACE) + "/temp"; + //璁粌鍓嶆牎楠� + try { + Files.createDirectories(Path.of(origin_audio)); + Files.createDirectories(Path.of(temp)); + } catch (IOException e) { + throw new RuntimeException(e); + } + //todo 瑙嗛鎶犲浘 + String extname = digitalHumansTrailVo.getFixVideoUrl().substring(digitalHumansTrailVo.getFixVideoUrl().lastIndexOf(".")); + String modelFileName = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) + extname; + String modelFilePath = Paths.get(temp, modelFileName).toString(); + + String substring = configApi.getConfigValueByKey(EASEGEN_URL)+digitalHumansTrailVo.getFixVideoUrl().substring(digitalHumansTrailVo.getFixVideoUrl().lastIndexOf("/")); + + try { + Files.copy(Path.of(substring), Path.of(modelFilePath), StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + throw new RuntimeException(e); + } + + + // 闊抽鏂囦欢璺緞 + String audioFileName = modelFileName.replace(extname, ".wav"); + String audioFilePath = Paths.get(origin_audio, audioFileName).toString(); + + // 浣跨敤 FFmpeg 鎻愬彇闊抽 + extractAudio(modelFilePath, audioFilePath); + + System.out.println("瑙嗛宸插瓨鍌�: " + modelFilePath); + System.out.println("闊抽宸叉彁鍙�: " + audioFilePath); + //audioFilePath鍒囬櫎configValueByKey + String configValueByKey = configApi.getConfigValueByKey(HEYGEM_VOICE_DATA); + // 璁$畻鐩稿璺緞 + Path relativeAudioPath = Path.of(configValueByKey).relativize(Path.of(audioFilePath)); + Map<String, Object> map = Map.of( + "format", "wav", + "reference_audio", relativeAudioPath.toString().replace("\\", "/"), + "lang", "zh" + ); + // 灏嗚矾寰勪腑鐨刓鏇挎崲涓�/ relativeAudioPath.toString() + + int maxRetries = 3; // 鏈�澶ч噸璇曟鏁� + int retryCount = 0; // 褰撳墠閲嶈瘯娆℃暟 + boolean success = false; + + while (retryCount < maxRetries && !success) { + try { + // 鍙戦�丳OST璇锋眰 + HttpResponse execute = HttpRequest.post(configApi.getConfigValueByKey(HEYGEM_CORE_URL) + "/v1/preprocess_and_tran") + .body(JSON.toJSONString(map)) + .execute(); + String body = execute.body(); + + // 妫�鏌ュ搷搴旂姸鎬佺爜鏄惁鎴愬姛 + if (execute.getStatus() != 200) { + retryCount++; + if (retryCount >= maxRetries) { + // 瓒呰繃閲嶈瘯娆℃暟锛岃缁冨け璐� + digitalHumansMapper.update(new UpdateWrapper<DigitalHumansDO>().lambda().eq(DigitalHumansDO::getCode, digitalHumansTrailVo.getCode()).set(DigitalHumansDO::getStatus, ERROR_STATUS)); + log.error("璁粌澶辫触锛�->>>>>>>>>", execute.getStatus()); + return; + } + continue; // 閲嶆柊灏濊瘯 + } + retryCount++; + if (retryCount >= maxRetries) { + digitalHumansMapper.update(new UpdateWrapper<DigitalHumansDO>().lambda().eq(DigitalHumansDO::getCode, digitalHumansTrailVo.getCode()).set(DigitalHumansDO::getStatus, ERROR_STATUS)); + log.error("璁粌澶辫触锛�->>>>>>>>>"); + return; + } + // 瑙f瀽鍝嶅簲锛屾鏌ユ槸鍚︽湁閿欒淇℃伅 + JSONObject responseJson = JSON.parseObject(body); + // 澶勭悊涓氬姟閫昏緫閿欒锛屾洿鏂扮姸鎬佸拰閿欒淇℃伅 + String referenceAudioText = responseJson.getString("reference_audio_text"); + String asrFormatAudioUrl = responseJson.getString("asr_format_audio_url"); + // 濡傛灉鎴愬姛锛屾洿鏂扮姸鎬佷负0锛堟垚鍔燂級 + + digitalHumansMapper.update( + new UpdateWrapper<DigitalHumansDO>() + .lambda() + .eq(DigitalHumansDO::getCode, digitalHumansTrailVo.getCode()) // 鏉′欢锛歝ode 绛変簬浼犲叆鐨勫�� + .set(DigitalHumansDO::getStatus, 0) // 鏇存柊瀛楁 status 涓� 0 + .set(DigitalHumansDO::getAsrFormatAudioUrl,asrFormatAudioUrl) + .set(DigitalHumansDO::getReferenceAudioText,referenceAudioText) + ); + success = true; + }catch (Exception e){ + retryCount++; + if (retryCount >= maxRetries) { + // 鎹曡幏寮傚父锛岃褰曢敊璇師鍥犲苟鏇存柊鐘舵�� + digitalHumansMapper.update(new UpdateWrapper<DigitalHumansDO>().lambda().eq(DigitalHumansDO::getCode, digitalHumansTrailVo.getCode()).set(DigitalHumansDO::getStatus, ERROR_STATUS)); + log.error("璁粌澶辫触锛�->>>>>>>>>", e.getMessage()); + return; + } + + try { + // 閲嶈瘯鍓嶇瓑寰呬竴娈垫椂闂达紝閬垮厤棰戠箒璇锋眰 + TimeUnit.SECONDS.sleep(2); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); // 澶勭悊涓柇寮傚父 + break; + } + } + } + + } + /** + * 璋冪敤 FFmpeg 鎻愬彇闊抽 + * @param videoFilePath 瑙嗛鏂囦欢璺緞 + * @param audioFilePath 杈撳嚭闊抽鏂囦欢璺緞 + */ + private static void extractAudio(String videoFilePath, String audioFilePath) { + try { + ProcessBuilder builder = new ProcessBuilder( + "ffmpeg", "-i", videoFilePath, "-q:a", "0", "-map", "a", audioFilePath + ); + builder.redirectErrorStream(true); + Process process = builder.start(); + + // 璇诲彇 FFmpeg 杈撳嚭锛堝彲閫夛級 + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String line; + while ((line = reader.readLine()) != null) { + System.out.println(line); + } + + int exitCode = process.waitFor(); + if (exitCode == 0) { + System.out.println("闊抽鎻愬彇鎴愬姛: " + audioFilePath); + } else { + System.out.println("闊抽鎻愬彇澶辫触锛�"); + } + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + } public void remoteTrain(DigitalHumansTrailVO digitalHumansTrailVo){ //璁粌鍓嶆牎楠� @@ -112,7 +266,6 @@ } } - @Async public void queryRemoteTrainResult(){ try { -- Gitblit v1.9.3