提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、功能配置
    • 1.引入官方demo中的js
    • 2.页面调用
  • 二、踩坑+填坑
    • 1.new Worker()报错
    • 2.webpack版本问题
    • 3.混用import 以及module.exports报错问题
  • 总结

前言

此为VUE项目配置科大讯飞语音转写及语音合成功能,通过语音转写将人声转为文字,通过对话库找到对应答复,再有语音合成功能合成回复语音播放,实现智能问答功能。前端实现中语音转写已实现,语音合成目前文字为写死,小小修改即可使用。此文章引入并不费劲,关键在于与原项目配置是否兼容,算是踩了不少坑,分享出来,记录下自己的辛酸历程。


一、功能配置

1.引入官方demo中的js

IatRecorder.js:

import CryptoJS from 'crypto-js'
import Worker from './transcode.worker.js'const APPID = '自己的APPID'
const API_SECRET = '自己的API_SECRET'
const API_KEY = '自己的API_KEY'let transWorker = new Worker()
console.log(transWorker)
var startTime = ''
var endTime = ''function getWebSocketUrl () {return new Promise((resolve, reject) => {// 请求地址根据语种不同变化var url = 'wss://iat-api.xfyun.cn/v2/iat'var host = 'iat-api.xfyun.cn'var apiKey = API_KEYvar apiSecret = API_SECRETvar date = new Date().toGMTString()var algorithm = 'hmac-sha256'var headers = 'host date request-line'var signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/iat HTTP/1.1`var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret)var signature = CryptoJS.enc.Base64.stringify(signatureSha)var authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`var authorization = btoa(authorizationOrigin)url = `${url}?authorization=${authorization}&date=${date}&host=${host}`resolve(url)})
}const IatRecorder = class {constructor ({language, accent, appId} = {}) {let self = thisthis.status = 'null'this.language = language || 'zh_cn'this.accent = accent || 'mandarin'this.appId = appId || APPID// 记录音频数据this.audioData = []// 记录听写结果this.resultText = ''// wpgs下的听写结果需要中间状态辅助记录this.resultTextTemp = ''transWorker.onmessage = function (event) {// console.log("构造方法中",self.audioData)self.audioData.push(...event.data)}}// 修改录音听写状态setStatus (status) {this.onWillStatusChange && this.status !== status && this.onWillStatusChange(this.status, status)this.status = status}setResultText ({resultText, resultTextTemp} = {}) {this.onTextChange && this.onTextChange(resultTextTemp || resultText || '')resultText !== undefined && (this.resultText = resultText)resultTextTemp !== undefined && (this.resultTextTemp = resultTextTemp)}// 修改听写参数setParams ({language, accent} = {}) {language && (this.language = language)accent && (this.accent = accent)}// 连接websocketconnectWebSocket () {return getWebSocketUrl().then(url => {let iatWSif ('WebSocket' in window) {iatWS = new WebSocket(url)} else {alert('浏览器不支持WebSocket')return}this.webSocket = iatWSthis.setStatus('init')iatWS.onopen = e => {this.setStatus('ing')// 重新开始录音setTimeout(() => {this.webSocketSend()}, 500)}iatWS.onmessage = e => {this.result(e.data)}iatWS.onerror = e => {this.recorderStop()}iatWS.onclose = e => {endTime = Date.parse(new Date())console.log('持续时间', endTime - startTime)this.recorderStop()}})}// 初始化浏览器录音recorderInit () {navigator.getUserMedia =navigator.getUserMedia ||navigator.webkitGetUserMedia ||navigator.mozGetUserMedia ||navigator.msGetUserMedia// 创建音频环境try {this.audioContext = new (window.AudioContext || window.webkitAudioContext)()this.audioContext.resume()if (!this.audioContext) {alert('浏览器不支持webAudioApi相关接口')return}} catch (e) {if (!this.audioContext) {alert('浏览器不支持webAudioApi相关接口')return}}// 获取浏览器录音权限if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {navigator.mediaDevices.getUserMedia({audio: true,video: false}).then(stream => {getMediaSuccess(stream)}).catch(e => {getMediaFail(e)})} else if (navigator.getUserMedia) {navigator.getUserMedia({audio: true,video: false},stream => {getMediaSuccess(stream)},function (e) {getMediaFail(e)})} else {if (navigator.userAgent.toLowerCase().match(/chrome/) && location.origin.indexOf('https://') < 0) {alert('chrome下获取浏览器录音功能,因为安全性问题,需要在localhost或127.0.0.1或https下才能获取权限')} else {alert('无法获取浏览器录音功能,请升级浏览器或使用chrome')}this.audioContext && this.audioContext.close()return}// 获取浏览器录音权限成功的回调let getMediaSuccess = stream => {// 创建一个用于通过JavaScript直接处理音频this.scriptProcessor = this.audioContext.createScriptProcessor(0, 1, 1)this.scriptProcessor.onaudioprocess = e => {// 去处理音频数据if (this.status === 'ing') {transWorker.postMessage(e.inputBuffer.getChannelData(0))//  this.audioData.push(e.inputBuffer.getChannelData(0))}}// 创建一个新的MediaStreamAudioSourceNode 对象,使来自MediaStream的音频可以被播放和操作this.mediaSource = this.audioContext.createMediaStreamSource(stream)// 连接this.mediaSource.connect(this.scriptProcessor)this.scriptProcessor.connect(this.audioContext.destination)this.connectWebSocket()}let getMediaFail = (e) => {this.audioContext && this.audioContext.close()this.audioContext = undefined// 关闭websocketif (this.webSocket && this.webSocket.readyState === 1) {this.webSocket.close()}}}recorderStart () {if (!this.audioContext) {this.recorderInit()} else {this.audioContext.resume()this.connectWebSocket()}}// 暂停录音recorderStop () {// safari下suspend后再次resume录音内容将是空白,设置safari下不做suspendif (!(/Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgen))) {this.audioContext && this.audioContext.suspend()}this.setStatus('end')}// 处理音频数据// transAudioData(audioData) {//   audioData = transAudioData.transaction(audioData)//   this.audioData.push(...audioData)// }// 对处理后的音频数据进行base64编码,toBase64 (buffer) {var binary = ''var bytes = new Uint8Array(buffer)var len = bytes.byteLengthfor (var i = 0; i < len; i++) {binary += String.fromCharCode(bytes[i])}return window.btoa(binary)}// 向webSocket发送数据webSocketSend () {if (this.webSocket.readyState !== 1) {return}let audioData = this.audioData.splice(0, 1280)var params = {common: {app_id: this.appId},business: {language: this.language, // 小语种可在控制台--语音听写(流式)--方言/语种处添加试用domain: 'iat',accent: this.accent // 中文方言可在控制台--语音听写(流式)--方言/语种处添加试用},data: {status: 0,format: 'audio/L16;rate=16000',encoding: 'raw',audio: this.toBase64(audioData)}}console.log('参数language:', this.language)console.log('参数accent:', this.accent)this.webSocket.send(JSON.stringify(params))startTime = Date.parse(new Date())this.handlerInterval = setInterval(() => {// websocket未连接if (this.webSocket.readyState !== 1) {console.log('websocket未连接')this.audioData = []clearInterval(this.handlerInterval)return}if (this.audioData.length === 0) {console.log('自动关闭', this.status)if (this.status === 'end') {this.webSocket.send(JSON.stringify({data: {status: 2,format: 'audio/L16;rate=16000',encoding: 'raw',audio: ''}}))this.audioData = []clearInterval(this.handlerInterval)}return false}audioData = this.audioData.splice(0, 1280)// 中间帧this.webSocket.send(JSON.stringify({data: {status: 1,format: 'audio/L16;rate=16000',encoding: 'raw',audio: this.toBase64(audioData)}}))}, 40)}result (resultData) {// 识别结束let jsonData = JSON.parse(resultData)if (jsonData.data && jsonData.data.result) {let data = jsonData.data.resultlet ws = data.wslet str = ''for (let i = 0; i < ws.length; i++) {str = str + ws[i].cw[0].w}console.log('识别的结果为:', str)// 开启wpgs会有此字段(前提:在控制台开通动态修正功能)// 取值为 "apd"时表示该片结果是追加到前面的最终结果;取值为"rpl" 时表示替换前面的部分结果,替换范围为rg字段if (data.pgs) {if (data.pgs === 'apd') {// 将resultTextTemp同步给resultTextthis.setResultText({resultText: this.resultTextTemp})}// 将结果存储在resultTextTemp中this.setResultText({resultTextTemp: this.resultText + str})} else {this.setResultText({resultText: this.resultText + str})}}if (jsonData.code === 0 && jsonData.data.status === 2) {this.webSocket.close()}if (jsonData.code !== 0) {this.webSocket.close()console.log(`${jsonData.code}:${jsonData.message}`)}}start () {this.setResultText({resultText: '', resultTextTemp: ''})this.recorderStart()}stop () {this.recorderStop()}
}export default IatRecorder

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)// return 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}
}

audio.js:

/** @Autor: lycheng* @Date: 2020-01-13 16:12:22*/
/*** Created by iflytek on 2019/11/19.** 在线语音合成调用demo* 此demo只是一个简单的调用示例,不适合用到实际生产环境中** 在线语音合成 WebAPI 接口调用示例 接口文档(必看):https://www.xfyun.cn/doc/tts/online_tts/API.html* 错误码链接:* https://www.xfyun.cn/doc/tts/online_tts/API.html* https://www.xfyun.cn/document/error-code (code返回错误码时必看)**/// 1. websocket连接:判断浏览器是否兼容,获取websocket url并连接,这里为了方便本地生成websocket url
// 2. 连接websocket,向websocket发送数据,实时接收websocket返回数据
// 3. 处理websocket返回数据为浏览器可以播放的音频数据
// 4. 播放音频数据
// ps: 该示例用到了es6中的一些语法,建议在chrome下运行
// import {downloadPCM, downloadWAV} from 'js/download.js'
import CryptoJS from 'crypto-js'
import TransWorker from './transcode2.worker.js'
// import VConsole from 'vconsole'
import {Base64} from 'js-base64'
// import './index.css'let transWorker = new TransWorker()
// APPID,APISecret,APIKey在控制台-我的应用-语音合成(流式版)页面获取
const APPID = '你的APPID'
const API_SECRET = '你的API_SECRET'
const API_KEY = '你的API_KEY'function getWebsocketUrl () {return new Promise((resolve, reject) => {var apiKey = API_KEYvar apiSecret = API_SECRETvar url = 'wss://tts-api.xfyun.cn/v2/tts'var host = location.hostvar date = new Date().toGMTString()var algorithm = 'hmac-sha256'var headers = 'host date request-line'var signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/tts HTTP/1.1`var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret)var signature = CryptoJS.enc.Base64.stringify(signatureSha)var authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`var authorization = btoa(authorizationOrigin)url = `${url}?authorization=${authorization}&date=${date}&host=${host}`resolve(url)})
}const TTSRecorder = class {constructor ({speed = 30,voice = 50,pitch = 50,voiceName = 'xiaoyan',appId = APPID,text = '',tte = 'UTF8',defaultText = '请输入您要合成的文本'} = {}) {this.speed = speedthis.voice = voicethis.pitch = pitchthis.voiceName = voiceNamethis.text = textthis.tte = ttethis.defaultText = defaultTextthis.appId = appIdthis.audioData = []this.rawAudioData = []this.audioDataOffset = 0this.status = 'init'transWorker.onmessage = (e) => {this.audioData.push(...e.data.data)this.rawAudioData.push(...e.data.rawAudioData)}}// 修改录音听写状态setStatus (status) {this.onWillStatusChange && this.onWillStatusChange(this.status, status)this.status = status}// 设置合成相关参数setParams ({speed, voice, pitch, text, voiceName, tte}) {speed !== undefined && (this.speed = speed)voice !== undefined && (this.voice = voice)pitch !== undefined && (this.pitch = pitch)text && (this.text = text)tte && (this.tte = tte)voiceName && (this.voiceName = voiceName)this.resetAudio()}// 连接websocketconnectWebSocket () {this.setStatus('ttsing')return getWebsocketUrl().then(url => {let ttsWSif ('WebSocket' in window) {ttsWS = new WebSocket(url)} else {alert('浏览器不支持WebSocket')return}this.ttsWS = ttsWSttsWS.onopen = e => {this.webSocketSend()this.playTimeout = setTimeout(() => {this.audioPlay()}, 1000)}ttsWS.onmessage = e => {this.result(e.data)}ttsWS.onerror = e => {clearTimeout(this.playTimeout)this.setStatus('errorTTS')alert('WebSocket报错,请f12查看详情')console.error(`详情查看:${encodeURI(url.replace('wss:', 'https:'))}`)}ttsWS.onclose = e => {// console.log(e)}})}// 处理音频数据transToAudioData (audioData) {}// websocket发送数据webSocketSend () {var params = {common: {app_id: this.appId // APPID},business: {aue: 'raw',// sfl= 1,auf: 'audio/L16;rate=16000',vcn: this.voiceName,speed: this.speed,volume: this.voice,pitch: this.pitch,bgs: 0,tte: this.tte},data: {status: 2,text: this.encodeText(this.text || this.defaultText,this.tte === 'unicode' ? 'base64&utf16le' : '')}}this.ttsWS.send(JSON.stringify(params))}encodeText (text, encoding) {switch (encoding) {case 'utf16le' : {let buf = new ArrayBuffer(text.length * 4)let bufView = new Uint16Array(buf)for (let i = 0, strlen = text.length; i < strlen; i++) {bufView[i] = text.charCodeAt(i)}return buf}case 'buffer2Base64': {let binary = ''let bytes = new Uint8Array(text)let len = bytes.byteLengthfor (let i = 0; i < len; i++) {binary += String.fromCharCode(bytes[i])}return window.btoa(binary)}case 'base64&utf16le' : {return this.encodeText(this.encodeText(text, 'utf16le'), 'buffer2Base64')}default : {return Base64.encode(text)}}}// websocket接收数据的处理result (resultData) {let jsonData = JSON.parse(resultData)// 合成失败if (jsonData.code !== 0) {alert(`合成失败: ${jsonData.code}:${jsonData.message}`)console.error(`${jsonData.code}:${jsonData.message}`)this.resetAudio()return}transWorker.postMessage(jsonData.data.audio)if (jsonData.code === 0 && jsonData.data.status === 2) {this.ttsWS.close()}}// 重置音频数据resetAudio () {this.audioStop()this.setStatus('init')this.audioDataOffset = 0this.audioData = []this.rawAudioData = []this.ttsWS && this.ttsWS.close()clearTimeout(this.playTimeout)}// 音频初始化audioInit () {let AudioContext = window.AudioContext || window.webkitAudioContextif (AudioContext) {this.audioContext = new AudioContext()this.audioContext.resume()this.audioDataOffset = 0}}// 音频播放audioPlay () {this.setStatus('play')let audioData = this.audioData.slice(this.audioDataOffset)this.audioDataOffset += audioData.lengthlet audioBuffer = this.audioContext.createBuffer(1, audioData.length, 22050)let nowBuffering = audioBuffer.getChannelData(0)if (audioBuffer.copyToChannel) {audioBuffer.copyToChannel(new Float32Array(audioData), 0, 0)} else {for (let i = 0; i < audioData.length; i++) {nowBuffering[i] = audioData[i]}}let bufferSource = this.bufferSource = this.audioContext.createBufferSource()bufferSource.buffer = audioBufferbufferSource.connect(this.audioContext.destination)bufferSource.start()bufferSource.onended = event => {if (this.status !== 'play') {return}if (this.audioDataOffset < this.audioData.length) {this.audioPlay()} else {this.audioStop()}}}// 音频播放结束audioStop () {this.setStatus('endPlay')clearTimeout(this.playTimeout)this.audioDataOffset = 0if (this.bufferSource) {try {this.bufferSource.stop()} catch (e) {// console.log(e)}}}start () {if (this.audioData.length) {this.audioPlay()} else {if (!this.audioContext) {this.audioInit()}if (!this.audioContext) {alert('该浏览器不支持webAudioApi相关接口')return}this.connectWebSocket()}}stop () {this.audioStop()}
}
export default TTSRecorder

transcode2.worker.js:

/** @Autor: lycheng* @Date: 2020-01-13 16:12:22*/const TransWorker = (function () {self.onmessage = function (e) {transcode.transToAudioData(e.data)}var transcode = {transToAudioData: function (audioDataStr, fromRate = 16000, toRate = 22505) {let outputS16 = transcode.base64ToS16(audioDataStr)let output = transcode.transS16ToF32(outputS16)output = transcode.transSamplingRate(output, fromRate, toRate)output = Array.from(output)self.postMessage({data: output,rawAudioData: Array.from(outputS16)})},transSamplingRate: function (data, fromRate = 44100, toRate = 16000) {var fitCount = Math.round(data.length * (toRate / fromRate))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},transS16ToF32: function (input) {var tmpData = []for (let i = 0; i < input.length; i++) {var d = input[i] < 0 ? input[i] / 0x8000 : input[i] / 0x7ffftmpData.push(d)}return new Float32Array(tmpData)},base64ToS16: function (base64AudioData) {base64AudioData = atob(base64AudioData)const outputArray = new Uint8Array(base64AudioData.length)for (let i = 0; i < base64AudioData.length; ++i) {outputArray[i] = base64AudioData.charCodeAt(i)}return new Int16Array(new DataView(outputArray.buffer).buffer)}}
})()export default TransWorker

2.页面调用

代码如下:

<template><div class="body"><p>按住录制音频</p><!--      <img src="../../static/image/timg.gif" alt="" @click="translationStart" >--><!--      <span @click="translationStart">停止</span>--><button class="taste-button ready-button" @click="translationStart">开始</button><button class="taste-button ready-button" @click="translationEnd">结束</button><div class="contert"><button @click="play">开始合成</button><button @click="pause">停止播放</button></div></div>
</template><script>
import IatRecorder from '@/assets/js/IatRecorder'
import TtsRecorder from '@/assets/js/audio'const ttsRecorder = new TtsRecorder()const iatRecorder = new IatRecorder('en_us', 'mandarin', '5fe58946')//export default {data () {return {}},mounted () {},created () {},methods: {translationStart () {iatRecorder.start()},translationEnd () {iatRecorder.stop()},play () {// 要合成的文本ttsRecorder.setParams({// 文本内容text: '1',// 角色//  voiceName: '',// 语速speed: 50,// 音量voice: 50})ttsRecorder.start()},pause () {ttsRecorder.stop()}}
}
</script>
<style scoped>.body {user-select: none;}audio {display: block;margin-bottom: 10px;}#audio-container {padding: 20px 0;}.ui-btn {display: inline-block;padding: 5px 20px;font-size: 14px;line-height: 1.428571429;box-sizing: content-box;text-align: center;border: 1px solid #e8e8e8;border-radius: 3px;color: #555;background-color: #fff;border-color: #e8e8e8;white-space: nowrap;cursor: pointer;-webkit-user-select: none;-moz-user-select: none;-ms-user-select: none;user-select: none;}.ui-btn:hover,.ui-btn.hover {color: #333;text-decoration: none;background-color: #f8f8f8;border: 1px solid #ddd;}.ui-btn:focus,.ui-btn:active {color: #333;outline: 0;}.ui-btn.disabled,.ui-btn.disabled:hover,.ui-btn.disabled:active,.ui-btn[disabled],.ui-btn[disabled]:hover,.ui-state-disabled .ui-btn {cursor: not-allowed;background-color: #eee;border-color: #eee;color: #aaa;}.ui-btn-primary {color: #fff;background-color: #39b54a;border-color: #39b54a;position: fixed;bottom: 1.5rem;width: 80%;margin-left: 10%;padding: 0.5rem 0;}.ui-btn-primary:hover,.ui-btn-primary.hover {color: #fff;background-color: #16a329;border-color: #16a329;}.ui-btn-primary:focus,.ui-btn-primary:active {color: #fff;}.ui-btn-primary.disabled:focus {color: #aaa;}img {display: block;width: 40%;margin: auto;}body {margin: 0;padding: 0;}#mask {width: 43%;background: rgba(0, 0, 0, 0.05);padding: 3rem 0 1rem 0;display: none;margin: 2rem auto;margin-top: 51%;}#mask p {text-align: center;font-size: 0.8rem;color: rgba(0, 0, 0, 0.5);}
</style>

