diff --git a/pom.xml b/pom.xml
index 16004b1..5c61eb3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -353,6 +353,24 @@
3.4.0
+
+
+ cn.xfyun
+ websdk-java-spark
+ 2.1.3
+
+
+
+ cn.xfyun
+ websdk-java-speech
+ 3.0.3
+
+
+
+ cn.xfyun
+ websdk-java-nlp
+ 2.0.7
+
diff --git a/src/main/java/com/newyetai/ai/controller/AiController.java b/src/main/java/com/newyetai/ai/controller/AiController.java
index b2bcde8..919d51e 100644
--- a/src/main/java/com/newyetai/ai/controller/AiController.java
+++ b/src/main/java/com/newyetai/ai/controller/AiController.java
@@ -1,6 +1,7 @@
package com.newyetai.ai.controller;
import com.newyetai.common.AlitaResult;
+import com.newyetai.sdk.xf.dto.RtasrReqDTO;
import com.newyetai.sdk.xf.model.ChatReq;
import com.newyetai.sdk.xf.model.TranslateReq;
import com.newyetai.sdk.xf.util.XfUtils;
@@ -25,9 +26,15 @@ public class AiController {
@PostMapping("translate")
@ApiOperation("ai翻译")
- public AlitaResult chat(@Validated @RequestBody TranslateReq req) {
+ public AlitaResult translate(@Validated @RequestBody TranslateReq req) {
return AlitaResult.success(XfUtils.translate(req));
}
+ @PostMapping("rtasr")
+ @ApiOperation("ai实时语音转写")
+ public AlitaResult rtasr(@Validated @RequestBody RtasrReqDTO req) {
+ return AlitaResult.success(XfUtils.rtasr(req));
+ }
+
}
diff --git a/src/main/java/com/newyetai/sdk/xf/config/XfProperties.java b/src/main/java/com/newyetai/sdk/xf/config/XfProperties.java
index 827027c..5937ba2 100644
--- a/src/main/java/com/newyetai/sdk/xf/config/XfProperties.java
+++ b/src/main/java/com/newyetai/sdk/xf/config/XfProperties.java
@@ -36,6 +36,16 @@ public class XfProperties implements Serializable{
private String ttsHostUrl;
/** 机器翻译niutrans **/
private String otsHostUrl;
+ /** 实时语音转写 **/
+ private XfAppProperties rtasr;
+
+ @Data
+ @NoArgsConstructor
+ @AllArgsConstructor
+ @Builder
+ public static class XfAppProperties implements Serializable{
+ private String apiKey;
+ }
}
diff --git a/src/main/java/com/newyetai/sdk/xf/dto/RtasrReqDTO.java b/src/main/java/com/newyetai/sdk/xf/dto/RtasrReqDTO.java
new file mode 100644
index 0000000..b5b1399
--- /dev/null
+++ b/src/main/java/com/newyetai/sdk/xf/dto/RtasrReqDTO.java
@@ -0,0 +1,24 @@
+package com.newyetai.sdk.xf.dto;
+
+import java.io.Serializable;
+import javax.validation.constraints.NotBlank;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Builder.Default;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class RtasrReqDTO implements Serializable {
+
+ @NotBlank(message = "语音文件不能为空")
+ private String fileCode;
+ @Default
+ private String from = "cn_uyghur";
+
+
+
+}
diff --git a/src/main/java/com/newyetai/sdk/xf/model/ChatReq.java b/src/main/java/com/newyetai/sdk/xf/model/ChatReq.java
index cd9c244..3927708 100644
--- a/src/main/java/com/newyetai/sdk/xf/model/ChatReq.java
+++ b/src/main/java/com/newyetai/sdk/xf/model/ChatReq.java
@@ -22,8 +22,19 @@ public class ChatReq implements Serializable{
@Singular
@NotNull(message = "消息内容不能为空")
private List messages;
-
-
-
+ @Default
+ private String temperature = "0.3";
+ @Default
+ private String max_tokens = "150";
+ @Default
+ private String repetition_penalty = "1.25";
+ @Default
+ private String top_p = "0.65";
+ @Default
+ private String presence_penalty = "-0.6";
+ @Default
+ private String frequency_penalty = "0.2";
+
+
}
diff --git a/src/main/java/com/newyetai/sdk/xf/service/RtasrClientApp.java b/src/main/java/com/newyetai/sdk/xf/service/RtasrClientApp.java
new file mode 100644
index 0000000..a98dbda
--- /dev/null
+++ b/src/main/java/com/newyetai/sdk/xf/service/RtasrClientApp.java
@@ -0,0 +1,155 @@
+package com.newyetai.sdk.xf.service;
+
+import cn.hutool.json.JSON;
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import cn.xfyun.api.RtasrClient;
+import cn.xfyun.model.response.rtasr.RtasrResponse;
+import cn.xfyun.service.rta.AbstractRtasrWebSocketListener;
+import com.newyetai.common.AlitaResult;
+import com.newyetai.common.util.JsonUtils;
+import com.newyetai.sdk.xf.config.XfProperties;
+import java.io.InputStream;
+import java.util.concurrent.CountDownLatch;
+import okhttp3.Response;
+import okhttp3.WebSocket;
+import org.apache.commons.codec.binary.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * ( Real-time ASR ) 实时语音转写 1、APPID、APIKey信息获取:... 2、文档地址:...
+ *
+ * @author kaili23
+ */
+public class RtasrClientApp extends AbstractRtasrWebSocketListener{
+
+ private static final Logger logger = LoggerFactory.getLogger(RtasrClientApp.class);
+
+ /**
+ * 记录完整结果
+ */
+ private StringBuffer finalResult = new StringBuffer();
+
+ private AlitaResult result;
+
+ /**
+ * 线程同步
+ */
+ private CountDownLatch latch;
+
+ RtasrClientApp(CountDownLatch latch){
+ this.latch = latch;
+ }
+
+ public AlitaResult getResult() {
+ return result;
+ }
+
+ @Override
+ public void onSuccess(WebSocket webSocket, String text) {
+ RtasrResponse response = JsonUtils.toObject(text, RtasrResponse.class);
+ // finalResult为服务端已转写的完整语句,后面拼接服务端本次返回的当前语句的转写中间结果。
+ String tempResult = handleAndReturnContent(response.getData());
+ logger.info("实时转写结果:{}", finalResult + tempResult);
+ result = AlitaResult.success(finalResult.toString());
+ }
+
+ @Override
+ public void onFail(WebSocket webSocket, Throwable t, Response response) {
+ result = AlitaResult.bizError(t.getMessage());
+ latch.countDown();
+ System.exit(0);
+ }
+
+ @Override
+ public void onBusinessFail(WebSocket webSocket, String text) {
+ logger.error("业务异常,返回信息为:{}", text);
+ result = AlitaResult.bizError(text);
+ latch.countDown();
+ System.exit(0);
+ }
+
+ @Override
+ public void onClosing(WebSocket webSocket, int code, String reason) {
+ latch.countDown();
+ System.exit(0);
+ }
+
+ @Override
+ public void onClosed() {
+ latch.countDown();
+ System.exit(0);
+ }
+
+ public static AlitaResult execute(InputStream is, String from, XfProperties xfProperties) {
+ try {
+ CountDownLatch latch = new CountDownLatch(1);
+ RtasrClientApp app = new RtasrClientApp(latch);
+ RtasrClient client = new RtasrClient.Builder()
+ .signature(xfProperties.getAppId(), xfProperties.getRtasr().getApiKey())
+ .lang(from)
+ // 设置此参数需需开通翻译功能,请在控制台申请并开通
+// .targetLang(to)
+ .build();
+ client.send(is, app);
+ latch.await();
+ return app.getResult();
+ } catch (Exception e) {
+ if (e instanceof InterruptedException) {
+ Thread.currentThread().interrupt();
+ }
+ logger.error("语音转写失败", e);
+ return AlitaResult.error("语音转写失败:{}", e.getMessage());
+ }
+ }
+
+ /**
+ * 解析转写流式响应,更新实时结果,返回此次的中间结果
+ */
+ public String handleAndReturnContent(String message) {
+ StringBuilder tempResult = new StringBuilder();
+
+ try {
+ // 解析本次服务端返回的文本内容
+
+ JSONObject messageObj = JSONUtil.parseObj(message);
+ JSONObject cn = messageObj.getJSONObject("cn");
+ JSONObject st = cn.getJSONObject("st");
+ JSONArray rtArr = st.getJSONArray("rt");
+ for (int i = 0; i < rtArr.size(); i++) {
+ JSONObject rtArrObj = rtArr.getJSONObject(i);
+ JSONArray wsArr = rtArrObj.getJSONArray("ws");
+ for (int j = 0; j < wsArr.size(); j++) {
+ JSONObject wsArrObj = wsArr.getJSONObject(j);
+ JSONArray cwArr = wsArrObj.getJSONArray("cw");
+ for (int k = 0; k < cwArr.size(); k++) {
+ JSONObject cwArrObj = cwArr.getJSONObject(k);
+ String wStr = cwArrObj.getStr("w");
+ tempResult.append(wStr);
+ }
+ }
+ }
+
+ // 根据中间结果类型更新最终结果
+ String type = st.getStr("type");
+ if (StringUtils.equals("1", type)) {
+ // 此时服务端返回的是当前语句的实时转写内容,不保存到最终结果中,返回到调用处进行拼接展示。
+ return tempResult.toString();
+ } else if (StringUtils.equals("0", type)) {
+ // 此时服务端返回的是当前语句的完整转写内容,保存到最终结果中,并返回空字符串。
+ finalResult.append(tempResult);
+ return "";
+ } else {
+ logger.warn("未知的转写响应类型:{}", type);
+ return tempResult.toString();
+ }
+ } catch (Exception e) {
+ return message;
+ }
+ }
+
+}
diff --git a/src/main/java/com/newyetai/sdk/xf/util/XfUtils.java b/src/main/java/com/newyetai/sdk/xf/util/XfUtils.java
index 1c8dc5c..705651b 100644
--- a/src/main/java/com/newyetai/sdk/xf/util/XfUtils.java
+++ b/src/main/java/com/newyetai/sdk/xf/util/XfUtils.java
@@ -1,6 +1,8 @@
package com.newyetai.sdk.xf.util;
+import com.newyetai.sdk.xf.dto.RtasrReqDTO;
import com.newyetai.sdk.xf.model.TranslateReq;
+import com.newyetai.sdk.xf.service.RtasrClientApp;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -99,7 +101,7 @@ public class XfUtils {
/**
* 语音听写
- * @param filePath
+ * @param fileCode
* @return
* @author sr on 2025-01-09
*/
@@ -117,7 +119,6 @@ public class XfUtils {
/**
* 语音合成
- * @param filePath
* @return
* @author sr on 2025-01-09
*/
@@ -230,16 +231,42 @@ public class XfUtils {
return result.getData();
}
+ /**
+ * 对话
+ * @param req
+ * @return
+ */
public static String chat(ChatReq req) {
AlitaResult result = XfSparkProvider.httpChat(req);
Assert.isTrue(result.getSuccess(), result.getMsg());
return result.getData();
}
+ /**
+ * 翻译
+ * @param req
+ * @return
+ */
public static String translate(TranslateReq req) {
AlitaResult result = XfSparkProvider.translate(req);
Assert.isTrue(result.getSuccess(), result.getMsg());
return result.getData();
}
+ /**
+ * 实时语音转写
+ * @param reqDTO
+ * @return
+ */
+ public static String rtasr(RtasrReqDTO reqDTO) {
+ try (InputStream is = fileRecordService.getFile(reqDTO.getFileCode())){
+ AlitaResult result = RtasrClientApp.execute(is, reqDTO.getFrom(), xfProperties);
+ Assert.isTrue(result.getSuccess(), result.getMsg());
+ return result.getData();
+ } catch (Exception e) {
+ throw new BusinessException("语音听写异常:" + e.getMessage());
+ }
+
+ }
+
}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index a927657..ad2c564 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -165,6 +165,8 @@ xf.iatHostUrl=https://iat-api.xfyun.cn/v2/iat
xf.ttsHostUrl=https://tts-api.xfyun.cn/v2/tts
#机器翻译niutrans
xf.otsHostUrl=https://ntrans.xfyun.cn/v2/ots
+#实时语音转写
+xf.rtasr.APIKey=2e33d9128a73be21b294594e5377ca53
#腾讯地图
tencent.map.key=TS7BZ-GOVCB-CUZUL-JUUAV-WTYT3-Z2B4Z
diff --git a/src/main/resources/iat/ug.pcm b/src/main/resources/iat/ug.pcm
new file mode 100644
index 0000000..d7a980b
Binary files /dev/null and b/src/main/resources/iat/ug.pcm differ
diff --git a/src/test/java/com/newyetai/SparkTest.java b/src/test/java/com/newyetai/SparkTest.java
index 36d49be..7244a7d 100644
--- a/src/test/java/com/newyetai/SparkTest.java
+++ b/src/test/java/com/newyetai/SparkTest.java
@@ -1,5 +1,8 @@
package com.newyetai;
+import com.newyetai.sdk.xf.config.XfProperties.XfAppProperties;
+import com.newyetai.sdk.xf.model.TranslateReq;
+import com.newyetai.sdk.xf.service.RtasrClientApp;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -47,9 +50,11 @@ public class SparkTest {
static XfProperties xfProperties = XfProperties.builder()
.iatHostUrl("https://iat-api.xfyun.cn/v2/iat")
.ttsHostUrl("https://tts-api.xfyun.cn/v2/tts")
- .appId("a2847f13")
- .apiSecret("")
- .apiKey("")
+ .otsHostUrl("https://ntrans.xfyun.cn/v2/ots")
+ .appId("83b8ddca")
+ .apiSecret("ZWE2MjkzY2VmZDkwM2EwZGJhNGRhOWJm")
+ .apiKey("e092f93e28ebe6d27f756bb2d884dcff")
+ .rtasr(XfAppProperties.builder().apiKey("2e33d9128a73be21b294594e5377ca53").build())
.build();
@Test
@@ -207,7 +212,7 @@ public class SparkTest {
// WebTtsWS.execute("欢迎来到讯飞开放平台", xfProperties, outputStream);
// fs.write(outputStream.toByteArray());
// }
-
+
try(ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
OutputStream fs = new FileOutputStream("src/main/resources/iat/323.mp3");){
AlitaResult result = WebTtsWS.execute("欢迎来到讯飞开放平台", xfProperties, outputStream);
@@ -218,4 +223,20 @@ public class SparkTest {
}
}
+ @Test
+ public void ots(){
+// AlitaResult> result = XfSparkProvider.translate(TranslateReq.builder().text("欢迎#你啊,.;@#$你好").build(), xfProperties);
+ AlitaResult> result = XfSparkProvider.translate(TranslateReq.builder().text("تىيانەي ئەقىللىق خىزمەت مۇلازىمىتى بىرلەشمە سۇپىسىغا خوش ھەمرىيىڭىز.").from("uy").to("cn").build(), xfProperties);
+ log.info("{}", result);
+ }
+
+ @Test
+ public void rtasr() throws IOException {
+ String file = "src/main/resources/iat/ug.pcm";
+ try (InputStream is = new FileInputStream(file)) {
+ AlitaResult result = RtasrClientApp.execute(is, "cn_uyghur", xfProperties);
+ log.info("{}", result);
+ }
+ }
+
}