|
@@ -1,47 +1,41 @@
|
|
|
-package org.thyy.thirdpartapi.xfyun;
|
|
|
+package org.thyy.thirdpartapi.tts.ttsService;
|
|
|
|
|
|
import cn.hutool.core.io.FileUtil;
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
import cn.xfyun.api.TtsClient;
|
|
|
import cn.xfyun.model.response.TtsResponse;
|
|
|
import cn.xfyun.service.tts.AbstractTtsWebSocketListener;
|
|
|
-import jakarta.annotation.PostConstruct;
|
|
|
+import jakarta.servlet.http.HttpServletResponse;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import okhttp3.Response;
|
|
|
import okhttp3.WebSocket;
|
|
|
-import org.springframework.beans.factory.annotation.Autowired;
|
|
|
-import org.springframework.web.bind.annotation.PostMapping;
|
|
|
-import org.springframework.web.bind.annotation.RequestBody;
|
|
|
-import org.springframework.web.bind.annotation.RequestMapping;
|
|
|
-import org.springframework.web.bind.annotation.RestController;
|
|
|
-import org.thyy.thirdpartapi.xfyun.request.TtsRequest;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.thyy.thirdpartapi.tts.Tts;
|
|
|
+import org.thyy.thirdpartapi.tts.TtsConfig;
|
|
|
+import org.thyy.thirdpartapi.tts.TtsRequest;
|
|
|
import org.thyy.utils.exception.ExceptionEnum;
|
|
|
import org.thyy.utils.result.R;
|
|
|
import org.thyy.utils.result.ResultVo;
|
|
|
|
|
|
import java.io.File;
|
|
|
-import java.util.concurrent.TimeUnit;
|
|
|
+import java.util.concurrent.CompletableFuture;
|
|
|
+import java.util.concurrent.ExecutionException;
|
|
|
+import java.util.concurrent.atomic.AtomicReference;
|
|
|
|
|
|
@Slf4j
|
|
|
-@RestController
|
|
|
-@RequestMapping("/xfTts")
|
|
|
-public class XfTtsApi {
|
|
|
+@Service(value = "xf")
|
|
|
+public class XfTtsApi implements Tts {
|
|
|
private TtsClient ttsClient;
|
|
|
- private final XfConfig cfg;
|
|
|
+ private TtsConfig cfg;
|
|
|
|
|
|
- @Autowired
|
|
|
- public XfTtsApi(XfConfig cfg) {
|
|
|
- this.cfg = cfg;
|
|
|
- }
|
|
|
-
|
|
|
- @PostConstruct
|
|
|
- public void initTtsClient() {
|
|
|
+ public void init(TtsConfig cfg, TtsConfig.Config xf) {
|
|
|
try {
|
|
|
+ this.cfg = cfg;
|
|
|
if (StrUtil.isBlank(cfg.getDirectory())) {
|
|
|
cfg.setDirectory(System.getProperty("user.dir"));
|
|
|
}
|
|
|
ttsClient = new TtsClient.Builder()
|
|
|
- .signature(cfg.getAppId(), cfg.getApiKey(), cfg.getApiSecret())
|
|
|
+ .signature(xf.getAppId(), xf.getApiKey(), xf.getApiSecret())
|
|
|
.vcn("aisjinger").volume(100).build();
|
|
|
log.info("讯飞SDK初始化成功。");
|
|
|
} catch (Exception e) {
|
|
@@ -49,30 +43,28 @@ public class XfTtsApi {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- @PostMapping("/textToSpeech")
|
|
|
- public ResultVo<String> textToSpeech(@RequestBody TtsRequest request) {
|
|
|
+
|
|
|
+ public ResultVo<String> textToSpeech(TtsRequest request, HttpServletResponse response) {
|
|
|
String filePath = cfg.getDirectory() + File.separator + request.getId() + ".mp3";
|
|
|
FileUtil.del(filePath);
|
|
|
|
|
|
- final Boolean[] progress = { false, null };
|
|
|
- final String[] message = {""};
|
|
|
- try {
|
|
|
+ CompletableFuture<Void> future = new CompletableFuture<>();
|
|
|
+
|
|
|
+ try {
|
|
|
File file = new File(filePath);
|
|
|
ttsClient.send(request.getText(), new AbstractTtsWebSocketListener(file) {
|
|
|
@Override
|
|
|
public void onSuccess(byte[] bytes) {
|
|
|
- progress[0] = true;
|
|
|
}
|
|
|
+
|
|
|
@Override
|
|
|
public void onFail(WebSocket webSocket, Throwable throwable, Response response) {
|
|
|
log.error("[onFail]生成语音文件失败:{}", throwable.getMessage());
|
|
|
- message[0] = throwable.getMessage();
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void onBusinessFail(WebSocket webSocket, TtsResponse ttsResponse) {
|
|
|
log.error("[onBusinessFail]生成语音文件失败:{}", ttsResponse.toString());
|
|
|
- message[0] = ttsResponse.toString();
|
|
|
}
|
|
|
|
|
|
@Override
|
|
@@ -83,29 +75,32 @@ public class XfTtsApi {
|
|
|
@Override
|
|
|
public void onClosed(WebSocket webSocket, int code, String reason) {
|
|
|
super.onClosed(webSocket, code, reason);
|
|
|
- progress[1] = true;
|
|
|
+ future.complete(null);
|
|
|
}
|
|
|
});
|
|
|
} catch (Exception e) {
|
|
|
log.error("生成语音文件失败", e);
|
|
|
log.error("错误码查询链接:https://www.xfyun.cn/document/error-code");
|
|
|
- message[0] = e.getMessage();
|
|
|
- progress[1] = true;
|
|
|
+ future.completeExceptionally(e);
|
|
|
}
|
|
|
|
|
|
- while (null == progress[1]) {
|
|
|
- try {
|
|
|
- TimeUnit.MILLISECONDS.sleep(1000);
|
|
|
- } catch (InterruptedException e) {
|
|
|
- e.printStackTrace();
|
|
|
+ String voiceUrl = cfg.getSpeechUrl() + "/" + request.getId() + ".mp3";
|
|
|
+ AtomicReference<ResultVo<String>> resultVo = new AtomicReference<>(R.fail(ExceptionEnum.INTERNAL_SERVER_ERROR, ""));
|
|
|
+
|
|
|
+ future.whenComplete((result, ex) -> {
|
|
|
+ if (ex != null) {
|
|
|
+ resultVo.set(R.fail(ExceptionEnum.INTERNAL_SERVER_ERROR, ex.getMessage()));
|
|
|
+ } else {
|
|
|
+ resultVo.set(R.ok(voiceUrl));
|
|
|
}
|
|
|
- }
|
|
|
- if (StrUtil.isNotBlank(message[0])) {
|
|
|
- return R.fail(ExceptionEnum.INTERNAL_SERVER_ERROR, message[0]);
|
|
|
+ });
|
|
|
+ try {
|
|
|
+ future.get();
|
|
|
+ } catch (InterruptedException | ExecutionException e) {
|
|
|
+ return R.fail(ExceptionEnum.INTERNAL_SERVER_ERROR, e.getMessage());
|
|
|
}
|
|
|
|
|
|
- String voiceUrl = cfg.getSpeechUrl() + "/" + request.getId() + ".mp3";
|
|
|
- return R.ok(voiceUrl);
|
|
|
+ return resultVo.get();
|
|
|
}
|
|
|
|
|
|
}
|