聊天机器人开发实战--(微信小程序+SpringCloud+Pytorch+Flask)【完整版】

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

文章目录

前言

没想到从五一之后到现在鸽了那么久。没办法实话实说确实忙五一期间就没怎么休息开局第一周准备IEEE国际会议报告第二周大创结题准备材料和最后的代码调试组合。上周还跑到武汉去培训备研大忌估计是被我踩了个遍。按照以前的传统在520前我是会做点啥好玩的东西用来表白啥的虽然我是真用不上。不过不过由于忙这个传统被打破了那么竟然如此也是时候迈向未来了。我们追求的始终是更高层次的精神会晤精神上的交流而不单单是生理上的刺激如果是那样洗脚脚未必不可。那么既然以前是写一点好玩的用程序去表达一种浪漫给喜欢的女孩子但是这个女孩子一直再出现对我来说。并且我们要求的是高级的会晤而非生物上的。通过现实生活当中的”概率论“以及救不了我了那么为什么不去试试“Artificial probability”。这一段开个玩笑引入一下不要当真方便我后面吹一下

详细后端部分见博文聊天机器人开发实战–微信小程序+SpringCloud+Pytorch+Flask【后端部分】
Now

聊天伴侣猫雨雫 震撼上线
在这里插入图片描述

打造您的贴身伴侣女朋友能24小时陪伴你吗不,她不能。男朋友可以嘛不也不行。
但是我们可以It all you need!!!

架构

好了牛皮吹完了我们来点正经的。
首先为什么要做这个项目呢肯定不是为了那啥实际上是为了做期末作孽。没办法谁那么无聊呢虽然我有时候这很符合我的风格。那么这里也说明一下那就是由于这个是期末作孽所以我不可能做得太复杂做的怎么怎么样。很简单的道理我们有能力做好但是做好的前提是她值得。如果值得那么我会尽我所能。否则明明100块就可以搞定我为什么要花200太亏了呀。

在这里插入图片描述

所以的话整个项目启动你会见到三个玩意。

小程序端

这个是个人中心
在这里插入图片描述

管理端

在这里插入图片描述

运维端

在这里插入图片描述

其他的就这样了。
这个结构非常简单。

交互

那么之后的话就是交互。后端的话基本上七七八八都说了一下都是挺简单的东西。

那么这边的话我们主要把注意力放在前端这边。还有到后端的交互。

聊天页面

首先最重要的当然就是聊天了。
聊天页面的话设计的非常简单也没有做什么特效懒得做。
就这个玩意
在这里插入图片描述
这里的话是封装为了一个组件当然这样也是原来找的一个然后改了一下。

<scroll-view class="cu-chat" scroll-y="true" enable-back-to-top enable-flex scroll-into-view="{{scrollId}}"
  style="height:{{systemInfo.windowHeight - 50}}px;" bindscrolltoupper="tapTop"
  >
  <view wx:for="{{chatList}}" wx:key="index" wx:for-item="item">
    <!--robot发送的信息-->
    <view class="cu-item" wx:if="{{item.type != 'man'}}" id="msg-{{index}}">
      <view class="cu-avatar radius" style="background-image:url({{item.avatarUrl}});"></view>
      <view class="main">
        <view class="content bg-cyan shadow">
          <text>{{item.content}}</text>
        </view>
      </view>
    </view>
    <!--自己发送的信息-->
    <view class="cu-item self" wx:if="{{item.type == 'man' }}" id="msg-{{index}}">
      <view class="main">
        <view class="content bg-green shadow">
          <text>{{item.content}}</text>
        </view>
      </view>
      <view class="cu-avatar radius" style="background-image:url({{item.avatarUrl}});"></view>
    </view>
  </view>
</scroll-view>

然后是对应的js

