前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >腾讯云语音识别云开发微信小程序

腾讯云语音识别云开发微信小程序

原创
作者头像
张世强
修改2020-06-04 17:32:49
21.5K8
修改2020-06-04 17:32:49
举报
文章被收录于专栏:zhang

一、实现方式

通过录音管理器 RecorderManager调用手机的录音功能实现音频的在线采集,通过采集到的音频的base64字符串调用云开发侧实现的腾讯云一句话识别云函数,然后将识别结果回调到小程序页面中。

二、实现流程

第一步:开通云开发控制台并创建云端项目环境

添加描述

添加描述

添加描述

第二步:在小程序项目根目录下创建本地云函数根目录functions,在项目根目录找到 project.config.json 文件,新增 cloudfunctionRoot 字段,值为刚才创建的本地云函数根目录名称

第三步:创建一句话识别云函数并配置tencentcloud-sdk-nodejs依赖

第四步:安装依赖

在asr云函数目录上右键选择在"在终端中打开"

代码语言:shell
复制
E:\tencentcloudcode\wechat\functions\asr>npm install
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142

> protobufjs@6.8.8 postinstall E:\tencentcloudcode\wechat\functions\asr\node_modules\protobufjs
> node scripts/postinstall

npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN asr@1.0.0 No description
npm WARN asr@1.0.0 No repository field.

added 101 packages from 194 contributors and audited 186 packages in 8.85s
found 0 vulnerabilities

第五步:在一句话识别云函数目录下的入口文件index.js中实现一句话识别的API调用Demo,然后上传Demo至云端

代码语言:javascript
复制
// 云函数入口文件
const cloud = require('wx-server-sdk')  // 引入云开发服务的内核SDK

cloud.init(   //初始化一个'wx-server-sdk' SDK 实例
{
  env: 'ai-test-t7t64'   // 开通云开发服务后创建的云环境的环境ID(默认可以创建两个ID)
}
)

// 云函数入口函数
exports.main = async (event, context) => {
   
const tencentcloud = require("tencentcloud-sdk-nodejs");  //引入腾讯云SDK

// 下面的代码可以通过explorer在线生成(https://console.cloud.tencent.com/api/explorer?Product=aai&Version=2018-05-22&Action=SentenceRecognition&SignVersion=)
const AaiClient = tencentcloud.aai.v20180522.Client;
const models = tencentcloud.aai.v20180522.Models;

const Credential = tencentcloud.common.Credential;
const ClientProfile = tencentcloud.common.ClientProfile;
const HttpProfile = tencentcloud.common.HttpProfile;

let cred = new Credential("", "");
let httpProfile = new HttpProfile();
httpProfile.endpoint = "aai.tencentcloudapi.com";
let clientProfile = new ClientProfile();
clientProfile.httpProfile = httpProfile;
let client = new AaiClient(cred, "ap-guangzhou", clientProfile);

let req = new models.SentenceRecognitionRequest();
let base64Data=event.x   //接收客户端post的x参数,值类型为base64字符串
let DataLen = event.s    //接收音频文件的大小
var params =  {"ProjectId":0,"SubServiceType":2,"EngSerViceType":"16k_zh","SourceType":1,"VoiceFormat":"mp3","UsrAudioKey":"www","Data":base64Data,"DataLen":DataLen}  // 定义SDK的请求参数字典
params = JSON.stringify(params)   // 转换为json字符串
req.from_json_string(params);
return new Promise((resolve, reject) => {   // 通过Promise容器来接收异步API的回调,然后通过当前脚本返回给客户端
  client.SentenceRecognition(req, function(errMsg, response)  {  // 此接口是异步的,那么当前脚本无法对外直接访问接口返回值
    if (errMsg) {
      resolve({ "Result": errMsg })
    }
    // resp = response.to_json_string()
    resolve({ "Result": response})
});
})
}

注:云函数的入口文件index.js中调用的"一句话识别"API方法"SentenceRecognition”是异步的,如果直接拷贝Explorer中生成的Demo,将无法为小程序客户端返回"SentenceRecognition”的回调数据,脚本最终会返回null;所以这里我们需要使用Promise对象来获取"SentenceRecognition"的回调数据,然后返回给小程序客户端

第六步:小程序中实现音频在线采集页面

在小程序公共配置文件app.json中,添加页面生成参数

代码语言:json
复制
"pages/voicec/voicec",

点击"编译"生成页面目录及页面

voicec.wxml

