前言

        现在语音识别技术得到了越来越广泛的应用,有的时候要在前端项目之中加入语音识别功能,也就是能识别并转义使用者说的话然后根据使用者说的话来触发某种操作。就比如开启语音助手之后说出“切换主题”,页面就会自动切换主题;说出“打开背景音乐”,就会自动播放网页的背景音乐等等。

        本文的主要思路就是调用讯飞旗下的讯飞实时语音转写接口,并通过当前系统的麦克风读取用户说出的语音信息,并计算编码通过websocket实时发送到讯飞实时语音接口,并接收返回数据也就是根据语音数据转码后的中文字符串,然后根据识别出来的中文字符串来调用对应的操作。

        讯飞实时语音转写接口API文档:

实时语音转写 API 文档 | 讯飞开放平台文档中心

        该工程实现了对于讯飞实时语音转写api接口的一个简单封装,开发者只需要按照下面的方法来进行安装和传参就可以实现。而且该项目在React和Vue均可引入调用。

        npm包github地址:

        https://github.com/yinlingyun97/voicecore.git

一、安装语音核心

npm install voice-core

二、引入语音核心

         1.可以通过import方式来进行引入:

import VoiceCore from 'voice-core';

        2.或者通过require方式来引入:

const VoiceCore = require('voice-core');

三、调用语音核心

   传参

        调用时需要对引入的voiceCore进行实例化操作,对voiceCore实例化的过程中需要传入四个参数,分别为config, textData, appId, apiKey

        1.config:

        将语音助手启动,关闭和错误等的方法传入到语音核心实例中,当语音核心启动时,错误时,关闭时会自动调用传入的config中的对应方法。

        示例:

let config = {
  // 语音核心关闭时调用的方法
  onClose: () => {
    console.log('发送结束标识');
    console.log('关闭连接ws.onclose');
    console.info('onClose');
  },
  // 语音核心出错时调用的方法,并且会将错误传出来
  onError: (err) => {
    console.info(err);
  },
  // 说话时的实时分贝值,e为Number值
  voiceValue:(e)=>{
    console.info(e)
  },
  // 语音核心匹配结果
  textResponse: (e) => {
    // 匹配成功时返回 { 'result':'识别结果','dsc':'匹配成功'}
    // 匹配失败时返回 { 'result':'识别结果','dsc':'无匹配数据'}
	console.info(e)
  },
  // 语音核心启动时调用的方法
  onStart: () => {
    console.info('onStart');
  },
  // 语音核心开始进行语音数据匹配时调用的方法
  startMatching:()=>{
    console.info('匹配语句中');
  }
};

       注意voiceValue是接收到的实时的声音大小,最小为0,最大为100。所以当配置上这个方法的时候,周围声音有一点改变都会触发这个方法。

        匹配成功时和匹配失败时控制台输出示例:

         2.textData:

         语音匹配列表,当识别到text中的语句的时候就会自动调用对应的方法,也就是对应的success方法。其中对于语句使用"|"来进行分隔表示“或”的概念。

        当检测到对应的语句的时候会调用对应的success方法,而且会将匹配的textData项和其次序当做参数传入success。

        请注意不要传入重复的语音指令,如果传入重复的那么会优先调用位置比较靠前的语音指令的success方法。所以在将textData传入voice-core的时候要进行一步数组去重的操作

        示例:

    let textData = [
      {
        id: 'end',
        text: '结束|关闭|注销',
        success: (item,index)=>{
            console.info(item,index)
        },
      },
      {
        id: 'start',
        text: '开始|启动|发动',
        success: (item,index)=>{
            console.info(item,index)
        },
      },
    ];

        3. appId&appKey

        登录讯飞首页:讯飞开放平台-以语音交互为核心的人工智能开放平台

        注册或登录之后选择实时语音转写服务:

         然后按照提示或购买服务或免费试用。在该过程中按照提示创建一个新应用

        试用或购买服务后点击实时语音转写会出现以下界面:

        红框框出来的就是appId和appKey

   调用实例

        1.启动语音识别:

import VoiceCore from 'voice-core';
this.voice = new VoiceCore(config, textData, appId, apiKey);
this.voice.start();

       2.关闭||停止语音识别

import VoiceCore from 'voice-core';
this.voice = new VoiceCore(config, textData, appId, apiKey);
this.voice.stop();

在React框架下的使用:    

         以React框架为例:

/**
 * @Description: voice-core 调用示例
 *
 * @author: yinlingyun
 *
 * @date: 2021/8/6
 */
import React, {PureComponent} from 'react';
import styles from './index.less';
import VoiceCore from 'voice-core';

