提交 560a93e7 编写于 作者: DCloud_JSON's avatar DCloud_JSON

1.0.23

上级 ad9168bf
## 1.0.23(2023-06-08)
- 新增 支持单独删除某一次对话(注意:一次对话包含提问和回答2条消息)
- 更新 客户端网络请求超时时间(`manifest.json`->`networkTimeout`->`request`)设置为`600000`毫秒 [详情参考](https://uniapp.dcloud.net.cn/collocation/manifest.html#networktimeout)
- 修复 部分情况,消息发送失败 仍然会显示“ai正在思考中”的问题
## 1.0.22(2023-06-07)
- 修复 解决Vue3版本的微信小程序端 textarea的blur事件,会触发“清空会话”事件的问题
## 1.0.21(2023-06-06)
......
<template>
<template>
<uni-popup ref="popup" type="top">
<view class="box">
<text class="title">请选择llm的model</text>
<radio-group @change="radioChange" class="radio-group">
<label class="item" v-for="(model, index) in models" :key="model">
<radio :value="model" :checked="currentModel === model" class="radio" />
<view class="item-title">{{model}}</view>
<label class="item" v-for="(item, index) in models" :key="item.value">
<radio :value="item.value" :checked="currentModel === item.value" class="radio" />
<view class="item-title">{{item.text}}</view>
</label>
</radio-group>
<view class="btn-box">
......@@ -13,34 +13,56 @@
<view @click="confirm" class="btn confirm">确认</view>
</view>
</view>
</uni-popup>
</template>
</uni-popup>
</template>
<script>
let confirmCallback = ()=>{}
export default {
name: "llm-config",
data() {
return {
let confirmCallback = ()=>{}
export default {
name: "llm-config",
data() {
return {
models: [
"gpt-4",
"gpt-4-0314",
"gpt-4-32k",
"gpt-4-32k-0314",
"gpt-3.5-turbo",
"gpt-3.5-turbo-0301"
{
text:"gpt-4",
value:"gpt-4"
},
{
text:"gpt-4-0314",
value:"gpt-4-0314"
},
{
text:"gpt-4-32k",
value:"gpt-4-32k"
},
{
text:"gpt-4-32k-0314",
value:"gpt-4-32k-0314"
},
{
text:"gpt-3.5-turbo",
value:"gpt-3.5-turbo"
},
{
text:"gpt-3.5-turbo-0301",
value:"gpt-3.5-turbo-0301"
},
{
text:"都不选",
value:""
}
],
currentModel:''
};
};
},
mounted() {
this.currentModel = uni.getStorageSync('uni-ai-chat-llmModel')
},
},
methods: {
open(callback){
confirmCallback = callback
this.$refs.popup.open('center')
},
},
radioChange(event) {
console.log('event',event.detail.value)
this.currentModel = event.detail.value
......@@ -52,11 +74,11 @@
// console.log(this.models[this.current]);
confirmCallback(this.currentModel)
this.$refs.popup.close()
},
}
}
</script>
},
}
}
</script>
<style>
/* #ifndef APP-NVUE */
.box,
......@@ -73,8 +95,8 @@
.box,.title,.btn-box {
width: 250px;
}
.box {
.box {
background-color: #fff;
display: flex;
flex-direction: column;
......@@ -163,5 +185,5 @@
/* transform-origin: 0 0; */
transform: scaleX(.5);
}
/* #endif */
/* #endif */
</style>
\ No newline at end of file
<template>
<view class="msg-item">
<view class="msg-item" v-if="!msg.isDelete">
<view class="create_time-box">
<uni-dateformat class="create_time" :date="msg.create_time" format="MM/dd hh:mm:ss"></uni-dateformat>
</view>
......@@ -22,12 +22,21 @@
</text>
<!-- <uni-ad-rewarded-video :adpid="adpid" @onAdClose="onAdClose"></uni-ad-rewarded-video> -->
</view>
<view v-if="msg.isAi" class="controller">
<text v-if="isLastMsg" title="换一个答案" @click="changeAnswer" class="retry-icon"></text>
<view @click="copy" title="复制" class="copy-icon">
<view class="copy-icon-a"></view>
<view class="copy-icon-b"></view>
<view class="menu-box" :class='{"menu-box-ai":msg.isAi}'>
<text v-if="isLastMsg && msg.isAi" title="换一个答案" @click="changeAnswer" class="pointer change-answer"></text>
<view @click="showMoreMenu = !showMoreMenu" class="more-icon-box">
<text class="more-icon pointer">...</text>
</view>
<template v-if="showMoreMenu">
<view class="more-menu">
<view @click="copy" title="复制" class="copy-icon pointer">
<view class="copy-icon-a"></view>
<view class="copy-icon-b"></view>
</view>
<uni-icons class="remove-msg pointer" @click="removeMsg" type="trash" size="20" color="#bbb"></uni-icons>
</view>
<view class="more-menu-mask" @click="showMoreMenu = false"></view>
</template>
</view>
</view>
<uni-icons v-if="isLastMsg && !msg.isAi && msg.state != 100 && msgStateIcon(msg)"
......@@ -125,10 +134,12 @@
// 悬浮的复制按钮的上边距
top: "-100px",
msg: {
content: ""
content: "",
isDelete:false
},
msgIndexList: 0,
adpid
adpid,
showMoreMenu:false
};
},
mounted() {
......@@ -166,7 +177,7 @@
// 修改转换结果的htmlString值 用于正确给界面增加鼠标闪烁的效果
// 判断markdown中代码块标识符的数量是否为偶数
if (this.msgContent.split("```").length % 2) {
htmlString = markdownIt.render(this.msgContent + ' <span class="cursor">|</span>');
htmlString = markdownIt.render(this.msgContent)+ '<span class="cursor">|</span>';
} else {
htmlString = markdownIt.render(this.msgContent) + ' \n <span class="cursor">|</span>';
}
......@@ -211,7 +222,7 @@
console.log({attrs});
let {"code-data-index":codeDataIndex,"class":className} = attrs
if(className == 'copy-btn'){
console.log('codeDataList[codeDataIndex]',codeDataList[codeDataIndex]);
// console.log('codeDataList[codeDataIndex]',codeDataList[codeDataIndex]);
uni.setClipboardData({
data:codeDataList[codeDataIndex],
showToast:false,
......@@ -241,7 +252,13 @@
icon: 'none'
});
}
})
})
this.showMoreMenu = false
},
// 删除消息
removeMsg(){
this.$emit('removeMsg',this.msgIndex)
this.showMoreMenu = false
}
}
}
......@@ -273,8 +290,8 @@
.msgStateIcon {
position: relative;
top: 5px;
right: 5px;
top: -5px;
right: 1px;
align-self: center;
}
......@@ -300,7 +317,7 @@
.content {
position: relative;
/* #ifndef APP-NVUE */
max-width: calc(85% - 15px);
max-width: calc(85% - 45px);
/* #endif */
background-color: #FFF;
border-radius: 5px;
......@@ -313,9 +330,9 @@
/* #endif */
}
.controller {
.menu-box {
position: absolute;
right: -25px;
left: -18px;
bottom: 0;
width: 20px;
flex-direction: column;
......@@ -323,26 +340,81 @@
justify-content: flex-end;
}
.retry-icon {
.menu-box-ai {
left: auto;
right: -20px;
}
.change-answer {
font-size: 26px;
color: #d4d4d4;
height: 25px;
line-height: 15px;
margin-bottom: 5px;
position: relative;
left: 2px;
}
.retry-icon:hover {
.pointer {
cursor: pointer;
}
.pointer:hover {
color: #BBB;
}
.retry-icon,.copy-icon {
cursor: pointer;
.more-icon-box {
justify-content: center;
overflow: hidden;
}
.copy-icon {
.more-icon {
color: #d4d4d4;
transform: rotate(90deg);
position: relative;
height: 25px;
left: 4px;
font-size: 16px;
z-index: 999;
}
.more-menu {
position: absolute;
bottom:-10px;
left:-30px;
flex-direction: column;
justify-content: space-around;
width: 30px;
padding: 2px 5px;
height: 60px;
z-index: 999;
background-color: #FFF;
box-shadow: 0 0 20px #eee;
border-radius: 3px;
}
.more-menu-mask {
position: fixed;
width: 100vw;
height: 100vh;
top: 0;
left: 0;
z-index: 998;
}
.menu-box-ai .more-menu {
left:auto;
right: -32px;
}
.more-menu .pointer{
width: 20px;
}
.copy-icon{
position: relative;
height: 25px;
width: 20px;
}
.copy-icon-a,
.copy-icon-b {
position: absolute;
......@@ -350,18 +422,29 @@
width: 10px;
height: 12px;
background-color: #FFF;
left: 2px;
top: 2px;
left: 3px;
top: 4px;
border-radius: 3px;
}
.copy-icon-b {
top: 8px;
left: 6px;
}
.copy-icon:hover .copy-icon-a,
.copy-icon:hover .copy-icon-b,{
border-color:#bbb;
}
.copy-icon-b {
top: 5px;
left: 5px;
}
.remove-msg {
position: relative;
opacity: 0.7;
}
.remove-msg:hover{
opacity: 1;
}
/* #ifndef APP-NVUE */
.content ::v-deep rich-text {
......
......@@ -5,6 +5,9 @@
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
"networkTimeout" : {
"request" : 600000
},
"app-plus" : {
"usingComponents" : true,
"nvueStyleCompiler" : "uni-app",
......
{
"id": "uni-ai-chat",
"name": "uni-ai-chat",
"version": "1.0.22",
"version": "1.0.23",
"description": "基于uni-ai的聊天示例项目,支持流式、支持前文总结,云端一体",
"main": "main.js",
"scripts": {
......
......@@ -7,8 +7,8 @@
<text class="noData" v-if="msgLength === 0">没有对话记录</text>
<scroll-view :scroll-into-view="scrollIntoView" scroll-y="true" class="msg-list" :enable-flex="true">
<uni-ai-msg ref="msg" v-for="(msgIndex,index) in msgLength" :key="index" :msgIndex="index" @retriesSendMsg="retriesSendMsg" @changeAnswer="changeAnswer"
:show-cursor="index == msgLength - 1 && msgLength%2 === 0 && sseIndex" :isLastMsg="index == msgLength - 1"></uni-ai-msg>
<view class="tip-ai-ing" v-if="msgLength && msgLength%2 !== 0">
:show-cursor="index == msgLength - 1 && msgLength%2 === 0 && sseIndex" :isLastMsg="index == msgLength - 1" @removeMsg="removeMsg"></uni-ai-msg>
<view class="tip-ai-ing" v-if="msgLength && msgLength%2 !== 0 && lastMsgState != -100">
<text>uni-ai正在思考中...</text>
<view v-if="NODE_ENV == 'development' && !enableStream">
如需提速,请开通<uni-link class="uni-link" href="https://uniapp.dcloud.net.cn/uniCloud/uni-ai-chat.html"
......@@ -35,9 +35,9 @@
<uni-icons class="menu-item" @click="clearAllMsg" type="trash" size="24" color="#888"></uni-icons>
<uni-icons class="menu-item" @click="setLLMmodel" color="#555" size="20px" type="settings"></uni-icons>
</view>
<view class="textarea-box" @click="focus = true">
<view class="textarea-box">
<textarea v-model="content" :cursor-spacing="15" class="textarea" :auto-height="!isWidescreen"
:placeholder="placeholderText" :maxlength="-1" :focus="focus" @blur="focus = false"
:placeholder="placeholderText" :maxlength="-1"
placeholder-class="input-placeholder"></textarea>
</view>
<view class="send-btn-box" :title="(msgLength && msgLength%2 !== 0) ? 'ai正在回复中不能发送':''">
......@@ -68,8 +68,10 @@
let uniCoTaskList = []
// 定义终止并清空 云对象的任务列表中所有 任务的方法
uniCoTaskList.clear = function(){
// 执行数组内的所有任务
uniCoTaskList.forEach(task=>task.abort())
uniCoTaskList.slice(0,0)
// 清空数组
uniCoTaskList.slice(0,uniCoTaskList.length)
}
// 获取广告id
......@@ -99,8 +101,7 @@
// 当前屏幕是否为宽屏
isWidescreen: false,
// 广告位id
adpid,
focus: false,
adpid,
llmModel:false
}
},
......@@ -125,6 +126,15 @@
// 获取当前环境
NODE_ENV() {
return process.env.NODE_ENV
},
//最后一条消息的状态
lastMsgState(){
let mLength = this.msgList.length
if(mLength){
return this.msgList[mLength - 1].state
}else{
return false
}
}
},
// 监听msgList变化,将其存储到本地缓存中
......@@ -137,7 +147,8 @@
this.$nextTick(() => {
this.updateLastMsg(msgList[msgLength - 1])
})
}
}
msgList = msgList.filter(i=>i.isDelete !== true)
// 将msgList存储到本地缓存中
uni.setStorage({
"key": "uni-ai-msg",
......@@ -373,6 +384,26 @@
illegal:false
})
this.send()
},
removeMsg(index){
// #ifdef VUE3
this.msgList[index].isDelete = true
if(this.msgList[index].isAi && this.msgList[index - 1]){
this.msgList[index - 1].isDelete = true
}else if(this.msgList[index + 1]){
this.msgList[index + 1].isDelete = true
}
// #endif
// #ifdef VUE2
this.$set(msgList[index],"isDelete",true)
msgList.slice(index,1,msgList[index])
if(msgList[index].isAi && msgList[index - 1]){
this.$set(msgList[index - 1],"isDelete",true)
}else if(msgList[index + 1]){
this.$set(msgList[index + 1],"isDelete",true)
}
// #endif
},
async beforeSendMsg() {
if(this.inputBoxDisabled){
......@@ -465,7 +496,7 @@
let messages = []
// 复制一份,消息列表数据
let msgs = JSON.parse(JSON.stringify(this.msgList))
let msgs = msgList.filter(i=>i.isDelete !== true)
// 带总结的消息 index
let findIndex = [...msgs].reverse().findIndex(item => item.summarize)
// console.log('findIndex', findIndex)
......@@ -681,14 +712,6 @@
},
// 清空消息列表
clearAllMsg(e) {
// #ifdef MP-WEIXIN && VUE3
console.log('clearAllMsg',e);
if(e && e.type == "blur"){
console.log('补丁:解决Vue3版本的微信小程序端 textarea的blur事件,会触发“清空会话”事件的问题');
return false
}
// #endif
// 弹出确认清空聊天记录的提示框
uni.showModal({
title: "确认要清空聊天记录?",
......@@ -795,13 +818,13 @@
}
.textarea-box .textarea {
max-height: 100px;
max-height: 120px;
font-size: 14px;
/* #ifndef APP-NVUE */
overflow: auto;
/* #endif */
width: 450rpx;
font-size: 14px;
font-size: 14px;
}
/* #ifdef H5 */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册