Vue3集成语音识别:百度API实现录音转文字全流程

Vue3集成语音识别:百度API实现录音转文字全流程

在智能办公、语音交互等场景中,将语音实时转换为文字的需求日益普遍。本文基于Vue3框架,结合主流云服务商的语音识别API,实现长按录音实时转文字及上传音频文件转换的完整功能。通过模块化设计,开发者可快速集成语音识别能力,提升应用交互体验。

一、技术架构设计

1.1 整体流程

系统分为录音采集、音频传输、API调用、结果展示四个核心模块:

  • 录音模块:通过浏览器MediaRecorder API捕获音频流
  • 传输模块:支持实时流式传输与文件分块上传两种模式
  • API对接层:封装百度智能云语音识别SDK的调用逻辑
  • 结果处理层:处理识别结果并更新前端界面

1.2 关键技术选型

  • 录音库:使用原生Web API(MediaRecorder)实现跨浏览器兼容
  • 流式处理:采用WebSocket协议传输实时音频数据
  • API封装:基于Promise的异步调用模式,统一错误处理

二、核心功能实现

2.1 录音组件开发

录音权限管理

  1. // 检查浏览器录音权限
  2. async function checkPermission() {
  3. try {
  4. const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
  5. stream.getTracks().forEach(track => track.stop());
  6. return true;
  7. } catch (err) {
  8. console.error('录音权限获取失败:', err);
  9. return false;
  10. }
  11. }

长按录音实现

  1. <template>
  2. <div
  3. @mousedown="startRecord"
  4. @mouseup="stopRecord"
  5. @mouseleave="cancelRecord"
  6. class="record-btn"
  7. >
  8. 长按录音
  9. </div>
  10. </template>
  11. <script setup>
  12. let mediaRecorder;
  13. let audioChunks = [];
  14. const startRecord = async () => {
  15. if (!await checkPermission()) return;
  16. const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
  17. mediaRecorder = new MediaRecorder(stream);
  18. mediaRecorder.ondataavailable = (event) => {
  19. audioChunks.push(event.data);
  20. };
  21. mediaRecorder.start(100); // 每100ms收集一次数据
  22. };
  23. const stopRecord = () => {
  24. if (!mediaRecorder) return;
  25. mediaRecorder.stop();
  26. mediaRecorder.stream.getTracks().forEach(track => track.stop());
  27. // 处理录音数据
  28. const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
  29. processAudio(audioBlob);
  30. audioChunks = [];
  31. };
  32. </script>

2.2 百度智能云API集成

初始化配置

  1. // config.js
  2. export const ASR_CONFIG = {
  3. apiKey: 'your-api-key',
  4. secretKey: 'your-secret-key',
  5. endpoint: 'https://aip.baidubce.com/rpc/2.0/asr/v1/recognize'
  6. };
  7. // 生成访问令牌
  8. export async function getAccessToken() {
  9. const authUrl = `https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=${ASR_CONFIG.apiKey}&client_secret=${ASR_CONFIG.secretKey}`;
  10. const response = await fetch(authUrl);
  11. const data = await response.json();
  12. return data.access_token;
  13. }

实时流式识别

  1. async function streamRecognize(audioStream) {
  2. const accessToken = await getAccessToken();
  3. const wsUrl = `wss://vop.baidu.com/ws_async?token=${accessToken}`;
  4. const ws = new WebSocket(wsUrl);
  5. let isFirstFrame = true;
  6. ws.onopen = () => {
  7. // 发送配置信息
  8. const config = {
  9. format: 'wav',
  10. rate: 16000,
  11. channel: 1,
  12. cuid: 'your-device-id',
  13. token: accessToken
  14. };
  15. ws.send(JSON.stringify({...config, type: 'START'}));
  16. };
  17. ws.onmessage = (event) => {
  18. const data = JSON.parse(event.data);
  19. if (data.result) {
  20. emit('text-update', data.result.join(''));
  21. }
  22. };
  23. // 创建可读流处理
  24. const reader = audioStream.getReader();
  25. const processStream = async () => {
  26. const { done, value } = await reader.read();
  27. if (done) {
  28. ws.send(JSON.stringify({type: 'END'}));
  29. return;
  30. }
  31. ws.send(value);
  32. await processStream();
  33. };
  34. processStream();
  35. }

