webAPI语音合成以及vue项目实践

1,797 阅读2分钟

   前两天接到一个需求,要求web端能到接收到后台实时推送的告警信息,并进行语音播报,what?这是什么黑科技,我第一反应是做不到...问了一下同事才知道,这个功能可以有,语音合成api了结一下.

  官方文档:developer.mozilla.org/en-US/docs/…

   语音合成,顾名思义,就是可以将文字转换为语音,恕我孤陋寡闻,第一次知道这种黑科技.看了一下文档,其实很简单.示例demo如下:

let windowSpeech = new window.SpeechSynthesisUtterance('hello world!');
window.speechSynthesis.speak(windowSpeech);

  将上面的代码复制到控制台就可以听到电脑的播放音了.(如果你发现没有播放出声音,那有可能window版本有问题,不是完全版的,tts引擎没有安装,可以百度一下补丁包自行安装一下)这段功能的核心主要有两个对象SpeechSynthesisUtterancespeechSynthesis.

1.SpeechSynthesisUtterance对象

主要用来构建语音合成实例,例如上面代码中的实例对象windowSpeech。我们可以直接在构建的时候就把要读的文字内容写进去,也可以通过text属性设置要读的内容.SpeechSynthesisUtterance对象属性如下:

属性

text: 要合成的文字内容,字符串。

lang: 使用的语言,字符串, 例如:"zh-cn"

voiceURI: 指定希望使用的声音和服务,字符串。

volume: 声音的音量,区间范围是0到1,默认是1。

rate: 语速,数值,默认值是1,范围是0.1到10,表示语速的倍数,例如2表示正常语速的两倍。

pitch: 表示说话的音高,数值,范围从0(最小)到2(最大)。默认值为1。

事件:

onstart: 语音合成开始时候的回调。

onpause: 语音合成暂停时候的回调。

onresume: 语音合成重新开始时候的回调。

onend: 语音合成结束时候的回调。

2.speechSynthesis对象

主要作用是触发行为,例如读,停,还原等,可以控制语音合成的播放过程.

speak(): 只能接收SpeechSynthesisUtterance作为唯一的参数,作用是读合成的话语。

stop(): 立即终止合成过程。

pause(): 暂停合成过程。

resume(): 重新开始合成过程。

getVoices: 此方法不接受任何参数,用来返回浏览器支持的语音包列表,是个数组.

3.在vue项目中使用:

为了测试上文两个核心对象的功能,写了一个demo.主要实现了列表循环播放,逐条播放,以及播放的暂停,重新开始等功能.

效果图:

代码如下:

<template>
    <div class="window-speech">
        <div class="button-box">
            <span class="button" @click="allPlay">循环播放</span>
            <span class="button" @click="go_erasure">消音</span>
        </div>
        <div class="list-box">
            <div v-for="(item) in speechList" :key="item.index" :class="activeIndex == item.index?'red':''">
                <span>{{item.text}}</span>
                <span class="button" @click="onePlay(item)" v-if="item.status === 0">播放</span>
                <span class="button" @click="onePause(item)" v-if="item.status === 1">暂停</span>
                <span class="button" @click="oneContinue(item)" v-if="item.status === 2">继续 </span>
            </div>
        </div>
    </div>
</template>
<script>
export default {
    name:'windowSpeech',
    data(){
        return {  
            speechList:[  // 0 停止 1 播放中 2 暂停中
                {text:'测试报警声音001', index:0, status:0},
                {text:'测试报警声音002', index:1, status:0},
                {text:'测试报警声音003', index:2, status:0},
                {text:'测试报警声音004', index:3, status:0},
                {text:'测试报警声音005', index:4, status:0},
                {text:'测试报警声音006', index:5, status:0},
                {text:'测试报警声音007', index:6, status:0},
                {text:'测试报警声音008', index:7, status:0},
                {text:'测试报警声音009', index:8, status:0},
            ],
            activeIndex: -1,
            windowMsg:null,
            windowSpeech:null,
            playFlag: true,
        }   
    },
    mounted(){
        this.windowMsg = new window.SpeechSynthesisUtterance()
        this.windowSpeech = window.speechSynthesis
    },
    methods:{
        onePause(data){
            console.log('暂停')
            this.windowSpeech.pause()
        },
        oneContinue(data){
            console.log('继续')
            this.windowSpeech.resume()
        },
        onePlay(data){
            console.log('bofang')
            this.playFlag = true;
            this.circleFlag = false;
            this.play(data); 
        },
        play(data){
            if(!this.playFlag){
                console.log('消音了')
                this.windowSpeech.cancel();
                return
            }
            if(!this.windowMsg || !this.windowSpeech ){
                this.windowMsg = new window.SpeechSynthesisUtterance();
                this.windowSpeech = window.speechSynthesis
            }
            this.windowMsg.text = data.text;
            this.windowMsg.volume = 1;
            this.windowMsg.voiceURI = 'Google 普通话(中国大陆)';
            
            
            console.log(this.windowMsg,'this.windowMsg')
            console.log(this.windowSpeech,'this.windowMsg')
            this.windowMsg.onstart = ()=>{
                
                console.log('开始合成')
                this.activeIndex = data.index;
                this.speechList[data.index].status = 1;
            }
            this.windowMsg.onerror = (e)=>{
                console.log('出问题了',e)
                this.speechList[data.index].status = 0;
            }
            this.windowMsg.onend = ()=>{
                if(this.circleFlag){
                    console.log('播放完成一条',this.activeIndex)
                    this.activeIndex++
                    if(this.activeIndex == this.speechList.length){
                        this.activeIndex = 0;
                    }
                    this.play(this.speechList[this.activeIndex])
                }else{
                    this.activeIndex = -1;
                } 
                this.speechList[data.index].status = 0;
            }
            this.windowMsg.onresume = () => {
                this.speechList[data.index].status = 1;
            }
            this.windowMsg.onpause = (e) => {
                console.log('暂停',e)
                this.speechList[data.index].status = 2;
            }


            this.windowSpeech.speak(this.windowMsg);
        },
        allPlay(){
            this.circleFlag = true;
            this.activeIndex = 0;
            this.play(this.speechList[this.activeIndex])
        },
        go_erasure(){
            this.playFlag = false;
            this.$message.success('消音成功')
        }
    }
}
</script>
<style lang="less" scoped>
.window-speech{
    width: 60%;
    margin: auto;
    .button{
        display: inline-block;
        line-height: 40px;
        cursor: pointer;
        margin: 0 10px;
    }
    .button-box{

    }
    .list-box{
        .red{
            color: red;
        }
    }
}
</style>

git地址:github.com/aicai0/test…

如有问题,欢迎探讨,如果满意,请手动点赞,谢谢!🙏

及时获取更多姿势,请您关注!!