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