基于Uniapp实现长按语音识别文字的完整方案

基于Uniapp实现长按语音识别文字的完整方案

在移动端应用中,语音输入因其高效便捷的特性已成为重要交互方式。Uniapp作为跨平台开发框架,结合主流语音识别技术可实现长按触发语音转文字功能。本文将系统阐述从长按事件监听到语音识别结果处理的完整技术实现路径。

一、技术架构设计

实现长按语音识别需构建三层技术架构:

  1. 交互层:通过手势事件监听长按操作
  2. 识别层:调用语音识别API进行声学处理
  3. 结果层:处理识别文本并更新UI

跨平台实现时需考虑不同操作系统的差异:iOS需适配语音权限申请,Android需处理后台服务限制,H5端则依赖浏览器Web Speech API支持。建议采用条件编译实现平台差异化处理。

二、核心实现步骤

1. 长按事件监听实现

在Uniapp中可通过@longpress事件或手动计算触摸时长实现:

  1. <view
  2. @touchstart="handleTouchStart"
  3. @touchend="handleTouchEnd"
  4. @touchcancel="handleTouchCancel"
  5. >
  6. 按住说话
  7. </view>
  1. methods: {
  2. handleTouchStart(e) {
  3. this.touchStartTime = Date.now()
  4. this.isLongPress = false
  5. this.startTimer = setTimeout(() => {
  6. this.isLongPress = true
  7. this.startVoiceRecognition()
  8. }, 800) // 800ms判定为长按
  9. },
  10. handleTouchEnd(e) {
  11. clearTimeout(this.startTimer)
  12. if (this.isLongPress) {
  13. this.stopVoiceRecognition()
  14. }
  15. },
  16. handleTouchCancel() {
  17. clearTimeout(this.startTimer)
  18. if (this.isLongPress) {
  19. this.stopVoiceRecognition()
  20. }
  21. }
  22. }

2. 语音识别API集成

方案一:使用Web Speech API(H5端)

  1. startVoiceRecognition() {
  2. const recognition = new (window.SpeechRecognition ||
  3. window.webkitSpeechRecognition ||
  4. window.mozSpeechRecognition ||
  5. window.msSpeechRecognition)()
  6. recognition.continuous = false
  7. recognition.interimResults = false
  8. recognition.lang = 'zh-CN'
  9. recognition.onresult = (event) => {
  10. const transcript = event.results[0][0].transcript
  11. this.handleRecognitionResult(transcript)
  12. }
  13. recognition.onerror = (event) => {
  14. console.error('识别错误:', event.error)
  15. this.showError('语音识别失败')
  16. }
  17. recognition.start()
  18. this.recognitionInstance = recognition
  19. }

方案二:调用原生语音识别(App端)

通过uni-app插件市场或自定义原生插件集成:

  1. // 使用uni.request调用后端语音识别API示例
  2. async startVoiceRecognition() {
  3. try {
  4. // 1. 初始化录音
  5. const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
  6. this.mediaRecorder = new MediaRecorder(stream)
  7. // 2. 创建音频块收集器
  8. const audioChunks = []
  9. this.mediaRecorder.ondataavailable = event => {
  10. audioChunks.push(event.data)
  11. }
  12. // 3. 开始录音
  13. this.mediaRecorder.start(100) // 100ms分割一次
  14. // 4. 设置录音时长限制
  15. this.recordTimeout = setTimeout(() => {
  16. this.stopAndRecognize(audioChunks)
  17. }, 60000) // 60秒限制
  18. } catch (err) {
  19. console.error('录音错误:', err)
  20. }
  21. }
  22. async stopAndRecognize(chunks) {
  23. this.mediaRecorder.stop()
  24. clearTimeout(this.recordTimeout)
  25. const audioBlob = new Blob(chunks, { type: 'audio/wav' })
  26. const audioUrl = URL.createObjectURL(audioBlob)
  27. // 调用语音识别服务(示例为伪代码)
  28. const formData = new FormData()
  29. formData.append('audio', audioBlob, 'recording.wav')
  30. const response = await fetch('https://api.example.com/asr', {
  31. method: 'POST',
  32. body: formData
  33. })
  34. const result = await response.json()
  35. this.handleRecognitionResult(result.text)
  36. }

3. 跨平台兼容性处理

通过条件编译实现差异化处理:

  1. // #ifdef H5
  2. startVoiceRecognition() {
  3. // 使用Web Speech API
  4. }
  5. // #endif
  6. // #ifdef APP-PLUS
  7. startVoiceRecognition() {
  8. // 调用原生插件或后端API
  9. if (plus.os.name === 'iOS') {
  10. // iOS特殊处理
  11. } else {
  12. // Android处理
  13. }
  14. }
  15. // #endif

三、最佳实践与优化

1. 用户体验优化

  • 视觉反馈:长按期间显示录音动画和音量波纹
  • 语音提示:开始录音时播放”开始录音”提示音
  • 超时处理:设置最长录音时间(建议60秒)
  • 网络检测:录音前检查网络连接状态

2. 性能优化策略

  • 音频压缩:录音时采用8kHz采样率,16bit位深
  • 分块传输:将长录音分割为多个小文件传输
  • 缓存机制:本地缓存最近10条识别结果
  • 错误重试:网络错误时自动重试3次

