背景
最近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>