292 lines
6.4 KiB
JavaScript
292 lines
6.4 KiB
JavaScript
import request, { streamRequest } from "@/utils/request";
|
||
import { copyText } from "@/utils/common"
|
||
let outTimer; //输出定时器
|
||
let outStrList = [];//输出字符串数组
|
||
const app = getApp()
|
||
|
||
let chat_uuid
|
||
//工具
|
||
let toolText = ''
|
||
let toolInfo = {}
|
||
Page({
|
||
data: {
|
||
chatList: [], //会话记录
|
||
aiStatus: 3,//1表示接口响应中,2表示接口响应完毕,3表示完全输出完毕
|
||
keyboardBottom: 0, //底部键盘高度
|
||
scrollTop: 0, //滚动条位置
|
||
inputText: '',//输入框内容
|
||
},
|
||
onLoad() {
|
||
let str = `您好!我是术极守护AI助手 🤖\n\n我可以为您解答术后康复相关的问题。请注意,我只能提供基于康复指南的一般性建议,如遇紧急情况请立即就医或联系您的主治医生。`
|
||
let mdResult = app.towxml(str, 'markdown', {
|
||
base: "www.xxx.com",
|
||
});
|
||
let list = [
|
||
{
|
||
loading: false,
|
||
end: true,
|
||
chat_type: 2,
|
||
md_content: mdResult,
|
||
chat_content: str,
|
||
quick_btn: [
|
||
{ text: '🩹伤口有轻微渗液怎么办?' },
|
||
{ text: '🌡️术后轻微发烧正常吗?' },
|
||
{ text: '🚿什么时候可以洗澡?' },
|
||
{ text: '🥗饮食需要注意什么?' }
|
||
]
|
||
}
|
||
]
|
||
this.setData({
|
||
chatList: list
|
||
})
|
||
},
|
||
onShow() {
|
||
this.getTabBar((tabBar) => {
|
||
tabBar.setData({
|
||
selected: 'AI助手',
|
||
})
|
||
})
|
||
},
|
||
//监听键盘弹出
|
||
bindkeyboardheightchange(event) {
|
||
let height = event.detail.height
|
||
let { keyboardBottom } = this.data
|
||
let scrollTop = 0
|
||
//获取当前滚动距离
|
||
const query = wx.createSelectorQuery().in(this)
|
||
query.select(".silder").scrollOffset()
|
||
query.exec(function (res) {
|
||
scrollTop = res[0].scrollTop
|
||
})
|
||
this.setData({
|
||
keyboardBottom: height > 0 ? height - 50 : keyboardBottom,
|
||
}, () => {
|
||
if (height > 0) {
|
||
setTimeout(() => {
|
||
this.setData({
|
||
scrollTop: scrollTop + height
|
||
})
|
||
}, 300)
|
||
}
|
||
})
|
||
},
|
||
//键盘失去焦点
|
||
bindkeyboardBlur() {
|
||
let { scrollTop, keyboardBottom } = this.data
|
||
let endScrollTop = scrollTop - keyboardBottom
|
||
this.setData({
|
||
keyboardBottom: 0
|
||
}, () => {
|
||
this.setData({
|
||
scrollTop: endScrollTop
|
||
})
|
||
})
|
||
},
|
||
//监听输入框内容
|
||
changeInput(e) {
|
||
let value = e.detail.value
|
||
this.setData({
|
||
inputText: value
|
||
})
|
||
},
|
||
async handQuick(e) {
|
||
let { data } = e.currentTarget.dataset
|
||
this.pushUserTemplate(data.text)
|
||
this.sendMessage(data.text)
|
||
|
||
},
|
||
|
||
// 文字提交发送
|
||
submitInput() {
|
||
let { inputText, aiStatus } = this.data
|
||
if (!inputText.trim() == '' && aiStatus) {
|
||
console.log('111--');
|
||
this.pushUserTemplate(inputText)
|
||
this.sendMessage(inputText)
|
||
}
|
||
},
|
||
//发送聊天
|
||
async sendMessage(text) {
|
||
let { chatList, aiStatus } = this.data
|
||
if (aiStatus == 3) {
|
||
let that = this
|
||
//初始化变量
|
||
toolText = ''
|
||
toolInfo = {}
|
||
chat_uuid = String(new Date().getTime())
|
||
this.setData({
|
||
aiStatus: 1
|
||
})
|
||
//输出
|
||
this.timerOutput()
|
||
//请求
|
||
streamRequest("/ai/chat", {
|
||
message: text,
|
||
chat_uuid: chat_uuid,
|
||
}, this.onChunkReceived).then(() => {
|
||
console.log('-------------成功-----------');
|
||
if (this.data.aiStatus != 3) {
|
||
that.setData({
|
||
aiStatus: 2
|
||
})
|
||
}
|
||
}).catch(() => {
|
||
console.log("------失败1---------");
|
||
that.data.chatList.at(-1).loading = false
|
||
that.setData({
|
||
aiStatus: 3,
|
||
chatList: chatList
|
||
})
|
||
})
|
||
}
|
||
},
|
||
|
||
//填充用户的聊天数据
|
||
pushUserTemplate(text) {
|
||
let { chatList } = this.data
|
||
let userItem = {
|
||
loading: false,
|
||
chat_type: 1,
|
||
con_type: 1,
|
||
chat_content: text,
|
||
md_content: '',
|
||
}
|
||
let aiItem = {
|
||
chat_type: 2,
|
||
chat_content: '',
|
||
md_content: '',
|
||
con_type: 1,
|
||
loading: true,
|
||
}
|
||
chatList.push(userItem)
|
||
|
||
chatList.push(aiItem)
|
||
|
||
//要修改的数据
|
||
let setData = {
|
||
chatList,
|
||
scrollTop: 80000,
|
||
inputText: ''
|
||
}
|
||
this.setData(setData, () => {
|
||
this.setData({
|
||
scrollTop: 80000
|
||
})
|
||
})
|
||
},
|
||
//只填充ai的默认回复
|
||
pushAiTemplate(text, options = {}) {
|
||
let { chatList } = this.data
|
||
let mdResult = app.towxml(text, 'markdown', {
|
||
base: "www.xxx.com",
|
||
});
|
||
let aiItem = {
|
||
chat_type: 2,
|
||
chat_content: text,
|
||
md_content: mdResult,
|
||
con_type: 1,
|
||
quick_btn: options.quick_btn || [],
|
||
...options
|
||
}
|
||
chatList.push(aiItem)
|
||
//要修改的数据
|
||
let setData = {
|
||
chatList,
|
||
scrollTop: 80000,
|
||
inputText: ''
|
||
}
|
||
this.setData(setData, () => {
|
||
this.setData({
|
||
scrollTop: 80000
|
||
})
|
||
})
|
||
},
|
||
|
||
//定时器输出
|
||
timerOutput() {
|
||
let { chatList } = this.data
|
||
let that = this
|
||
clearInterval(outTimer)
|
||
outStrList = []
|
||
let lastChat = this.data.chatList.at(-1)
|
||
//定时
|
||
outTimer = setInterval(async () => {
|
||
if ((outStrList.length == 0) && that.data.aiStatus == 2) {
|
||
clearInterval(outTimer)
|
||
lastChat.end = true
|
||
//如果有工具,设置工具对象
|
||
let text = lastChat.chat_content
|
||
// 上传AI响应结果
|
||
if (text) {
|
||
await request.post("/ai/history/upload", {
|
||
chat_content: text,
|
||
chat_uuid: chat_uuid,
|
||
})
|
||
}
|
||
//调用工具
|
||
if (toolText) { }
|
||
that.setData({
|
||
chatList,
|
||
aiStatus: 3
|
||
})
|
||
|
||
} else if (outStrList.length > 0) {
|
||
let firstValue = outStrList.shift();
|
||
lastChat.chat_content += firstValue
|
||
//转换md
|
||
let mdResult = app.towxml(lastChat.chat_content, 'markdown', {
|
||
base: "www.xxx.com",
|
||
});
|
||
lastChat.md_content = mdResult
|
||
lastChat.loading = false
|
||
that.setData({
|
||
chatList: chatList,
|
||
scrollTop: 80000
|
||
})
|
||
}
|
||
}, 50)
|
||
},
|
||
//流回调
|
||
onChunkReceived(data) {
|
||
data.forEach((item) => {
|
||
let value = item?.choices[0].delta.content ?? ''
|
||
let call = item?.choices[0].delta.tool_calls
|
||
//储存tool的id和名称
|
||
if (call) {
|
||
if (call[0].id) {
|
||
toolInfo.tool_call_id = call[0].id
|
||
toolInfo.name = call[0].function.name
|
||
}
|
||
let tool = call[0].function.arguments ?? ''
|
||
toolText += tool
|
||
}
|
||
if (value) {
|
||
outStrList.push(value)
|
||
}
|
||
})
|
||
},
|
||
//停止
|
||
async stopMessage() {
|
||
clearInterval(outTimer)
|
||
let lastChat = this.data.chatList.at(-1)
|
||
lastChat.chat_status = 2
|
||
this.setData({
|
||
aiStatus: 3,
|
||
chatList: this.data.chatList
|
||
})
|
||
await request.post("/ai/history/upload", {
|
||
chat_content: lastChat.chat_content || 'nocontent',
|
||
chat_status: 2,
|
||
chat_uuid: chat_uuid
|
||
})
|
||
},
|
||
//复制文字
|
||
copy(e) {
|
||
let { content, chat_content } = e.currentTarget.dataset.text
|
||
console.log(e);
|
||
if (!content) {
|
||
content = chat_content
|
||
}
|
||
copyText(content)
|
||
},
|
||
}) |