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

1.1.0

- 【重要】优化`uni-ai-chat`云对象的`send`方法性能(并发:“普通消息对话”和“获得内容总结”),大幅提高会话响应速度。
- 修复 手机端 当消息列表数据不满一屏幕时,键盘弹出后看不到历史消息
- 修复 单独删除最后一次对话后,新的最后一条对话消息没有`换答案`按钮
- 修复 当消息发送失败 重新发送消息按钮图标与 复制和删除消息按钮 样式重叠的问题
上级 4948c67c
## 1.1.0(2023-06-09)
- 【重要】优化`uni-ai-chat`云对象的`send`方法性能(并发:“普通消息对话”和“获得内容总结”),大幅提高会话响应速度。
- 修复 手机端 当消息列表数据不满一屏幕时,键盘弹出后看不到历史消息
- 修复 单独删除最后一次对话后,新的最后一条对话消息没有`换答案`按钮
- 修复 当消息发送失败 重新发送消息按钮图标与 复制和删除消息按钮 样式重叠的问题
## 1.0.23(2023-06-08) ## 1.0.23(2023-06-08)
- 新增 支持单独删除某一次对话(注意:一次对话包含提问和回答2条消息) - 新增 支持单独删除某一次对话(注意:一次对话包含提问和回答2条消息)
- 更新 客户端网络请求超时时间(`manifest.json`->`networkTimeout`->`request`)设置为`600000`毫秒 [详情参考](https://uniapp.dcloud.net.cn/collocation/manifest.html#networktimeout) - 更新 客户端网络请求超时时间(`manifest.json`->`networkTimeout`->`request`)设置为`600000`毫秒 [详情参考](https://uniapp.dcloud.net.cn/collocation/manifest.html#networktimeout)
......
...@@ -39,10 +39,10 @@ ...@@ -39,10 +39,10 @@
</template> </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)"
@click="msg.state == -100 ? retriesSendMsg() : ''" :color="msg.state===0?'#999':'#d22'" @click="msg.state == -100 ? retriesSendMsg() : ''" :color="msg.state===0?'#999':'#d22'"
:type="msgStateIcon(msg)" class="msgStateIcon"> :type="msgStateIcon(msg)" class="msgStateIcon">
</uni-icons> </uni-icons> -->
</view> </view>
</view> </view>
</template> </template>
...@@ -370,11 +370,19 @@ ...@@ -370,11 +370,19 @@
.more-icon { .more-icon {
color: #d4d4d4; color: #d4d4d4;
transform: rotate(90deg); transform: rotate(270deg);
position: relative; position: relative;
left: 4px; left: -8px;
font-size: 16px; font-size: 16px;
z-index: 999; z-index: 999;
padding-bottom: 5px;
height: 10px;
}
.menu-box-ai .more-icon{
left: 7px;
top: -2px;
transform: rotate(90deg);
} }
.more-menu { .more-menu {
......
{ {
"id": "uni-ai-chat", "id": "uni-ai-chat",
"name": "uni-ai-chat", "name": "uni-ai-chat",
"version": "1.0.23", "version": "1.1.0",
"description": "基于uni-ai的聊天示例项目,支持流式、支持前文总结,云端一体", "description": "基于uni-ai的聊天示例项目,支持流式、支持前文总结,云端一体",
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {
......
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
"style": { "style": {
"navigationBarTitleText": "uni-ai-chat", "navigationBarTitleText": "uni-ai-chat",
"enablePullDownRefresh": false "enablePullDownRefresh": false
// #ifdef H5
,"navigationStyle": "custom"
//#endif
} }
}, { }, {
"path": "uni_modules/uni-id-pages/pages/userinfo/deactivate/deactivate", "path": "uni_modules/uni-id-pages/pages/userinfo/deactivate/deactivate",
......
<template> <template>
<view class="page">
<view class="container"> <view class="container">
<!-- #ifdef H5 --> <!-- #ifdef H5 -->
<view v-if="isWidescreen" class="header">uni-ai-chat</view> <view v-if="isWidescreen" class="header">uni-ai-chat</view>
<!-- #endif --> <!-- #endif -->
<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"
:show-cursor="index == msgLength - 1 && msgLength%2 === 0 && sseIndex" :isLastMsg="index == msgLength - 1" @removeMsg="removeMsg"></uni-ai-msg> @retriesSendMsg="retriesSendMsg" @changeAnswer="changeAnswer"
<view class="tip-ai-ing" v-if="msgLength && msgLength%2 !== 0 && lastMsgState != -100"> :show-cursor="index == msgLength - 1 && msgLength%2 === 0 && sseIndex"
:isLastMsg="index == visibleMsgLength - 1" @removeMsg="removeMsg"></uni-ai-msg>
<view v-if="lastMsgState == -100" class="retries-box">
<text>消息发送失败</text>
<uni-icons @click="retriesSendMsg" color="#d22" type="refresh-filled" class="retries-icon"></uni-icons>
</view>
<view class="tip-ai-ing" v-else-if="msgLength && msgLength%2 !== 0">
<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"
...@@ -19,7 +24,7 @@ ...@@ -19,7 +24,7 @@
<view id="last-msg-item" style="height: 1px;"></view> <view id="last-msg-item" style="height: 1px;"></view>
</scroll-view> </scroll-view>
<view class="foot-box"> <view class="foot-box" :style="{'padding-bottom':footBoxPaddingBottom}">
<!-- #ifdef H5 --> <!-- #ifdef H5 -->
<view class="pc-menu" v-if="isWidescreen"> <view class="pc-menu" v-if="isWidescreen">
<view class="pc-trash pc-menu-item" @click="clearAllMsg" title="删除"> <view class="pc-trash pc-menu-item" @click="clearAllMsg" title="删除">
...@@ -33,12 +38,13 @@ ...@@ -33,12 +38,13 @@
<view class="foot-box-content"> <view class="foot-box-content">
<view v-if="!isWidescreen" class="menu"> <view v-if="!isWidescreen" class="menu">
<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"> <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" :placeholder="placeholderText" :maxlength="-1" :adjust-position="false"
placeholder-class="input-placeholder"></textarea> :disable-default-padding="false" 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正在回复中不能发送':''">
<!-- #ifdef H5 --> <!-- #ifdef H5 -->
...@@ -49,7 +55,6 @@ ...@@ -49,7 +55,6 @@
</view> </view>
</view> </view>
</view> </view>
</view>
<llm-config ref="llm-config"></llm-config> <llm-config ref="llm-config"></llm-config>
</view> </view>
</template> </template>
...@@ -67,11 +72,11 @@ ...@@ -67,11 +72,11 @@
// 收集所有执行云对象的任务列表 // 收集所有执行云对象的任务列表
let uniCoTaskList = [] let uniCoTaskList = []
// 定义终止并清空 云对象的任务列表中所有 任务的方法 // 定义终止并清空 云对象的任务列表中所有 任务的方法
uniCoTaskList.clear = function(){ uniCoTaskList.clear = function() {
// 执行数组内的所有任务 // 执行数组内的所有任务
uniCoTaskList.forEach(task=>task.abort()) uniCoTaskList.forEach(task => task.abort())
// 清空数组 // 清空数组
uniCoTaskList.slice(0,uniCoTaskList.length) uniCoTaskList.slice(0, uniCoTaskList.length)
} }
// 获取广告id // 获取广告id
...@@ -102,7 +107,9 @@ ...@@ -102,7 +107,9 @@
isWidescreen: false, isWidescreen: false,
// 广告位id // 广告位id
adpid, adpid,
llmModel:false llmModel: false,
keyboardHeight: 0,
visibleMsgLength:0
} }
}, },
computed: { computed: {
...@@ -128,13 +135,16 @@ ...@@ -128,13 +135,16 @@
return process.env.NODE_ENV return process.env.NODE_ENV
}, },
//最后一条消息的状态 //最后一条消息的状态
lastMsgState(){ lastMsgState() {
let mLength = this.msgList.length let mLength = this.msgList.length
if(mLength){ if (mLength) {
return this.msgList[mLength - 1].state return this.msgList[mLength - 1].state
}else{ } else {
return false return false
} }
},
footBoxPaddingBottom() {
return (this.keyboardHeight || 10) + 'px'
} }
}, },
// 监听msgList变化,将其存储到本地缓存中 // 监听msgList变化,将其存储到本地缓存中
...@@ -148,7 +158,8 @@ ...@@ -148,7 +158,8 @@
this.updateLastMsg(msgList[msgLength - 1]) this.updateLastMsg(msgList[msgLength - 1])
}) })
} }
msgList = msgList.filter(i=>i.isDelete !== true) msgList = msgList.filter(i => i.isDelete !== true)
this.visibleMsgLength = msgList.length
// 将msgList存储到本地缓存中 // 将msgList存储到本地缓存中
uni.setStorage({ uni.setStorage({
"key": "uni-ai-msg", "key": "uni-ai-msg",
...@@ -158,20 +169,20 @@ ...@@ -158,20 +169,20 @@
// 深度监听msgList变化 // 深度监听msgList变化
deep: true deep: true
}, },
llmModel(llmModel){ llmModel(llmModel) {
let title = 'uni-ai-chat' let title = 'uni-ai-chat'
if(llmModel){ if (llmModel) {
title += ` (${llmModel})` title += ` (${llmModel})`
} }
uni.setNavigationBarTitle({title}) // uni.setNavigationBarTitle({title})
// #ifdef H5 // #ifdef H5
if(this.isWidescreen){ if (this.isWidescreen) {
document.querySelector('.header').innerText = title document.querySelector('.header').innerText = title
} }
// #endif // #endif
uni.setStorage({ uni.setStorage({
key:'uni-ai-chat-llmModel', key: 'uni-ai-chat-llmModel',
data:llmModel data: llmModel
}) })
} }
}, },
...@@ -186,7 +197,6 @@ ...@@ -186,7 +197,6 @@
// #endif // #endif
}, },
async mounted() { async mounted() {
// 如果存在广告位id且用户token未过期 // 如果存在广告位id且用户token未过期
if (this.adpid && uniCloud.getCurrentUserInfo().tokenExpired > Date.now()) { if (this.adpid && uniCloud.getCurrentUserInfo().tokenExpired > Date.now()) {
// 查询当前用户的积分 // 查询当前用户的积分
...@@ -233,7 +243,6 @@ ...@@ -233,7 +243,6 @@
} }
} }
// this.msgList.pop() // this.msgList.pop()
// console.log('this.msgList', this.msgList); // console.log('this.msgList', this.msgList);
...@@ -257,9 +266,9 @@ ...@@ -257,9 +266,9 @@
if (e.keyCode == 13 && !adjunctKeydown) { if (e.keyCode == 13 && !adjunctKeydown) {
e.preventDefault() e.preventDefault()
// 执行发送 // 执行发送
setTimeout(()=>{ setTimeout(() => {
this.beforeSendMsg(); this.beforeSendMsg();
},300) }, 300)
} }
}; };
textareaDom.onkeyup = e => { textareaDom.onkeyup = e => {
...@@ -268,13 +277,47 @@ ...@@ -268,13 +277,47 @@
adjunctKeydown = false; adjunctKeydown = false;
} }
}; };
// 可视窗口高
let initialInnerHeight = window.innerHeight;
if (uni.getSystemInfoSync().platform == "ios") {
textareaDom.addEventListener('focus', () => {
let interval = setInterval(function() {
if (window.innerHeight !== initialInnerHeight) {
clearInterval(interval)
// 触发相应的回调函数
document.querySelector('.container').style.height = window.innerHeight + 'px'
window.scrollTo(0, 0);
this.showLastMsg()
}
}, 1);
})
textareaDom.addEventListener('blur', () => {
document.querySelector('.container').style.height = initialInnerHeight + 'px'
})
}else{
window.addEventListener('resize',(e)=>{
this.showLastMsg()
})
}
} }
// #endif // #endif
// #ifndef H5
uni.onKeyboardHeightChange(e => {
this.keyboardHeight = e.height
// 在dom渲染完毕后 使聊天窗口滚动到最后一条消息
this.$nextTick(() => {
this.showLastMsg()
})
})
// #endif
}, },
methods: { methods: {
setLLMmodel(){ setLLMmodel() {
this.$refs['llm-config'].open(model=>{ this.$refs['llm-config'].open(model => {
console.log('model',model); console.log('model', model);
this.llmModel = model this.llmModel = model
}) })
}, },
...@@ -313,6 +356,20 @@ ...@@ -313,6 +356,20 @@
} }
this.msgList.splice(length - 1, 1, lastMsg) this.msgList.splice(length - 1, 1, lastMsg)
}, },
setSummarize(summarizeData) {
// console.log('setSummarize');
let length = this.msgList.length;
let index = length - 2
// 从 v1.1.0起,总结可能是总结倒数第二条之前的内容
if (index < 0) {
index = 0
}
let msg = this.msgList[index]
msg.summarize = summarizeData
this.msgList.splice(index, 1, msg)
// console.log('setSummarize this.msgList',this.msgList);
},
// 广告关闭事件 // 广告关闭事件
onAdClose(e) { onAdClose(e) {
console.log('onAdClose e.detail.isEnded', e.detail.isEnded); console.log('onAdClose e.detail.isEnded', e.detail.isEnded);
...@@ -370,9 +427,9 @@ ...@@ -370,9 +427,9 @@
this.send() this.send()
}, },
// 换一个答案 // 换一个答案
async changeAnswer(){ async changeAnswer() {
// 如果问题还在回答中需要先关闭 // 如果问题还在回答中需要先关闭
if(this.sseIndex){ if (this.sseIndex) {
this.closeSseChannel() this.closeSseChannel()
} }
...@@ -381,32 +438,31 @@ ...@@ -381,32 +438,31 @@
// 防止 偶发答案涉及敏感,重复回答时。提问内容 被卡掉无法重新问 // 防止 偶发答案涉及敏感,重复回答时。提问内容 被卡掉无法重新问
this.updateLastMsg({ this.updateLastMsg({
illegal:false illegal: false
}) })
this.send() this.send()
}, },
removeMsg(index){ removeMsg(index) {
// #ifdef VUE3 // #ifdef VUE3
this.msgList[index].isDelete = true this.msgList[index].isDelete = true
if(this.msgList[index].isAi && this.msgList[index - 1]){ if (this.msgList[index].isAi && this.msgList[index - 1]) {
this.msgList[index - 1].isDelete = true this.msgList[index - 1].isDelete = true
}else if(this.msgList[index + 1]){ } else if (this.msgList[index + 1]) {
this.msgList[index + 1].isDelete = true this.msgList[index + 1].isDelete = true
} }
// #endif // #endif
// #ifdef VUE2 // #ifdef VUE2
this.$set(msgList[index],"isDelete",true) this.$set(msgList[index], "isDelete", true)
msgList.slice(index,1,msgList[index]) if (msgList[index].isAi && msgList[index - 1]) {
if(msgList[index].isAi && msgList[index - 1]){ this.$set(msgList[index - 1], "isDelete", true)
this.$set(msgList[index - 1],"isDelete",true) } else if (msgList[index + 1]) {
}else if(msgList[index + 1]){ this.$set(msgList[index + 1], "isDelete", true)
this.$set(msgList[index + 1],"isDelete",true)
} }
// #endif // #endif
}, },
async beforeSendMsg() { async beforeSendMsg() {
if(this.inputBoxDisabled){ if (this.inputBoxDisabled) {
return uni.showToast({ return uni.showToast({
title: 'ai正在回复中不能发送', title: 'ai正在回复中不能发送',
icon: 'none' icon: 'none'
...@@ -496,7 +552,7 @@ ...@@ -496,7 +552,7 @@
let messages = [] let messages = []
// 复制一份,消息列表数据 // 复制一份,消息列表数据
let msgs = msgList.filter(i=>i.isDelete !== true) 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)
...@@ -570,6 +626,11 @@ ...@@ -570,6 +626,11 @@
// console.log('on end', e); // console.log('on end', e);
// 如果e存在且包含summarize或insufficientScore属性 // 如果e存在且包含summarize或insufficientScore属性
if (e) { if (e) {
// 如果e包含summarize属性
if (e.summarize) {
// 设置总结
this.setSummarize(e.summarize)
}else{
// 更新最后一条消息 // 更新最后一条消息
this.updateLastMsg(lastMsg => { this.updateLastMsg(lastMsg => {
// 如果e包含illegal属性 // 如果e包含illegal属性
...@@ -580,11 +641,6 @@ ...@@ -580,11 +641,6 @@
// 倒数第二条(用户发问内容)也需要设置illegal的值 // 倒数第二条(用户发问内容)也需要设置illegal的值
this.msgList[this.msgList.length - 2].illegal = e.illegal this.msgList[this.msgList.length - 2].illegal = e.illegal
} }
// 如果e包含summarize属性
else if (e.summarize) {
// 将最后一条消息的summarize属性更新为e的summarize属性
lastMsg.summarize = e.summarize
}
// 如果e包含insufficientScore属性 // 如果e包含insufficientScore属性
else if (e.insufficientScore) { else if (e.insufficientScore) {
// 将最后一条消息的insufficientScore属性更新为e的insufficientScore属性 // 将最后一条消息的insufficientScore属性更新为e的insufficientScore属性
...@@ -592,6 +648,7 @@ ...@@ -592,6 +648,7 @@
} }
}) })
} }
}
// 结束流式响应 将流式响应计数值 设置为 0 // 结束流式响应 将流式响应计数值 设置为 0
this.sseIndex = 0 this.sseIndex = 0
...@@ -603,17 +660,17 @@ ...@@ -603,17 +660,17 @@
// 导入uni-ai-chat模块,并设置customUI为true // 导入uni-ai-chat模块,并设置customUI为true
let task = uniCoTask({ let task = uniCoTask({
coName:"uni-ai-chat", coName: "uni-ai-chat",
funName:"send", funName: "send",
param:[{ param: [{
messages, // 消息列表 messages, // 消息列表
sseChannel, // 消息通道 sseChannel, // 消息通道
llmModel:this.llmModel llmModel: this.llmModel
}], }],
config:{ config: {
customUI: true customUI: true
}, },
success:res => { success: res => {
// console.log(111,res); // console.log(111,res);
if (!sseChannel) { if (!sseChannel) {
if (!res.data) { if (!res.data) {
...@@ -644,13 +701,15 @@ ...@@ -644,13 +701,15 @@
isAi: true, isAi: true,
// 添加消息内容 // 添加消息内容
content, content,
// 添加消息总结
summarize,
// 添加消息分数不足标记 // 添加消息分数不足标记
insufficientScore, insufficientScore,
// 添加消息涉敏标记 // 添加消息涉敏标记
illegal illegal
}) })
// 如果回调包含总结的内容,就设置总结
if(summarize){
this.setSummarize(summarize)
}
// 滚动窗口以显示最新的一条消息 // 滚动窗口以显示最新的一条消息
this.$nextTick(() => { this.$nextTick(() => {
this.showLastMsg() this.showLastMsg()
...@@ -661,7 +720,7 @@ ...@@ -661,7 +720,7 @@
this.sseIndex = 0 this.sseIndex = 0
} }
}, },
fail:e => { fail: e => {
console.log(e); console.log(e);
// 获取消息列表长度 // 获取消息列表长度
let l = this.msgList.length let l = this.msgList.length
...@@ -686,9 +745,9 @@ ...@@ -686,9 +745,9 @@
}) })
uniCoTaskList.push(task) uniCoTaskList.push(task)
}, },
closeSseChannel(){ closeSseChannel() {
// 如果存在消息通道,就关闭消息通道 // 如果存在消息通道,就关闭消息通道
if(sseChannel){ if (sseChannel) {
sseChannel.close() sseChannel.close()
sseChannel = false sseChannel = false
} }
...@@ -737,26 +796,31 @@ ...@@ -737,26 +796,31 @@
/* #endif */ /* #endif */
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
.container *,
view, view,
textarea, textarea,
button, button {
.page {
display: flex; display: flex;
box-sizing: border-box; box-sizing: border-box;
} }
page {
height: 100%;
width: 100%;
}
/* #endif */ /* #endif */
.stop-responding { .stop-responding {
font-size: 14px; font-size: 14px;
border-radius: 3px; border-radius: 3px;
margin-bottom:15px; margin-bottom: 15px;
background-color: #f0b00a; background-color: #f0b00a;
color: #FFF; color: #FFF;
width: 90px; width: 90px;
height: 30px; height: 30px;
line-height: 30px; line-height: 30px;
margin:0 auto; margin: 0 auto;
justify-content: center; justify-content: center;
margin-bottom: 15px; margin-bottom: 15px;
/* #ifdef H5 */ /* #ifdef H5 */
...@@ -764,41 +828,19 @@ ...@@ -764,41 +828,19 @@
/* #endif */ /* #endif */
} }
.stop-responding:hover{ .stop-responding:hover {
box-shadow: 0 0 10px #aaa; box-shadow: 0 0 10px #aaa;
} }
/* #ifndef APP-NVUE */
page,
/* #endif */
.page,
.container { .container {
background-color: #efefef; height: 100%;
background-color: #FAFAFA;
/* #ifdef APP-NVUE */
flex: 1;
/* #endif */
/* #ifndef APP-NVUE */
height: 100vh;
/* #endif */
/* #ifdef H5 */
height: calc(100vh - 44px);
/* #endif */
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
// border: 1px solid blue;
} }
/* #ifndef APP-NVUE */
.container {
background-color: #FAFAFA;
}
/* #endif */
.foot-box { .foot-box {
width: 750rpx; width: 750rpx;
display: flex; display: flex;
...@@ -859,9 +901,10 @@ ...@@ -859,9 +901,10 @@
align-items: center; align-items: center;
flex-shrink: 0; flex-shrink: 0;
} }
.menu-item{
.menu-item {
width: 30rpx; width: 30rpx;
margin:0 10rpx; margin: 0 10rpx;
} }
.send { .send {
...@@ -883,9 +926,10 @@ ...@@ -883,9 +926,10 @@
.msg-list { .msg-list {
height: 0; //不可省略,先设置为0 再由flex: 1;撑开才是一个滚动容器
flex: 1; flex: 1;
height: 1px;
width: 750rpx; width: 750rpx;
// border: 1px solid red;
} }
.noData { .noData {
...@@ -916,17 +960,11 @@ ...@@ -916,17 +960,11 @@
border-top: solid 1px #dde0e2; border-top: solid 1px #dde0e2;
} }
.page { .container * {
width: 100vw;
flex-direction: row;
}
.page * {
max-width: 950px; max-width: 950px;
} }
.container .container {
{
box-shadow: 0 0 5px #e0e1e7; box-shadow: 0 0 5px #e0e1e7;
margin-top: 44px; margin-top: 44px;
border-radius: 10px; border-radius: 10px;
...@@ -1026,6 +1064,15 @@ ...@@ -1026,6 +1064,15 @@
line-height: 28px; line-height: 28px;
} }
} }
/* #endif */ /* #endif */
.retries-box{
justify-content: center;
align-items: center;
font-size: 12px;
color: #d2071b;
}
.retries-icon{
margin-top: 1px;
margin-left: 5px;
}
</style> </style>
\ No newline at end of file
...@@ -191,8 +191,6 @@ module.exports = { ...@@ -191,8 +191,6 @@ module.exports = {
// 返回处理后的结果 // 返回处理后的结果
return result return result
}, },
// 发送消息 // 发送消息
async send({ async send({
// 消息内容 // 消息内容
...@@ -226,6 +224,31 @@ module.exports = { ...@@ -226,6 +224,31 @@ module.exports = {
} }
chatCompletionOptions.model = llmModel chatCompletionOptions.model = llmModel
} }
// 判断是否需要总结,如果需要就开始总结
// 计算消息总长度,判断是否需要总结
let needSummarize = messages.map(i => i.content).join('').length > 50,
// 总结的内容默认为 false 表示没有内容或者暂未拿到
summarizeData = false,
//成功拿到总结内容的回调函数列表
getSummarizeCallbackList = []
console.log('needSummarize',needSummarize);
if (needSummarize) {
// 获取总结
let replySummarize = getSummarize(messages)
.then((replySummarize)=>{
// console.log('replySummarize1',replySummarize);
summarizeData = replySummarize
getSummarizeCallbackList.forEach(fun=>fun())
})
.catch((error)=>{
// 抛出错误
throw error
})
}
return await chatCompletion({ return await chatCompletion({
messages, //消息内容 messages, //消息内容
sseChannel, //sse渠道对象 sseChannel, //sse渠道对象
...@@ -247,6 +270,7 @@ module.exports = { ...@@ -247,6 +270,7 @@ module.exports = {
// 获取语言模型管理器 // 获取语言模型管理器
const llmManager = uniCloud.ai.getLLMManager(llm) const llmManager = uniCloud.ai.getLLMManager(llm)
// 调用chatCompletion方法,传入参数 // 调用chatCompletion方法,传入参数
// console.log('______messages',messages);
let res = await llmManager.chatCompletion({ let res = await llmManager.chatCompletion({
...chatCompletionOptions, ...chatCompletionOptions,
messages, messages,
...@@ -290,19 +314,27 @@ module.exports = { ...@@ -290,19 +314,27 @@ module.exports = {
// 计算消息总长度 // 计算消息总长度
let totalTokens = messages.map(i => i.content).join('').length; let totalTokens = messages.map(i => i.content).join('').length;
// console.log('totalTokens',totalTokens); // console.log('totalTokens',totalTokens);
// 如果不需要总结且消息总长度超过500
if (!summarize && totalTokens > 500) { // 判断:是否有‘总结’需要带上
// 获取总结 if(needSummarize){
let replySummarize = await getSummarize(messages) if(!summarizeData){
// console.log('replySummarize',replySummarize) // 如果需要等待
await new Promise((reject,resolve)=>{
getSummarizeCallbackList.push(reject)
})
// console.log('等到了总结',summarizeData);
} else{
// console.log('直接拿到总结',summarizeData);
}
// 结束sseChannel并返回总结 // 结束sseChannel并返回总结
await channel.end({ await channel.end({
summarize: replySummarize "summarize": summarizeData
}) })
} else { }else{
// 结束sseChannel // 结束sseChannel
await channel.end() await channel.end()
} }
// 返回处理结果 // 返回处理结果
resolve({ resolve({
errCode: 0 errCode: 0
...@@ -326,21 +358,26 @@ module.exports = { ...@@ -326,21 +358,26 @@ module.exports = {
}) })
}) })
} else { } else {
// 如果不需要总结 // 如果 不是正在总结
if (summarize == false) { if (summarize == false) {
// 将回复内容添加到消息列表中 // 将回复内容添加到消息列表中
messages.push({ messages.push({
"content": res.reply, "content": res.reply,
"role": "assistant" "role": "assistant"
}) })
// 计算消息总长度
let totalTokens = messages.map(i => i.content).join('').length; // 判断:是否有‘总结’需要带上
// 如果消息总长度超过500 if(needSummarize){
if (totalTokens > 500) { if(!summarizeData){
// 获取总结 // 如果需要等待
let replySummarize = await getSummarize(messages) await new Promise((reject,resolve)=>{
// 将总结添加到返回结果中 getSummarizeCallbackList.push(reject)
res.summarize = replySummarize })
// console.log('等到了总结',summarizeData);
}else{
// console.log('直接拿到总结',summarizeData);
}
res.summarize = summarizeData
} }
} }
// 如果存在错误 // 如果存在错误
...@@ -359,23 +396,32 @@ module.exports = { ...@@ -359,23 +396,32 @@ module.exports = {
//获总结 //获总结
async function getSummarize(messages) { async function getSummarize(messages) {
messages.push({ let _messages = [...messages]
_messages.push({
"content": "请简要总结上述全部对话", "content": "请简要总结上述全部对话",
"role": "user" "role": "user"
}) })
// 调用chatCompletion函数,传入messages、summarize、stream、sseChannel参数 // 调用chatCompletion函数,传入messages、summarize、stream、sseChannel参数
let res = await chatCompletion({ let res = await chatCompletion({
// 消息内容 // 消息内容
messages, messages:_messages,
// 是否需要总结 // 是否需要总结
summarize: true, summarize: true,
// 是否需要流式返回 // 是否需要流式返回
stream: false, stream: false,
// sse渠道对象 // sse渠道对象
sseChannel: false sseChannel: false ,
// 大语言模型配置
llm
}) })
//故意延迟看看,总结比答案晚,是否成功进入等的逻辑
//function sleep(time) { return new Promise(resolve => setTimeout(resolve, time)); }
// await sleep(10000)
// console.log('getSummarize',res);
// 返回总结的文字内容 // 返回总结的文字内容
return res.reply return res.data.reply
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册