• 文字转语音播报模块(一):阿里云nls服务使用示例


    一、业务场景

    最近笔者在业务中涉及到语音告警的模块,需要将告警内容以文件或流形式返回给前端进行语音播报,具体的分析与处理如下

    二、业务分析

    首先告警内容提示信息这里做的处理是通过专门字段去存储、编辑,根据拟定好的代码逻辑判断是否触发语音告警操作,后续考虑用哪种方案实现文字转语音功能合适,这里笔者选用的是阿里云付费的nls语音服务。

    三、解决方案

    1、pom文件引入

    <dependency>
        <groupId>com.alibaba.nls</groupId>
        <artifactId>nls-sdk-tts</artifactId>
        <version>2.2.1</version>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2、yml文件配置添加

    #  nls语音配置
    ali:
      nls:
      ##产品相关信息
        app-key: 
        access-key-id: 
        access-key-secret: 
      ##语音信息(声音类型、语速)
        voice: sijia
        pitch-rate: -68
        speech-rate: 0
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3、实体类构建

    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;
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    4、config类构建

    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);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    5、服务类构建

    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();
            }
        }
    
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117

    具体的配置可以参考官方文档 https://help.aliyun.com/product/30413.html?spm=a2c4g.750001.0.0.61184fadyUJTlQ
    如果服务会频繁使用,可以把获取到阿里云token暂存在redis使用。

    四、尾言

    以上是语音合成业务的大致实现方案,后续笔者尝试或有改进的方案也会同步上去,感谢阅读和指正。

  • 相关阅读:
    Allegro Design Entry HDL(OrCAD Capture HDL)模块管理菜单详细介绍
    金仓数据库 KingbaseES 插件参考手册 R
    北斗导航 | 从事卫星导航工作需要知道的基本算法
    Auto.js脚本开发入门
    node插件MongoDB(二)——MongoDB的基本命令
    前端 代码规范
    【PS-7】移动工具
    数据库总结
    Spring MVC相关
    机器学习算法系列————决策树(二)
  • 原文地址:https://blog.csdn.net/weixin_50927151/article/details/133643760