vue项目中集合科大讯飞语音识别功能,web端,语音听写(流式版)WebAPI 文档

06-01 1346阅读

科大讯飞官方文档:语音听写(流式版)WebAPI 文档 | 讯飞开放平台文档中心

这是demovue项目中集合科大讯飞语音识别功能,web端,语音听写(流式版)WebAPI 文档

这次主要是将demo改写成了vue语法,其他的都没变。

先在public文件下加入了iat,也就是demo文件中的dist文件夹

vue项目中集合科大讯飞语音识别功能,web端,语音听写(流式版)WebAPI 文档 vue项目中集合科大讯飞语音识别功能,web端,语音听写(流式版)WebAPI 文档

然后还要准备CryptoJS这个第三方的包import CryptoJS from 'crypto-js';,直接npm下载就行。

最后是封装了一个组件,来使用。这个项目使用的是ant的组件库。可自行换成别的。

import { Close, Voice } from '@icon-park/vue-next';
import CryptoJS from 'crypto-js';
import { message } from 'ant-design-vue';
export default {
  name: 'XfIat',
  components: { Close, Voice },
  data() {
    return {
      // 控制录音弹窗
      voiceOpen: false,
      // 是否开始录音
      startVoiceStatus: false,
      // 识别中状态
      identifyStatus: false,
      recorder: null,
      transcription: '',
      btnStatus: '',
      resultText: '',
      resultTextTemp: '',
      countdownInterval: null,
      iatWS: null,
      recognition: null,
    };
  },
  emits: ['sendMsg'],
  props: {
    buttonDisabled: {
      type: Boolean,
      default: true,
    },
    loading: {
      type: Boolean,
      default: false,
    },
    xfIatKeys: {
      default: {
        APPID: '',
        APIKey: '',
        APISecret: '',
      },
    },
  },
  methods: {
    /**
     * 打开录音
     * @returns {Promise}
     */
    async startVoice() {
      if (this.loading) {
        return;
      }
      this.voiceOpen = true;
      await this.playIatVoice();
    },
    async playIatVoice() {
      if (this.loading) {
        return;
      }
      this.startVoiceStatus = !this.startVoiceStatus;
      // 浏览器自带的识别
      if (this.recognition) {
        if (this.startVoiceStatus) {
          this.recognition.start();
        } else {
          this.recognition.stop();
        }
        return;
      }
      if (this.startVoiceStatus) {
        this.connectWebSocket();
      } else {
        this.recorder.stop();
      }
    },
    /**
     * 关闭录音弹窗
     */
    closeVoiceOpen() {
      this.voiceOpen = false;
      this.startVoiceStatus = false;
      if (this.recorder) {
        this.recorder.stop();
      }
      if (this.recognition) {
        this.recognition.stop();
      }
      this.transcription = '';
    },
    renderResult(resultData) {
      // 识别结束
      const jsonData = JSON.parse(resultData);
      if (jsonData.data && jsonData.data.result) {
        const data = jsonData.data.result;
        let str = '';
        const { ws } = data;
        for (let i = 0; i  {
        console.log('iatWS.onopen', e);
        // 开始录音
        this.recorder.start({
          sampleRate: 16000,
          frameSize: 1280,
        });
        const params = {
          common: {
            app_id: this.xfIatKeys.APPID,
          },
          business: {
            language: 'zh_cn',
            domain: 'iat',
            accent: 'mandarin',
            vad_eos: 5000,
            dwa: 'wpgs',
            nbest: 1,
            wbest: 1,
          },
          data: {
            status: 0,
            format: 'audio/L16;rate=16000',
            encoding: 'raw',
          },
        };
        this.iatWS.send(JSON.stringify(params));
      };
      this.iatWS.onmessage = e => {
        this.renderResult(e.data);
      };
      this.iatWS.onerror = e => {
        console.error(e);
        this.recorder.stop();
        this.changeBtnStatus('CLOSED');
      };
      this.iatWS.onclose = e => {
        console.log(e);
        this.recorder.stop();
        this.changeBtnStatus('CLOSED');
      };
    },
    getWebSocketUrl() {
      const { APIKey, APISecret } = this.xfIatKeys;
      if (!APIKey) {
        message.error('语音识别配置未生效');
        return null;
      }
      // 请求地址根据语种不同变化
      let url = 'wss://iat-api.xfyun.cn/v2/iat';
      const host = 'iat-api.xfyun.cn';
      const apiKey = APIKey;
      const apiSecret = APISecret;
      const date = new Date().toGMTString();
      const algorithm = 'hmac-sha256';
      const headers = 'host date request-line';
      const signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/iat HTTP/1.1`;
      const signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret);
      const signature = CryptoJS.enc.Base64.stringify(signatureSha);
      const authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`;
      const authorization = btoa(authorizationOrigin);
      url = `${url}?authorization=${authorization}&date=${date}&host=${host}`;
      return url;
    },
    countdown() {
      let seconds = 60;
      console.log(`录音中(${seconds}s)`);
      this.countdownInterval = setInterval(() => {
        seconds -= 1;
        if (seconds  {
        this.transcription = Array.from(event.results)
          .map(result => result[0].transcript)
          .join('');
      };
      this.recognition.onerror = event => {
        console.error('识别错误:', event.error);
      };
      this.recognition.onend = () => {
        console.log('录音停止了');
        this.startVoiceStatus = false;
      };
      this.recognition.onstart = () => {
        this.changeBtnStatus('OPEN');
      };
      return;
    } */
    this.recorder = new window.RecorderManager('/iat');
    this.recorder.onStart = () => {
      this.changeBtnStatus('OPEN');
    };
    this.recorder.onFrameRecorded = ({ isLastFrame, frameBuffer }) => {
      if (this.iatWS.readyState === this.iatWS.OPEN) {
        this.iatWS.send(
          JSON.stringify({
            data: {
              status: isLastFrame ? 2 : 1,
              format: 'audio/L16;rate=16000',
              encoding: 'raw',
              audio: this.toBase64(frameBuffer),
            },
          }),
        );
        if (isLastFrame) {
          this.changeBtnStatus('CLOSING');
        }
      }
    };
    this.recorder.onStop = () => {
      console.log('录音结束,停止定时器');
      clearInterval(this.countdownInterval);
      this.startVoiceStatus = false;
    };
  },
};


  
    
      语音输入
    
    
      
    
  
  
    
      
        
      
      
        
        
          {{ identifyStatus ? '识别中' : '想问什么,说来听听...' }}
          点击下方语音图标可{{ startVoiceStatus ? '停止' : '开始' }}录音
        
      
      
        清空
        
          
        
        发送
        
          
          
          
          
        
      
    
  


.send-btn {
  //margin-left: 1rem;
  height: 2.25rem;
  width: 2.25rem;
  cursor: pointer;
  border-radius: 100%;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  transition-duration: 0.15s;
  &:hover {
    background-color: #f2f3f5;
    .icon {
      margin: 2px 2px 0 0;
      color: #7f5df6;
    }
  }
}
.inactive {
  .icon {
    color: #b4becf;
    margin: 2px 2px 0 0;
  }
}
.active {
  .icon {
    margin: 2px 2px 0 0;
    color: #7f5df6;
  }
}
.voice-box {
  width: 100%;
  position: fixed;
  bottom: 5px;
  left: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  .voice-body {
    position: absolute;
    bottom: 0;
    width: 64%;
    height: 11rem;
    border-radius: 1rem;
    padding: 1rem 1.25rem;
    font-size: .875rem;
    line-height: 1.5rem;
    box-shadow: 0 8px 32px rgba(0, 0, 0, .16);
    box-sizing: border-box;
    background-color: #fff;
    border: 1px solid #e4e7ed;
    color: #303133;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    .close-box {
      position: absolute;
      right: 1rem;
      top: 1rem;
      .close-icon {
        color: #596780;
        float: right;
        cursor: pointer;
      }
    }
    .textarea-box {
      padding-right: 1.25rem;
      .custom-textarea-wrapper {
        max-height: 90px; /* 设置最大高度以激活滚动条 */
        overflow: auto; /* 启用滚动条 */
      }
      /* WebKit 浏览器的滚动条样式 */
      .custom-textarea-wrapper ::-webkit-scrollbar {
        width: 8px; /* 设置滚动条的宽度 */
      }
      .custom-textarea-wrapper ::-webkit-scrollbar-track {
        background: transparent; /* 滚动条轨道背景 */
      }
      .custom-textarea-wrapper ::-webkit-scrollbar-thumb {
        background: #f2f3f5; /* 滚动条滑块的颜色 */
        border-radius: 4px; /* 滚动条滑块的圆角 */
      }
      .custom-textarea-wrapper ::-webkit-scrollbar-thumb:hover {
        background: #555; /* 滚动条滑块在悬停时的颜色 */
      }
      /* Firefox 的滚动条样式 */
      .custom-textarea-wrapper {
        scrollbar-width: thin; /* 滚动条宽度: thin/auto */
        scrollbar-color: #f2f3f5 transparent; /* 滚动条颜色 (滑块 背景) */
      }
      .text-center-box {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        .font-medium {
          font-weight: 500;
        }
        .tip-text {
          font-size: .75rem;
          line-height: 1rem;
          margin-top: 0.35rem;
          color: #9DA3AF;
        }
      }
    }
    .action-box {
      display: flex;
      align-items: center;
      justify-content: center;
      position: relative;
      gap: 2.5rem;
      .start-voice-box {
        width: 2.25rem;
        height: 2.25rem;
        display: flex;
        align-items: center;
        justify-content: center;
        background-color: rgb(124 92 252);
        border-radius: 50%;
        cursor: pointer;
        z-index: 3;
        .start-voice {
          color: #fff;
        }
      }
      .start-voice-box:hover {
        opacity: 0.8;
      }
      .water-ripples {
        z-index: 2;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: 28px;
        height: 28px;
        .circle {
          width: 28px;
          height: 28px;
          background: rgb(124, 92, 252);
          border-radius: 100%;
          position: absolute;
        }
        .circle1 {
          animation-delay: 0s;
          animation-name: waterCircle;
          animation-duration: 2s;
          animation-iteration-count: infinite;
          animation-timing-function: linear;
        }
        .circle2 {
          animation-delay: 1s;
          animation-name: waterCircle;
          animation-duration: 2s;
          animation-iteration-count: infinite;
          animation-timing-function: linear;
        }
        .circle3 {
          animation-delay: 2s;
          animation-name: waterCircle;
          animation-duration: 2s;
          animation-iteration-count: infinite;
          animation-timing-function: linear;
        }
        @keyframes waterCircle {
          0% {
            transform: scale(1);
            opacity: .5;
          }
          25% {
            transform: scale(1.25);
            opacity: .375;
          }
          50% {
            transform: scale(1.5);
            opacity: .25;
          }
          75% {
            transform: scale(1.75);
            opacity: .125;
          }
          100% {
            transform: scale(2);
            opacity: .05;
          }
        }
      }
      .ant-btn-text {
        color: #909399;
      }
      .ant-btn-text:disabled {
        background-color: transparent;
        border-color: transparent;
        color: #c8c9cc;
      }
      .ant-btn-text:not(:disabled):hover {
        background-color: transparent;
        border-color: transparent;
        color: #c8c9cc;
      }
    }
  }
}
@media (max-width: 1279px) {
  .voice-body{
    width: 76% !important;
  }
}
@media (max-width: 1023px) {
  .voice-body{
    width: calc(100% - 1rem) !important;
  }
}

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

相关阅读

目录[+]

取消
微信二维码
微信二维码
支付宝二维码