前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >腾讯元器:为了荒天帝,自学从零开发了一个微信小程序...

腾讯元器:为了荒天帝,自学从零开发了一个微信小程序...

原创
作者头像
叫我阿柒啊
修改2024-06-13 15:18:07
4352
修改2024-06-13 15:18:07
举报

前言

腾讯元器是基于腾讯混元大模型的一站式智能体制作平台,我们可以在这个平台上制作属于自己的智能体,并且可以制作插件,通过智能体插件配置,让智能体拥有这些插件的能力。

在智能体创建完成之后,可以将这些智能体接入到QQ和微信客服。当然,如果我们想要在第三方应用接入元器智能体,可以和chatGPT一样通过api调用。在本篇文章中,会讲述如何创建一个智能体、如何使用插件以及如何在微信小程序中接入智能体。

元器/ChatGPT微信小程序效果图展示:

元器/ChatGPT微信小程序动图展示:

在这里插入图片描述
在这里插入图片描述

元器

进入腾讯元器首页,我们可以看到有智能体和插件的入口。点击“创建智能体”就可以新建一个智能体。

因为初次使用元器,我们可以参考已经发布的智能体设置,来创建智能体。

我个人是个国漫迷,尤其是文改漫,所以我打算创建一个很中二的智能体:完美世界的男主 -- 荒天帝。我参考孔乙己”智能体设置,来配置荒天帝智能体。

在详细设定中设定智能体身份、个人背景、任务关系、个人技能和人物性格等。

因为详细设定有10000字的限制,如果想要让智能体更好地理解用户问题意图,我们可以通过添加知识库的方式辅助模型回答用户的问题。

我直接下载了完美世界全本,在智能体设置页面通过创建知识库来添加。至此,一个名为荒天帝的智能体创建成功。创建之后可以进行对话测试。

如图,可以与荒天帝实现简单的对话。体验入口:https://yuanqi.tencent.com/agent/v0c4FkvNvtOi?from=share

接下来我们要做的就是添加一些插件,并将荒天帝接入到微信小程序中。

很早之前就想写一个类似于ChatGPT的小程序,后来因为事情太多搁置了,正好借此机会来手写一个微信小程序,并接入腾讯智能体实现对话功能。

架构设计

技术架构还是uni-app + vue3,前端能力有限,所以开发周期就是边学边开发,我前端开发的思路就是:先有这个东西,然后在需要和其他模块数据联动交互的时候,再进行公共模块的开发,这些小程序的过程中都有体现。

Layout布局

不论是H5还是小程序开发,第一步就是考虑布局layout。我这个小程序布局主要分为四个部分:从从左到右分为菜单aside和会话区。会话区从上到下分为header、对话显示main区域以及输入框区域。布局代码如下:

代码语言:html
复制
<view>
    <view class="laytout">
        <view class="aside">Aside</view>
        <view class="right">
            <view class="header">Header</view>
            <view class="main">Main Content</view>
            <view class="footer">footer</view>
        </view>
    </view>
</view>

Element Plus提供了布局元素,uni-app只能使用原生的view(div)元素,然后通过自定义css来完成布局。

代码语言:css
复制
	.laytout {
		display: flex;
		height: 100%;
		width: 100%;
	}

	.right {
		display: flex;
		flex-direction: column;
	}

	.header {
		height: 5vh;
	}

	.main {
		height: 84vh;
		width: 100vw;
		margin-top: 10px;
	}

	.footer {
		width: 100vw;
	}

为了方便开发和标识各个区域,可以给各个区域添加background和border,在添加css样式之后,布局雏形就出来了。

布局完成,接着就是每个布局区域的功能设计。

main

main区域是与ChatGPT的会话区域,在这里要实现的功能:

  1. 滚动窗口:当对话超出屏幕大小时,产生滚动效果,确保不会影响其他元素的布局。
  2. 交互式会话:元器对话框在左,用户对话框在右。

滚动窗口

滚动窗口使用scroll-view组件来实现,

代码语言:html
复制
<scroll-view class="scroll-Y" scroll-y="true" scroll-with-animation='true'>
</scroll-view>

scroll-y设置为true,表示是在垂直方向上滚动,scroll-with-animation用来开启滚动条动画。滚动窗口的高度设置为84vh,剩下的16vh就分配给header和footer。接下来就是将交互会话在scroll中实现。

交互式会话

会话部分是整个小程序的核心内容。和平时我们使用的微信和QQ聊天一样,ChatGPT/元器消息在左,个人消息在右。在开发这个模块的时候,我从最简单的功能实现开始,在js中定义了一个消息列表messageList

代码语言:javascript
复制
const messageList = []
messageList.push({ content: '你好', sender: 'right' });
messageList.push({ content: '请问有什么可以帮助您吗', sender: 'left' });

