本文基于「灶台导航」小程序实际开发经验,全面总结微信同声传译插件(WechatSI)的使用方法,涵盖插件配置、语音识别、语音合成、权限处理及最佳实践。


一、插件简介

1.1 什么是微信同声传译插件?

微信同声传译插件是微信官方提供的语音处理插件,主要提供以下能力:

功能 说明 应用场景
语音识别 将语音转为文字 语音搜索、语音输入
语音合成 将文字转为语音 步骤播报、语音提示
实时翻译 中英互译(暂不常用) 国际化场景

1.2 为什么选择官方插件?

对比项 官方插件 第三方服务
集成难度 ⭐ 简单,声明即可 ⭐⭐⭐ 需对接API
费用 基础配额免费 按量计费
稳定性 官方维护 依赖第三方
审核速度 无需额外审核 可能需要ICP备案

二、插件配置

2.1 在 app.json 中声明插件

{
  "plugins": {
    "WechatSI": {
      "version": "0.3.6",
      "provider": "wx069ba97219f66d99"
    }
  }
}

参数说明:

  • version:插件版本号,建议使用稳定版本
  • provider:插件 AppID,固定为 wx069ba97219f66d99
    在这里插入图片描述
    注意:需要在插件市场将该插件导入。

2.2 录音权限声明

app.json 中添加录音权限描述:

{
  "permission": {
    "scope.record": {
      "desc": "用于语音输入,让您通过说话快速输入食材和场景"
    }
  }
}

2.3 引入插件

在需要使用的页面 JS 文件顶部引入:

const plugin = requirePlugin('WechatSI')

三、语音识别实战

3.1 获取识别管理器

微信同声传译插件提供了专门的语音识别管理器,集成了录音+识别功能:

const plugin = requirePlugin('WechatSI')

// 获取语音识别管理器(录音+识别一体化)
const manager = plugin.getRecordRecognitionManager()

注意:这是插件特有的管理器,不同于 wx.getRecorderManager()。插件管理器将录音和识别合并为一个流程,使用更便捷。

3.2 初始化识别事件

Page({
  data: {
    isRecording: false,
    recognizedText: ''
  },

  onLoad() {
    this.initRecorderManager()
  },

  initRecorderManager() {
    const manager = plugin.getRecordRecognitionManager()
    this.recorderManager = manager

    // 录音开始
    manager.onStart = (res) => {
      console.log('[录音] 开始录音识别')
      this.setData({ isRecording: true })
    }

    // 识别完成
    manager.onStop = (res) => {
      console.log('[识别] 结果:', res.result, '时长:', res.duration)
      this.setData({ isRecording: false })

      const text = res.result || ''
      if (text.trim()) {
        this.setData({ recognizedText: text.trim() })
        // 自动发送或处理识别结果
        this.handleRecognizedText(text.trim())
      } else {
        wx.showToast({ title: '未识别到语音内容', icon: 'none' })
      }
    }

    // 错误处理
    manager.onError = (res) => {
      console.error('[录音] 错误:', res.msg, 'retcode:', res.retcode)
      this.setData({ isRecording: false })
      wx.showToast({ title: '录音失败: ' + (res.msg || '未知错误'), icon: 'none' })
    }
  }
})

3.3 开始/停止识别

// 开始录音识别
startRecognition() {
  this.recorderManager.start({
    duration: 60000,  // 最长60秒
    lang: 'zh_CN'     // 中文
  })
}

// 停止录音识别
stopRecognition() {
  this.recorderManager.stop()
}

3.4 两种交互模式

在实际项目中,我们实现了两种语音输入模式:

模式一:长按说话(按住录音,松开发送)
// 按下开始
holdStart() {
  this._checkRecordPermission(() => {
    this._recordSource = 'hold'  // 标记来源
    this.recorderManager.start({ duration: 60000, lang: 'zh_CN' })
  })
}

// 松开结束
holdEnd() {
  if (this.data.isRecording) {
    this.recorderManager.stop()
  }
}

// 在 onStop 回调中判断
manager.onStop = (res) => {
  const source = this._recordSource
  if (res.result && source === 'hold') {
    // 自动发送
    setTimeout(() => this.onSend(), 300)
  }
}
模式二:点击切换(点击开始,再点击结束)
toggleRecording() {
  if (this.data.isRecording) {
    // 正在录音,点击结束
    this.recorderManager.stop()
  } else {
    // 未在录音,点击开始
    this._checkRecordPermission(() => {
      this._recordSource = 'toggle'
      this.recorderManager.start({ duration: 60000, lang: 'zh_CN' })
    })
  }
}

四、语音合成(TTS)实战

