欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue +WebSocket + WaveSurferJS 實(shí)現(xiàn)H5聊天對話交互的實(shí)例

 更新時間:2020年11月18日 10:19:40   作者:Ygria  
這篇文章主要介紹了Vue +WebSocket + WaveSurferJS 實(shí)現(xiàn)H5聊天對話交互的實(shí)例,幫助大家更好的理解和學(xué)習(xí)vue,感興趣的朋友可以了解下

引言

在與實(shí)現(xiàn)了語音合成、語義分析、機(jī)器翻譯等算法的后端交互時,頁面可以設(shè)計(jì)成更為人性化、親切的方式。我們采用類似于聊天對話的實(shí)現(xiàn),效果如下:

  • 智能客服(輸入文本,返回引擎處理后的文本結(jié)果)

  • 語音合成(輸入文本,返回文本以及合成的音頻)

如上圖所示,返回文本后,再返回合成出的音頻。
音頻按鈕嵌在對話氣泡中,可以點(diǎn)擊播放。

  • 語音識別(在頁面錄制語音發(fā)送,頁面實(shí)時展示識別出的文本結(jié)果)

實(shí)現(xiàn)功能及技術(shù)要點(diǎn)

1、基于WebSocket實(shí)現(xiàn)對話流
頁面與后端的交互是實(shí)時互動的,所以采用WebSocket協(xié)議,而不是HTTP請求,這樣后端推送回的消息可以實(shí)時顯示在頁面上。
WebSocket的返回是隊(duì)列的、無序的,在后續(xù)處理中我們也需要注意這一點(diǎn),在后文中會說到。
2、調(diào)用設(shè)備麥克風(fēng)進(jìn)行音頻錄制和轉(zhuǎn)碼加頭,基于WebAudio、WaveSurferJS等實(shí)現(xiàn)音頻處理和繪制
3、基于Vue的響應(yīng)式頁面實(shí)現(xiàn)
4、CSS3 + Canvas + JS 交互效果優(yōu)化

  • 錄制音頻CSS動畫效果
  • 聊天記錄自動滾動

下面給出部分實(shí)現(xiàn)代碼。

集成WebSocket

我們的聊天組件是頁面?zhèn)冗叴蜷_的抽屜(el-drawer),Vue組件會在打開時創(chuàng)建,關(guān)閉時銷毀。在組件中引入WebSocket,并管理它的開、關(guān)、消息接收和發(fā)送,使它的生命周期與組件一致(打開窗口時創(chuàng)建ws連接,關(guān)閉窗口時關(guān)閉連接,避免與后臺連接過多。)

created(){
 if (typeof WebSocket === 'undefined') {
  alert('您的瀏覽器不支持socket')
 } else {
  // 實(shí)例化socket
  this.socket = new WebSocket(this.socketServerPath)
  // 監(jiān)聽socket連接
  this.socket.onopen = this.open
  // 監(jiān)聽socket錯誤信息
  this.socket.onerror = this.error
  // 監(jiān)聽socket消息
  this.socket.onmessage = this.onMessage
  this.socket.onclose = this.close
 }
}
destroyed(){
 this.socket.close()
}

如上,將WebSocket的事件綁定到JS方法中,可以在對應(yīng)方法中實(shí)現(xiàn)對數(shù)據(jù)的接收和發(fā)送。
打開瀏覽器控制臺,選中指定的標(biāo)簽,便于對WebSocket連接進(jìn)行監(jiān)控和查看。

音頻錄制采集

從瀏覽器端音頻和視頻采集基于網(wǎng)頁即時通信(Web Real-Time
Communication,簡稱WebRTC) 的API。通過WebRTC的getUserMedia實(shí)現(xiàn),獲取一個MediaStream對象,將該對象關(guān)聯(lián)到AudioContext即可獲得音頻。

可參考RecorderJS的實(shí)現(xiàn): https://github.com/mattdiamond/Recorderjs/blob/master/examples/example_simple_exportwav.html