其中content是文本内容,sender用来区别是元器智能体还是用户,这里都使用了固定值,只是为了做一个样式设计,后面会根据元器智能体API请求规范进行填充。然后就是html的设计。

代码语言:html
复制
<view class="session" v-for="(message, index) in messageList" :key="index">
    <view class="message-line" :class="message.sender === 'left' ? 'message-line-receive' : 'message-line-send'">
        <image v-if="message.sender === 'left'" src='../../../static/chatgpt.png'></image>
        <view :class="message.sender === 'left' ? 'receive' : 'send'">{{ message.content }}</view>
        <image v-if="message.sender === 'right'" src='../../../static/logo.png'></image>
    </view>
</view>

通过遍历messageList来渲染消息。每行消息又分为两部分:头像和消息内容,通过v-if对sender的判断,来实现智能体对话部分是头像在消息内容左侧,而用户的头像在消息内容右侧。

在上面我使用了flex弹性布局,并使用flex-end使元素靠右分布。

代码语言:css
复制
.session {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
}
.message-line {
    display: flex;
    justify-content: flex-end;
}

而元器智能体的消息框应该靠左侧分布,所以我将align-self设置成flex-start,来实现这个功能。

代码语言:css
复制
.message-line-receive {
    align-self: flex-start;
}

除此之外,使用margin设置一下元素间隔,最后的样式:

因为和智能体的对话要靠用户的输入内容驱动,所以接下来就是设计footer区域。

footer

footer区域主要是用户输入问题,除了输入框之外可以增加一些功能按钮,例如语音、文件上传等。

代码语言:html
复制
<view class="input">
    <uni-icons type="chat" size="30"></uni-icons>
    <view class="chat-input uni-column">
        <input class="uni-input" v-model="inputMessage" maxlength="200" placeholder="你有什么想知道的?" @confirm="sendMessages" />
    </view>
    <uni-icons class='mic' type="mic" size="30"></uni-icons>
</view>

我这里的footer区域设置了三个组件:两个uni图标,一个input输入框。

第一个chat图标暂时没什么想法,第二个mic图标我打算接入腾讯云语音识别,这个就留给下一篇文章。从上面的html可以看到,input输入框绑定了一个confirm事件,当输入完成点击回车,这时候需要触发三个动作:

  1. 输入内容显示在main的会话区域
  2. 清空输入框
  3. 通过智能体API进行会话交互,将返回结果渲染在main会话区域。

footer和main区域是两个组件实现的,按照我们上面的设计,我们要将输入的消息内容,放到main定义的messageList中才能渲染成功。但是两个组件要想数据交互,就要使用共享状态变量,要不就是vuex、要不就是pinia。uin-app内置了pinia,所以这里还是使用pinia。

