最近笔者在业务中涉及到语音告警的模块,需要讲告警内容以文件或流形式返回给前端进行语音播报,具体的分析与处理如下
首先告警内容提示信息这里做的处理是通过专门字段去存储、编辑,根据拟定好的代码逻辑判断是否触发语音告警操作,比较重要的是考虑用那种api实现文字转语音功能,这里笔者选用的是阿里云的nls语音服务。
<dependency>
<groupId>com.alibaba.nls</groupId>
<artifactId>nls-sdk-tts</artifactId>
<version>2.2.1</version>
</dependency>
# nls语音配置
ali:
nls:
##产品相关信息
app-key:
access-key-id:
access-key-secret:
##语音信息(声音类型、语速)
voice: sijia
pitch-rate: -68
speech-rate: 0
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "ali.nls")
public class NlsProperties {
private String appKey;
private String accessKeyId;
private String accessKeySecret;
private String url;
//发音人
private String voice;
//语调,范围是-500~500,可选,默认是0
private Integer pitchRate;
//语速,范围是-500~500,默认是0
private Integer speechRate;
}
import com.demo.NlsProperties;
import com.demo.NlsTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
@Configuration
public class NlsAutoConfiguration {
@Bean
public NlsTemplate nlsTemplate(NlsProperties nlsProperties, StringRedisTemplate stringRedisTemplate){
return new NlsTemplate(nlsProperties,stringRedisTemplate);
}
}
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.nls.client.AccessToken;
import com.alibaba.nls.client.protocol.OutputFormatEnum;
import com.alibaba.nls.client.protocol.SampleRateEnum;
import com.demo.NlsProperties;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.io.*;
import java.util.Date;
@Slf4j
@RequiredArgsConstructor
public class NlsTemplate {
private final NlsProperties nlsProperties;
private final StringRedisTemplate stringRedisTemplate;
/**
* HTTPS POST请求
*/
public byte[] processPOSTRequest(String text) {
/**
* 设置HTTPS POST请求:
* 1.使用HTTPS协议
* 2.语音合成服务域名:nls-gateway-cn-shanghai.aliyuncs.com
* 3.语音合成接口请求路径:/stream/v1/tts
* 4.设置必须请求参数:appkey、token、text、format、sample_rate
* 5.设置可选请求参数:voice、volume、speech_rate、pitch_rate
*/
String url = "https://nls-gateway-cn-shenzhen.aliyuncs.com/stream/v1/tts";
JSONObject taskObject = new JSONObject();
taskObject.putOpt("appkey", nlsProperties.getAppKey());
taskObject.putOpt("token", this.getToken());
taskObject.putOpt("text", text);
taskObject.putOpt("format", OutputFormatEnum.MP3.getName());
taskObject.putOpt("voice", nlsProperties.getVoice());
taskObject.putOpt("sample_rate", SampleRateEnum.SAMPLE_RATE_16K.value);
// speech_rate 语速,范围是-500~500,可选,默认是0。
taskObject.putOpt("speech_rate", nlsProperties.getSpeechRate());
// pitch_rate 语调,范围是-500~500,可选,默认是0。
taskObject.putOpt("pitch_rate", nlsProperties.getPitchRate());
String bodyContent = JSONUtil.toJsonStr(taskObject);
System.out.println("POST Body Content: " + bodyContent);
RequestBody reqBody = RequestBody.create(MediaType.parse("application/json"), bodyContent);
Request request = new Request.Builder()
.url(url)
.header("Content-Type", "application/json")
.post(reqBody)
.build();
try {
OkHttpClient client = new OkHttpClient();
Response response = client.newCall(request).execute();
String contentType = response.header("Content-Type");
byte[] data = null;
if ("audio/mpeg".equals(contentType)) {
data = response.body().bytes();
System.out.println("The POST request succeed!");
} else {
String errorMessage = response.body().string();
System.out.println("The POST request failed: " + errorMessage);
}
response.close();
if (data != null && data.length > 0) {
// String filePath = "D:/test.wav"; //音频文件保存路径及文件名
// saveFile(data, filePath); //调用函数将音频保存到本地
return data;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* token暂存redis中
*
*
* */
@SneakyThrows
private String getToken() {
String key = "NLS_TOKEN";
Boolean hasKey = stringRedisTemplate.hasKey(key);
if (BooleanUtil.isTrue(hasKey)) {
return stringRedisTemplate.opsForValue().get(key);
}
AccessToken token = new AccessToken(nlsProperties.getAccessKeyId(), nlsProperties.getAccessKeySecret());
token.apply();
String accessToken = token.getToken();
stringRedisTemplate.opsForValue().set(key, accessToken);
stringRedisTemplate.expireAt(key, new Date(token.getExpireTime() * 1000));
return accessToken;
}
/**
* 文件转换与生成
*
* */
public static void saveFile(byte[] bytes, String filePath) {
try {
FileOutputStream fos = new FileOutputStream(new File(filePath));
fos.write(bytes);
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
具体的配置可以参考官方文档 https://help.aliyun.com/product/30413.html?spm=a2c4g.750001.0.0.61184fadyUJTlQ ;
如果服务会频繁使用,可以把获取到阿里云token暂存在redis使用。
以上是语音合成业务的大致实现方案,感谢聆听和指正。后续笔者尝试或有改进的方案也会同步上去。