4.1 基础用法

const plugin = requirePlugin('WechatSI')

// 文字转语音
speakText(text) {
  plugin.textToSpeech({
    lang: 'zh_CN',
    tts: true,
    content: text,
    success: (res) => {
      // res.filename 是生成的音频文件临时路径
      const innerAudio = wx.createInnerAudioContext()
      innerAudio.src = res.filename
      innerAudio.play()

      innerAudio.onEnded(() => {
        innerAudio.destroy()
      })

      innerAudio.onError((err) => {
        console.error('[TTS] 播放失败:', err)
        innerAudio.destroy()
      })
    },
    fail: (err) => {
      console.error('[TTS] 语音合成失败:', err)
    }
  })
}

4.2 播报当前步骤(实际应用)

在烹饪导航页中,我们使用 TTS 播报当前步骤:

// pages/cook/cook.js
const plugin = requirePlugin('WechatSI')

Page({
  data: {
    currentStep: 1,
    currentStepData: {},
    isVoiceOn: false,
    currentAudio: null
  },

  // 播报当前步骤
  speakCurrentStep() {
    const step = this.data.currentStepData
    if (!step || !step.description) return

    // 构建播报文本
    let text = `${this.data.currentStep}步,${step.description}`

    // 添加时长提示
    if (step.duration) {
      const m = Math.floor(step.duration / 60)
      const s = step.duration % 60
      if (m > 0) {
        text += `。预计需要${m}${s > 0 ? s + '秒' : '钟'}`
      } else {
        text += `。预计需要${s}`
      }
    }

    // 添加小贴士
    if (step.tips) {
      text += `。小贴士:${step.tips}`
    }

    this.speakText(text)
  },

  // 通用播报方法
  speakText(text) {
    if (!this.data.isVoiceOn || !text) return

    // 先停止之前的播放
    if (this.currentAudio) {
      this.currentAudio.stop()
      this.currentAudio.destroy()
      this.currentAudio = null
    }

    plugin.textToSpeech({
      lang: 'zh_CN',
      tts: true,
      content: text,
      success: (res) => {
        if (!this.data.isVoiceOn) return  // 用户已关闭

        const innerAudio = wx.createInnerAudioContext()
        innerAudio.src = res.filename
        this.currentAudio = innerAudio

        innerAudio.play()

        innerAudio.onEnded(() => {
          innerAudio.destroy()
          if (this.currentAudio === innerAudio) {
            this.currentAudio = null
          }
        })

        innerAudio.onError((err) => {
          console.error('[TTS] 播放失败:', err)
          innerAudio.destroy()
          if (this.currentAudio === innerAudio) {
            this.currentAudio = null
          }
        })
      },
      fail: (err) => {
        console.error('[TTS] 语音合成失败:', err)
      }
    })
  },

  // 开启语音
  startVoice() {
    this.setData({ isVoiceOn: true })
    this.speakCurrentStep()
  },

  // 关闭语音
  stopVoice() {
    this.setData({ isVoiceOn: false })
    if (this.currentAudio) {
      this.currentAudio.stop()
      this.currentAudio.destroy()
      this.currentAudio = null
    }
  }
})

五、权限处理

5.1 检查并申请录音权限

_checkRecordPermission(callback) {
  wx.getSetting({
    success: (res) => {
      const recordAuth = res.authSetting['scope.record']

      if (recordAuth === true) {
        // 已授权
        callback()
      } else if (recordAuth === false) {
        // 用户之前拒绝过,引导去设置
        wx.showModal({
          title: '提示',
          content: '需要麦克风权限才能使用语音输入,是否前往设置?',
          success: (modalRes) => {
            if (modalRes.confirm) {
              wx.openSetting()
            }
          }
        })
      } else {
        // 从未授权,申请授权
        wx.authorize({
          scope: 'scope.record',
          success: () => callback(),
          fail: () => {
            wx.showModal({
              title: '提示',
              content: '需要麦克风权限才能使用语音输入,是否前往设置?',
              success: (modalRes) => {
                if (modalRes.confirm) {
                  wx.openSetting()
                }
              }
            })
          }
        })
      }
    }
  })
}

5.2 权限状态说明

authSetting 值 含义 处理方式
true 已授权 直接使用
false 已拒绝 引导去设置
undefined 未询问 调用 wx.authorize

六、完整交互流程

6.1 语音搜索完整实现

// pages/index/index.js
const plugin = requirePlugin('WechatSI')

