一、技术选型与前期准备
1.1 百度语音识别服务开通
开发者需先在百度智能云平台完成语音识别服务的开通。进入”语音技术”产品页,创建应用并获取API Key和Secret Key。注意区分”短语音识别”和”实时语音识别”两种模式,移动端通常采用短语音识别(REST API)以降低流量消耗。
1.2 UniApp项目配置
在Vue2项目中,需确保manifest.json配置了录音权限:
{"permission": {"scope.record": {"desc": "需要录音权限以实现语音识别"}}}
同时安装axios用于HTTP请求:
npm install axios --save
二、核心实现步骤
2.1 录音功能封装
创建utils/recorder.js实现跨平台录音:
export default {startRecord(success, fail) {#ifdef H5// H5端使用WebRTC APInavigator.mediaDevices.getUserMedia({ audio: true }).then(stream => {const mediaRecorder = new MediaRecorder(stream);mediaRecorder.ondataavailable = e => success(e.data);mediaRecorder.start();}).catch(fail);#endif#ifdef APP-PLUS// App端使用原生录音插件const recorder = plus.audio.getRecorder();recorder.record({ filename: '_doc/audio/' },data => success(data),fail);#endif},stopRecord() {#ifdef APP-PLUSplus.audio.getRecorder().stop();#endif}}
2.2 百度API认证与请求
创建api/baiduVoice.js处理认证和请求:
import axios from 'axios';import CryptoJS from 'crypto-js'; // 需安装crypto-jsconst API_KEY = '你的API_KEY';const SECRET_KEY = '你的SECRET_KEY';// 获取access_tokenasync function getToken() {const timestamp = Date.now();const sign = CryptoJS.HmacSHA256(`/oauth/2.0/token?grant_type=client_credentials&client_id=${API_KEY}&client_secret=${SECRET_KEY}`,SECRET_KEY).toString();const res = await axios.get(`https://aip.baidubce.com/oauth/2.0/token`, {params: {grant_type: 'client_credentials',client_id: API_KEY,client_secret: SECRET_KEY}});return res.data.access_token;}// 语音识别export async function recognizeSpeech(audioData) {const token = await getToken();const formData = new FormData();#ifdef APP-PLUS// App端需将音频转为base64const base64 = plus.io.convertLocalFileSystemURL(audioData).then(url => {return new Promise((resolve) => {plus.io.resolveLocalFileSystemURL(url, entry => {entry.file(file => {const reader = new FileReader();reader.onload = e => resolve(e.target.result.split(',')[1]);reader.readAsDataURL(file);});});});});formData.append('speech', await base64);#endif#ifdef H5// H5端直接传递BlobformData.append('speech', audioData, 'audio.wav');#endifformData.append('format', 'wav');formData.append('rate', 16000);formData.append('channel', 1);formData.append('token', token);const res = await axios.post('https://vop.baidu.com/server_api',formData,{headers: { 'Content-Type': 'multipart/form-data' }});return res.data;}
2.3 组件集成实现
创建components/VoiceInput.vue组件:
<template><view><button @click="startRecording" :disabled="isRecording">{{ isRecording ? '录制中...' : '开始录音' }}</button><button @click="stopRecording" :disabled="!isRecording">停止录音</button><view v-if="result">识别结果:{{ result }}</view></view></template><script>import recorder from '@/utils/recorder';import { recognizeSpeech } from '@/api/baiduVoice';export default {data() {return {isRecording: false,audioData: null,result: ''};},methods: {async startRecording() {this.isRecording = true;recorder.startRecord(data => this.audioData = data,err => console.error('录音失败:', err));},async stopRecording() {recorder.stopRecord();this.isRecording = false;try {const res = await recognizeSpeech(this.audioData);if (res.result) {this.result = res.result[0];}} catch (err) {console.error('识别失败:', err);uni.showToast({ title: '识别失败', icon: 'none' });}}}};</script>
三、关键问题解决方案
3.1 音频格式兼容性
百度语音识别要求:
- 采样率:16000Hz(必须)
- 格式:wav/pcm/amr/mp3
- 码率:建议16kbps以上
在App端录音时需显式设置参数:
// APP-PLUS录音配置plus.audio.getRecorder().record({format: 'wav',samplerate: 16000,bitrate: 256000}, success, fail);
3.2 网络请求优化
- Token缓存:access_token有效期24小时,可缓存避免重复获取
```javascript
let cachedToken = null;
let tokenExpire = 0;
export async function getToken() {
if (cachedToken && Date.now() < tokenExpire) {
return cachedToken;
}
const res = await axios.get(‘…’); // 同前
cachedToken = res.data.access_token;
tokenExpire = Date.now() + res.data.expires_in * 1000 - 300000; // 提前5分钟刷新
return cachedToken;
}
2. **请求超时处理**:```javascriptaxios.post(url, data, {timeout: 10000, // 10秒超时headers: { 'Content-Type': 'multipart/form-data' }}).catch(err => {if (err.code === 'ECONNABORTED') {uni.showToast({ title: '请求超时', icon: 'none' });}});
3.3 错误处理机制
建立完整的错误处理体系:
async function handleRecognition(audioData) {try {const res = await recognizeSpeech(audioData);if (res.error_code) {throw new Error(res.error_msg || '识别服务错误');}return res.result[0];} catch (err) {const errorMap = {40001: '参数错误',40002: '请求超时',40003: '音频过长',40004: '音频格式错误'};const msg = errorMap[err.response?.data?.error_code] || err.message;uni.showToast({ title: `识别失败: ${msg}`, icon: 'none' });throw err;}}
四、性能优化建议
-
音频压缩:使用opus编码减小体积
// 使用opus-encoder插件(需原生插件支持)function compressAudio(blob) {return new Promise((resolve) => {const worker = new Worker('/static/opus-worker.js');worker.postMessage(blob);worker.onmessage = e => resolve(e.data);});}
-
分片上传:对于长音频(>60s)采用WebSocket分片传输
async function streamRecognize(audioChunks) {const token = await getToken();const ws = new WebSocket(`wss://vop.baidu.com/websocket_api?token=${token}`);ws.onopen = () => {audioChunks.forEach(chunk => {ws.send(JSON.stringify({type: 'audio',data: arrayBufferToBase64(chunk)}));});ws.send(JSON.stringify({ type: 'finish' }));};let result = '';ws.onmessage = e => {const data = JSON.parse(e.data);if (data.type === 'final_result') {result = data.result;}};return new Promise(resolve => {ws.onclose = () => resolve(result);});}
五、完整项目结构建议
/src/apibaiduVoice.js # 百度API封装/componentsVoiceInput.vue # 语音输入组件/utilsrecorder.js # 录音封装audioProcessor.js # 音频处理工具/staticopus-worker.js # WebWorker脚本(可选)App.vue # 主入口manifest.json # 权限配置
六、测试与调试要点
- 真机测试:H5模拟器无法测试录音权限
- 日志收集:
uni.setDebug({enableDebug: true,debugOptions: {logging: true,info: true}});
- 抓包分析:使用Charles或Fiddler检查API请求
七、扩展功能建议
-
多语言支持:通过
dev_pid参数指定语言模型// 中文普通话formData.append('dev_pid', 1537);// 英文formData.append('dev_pid', 1737);
-
语音唤醒:结合WebAudio API实现关键词检测
-
离线识别:考虑集成百度离线语音SDK(需商业授权)
通过以上实现方案,开发者可以在UniApp(Vue2)项目中快速构建稳定的语音识别功能。实际开发中需注意百度API的调用频率限制(免费版QPS=5),对于高并发场景建议申请企业版服务。