微信小程序——实现对话模式(调用大模型图片生成)

这篇具有很好参考价值的文章主要介绍了微信小程序——实现对话模式(调用大模型图片生成)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


微信小程序——实现对话模式(调用大模型图片生成),web站点,微信小程序,AIGC

⭐前言

大家好,我是yma16,本文分享微信小程序——实现对话模式(调用大模型图片生成)。

aigc图片生成
AIGC (Artificial Intelligence Generated Content) 可以生成各种类型的图片,包括风景、动物、人物、抽象等等。生成图片的过程通常是使用预训练的神经网络模型,该模型可以根据输入的文本或图像生成新的图片。

⭐ 后端接口封装

💖 使用axios调用api

koa封装axios请求

const axios = require('axios')


const axiosInstance = (baseURL, headers) => {
    const instance = axios.create({
        baseURL: baseURL,
        timeout: 20000,
        headers: {...headers }
    });

    return instance
}

const postAction = (baseURL, path, headers, data) => {
    const http = axiosInstance(baseURL, headers)
    return http.post(path, data)
}



module.exports = {
    postAction
}

💖 暴露koa接口

这里我调用的时掘金的bot-api

const Router = require('koa-router');
const router = new Router();
const { postAction } = require('../../utils/request/index');

const API_KEY = '你的apikey'
const bot_id = '你的bot_id'

// 和bot聊天
router.post('/chat/bot', async(ctx) => {
    try {
        const bodyParams = ctx.request.body
        const { user, query } = bodyParams
        console.log('bodyParams', bodyParams)

        const headers = {
            "Authorization": `Bearer ${API_KEY}`,
            "Content-Type": "application/json",
            "Host": 'api.coze.cn',
            "Connection": "keep-alive"
        }

        const data = {
            "bot_id": bot_id,
            "user": user,
            "query": query,
        }

        const baseUrl = "https://api.coze.cn"
        const path = '/open_api/v2/chat'


        const res = await postAction(baseUrl, path, headers, data)
        ctx.body = {
            code: res.status,
            data: res.data,
            msg: res.statusText
        };
    } catch (r) {
        ctx.body = {
            code: 0,
            msg: r
        }
    }
});

module.exports = router;

⭐ 前端的交互设计

💖 布局设计

界面布局设计(一对一的对话模式)

