xf实时语音转写
This commit is contained in:
18
pom.xml
18
pom.xml
@@ -353,6 +353,24 @@
|
||||
<version>3.4.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 讯飞-星火大模型相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.xfyun</groupId>
|
||||
<artifactId>websdk-java-spark</artifactId>
|
||||
<version>2.1.3</version>
|
||||
</dependency>
|
||||
<!-- 讯飞-语音相关能力 -->
|
||||
<dependency>
|
||||
<groupId>cn.xfyun</groupId>
|
||||
<artifactId>websdk-java-speech</artifactId>
|
||||
<version>3.0.3</version>
|
||||
</dependency>
|
||||
<!-- 讯飞-自然语言处理 -->
|
||||
<dependency>
|
||||
<groupId>cn.xfyun</groupId>
|
||||
<artifactId>websdk-java-nlp</artifactId>
|
||||
<version>2.0.7</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -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<String> chat(@Validated @RequestBody TranslateReq req) {
|
||||
public AlitaResult<String> translate(@Validated @RequestBody TranslateReq req) {
|
||||
return AlitaResult.success(XfUtils.translate(req));
|
||||
}
|
||||
|
||||
@PostMapping("rtasr")
|
||||
@ApiOperation("ai实时语音转写")
|
||||
public AlitaResult<String> rtasr(@Validated @RequestBody RtasrReqDTO req) {
|
||||
return AlitaResult.success(XfUtils.rtasr(req));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
24
src/main/java/com/newyetai/sdk/xf/dto/RtasrReqDTO.java
Normal file
24
src/main/java/com/newyetai/sdk/xf/dto/RtasrReqDTO.java
Normal file
@@ -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";
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -22,7 +22,18 @@ public class ChatReq implements Serializable{
|
||||
@Singular
|
||||
@NotNull(message = "消息内容不能为空")
|
||||
private List<MessageDTO> 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";
|
||||
|
||||
|
||||
|
||||
|
||||
155
src/main/java/com/newyetai/sdk/xf/service/RtasrClientApp.java
Normal file
155
src/main/java/com/newyetai/sdk/xf/service/RtasrClientApp.java
Normal file
@@ -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信息获取:<a
|
||||
* href="https://console.xfyun.cn/services/rta">...</a> 2、文档地址:<a
|
||||
* href="https://www.xfyun.cn/doc/asr/rtasr/API.html">...</a>
|
||||
*
|
||||
* @author kaili23
|
||||
*/
|
||||
public class RtasrClientApp extends AbstractRtasrWebSocketListener{
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(RtasrClientApp.class);
|
||||
|
||||
/**
|
||||
* 记录完整结果
|
||||
*/
|
||||
private StringBuffer finalResult = new StringBuffer();
|
||||
|
||||
private AlitaResult<String> result;
|
||||
|
||||
/**
|
||||
* 线程同步
|
||||
*/
|
||||
private CountDownLatch latch;
|
||||
|
||||
RtasrClientApp(CountDownLatch latch){
|
||||
this.latch = latch;
|
||||
}
|
||||
|
||||
public AlitaResult<String> 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<String> 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<String> result = XfSparkProvider.httpChat(req);
|
||||
Assert.isTrue(result.getSuccess(), result.getMsg());
|
||||
return result.getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* 翻译
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
public static String translate(TranslateReq req) {
|
||||
AlitaResult<String> 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<String> result = RtasrClientApp.execute(is, reqDTO.getFrom(), xfProperties);
|
||||
Assert.isTrue(result.getSuccess(), result.getMsg());
|
||||
return result.getData();
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException("语音听写异常:" + e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
BIN
src/main/resources/iat/ug.pcm
Normal file
BIN
src/main/resources/iat/ug.pcm
Normal file
Binary file not shown.
@@ -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
|
||||
@@ -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<String> result = RtasrClientApp.execute(is, "cn_uyghur", xfProperties);
|
||||
log.info("{}", result);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user