康鲁杰
2025-03-24 1972364a34dde64877b831588389312779547102
试听
已修改5个文件
已添加2个文件
227 ■■■■ 文件已修改
easegen-front/src/views/chooseTemplate/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/controller/admin/voices/VoicesController.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/dal/dataobject/voices/AuditionDO.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/dal/dataobject/voices/AuditionVO.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/dal/dataobject/voices/InvokeVO.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/voices/VoicesService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/voices/VoicesServiceImpl.java 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easegen-front/src/views/chooseTemplate/index.vue
@@ -1707,7 +1707,7 @@
    const html = editorRef.value.getText();
  const params = {
    text: html,
    humans: humanId
    humanId: humanId
  }
  showAudioPlay.value = true
  pptTemplateApi
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/controller/admin/voices/VoicesController.java
@@ -9,6 +9,7 @@
import cn.iocoder.yudao.module.digitalcourse.controller.admin.voices.vo.VoicesRespVO;
import cn.iocoder.yudao.module.digitalcourse.controller.admin.voices.vo.VoicesSaveReqVO;
import cn.iocoder.yudao.module.digitalcourse.dal.dataobject.voices.AuditionDO;
import cn.iocoder.yudao.module.digitalcourse.dal.dataobject.voices.AuditionVO;
import cn.iocoder.yudao.module.digitalcourse.dal.dataobject.voices.VoicesDO;
import cn.iocoder.yudao.module.digitalcourse.service.voices.VoicesService;
import cn.iocoder.yudao.module.infra.api.config.ConfigApi;
@@ -112,12 +113,12 @@
    @PostMapping("/audition")
    @Operation(summary = "试听")
    public CommonResult<String> audition(@Valid @RequestBody AuditionDO auditionDO) {
    public CommonResult<String> audition(@Valid @RequestBody AuditionVO auditionVO) {
        int limitWord = Integer.parseInt(configApi.getConfigValueByKey(Limit_AUDITIONWORD));
        if (limitWord<(auditionDO.getText().length())) {
        if (limitWord<(auditionVO.getText().length())) {
            return CommonResult.error(BAD_REQUEST.getCode(), "试听文字超出字数限制,最多【"+limitWord+"】字");
        }
        return success(voicesService.audition(auditionDO));
        return success(voicesService.audition(auditionVO));
    }
}
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/dal/dataobject/voices/AuditionDO.java
@@ -4,9 +4,6 @@
@Data
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AuditionDO {
    /**
@@ -15,38 +12,8 @@
    private String text;
    /**
     * è¯­é€Ÿ
     */
    private Float speed;
    /**
     * éŸ³é«˜
     */
    private Float pitch;
    /**
     * éŸ³é‡
     */
    private Float volume;
    /**
     * å£°éŸ³ç±»åž‹
     */
    private Integer voiceType;
    /**
     * å£°éŸ³ç±»åž‹Id
     */
    private Integer voiceTypeId;
    /**
     * å£°éŸ³Id
     */
    private String voiceId;
    /**
     * æ™ºèƒ½è¯­é€Ÿ
     */
    private Integer smartSpeed;
}
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/dal/dataobject/voices/AuditionVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
package cn.iocoder.yudao.module.digitalcourse.dal.dataobject.voices;
import lombok.Data;
/**
 * @author kanglujie
 * @date 2025-03-24 15:50:10
 */
@Data
public class AuditionVO {
    private String text;
    private String humanId;
}
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/dal/dataobject/voices/InvokeVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,56 @@
package cn.iocoder.yudao.module.digitalcourse.dal.dataobject.voices;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;
import java.util.UUID;
@Data
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class InvokeVO {
    private String speaker; // UUID,保持唯一
    private String text; // éœ€è¦åˆæˆçš„æ–‡æœ¬å†…容
    private String format = "wav"; // å›ºå®šä¼ å‚ "wav"
    @JsonProperty("topP")
    private double topP = 0.7; // å›ºå®šä¼ å‚ 0.7
    @JsonProperty("max_new_tokens")
    private int maxNewTokens = 1024; // å›ºå®šä¼ å‚ 1024
    @JsonProperty("chunk_length")
    private int chunkLength = 100; // å›ºå®šä¼ å‚ 100
    @JsonProperty("repetition_penalty")
    private double repetitionPenalty = 1.2; // å›ºå®šä¼ å‚ 1.2
    private double temperature = 0.7; // å›ºå®šä¼ å‚ 0.7
    @JsonProperty("need_asr")
    private boolean needAsr = false; // å›ºå®šä¼ å‚ false
    private boolean streaming = false; // å›ºå®šä¼ å‚ false
    @JsonProperty("is_fixed_seed")
    private int isFixedSeed = 0; // å›ºå®šä¼ å‚ 0
    @JsonProperty("is_norm")
    private int isNorm = 0; // å›ºå®šä¼ å‚ 0
    @JsonProperty("reference_audio")
    private String referenceAudio; // ä¸Šä¸€æ­¥â€œæ¨¡ç‰¹è®­ç»ƒâ€çš„返回值
    @JsonProperty("reference_text")
    private String referenceText; // ä¸Šä¸€æ­¥â€œæ¨¡ç‰¹è®­ç»ƒâ€çš„返回值
    // ç”Ÿæˆé»˜è®¤ UUID æ–¹ä¾¿æµ‹è¯•
    public static String generateUUID() {
        return UUID.randomUUID().toString();
    }
}
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/voices/VoicesService.java
@@ -1,7 +1,6 @@
package cn.iocoder.yudao.module.digitalcourse.service.voices;
import cn.iocoder.yudao.module.digitalcourse.dal.dataobject.voices.AuditionDO;
import cn.iocoder.yudao.module.digitalcourse.dal.dataobject.voices.TTSDTO;
import cn.iocoder.yudao.module.digitalcourse.dal.dataobject.voices.AuditionVO;
import jakarta.validation.*;
import cn.iocoder.yudao.module.digitalcourse.controller.admin.voices.vo.*;
import cn.iocoder.yudao.module.digitalcourse.dal.dataobject.voices.VoicesDO;
@@ -53,7 +52,7 @@
    PageResult<VoicesDO> getVoicesPage(VoicesPageReqVO pageReqVO);
    PageResult<VoicesDO> getVoicesCommonPage(VoicesPageReqVO pageReqVO);
    String audition(AuditionDO auditionDO);
    String audition(AuditionVO auditionVO);
    Boolean auditing();
}
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/voices/VoicesServiceImpl.java
@@ -2,36 +2,25 @@
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.module.digitalcourse.controller.admin.voices.vo.VoicesPageReqVO;
import cn.iocoder.yudao.module.digitalcourse.controller.admin.voices.vo.VoicesSaveReqVO;
import cn.iocoder.yudao.module.digitalcourse.controller.admin.voices.vo.VoicesTrailVO;
import cn.iocoder.yudao.module.digitalcourse.dal.dataobject.voices.AuditionDO;
import cn.iocoder.yudao.module.digitalcourse.dal.dataobject.voices.TTSDTO;
import cn.iocoder.yudao.module.digitalcourse.dal.dataobject.voices.VoicesDO;
import cn.iocoder.yudao.module.digitalcourse.dal.dataobject.digitalhumans.DigitalHumansDO;
import cn.iocoder.yudao.module.digitalcourse.dal.dataobject.voices.*;
import cn.iocoder.yudao.module.digitalcourse.dal.mysql.digitalhumans.DigitalHumansMapper;
import cn.iocoder.yudao.module.digitalcourse.dal.mysql.voices.VoicesMapper;
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.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import org.apache.commons.codec.binary.Base64;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.ParseException;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.io.IOException;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.digitalcourse.enums.ErrorCodeConstants.VOICES_NOT_EXISTS;
@@ -145,61 +134,44 @@
        return (auditing == null || auditing == 0);
    }
    @Resource
    private DigitalHumansMapper digitalHumansMapper;
    private static final String EASEGEN_URL = "easegen.url";
    @Override
    public String audition(AuditionDO auditionDO) {
        VoicesDO voice = voicesMapper.selectById(auditionDO.getVoiceId());
        TTSDTO ttsdto = new TTSDTO();
        if (voice != null) {
            ttsdto.setModel_code(voice.getCode());
            ttsdto.setSentence(auditionDO.getText());
            ttsdto.setRequest_id(StrUtil.uuid());
            ttsdto.setUser_id(String.valueOf(SecurityFrameworkUtils.getLoginUser().getId()));
            ttsdto.setVoice_type(String.valueOf(voice.getVoiceType()));
            ttsdto.setPitch(auditionDO.getPitch());
            ttsdto.setSpeed(auditionDO.getSpeed());
            ttsdto.setVolume(auditionDO.getVolume());
        } else {
            throw exception(VOICES_NOT_EXISTS);
    public String audition(AuditionVO auditionVO) {
        DigitalHumansDO digitalHumansDO = digitalHumansMapper.selectById(auditionVO.getHumanId());
        InvokeVO invokeVO = new InvokeVO();
        invokeVO.setSpeaker(InvokeVO.generateUUID());
        invokeVO.setReferenceText(digitalHumansDO.getReferenceAudioText());
        invokeVO.setReferenceAudio(digitalHumansDO.getAsrFormatAudioUrl());
        invokeVO.setText(auditionVO.getText());
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonString = null;
        try {
            jsonString = objectMapper.writeValueAsString(invokeVO);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        HttpResponse execute = HttpRequest.post("http://192.168.3.161:18180/v1/invoke")
                .body(jsonString)
                .execute();
        if (execute.getStatus() != 200) {
            return null;
        }
        String apiUrl = configApi.getConfigValueByKey(EASEGEN_CORE_URL)+"/api/tts";
        String apiKey = configApi.getConfigValueByKey(EASEGEN_CORE_KEY);
        // åˆ›å»ºHTTP客户端
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            // åˆ›å»ºPOST请求
            HttpPost httpPost = new HttpPost(apiUrl);
            httpPost.setHeader("Content-Type", "application/json");
            httpPost.setHeader("X-API-Key", apiKey);
            httpPost.setEntity(new StringEntity(JSON.toJSONString(ttsdto), ContentType.APPLICATION_JSON));
            // æ‰§è¡Œè¯·æ±‚
            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
                int statusCode = response.getCode();
                String responseString = EntityUtils.toString(response.getEntity());
                if (statusCode == 200) {
                    // è§£æžJSON响应
                    ObjectMapper objectMapper = new ObjectMapper();
                    JsonNode jsonResponse = objectMapper.readTree(responseString);
                    String audioBase64 = jsonResponse.get("audio").asText();
                    // è§£ç Base64音频字符串
                    byte[] audioBytes = Base64.decodeBase64(audioBase64);
                    // ä¿å­˜éŸ³é¢‘文件
                    // æŒ‡å®šæ–‡ä»¶è·¯å¾„(你可以根据实际情况设置)
                    String fileName = StrUtil.uuid() + ".wav";
                    String filePath = "temp/wav/" + fileName;
                    return fileApi.createFile(fileName, filePath, audioBytes);
//                    try (FileOutputStream fos = new FileOutputStream("output.wav")) {
//                        fos.write(audioBytes);
//                        String path = fileApi.createFile("output.wav", null, audioBytes);
//                        return path;
//                    }
                } else {
                    System.out.println("Error: " + responseString);
                }
            }
        } catch (IOException | ParseException e) {
            e.printStackTrace();
        }
        return null;
        String fileName = UUID.randomUUID().toString() + ".wav";
        // èŽ·å–éŸ³é¢‘æ–‡ä»¶çš„äºŒè¿›åˆ¶æ•°æ®
        byte[] content = execute.bodyBytes();
        // ä½¿ç”¨ `createFile` æ–¹æ³•存储文件,并获取 URL
        String fileUrl = fileApi.createFile(fileName, null, content);
        return fileUrl;  // è¿”回存储的文件 URL
        // è¿”回音频文件路径
    }
}