<view class="container-box">

  <view class="chat-container" id="chat-container-id" style="width: 100%;">
    <scroll-view scroll-y="true" class="scroll-answer" scroll-with-animation bindscrolltoupper="upper" bindscrolltolower="lower" bindscroll="scroll" scroll-into-view="{{toView}}" scroll-top="{{scrollTop}}" wx:if="{{ chatObjConfig.option&&chatObjConfig.option.length>0 }}">
      <view wx:for="{{ chatObjConfig.option }}" wx:for-index="index" wx:for-item="item" wx:key="index" id="chat-mode{{index}}">
        <view class="create-time">
          {{item.createTime}}
        </view>
        <view class="form-request">
          <view wx:if="{{!item.isEdit}}" class='questioned'>
            <view style="display: flex;text-align: right;flex-direction:row-reverse;">
              <view class="questioned-box-container">
                <view class='questioned-box' style="text-align: left;">
                  {{item.question}}
                </view>
                <view class='questioned-box-poly'>
                </view>
                <view style="text-align: right;line-height: 50px;display: flex;max-height: 50px;">
                  <view class='form-request-user'>
                    <!-- {{currentUserInfo.nickName}} -->
                    <image class="user-image" src="{{currentUserInfo.avatarUrl}}"></image>
                  </view>
                </view>
              </view>
            </view>
          </view>
        </view>
        <view class="form-response" wx:if="{{!item.isEdit}}">
          <view style="display: flex;">
            <view style="line-height: 50px;">
              <view class='form-response-user'>
                <image class="ai-image" src="{{aiConfig.avatarUrl}}"></image>
                <!-- {{aiConfig.nickName}} -->
              </view>

            </view>
            <view class="form-response-box-poly">
            </view>
            <view class='form-response-box' style="overflow: auto;">
              <towxml wx:key="index" nodes="{{item.answerMarkdown}}" style="position: relative;background: transparent;user-select: text;" />
            </view>

          </view>
          <view style="display: flex;width: 100%;box-sizing: border-box;" wx:if="{{layoutConfig.isShowCopyBtn}}">
            <view style="width: 70%;">
            </view>
            <view style="width: 30%;text-align: center;">
              <button class="copy-btn" size="mini" bindtap="copyBtn" data-response=" {{item.answer}}">{{layoutConfig.copyText}}</button>
            </view>
          </view>
        </view>
      </view>

      <view class="form-submit" wx:if="{{mode==='openAiUse'}}" style="width: 100%;">
      </view>
    </scroll-view>
    <view wx:else class="scroll-answer">
      <view class="create-time">
        {{currenTime}}
      </view>
      <view style="display: flex;">
        <view style="line-height: 50px;">
          <view class='form-response-user'>
            <image class="ai-image" src="{{aiConfig.avatarUrl}}"></image>
            <!-- {{aiConfig.nickName}} -->
          </view>
        </view>
        <view class="form-response-box-poly">
        </view>
        <view class="form-response-box" style="padding: 0 10px;">
          {{layoutConfig.emptyText}}
        </view>
      </view>
    </view>

    <view class="bottom-box">
      <view class='submit-input'>
        <textarea class='send-input' bindinput="bindKeyInput" placeholder="{{layoutConfig.searchText}}" bindconfirm="search" value="{{searchOpenAiText}}" disabled="{{isLoading||isTruth}}" />
      </view>
      <view class='send-btn' type="primary" bindtap="search" loading="{{isLoading}}" disabled="{{isLoading}}">{{layoutConfig.sendText}}</view>
    </view>

  </view>


</view>

样式设置

/* pages/aiBot/aiBot.wxss */

.container-box{
  position: relative;
  width: 100vw;
  height: 100vh;
  background: rgb(245, 245, 245);
  overflow: hidden;
  box-sizing: border-box;
}

.container-box-article {
  position: relative;
  padding-top:0px;
  width: 100%;
  height: calc(100vh - 88px);
  box-shadow: inset 5px 5px #262626;
  overflow: auto;
  user-select: text;
}

.scroll-answer {
  height: calc(100vh - 100px);
}

.chat-container {
  width: 100%;
  height: 100vh;
  overflow-y: auto;
  overflow-x: hidden;
  position: relative;
}

.paste-btn {
  background: rgba(16, 116, 187);
  color: #ffffff;
  /* transform: scale(.7); */
  border-radius: 5px;
}

.clear-btn {
  background: rgba(16, 116, 187);
  color: #ffffff;
  /* transform: scale(.7); */
  border-radius: 5px;
}

.paste-btn:hover {
  border: none;
  background: rgb(221, 0, 66);
}

.user-image-box {
  width: 300px;
  text-align: center;
  align-items: center;
}

.user-image {
  position: relative;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background-color: transparent;
  background: transparent;
}

.ai-image {
  position: relative;
  width: 20px;
  height: 20px;
  border-radius: 50%;
}

.questioned-box-container {
  display: flex;
}

.questioned-box {
  position: relative;
  max-width: calc(100vw - 90px);
  height: auto;
  overflow-x: auto;
  background-color: rgb(255, 255, 255);
  border-radius: 10px;
  right: -5px;
  padding: 0 10px;
  z-index: 999;
  color: #333;
  font-family: PingFang SC, Lantinghei SC, Microsoft Yahei, Hiragino Sans GB, Microsoft Sans Serif, WenQuanYi Micro Hei, sans-serif;
  font-weight: 300;
  font-size: 32rpx;
  user-select: text;
  box-shadow: -5rpx 3rpx 1rpx -4rpx #c8c3c3;
}

