2021级山软项目实训(八)——问答系统前后端交互

目录

一、前端编写

二、与后端连接

三、布局调整


一、前端编写

        我的队友在服务器上部署了大模型,并进行了微调。现在需要做的事我把前端写好和她编写的后端代码进行交互,把用户在小程序内输入文字信息和上传的图像传递到服务器,然后喂给大模型,得到大模型的返回结果后再将结果返回前端显示给用户。

        需要往后端传递的信息有 文本 和 图像。上一篇博客写到了我们的图像上传之后暂存在前端,然后我们需要把前端输入的文字信息也暂存前端,通过发送按钮一键发送。

        结构的代码如下:

<!--下方的输入框-->
<view class="input" style="{{'bottom:'+KeyboardHeight+'px; position: fixed;'}}">
  <!--上传图片的内容-->
  <view class="input-picture" bind:tap="open_camera">
    <image src="/images/dialogue/camera.png"></image>
  </view>
  <!--语音识别-->
  <view class='input-voice' bind:longpress="startRecord" bind:touchend="stopRecord">
    <image src="/images/dialogue/voice.png"></image>
  </view>
  <!--输入条-->
  <scroll-view class="input-textarea">
    <textarea placeholder="请输入内容" auto-height bindinput="bindInput" value="{{msg}}"></textarea>
  </scroll-view>
  <!--发送按钮-->
  <button class="input-button" bind:tap="sendMsg">发送</button>
</view>

        我们通过bindinput这个函数将输入框的内容传递给msg。

        当我们点击button的时候,会执行四个事:

        一是把图片、文字封装上flag和type(分别代表是用户或ai发送的信息和是否含有图像信息)暂存到前端,并显示在上方的对话框中。

        二是将图像信息和文字信息传递到后端,喂给大模型。

        三是把大模型的信息返回到前端。

        四是对大模型的信息进行封装然后显示在上方的对话框上。

        这一部分只讲第一件事儿,下一部分详细将后三部分。

        封装上传的代码如下所示:

  console.log(this.data.tempImagePath)
    if(this.data.msg.length==0){ //如果啥也没写
      Notify({ type: 'success', message: '输入内容不能为空' });
    }else{  //有有效信息
      if(this.data.tempImagePath.length > 0 ) {
        // 如果有图片
        this.data.dialogue.push({"flag": 1, "type": "0", "content": this.data.msg, "url": this.data.tempImagePath})
      }
      else {
        this.data.dialogue.push({"flag": 1, "type":"1", "content": this.data.msg})
      }

        这里会判断文字信息是否为空,和是否有图像存在,以便进行封装。

        如果没有文字信息,会报错。

二、与后端连接

        我们需要信息传递给后端。通过Process函数将文本信息和图像信息传递给后端。

        我们的函数会判断是否含有图像信息,然后通过两种传递方式与后端进行交互。

        数据传递到后端后,喂给大模型后返回信息,我们会把它显示到对话框中。

        代码如下所示:

/*与后端大模型进行交互*/
Process: function() {
  const _this = this;

  // 检查数据有效性
  if (!this.data.msg && !this.data.tempImagePath) {
    console.log("Invalid data");
    return;
  }

  if (this.data.tempImagePath) {
    // 如果有图片,使用 wx.uploadFile
    console.log("Uploading file from path:", this.data.tempImagePath[0]); // 打印文件路径

    wx.uploadFile({
      url: 'https://www.aiguider666.asia/process', // 后端服务器地址
      filePath: this.data.tempImagePath[0], // 确保这是一个字符串
      name: 'image', // 与后端字段名一致
      formData: {
        text: this.data.msg,
        temperature: '0.8',
        top_p: '0.4'
      },
      success: (res) => {
        try {
          const data = JSON.parse(res.data); // 确保解析响应数据
          if (data.result != '') {
            _this.setData({
              dialogue: _this.data.dialogue.concat({"flag": 0, "type": "1", "content": data.result })
            });
            var len = this.data.dialogue.length //遍历的数组的长度
            this.setData({
              dialogue: this.data.dialogue,
              scroll_top: 1000 * len,
            })
          } else {
            console.log("Error", data);
          }
        } catch (e) {
          console.log("Response parse error", e);
        }
      },
      fail: (err) => {
        console.log("Internet error", err);
      }
    });
  } else {
    // 如果没有图片,使用 wx.request
    wx.request({
      url: 'https://www.aiguider666.asia/qanda', // 后端服务器地址
      method: 'POST',
      data: {
        user_id: this.data.user,
        text: this.data.msg,
        temperature: '0.8',
        top_p: '0.4'
      },
      header: {
        'Content-Type': 'application/x-www-form-urlencoded' // 确保发送正确的内容类型
      },
      success: (res) => {
        if (res.data.result != '') {
          _this.setData({
            dialogue: _this.data.dialogue.concat({"flag": 0, "type": "1", "content": res.data.result })
          });
    var len = this.data.dialogue.length //遍历的数组的长度
      this.setData({
        dialogue: this.data.dialogue,
        scroll_top: 1000 * len,
        msg:""
      })
        } else {
          console.log("Error", res.data);
        }
      },
      fail: (err) => {
        console.log("Internet error", err);
      }
    });
  }
},

三、布局调整

        我们在每次对话更新后,对将对话内容滚动到最下方。采取的方式是读取数组长度,然后乘以一个大的数,让其显示保持在最下方。

        此外每次输入结束后,我们会清空输入框中的文字和上传的图像,以便进行下一次输入和上传。

        代码如下:

      this.setData({
        tempImagePath: "",
        isImage: 0,
      })
      
      var len = this.data.dialogue.length //遍历的数组的长度
      this.setData({
        dialogue: this.data.dialogue,
        scroll_top: 1000 * len,
        msg:""
      })
    }

        此外,我们发现,真机调试的时候,由于键盘的升起,会挡住我们下方的输入条,因此我们读取键盘的长度,然后将输入框的position设置成fixed,然后计算计算其应该在的位置。

        父组件代码如下:

<view class="input" style="{{'bottom:'+KeyboardHeight+'px; position: fixed;'}}">
  • 8
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值