二、踩坑+填坑

1.new Worker()报错

IatRecorder .js中let transWorker = new Worker()报错,原因是VUE项目无法直接使用new Worker这一特性。直接上解决方案:

首先安装worker-loader的2.0.0版本:

npm install worker-loader@2.0.0 -D

config下的index.js添加配置:

configureWebpack: config => {config.module.rules.push({test: /\.worker.js$/,use: {loader: 'worker-loader',options: { inline: true, name: 'workerName.[hash].js' }}})},parallel: false,chainWebpack: config => {config.output.globalObject('this')}

bulid下webpack.base.conf.js文件增加配置:

{test: /\.worker\.js$/,use: {loader: 'worker-loader',}
}

2.webpack版本问题

webpack版本影响使用,我也在此踩了坑,分享出来解决方案。
webpack版本我最后使用的4.44.1,对应webpack-dev-server等版本也尽量修改为适配的版本,下方我会贴上我的package文件的配置信息。更换版本后,重新执行npm install,如果出现错误,手动删除node_modules文件夹,再次执行即可。

package.json代码如下:

"dependencies": {"@amap/amap-jsapi-loader": "^0.0.1","axios": "^0.19.0","babel-plugin-syntax-dynamic-import": "^6.18.0","crypto-js": "^4.0.0","dayjs": "^1.9.6","echarts": "^4.2.1","element-ui": "^2.13.1","jquery": "^3.5.1","recorder-core": "^1.1.20112600","vue": "^2.6.10","vue-cookies": "^1.5.13","vue-router": "^3.0.1","vue-uuid": "^2.0.2","vxe-table": "^1.5.15","vxe-table-plugin-element": "^1.1.1","webpack-dev-server": "^3.11.0","xe-utils": "^1.9.6"},"devDependencies": {"address": "^1.0.3","autoprefixer": "^7.1.2","babel-core": "^6.22.1","babel-eslint": "^8.2.1","babel-helper-vue-jsx-merge-props": "^2.0.3","babel-loader": "^7.1.1","babel-plugin-syntax-jsx": "^6.18.0","babel-plugin-transform-runtime": "^6.22.0","babel-plugin-transform-vue-jsx": "^3.5.0","babel-preset-env": "^1.3.2","babel-preset-stage-2": "^6.22.0","chalk": "^2.0.1","copy-webpack-plugin": "^4.0.1","css-loader": "^0.28.0","eslint": "^4.15.0","eslint-config-standard": "^10.2.1","eslint-friendly-formatter": "^3.0.0","eslint-loader": "^2.1.2","eslint-plugin-import": "^2.7.0","eslint-plugin-node": "^5.2.0","eslint-plugin-promise": "^3.4.0","eslint-plugin-standard": "^3.0.1","eslint-plugin-vue": "^4.0.0","extract-text-webpack-plugin": "^3.0.0","file-loader": "^1.1.4","friendly-errors-webpack-plugin": "^1.6.1","html-webpack-plugin": "^3.2.0","mockjs": "^1.0.1-beta3","node-notifier": "^5.1.2","node-sass": "^4.12.0","optimize-css-assets-webpack-plugin": "^3.2.0","ora": "^1.2.0","portfinder": "^1.0.13","postcss-import": "^11.0.0","postcss-loader": "^2.0.8","postcss-url": "^7.2.1","rimraf": "^2.6.0","sass-loader": "^7.1.0","semver": "^5.3.0","shelljs": "^0.7.6","uglifyjs-webpack-plugin": "^1.1.1","url-loader": "^0.5.8","vue-loader": "^15.9.3","vue-style-loader": "^3.0.1","vue-template-compiler": "^2.5.2","webpack": "^4.44.1","webpack-bundle-analyzer": "^2.9.0","webpack-cli": "^3.3.12","webpack-merge": "^4.1.0","worker-loader": "^2.0.0"}

