1
This commit is contained in:
292
pages/chat/index.js
Normal file
292
pages/chat/index.js
Normal file
@@ -0,0 +1,292 @@
|
||||
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)
|
||||
},
|
||||
})
|
||||
Reference in New Issue
Block a user