3. 安全与隐私

  • 权限管理:动态申请录音权限
  • 数据加密:传输过程使用HTTPS加密
  • 隐私政策:明确告知用户语音数据处理方式
  • 本地处理:敏感场景建议使用端侧识别

四、完整实现示例

  1. export default {
  2. data() {
  3. return {
  4. touchStartTime: 0,
  5. isLongPress: false,
  6. startTimer: null,
  7. mediaRecorder: null,
  8. recordTimeout: null
  9. }
  10. },
  11. methods: {
  12. handleTouchStart(e) {
  13. this.touchStartTime = Date.now()
  14. this.isLongPress = false
  15. this.startTimer = setTimeout(() => {
  16. this.isLongPress = true
  17. this.showRecordingUI()
  18. this.startVoiceRecognition()
  19. }, 800)
  20. },
  21. async startVoiceRecognition() {
  22. try {
  23. // #ifdef H5
  24. if (!('webkitSpeechRecognition' in window) &&
  25. !('SpeechRecognition' in window)) {
  26. throw new Error('浏览器不支持语音识别')
  27. }
  28. const recognition = new (window.SpeechRecognition ||
  29. window.webkitSpeechRecognition)()
  30. recognition.lang = 'zh-CN'
  31. recognition.interimResults = false
  32. recognition.onresult = (event) => {
  33. const transcript = event.results[0][0].transcript
  34. this.handleRecognitionResult(transcript)
  35. }
  36. recognition.onerror = (event) => {
  37. this.handleRecognitionError(event.error)
  38. }
  39. recognition.start()
  40. this.recognitionInstance = recognition
  41. // #endif
  42. // #ifdef APP-PLUS
  43. // 实现APP端录音逻辑
  44. const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
  45. this.mediaRecorder = new MediaRecorder(stream, {
  46. mimeType: 'audio/wav',
  47. audioBitsPerSecond: 128000
  48. })
  49. const chunks = []
  50. this.mediaRecorder.ondataavailable = e => chunks.push(e.data)
  51. this.mediaRecorder.start(100)
  52. this.recordTimeout = setTimeout(() => {
  53. this.stopAndRecognize(chunks)
  54. }, 60000)
  55. // #endif
  56. } catch (error) {
  57. console.error('启动识别失败:', error)
  58. this.showError('无法启动语音识别')
  59. }
  60. },
  61. stopVoiceRecognition() {
  62. clearTimeout(this.startTimer)
  63. clearTimeout(this.recordTimeout)
  64. // #ifdef H5
  65. if (this.recognitionInstance) {
  66. this.recognitionInstance.stop()
  67. }
  68. // #endif
  69. // #ifdef APP-PLUS
  70. if (this.mediaRecorder && this.mediaRecorder.state !== 'inactive') {
  71. this.stopAndRecognize([])
  72. }
  73. // #endif
  74. },
  75. async stopAndRecognize(chunks) {
  76. if (this.mediaRecorder) {
  77. this.mediaRecorder.stop()
  78. }
  79. if (chunks.length === 0) return
  80. const blob = new Blob(chunks, { type: 'audio/wav' })
  81. const formData = new FormData()
  82. formData.append('file', blob, 'record.wav')
  83. try {
  84. const response = await uni.request({
  85. url: 'https://api.example.com/asr',
  86. method: 'POST',
  87. data: formData,
  88. header: {
  89. 'Content-Type': 'multipart/form-data'
  90. }
  91. })
  92. if (response[1].statusCode === 200) {
  93. this.handleRecognitionResult(response[1].data.result)
  94. } else {
  95. throw new Error('识别服务错误')
  96. }
  97. } catch (error) {
  98. this.handleRecognitionError('网络错误')
  99. }
  100. },
  101. handleRecognitionResult(text) {
  102. uni.showToast({
  103. title: '识别成功',
  104. icon: 'success'
  105. })
  106. console.log('识别结果:', text)
  107. // 更新UI或处理文本
  108. },
  109. handleRecognitionError(error) {
  110. console.error('识别错误:', error)
  111. uni.showToast({
  112. title: '识别失败: ' + error,
  113. icon: 'none'
  114. })
  115. }
  116. }
  117. }

五、常见问题解决方案

  1. iOS录音权限问题

    • 在info.plist中添加NSMicrophoneUsageDescription字段
    • 调用uni.authorize提前申请权限
  2. Android后台录音限制

    • 配置AndroidManifest.xml添加RECORD_AUDIO权限
    • 使用Service保持录音进程
  3. H5端兼容性问题

    • 检测浏览器支持情况:'webkitSpeechRecognition' in window
    • 提供降级方案:显示输入框替代
  4. 识别准确率优化

    • 控制录音环境噪音
    • 使用专业音频格式(如16kHz 16bit PCM)
    • 选择支持方言识别的服务

通过上述技术方案,开发者可在Uniapp中构建稳定的长按语音识别功能,兼顾各平台特性和用户体验。实际开发时建议先实现H5端基础功能,再逐步扩展App端特性,最后处理边缘场景和异常情况。