• uniapp开发小程序接入阿里云TTS语音合成(RESTful API)


    流程
    1. 首先小程序后台配置白名单
      1.1 路径:开发-开发管理-开发设置-服务器域名-request合法域名
      1.2 request合法域名参数:
            https://nls-meta.cn-shanghai.aliyuncs.com
            https://nls-gateway-cn-shanghai.aliyuncs.com
    2. 引入alitts.js
    3. 页面使用
      3.1 只需替换AccessKeyID、AccessKeySecret 、appkey三个参数即可直接使用
    AccessKeyID、AccessKeySecret 、appkey获取地址:
    1. 阿里云RESTful API对接文档
    2. 阿里云TTS管理平台创建项目获取appkey
    3. 阿里云获取AccessKeyID和AccessKeySecret
    static/js/alitts.js 用于获取阿里云动态token
    // 这个东西我都没执行yarn add crypto竟然能用,可能另一个项目安装了全局共享了,如报错找不到,执行一下yarn add crypto
    import crypto from 'crypto'
    
    export class AccessToken {
        static encodeText(text) {
            let encodedText = encodeURIComponent(text);
            return encodedText.replace('+', '%20').replace('*', '%2A').replace('~', '%7E');
        }
    
        static encodeDict(dict) {
            let keys = Object.keys(dict).sort();
            return keys.map(key => `${this.encodeText(key)}=${this.encodeText(dict[key])}`).join('&');
        }
    
        static async createToken(accessKeyId, accessKeySecret) {
            const parameters = {
                AccessKeyId: accessKeyId,
                Action: 'CreateToken',
                Format: 'JSON',
                RegionId: 'cn-shanghai',
                SignatureMethod: 'HMAC-SHA1',
                SignatureNonce: uuidv4(),
                SignatureVersion: '1.0',
                Timestamp: new Date().toISOString(),
                Version: '2019-02-28'
            };
    
            const queryString = this.encodeDict(parameters);
            console.log('Normalized request string:', queryString);
    
            const stringToSign = `GET&${this.encodeText('/')}&${this.encodeText(queryString)}`;
            console.log('String to sign:', stringToSign);
    
            const hmac = crypto.createHmac('sha1', `${accessKeySecret}&`);
            hmac.update(stringToSign);
            const signature = hmac.digest('base64');
            console.log('Signature:', signature);
    
            const encodedSignature = this.encodeText(signature);
            console.log('URL-encoded signature:', encodedSignature);
    
            const fullUrl = `https://nls-meta.cn-shanghai.aliyuncs.com/?Signature=${encodedSignature}&${queryString}`;
            console.log('URL:', fullUrl);
    
            let resData =  await new Promise((resolve, reject) => {
                uni.request({
                    url: fullUrl,
                    method: 'GET',
                    success: res => {
                        const data = res.data
                        resolve({
                            token: data.Token.Id,
                            expireTime: data.Token.ExpireTime
                        })
                    },
                    fail: error => {
                        console.log(error)
                        reject(error)
                    }
                })
            })
             console.log('res',resData)
             if(resData){
                return resData
             }
            // Using fetch for HTTP request
            // const response = await fetch(fullUrl);
            // if (response.ok) {
            //     const jsonResponse = await response.json();
            //     if (jsonResponse.Token) {
            //         return {
            //             token: jsonResponse.Token.Id,
            //             expireTime: jsonResponse.Token.ExpireTime
            //         };
            //     }
            // }
            // console.error(await response.text());
            return {
                token: null,
                expireTime: null
            };
        }
    }
    
    // Sample UUIDv4 function, or you could use a library like `uuid`
    function uuidv4() {
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
            var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
            return v.toString(16);
        });
    }
    
    • 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
    使用
    // 阿里云动态token获取函数
    import { AccessToken } from "@/static/js/alitts"
    // 阿里云动态token
    const aliToken = null
    // 需要在阿里云管理平台获取
    const AccessKeyID = '你的AccessKeyID '
    const AccessKeySecret = '你的AccessKeySecret '
    // 需要在阿里云tts管理平台创建项目
    const appkey = '你的阿里云后台创建项目的key'
    
    export default {
        name: "tts",
        data() {
            return {
            	isPlay:false,
            	// tts播放实例
                ttsAudio: null,
            }
        },
        onUnload() {
            if(this.ttsAudio){
                this.ttsAudio.stop()
                this.ttsAudio.destroy()
            }
        },
        async onLoad(val) {
    		// 获取阿里云动态token,tts需要此参数
    		AccessToken.createToken(AccessKeyID, AccessKeySecret).then(({ token, expireTime }) => {
    		   console.log('阿里云token:', token, 'Expire Time:', expireTime);
    		   aliToken = token
    		});
    
    		// 模拟调用
    		setTimeout(() => {
    			this.tts('刘斩仙明天要去江苏,晚上回来又约了朋友撸串,忙死了')
    		},5000)
    	},
    	methods: {
    		/**
    		* 文字转语音
    		* @param {string} text 
    		*/
    		tts(text) {
    			uni.request({
    			      url:'https://nls-gateway-cn-shanghai.aliyuncs.com/stream/v1/tts',
    			      method:'POST',
    			      // header:{
    			      //     "Content-Type": "application/json"
    			      // },
    			      data:{
    			          appkey: appkey,
    			          token: aliToken,
    			          text: text,
    			          format: 'mp3',
    			          sample_rate: 16000,
    			          volume: 100
    			      },
    			      // dataType:'tts',
    			      responseType:'arraybuffer',
    			      success:ttsRes => {
    			           console.log('阿里云:')
    			          // 语音
    			          const audio = uni.createInnerAudioContext();
    			          // 设置不遵循静音开关播放,否则ios无法外音播放
    			          audio.obeyMuteSwitch = false
    			          uni.setInnerAudioOption({
    			              obeyMuteSwitch: false
    			          })
    			          // 临时路径-此处必须加时间戳或者随机数,否则同样临时路径无法覆盖,小程序bug
    			          const ttsPath = `${wx.env.USER_DATA_PATH}/tts${new Date().getTime()}.mp3`
    			          if(this.ttsAudio){
    			              this.ttsAudio.stop()
    			              this.ttsAudio.destroy()
    			          }
    			          this.ttsAudio = audio
    			          // 将 arrayBuffer 写入临时文件
    			          const fs = uni.getFileSystemManager()
    			          try {
    			              const writeRes = fs.writeFileSync(ttsPath, ttsRes.data, "binary")
    			              console.log('writeRes',writeRes)
    			          } catch(e) {
    			              console.error(e)
    			          }
    			          
    			          audio.src = ttsPath
    			          audio.autoplay = false;
    			          audio.onError((res) => {
    			              console.error('音频播放出错', res);
    			          });
    			          // 监听播放完成
    			          audio.onEnded(() => {
    			              console.log('音频播放结束');
    			              this.isPlay = false
    			              // 播放完成后删除临时文件,此处虽然设置同步删除即使执行成功,文件也不会立即删除,还是能访问到,实际删除为异步操作
    			              try {
    			                  const unlinkRes = fs.unlinkSync(ttsPath)
    			                  console.log('unlinkRes',unlinkRes)
    			              } catch(e) {
    			                  console.error(e)
    			              }
    			          });
    			          // 播放音频
    			          audio.onCanplay(() => {
    			              console.log('音频开始播放');
    			              this.ttsAudio.play();
    			              this.isPlay = true
    			          })   
    			      }
    			  })
    		}
    	},
    }
    
    • 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
    备注:

    就想到这些,如果还有需要注意的后续再补充;最近骑电车要带头盔,飘逸的发型压得趴在头上,影响刘斩仙风度翩翩谦谦君子形象,可恶啊!

  • 相关阅读:
    PCL 使用MLS 上采样
    flink1.15.2 报错 processElement_split
    选低代码开发的OA系统,对低效办公说“漏”
    Netty12-Netty的入站出站编解码
    Spring笔记(四)(黑马)(web层解决方案-SpringMVC)
    【C++初阶】STL详解(三)vector的介绍与使用
    接口测试实战工具如何选择?这6个工具首选(建议收藏)
    策略模式(Stragedy)
    多线程进阶
    Ubuntu安装git方法
  • 原文地址:https://blog.csdn.net/qq_25252769/article/details/134201309