635 lines
16 KiB
JavaScript
635 lines
16 KiB
JavaScript
import {
|
||
doRequest,
|
||
SERVER_WSS_HOST,
|
||
systemInfo,
|
||
sid_prefix
|
||
} from "../../config"
|
||
|
||
const initHeight = inputPop() ? 22 : 5
|
||
// 是否使用websocket请求
|
||
var useWebsocket = true
|
||
try {
|
||
var notuseWebsocket = wx.getStorageSync("notuseWebsocket")
|
||
if (notuseWebsocket) {
|
||
useWebsocket = false
|
||
}
|
||
} catch (e) {
|
||
useWebsocket = true
|
||
}
|
||
|
||
function inputPop() {
|
||
return systemInfo.platform == "ios" || systemInfo.platform == "android"
|
||
}
|
||
// 自增对话
|
||
var autoIncrConversation = 0
|
||
|
||
// 默认采用new bing
|
||
var chatType = "bing"
|
||
try {
|
||
if (wx.getStorageSync("usechatgpt")) {
|
||
chatType = "chatgpt"
|
||
}
|
||
} catch (e) {
|
||
chatType = "bing"
|
||
}
|
||
|
||
Date.prototype.format = function (fmt) {
|
||
var o = {
|
||
"M+": this.getMonth() + 1, //月份
|
||
"d+": this.getDate(), //日
|
||
"h+": this.getHours(), //小时
|
||
"m+": this.getMinutes(), //分
|
||
"s+": this.getSeconds(), //秒
|
||
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
|
||
S: this.getMilliseconds(), //毫秒
|
||
}
|
||
if (/(y+)/.test(fmt)) {
|
||
fmt = fmt.replace(
|
||
RegExp.$1,
|
||
(this.getFullYear() + "").substr(4 - RegExp.$1.length)
|
||
)
|
||
}
|
||
for (var k in o) {
|
||
if (new RegExp("(" + k + ")").test(fmt)) {
|
||
fmt = fmt.replace(
|
||
RegExp.$1,
|
||
RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length)
|
||
)
|
||
}
|
||
}
|
||
return fmt
|
||
}
|
||
|
||
function getNow() {
|
||
return new Date().format("yyyy-MM-dd hh:mm:ss")
|
||
}
|
||
|
||
const app = getApp()
|
||
const robAvatar = "../../image/bing-avatar.png"
|
||
const personAvatar = "../../image/person.jpeg"
|
||
|
||
Page({
|
||
data: {
|
||
inputBottom: initHeight,
|
||
content: "",
|
||
lastContent: "",
|
||
systemInfo: systemInfo,
|
||
textareaFocus: false,
|
||
searching: false,
|
||
socket: {
|
||
socket: null,
|
||
isOpen: false,
|
||
},
|
||
useWebsocket: useWebsocket,
|
||
showSearchPop: false,
|
||
searchPopMessage: "",
|
||
chatType: chatType,
|
||
},
|
||
inputFocus(e) {
|
||
if (inputPop()) {
|
||
this.setData({
|
||
inputBottom: e.detail.height,
|
||
})
|
||
}
|
||
},
|
||
inputBlur(e) {
|
||
this.setData({
|
||
inputBottom: initHeight,
|
||
textareaFocus: false,
|
||
})
|
||
},
|
||
processContent(content) {
|
||
return content.replace(/\\n/g, "\n").replace(/\[\^\d+\^\]/g, "")
|
||
},
|
||
resetConversation: function (callback) {
|
||
app.getSid(sid => {
|
||
doRequest("/reset", "GET", {
|
||
sid: sid_prefix + sid,
|
||
}).then(res => {
|
||
if (callback) {
|
||
callback(res)
|
||
}
|
||
})
|
||
})
|
||
},
|
||
getOptions: function () {
|
||
var pages = getCurrentPages()
|
||
var currentPage = pages[pages.length - 1]
|
||
return currentPage.options
|
||
},
|
||
onPopButtonClick: function (e) {
|
||
if (e.detail.t === "confirm") {
|
||
this.submitContent(e.currentTarget.dataset.q)
|
||
}
|
||
this.setData({
|
||
showSearchPop: false,
|
||
q: ""
|
||
})
|
||
},
|
||
onShow() {
|
||
var options = this.getOptions()
|
||
if (options && options["q"]) {
|
||
var q = decodeURIComponent(options["q"])
|
||
var chatType = this.data.chatType
|
||
if (options["chatType"]) {
|
||
chatType = options["chatType"]
|
||
// 聊天方式不同,关闭websocket
|
||
if (chatType != this.data.chatType) {
|
||
this.onCancelReceive()
|
||
}
|
||
}
|
||
this.setData({
|
||
searchPopMessage: "即将搜索“" + q + "”",
|
||
showSearchPop: true,
|
||
q: q,
|
||
chatType: chatType,
|
||
})
|
||
}
|
||
// 切换title
|
||
this.switchTitle()
|
||
},
|
||
switchTitle: function () {
|
||
if (this.data.chatType == "bing") {
|
||
wx.setNavigationBarTitle({
|
||
title: "New Bing 🤖️",
|
||
})
|
||
} else {
|
||
wx.setNavigationBarTitle({
|
||
title: "ChatGPT 🤖️",
|
||
})
|
||
}
|
||
},
|
||
scrollBottom: function () {
|
||
const cht = app.globalData.cht
|
||
if (cht.data.chatList.length > 1 && !this.data.textareaFocus) {
|
||
cht.setData({
|
||
scrollId: "item" + (cht.data.chatList.length - 2),
|
||
})
|
||
}
|
||
},
|
||
onLoad() {
|
||
const cht = app.globalData.cht
|
||
setTimeout(() => {
|
||
if (cht.data.chatList.length > 1) {
|
||
cht.setData({
|
||
scrollId: "item" + (cht.data.chatList.length - 2),
|
||
})
|
||
}
|
||
}, 1500)
|
||
},
|
||
processData: function (data, suggests, content) {
|
||
var robContent = data["data"]["status"]
|
||
if (robContent == "Success") {
|
||
robContent = data["data"]["text"]
|
||
suggests.push(...data["data"]["suggests"])
|
||
if (robContent.indexOf("New topic") != -1 && this.data.chatType == "bing") {
|
||
robContent += "\n发送“重新对话!”开始新的对话"
|
||
suggests.push("重新对话!")
|
||
suggests.push(content)
|
||
}
|
||
} else {
|
||
if (robContent == "Throttled") {
|
||
robContent = "这真是愉快,但你已达到每日限制。是否明天再聊?"
|
||
suggests.push("重新对话!")
|
||
suggests.push(content)
|
||
} else {
|
||
var msg = data["data"]["message"]
|
||
if (msg.indexOf("has expired") != -1) {
|
||
this.resetConversation()
|
||
robContent = "本轮对话已过期,请重新开始。"
|
||
suggests.push(content)
|
||
} else {
|
||
robContent = "抱歉😭,发生错误:" + msg
|
||
if (this.data.chatType == "bing") {
|
||
suggests.push("重新对话!")
|
||
}
|
||
suggests.push(content)
|
||
}
|
||
}
|
||
}
|
||
return robContent
|
||
},
|
||
sendWSRequest: function (content) {
|
||
var that = this
|
||
app.getSid(sid => {
|
||
that.sendSocketMessage({
|
||
"q": content,
|
||
"sid": sid_prefix + sid,
|
||
"t": new Date().getTime()
|
||
})
|
||
})
|
||
},
|
||
sendHttpRequest: function (content) {
|
||
var that = this
|
||
const cht = app.globalData.cht
|
||
var api = that.data.chatType == "bing" ? "/chat" : "/openai_chat"
|
||
app.getSid(sid => {
|
||
doRequest(api, "POST", {
|
||
q: content,
|
||
sid: sid_prefix + sid,
|
||
}).then(res => {
|
||
try {
|
||
var robContent = ""
|
||
var suggests = []
|
||
var num_in_conversation = -1
|
||
if (res.statusCode != 200) {
|
||
robContent =
|
||
"抱歉😭,网络异常,请稍后重试 [" + res.statusCode + "]"
|
||
suggests.push(content)
|
||
} else {
|
||
robContent = that.processData(res.data, suggests, content)
|
||
num_in_conversation = res.data["data"]["num_in_conversation"]
|
||
}
|
||
that.pushStorageMessage(cht, robContent, "rob", suggests, false, true, num_in_conversation)
|
||
} catch (error) {
|
||
wx.showToast({
|
||
title: "fatal error",
|
||
icon: "error"
|
||
})
|
||
that.pushStorageMessage(cht, "发生致命错误😱", "rob", [], false, true)
|
||
}
|
||
}).catch(e => {
|
||
that.pushStorageMessage(cht, e.errMsg, "rob", [], false, true)
|
||
})
|
||
})
|
||
},
|
||
submitContent: function (content) {
|
||
if (this.data.searching) {
|
||
wx.showToast({
|
||
title: "请等待完成",
|
||
icon: "error"
|
||
})
|
||
return
|
||
} else {
|
||
this.setData({
|
||
searching: true
|
||
})
|
||
}
|
||
var that = this
|
||
const cht = app.globalData.cht
|
||
that.pushStorageMessage(cht, content, "man", [], false)
|
||
that.setData({
|
||
content: "",
|
||
lastContent: content,
|
||
})
|
||
if (content == "重新对话!" && that.data.chatType == "bing") {
|
||
that.resetConversation(() => {
|
||
that.pushStorageMessage(cht, "现在我们可以开始新的对话😊", "rob", [], false)
|
||
})
|
||
return
|
||
} else {
|
||
that.pushStorageMessage(cht, "搜索中🔍...", "rob", [], true, false, -1, false)
|
||
}
|
||
if (that.data.useWebsocket) {
|
||
that.sendWSRequest(content)
|
||
} else {
|
||
that.sendHttpRequest(content)
|
||
}
|
||
},
|
||
pushStorageMessage: function (cht, content, role, suggests, blink, pop, num_in_conversation = -1, final = true) {
|
||
if (pop) {
|
||
cht.data.chatList.pop()
|
||
}
|
||
var rAvatar = this.data.chatType == "bing" ? robAvatar : "../../image/chatgpt.png"
|
||
cht.data.chatList.push({
|
||
type: role,
|
||
avatarUrl: role == "rob" ? rAvatar : personAvatar,
|
||
dt: getNow(),
|
||
originContent: this.processContent(content),
|
||
suggests: suggests,
|
||
blink: blink,
|
||
num_in_conversation: num_in_conversation,
|
||
})
|
||
autoIncrConversation += 1
|
||
cht.setData({
|
||
chatList: cht.data.chatList,
|
||
autoIncrConversation: autoIncrConversation,
|
||
})
|
||
if (role == "rob" && !blink && final) {
|
||
this.setData({
|
||
searching: false
|
||
})
|
||
}
|
||
// 只保留最新的10条
|
||
wx.setStorage({
|
||
key: "chatList",
|
||
data: cht.data.chatList.slice(cht.data.chatList.length - 10),
|
||
})
|
||
if (final) {
|
||
app.upload_conversation(cht.data.chatList.slice(cht.data.chatList.length - 1))
|
||
}
|
||
setTimeout(() => {
|
||
cht.setData({
|
||
scrollId: "item" + (autoIncrConversation + "9999"),
|
||
})
|
||
}, 100)
|
||
},
|
||
submit() {
|
||
var content = this.data.content
|
||
if (content.length == 0 || content.trim().length == 0) {
|
||
return
|
||
}
|
||
this.submitContent(content)
|
||
},
|
||
onShareAppMessage() {
|
||
var title = this.data.chatType == "bing" ? "New Bing 🤖" : "ChatGPT 🤖️"
|
||
var content = this.data.content.trim()
|
||
if (content.length > 0) {
|
||
title = content
|
||
} else {
|
||
var cache = wx.getStorageSync("shareContent")
|
||
if (cache) {
|
||
if (cache["validTime"] > (new Date()).getTime()) {
|
||
content = cache["q"]
|
||
title = content
|
||
wx.removeStorage({
|
||
key: "shareContent",
|
||
})
|
||
}
|
||
}
|
||
}
|
||
return {
|
||
title: title,
|
||
path: "/pages/index/index?q=" + encodeURIComponent(content) + "&chatType=" + this.data.chatType,
|
||
imageUrl: this.data.chatType == "bing" ? "../../image/newBing.png" : "../../image/chatgpt_share.png"
|
||
}
|
||
},
|
||
onSuggestSubmit: function (e) {
|
||
var suggest = e.detail.suggest
|
||
this.submitContent(suggest)
|
||
},
|
||
focus: function (e) {
|
||
this.setData({
|
||
textareaFocus: true
|
||
})
|
||
},
|
||
openSocket(callback) {
|
||
if (this.data.socket.isOpen) {
|
||
return
|
||
}
|
||
var that = this
|
||
const cht = app.globalData.cht
|
||
var apiPath = that.data.chatType == "bing" ? "/chat" : "/ws_openai_chat"
|
||
const socket = wx.connectSocket({
|
||
url: SERVER_WSS_HOST + apiPath,
|
||
fail: function () {
|
||
wx.showToast({
|
||
title: "打开websocket失败",
|
||
icon: "none",
|
||
})
|
||
}
|
||
})
|
||
socket.onOpen(() => {
|
||
console.log("Socket onOpen", socket)
|
||
if (socket.readyState == 1) {
|
||
that.setData({
|
||
socket: {
|
||
socket: socket,
|
||
isOpen: true
|
||
}
|
||
})
|
||
setTimeout(() => {
|
||
if (callback) {
|
||
callback()
|
||
}
|
||
}, 50)
|
||
}
|
||
})
|
||
socket.onClose((code, reason) => {
|
||
console.log("Socket onClose", code, reason)
|
||
that.setData({
|
||
socket: {
|
||
socket: null,
|
||
isOpen: false
|
||
},
|
||
searching: false,
|
||
})
|
||
cht.setData({
|
||
receiveData: false
|
||
})
|
||
})
|
||
socket.onError(msg => {
|
||
console.log("Socket onError", msg)
|
||
that.setData({
|
||
socket: {
|
||
socket: null,
|
||
isOpen: false
|
||
},
|
||
searching: false
|
||
})
|
||
wx.showToast({
|
||
title: "网络异常 " + msg.errMsg,
|
||
icon: "none",
|
||
})
|
||
cht.setData({
|
||
receiveData: false
|
||
})
|
||
})
|
||
socket.onMessage(data => {
|
||
const cht = app.globalData.cht
|
||
var data = JSON.parse(data.data)
|
||
var suggests = []
|
||
var robContent = ""
|
||
var num_in_conversation = -1
|
||
if (!data["final"]) {
|
||
if (data["data"]["data"]) {
|
||
robContent = data["data"]["data"]["text"] + " ..."
|
||
} else {
|
||
robContent = data["data"] + " ..."
|
||
}
|
||
cht.setData({
|
||
receiveData: true
|
||
})
|
||
} else {
|
||
robContent = that.processData(data["data"], suggests, that.data.lastContent)
|
||
num_in_conversation = data["data"]["data"]["num_in_conversation"]
|
||
cht.setData({
|
||
receiveData: false
|
||
})
|
||
}
|
||
that.pushStorageMessage(cht, robContent, "rob", suggests, false, true, num_in_conversation, data["final"])
|
||
})
|
||
},
|
||
sendSocketMessage: function (data) {
|
||
if (!this.data.socket.isOpen) {
|
||
this.openSocket(() => {
|
||
this.data.socket.socket.send({
|
||
data: JSON.stringify(data),
|
||
fail: err => {
|
||
console.log(err)
|
||
wx.showToast({
|
||
title: "消息发送失败",
|
||
icon: "error",
|
||
})
|
||
}
|
||
})
|
||
})
|
||
} else {
|
||
this.data.socket.socket.send({
|
||
data: JSON.stringify(data),
|
||
fail: err => {
|
||
console.log(err)
|
||
wx.showToast({
|
||
title: "消息发送失败",
|
||
icon: "error",
|
||
})
|
||
}
|
||
})
|
||
}
|
||
},
|
||
onUnload: function () {
|
||
if (this.data.socket.isOpen) {
|
||
this.data.socket.socket.close({
|
||
code: 1000,
|
||
reason: "Page Unload"
|
||
})
|
||
}
|
||
},
|
||
inputData: function (e) {
|
||
var that = this
|
||
var value = e.detail.value
|
||
that.setData({
|
||
content: value
|
||
})
|
||
// 特定用户在桌面版本下触发提交,因为textarea在桌面版下回车是换行,并且无法监听快捷键输入,只能出此下策
|
||
if (systemInfo.platform != "windows" && systemInfo.platform != "mac") {
|
||
return
|
||
}
|
||
if (value.indexOf("》》》\n") != -1 || value.indexOf(">>>\n") != -1) {
|
||
that.setData({
|
||
content: value.replace("》》》\n", "").replace(">>>\n", ""),
|
||
}, () => {
|
||
that.submit()
|
||
})
|
||
}
|
||
},
|
||
onCancelReceive: function (e) {
|
||
if (this.data.socket.isOpen) {
|
||
this.data.socket.socket.close({
|
||
code: 1000,
|
||
reason: "User cancel"
|
||
})
|
||
}
|
||
},
|
||
switchRequestMethod: function (e) {
|
||
var that = this
|
||
if (this.data.useWebsocket) {
|
||
wx.setStorage({
|
||
key: "notuseWebsocket",
|
||
data: 1,
|
||
success: (res) => {
|
||
that.setData({
|
||
useWebsocket: false
|
||
})
|
||
wx.showToast({
|
||
title: "已切换成Https",
|
||
icon: "none"
|
||
})
|
||
}
|
||
})
|
||
} else {
|
||
wx.removeStorage({
|
||
key: "notuseWebsocket",
|
||
success: (res) => {
|
||
that.setData({
|
||
useWebsocket: true
|
||
})
|
||
wx.showToast({
|
||
title: "已切换成Websocket",
|
||
icon: "none"
|
||
})
|
||
}
|
||
})
|
||
}
|
||
},
|
||
deleteAllChat: function () {
|
||
const cht = app.globalData.cht
|
||
wx.showModal({
|
||
content: "是否删除全部聊天?",
|
||
complete: (res) => {
|
||
if (res.confirm) {
|
||
cht.setData({
|
||
chatList: [],
|
||
})
|
||
app.getSid(sid => {
|
||
doRequest("/delete_all", "POST", {
|
||
"sid": sid_prefix + sid
|
||
}).then(res => {
|
||
console.log("delete all")
|
||
})
|
||
})
|
||
}
|
||
},
|
||
})
|
||
},
|
||
longPress: function (e) {
|
||
var that = this
|
||
const cht = app.globalData.cht
|
||
wx.showActionSheet({
|
||
itemList: ["删除全部聊天记录", "切换聊天接口方式", that.data.chatType == "bing" ? "切换成ChatGPT" : "切换成New Bing", cht.data.closeShareOnCopy ? "打开复制后分享" : "关闭复制后分享"],
|
||
success(res) {
|
||
if (res.tapIndex == 0) {
|
||
that.deleteAllChat()
|
||
} else if (res.tapIndex == 1) {
|
||
that.switchRequestMethod()
|
||
} else if (res.tapIndex == 3) {
|
||
if (cht.data.closeShareOnCopy) {
|
||
cht.setData({
|
||
closeShareOnCopy: false,
|
||
})
|
||
wx.showToast({
|
||
title: "已打开复制后分享",
|
||
icon: "none"
|
||
})
|
||
wx.removeStorage({
|
||
key: "closeShareOnCopy",
|
||
})
|
||
} else {
|
||
cht.setData({
|
||
closeShareOnCopy: true,
|
||
})
|
||
wx.showToast({
|
||
title: "已关闭复制后分享",
|
||
icon: "none"
|
||
})
|
||
wx.setStorage({
|
||
key: "closeShareOnCopy",
|
||
data: 1,
|
||
})
|
||
}
|
||
} else if (res.tapIndex == 2) {
|
||
if (that.data.chatType == "chatgpt") {
|
||
wx.removeStorage({
|
||
key: "usechatgpt",
|
||
})
|
||
that.setData({
|
||
chatType: "bing",
|
||
})
|
||
wx.showToast({
|
||
title: "已切换成New Bing",
|
||
icon: "none"
|
||
})
|
||
} else {
|
||
wx.setStorage({
|
||
key: "usechatgpt",
|
||
data: 1,
|
||
})
|
||
that.setData({
|
||
chatType: "chatgpt",
|
||
})
|
||
wx.showToast({
|
||
title: "已切换成ChatGPT",
|
||
icon: "none"
|
||
})
|
||
}
|
||
}
|
||
// 关闭websocket
|
||
that.onCancelReceive()
|
||
setTimeout(() => {
|
||
that.switchTitle()
|
||
}, 100)
|
||
}
|
||
})
|
||
},
|
||
})
|