Page({
  data: {
    inputMode: 'text',  // 'text' | 'voice'
    isRecording: false,
    inputText: ''
  },

  onLoad() {
    this.initRecorderManager()
  },

  initRecorderManager() {
    const manager = plugin.getRecordRecognitionManager()
    this.recorderManager = manager

    manager.onStart = () => {
      this.setData({ isRecording: true })
    }

    manager.onStop = (res) => {
      this.setData({ isRecording: false })

      const text = res.result || ''
      if (text.trim()) {
        this.setData({ inputText: text.trim() })
        // 自动发送搜索
        this.handleSearch(text.trim())
      }
    }

    manager.onError = (err) => {
      this.setData({ isRecording: false })
      wx.showToast({ title: '识别失败', icon: 'none' })
    }
  },

  // 切换输入模式
  switchInputMode() {
    const newMode = this.data.inputMode === 'text' ? 'voice' : 'text'
    this.setData({ inputMode: newMode })
  },

  // 开始语音输入
  startVoiceRecord() {
    this._checkRecordPermission(() => {
      this.recorderManager.start({ duration: 60000, lang: 'zh_CN' })
    })
  },

  // 结束语音输入
  stopVoiceRecord() {
    this.recorderManager.stop()
  },

  // 处理搜索
  async handleSearch(text) {
    wx.showLoading({ title: '搜索中...' })

    try {
      const res = await wx.cloud.callFunction({
        name: 'chat',
        data: { message: text }
      })

      this.setData({ searchResult: res.result })

      // 可选:TTS播报结果
      if (res.result.speakText) {
        this.speakText(res.result.speakText)
      }
    } catch (err) {
      wx.showToast({ title: '搜索失败', icon: 'none' })
    } finally {
      wx.hideLoading()
    }
  }
})

七、最佳实践

7.1 音频实例管理

问题:多次调用 wx.createInnerAudioContext() 会创建多个实例,导致资源浪费和播放混乱。

解决方案:单例管理

// utils/audio-manager.js
class AudioManager {
  constructor() {
    this.innerAudioContext = null
    this.isPlaying = false
  }

  getInstance() {
    if (!this.innerAudioContext) {
      this.innerAudioContext = wx.createInnerAudioContext()
      this.setupEvents()
    }
    return this.innerAudioContext
  }

  play(src) {
    const audio = this.getInstance()

    // 如果正在播放,先停止
    if (this.isPlaying) {
      audio.stop()
    }

    audio.src = src
    this.isPlaying = true
    audio.play()
  }

  stop() {
    if (this.innerAudioContext && this.isPlaying) {
      this.innerAudioContext.stop()
      this.isPlaying = false
    }
  }

  destroy() {
    if (this.innerAudioContext) {
      this.innerAudioContext.destroy()
      this.innerAudioContext = null
    }
  }
}

module.exports = new AudioManager()

7.2 语音开关持久化

// 存储用户设置
function saveVoiceSettings(enabled) {
  wx.setStorageSync('voiceEnabled', enabled)
}

// 读取用户设置
function getVoiceSettings() {
  return wx.getStorageSync('voiceEnabled') !== false  // 默认开启
}

// 页面中使用
Page({
  onLoad() {
    const voiceEnabled = getVoiceSettings()
    this.setData({ isVoiceOn: voiceEnabled })
  },

  onVoiceToggle() {
    const newStatus = !this.data.isVoiceOn
    this.setData({ isVoiceOn: newStatus })
    saveVoiceSettings(newStatus)
  }
})

7.3 页面卸载时释放资源

Page({
  onUnload() {
    // 停止定时器
    if (this._timerInterval) {
      clearInterval(this._timerInterval)
    }

    // 停止语音
    if (this.currentAudio) {
      this.currentAudio.stop()
      this.currentAudio.destroy()
      this.currentAudio = null
    }
  }
})

八、常见问题

8.1 识别不到语音

插件版本过老,api过时了
或者没有打开录音权限。

8.2 点击去授权跳转页面没有授权按钮

需要先进行微信登录再通过微信授权

九、总结

9.1 核心API速查表

功能 API 说明
获取识别管理器 plugin.getRecordRecognitionManager() 录音+识别一体化
开始识别 manager.start({ duration, lang }) duration 最长60秒
停止识别 manager.stop() 触发 onStop 回调
文字转语音 plugin.textToSpeech({ lang, tts, content }) 返回音频临时路径
播放音频 wx.createInnerAudioContext() 配合 TTS 使用

9.2 使用流程图

语音识别流程:
开始录音 → onStart → 用户说话 → stop() → onStop(result) → 处理识别结果

语音合成流程:
构建文本 → textToSpeech → success(filename) → InnerAudioContext.play() → onEnded → destroy()

作者:「倒灶了队」

项目:灶台导航 - 微信小程序

更新时间:2026-04-08

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