|
|
@@ -0,0 +1,111 @@
|
|
|
+package org.thyy.thirdpartapi.xfyun;
|
|
|
+
|
|
|
+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 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.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;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
+@RestController
|
|
|
+@RequestMapping("/xfTtsApi")
|
|
|
+public class XfTtsApi {
|
|
|
+ private TtsClient ttsClient;
|
|
|
+ private final XfConfig cfg;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ public XfTtsApi(XfConfig cfg) {
|
|
|
+ this.cfg = cfg;
|
|
|
+ }
|
|
|
+
|
|
|
+ @PostConstruct
|
|
|
+ public void initTtsClient() {
|
|
|
+ try {
|
|
|
+ if (StrUtil.isBlank(cfg.getDirectory())) {
|
|
|
+ cfg.setDirectory(System.getProperty("user.dir"));
|
|
|
+ }
|
|
|
+ ttsClient = new TtsClient.Builder()
|
|
|
+ .signature(cfg.getAppId(), cfg.getApiKey(), cfg.getApiSecret())
|
|
|
+ .vcn("aisjinger").volume(100).build();
|
|
|
+ log.info("讯飞SDK初始化成功。");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("讯飞SDK初始化失败:", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @PostMapping("/textToSpeech")
|
|
|
+ public ResultVo<String> textToSpeech(@RequestBody TtsRequest request) {
|
|
|
+ String filePath = cfg.getDirectory() + File.separator + request.getId() + ".mp3";
|
|
|
+ FileUtil.del(filePath);
|
|
|
+
|
|
|
+ final Boolean[] progress = { false, null };
|
|
|
+ final String[] message = {""};
|
|
|
+ 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
|
|
|
+ public void onClosing(WebSocket webSocket, int code, String reason) {
|
|
|
+ super.onClosing(webSocket, code, reason);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onClosed(WebSocket webSocket, int code, String reason) {
|
|
|
+ super.onClosed(webSocket, code, reason);
|
|
|
+ progress[1] = true;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("生成语音文件失败", e);
|
|
|
+ log.error("错误码查询链接:https://www.xfyun.cn/document/error-code");
|
|
|
+ message[0] = e.getMessage();
|
|
|
+ progress[1] = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ while (null == progress[1]) {
|
|
|
+ try {
|
|
|
+ TimeUnit.MILLISECONDS.sleep(1000);
|
|
|
+ } catch (InterruptedException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (StrUtil.isNotBlank(message[0])) {
|
|
|
+ return R.fail(ExceptionEnum.INTERNAL_SERVER_ERROR, message[0]);
|
|
|
+ }
|
|
|
+
|
|
|
+ String voiceUrl = cfg.getSpeechUrl() + "/" + request.getId() + ".mp3";
|
|
|
+ return R.ok(voiceUrl);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|