// release/components/chatbox
const app = getApp();
// 时间工具类
const timeutil = require('./timeutil');
const cx = Component({
  /**
   * 组件的一些选项
   */
  options: {
    addGlobalClass: true,
    multipleSlots: true
  },
  /**
   * 组件的属性列表
   */
  properties: {
    roomId: {
      type: Number,
      observer: function (newVal, oldVal) {
        if (newVal != undefined && newVal != null) {
          // console.log(newVal)
        }
      }
    }
  },
  /**
   * 组件注册页面生命周期
   */
  pageLifetimes: {
    show: function () {
      // 页面被展示
    },
  },
  lifetimes: {
    attached() {
      var that = this;
      that.initMessageHistory();
      //初始化监听器
      // that.initWatcher();
      wx.getSystemInfo({
        success: function (res) {
          that.setData({
            systemInfo: res
          })
        }
      })
    },
    detached() {
      try {
      } catch (error) {
        console.log('--消息监听器关闭失败--')
      }
    }
  },
  /**
   * 组件的初始数据
   */
  data: {
    openid: app.globalData.openid || wx.getStorageSync('openid'),
    scrollId: '',
    systemInfo: {},
    //消息记录列表
    chatList: [],
    //标记触顶事件
    isTop: false,
    cur_page: 2,
    limit: 10,
    pagesize: 0,
  },
  /**
   * 组件的方法列表
   */
  methods: {
    loadMsgs(wid,itemid){
      var that = this;
      var dataList = that.data.chatList;
      wx.request({
        method: 'POST',
        url: 'http://127.0.0.1:88/api/ikunchat/histories/msgs',
        header: {
          'content-type': 'application/json'
        },
        data: {
          wid: wid,
          itemid: itemid,
          page: that.data.cur_page,
          limit: that.data.limit
        },
        success(res) {
          // 处理响应数据
          let r_code = res.data.code
          if (r_code != 0) {
            wx.switchTab({
              url: "/pages/mycenter/mycenter"
            });
            wx.showToast({
              title: "请先登录",
              icon: 'error',
              duration: 2000
            })
          }else{
            let page = res.data.page
            that.setData({
              cur_page: that.data.cur_page+1
            })
            let list = page.list
            if(list.length==0){
              wx.showToast({
                title: "到顶了吖~",
                icon: 'error',
                duration: 2000
              })
            }
            for(var i=0;i<list.length;i++){
              dataList.unshift(list[i]);
            }
          }
        },
        fail(error) {
          // 处理请求失败情况
          wx.switchTab({
            url: "/pages/mycenter/mycenter"
          });
        },
      })
    },
    // 预览图片
    viewImage(e) {
      // console.log(e)
      let url = e.currentTarget.dataset.url;
      wx.previewImage({
        urls: [url],
      })
    },
    //触顶事件
    tapTop() {
      console.log('--触顶--')
      var that = this;
      that.setData({
        isTop: true
      }, () => {
        let current_itemid = app.globalData.curr_itemid
        let wid = app.globalData.wid
        that.loadMsgs(wid,current_itemid)
      })
    },
    //初始化
    initMessageHistory() {
      let is_new_chat = app.globalData.is_new_chat
      if(is_new_chat){
        //初始化消息历史
        var that = this;
        app.globalData.cht = that
        that.setData({
          chatList: [
            {
              "type":"robot",
              "avatarUrl":"../index/image/yu.png",
              "content":"你好我是 羽雫是由Huterox研发的智能虚拟女友很高兴认识你~(测试阶段会话自动保存)",
            }
          ]
        })
      }else{
        var that = this;
        let current_itemid = app.globalData.curr_itemid
        let wid = app.globalData.wid
        that.loadMsgs(wid,current_itemid)
      }
    },
  }
})

基本样式的话没有因为就是堆上去的而且作为一个组件。

聊天发送流程

那么之后就是这个流程这个玩意的话比较简单。
在这里插入图片描述
然后这里的话用户的验证啥的做的都很简单直接用wid,感兴趣的自己可以去优化也非常简单这个就作为base beta 作孽版本搞了。

然后就是基本的后端处理逻辑。这个就没啥好说的了还是比较简单的。

历史聊天记录

然后就是这个玩意
在这里插入图片描述


这个玩意的前端代码比较简单无非就是请求数据啥的。
然后比较主要的是后端的一个交互。
这里的话有两个玩意
在这里插入图片描述
也就是这两个
在这里插入图片描述

个人中心

个人中心的话其实就两个一个是注册登录还有一个是查看当前剩余次数。当时是想要做全套再来个支付接口的。但是后来没时间砍掉了。
在这里插入图片描述
这个是相应的前端代码实现

