xf 维语转语音
This commit is contained in:
@@ -3,6 +3,7 @@ package com.newyetai.ai.resume.controller;
|
|||||||
import com.newyetai.ai.resume.dto.AiResumeReqDTO;
|
import com.newyetai.ai.resume.dto.AiResumeReqDTO;
|
||||||
import com.newyetai.ai.resume.service.AiResumeService;
|
import com.newyetai.ai.resume.service.AiResumeService;
|
||||||
import com.newyetai.common.AlitaResult;
|
import com.newyetai.common.AlitaResult;
|
||||||
|
import com.newyetai.sdk.xf.dto.TtsReqDTO;
|
||||||
import com.newyetai.sdk.xf.util.XfUtils;
|
import com.newyetai.sdk.xf.util.XfUtils;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -48,8 +49,8 @@ public class AiResumeController {
|
|||||||
|
|
||||||
@PostMapping("/tts")
|
@PostMapping("/tts")
|
||||||
@ApiOperation("ai简历-语音合成")
|
@ApiOperation("ai简历-语音合成")
|
||||||
public AlitaResult<String> tts(@RequestParam("text") String text) {
|
public AlitaResult<String> tts(@RequestBody @Validated TtsReqDTO ttsReq) {
|
||||||
return AlitaResult.success(XfUtils.tts(text));
|
return AlitaResult.success(XfUtils.tts(ttsReq));
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/analyseResume")
|
@PostMapping("/analyseResume")
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ public class RtasrReqDTO implements Serializable {
|
|||||||
|
|
||||||
@NotBlank(message = "语音文件不能为空")
|
@NotBlank(message = "语音文件不能为空")
|
||||||
private String fileCode;
|
private String fileCode;
|
||||||
|
/**
|
||||||
|
* 中文:cn
|
||||||
|
* 维语:cn_uyghur
|
||||||
|
*/
|
||||||
@Default
|
@Default
|
||||||
private String from = "cn_uyghur";
|
private String from = "cn_uyghur";
|
||||||
|
|
||||||
|
|||||||
40
src/main/java/com/newyetai/sdk/xf/dto/TtsReqDTO.java
Normal file
40
src/main/java/com/newyetai/sdk/xf/dto/TtsReqDTO.java
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package com.newyetai.sdk.xf.dto;
|
||||||
|
|
||||||
|
import com.newyetai.sdk.xf.util.WebTtsWS;
|
||||||
|
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 TtsReqDTO implements Serializable {
|
||||||
|
|
||||||
|
@NotBlank(message = "合成文本不能为空")
|
||||||
|
private String text;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发音人
|
||||||
|
* x4_yezi(中文)/x2_ugsp_dilare(维语)
|
||||||
|
*/
|
||||||
|
@Default
|
||||||
|
private String vcn = "xiaoyan";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本编码格式
|
||||||
|
* GB2312
|
||||||
|
* GBK
|
||||||
|
* BIG5
|
||||||
|
* UNICODE(小语种)
|
||||||
|
* GB18030
|
||||||
|
* UTF8(小语种推荐使用UTF8编码)
|
||||||
|
* */
|
||||||
|
@Default
|
||||||
|
private String tte = WebTtsWS.TTL_UTF8;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
@@ -22,6 +23,7 @@ import org.apache.tomcat.util.http.fileupload.ByteArrayOutputStream;
|
|||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.newyetai.common.AlitaResult;
|
import com.newyetai.common.AlitaResult;
|
||||||
import com.newyetai.sdk.xf.config.XfProperties;
|
import com.newyetai.sdk.xf.config.XfProperties;
|
||||||
|
import com.newyetai.sdk.xf.dto.TtsReqDTO;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import okhttp3.HttpUrl;
|
import okhttp3.HttpUrl;
|
||||||
@@ -44,6 +46,9 @@ public class WebTtsWS extends WebSocketListener {
|
|||||||
public static final int StatusFirstFrame = 0;
|
public static final int StatusFirstFrame = 0;
|
||||||
public static final int StatusContinueFrame = 1;
|
public static final int StatusContinueFrame = 1;
|
||||||
public static final int StatusLastFrame = 2;
|
public static final int StatusLastFrame = 2;
|
||||||
|
public static final String TTL_UTF8 = "UTF8";
|
||||||
|
public static final String TTL_UNICODE = "UNICODE";
|
||||||
|
|
||||||
public static final Gson json = new Gson();
|
public static final Gson json = new Gson();
|
||||||
// mp3格式
|
// mp3格式
|
||||||
private String encoding = "lame";
|
private String encoding = "lame";
|
||||||
@@ -52,14 +57,16 @@ public class WebTtsWS extends WebSocketListener {
|
|||||||
private String text;
|
private String text;
|
||||||
private String appId;
|
private String appId;
|
||||||
OutputStream outputStream;
|
OutputStream outputStream;
|
||||||
// 合成文本编码格式
|
// 小语种必须使用UNICODE编码作为值
|
||||||
public static final String TTE = "UTF8"; // 小语种必须使用UNICODE编码作为值
|
private String tte;
|
||||||
// 发音人参数。到控制台-我的应用-语音合成-添加试用或购买发音人,添加后即显示该发音人参数值,若试用未添加的发音人会报错11200
|
// 发音人参数。到控制台-我的应用-语音合成-添加试用或购买发音人,添加后即显示该发音人参数值,若试用未添加的发音人会报错11200
|
||||||
public static final String VCN = "xiaoyan";
|
private String vcn;
|
||||||
|
|
||||||
WebTtsWS(String text, String appId, OutputStream outputStream){
|
WebTtsWS(String text, String appId, String vcn, String tte, OutputStream outputStream){
|
||||||
this.text = text;
|
this.text = text;
|
||||||
this.appId = appId;
|
this.appId = appId;
|
||||||
|
this.vcn = vcn;
|
||||||
|
this.tte = tte;
|
||||||
this.outputStream = outputStream;
|
this.outputStream = outputStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,6 +80,16 @@ public class WebTtsWS extends WebSocketListener {
|
|||||||
super.onOpen(webSocket, response);
|
super.onOpen(webSocket, response);
|
||||||
log.info("ws建立连接成功...");
|
log.info("ws建立连接成功...");
|
||||||
String requestJson;//请求参数json串
|
String requestJson;//请求参数json串
|
||||||
|
String encodedText ;
|
||||||
|
if (WebTtsWS.TTL_UNICODE.equals(tte)) {
|
||||||
|
try {
|
||||||
|
encodedText = Base64.getEncoder().encodeToString(text.getBytes("UTF-16LE"));
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
encodedText = Base64.getEncoder().encodeToString(text.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
requestJson = "{\n" +
|
requestJson = "{\n" +
|
||||||
" \"common\": {\n" +
|
" \"common\": {\n" +
|
||||||
" \"app_id\": \"" + appId + "\"\n" +
|
" \"app_id\": \"" + appId + "\"\n" +
|
||||||
@@ -80,21 +97,19 @@ public class WebTtsWS extends WebSocketListener {
|
|||||||
" \"business\": {\n" +
|
" \"business\": {\n" +
|
||||||
" \"aue\": \"lame\",\n" +
|
" \"aue\": \"lame\",\n" +
|
||||||
" \"sfl\": 1,\n" +
|
" \"sfl\": 1,\n" +
|
||||||
" \"tte\": \"" + TTE + "\",\n" +
|
" \"tte\": \"" + tte + "\",\n" +
|
||||||
" \"ent\": \"intp65\",\n" +
|
" \"ent\": \"intp65\",\n" +
|
||||||
" \"vcn\": \"" + VCN + "\",\n" +
|
" \"vcn\": \"" + vcn + "\",\n" +
|
||||||
" \"pitch\": 50,\n" +
|
" \"pitch\": 50,\n" +
|
||||||
" \"speed\": 50\n" +
|
" \"speed\": 50\n" +
|
||||||
" },\n" +
|
" },\n" +
|
||||||
" \"data\": {\n" +
|
" \"data\": {\n" +
|
||||||
" \"status\": 2,\n" +
|
" \"status\": 2,\n" +
|
||||||
" \"text\": \""
|
" \"text\": \""
|
||||||
+ Base64.getEncoder().encodeToString(text.getBytes(StandardCharsets.UTF_8)) + "\"\n" +
|
+ encodedText + "\"\n" +
|
||||||
//" \"text\": \"" + Base64.getEncoder().encodeToString(TEXT.getBytes("UTF-16LE")) + "\"\n" +
|
|
||||||
" }\n" +
|
" }\n" +
|
||||||
"}";
|
"}";
|
||||||
webSocket.send(requestJson);
|
webSocket.send(requestJson);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -145,7 +160,7 @@ public class WebTtsWS extends WebSocketListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AlitaResult<Void> execute(String text, XfProperties xfProperties, OutputStream outputStream) {
|
public static AlitaResult<Void> execute(TtsReqDTO ttsReq, XfProperties xfProperties, OutputStream outputStream) {
|
||||||
try {
|
try {
|
||||||
// 构建鉴权url
|
// 构建鉴权url
|
||||||
String authUrl = getAuthUrl(xfProperties.getTtsHostUrl(), xfProperties.getApiKey(),
|
String authUrl = getAuthUrl(xfProperties.getTtsHostUrl(), xfProperties.getApiKey(),
|
||||||
@@ -154,7 +169,7 @@ public class WebTtsWS extends WebSocketListener {
|
|||||||
//将url中的 schema http://和https://分别替换为ws:// 和 wss://
|
//将url中的 schema http://和https://分别替换为ws:// 和 wss://
|
||||||
String url = authUrl.toString().replace("http://", "ws://").replace("https://", "wss://");
|
String url = authUrl.toString().replace("http://", "ws://").replace("https://", "wss://");
|
||||||
Request request = new Request.Builder().url(url).build();
|
Request request = new Request.Builder().url(url).build();
|
||||||
WebTtsWS webIATWS = new WebTtsWS(text, xfProperties.getAppId(), outputStream);
|
WebTtsWS webIATWS = new WebTtsWS(ttsReq.getText(), xfProperties.getAppId(), ttsReq.getVcn(), ttsReq.getTte(), outputStream);
|
||||||
WebSocket webSocket = client.newWebSocket(request, webIATWS);
|
WebSocket webSocket = client.newWebSocket(request, webIATWS);
|
||||||
while (webIATWS.result == null) {
|
while (webIATWS.result == null) {
|
||||||
// 未拿到结果等待
|
// 未拿到结果等待
|
||||||
@@ -165,7 +180,6 @@ public class WebTtsWS extends WebSocketListener {
|
|||||||
log.info("err ", e);
|
log.info("err ", e);
|
||||||
return AlitaResult.error("语音合成失败:{}", e.getMessage());
|
return AlitaResult.error("语音合成失败:{}", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getAuthUrl(String hostUrl, String apiKey, String apiSecret)
|
public static String getAuthUrl(String hostUrl, String apiKey, String apiSecret)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import com.newyetai.component.file.util.FileUtils;
|
|||||||
import com.newyetai.config.service.ConfigService;
|
import com.newyetai.config.service.ConfigService;
|
||||||
import com.newyetai.sdk.xf.config.XfProperties;
|
import com.newyetai.sdk.xf.config.XfProperties;
|
||||||
import com.newyetai.sdk.xf.dto.InterviewContentDTO;
|
import com.newyetai.sdk.xf.dto.InterviewContentDTO;
|
||||||
|
import com.newyetai.sdk.xf.dto.TtsReqDTO;
|
||||||
import com.newyetai.sdk.xf.model.ChatReq;
|
import com.newyetai.sdk.xf.model.ChatReq;
|
||||||
import com.newyetai.sdk.xf.model.MessageDTO;
|
import com.newyetai.sdk.xf.model.MessageDTO;
|
||||||
import com.newyetai.sdk.xf.service.XfSparkProvider;
|
import com.newyetai.sdk.xf.service.XfSparkProvider;
|
||||||
@@ -123,15 +124,14 @@ public class XfUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 语音合成
|
* 语音合成
|
||||||
* @return
|
* @return
|
||||||
* @author sr on 2025-01-09
|
* @author sr on 2025-01-09
|
||||||
*/
|
*/
|
||||||
public static String tts(String text) {
|
public static String tts(TtsReqDTO ttsReq) {
|
||||||
try(ByteArrayOutputStream outputStream = new ByteArrayOutputStream()){
|
try(ByteArrayOutputStream outputStream = new ByteArrayOutputStream()){
|
||||||
AlitaResult<Void> result = WebTtsWS.execute(text, xfProperties, outputStream);
|
AlitaResult<Void> result = WebTtsWS.execute(ttsReq, xfProperties, outputStream);
|
||||||
Assert.isTrue(result.getSuccess(), result.getMsg());
|
Assert.isTrue(result.getSuccess(), result.getMsg());
|
||||||
FileRecord fileRecord = fileService.upload("语音合成.mp3", outputStream.toByteArray());
|
FileRecord fileRecord = fileService.upload("语音合成.mp3", outputStream.toByteArray());
|
||||||
return fileRecord.getFileCode();
|
return fileRecord.getFileCode();
|
||||||
|
|||||||
Reference in New Issue
Block a user