深圳幻海软件技术有限公司 欢迎您!

vue3+vite+ts项目集成科大讯飞语音识别(项目搭建过程以及踩坑记录)

2023-02-28

🐱个人主页:不叫猫先生🙋‍♂️作者简介:前端领域新星创作者、阿里云专家博主,专注于前端各领域技术,共同学习共同进步,一起加油呀!💫系列专栏:vue3从入门到精通、TypeScript从入门到实践📢资料领取:前端进阶资料以及文中源码可以找我免费领取🔥前端学习交流:博主建立了一个前端交流群,汇

🐱 个人主页:不叫猫先生
🙋‍♂️ 作者简介:前端领域新星创作者、阿里云专家博主,专注于前端各领域技术,共同学习共同进步,一起加油呀!
💫系列专栏:vue3从入门到精通、TypeScript从入门到实践
📢 资料领取:前端进阶资料以及文中源码可以找我免费领取
🔥 前端学习交流:博主建立了一个前端交流群,汇集了各路大神,互相交流学习,期待你的加入!(文末有我wx或者直接私信)

目录

    • 背景
    • 一、项目环境
    • 二、注册科大讯飞
    • 三、下载语音识别demo
    • 四、新建vue3项目
    • 五、项目目录
    • 六、配置
    • 七、踩坑记录
    • 八、实现效果

背景

本人最近在做数字人项目,用到科大讯飞的语音识别功能,遇到了许多坑,做个总结,给兄弟们铺铺路。科大讯飞语音识别主要通过识别声音然后转换成文字,具体展示如下图所示:

一、项目环境

vue3+ts+vite

二、注册科大讯飞

注册后新建个应用,拿到APPID、APISecret、APIkey,在项目中会用到这三个参数,新用户有500条免费的服务量。
,

三、下载语音识别demo

科大讯飞文档中心中示例demo,博主选择的是js语言,注意该demo项目环境为webpack+js

选择demo-js语言下载

四、新建vue3项目

yarn creat vite 'project-name'
或者
npm init vite@latest 'project-name'
  • 1
  • 2
  • 3

五、项目目录

digitalPerson
├─ .gitignore
├─ README.md
├─ auto-imports.d.ts
├─ index.html
├─ package.json
├─ public
│  ├─ index.html
│  └─ vite.svg
├─ src
│  ├─ App.vue
│  ├─ assets
│  │  └─ vue.svg
│  ├─ components
│  │  └─ HelloWorld.vue
│  ├─ iat_ws.js
│  ├─ layout
│  │  └─ index.vue
│  ├─ main.ts
│  ├─ router
│  │  └─ index.ts
│  ├─ style.css
│  ├─ until
│  │  ├─ base64js.js
│  │  ├─ bootstrap.js
│  │  ├─ browser.min.js
│  │  ├─ jquery.js
│  │  └─ transcode.worker.js
│  ├─ views
│  │  └─ index.vue
│  └─ vite-env.d.ts
├─ tsconfig.json
├─ tsconfig.node.json
├─ vite.config.ts
├─ vite.config.ts.js
└─ yarn.lock
  • 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

六、配置