代码语言:typescript
复制
export const useChat = defineStore('useChat',
	() => {
		const state : Chat = reactive({
			messages: [],
			model_id: 0,
			receiver: '',
			sender: '',
		})

这里一共定义了四个变量,messages用来存放智能体和用户的消息内容,用来构造元器智能体api的请求参数。model_id用来区分使用的模型,例如0是智能体、1是ChatGPT,以此来调用不同的接口。

receiversender表示角色,在元器智能体api的请求参数中,必须要有role,用户的role是user,智能体的是assistant,在这里也就对应着这个变量。

在智能体的调用api文档中,可以看到请求参数。

而其中messages参数,就是我们在状态变量中构造的。所以在共享状态变量中,我定义了constructMessage函数,用来处理共享状态变量和构造消息列表。

代码语言:typescript
复制
// role 1表示send, 2 receive
const constructMessage = function (message, role) {
    switch (state.model_id) {
        // 元器
        case 0:
            state.sender = 'user'
            state.receiver = 'assistant'
            const templete = {
                "role": "",
                "content": [
                    {
                        "type": "text",
                        "text": message
                    }]
            }
            if (role == 1) {
                templete.role = 'user'
            } else {
                templete.role = 'assistant'

            }
            state.messages.push(templete)
            break;
        case 1:
            break;

    }
}

然后就是在input的confirm事件绑定的回调函数sendMessages中,调用智能体的api进行交互。

代码语言:JavaScript
复制
import {useChat} from '../../../stores/chat'
	
const chat = useChat()
const inputMessage = ref()

const sendMessages = function () {
    // 将新输入的问题添加到messages中
    chat.constructMessage(inputMessage.value, 1)
    inputMessage.value = ''
    uni.request({
        url: "https://yuanqi.tencent.com/openapi/v1/agent/chat/completions",
        method: 'POST',
        header: {
            'X-Source': 'openapi',
            'Content-Type': 'application/json',
            'Authorization': 'Bearer pJhqvfJ1xxx',
        },

        data: {
            "assistant_id": "v0c4FkvN",
            "user_id": "rodneyxiong",
            "stream": false,
            "messages": chat.state.messages
        },
        success: (res) => {
            const message = res.data['choices'][0]['message']['content']
            // 将智能体返回的消息放到messages中
            chat.constructMessage(message, 2)
            console.log(res.data);
        }
    })
}

在上面的代码中,实现了上面说的三个功能。input使用v-model绑定了inputMessage,在点击回车发送消息之后,先调用共享状态的constructMessage方法,将inputMessage放入message,这样输入内容就出现在了main区域,然后将inputMessage置为空,就实现了清空输入框的动作。

然后调用智能体接口,提取返回的消息内容变量,在上面的sendMessages回调函数中,也放入了共享变量的messages中,然后渲染在了main区域。

这里需要按照状态变量messages中的内容结构,替换main中元素使用的变量。

代码语言:html
复制
<view class="session" v-for="(message, index) in chat.state.messages" :key="index">
    <view class="message-line" :class="message.role === chat.state.receiver ? 'message-line-receive' : 'message-line-send'">
        <image v-if="message.role === chat.state.receiver" src="../../../static/chatgpt.jpeg"></image>
        <view :class="message.role === chat.state.receiver ? 'receive' : 'send'">{{ message.content[0].text }}</view>
        <image v-if="message.role === chat.state.sender" src='../../../static/logo.jpeg'></image>
    </view>
</view>

判断角色的变量从之前的sender变成了role,然后就渲染成了下面的样子。

这里就出现问题了,当文字过多的时候,头像就被挤压到变形了,只要将send和receive元素,也就是消息内容元素的width设置为80vw就可以解决了。

最后做一下css细节优化,更换头像、缩放字体以及设置对话框的背景颜色,最后效果如下图。

在这里插入图片描述
在这里插入图片描述

header

在很多ChatGPT的web中,header用来实现新建会话、切换ChatGPT版本的功能,在我的设计中,header包含控制aside折叠的按钮和切换模型的下拉框。

这里的header就两个图标和下拉框,第一个图标用来控制aside的展开和缩放,第二个图标用来新建一个会话,用来切断上下文的联系,最右侧是一个下拉框,用来选择会话模型。

代码语言:html
复制
<view class="header">
    <view class="uni-icons">
        <uni-icons type="bars" size="26" @click="collapse"></uni-icons>
        <uni-icons type="plusempty" size="26" @click="createSession"></uni-icons>
    </view>
    <view class='data-select'>
        <uni-data-select v-model="value" :localdata="models" :clear="false" @change="change"></uni-data-select>
    </view>
</view>

也是定了三个组件,这里需要注意的就是uni-data-select组件,使用localdata绑定数据,v-model用来绑定模型的value值,这里的value值就是之前在共享变量中提到的model_id,这样就能区分出使用了哪个模型。

同时也绑定了change回调函数,当下拉框选项发生变化时,就可以获取切换后模型的value,然后赋值给model_id。

bars图标用来控制aside的折叠。plusempty图标用来新建会话,这个还需要后面完善。

aside

最后就是aside区域,Aside打算做一个会话别表,可以删除会话列表用来清除上下文关联,重新开始一个对话。图标控制展开、隐藏的边栏,我在实现BuildAdmin管理系统的边栏菜单中,详细介绍了其实现原理。这里目前只实现了通过bars图标来控制是否展开。

代码语言:html
复制
<view class="aside" v-show="!layout.state.menuCollapse"> </view>

同样,这里的layout.state.menuCollapse也是使用pinia定义的状态变量,header区域的bars图标元素绑定了click回调函数collapse,用来更改menuCollapse。

代码语言:JavaScript
复制
const collapse = function () {
    layout.state.menuCollapse = !layout.state.menuCollapse
}

这里我将aside的width设置为75vw,有一种推拉的感觉。

代码语言:css
复制
.aside {
    width: 75vw;
    transition: width 0.3s ease;
}

最后效果如下:

在这里插入图片描述
在这里插入图片描述

可以在aside右上角设置一个关闭按钮,或者点击main区域来隐藏aside,而非再点击折叠按钮。

优化

从小程序的整体功能和页面设计上来说,还有很多优化的地方,例如:

  1. 接入多种模型,例如元器智能体、ChatGPT,实现切换
  2. aside区域的会话列表,包括新建会话、删除会话
  3. 腾讯云语音识别的接入,实现原因转文字和文字转语音的功能
  4. 实现智能体/ChatGPT消息流式打字展示,目前是一次性返回渲染
  5. 获取用户头像

结语

总体来说,元器智能体还是比较容易上手的,操作手册中也提供了创建、发布、接入、api调用以及插件使用的详细步骤。

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 元器
  • 架构设计
  • Layout布局
  • main
    • 滚动窗口
      • 交互式会话
      • footer
      • header
      • aside
      • 优化
      • 结语
      相关产品与服务
      云开发 CloudBase
      云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档