.questioned-box-poly {
  position: relative;
  top: 15px;
  width: 0;
  height: 0;
  border-radius: 5px;
  border-top: 10px solid transparent;
  border-bottom: 10px solid transparent;
  border-left: 12px solid rgb(255, 255, 255);
  box-shadow: 0rpx 0rpx 0rpx 0rpx #c8c3c3;
}
.clear-paste-btn{
  width:70%;
  display: flex;
}
.submit-input {
  box-shadow: 0 2rpx 5rpx 5rpx #c8c3c3;
  width: 70%;
}

.send-input {
  height: 60px;
  background: rgba(255, 255, 255, .8);
  width: 100%;
  height: 100px;
  position: relative;
  text-indent: 8px;
  /* padding-left: 5px; */
  color: rgb(0, 114, 221);
}
.send-btn::after{
  position: absolute;
  left:0;
  top:0;
  width: 100px;
  height: 100%;
  background-color:  rgba(255, 255, 255, .8);
}

.up-down-btn{
  width:30%;
}

.send-btn {
  box-shadow: 0 2rpx 5rpx 5rpx #c8c3c3;
  width: 30%;
  background-color:rgba(16, 116, 187);
  color: #ffffff;
  height: 100px;
  line-height: 100px;
  /* border-radius: 10px 0 0 10px; */
  text-align: center;
}

.empty-reponse-msg {
  position: relative;
  max-width: calc(100vw - 90px);
  height: auto;
  overflow-x: auto;
  background-color: rgb(255, 255, 255);
  border-radius: 10px;
  left: -5px;
  padding: 0 10px;
  z-index: 999;
  color: #333;
  font-family: PingFang SC, Lantinghei SC, Microsoft Yahei, Hiragino Sans GB, Microsoft Sans Serif, WenQuanYi Micro Hei, sans-serif;
  font-weight: 300;
  font-size: 32rpx;
  user-select: text;
}

.create-time {
  width: 100%;
  text-align: center;
  color: rgb(255, 255, 255);
  background: rgb(218, 218, 218);
  margin: 5px auto;
  box-shadow: inset 0 1rpx 2rpx 1rpx rgba(0, 0, 0, 0.2);
}

.form-response-user {
  background-color: rgba(0, 72, 94, 0);
  color: #fff;
}

.form-response-box-poly {
  position: relative;
  top: 15px;
  width: 0;
  height: 0;
  border-radius: 5px;
  border-top: 10px solid transparent;
  border-bottom: 10px solid transparent;
  border-right: 12px solid rgb(255, 255, 255);
}

.form-response-box {
  position: relative;
  max-width: calc(100vw - 50px);
  /* word-break:keep-all; */
  /* white-space: pre-wrap; */
  white-space: pre-line;
  height: auto;
  overflow-x: auto;
  background-color: rgb(255, 255, 255);
  border-radius: 10px;
  color: #333;
  font-family: PingFang SC, Lantinghei SC, Microsoft Yahei, Hiragino Sans GB, Microsoft Sans Serif, WenQuanYi Micro Hei, sans-serif;
  font-weight: 300;
  font-size: 32rpx;
  left: -5px;
  box-sizing: content-box;
  z-index: 999;
  user-select: text;
  box-shadow: 5rpx 3rpx 1rpx -4rpx #c8c3c3;
}



.form-request {
  display: block;
  width: 100%;
  color: #fff;
  background-color: rgba(37, 0, 97, 0);
  line-height: 50px;
}

.form-response {
  position: relative;
  width: 100%;
  margin-top: 10px;
  display: block;
  margin-bottom: 10px;
  color: #fff;
  background-color: rgba(0, 72, 94, 0);
  box-sizing: border-box;
  min-height: 60px;
}

.form-response-user {
  background-color: rgba(0, 72, 94, 0);
  color: #fff;
}