<view class="top-bg"></view>
<view class="box">
  <!-- 头像 -->
  <view class="head-box">
    <button open-type="chooseAvatar" class="avatar" bindchooseavatar="chooseAvatar">
      <image class="head-img" src="{{login.avatar}}" mode="widthFix"></image>
    </button>
    <view class="tip">{{login.show?'欢迎使用':'当前未登录请登录'}}</view>
  </view>
  <!-- 第一部分列表 -->
  <view>
    <button class="row" style="width: 100%;" bindtap="basicClick">
      <view class="left">
        <icon class="icon-small" type="success" size="16"></icon>
        <text class="text">今日限额</text>
      </view>
      <view class="right"></view>
    </button>
    <button class="row" style="width: 100%;" bindtap="feedbackClick">
      <view class="left">
        <icon class="icon-small" type="success" size="16"></icon>
        <text class="text">FeedBack</text>
      </view>
      <view class="right"></view>
    </button>
    <button class="row" style="width: 100%;border-bottom: none;" bindtap="aboutClick">
      <view class="left">
        <icon class="icon-small" type="success" size="16"></icon>
        <text class="text">关于我们</text>
      </view>
      <view class="right"></view>
    </button>
  </view>
</view>
<!-- 第二部分列表 -->
<view class="end">
  <button open-type="share" class="row" style="width: 100%;">
    <view class="left">
      <icon class="icon-small" type="success" size="16"></icon>
      <text class="text">分享好友</text>
    </view>
    <view class="right"></view>
  </button>
</view>
<!-- 第三部分列表 -->
<view class="end">
  <button wx:if="{{login.line}}" bindtap="exitClick" class="row" style="width: 100%;border-bottom: none;">
    <view class="left">
      <icon class="icon-small" type="success" size="16"></icon>
      <text class="text">退出登录</text>
    </view>
  </button>
  <button class="row" open-type="chooseAvatar" bindchooseavatar="chooseAvatar" style="width: 100%;border-bottom: none;" wx:else>
    <view class="left">
      <icon class="icon-small" type="success" size="16"></icon>
      <text class="text">立即登录</text>
    </view>
  </button>
</view>
<view class="footer">
  <text>©Huterox is awesome!</text>
</view>

然后是js