if (navigator.getUserMedia) {
  navigator.getUserMedia(
  { audio: true }, // 只啟用音頻
  function(stream) {
   var context = new(window.webkitAudioContext || window.AudioContext)()
   var audioInput = context.createMediaStreamSource(stream)
   var recorder = new Recorder(audioInput)

  },
  function(error) {
   switch (error.code || error.name) {
   case 'PERMISSION_DENIED':
   case 'PermissionDeniedError':
    throwError('用戶拒絕提供信息。')
    break
   case 'NOT_SUPPORTED_ERROR':
   case 'NotSupportedError':
    throwError('瀏覽器不支持硬件設(shè)備。')
    break
   case 'MANDATORY_UNSATISFIED_ERROR':
   case 'MandatoryUnsatisfiedError':
    throwError('無法發(fā)現(xiàn)指定的硬件設(shè)備。')
    break
   default:
    throwError('無法打開麥克風(fēng)。異常信息:' + (error.code || error.name))
    break
   }
  }
  )
 } else {
  throwError('當(dāng)前瀏覽器不支持錄音功能。')
 }

注意: 若navigator.getUserMedia獲取到的是undefined,是Chrome瀏覽器的安全策略導(dǎo)致的,需要通過https請求或配置瀏覽器,配置地址: chrome://flags/#unsafely-treat-insecure-origin-as-secure

瀏覽器采集到的音頻為PCM格式(PCM (脈沖編碼調(diào)制 Pulse Code Modulation)),需要對音頻加頭才能在頁面上進(jìn)行播放。注意加頭時采樣率、采樣頻率、聲道數(shù)量等必須與采樣時相同,不然加完頭后的音頻無法解碼。參考查看https://github.com/mattdiamond/Recorderjs/blob/master/src/recorder.js中exportWav方法。

業(yè)務(wù)中對接的語音識別引擎為實(shí)時轉(zhuǎn)寫引擎,即:不是錄制完成后再發(fā)送,而是一邊錄制一邊進(jìn)行編碼并發(fā)送。
使用onaudioprocess方法監(jiān)聽語音的輸入:

參考這個實(shí)現(xiàn),我們可以在每次監(jiān)聽到有數(shù)據(jù)寫入時,從buffer中獲取到錄制到的數(shù)據(jù),并進(jìn)行編碼、壓縮,再通過WebSocket發(fā)送。

Vue組件設(shè)計(jì)和業(yè)務(wù)實(shí)現(xiàn)

分析頁面業(yè)務(wù)邏輯,將代碼拆分成兩個組件:
ChatDialog.vue 聊天對話框頁面,根據(jù)輸入類型,分為文本輸入、語音輸入。
ChatRecord.vue聊天記錄組件,根據(jù)發(fā)送方(自己或者系統(tǒng))展示向左/向右的氣泡,根據(jù)內(nèi)容顯示文本、音頻等。ChatDialog是ChatRecord的父組件,遍歷ChatDialog中的chatList對象(Array),將chatList中的項(xiàng)注入到ChatRecord中。

<div class="chat-list">
   <div v-for="(item,index) in chatList" :key="index" class="msg-wrapper">
    <chat-record ref="chatRecord" :data="item" @showJson="showJsonDialog"></chat-record>
   </div>
   <div id="msg_end" style="height:0px; overflow:hidden"></div>
  </div>
</div>

對于聊天記錄的氣泡展示,與數(shù)據(jù)類型相關(guān)性很強(qiáng),ChatRecord組件只關(guān)心對數(shù)據(jù)的處理和展示,我們可以完全不用關(guān)心消息的發(fā)送、接收、音頻的錄制、停止錄制、接受音頻等邏輯,只需要根據(jù)數(shù)據(jù)來展示不同的樣式即可。
這樣Vue的響應(yīng)式就充分獲得了用武之地:無需用代碼對樣式展示進(jìn)行控制,只需要設(shè)計(jì)合理的數(shù)據(jù)格式和樣式模板,然后注入不同的數(shù)據(jù)即可。
模板頁面: 使用v-if控制,修改chatList里的對象內(nèi)容即可改變頁面展示。

根據(jù)業(yè)務(wù)需求,將ChatRecord可能接收到的數(shù)據(jù)分為以下幾類:

發(fā)送方為自己:

  • 文本輸入,顯示文本

實(shí)現(xiàn)簡單,不做贅述。

  • 語音輸入 Loading狀態(tài),顯示波紋動畫和計(jì)時

該動畫使用CSS實(shí)現(xiàn),參考地址: https://www.cnblogs.com/lhb25/p/loading-spinners-animated-with-css3.html

計(jì)時器使用JS的setInterval方法,每100ms更新一次錄制時長

 this.recordTimer = setInterval(() => {
  this.audioDuration = this.audioDuration + 0.1
  }, 100)

停止后清空計(jì)時器:

  • 語音輸入完畢,根據(jù)錄制的語音,繪制波紋

效果:

使用wavesurfer插件:

 initWaveSurfer() {
  this.$nextTick(() => {
  this.wavesurfer = WaveSurfer.create({
   container: this.$refs.waveform,
   height: 20,
   waveColor: '#3d6fff',
   progressColor: 'blue',
   backend: 'MediaElement',
   mediaControls: false,
   audioRate: '1',
   fillParent: false,
   maxCanvasWidth: 500,
   barWidth: 1,
   barGap: 2,
   barHeight: 5,
   barMinHeight: 3,
   normalize: true,
   cursorColor: '#409EFF'
  })
  this.convertAudioToUrl(this.waveAudio).then((res) => {
   this.wavesurfer.load(res)

   setTimeout(() => {
   this.audioDuration = this.getAudioDuration()
   }, 100)
  })
  })
 },

 // 將音頻轉(zhuǎn)化成url地址
 convertAudioToUrl(audio) {
  let blobUrl = ''
  if (this.data.sendBy === 'self') {
  blobUrl = window.URL.createObjectURL(audio)
  return new Promise((resolve) => {
   resolve(blobUrl)
  })
  } else {
  return this.base64ToBlob({
   b64data: audio,
   contentType: 'audio/wav'
  })
  }
 },

 base64ToBlob({ b64data = '', contentType = '', sliceSize = 512 } = {}) {
  return new Promise((resolve, reject) => {
  // 使用 atob() 方法將數(shù)據(jù)解碼
  let byteCharacters = atob(b64data)
  let byteArrays = []
  for (
   let offset = 0;
   offset < byteCharacters.length;
   offset += sliceSize
  ) {
   let slice = byteCharacters.slice(offset, offset + sliceSize)
   let byteNumbers = []
   for (let i = 0; i < slice.length; i++) {
   byteNumbers.push(slice.charCodeAt(i))
   }
   // 8 位無符號整數(shù)值的類型化數(shù)組。內(nèi)容將初始化為 0。
   // 如果無法分配請求數(shù)目的字節(jié),則將引發(fā)異常。
   byteArrays.push(new Uint8Array(byteNumbers))
  }
  let result = new Blob(byteArrays, {
   type: contentType
  })
  result = Object.assign(result, {
   // 這里一定要處理一下 URL.createObjectURL
   preview: URL.createObjectURL(result),
   name: `XXX.wav`
  })
  resolve(window.URL.createObjectURL(result))
  })
 },

發(fā)送方為系統(tǒng):

  • 僅返回文本:顯示文本
  • 僅返回音頻(參考發(fā)送方為自己的實(shí)現(xiàn))

  • 返回文本,隨即返回文本對應(yīng)的合成音頻,顯示文本和播放按鈕

頁面嵌入audio標(biāo)簽,將hidden設(shè)置為true使其不顯示:

<div class="audio-player">
   <svg-icon v-if="!isPlaying" icon-class='play' @click="onClickAudioPlayer" />
   <svg-icon v-else icon-class='pause' @click="onClickAudioPlayer" />
   <audio :src="playAudioUrl" autostart="true" hidden="true" ref="audioPlayer" />
  </div>