class voiceCoreComponent extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {};
    this.voice = null; // voiceCore实例化的存放地址
  }

  componentDidMount() {
    let config = {
      onClose: () => {
        console.log('发送结束标识');
        console.log('关闭连接ws.onclose');
        console.info('onClose');
      },
      onError: (data) => {
        console.log('关闭连接ws.onerror');
        console.info(data);
      },
	  // 语音助手匹配结果
      textResponse: (e) => {
        // 匹配成功时返回 { 'result':'识别结果','dsc':'匹配成功'}
        // 匹配失败时返回 { 'result':'识别结果','dsc':'无匹配数据'}
		console.info(e)
      },
      onStart: () => {
        console.info('onStart');
      },
    };
    let textData = [
      {
        id: 'start',
        text: '结束|关闭|注销',
        success: this.success,
      },
      {
        id: 'end',
        text: '开始|启动|发动',
        success: this.success,
      },
    ];
    let appId = '你的appId';
    let apiKey = '你的apiKey';
    this.voice = new VoiceCore(config, textData, appId, apiKey);
  }

  success = (item,index) => {
    console.info(index, 'success');
    if (item.id === 'end') {
      this.voice.stop();
    }
  };

  render() {
    return (
      <div>
        <div
          onClick={() => {
            this.voice.start();
          }}
        >
          启动语音助手
        </div>
        <div
          onClick={() => {
            this.voice.stop();
          }}
        >
          关闭语音助手
        </div>
      </div>
    );
  }
}

export default voiceCoreComponent;

实现效果:

        

        红框内为识别结果

在VUE框架下的使用:     

<template>
  <div class="voiceAss" @click="voiceStateChange">
    <div class="img">
      <img :src="voiceState ? voiceOn : voiceOff" alt="" />
    </div>
    <canvas class="canvas" id='canvas'></canvas>
  </div>
</template>

<script>
import _ from 'lodash'
import VoiceCore from 'voice-core'
import voiceOn from './img/voiceOn.png'
import voiceOff from './img/voiceOff.png'
export default {
  name: 'VoiceAssistant',
  props: {
    list: {
      type: Array,
      default: () => []
    }
  },
  data () {
    return {
      voiceOn,
      voiceOff,
      voiceState: false,
      appId: '你的appId',
      apiKey: '你的apiKey',
      voice: null
    }
  },
  mounted () {},
  methods: {
    // 初始化语音核心
    voiceCoreInit (list) {
      const config = {
        onClose: () => {
          console.info('语音助手关闭成功')
        },
        onError: (err) => {
          console.info(err)
        },
        matchFailed: (e) => {
          console.info(e)
        },
        voiceValue: (e) => {
          const canvas = document.getElementById('canvas')
          if (canvas) {
            const canvasCtx = canvas.getContext('2d')
            canvasCtx.fillStyle = '#8FCE5E'
            canvasCtx.clearRect(0, 0, 300, 150)
            if (e > 1) {
              canvasCtx.fillRect(0, 0, 300, 75 + e * 0.75)
            }
          }
        },
        onStart: () => {
          console.info('语音助手开启成功')
        }
      }
      const textData = this.voiceCommandData(['打开', '切换', '转到', '开启'], list)
      this.voice = new VoiceCore(config, textData, this.appId, this.apiKey)
    },

    // 生成语音指令
    voiceCommandData (command, list) {
      if (!list || !Array.isArray(list)) {
        return null
      }
      const textData = [
        {
          id: 'exit',
          text: '结束|关闭|结束语音助手|关闭语音助手|退出',
          success: this.voiceSuccessCallback
        }
      ]
      this.arraysFlatten(list).forEach((item) => {
        if (item.children.length < 1) {
          const text = command
            .map((val) => {
              if (item.name.indexOf('-') > -1) {
                let outText = _.cloneDeep(item.name)
                outText = outText.replace('-', '')
                outText = outText.replace('/', '')
                return val + outText
              }
              return val + item.name
            })
            .join('|')
          textData.push({
            id: item.value,
            text,
            success: this.voiceSuccessCallback,
            ...item
          })
        }
      })
      return textData
    },

    // 语音匹配成功后调用方法
    voiceSuccessCallback (item) {
      if (item.id === 'exit' && this.voice) {
        this.voice.stop()
        this.voiceState = false
        return
      }
      if (this.props.callback && typeof this.props.callback === 'function') {
        this.props.callback(item)
      }
    },

    // 数组扁平化方法
    arraysFlatten (list, parent) {
      let outputData = []
      list.forEach((item) => {
        if (item.children.length < 1) {
          outputData.push(
            parent
              ? {
                ...item,
                parentId: parent.id
              }
              : item
          )
        } else {
          outputData = outputData.concat(this.arraysFlatten(item.children, item))
        }
      })
      // 对输出数据进行内部去重
      return outputData
    },

    // 开关语音助手方法
    voiceStateChange () {
      if (!this.voice) {
        return
      }
      if (!this.voiceState) {
        this.voice.start()
      } else {
        this.voice.stop()
      }
      this.voiceState = !this.voiceState
    }
  },
  watch: {
    list: {
      handler (val, oldval) {
        this.voiceCoreInit(val)
      },
      immediate: true,
      deep: true
    }
  }
}
</script>

<style scoped lang="less">
  .voiceAss{
    width: 40px;
    height: 40px;
    top:2%;
    left: 2%;
    position: absolute;
    z-index: 99;
    .img{
      position: absolute;
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
      z-index: 101;
      img{
        width: 100%;
        height: 100%;
      }
    }
    .canvas{
      position: absolute;
      background: #ffffff;
      border-radius: 50%;
      width: 40px;
      height: 40px;
      z-index: 100;
      transform: rotateX(180deg);
    }
  }
</style>

实现效果:

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