代码语言:javascript
复制
<!--pages/voicec/voicec.wxml-->
<view class="REC">
  <view class="time">{{status==0?'录音时长':(status==3?'录音结束':'录音中')}}:{{time}} 秒 ({{duration/1000}}秒)</view>
  <view class="rin">
  <view class="{{status==3 && actionStatus==0?'show':'hide'}}" bindtap="play" hover-class="skip">{{actionStatus==1?'播放中':'播放录音'}}</view>
    <view class="{{status==3?'show':'hide'}}" bindtap="again" hover-class="skip">再次录制</view> 
  </view>
  <view class="anniu">
    <view class="{{status==0?'highlight':'gray'}}" bindtap="start" hover-class="skip">开始</view>
    <view class="{{status==1?'highlight':'gray'}}" bindtap="stop" hover-class="skip">暂停</view>
    <view class="{{status==2?'highlight':'gray'}}" bindtap="continue" hover-class="skip">继续</view>
    <view class="{{(status==1 || status==2)?'highlight':'gray'}}" bindtap="shutoff" hover-class="skip">停止</view>
    <view class="{{status==3?'highlight':'gray'}}" bindtap="recognition" hover-class="skip">识别</view>
  </view>
   <view class="progress">
    <progress percent="{{time*(100/(duration/1000))}}"  stroke-width="10" backgroundColor="#fff" border-radius="15" stroke-width="4" color="#7FFF00" active />
  </view>
</view>
<view class=".REC">
  <textarea placeholder="录音完成后点击识别可将音频转文字" auto-focus value="{{ Words }}" />
</view>

使用的组件:

进度条progress

多行输入框textarea

使用的视图容器:

view

使用的XML语法:

双大括号数据绑定之三元运算

使用的视图层:

bindtap事件绑定

voicec.js

