个人主页:不叫猫先生
‍♂️ 作者简介:前端领域新星创作者、阿里云专家博主,专注于前端各领域技术,共同学习共同进步,一起加油呀!
系列专栏: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'

五、项目目录

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

六、配置

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"}
依赖名称描述
@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 中的 jqueryjQuery: "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,// 开启热更新}})

七、踩坑记录

在科大讯飞的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" />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()

改为如下

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

并且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 * springFactorvar before = Math.floor(tmp).toFixed()var after = Math.ceil(tmp).toFixed()var atPoint = tmp - beforenewData[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 = 0for (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},}

八、实现效果

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