2.3 文件上传识别

  1. async function uploadRecognize(audioFile) {
  2. const accessToken = await getAccessToken();
  3. const formData = new FormData();
  4. formData.append('audio', audioFile);
  5. formData.append('format', 'wav');
  6. formData.append('rate', 16000);
  7. formData.append('channel', 1);
  8. formData.append('token', accessToken);
  9. const response = await fetch(ASR_CONFIG.endpoint, {
  10. method: 'POST',
  11. body: formData
  12. });
  13. const result = await response.json();
  14. return result.result.join('');
  15. }

三、性能优化与最佳实践

3.1 录音质量优化

  • 采样率设置:推荐16kHz采样率,平衡音质与数据量
  • 编码格式:优先选择PCM或WAV格式,避免有损压缩
  • 分块处理:每100ms处理一次音频数据,减少内存占用

3.2 API调用优化

  • 连接复用:保持WebSocket长连接,避免频繁重连
  • 错误重试:实现指数退避重试机制
  • 并发控制:限制同时进行的识别请求数量

3.3 用户体验优化

  • 进度反馈:显示录音时长与识别进度
  • 结果缓存:本地缓存最近识别结果
  • 断点续传:支持大文件分片上传

四、完整组件实现

  1. <template>
  2. <div class="asr-container">
  3. <div
  4. class="record-btn"
  5. @mousedown="startRecord"
  6. @mouseup="stopRecord"
  7. @mouseleave="cancelRecord"
  8. >
  9. {{ isRecording ? '松开结束' : '长按录音' }}
  10. </div>
  11. <div class="upload-area" @click="triggerUpload">
  12. <input
  13. type="file"
  14. ref="fileInput"
  15. @change="handleFileUpload"
  16. accept="audio/*"
  17. style="display: none"
  18. >
  19. 或上传音频文件
  20. </div>
  21. <div class="result-box">
  22. <div v-for="(line, index) in resultLines" :key="index" class="result-line">
  23. {{ line }}
  24. </div>
  25. </div>
  26. </div>
  27. </template>
  28. <script setup>
  29. import { ref } from 'vue';
  30. import { ASR_CONFIG, getAccessToken } from './config';
  31. const isRecording = ref(false);
  32. const resultLines = ref([]);
  33. const fileInput = ref(null);
  34. let mediaRecorder;
  35. let audioChunks = [];
  36. let currentStream;
  37. const startRecord = async () => {
  38. if (!await checkPermission()) return;
  39. isRecording.value = true;
  40. currentStream = await navigator.mediaDevices.getUserMedia({ audio: true });
  41. mediaRecorder = new MediaRecorder(currentStream, {
  42. mimeType: 'audio/wav',
  43. audioBitsPerSecond: 256000
  44. });
  45. mediaRecorder.ondataavailable = (event) => {
  46. audioChunks.push(event.data);
  47. };
  48. mediaRecorder.start(100);
  49. };
  50. const stopRecord = async () => {
  51. if (!mediaRecorder) return;
  52. mediaRecorder.stop();
  53. mediaRecorder.stream.getTracks().forEach(track => track.stop());
  54. isRecording.value = false;
  55. const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
  56. const result = await uploadRecognize(audioBlob);
  57. resultLines.value.push(result);
  58. audioChunks = [];
  59. };
  60. const triggerUpload = () => {
  61. fileInput.value.click();
  62. };
  63. const handleFileUpload = async (event) => {
  64. const file = event.target.files[0];
  65. if (!file) return;
  66. const result = await uploadRecognize(file);
  67. resultLines.value.push(result);
  68. };
  69. </script>

五、安全与合规考虑

  1. 数据传输安全:确保所有音频数据通过HTTPS/WSS加密传输
  2. 隐私保护:明确告知用户数据使用范围,提供隐私政策链接
  3. 权限管理:遵循最小权限原则,仅请求必要的麦克风权限
  4. 日志脱敏:避免在前端记录原始音频或敏感识别结果

六、扩展功能建议

  1. 多语言支持:通过API参数切换识别语言类型
  2. 标点预测:启用百度API的标点符号预测功能
  3. 热词优化:上传行业术语表提升专业词汇识别率
  4. 实时纠错:结合NLP模型实现识别结果后处理

通过本文实现的方案,开发者可在Vue3项目中快速集成语音识别能力。实际开发中,建议根据业务场景调整参数配置,并建立完善的错误处理机制。对于高并发场景,可考虑引入消息队列缓冲请求,确保系统稳定性。