微信小程序实现的腾讯AI闲聊和语音识别

微信前端的开发

.wxml文件(界面的编写)
<text>智能聊天助手</text>
<view class="top"></view>
<scroll-view class="context" scroll-y="true" scroll-top="{{scrolltop}}">
<block wx:for="{{arr}}">
  <view wx:if="{{item.tag==true}}" class="right_view">
			<image class="right_head" src="{{item.head}}"></image>
				<view class="right">{{item.text}}</view>
		</view>
  <view wx:else class="left_view">
		<image class="left_head" src="{{item.head}}"></image>
		<view class="left">{{item.text}}</view>
	</view>
</block>
</scroll-view>

<!-- adjust-position="true" 键盘弹起时,是否自动上推页面 -->
<view class="input">
  <image class="yuyin" src="{{yuyin_img}}" bindtap="yuyin"></image> 
	<input type="text" bindinput="bindinput" class="input_text" adjust-position="true"></input>
	<view bindtap="adddata" class="send_button">发送</view>
</view>

说明:
scroll-view中语句的含义介绍

  • 这里定义一个滑块,作为显示聊天内容的界面
  • scroll-y 属性表示纵向滑动
  • 添加scroll-top属性是为了实现有信息出现在界面时它能自动弹起的效果,* * 取值与js的data中的scrolltop有关
  • 采用 wx:for 循环,调用 arr 数组中的值,并使用 wx:if 条件语句来判断元素中 tag 的真假值,真为右即为发送值,假为左为接收值
  • _head后缀class表示头像
  • right、left名(class)表示消息内容
    scroll-view外
  • 下面定义为输入框的定义
  • yuyin标签表示做下方的语音标识,同时使用 bindtap 绑定了js文件中的 yuyin 函数 ,使用src属性取值 data中 yuyin_img 的标识路径
  • input_text采用ipnut标签,属性设置上type为 text 表示输入为文本类型,同时使用 bindinput 属性与js 文件中的 bindinput 函数连接 输入框信息获
  • adjust-position=“true” 是使得在使用手机输入时 能够使手机键盘自动弹起
  • send_button的view标签即是发送按钮的功能,与 js 中 adddata 函数连接
前端.js文件(数据的存储与后端的AI调用)

【注意:智能闲聊、语音识别的信息发送方式有所不同,智能闲聊发送给后端的字符串信息较短,而语音在前端转成base64格式后会变成一个非常长的字符串,已经超过了GET的请求范围,所以需要使用POST的方式请求】
【注意:使用POST 请求时,后端会反应网络安全的问题,所以需要在后端的config文件中做出语句的修改,详见后端的 config 部分】