package.json配置项具体如下,我们需要安装一些依赖来支持语音识别demo适应vue3环境,不然会遇到很多问题.

 "dependencies": {
    "@originjs/vite-plugin-commonjs": "^1.0.3",
    "@rollup/plugin-inject": "^5.0.3",
    "ant-design-vue": "^3.2.15",
    "jquery": "^3.6.2",
    "vue": "^3.2.45",
    "vue-router": "^4.1.6"
  },
  "devDependencies": {
    "@types/node": "^18.11.17",
    "@vitejs/plugin-vue": "^4.0.0",
    "crypto-js": "4.0.0",
    "typescript": "^4.9.3",
    "unplugin-auto-import": "^0.12.1",
    "vconsole": "^3.15.0",
    "vite": "^4.0.0",
    "vue-tsc": "^1.0.11"
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
依赖名称描述
@originjs/vite-plugin-commonjs项目中混用 require 和 import ,即存在混用 commonJS 和 ES6 模块的情况,需要用该插件的transformMixedEsModules 配置进行 hotfix
@rollup/plugin-inject使用该插件注入全局 jQuery 环境
@types/node可以整体解决模块的声明文件问题
crypto-js加密、解密
unplugin-auto-import自动导入vue、vue-router等提供的API
vconsole提供轻量、可拓展、针对手机网页的前端开发者调试面板

具体代码实现如下:


import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
import AutoImport from 'unplugin-auto-import/vite'
import { viteCommonjs } from '@originjs/vite-plugin-commonjs' // 让浏览器支持commonjs语法
import inject from '@rollup/plugin-inject'
export default defineConfig({
  plugins: [
    vue(),
    AutoImport({
      imports: ['vue', 'vue-router']//自动导入vue和vue-router相关函数
    }),
    inject({
      $: "jquery",  // 这里会自动载入 node_modules 中的 jquery
      jQuery: "jquery",
      "windows.jQuery": "jquery"
    }),
    viteCommonjs({
    transformMixedEsModules: true//混用 commonJS 和 ES6 模块
    })
  ],
  resolve: {
    alias: {
      '@': resolve(__dirname, 'src'),
      'components': resolve(__dirname, 'src/components'),
    },
    extensions: ['.js', '.json', '.ts', '.vue'], // 使用路径别名时想要省略的后缀名,可以自己 增减
  },
  server: {
    port: 8070,
    host: true,
    open: true,
    proxy: {},
    hmr: 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

七、踩坑记录

在科大讯飞的js-demo中,并没有用到vue或者vite,我们实际开发时都会遇到let transWorker = new TransWorker()代码报错,比如:

报错1:TypeError:TransWorker is not a constructor
报错2:Uncaught SyntaxError: The requested module '/src/until/transcode.worker.js?t=1671455993687' does not provide an export named 'default'

为什么会报错呢?

import TransWorker from ‘js/transcode.worker.js引入了webWorker文件,webWorker相当于js中的线程,在主线程中启动一个子线程不影响ui,有关webworker内容如下:

web worker 是运行在后台的 JavaScript,不会影响页面的性能。 当在 HTML 页面中执行脚本时,页面的状态是不可响应的,直到脚本已完成。
web worker 是运行在后台的 JavaScript,独立于其他脚本,不会影响页面的性能。您可以继续做任何愿意做的事情:点击、选取内容等等,而此时 web worker 在后台运行。

在iat_ws.js(本人自定义的文件)文件里面const transWorker = new TransWorker() 报错,原因是vue里面不能直接使用原生的new Worker,vite中有专门关于webworker的配置项,详细请前往vite中webworker配置

语法:
const worker = new Worker(new URL(‘./worker.js’, import.meta.url))

所以需要将以下代码

 import TransWorker from './until/transcode.worker.js'
 let transWorker = new TransWorker()
  • 1
  • 2

改为如下

  const transWorker = new Worker(new URL('./until/transcode.worker.js', import.meta.url))
  • 1

并且transcode.worker.js文件需要修改为如下所示:

  self.onmessage = function(e){
    transAudioData.transcode(e.data)
  }
  let transAudioData = {
    transcode(audioData) {
      let output = transAudioData.to16kHz(audioData)
      output = transAudioData.to16BitPCM(output)
      output = Array.from(new Uint8Array(output.buffer))
      self.postMessage(output)
    },
    to16kHz(audioData) {
      var data = new Float32Array(audioData)
      var fitCount = Math.round(data.length * (16000 / 44100))
      var newData = new Float32Array(fitCount)
      var springFactor = (data.length - 1) / (fitCount - 1)
      newData[0] = data[0]
      for (let i = 1; i < fitCount - 1; i++) {
        var tmp = i * springFactor
        var before = Math.floor(tmp).toFixed()
        var after = Math.ceil(tmp).toFixed()
        var atPoint = tmp - before
        newData[i] = data[before] + (data[after] - data[before]) * atPoint
      }
      newData[fitCount - 1] = data[data.length - 1]
      return newData
    },
    to16BitPCM(input) {
      var dataLength = input.length * (16 / 8)
      var dataBuffer = new ArrayBuffer(dataLength)
      var dataView = new DataView(dataBuffer)
      var offset = 0
      for (var i = 0; i < input.length; i++, offset += 2) {
        var s = Math.max(-1, Math.min(1, input[i]))
        dataView.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7fff, true)
      }
      return dataView
    },
  }
  • 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

八、实现效果

具体实现效果如下,样式忽略😄

文章知识点与官方知识档案匹配,可进一步学习相关知识
Python入门技能树首页概览237982 人正在系统学习中
前端进阶资料免费领取|商务合作
微信名片