.form-request-user {
  background-color: rgba(37, 0, 97, 0);
  color: #fff;
}



.bottom-box {
  display: flex;
  width: 100%;
  display: absolute;
  bottom: 100px;
}

引入markdown

{
  "usingComponents": {
    "towxml":"/towxml/towxml"
  }
}

💖 页面逻辑

page逻辑

// pages/aiBot/aiBot.js

const app = getApp();
Page({

  /**
   * 页面的初始数据
   */
  data: {
    currentUserInfo: {
      nickName: '',
      avatarUrl: 'https://profile-avatar.csdnimg.cn/8bea3d4b0c56486691de8f54fb649fa4_qq_38870145.jpg!1',
    },
    saveKey: 'aiBot',
    baseCloudUrl: app.remoteConfig.baseCloudUrl,
    password: "***",
    username: "***",
    token: '',
    currenTime: '',
    isLoading: false,
    searchOpenAiText: '画一只猫',
    chatObjConfig: {
      option: [
        //   {
        //   question: '',
        //   answer: '',
        //   isEdit: true,
        //   createTime: ''
        // }
      ],
      currentIndex: 0,
      errorMsg: 'openai的服务器异常!'
    },
    layoutConfig: {
      showPasteBtn: false,
      showTopBtn: false,
      introduceText: 'api介绍',
      useText: '使用',
      returnText: '返回介绍',
      sendText: '发送',
      searchText: '请输入关键词进行对话',
      reportText: '复制数据',
      copyText: '复制',
      pasteText: '粘贴',
      upText: "↑",
      downText: "↓",
      errorMsg: 'bot ai服务器异常!',
      emptyText: '欢迎使用aibot',
      storageKey: 'openAiOptionsConfig',
      permissionTitle: '很抱歉您没有权限!',
      permissionContent: '请联系微信号:cse-yma16\r\n 需要1元开通权限\r\n1元可支持100条消息!',
      wxInfoImg: 'https://yongma16.xyz/staticFile/common/img/userInfo.png',
      limitMsgCount: 10,
      confirmText: '添加微信',
      cancelText: '返回'
    },
    aiConfig: {
      avatarUrl: 'https://yongma16.xyz/staticFile/common/img/aiTop.jpg',
      bgUrl: 'https://yongma16.xyz/staticFile/common/img/aiBg.jpg',
      nickName: 'openai',
    },
  },
  getUserToken() {
    const that = this
    wx.showLoading({
      title: 'gen token loading',
    });
    wx.request({
      url: this.data.baseCloudUrl + 'token/gen',
      method: 'POST',
      data: {
        username: this.data.username,
        password: this.data.password
      },
      success: (res => {
        that.setData({
          token: res.data.token
        })
        wx.hideLoading()
      }),
      fail: r => {
        console.log('cloud r', r)
        wx.hideLoading()
      }
    })
  },
  getCurrentTime() {
    const now = new Date()
    const year = now.getFullYear()
    const month = now.getMonth()
    const date = now.getDate()
    const hour = now.getHours()
    const minutes = now.getMinutes()
    const second = now.getSeconds()
    const formatNum = (n) => {
      return n > 9 ? n.toString() : '0' + n
    }
    return `${year}-${formatNum(month + 1)}-${formatNum(date)} ${formatNum(hour)}:${formatNum(minutes)}:${formatNum(second)}`
  },
  bindKeyInput(e) {
    console.log('e.detail.value', e.detail.value)
    this.setData({
      searchOpenAiText: e.detail.value
    })
  },
  scrollToBottom() {
    const index = this.data.chatObjConfig.option.length - 1
    this.setData({
      toView: `chat-mode${index}`
    })
  },

  saveStore() {

  },

  search(e) {
    this.scrollToBottom()
    if (this.data.isLoading) {
      wx.showModal({
        cancelColor: 'cancelColor',
        title: '正在响应中,请稍等...'
      })
      return
    }
    if (!this.data.searchOpenAiText) {
      wx.showModal({
        cancelColor: 'cancelColor',
        title: '请输入!'
      })
      return
    }
    wx.showLoading({
      title: '加载中',
    })
    this.setData({
      isLoading: true
    })
    const that = this

    return new Promise((resolve, reject) => {
      wx.request({
        url: that.data.baseCloudUrl + '/chat/bot',
        method: 'POST',
        header: {
          Authorization: `bearer ${that.data.token}`
        },
        data: {
          user: 'qwerqwre',
          query: that.data.searchOpenAiText
        },
        success: (res) => {
          console.log(res, 'res')
          const data = res.data.data
          const option = that.data.chatObjConfig.option
          console.log('data', data)
          const choices = data.messages?.[2]
          const answer = choices?.content || that.data.layoutConfig.errorMsg
          option.push({
            question: that.data.searchOpenAiText,
            answer: answer,
            answerMarkdown: app.changeMrkdownText(answer),
            createTime: that.getCurrentTime(),
            isEdit: false,
          })
          const chatObjConfig = {
            option: option
          }

          that.setData({
            isLoading: false,
            searchOpenAiText: '',
            chatObjConfig: chatObjConfig
          })
          wx.hideLoading()
          that.scrollToBottom()
          resolve(res)
          console.log('that.data.chatObjConfig.option', that.data.chatObjConfig.option)
          that.saveStore()
        },
        fail: error => {
          
          that.setData({
            isLoading: false
          })
          wx.hideLoading()
          wx.showModal({
            cancelColor: 'cancelColor',
            title: '网络波动失败...'
          })
        }
      });
    })
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {
    const aiBotConfig = app.wxProgramConfig.aiBotConfig
    console.log('aiBotConfig', aiBotConfig)
    this.setData({
      saveKey: aiBotConfig.saveKey,
      searchOpenAiText: aiBotConfig.searchOpenAiText,
      password: aiBotConfig.cloudPwd || "U2FsdGVkX1+jfEkF2OXTQ5iIG4mrYc5/TLOiIntyENU=",
      username: aiBotConfig.cloudEmail || "1575057249@qq.com",
    })


    this.getUserToken()
    this.setData({
      currenTime: this.getCurrentTime()
    })

    const currentUserInfo = wx.getStorageSync('currentUserInfo')
    if (currentUserInfo && currentUserInfo.nickName) {
      console.log('currentUserInfo', currentUserInfo)
      this.setData({
        currentUserInfo: currentUserInfo
      })
    }

    // 缓存
    const chatObjConfig = wx.getStorageSync(this.data.saveKey)

    if (chatObjConfig) {
      this.setData({
        chatObjConfig: chatObjConfig,
      })
    }

  },

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

  },

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

  },

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

  },

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

    if (this.data.chatObjConfig) {
      wx.setStorageSync(app.wxProgramConfig.aiBotConfig.saveKey, this.data.chatObjConfig)
    }
  },

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

  },

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

  },

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

  }
})