// pages/chat_index/chat_index.js
Page({

  /**
   * 页面的初始数据
   */
  /*data中的数据说明:
  arr数组中:tag为bool类型 显示时用于判断是接收方(false),还是发送方(true)
  */ 
  data: {
    arr:[
      {tag:true,text:"你好",head:"../../inco/1.jpg"},
      {tag:false,text:"您好",head:"../../inco/2.jpg"},
      {tag:true,text:"你叫啥",head:"../../inco/1.jpg"},
      {tag:false,text:"我叫小豪",head:"../../inco/2.jpg"},
      {tag:true,text:"背一首诗",head:"../../inco/1.jpg"},
      {tag:false,text:"寒雨连江夜入吴,平明送客楚山孤。洛阳亲友如相问,一片冰心在玉壶。",head:"../../inco/2.jpg"},
    ],
    inputvalue:'',//用于同步保存输入框中的值,以发送给后端
    //inputfeel:'',//
    scrolltop:1000,//用于聊天界面在有新消息时自动弹起的参数,与scroll-top属性相连
    flag:false,//用于语音按键的开关判断true为开,false为关
    yuyin_img:"../../inco/yuyin.png",//用于语音按钮标识的显示
    yuyin_text:"",//用于保存后端AI返回的识别内容
    yuyin_speack:""//用于调试打印录制的音频信息
  },
//语音识别功能
yuyin:function(){
      //1.在data中设置flag为false
      //2.按钮点击时执行下面的函数
      //每次点击改变flag的值 为了做一个开关按钮的功能
      this.data.flag = !this.data.flag
      console.log(this.data.flag)
      if (this.data.flag){
        this.setData({yuyin_img:"../../inco/yuyin2.png"})//更新语音按钮的标识,以表示正在录音
       console.log("开始录音")
        let myrecord=wx.getRecorderManager()//获取录音的工具
         this.setData({ myrecord: myrecord})//把录音工具保存到data中
          myrecord.start({ format:"mp3"})//开始录音
    //监听录音工具停止录音的事件:当录音停止了就会调用函数
          myrecord.onStop(
            (res)=>{
          console.log(res)//获取了录音文件的信息
          this.setData({yuyin_speack:res.tempFilePath})//将语音的地址字符串给yuyin_speack
          console.log(this.data.yuyin_speack)//打印录制的音频信息
          /*将语音的文件转化为based4格式,因为AI语音识别的要求*/
          let data1=wx.getFileSystemManager().readFileSync(res.tempFilePath,'base64')
          console.log(data1)
          //给后端发录音文件,因为发送的base64字符串过长,超出了 GET 请求(默认)的限度,所以使用 POST 请求方式
          wx.request({
            method:"POST",
            url: 'http://192.168.0.101:7001/speech',
            data:{
              info:data1
            },
            success:(res)=>{
              console.log(res);
              this.setData({yuyin_text:res.data.data.data.text})//获取返回的语音数据
             /*将返回的识别内容加入arr数组中,以显示在聊天界面*/
              this.data.arr.push(
                {
                  tag:false,
                  text:res.data.data.data.text,
                  head:"../../inco/2.jpg"
                })
                this.setData({arr:this.data.arr})
              this.setData({scrolltop:1000})
            }
          })
     }) 
  }
  else{
    console.log("结束录音 可以获取录音文件了")
    this.data.myrecord.stop()//停止录音
    this.setData({yuyin_img:"../../inco/yuyin.png"})//更换录音标识为关闭
    this.data.arr.push(
      {
        tag:true,
        text:"语音已发送",
        head:"../../inco/1.jpg"
      })
      this.setData({arr:this.data.arr})
      this.setData({scrolltop:1000})
     
      }
 },


// 发送按钮的点击事件(智能闲聊功能)
adddata:function(){
  var new_data=this.data.arr;
  new_data.push(
    {
      tag:true,
      text:this.data.inputvalue,
      head:"../../inco/1.jpg"
    }
  )
  this.setData({arr:new_data})
  this.setData({scrolltop:1000})

  //发送数据(下面data中的内容)给后端,并用success获取后端返回的数据
  wx.request({
    url: 'http://192.168.0.101:7001/text2',
    data:{
      info:this.data.inputvalue
    },
    success:(res)=>{
      console.log(res.data.data.data.answer);
      this.data.arr.push(
    {
      tag:false,
      text:res.data.data.data.answer,
      head:"../../inco/2.jpg"
    })
    this.setData({arr:this.data.arr})
    this.setData({scrolltop:1000})
    }
  })

},
// 与界面输入框绑定实时获取输入框内容
bindinput:function(e){
  this.setData({inputvalue:e.detail.value})
  console.log(e.detail.value)
},


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

  },

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

  },

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

  },

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

  },

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

  },

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

  },

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

  },

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

  }
})

nodejs后端的开发

app——router.js 的代码
'use strict';

/**
 * @param {Egg.Application} app - egg application
 */
module.exports = app => {
  const { router, controller } = app;
  //router.get('/', controller.home.index);
  
  //该功能是设置网址为/zcx,对应调用controler文件夹中home文件中的zcx函数
  router.get('/zcx', controller.home.zcx);

  router.get('/zcx_2', controller.home.zcx_2);

  router.get('/text', controller.home.text);

  router.get('/text2', controller.home.text2);//智能闲聊接收方

  router.post('/speech', controller.home.speech);//语音识别接收方

};

最后两个分别是智能闲聊接收方语音识别接收方

app——controller——home.js

【注意:】
在计算完成签名后,即准备工作完成,即可发送给腾讯AI进行处理,需要注意的是语音识别的AI的协议要求使用 POST 请求。 method:“POST”

'use strict';
const md5=require("md5");
const fs = require('fs');
const Controller = require('egg').Controller;

class HomeController extends Controller {
  // async index() {
  //   const { ctx } = this;
  //   ctx.body = '66666666';
  // }

  //router.js中使用代码调用zxc函数的功能即是将ctx.body的内容传给访问的前端
  async zcx() {
    const { ctx } = this;
    ctx.body = 'this is my data';
  }

  async zcx_2() {
    const { ctx } = this;
    ctx.body = [{"name":"derek","age":18,"grads":"10"},{"name":"derek1","age":19,"grads":"9"},{"name":"derek3","age":20,"grads":"8"}];
  }

