DeepSeek前端调研-第一篇

86 阅读1分钟

背景

最近DeepSeek很火,小伙伴们想接入DeepSeek,实现类似知识库的AI助手,在web端和手机端都要实现,手机端也是嵌套的h5页面,前端预研重任就落在了我的头上。

语音功能

在手机端-用户能语音输入,这涉及录音和播放两个主要功能。录音需要麦克风权限的授权,播放遇到了挺多坑,android和ios出现不兼容的情况,目前用的是howler库。

<template>
  <div class="audio-container">
    <div>{{ seconds }}</div>
    <div>
      <Button :disabled="recordDisabled" type="primary" @click="startRecord">录音</Button>
      <Button type="info" class="ml-10" @click="stopRecord">停止录音</Button>
      <Button type="success" class="ml-10" @click="playRecord">播放</Button>
    </div>
    <div>
      <P>状态提示:{{ state }}</P>
      <p>错误提示:{{ tip }}</p>
    </div>
  </div>
</template>

<script>
import { Howl } from 'howler'

export default {
    data() {
        return {
            mediaRecorder: null,
            audioChunks: [],
            recording: false,
            state: '',
            tip: '',
            recordDisabled: false,
            timerInterval: null,
            seconds: '00:00',
            audioUrl: ''
        }
    },
    mounted() {
        this.initRecorder()
    },
    methods: {
        // 初始化录音
        async initRecorder() {
          try {
            const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
            this.mediaRecorder = new MediaRecorder(stream)

            this.mediaRecorder.ondataavailable = (event) => {
              this.audioChunks.push(event.data)
            }

            this.mediaRecorder.onstop = () => {
              const audioBlob = new Blob(this.audioChunks, { type: 'audio/wav' })
              this.audioUrl = URL.createObjectURL(audioBlob)
              stream.getTracks().forEach(track => track.stop())
              clearInterval(this.timerInterval)
              this.recordDisabled = false
            }

            this.mediaRecorder.onerror = (event) => {
              this.tip = '录音出错,请重试'
            }
          } catch (err) {
            this.tip = `需要麦克风权限才能录音`
          }
        },
        // 开始录音
        async startRecord() {
          if (!this.recording) {
            if (!this.mediaRecorder) {
              await this.initRecorder()
            }
            this.audioChunks = []
            this.recording = true
            this.mediaRecorder.start()
            this.recordDisabled = true
            this.state = '录音中...'

            // 计时器
            const startTime = Date.now()
            this.timerInterval = setInterval(() => {
              const seconds = Math.floor((Date.now() - startTime) / 1000)
              this.seconds = this.formatTime(seconds)
            }, 1000)
          }
        },
        // 停止录音
        stopRecord() {
          this.recording = false
          this.mediaRecorder.stop()
          this.state = '录音结束'
        },
        // 播放
        playRecord() {
          try {
            if (this.audioChunks.length === 0) {
              this.tip = '请先录音'
              return
            }
            const sound = new Howl({
              src: [this.audioUrl],
              format: 'wav',
              onload: () => {
                this.state = '音频加载成功'
                sound.play()
              },
              onend: () => {
                this.state = '播放结束'
              }
            })
            // const audio = new Audio(this.audioUrl)
            // audio.play()
          } catch (err) {
            this.tip = `播放录音出错,请重试${err}`
          }
        },
        // 格式转换
        formatTime(seconds) {
          const mins = Math.floor(seconds / 60).toString().padStart(2, '0')
          const secs = (seconds % 60).toString().padStart(2, '0')
          return `${mins}:${secs}`
        }
    }
}
</script>