代码语言:javascript
复制
// pages/voicec/voicec.js
const recorderManager = wx.getRecorderManager()  // 获取全局唯一的录音管理器 RecorderManager
const innerAudioContext = wx.createInnerAudioContext()  // 创建内部 audio 上下文 InnerAudioContext 对象。
var init  // 声明一个全局变量,let为局部变量
Page({  // 使用Page函数作为Page构造器来注册一个页面

  /**
   * 页面的初始数据
   */
  data: {
    voiceSize:0, // 音频的大小
    time: 0, // 初始时间
    duration: 60000, // 录音长时间为1分钟
    localFilePath: "",  //录音文件在本地的路径
    status: 0,  // 录音器的状态:开始1,暂停2,继续1,停止3
    actionStatus: 0, //录音播放状态,1为播放状态,0为未播放状态
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function(options) {

  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function() {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function() {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function() {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function() {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function() {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function() {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function() {

  },


  /**开始录音 */
  start: function() {
    clearInterval(init) // 取消之前的计时
    recorderManager.onStart((res) => {  // 监听录音开始事件
      console.log('开始录音')
      this.setData({
        status: 1 // 录音开始状态为1
      })
    })

    recorderManager.onStop((res) => {  // 监听录音停止事件
      console.log('停止录音', res)
      this.setData({
        tempFilePath: res.tempFilePath, // 如果录音停止了,修改本地文件地址
        status: 3
      })
      this.timeCounter(this.data.time) // 取消计时
    })

    const options = { //定义录音参数
      duration: this.data.duration,  // 录音时长 
      format: 'mp3', // 音频格式
    }
    this.timeCounter()  // 开始计时
    recorderManager.start(options) // 开始录音
  },

  /**
   * 录音暂停
   */
  stop: function() {
    recorderManager.onPause(() => {
      console.log('recorder pause')
      this.setData({
        status: 2
      })
    })
    this.timeCounter(this.data.time) // 取消计时,暂时和停止都是取消计时
    recorderManager.pause() // 暂停录音
  },

  /**
   * 录音继续
   */
  continue: function() {
    this.setData({
      status: 1  // 标记为正在录音状态
    })
    this.timeCounter() // 在之前的计时基础上继续+1计时
    recorderManager.resume()  // 继续录音
  },

  /**
   * 录音停止
   */
  shutoff: function() {
    recorderManager.onStop((res) => {
      console.log('recorder stop', res)
      this.setData({
        tempFilePath: res.tempFilePath,  // 录音生成文件的本地路径
        status: 3  // 标记录音状态为停止
      })
    })
    this.timeCounter(this.data.time)   // 取消计时
    recorderManager.stop() // 停止录音

  },
  /**
   * 录音识别
   */
  recognition: function() {
    var that=this;
    wx.getFileInfo({
      filePath:this.data.tempFilePath,
      success (res) {
        console.log("录音文件的大小为"+res.size)
        that.data.voiceSize=res.size
      }
    })
    wx.cloud.init() // 初始化云函数环境
    wx.cloud.callFunction({  // 调用云函数
      // 云函数名称
      name: 'asr',  // 调用的云函数的名称
      // 传给云函数的参数
      data: {
        s:that.data.voiceSize,   // 音频文件的大小
        // x: wx.getFileSystemManager().readFileSync(this.data.tempFilePath, 'base64') 
        x: wx.getFileSystemManager().readFileSync("files/test.mp3", 'base64')  // 读取本地文件的base64字符串
      },
      success: function(res) {
        console.log(res)
        that.setData({  // 发送数据到视图层
          Words: res.result.Result.Result
        })
      },
      fail: console.error
    })
  },

  /**
   * 录音播放
   */
  play: function() {
    innerAudioContext.src = this.data.tempFilePath // 音频资源的地址,用于直接播放
    innerAudioContext.obeyMuteSwitch = false // 是否遵循系统静音开关,默认为 true,当此参数为 false 时,即使用户打开了静音开关,也能继续发出声音

    
    if (this.data.actionStatus == 0) {
      this.setData({
        actionStatus: 1
      })
      innerAudioContext.play()  // 播放音频
    }
  
    innerAudioContext.onEnded(() => {  //监听音频自然播放至结束的事件
      innerAudioContext.stop()  // 停止播放
      this.setData({
        actionStatus: 0
      })
    })
  },

  
  timeCounter: function(time) {  // 定义一个计时器函数
    var that = this
    if (time == undefined) {
   
      init = setInterval(function() { // 设定一个计时器ID。按照指定的周期(以毫秒计)来执行注册的回调函数
        var time = that.data.time + 1; // 每秒钟计时+1
        that.setData({
          time: time
        })
      }, 1000);
    } else {
      clearInterval(init) // 取消计时
      console.log("暂停计时")
    }
  },

  /**
   * 重新录制
   */
  again: function() {
    var that = this
    wx.showModal({  // 显示模态对话框
      title: "重新录音", //提示的标题 
      content: "是否重新录制?", //提示的内容
      success(res) {
        if (res.confirm) { // 点击了确定
          that.setData({  // 重置初始化数据
            time: 0, 
            tempFilePath: "", 
            status: 0,
            actionStatus: 0
          })
          innerAudioContext.stop() // 停止音频
        }
      }
    })
  }
})

使用到的知识点: Page 构造器

录音管理器

HTTPS 网络请求

文件管理器FileSystemManager读取指定编码的文件内容

数据传递setData

注意:如果自定义函数中嵌套了wx等对象函数,数据传递应该先声明"var that=this",然后再嵌套函数,如wx.request中使用"that.setData"来传递数据

voicec.json

代码语言:javascript
复制
{
  "navigationBarTitleText": "云开发一句话识别在线测试",
  "backgroundColor": "#eeeeee"
}

全局配置

voicec.wxss

代码语言:javascript
复制
/* pages/voicec/voicec.wxss */
.REC {
  border-radius: 25rpx;
  background-color: rgb( 199,237,204 );
  padding: 6rpx 0rpx;
  margin: 15rpx 35rpx;
}

.rin {
  justify-content: space-between;
  align-items: center;
  margin: 0rpx 120rpx;
  display: flex;
}

.rin .show {
  background-color: rgb(178, 228, 228);
  padding: 15rpx;
  width: 210rpx;
  border: 5rpx solid rgb(127, 204, 214);
  border-radius: 20rpx;
  font-size: 28rpx;
  display: flex;
  justify-content: center;
  align-items: center;
}

.rin .hide {
  padding: 15rpx;
  align-items: center;
  border-radius: 20rpx;
  display: flex;
  width: 215rpx;
  font-size: 28rpx;
  justify-content: center;
  border: 5rpx solid #eee;
  pointer-events: none;
  background-color: rgba(137, 190, 178, 0.445);
}

.time {
  text-align: center;
  line-height: 75rpx;
  font-size: 28rpx; 
}

.progress {
  margin: 25rpx;
}

.play {
  margin: 0rpx 25rpx;
}

.content {
  line-height: 60rpx;
  font-size: 28rpx;
  display: flex;
  justify-content: center;
}

.anniu {
  display: flex;
  margin: 10rpx 50rpx;
  justify-content: space-between;
}

.highlight {
  display: flex;
  font-size: 28rpx;
  width: 80rpx;
  height: 80rpx;
  justify-content: center;
  border-radius: 50%;
  align-items: center;
  background-color: rgb(107, 194, 53);
  border: 5rpx solid rgb(127, 204, 214);
}

.skip {
  transform: scale(0.9);
}



.anniu .gray {
  pointer-events: none;
  background-color: rgba(137, 190, 178, 0.445);
  display: flex;
  width: 80rpx;
  height: 80rpx;
  font-size: 28rpx;
  justify-content: center;
  align-items: center;
  border-radius: 50%;
  border: 5rpx solid rgb(241, 244, 245); 
}

WXSS样式学习

测试效果

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、实现方式
  • 二、实现流程
    • 第一步:开通云开发控制台并创建云端项目环境
      • 第二步:在小程序项目根目录下创建本地云函数根目录functions,在项目根目录找到 project.config.json 文件,新增 cloudfunctionRoot 字段,值为刚才创建的本地云函数根目录名称
        • 第三步:创建一句话识别云函数并配置tencentcloud-sdk-nodejs依赖
          • 第四步:安装依赖
            • 第五步:在一句话识别云函数目录下的入口文件index.js中实现一句话识别的API调用Demo,然后上传Demo至云端
              • 第六步:小程序中实现音频在线采集页面
                • voicec.wxml
                • voicec.js
                • voicec.json
                • voicec.wxss
            相关产品与服务
            云函数
            云函数(Serverless Cloud Function,SCF)是腾讯云为企业和开发者们提供的无服务器执行环境,帮助您在无需购买和管理服务器的情况下运行代码。您只需使用平台支持的语言编写核心代码并设置代码运行的条件,即可在腾讯云基础设施上弹性、安全地运行代码。云函数是实时文件处理和数据处理等场景下理想的计算平台。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档