提交 581817c8 编写于 作者: DCloud_JSON's avatar DCloud_JSON

1.0.23

上级 5dad5d56
## 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) ## 1.0.22(2023-06-07)
- 修复 解决Vue3版本的微信小程序端 textarea的blur事件,会触发“清空会话”事件的问题 - 修复 解决Vue3版本的微信小程序端 textarea的blur事件,会触发“清空会话”事件的问题
## 1.0.21(2023-06-06) ## 1.0.21(2023-06-06)
......
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
<view class="box"> <view class="box">
<text class="title">请选择llm的model</text> <text class="title">请选择llm的model</text>
<radio-group @change="radioChange" class="radio-group"> <radio-group @change="radioChange" class="radio-group">
<label class="item" v-for="(model, index) in models" :key="model"> <label class="item" v-for="(item, index) in models" :key="item.value">
<radio :value="model" :checked="currentModel === model" class="radio" /> <radio :value="item.value" :checked="currentModel === item.value" class="radio" />
<view class="item-title">{{model}}</view> <view class="item-title">{{item.text}}</view>
</label> </label>
</radio-group> </radio-group>
<view class="btn-box"> <view class="btn-box">
...@@ -23,12 +23,34 @@ ...@@ -23,12 +23,34 @@
data() { data() {
return { return {
models: [ models: [
"gpt-4", {
"gpt-4-0314", text:"gpt-4",
"gpt-4-32k", value:"gpt-4"
"gpt-4-32k-0314", },
"gpt-3.5-turbo", {
"gpt-3.5-turbo-0301" 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:'' currentModel:''
}; };
......
<template> <template>
<view class="msg-item"> <view class="msg-item" v-if="!msg.isDelete">
<view class="create_time-box"> <view class="create_time-box">
<uni-dateformat class="create_time" :date="msg.create_time" format="MM/dd hh:mm:ss"></uni-dateformat> <uni-dateformat class="create_time" :date="msg.create_time" format="MM/dd hh:mm:ss"></uni-dateformat>
</view> </view>
...@@ -22,12 +22,21 @@ ...@@ -22,12 +22,21 @@
</text> </text>
<!-- <uni-ad-rewarded-video :adpid="adpid" @onAdClose="onAdClose"></uni-ad-rewarded-video> --> <!-- <uni-ad-rewarded-video :adpid="adpid" @onAdClose="onAdClose"></uni-ad-rewarded-video> -->
</view> </view>
<view v-if="msg.isAi" class="controller"> <view class="menu-box" :class='{"menu-box-ai":msg.isAi}'>
<text v-if="isLastMsg" title="换一个答案" @click="changeAnswer" class="retry-icon"></text> <text v-if="isLastMsg && msg.isAi" title="换一个答案" @click="changeAnswer" class="pointer change-answer"></text>
<view @click="copy" title="复制" class="copy-icon"> <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-a"></view>
<view class="copy-icon-b"></view> <view class="copy-icon-b"></view>
</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>
</view> </view>
<uni-icons v-if="isLastMsg && !msg.isAi && msg.state != 100 && msgStateIcon(msg)" <uni-icons v-if="isLastMsg && !msg.isAi && msg.state != 100 && msgStateIcon(msg)"
...@@ -125,10 +134,12 @@ ...@@ -125,10 +134,12 @@
// 悬浮的复制按钮的上边距 // 悬浮的复制按钮的上边距
top: "-100px", top: "-100px",
msg: { msg: {
content: "" content: "",
isDelete:false
}, },
msgIndexList: 0, msgIndexList: 0,
adpid adpid,
showMoreMenu:false
}; };
}, },
mounted() { mounted() {
...@@ -166,7 +177,7 @@ ...@@ -166,7 +177,7 @@
// 修改转换结果的htmlString值 用于正确给界面增加鼠标闪烁的效果 // 修改转换结果的htmlString值 用于正确给界面增加鼠标闪烁的效果
// 判断markdown中代码块标识符的数量是否为偶数 // 判断markdown中代码块标识符的数量是否为偶数
if (this.msgContent.split("```").length % 2) { 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 { } else {
htmlString = markdownIt.render(this.msgContent) + ' \n <span class="cursor">|</span>'; htmlString = markdownIt.render(this.msgContent) + ' \n <span class="cursor">|</span>';
} }
...@@ -211,7 +222,7 @@ ...@@ -211,7 +222,7 @@
console.log({attrs}); console.log({attrs});
let {"code-data-index":codeDataIndex,"class":className} = attrs let {"code-data-index":codeDataIndex,"class":className} = attrs
if(className == 'copy-btn'){ if(className == 'copy-btn'){
console.log('codeDataList[codeDataIndex]',codeDataList[codeDataIndex]); // console.log('codeDataList[codeDataIndex]',codeDataList[codeDataIndex]);
uni.setClipboardData({ uni.setClipboardData({
data:codeDataList[codeDataIndex], data:codeDataList[codeDataIndex],
showToast:false, showToast:false,
...@@ -242,6 +253,12 @@ ...@@ -242,6 +253,12 @@
}); });
} }
}) })
this.showMoreMenu = false
},
// 删除消息
removeMsg(){
this.$emit('removeMsg',this.msgIndex)
this.showMoreMenu = false
} }
} }
} }
...@@ -273,8 +290,8 @@ ...@@ -273,8 +290,8 @@
.msgStateIcon { .msgStateIcon {
position: relative; position: relative;
top: 5px; top: -5px;
right: 5px; right: 1px;
align-self: center; align-self: center;
} }
...@@ -300,7 +317,7 @@ ...@@ -300,7 +317,7 @@
.content { .content {
position: relative; position: relative;
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
max-width: calc(85% - 15px); max-width: calc(85% - 45px);
/* #endif */ /* #endif */
background-color: #FFF; background-color: #FFF;
border-radius: 5px; border-radius: 5px;
...@@ -313,9 +330,9 @@ ...@@ -313,9 +330,9 @@
/* #endif */ /* #endif */
} }
.controller { .menu-box {
position: absolute; position: absolute;
right: -25px; left: -18px;
bottom: 0; bottom: 0;
width: 20px; width: 20px;
flex-direction: column; flex-direction: column;
...@@ -323,26 +340,81 @@ ...@@ -323,26 +340,81 @@
justify-content: flex-end; justify-content: flex-end;
} }
.retry-icon { .menu-box-ai {
left: auto;
right: -20px;
}
.change-answer {
font-size: 26px; font-size: 26px;
color: #d4d4d4; color: #d4d4d4;
height: 25px; height: 25px;
line-height: 15px; line-height: 15px;
margin-bottom: 5px; margin-bottom: 5px;
position: relative;
left: 2px;
}
.pointer {
cursor: pointer;
} }
.retry-icon:hover {
.pointer:hover {
color: #BBB; color: #BBB;
} }
.retry-icon,.copy-icon { .more-icon-box {
cursor: pointer; justify-content: center;
overflow: hidden;
} }
.copy-icon { .more-icon {
color: #d4d4d4;
transform: rotate(90deg);
position: relative; 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-a,
.copy-icon-b { .copy-icon-b {
position: absolute; position: absolute;
...@@ -350,19 +422,30 @@ ...@@ -350,19 +422,30 @@
width: 10px; width: 10px;
height: 12px; height: 12px;
background-color: #FFF; background-color: #FFF;
left: 2px; left: 3px;
top: 2px; top: 4px;
border-radius: 3px; border-radius: 3px;
} }
.copy-icon-b {
top: 8px;
left: 6px;
}
.copy-icon:hover .copy-icon-a, .copy-icon:hover .copy-icon-a,
.copy-icon:hover .copy-icon-b,{ .copy-icon:hover .copy-icon-b,{
border-color:#bbb; 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 */ /* #ifndef APP-NVUE */
.content ::v-deep rich-text { .content ::v-deep rich-text {
max-width: 100%; max-width: 100%;
......
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
"versionName" : "1.0.0", "versionName" : "1.0.0",
"versionCode" : "100", "versionCode" : "100",
"transformPx" : false, "transformPx" : false,
"networkTimeout" : {
"request" : 600000
},
"app-plus" : { "app-plus" : {
"usingComponents" : true, "usingComponents" : true,
"nvueStyleCompiler" : "uni-app", "nvueStyleCompiler" : "uni-app",
......
{ {
"id": "uni-ai-chat", "id": "uni-ai-chat",
"name": "uni-ai-chat", "name": "uni-ai-chat",
"version": "1.0.22", "version": "1.0.23",
"description": "基于uni-ai的聊天示例项目,支持流式、支持前文总结,云端一体", "description": "基于uni-ai的聊天示例项目,支持流式、支持前文总结,云端一体",
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {
......
...@@ -7,8 +7,8 @@ ...@@ -7,8 +7,8 @@
<text class="noData" v-if="msgLength === 0">没有对话记录</text> <text class="noData" v-if="msgLength === 0">没有对话记录</text>
<scroll-view :scroll-into-view="scrollIntoView" scroll-y="true" class="msg-list" :enable-flex="true"> <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" <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> :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"> <view class="tip-ai-ing" v-if="msgLength && msgLength%2 !== 0 && lastMsgState != -100">
<text>uni-ai正在思考中...</text> <text>uni-ai正在思考中...</text>
<view v-if="NODE_ENV == 'development' && !enableStream"> <view v-if="NODE_ENV == 'development' && !enableStream">
如需提速,请开通<uni-link class="uni-link" href="https://uniapp.dcloud.net.cn/uniCloud/uni-ai-chat.html" 如需提速,请开通<uni-link class="uni-link" href="https://uniapp.dcloud.net.cn/uniCloud/uni-ai-chat.html"
...@@ -35,9 +35,9 @@ ...@@ -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="clearAllMsg" type="trash" size="24" color="#888"></uni-icons>
<uni-icons class="menu-item" @click="setLLMmodel" color="#555" size="20px" type="settings"></uni-icons> <uni-icons class="menu-item" @click="setLLMmodel" color="#555" size="20px" type="settings"></uni-icons>
</view> </view>
<view class="textarea-box" @click="focus = true"> <view class="textarea-box">
<textarea v-model="content" :cursor-spacing="15" class="textarea" :auto-height="!isWidescreen" <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> placeholder-class="input-placeholder"></textarea>
</view> </view>
<view class="send-btn-box" :title="(msgLength && msgLength%2 !== 0) ? 'ai正在回复中不能发送':''"> <view class="send-btn-box" :title="(msgLength && msgLength%2 !== 0) ? 'ai正在回复中不能发送':''">
...@@ -68,8 +68,10 @@ ...@@ -68,8 +68,10 @@
let uniCoTaskList = [] let uniCoTaskList = []
// 定义终止并清空 云对象的任务列表中所有 任务的方法 // 定义终止并清空 云对象的任务列表中所有 任务的方法
uniCoTaskList.clear = function(){ uniCoTaskList.clear = function(){
// 执行数组内的所有任务
uniCoTaskList.forEach(task=>task.abort()) uniCoTaskList.forEach(task=>task.abort())
uniCoTaskList.slice(0,0) // 清空数组
uniCoTaskList.slice(0,uniCoTaskList.length)
} }
// 获取广告id // 获取广告id
...@@ -100,7 +102,6 @@ ...@@ -100,7 +102,6 @@
isWidescreen: false, isWidescreen: false,
// 广告位id // 广告位id
adpid, adpid,
focus: false,
llmModel:false llmModel:false
} }
}, },
...@@ -125,6 +126,15 @@ ...@@ -125,6 +126,15 @@
// 获取当前环境 // 获取当前环境
NODE_ENV() { NODE_ENV() {
return process.env.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变化,将其存储到本地缓存中 // 监听msgList变化,将其存储到本地缓存中
...@@ -138,6 +148,7 @@ ...@@ -138,6 +148,7 @@
this.updateLastMsg(msgList[msgLength - 1]) this.updateLastMsg(msgList[msgLength - 1])
}) })
} }
msgList = msgList.filter(i=>i.isDelete !== true)
// 将msgList存储到本地缓存中 // 将msgList存储到本地缓存中
uni.setStorage({ uni.setStorage({
"key": "uni-ai-msg", "key": "uni-ai-msg",
...@@ -374,6 +385,26 @@ ...@@ -374,6 +385,26 @@
}) })
this.send() 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() { async beforeSendMsg() {
if(this.inputBoxDisabled){ if(this.inputBoxDisabled){
return uni.showToast({ return uni.showToast({
...@@ -465,7 +496,7 @@ ...@@ -465,7 +496,7 @@
let messages = [] let messages = []
// 复制一份,消息列表数据 // 复制一份,消息列表数据
let msgs = JSON.parse(JSON.stringify(this.msgList)) let msgs = msgList.filter(i=>i.isDelete !== true)
// 带总结的消息 index // 带总结的消息 index
let findIndex = [...msgs].reverse().findIndex(item => item.summarize) let findIndex = [...msgs].reverse().findIndex(item => item.summarize)
// console.log('findIndex', findIndex) // console.log('findIndex', findIndex)
...@@ -681,14 +712,6 @@ ...@@ -681,14 +712,6 @@
}, },
// 清空消息列表 // 清空消息列表
clearAllMsg(e) { 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({ uni.showModal({
title: "确认要清空聊天记录?", title: "确认要清空聊天记录?",
...@@ -795,7 +818,7 @@ ...@@ -795,7 +818,7 @@
} }
.textarea-box .textarea { .textarea-box .textarea {
max-height: 100px; max-height: 120px;
font-size: 14px; font-size: 14px;
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
overflow: auto; overflow: auto;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册