playAudioUrl的生成參考上面生成的wavesurfer的url。
使用isPlaying參數(shù)記錄當(dāng)前音頻的播放狀態(tài),并使用setTimeout方法,當(dāng)播放了音頻時長后,將播放按鈕自動置為play。

 onClickAudioPlayer() {
  if (this.isPlaying) {
  this.$refs.audioPlayer.pause()
  this.isPlaying = false
  } else {
  // 每次點(diǎn)擊時,開始播放,并在播放完畢將isPlaying置為false
  this.$refs.audioPlayer.currentTime = 0
  this.$refs.audioPlayer.play()
  this.isPlaying = true

  setTimeout(() => {
   // 將正在播放重置為false
   this.isPlaying = false
  }, Math.ceil(this.$refs.audioPlayer.duration) * 1000)
  }
 },

聊天記錄自動定位到最后一條:

  • 使用scrollIntoView()方法

記錄每次會話對應(yīng)的記錄ID(recordId):

  • 定義單次會話的id,并在返回的消息中回傳,從而建立多條websocket返回的關(guān)聯(lián)關(guān)系。

以上就是全部實(shí)現(xiàn)。難點(diǎn)主要是請求麥克風(fēng)權(quán)限和對音頻進(jìn)行編碼,在加wav頭時必須保證和采樣時的采樣率、頻率一致 。

以上就是Vue +WebSocket + WaveSurferJS 實(shí)現(xiàn)H5聊天對話交互的實(shí)例的詳細(xì)內(nèi)容,更多關(guān)于vue 實(shí)現(xiàn)H5聊天對話交互的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Vue中使用jsencrypt進(jìn)行RSA非對稱加密的操作方法

    Vue中使用jsencrypt進(jìn)行RSA非對稱加密的操作方法

    這篇文章主要介紹了Vue中使用jsencrypt進(jìn)行RSA非對稱加密,在這里需要注意要加密的數(shù)據(jù)必須是字符串,對Vue?RSA非對稱加密相關(guān)知識感興趣的朋友一起看看吧
    2022-04-04
  • vue在外部方法給下拉框賦值后不顯示label的解決

    vue在外部方法給下拉框賦值后不顯示label的解決

    這篇文章主要介紹了vue在外部方法給下拉框賦值后不顯示label的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • Vue的方法和屬性案例詳解

    Vue的方法和屬性案例詳解

    這篇文章主要介紹了Vue的方法和屬性案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • vue實(shí)現(xiàn)圖片上傳到后臺

    vue實(shí)現(xiàn)圖片上傳到后臺

    這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)圖片上傳到后臺,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-06-06
  • Iframe在Vue中的狀態(tài)保持技術(shù)

    Iframe在Vue中的狀態(tài)保持技術(shù)

    這篇文章主要為大家介紹了Iframe在Vue中的狀態(tài)保持技術(shù)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • Vue2中Element?UI表單的使用詳解

    Vue2中Element?UI表單的使用詳解

    這篇文章主要為大家詳細(xì)介紹了Vue2中Element?UI表單的使用,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • 詳解mpvue scroll-view自動回彈bug解決方案

    詳解mpvue scroll-view自動回彈bug解決方案

    設(shè)置了scroll-top的scroll-view組件,在組件所在vue實(shí)例data發(fā)生改變時會自動回彈到最上方,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2018-10-10
  • vue實(shí)現(xiàn)集成騰訊TIM即時通訊

    vue實(shí)現(xiàn)集成騰訊TIM即時通訊

    最近在做商城類的項(xiàng)目,需要使用到客服系統(tǒng),用戶選擇的騰訊IM即時通信,所以本文主要介紹了vue實(shí)現(xiàn)集成騰訊TIM即時通訊,感興趣的可以了解一下
    2021-06-06
  • vue cli升級webapck4總結(jié)

    vue cli升級webapck4總結(jié)

    這篇文章主要介紹了vue cli升級webapck4的步驟以及需要注意的地方,大家可以跟著操作學(xué)習(xí)下。
    2018-04-04
  • vue實(shí)現(xiàn)可拖拽的dialog彈框

    vue實(shí)現(xiàn)可拖拽的dialog彈框

    element的dialog彈框在項(xiàng)目中挺常用的。拖拽形式的彈框會提高用戶體驗(yàn),本文實(shí)現(xiàn)了vue可拖拽的dialog彈框,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05

最新評論