一、解决byte[]数组转String类型失真
public class ByteConvertUtil {
public static String bytesToHexString(byte[] bArr) {
StringBuffer sb = new StringBuffer(bArr.length);
String sTmp;
for (int i = 0; i < bArr.length; i++) {
sTmp = Integer.toHexString(0xFF & bArr[i]);
if (sTmp.length() < 2){
sb.append(0);
}
sb.append(sTmp.toUpperCase());
}
return sb.toString();
}
public static byte[] hexToByteArray(String inHex){
int hexlen = inHex.length();
byte[] result;
if (hexlen % 2 == 1){
//奇数
hexlen++;
result = new byte[(hexlen/2)];
inHex="0"+inHex;
}else {
//偶数
result = new byte[(hexlen/2)];
}
int j=0;
for (int i = 0; i < hexlen; i+=2){
result[j]=(byte)Integer.parseInt(inHex.substring(i,i+2),16);
j++;
}
return result;
}
}
二、解决重命名问题
public static String deduplicateLabel(String labelString) {
String[] labelArray = labelString.split(",");
Set<String> stringSet = new HashSet<>();
//去重
for (String str : labelArray) {
if (StringUtils.isBlank(str)) {
continue;
}
stringSet.add(str);
}
//拼接
StringBuffer deduplicatedString = new StringBuffer();
for (String str : stringSet) {
deduplicatedString.append(str).append(",");
}
return deduplicatedString.substring(0, deduplicatedString.length() - 1);
}
public static String aliasName(String name){
if(Pattern.matches(".*([1-9][0-9]{0,100000})", name)){
//拆分数据
String substring = name.substring(name.indexOf("(") + 1, name.indexOf(")"));
int number = Integer.parseInt(substring);
String[] split = name.split("(");
return split[0].concat("(").concat(String.valueOf(number+1)).concat(")");
}else{
return name.concat("(1)");
}
}
三、服务器成本计算
public class ServerCostUtils {
public static int vmCost(ServerCostVO serverCostVO) {
// 服务器按3年折旧,1GB虚拟机使用成本约为11
// 每核心cpu按0.5元计算
int cost = 0;
cost = serverCostVO.getCpu() / 2 + serverCostVO.getMemory() / 1024 * 11;
return cost;
}
public static int ecsCost(ServerCostVO serverCostVO) {
String ecsType = serverCostVO.getCpu() + "/" + serverCostVO.getMemory() / 1024;
// cpu / memory(GB) 此费用在阿里云查询得到
switch (ecsType) {
case "1/1":
return 105;
case "1/2":
return 129;
case "2/4":
return 237;
case "4/8":
return 437;
case "8/16":
return 825;
case "16/32":
return 1601;
case "32/64":
return 3153;
default:
return 0;
}
}
}
四、流式合成TTS
依赖
<dependency>
<groupId>com.alibaba.nls</groupId>
<artifactId>nls-sdk-tts</artifactId>
<version>2.1.6</version>
</dependency>
代码
import com.alibaba.nls.client.AccessToken;
import com.alibaba.nls.client.protocol.NlsClient;
import com.alibaba.nls.client.protocol.OutputFormatEnum;
import com.alibaba.nls.client.protocol.SampleRateEnum;
import com.alibaba.nls.client.protocol.tts.SpeechSynthesizer;
import com.alibaba.nls.client.protocol.tts.SpeechSynthesizerListener;
import com.alibaba.nls.client.protocol.tts.SpeechSynthesizerResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.nio.ByteBuffer;
@Slf4j
public class SpeechUtils {
public StringBuffer buffers = new StringBuffer();
public String appKey;
NlsClient client;
public SpeechUtils(String appKey, String accessKeyId, String accessKeySecret, String url) {
this.appKey = appKey;
AccessToken accessToken = new AccessToken(accessKeyId, accessKeySecret);
try {
accessToken.apply();
if(url.isEmpty()) {
client = new NlsClient(accessToken.getToken());
}else {
client = new NlsClient(url, accessToken.getToken());
}
} catch (IOException e) {
log.error("客户端连接创建失败:{}", e);
}
}
public SpeechSynthesizerListener SpeechUtils() {
SpeechSynthesizerListener listener = null;
try {
listener = new SpeechSynthesizerListener() {
private boolean firstRecvBinary = true;
private StringBuffer buffer = new StringBuffer();
//语音合成结束
@Override
public void onComplete(SpeechSynthesizerResponse response) {
buffers.append(buffer);
}
//语音合成的语音二进制数据
@Override
public void onMessage(ByteBuffer message) {
try {
if (firstRecvBinary) {
//计算首包语音流的延迟,收到第一包语音流时,即可以进行语音播放,以提升响应速度(特别是实时交互场景下)。
firstRecvBinary = false;
}
byte[] bytesArray = new byte[message.remaining()];
message.get(bytesArray, 0, bytesArray.length);
buffer.append(ByteConvertUtil.bytesToHexString(bytesArray));
} catch (Exception e) {
log.error("语音合成流失败:{}", e);
}
}
@Override
public void onFail(SpeechSynthesizerResponse response) {}
};
} catch (Exception e) {
log.error("TTS调用失败:{}",e);
}
return listener;
}
public void process(String text, String voice, Integer volume, Integer speechRate,
Integer pitchRate) {
SpeechSynthesizer synthesizer = null;
try {
//创建实例,建立连接。
synthesizer = new SpeechSynthesizer(client, SpeechUtils());
synthesizer.setAppKey(appKey);
//设置返回音频的编码格式
synthesizer.setFormat(OutputFormatEnum.WAV);
//设置返回音频的采样率
synthesizer.setSampleRate(SampleRateEnum.SAMPLE_RATE_16K);
//发音人
synthesizer.setVoice(StringUtils.isEmpty(voice) ? "xiaoyun" :voice);
//语调,范围是-500~500,可选,默认是0。
synthesizer.setPitchRate(StringUtils.isEmpty(pitchRate) ? 0 : pitchRate);
//语速,范围是-500~500,默认是0。
synthesizer.setSpeechRate(StringUtils.isEmpty(speechRate) ? 0 : speechRate);
//音量
synthesizer.setVolume(StringUtils.isEmpty(volume) ? 50 : volume);
//设置用于语音合成的文本
synthesizer.setText(text);
// 是否开启字幕功能(返回相应文本的时间戳),默认不开启,需要注意并非所有发音人都支持该参数。
synthesizer.addCustomedParam("enable_subtitle", false);
synthesizer.start();
synthesizer.waitForComplete();
} catch (Exception e) {
log.error("TTS合成语音失败:{}",e);
} finally {
//关闭连接
if (null != synthesizer) {
synthesizer.close();
}
}
}
public void shutdown() {
client.shutdown();
}
}