3.混用import 以及module.exports报错问题

当完成上述两步工作后,启动项目前台报错:Uncaught TypeError: Cannot assign to read only property’exports‘ of object’#‘,我***,真可爱。原因如题。上解决方案:
找到项目中的.babelrc文件,plugins增加配置transform-es2015-modules-commonjs。

"plugins": ["transform-vue-jsx", "transform-runtime","transform-es2015-modules-commonjs"]

到这,项目成功启动,语音转写和语音合成功能正常使用,可爱!


总结

费劲,愿大家顺利!Respect!!!

科大讯飞语音转写以及语音合成配置+遇到问题处理相关推荐

  1. Unity使用科大讯飞-语音转写接口

    准备 接口文档 注册科大讯飞账户,获取语音转写的appid和secretkey 示例 StreamingAssets中放置一个中文音频 先上传语音,再获取转写文本. 上传语音成功,可获取orderId ...

  2. 语音转写基于科大讯飞WebApi接口的安卓实现--上传录音音频翻译成文字

    一.目的与实现过程 1.目的:将.wav/.mp3音频文件翻译成文字 2.方式:基于科大讯飞语音转写 WebApi的安卓实现 3.机制:采用自定义计时器轮询. 4.坑点1:科大讯飞当前暂无安卓文档/代 ...

  3. android集成科大讯飞语音听写和语音合成

    android集成科大讯飞语音听写和语音合成 集成科大讯飞语音听写和语音合成,语音听写只是语音识别下面的一部分,别弄混淆了,由于科大讯飞暂未开放gradle引包方式,所以目前集成还是手动引包.我的流程 ...

  4. 安卓TTS语音合成经验分享(科大讯飞语音+)集成

    应用场景:足浴软件,技师钟房安排调派和队列排序查看,语音播报提醒.老程序是使用双屏显卡,windows系统PC上运行一个无人值守桌面程序.如今安卓机顶盒(WIFI)和MINI电视棒通过HDMI接口和支 ...

  5. 技术解读 | 科大讯飞语音技术最新进展之二:语音识别与语音合成

    这一篇内容将围绕语音识别与合成方向,继续为大家带来相关技术解析. "风物长宜放眼量".面向人机交互更加自然流畅的未来,智能语音技术进展如何?该走向何方? 以下内容根据讯飞研究院杰出 ...

  6. python分割语音端点检测_python的webrtc库如何实现语音端点检测 科大讯飞输入法PC体验版下载:语音+手写+...

    python的webrtc库如何实现语音端点检测 科大讯飞输入法PC体验版下载:语音+手写+ 2018-03-05 出处:网络 整理:zhishizhan.net 延伸:科大讯飞输入法PC体验版下载: ...

  7. ubuntu下,在QT中利用科大讯飞语音库实现语音合成TTS

    首先要去科大讯飞语音库注册,下载linux下的在线合成TTS的SDK,然后在QT下建立一个基于控制台的工程,其实建立关于UI的也可以,问题不大,这里以控制台工程进行说明.将sample中TTS部分的t ...

  8. Android科大讯飞语音按队列播报

    在Android开发中,语音播报经常使用,但是,在使用过程中会发现,如果语音来源过于块,频率过高,在前一条没有播放完的情况下会执行第二条播放,本篇文章用来解决这个问题. 一.科大讯飞语音集成: 1.在 ...

  9. 科大讯飞语音离线命令识别

    目录直达 准备工作 1.必要文件包复制到自己的项目目录中 1.在libs 目录下放置这些包 2.将assets 文件放置在 app 目录下 3.在build 目录下添加一下配置 4.工具类拷贝到项目文 ...

  10. AndroidStudio集成科大讯飞语音SDK

    AndroidStudio集成科大讯飞语音SDK 讯飞开放平台作为全球首个开放的智能交互技术服务平台,致力于为开发者打造一站式智能人机交互解决方案.用户可通过互联网.移动互联网,使用任何设备.在任何时 ...

