| | |
| | | import cn.hutool.http.HttpRequest; |
| | | import cn.hutool.http.HttpResponse; |
| | | import cn.iocoder.yudao.module.digitalcourse.controller.admin.voices.vo.VoicesTrailVO; |
| | | import cn.iocoder.yudao.module.digitalcourse.dal.dataobject.digitalhumans.DigitalHumansDO; |
| | | import cn.iocoder.yudao.module.digitalcourse.dal.dataobject.voices.VoicesDO; |
| | | import cn.iocoder.yudao.module.digitalcourse.dal.mysql.voices.VoicesMapper; |
| | | import cn.iocoder.yudao.module.infra.api.config.ConfigApi; |
| | |
| | | import org.springframework.stereotype.Component; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.io.IOException; |
| | | 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; |
| | |
| | | private ConfigApi configApi; |
| | | @Resource |
| | | private VoicesMapper voicesMapper; |
| | | 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 HEYGEM_CORE_URL = "heygem.core.url"; |
| | | @Async |
| | | public void remoteTrain(VoicesTrailVO trailVO){ |
| | | String origin_audio = configApi.getConfigValueByKey(HEYGEM_VOICE_DATA) + "/origin_audio"; |
| | | //训练前校验 |
| | | try { |
| | | Files.createDirectories(Path.of(origin_audio)); |
| | | } catch (IOException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | String extname = trailVO.getFixAuditionUrl().substring(trailVO.getFixAuditionUrl().lastIndexOf(".")); |
| | | String modelFileName = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) + extname; |
| | | String modelFilePath = Paths.get(origin_audio, modelFileName).toString(); |
| | | |
| | | String substring = configApi.getConfigValueByKey(EASEGEN_URL)+trailVO.getFixAuditionUrl().substring(trailVO.getFixAuditionUrl().lastIndexOf("/")); |
| | | |
| | | try { |
| | | Files.copy(Path.of(substring), Path.of(modelFilePath), StandardCopyOption.REPLACE_EXISTING); |
| | | } catch (IOException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | |
| | | String configValueByKey = configApi.getConfigValueByKey(HEYGEM_VOICE_DATA); |
| | | // 计算相对路径 |
| | | Path relativeAudioPath = Path.of(configValueByKey).relativize(Path.of(modelFilePath)); |
| | | 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; |
| | | ObjectMapper mapper = new ObjectMapper(); |
| | | mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); |
| | | |
| | | while (retryCount < maxRetries && !success) { |
| | | try { |
| | | // 发送POST请求 |
| | | HttpResponse execute = HttpRequest.post(configApi.getConfigValueByKey(EASEGEN_CORE_URL) + "/api/clone_voice") |
| | | .header("X-API-Key", configApi.getConfigValueByKey(EASEGEN_CORE_KEY)) |
| | | .body(mapper.writeValueAsString(trailVO)) |
| | | HttpResponse execute = HttpRequest.post(configApi.getConfigValueByKey(HEYGEM_CORE_URL) + "/v1/preprocess_and_tran") |
| | | .body(JSON.toJSONString(map)) |
| | | .execute(); |
| | | String body = execute.body(); |
| | | |
| | |
| | | } |
| | | continue; // 重新尝试 |
| | | } |
| | | |
| | | retryCount++; |
| | | if (retryCount >= maxRetries) { |
| | | voicesMapper.update(new UpdateWrapper<VoicesDO>().lambda().eq(VoicesDO::getCode, trailVO.getCode()).set(VoicesDO::getStatus, ERROR_STATUS)); |
| | | log.error("训练失败:->>>>>>>>>"); |
| | | return; |
| | | } |
| | | // 解析响应,检查是否有错误信息 |
| | | JSONObject responseJson = JSON.parseObject(body); |
| | | if (!responseJson.getBoolean("success")) { |
| | | // 处理业务逻辑错误,更新状态和错误信息 |
| | | String errorDetail = responseJson.getString("detail"); |
| | | retryCount++; |
| | | if (retryCount >= maxRetries) { |
| | | voicesMapper.update(new UpdateWrapper<VoicesDO>().lambda().eq(VoicesDO::getCode, trailVO.getCode()).set(VoicesDO::getStatus, ERROR_STATUS)); |
| | | log.error("训练失败:->>>>>>>>>", errorDetail); |
| | | return; |
| | | } |
| | | continue; // 重新尝试 |
| | | } |
| | | // 处理业务逻辑错误,更新状态和错误信息 |
| | | String referenceAudioText = responseJson.getString("reference_audio_text"); |
| | | String asrFormatAudioUrl = responseJson.getString("asr_format_audio_url"); |
| | | |
| | | |
| | | voicesMapper.update( |
| | | new UpdateWrapper<VoicesDO>() |
| | | .lambda() |
| | | .eq(VoicesDO::getCode, trailVO.getCode()) // 条件:code 等于传入的值 |
| | | .set(VoicesDO::getStatus, 0) // 更新字段 status 为 0 |
| | | .set(VoicesDO::getAsrFormatAudioUrl,asrFormatAudioUrl) |
| | | .set(VoicesDO::getReferenceAudioText,referenceAudioText) |
| | | ); |
| | | success = true; |
| | | }catch (Exception e){ |
| | | retryCount++; |