const app = getApp();
Page({
  /**
   * 页面的初始数据
   */
  data: {
    login: {
      show: false,
      avatar: 'https://img0.baidu.com/it/u=3204281136,1911957924&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',
    },
    count: 10,
    wid: 0,
  },
  // 登录监听
  chooseAvatar(e) {
    console.log(e.detail.avatarUrl)
    var that = this;
    //请求后端服务器完成登录
    this.setData({
      login: {
        show: true,
        avatar: "../index/image/me.png",
      }
    })
    wx.request({
      method: 'POST',
      url: 'http://127.0.0.1:88/api/ikunchat/wcenter/login',
      header: {
        'content-type': 'application/json'
      },
      data: {
        wid: app.globalData.wid
      },
      success(res) {
        // 处理响应数据
        let r_code = res.data.code
        if(r_code==0){
          that.setData({
            login: {
              show: true,
              avatar: "../index/image/me.png",
            }
          })
          app.globalData.islogin = res.data.itemid
        }else{
          wx.showToast({
            title: res.data.msg,
            icon: 'error',
            duration: 2000
          })
        }
      },
      fail(error) {
        // 处理请求失败情况
        wx.showToast({
          title: error,
          icon: 'error',
          duration: 2000
        })
      }
    })
  },
  // 基本信息
  basicClick() {

    console.log(app.globalData.wid)
    var that = this;
    wx.request({
      method: 'POST',
      url: 'http://127.0.0.1:88/api/ikunchat/wcenter/count',
      header: {
        'content-type': 'application/json'
      },
      data: {
        wid: app.globalData.wid
      },
      success(res) {
        // 处理响应数据
        let r_code = res.data.code
        if(r_code==0){
          that.setData({
            count: res.data.msg
          })
          console.log(that.data.count)
          //显示
          wx.showModal({
            title: 'Hello ~',
            content: '剩余次数:' + that.data.count,
            success(res) {
              if (res.confirm) {
                console.log('用户点击了确定按钮')
              } else if (res.cancel) {
                console.log('用户点击了取消按钮')
              }
            }
          })
        }else{
          wx.showToast({
            title: res.data.msg,
            icon: 'error',
            duration: 2000
          })
        }
      },
      fail(error) {
        // 处理请求失败情况
        wx.showToast({
          title: error,
          icon: 'error',
          duration: 2000
        })
      }
    })
    console.log('基本信息监听');
  },
  // 匿名反馈
  feedbackClick() {
    wx.showModal({
      title: 'Huterox',
      content: '有问题随时email:3139541502@qq.com',
      success(res) {
        if (res.confirm) {
          console.log('用户点击了确定按钮')
        } else if (res.cancel) {
          console.log('用户点击了取消按钮')
        }
      }
    })
    console.log('匿名反馈监听');
  },
  // 关于我们
  aboutClick() {
    wx.showModal({
      title: 'Huterox',
      content: '嘿我是一个练习时长一kun年的代码练习生',
      success(res) {
        if (res.confirm) {
          console.log('用户点击了确定按钮')
        } else if (res.cancel) {
          console.log('用户点击了取消按钮')
        }
      }
    })
    console.log('关于我们监听');
  },
  // 退出监听
  exitClick() {
    let that = this;
    wx.showModal({
      title: '提示',
      content: '确定退出登录吗',
      success(res) {
        if (res.confirm) {
          that.setData({
            login: {
              show: false,
              avatar: 'https://img0.baidu.com/it/u=3204281136,1911957924&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',
            }
          })
        }
      }
    })
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {
    var app = getApp(); // 获取 App 实例
    if (app.globalData.islogin){
      this.setData({
        login: {
          show: true,
          avatar: "../index/image/me.png",
        }
      })
      //获取剩余次数
      var that = this;
      wx.request({
        method: 'POST',
        url: 'http://127.0.0.1:88/api/ikunchat/wcenter/count',
        header: {
          'content-type': 'application/json'
        },
        data: {
          wid: app.globalData.wid
        },
        success(res) {
          // 处理响应数据
          let r_code = res.data.code
          if(r_code==0){
            that.setData({
              count: res.data.msg
            })
          }else{
            wx.showToast({
              title: res.data.msg,
              icon: 'error',
              duration: 2000
            })
          }
        },
        fail(error) {
          // 处理请求失败情况
          wx.showToast({
            title: error,
            icon: 'error',
            duration: 2000
          })
        }
      })
    }
  },

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

  },

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

  },

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

  },

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

  },

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

  },

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

  },

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

  }
})

之后的话是css

page {
  background-color: #f1f1f1;
}

/* 设置背景颜色 */
.top-bg {
  height: 260rpx;
  background-color: #a0cfff;
}

/* 圆角盒子 */
.box {
  background-color: white;
  margin-top: -120rpx;
  border-top-left-radius: 50rpx;
  border-top-right-radius: 50rpx;
  padding: 0 20rpx;
}

/* 头像部分 */
.head-box {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  border-bottom: 1rpx solid #fbdbdc;
  padding-bottom: 20rpx;
}

.avatar {
  margin-top: -80rpx;
  font-weight: inherit;
  display: flex;
  justify-content: center;
  background-color: rgba(0, 0, 0, 0);
}

.avatar::after {
  border: none;
}

.head-img {
  width: 140rpx;
  height: 140rpx;
  overflow: hidden;
  border-radius: 50%;
  background-color: #fbdbdc;
}

.tip {
  font-size: 26rpx;
  color: gray;
  margin: 15rpx 0;
}

/* 列表部分 */
.row {
  display: flex;
  align-items: center;
  padding: 36rpx 10rpx;
  font-size: 30rpx;
  font-weight: inherit;
  background-color: rgba(0, 0, 0, 0);
  border-bottom: 1rpx solid #fbdbdc;
}

.row::after {
  border: none;
}

.text {
  margin-left: 15rpx;
  color: #636262;
}

.left {
  width: 90%;
  text-align: left;
  display: flex;
  align-items: center;
}

.right {
  width: 10%;
  text-align: right;
  color: rgb(148, 147, 147);
}

.end {
  background-color: white;
  margin-top: 20rpx;
  padding: 0 20rpx;
}

.footer {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 20rpx 0;
  font-size: 22rpx;
  margin: 30rpx 0;
  color: gray;
}

后端对应的就是这两个玩意
在这里插入图片描述

总结

那么以上就是全部内容了想要源码的话评论区留言的同时一键三联~ 谢谢

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: Spring