  //ctx.request.query 表示后端收到的前端的数据
  async text() {
    const { ctx } = this;
    console.log(ctx.request.query);
    ctx.body = '后端收到数据';
  }
  //智能闲聊的AI
  async text2() {

    const { ctx } = this;
    console.log(ctx.request.query);

    //1.把前端的发过来的数据发送过AI
    var url="https://api.ai.qq.com/fcgi-bin/nlp/nlp_textchat";

    var obj = {
      app_id: 2154766358,//申请应用时分配的
      session: 'zcx',
      question: ctx.request.query.info,//用户会话信息
      time_stamp: parseInt((new Date().getTime() / 1000)),
      nonce_str: parseInt((new Date().getTime() / 1000)),
      sign: ''
    };

    //以下为签名信息(sign)的计算过程
      //1
      const newkey = Object.keys(obj).sort();
      var params = {};
      for (var i = 0; i < newkey.length; i++) {
          params[newkey[i]] = obj[newkey[i]];
      }
      //2
      let str = '';
      for (const k in params) {
          if (params.hasOwnProperty(k) && params[k]) {
              str += k + '=' + encodeURIComponent(params[k]) + '&';
          }
      }
      //3
      str += 'app_key=' + 'o4ZCz3Mmzy5dTeeZ';
      //4
     //要去下载: npm i md5 --save  还要引入:const md5=require("md5")
     var singstr=md5(str).toUpperCase();


     //5,设置签名
     obj.sign=singstr;

     //准备工作完成,即可发送给腾讯AI进行处理,默认为GET请求
     var result= await this.ctx.curl(url,{
        dataType:"json",
        data:obj,
      })
 
      console.log(result)

    ctx.body = result;
      
    }


  //智能语音识别
  async speech() {

    const { ctx } = this;
    console.log(ctx.request.body);

    //1.把前端的发过来的数据发送过AI
    var url="https://api.ai.qq.com/fcgi-bin/aai/aai_asr";

    var obj = {
      app_id: 2154847969,//申请应用时分配的
      format:2,//语音压缩编码设置为amr
      rate:8000,
      speech:ctx.request.body.info,
      time_stamp: parseInt((new Date().getTime() / 1000)),
      nonce_str: parseInt((new Date().getTime() / 1000)),
      sign: ''
    };

    //以下为签名信息(sign)的计算过程
      //1
      const newkey = Object.keys(obj).sort();
      var params = {};
      for (var i = 0; i < newkey.length; i++) {
          params[newkey[i]] = obj[newkey[i]];
      }
      //2
      let str = '';
      for (const k in params) {
          if (params.hasOwnProperty(k) && params[k]) {
              str += k + '=' + encodeURIComponent(params[k]) + '&';
          }
      }
      //3
      str += 'app_key=' + 'nM2IfdlYGrrR1mgg';
      //4
     //要去下载: npm i md5 --save  还要引入:const md5=require("md5")
     var singstr=md5(str).toUpperCase();


     //5,设置签名
     obj.sign=singstr;

     //准备工作完成,即可发送给腾讯AI进行处理,需要注意的是语音AI的协议要求使用 POST 请求。
     var result= await this.ctx.curl(url,{
        dataType:"json",
        data:obj,
        method:"POST"
      })
 
      console.log(result)

    ctx.body = result;
      
    }
  

}

module.exports = HomeController;

config——config.default.js

这里做配置是为了 解决 使用POST请求时出现的网络安全问题
主要添加的语句是:

 config.security = {
		csrf: {
      			enable: false,
      			ignoreJSON: true,
   		}
	}

  return {
    ...config,
    ...userConfig,
    bodyParser: {
      jsonLimit: '100mb',//修改接受数量限制
      formLimit: '100mb',
  },
/* eslint valid-jsdoc: "off" */

'use strict';

/**
 * @param {Egg.EggAppInfo} appInfo app info
 */
module.exports = appInfo => {
  /**
   * built-in config
   * @type {Egg.EggAppConfig}
   **/
  const config = exports = {};

  config.security = {
		csrf: {
      			enable: false,
      			ignoreJSON: true,
   		}
	}

  // use for cookie sign key, should change to your own and keep security
  config.keys = appInfo.name + '_1594950148528_599';

  // add your middleware config here
  config.middleware = [];

  // add your user config here
  const userConfig = {
    // myAppName: 'egg',
  };

  return {
    ...config,
    ...userConfig,
    bodyParser: {
      jsonLimit: '100mb',
      formLimit: '100mb',
  },
  };
};

这里附带后端服务器的node整个文件:
后端服务器代码

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LionelMartin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值