⭐ 效果

生成的图片
微信小程序——实现对话模式(调用大模型图片生成),web站点,微信小程序,AIGC
微信小程序——实现对话模式(调用大模型图片生成),web站点,微信小程序,AIGC
微信小程序——实现对话模式(调用大模型图片生成),web站点,微信小程序,AIGC
提示词:在摸鱼的猫
微信小程序——实现对话模式(调用大模型图片生成),web站点,微信小程序,AIGC

⭐结束

本文分享到这结束,如有错误或者不足之处欢迎指出!

微信小程序——实现对话模式(调用大模型图片生成),web站点,微信小程序,AIGC

👍 点赞,是我创作的动力!
⭐️ 收藏,是我努力的方向!
✏️ 评论,是我进步的财富!
💖 最后,感谢你的阅读!文章来源地址https://www.toymoban.com/news/detail-845847.html

到了这里,关于微信小程序——实现对话模式(调用大模型图片生成)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 微信小程序实现分享里调用接口

    在开发微信小程序的时候,有一个需求,在点击分享按钮的时候,调用后台的接口,来获取一个分享的值,在分享的时候在分享链接里拼这个值。 初始的想法 在onShareAppMessage里使用promise 在这里去请求接口,但随后就遇到了问题,在用户未登录的情况下点击分享按钮,会跳转

    2024年02月11日
    浏览(41)
  • 微信小程序实现图片多点裁剪

    话不多说,直接上代码 1、页面布局 2、页面样式 3、页面逻辑

    2024年02月13日
    浏览(48)
  • 微信小程序(二)微信小程序选择本地图片显示并预览(实现左右滑动)

    在微信小程序里面实现选择图片然后预览是一个非常普遍的功能,在我们上传图片文件的时候,都会选择本地的图片进行上传,在上传之前会查看一下自己上传的图片是否准确。所以要做到预览图片。 下面就实现一个简单的本地图片显示预览的功能~~ 1、创建页面 这里我直接

    2024年02月03日
    浏览(76)
  • 微信小程序图片裁剪功能的实现

    在之前的博文中,已经介绍了如何使用在前端开发中,实现较方便自由的图片裁剪功能,可见博文: 如何一步步实现图片裁剪功能。 本文将进一步讲述在微信小程序中,我们实现图片裁剪功能需要如何处理,文章末尾将附上小程序端图片裁剪完整源码的下载链接。 在小程序

    2023年04月15日
    浏览(45)
  • 微信小程序实现一键保存多张图片

    实现功能:点击‘保存图片’可以将商品的所有图片以及商品的海报图片保存到相册中 由于downloadFile一次只能下载一张图片,因此需要依次遍历图片数组,将图片逐一保存

    2024年02月07日
    浏览(53)
  • 微信小程序实现图片上传(清晰版)

    在wxml文件中添加一个按钮和一个image标签用于显示上传的图片 在js文件中添加选择图片和上传图片的方法

    2023年04月16日
    浏览(96)
  • Java调用ChatGPT的API接口实现对话与图片生成

    有些魔法是需要做配置的。否则无法正确实现代码测试。这里以我使用的工具为例说明。 在pom.xml文件中添加: Constants类中,声明自己的API Key 其中,查看API Key的位置: https://platform.openai.com/account/api-keys 余额查询: https://platform.openai.com/account/usage pom.xml文件中需要增加依赖:

    2024年02月07日
    浏览(54)
  • 微信小程序 — 图片实现缩放,拖拽功能

    movable-view 可移动的视图容器,在页面中可以拖拽滑动。 movable-view必须在 movable-area 组件中,并且必须是直接子节点,否则不能移动。 如果想让图片实现缩放,拖拽效果。则可以把图片放到movable-view容器里面 。 movable-view 可移动的视图容器,在页面中可以拖拽滑动。 效果如下

    2024年02月13日
    浏览(93)
  • 微信小程序实现左边图片右边文字效果

     博主介绍: 本人专注于Android/java/数据库/微信小程序技术领域的开发,以及有好几年的计算机毕业设计方面的实战开发经验和技术积累;尤其是在安卓(Android)的app的开发和微信小程序的开发,很是熟悉和了解;本人也是多年的Android开发人员;希望我发布的此篇文件可以帮

    2024年02月01日
    浏览(96)
  • 【微信小程序】请注意游客模式下,调用 wx.operateWXData 是受限的, API 的返回是工具的模拟返回

    在使用XHbuilder X运行微信小程序的时候可能会遇到一个问题 请注意游客模式下,调用 wx.operateWXData 是受限的, API 的返回是工具的模拟返回 这是因为我们忘记在程序中配置AppID了才会出现这样的警告,接下来就让我带你们看看如何解决这个警告吧 首先让我们打开微信小程序助手

    2024年02月03日
    浏览(79)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包