最新文章

  1. Android学习路线
  2. xampp配置xdebug
  3. 微服务实战(四):服务发现的可行方案以及实践案例
  4. mysql开源内库_将内裤穿在外面的男人(mysql)
  5. 领动机器人教育_【领动知识科普】各阶段孩子该如何选择编程?乐高、机器人、编程间又有什么关系?...
  6. Spring Boot入门——JPA
  7. eureka 之前的服务如何关闭_干货分享 | 服务注册中心Spring Cloud Eureka部分源码分析...
  8. ftpclient读取服务器文件能获得文件名文件大小0_Spring WEB工程整合使用FTP,ftp文本文件解析入库,文件上传下载
  9. el-select下拉框组件el-option如何使用v-for动态渲染问题 - 方法篇
  10. LGD:涨点神器!旷视孙剑、张祥雨团队提出标签引导的自蒸馏技术,助力目标检测!...
  11. jupyter notebook介绍、安装以及使用教程
  12. H - 数论中的异或 HRBUST - 1688
  13. Python:计算器(代码全+解析+实现结果)
  14. Open Inventor:Windows下编译安装Coin3D
  15. 如何更改计算机屏幕分辨率,如何修改电脑默认屏幕分辨率
  16. Winform Chart控件常见问题汇总
  17. java三国鼎立,网页游戏三国鼎立(武三国)一键服务端带教程及修改说明
  18. 词干提取(stemming)与词形还原(lemmatization)
  19. wifi可以连接但是上不了网该怎么解决?
  20. 计算机中的ins是什么功能,insert键的功能是什么

热门文章

  1. IIS 禁用自动目录列表功能
  2. 广东省计算机学校,广东省计算机基础练习平台(高校版)安装设置方法
  3. FID指标复现踩坑避坑 文本生成图像FID定量实验全流程复现(Fréchet Inception Distance )定量评价实验踩坑避坑流程
  4. 硬盘容量和计算机容量的换算,t和g的换算(硬盘容量G跟T的换算)
  5. element树形控件拖拽allow-drop控制
  6. 十连跌!这个一线城市的房价到底怎么了?
  7. SharePoint CAML 查询时间类型
  8. Linux平台下软件推荐及主题图标推荐
  9. word之中快速插入已有公式的几种方法
  10. Excel中的空值与数值比较