diff --git a/bingchat/app.json b/bingchat/app.json index 097d91e..ba22b1d 100644 --- a/bingchat/app.json +++ b/bingchat/app.json @@ -2,22 +2,20 @@ "pages": [ "pages/index/index" ], - "useExtendedLib": { - "weui":true - }, "usingComponents": { - "chat-box":"components/chatbox/index" + "chat-box": "components/chatbox/index" }, "window": { "backgroundTextStyle": "light", "navigationBarBackgroundColor": "#ffffff", "navigationBarTitleText": "New Bing Bot 🤖", - "navigationBarTextStyle": "black" + "navigationBarTextStyle": "black" }, "sitemapLocation": "sitemap.json", "networkTimeout": { - "request": 1800000 - }, - "resizable": true, - "lazyCodeLoading": "requiredComponents" + "request": 900000, + "connectSocket": 900000 + }, + "resizable": true, + "lazyCodeLoading": "requiredComponents" } diff --git a/bingchat/config.js b/bingchat/config.js index fa73d96..85c1ae4 100644 --- a/bingchat/config.js +++ b/bingchat/config.js @@ -1,4 +1,5 @@ const SERVER_HOST = "https://example.com"; +const SERVER_WSS_HOST = "wss://example.com"; function doRequest(url, method = "GET", data = {}) { return new Promise((resolve, reject) => { @@ -20,5 +21,6 @@ function doRequest(url, method = "GET", data = {}) { } export { doRequest, - SERVER_HOST + SERVER_HOST, + SERVER_WSS_HOST } diff --git a/bingchat/pages/index/index.js b/bingchat/pages/index/index.js index 9212fc5..9efe43a 100644 --- a/bingchat/pages/index/index.js +++ b/bingchat/pages/index/index.js @@ -1,5 +1,6 @@ import { - doRequest + doRequest, + SERVER_WSS_HOST } from "../../config"; const systemInfo = wx.getSystemInfoSync() @@ -49,9 +50,14 @@ Page({ data: { InputBottom: initHeight, content: "", + lastContent: "", systemInfo: systemInfo, textareaFocus: false, searching: false, + socket: { + socket: null, + isOpen: false, + }, }, InputFocus(e) { if (inputPop()) { @@ -62,12 +68,12 @@ Page({ }, InputBlur(e) { this.setData({ - InputBottom: initHeight, - textareaFocus: false, + InputBottom: initHeight, + textareaFocus: false, }); }, processContent(content) { - return content.replace(/\\n/g, "\n"); + return content.replace(/\\n/g, "\n").replace(/\[\^\d+\^\]/g, ""); }, resetConversation: function (callback) { app.getSid(sid => { @@ -89,6 +95,77 @@ Page({ } }, onLoad() {}, + 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) { + robContent += "\n\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 + ",请重试"; + suggests.push(content); + } + } + } + return robContent + }, + sendWSRequest: function (content) { + var that = this + app.getSid(sid => { + that.sendSocketMessage({ + "q": content, + "sid": sid, + "t": new Date().getTime() + }) + }) + }, + sendHttpRequest: function (content) { + var that = this + const cht = app.globalData.cht; + app.getSid(sid => { + doRequest("/chat", "POST", { + q: content, + sid: 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", + }); + 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({ @@ -106,6 +183,7 @@ Page({ that.pushStorageMessage(cht, content, "man", [], false) that.setData({ content: "", + lastContent: content, }); if (content == "重新对话!") { that.resetConversation(() => { @@ -115,61 +193,10 @@ Page({ } else { that.pushStorageMessage(cht, "搜索中🔍...", "rob", [], true) } - app.getSid(sid => { - doRequest("/chat", "POST", { - q: content, - sid: 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 = res.data["data"]["status"]; - if (robContent == "Success") { - robContent = res.data["data"]["text"]; - suggests = res.data["data"]["suggests"]; - if (robContent.indexOf("New topic") != -1) { - robContent += "\n\n发送“重新对话!”开始新的对话"; - suggests.push("重新对话!"); - suggests.push(content); - } - num_in_conversation = res.data["data"]["num_in_conversation"]; - } else { - if (robContent == "Throttled") { - robContent = "这真是愉快,但你已达到每日限制。是否明天再聊?"; - suggests.push("重新对话!"); - suggests.push(content); - } else { - var msg = res.data["data"]["message"]; - if (msg.indexOf("has expired") != -1) { - that.resetConversation(); - robContent = "本轮对话已过期,请重新开始。"; - suggests.push(content); - } else { - robContent = "抱歉😭,发生错误:" + msg + ",请重试"; - suggests.push(content); - } - } - } - } - that.pushStorageMessage(cht, robContent, "rob", suggests, false, true, num_in_conversation) - } catch (error) { - wx.showToast({ - title: "fatal error", - }); - that.pushStorageMessage(cht, "发生致命错误😱", "rob", [], false, true) - } - }).catch(e => { - that.pushStorageMessage(cht, e.errMsg, "rob", [], false, true) - }) - }) + // that.sendHttpRequest(content) + that.sendWSRequest(content) }, - pushStorageMessage: function (cht, content, role, suggests, blink, pop, num_in_conversation = -1) { + pushStorageMessage: function (cht, content, role, suggests, blink, pop, num_in_conversation = -1, final = true) { if (pop) { cht.data.chatList.pop(); } @@ -185,7 +212,7 @@ Page({ cht.setData({ chatList: cht.data.chatList, }); - if (role == "rob" && !blink) { + if (role == "rob" && !blink && final) { this.setData({ searching: false }) @@ -221,5 +248,97 @@ Page({ this.setData({ textareaFocus: true }) + }, + openSocket(callback) { + if (this.data.socket.isOpen) { + return + } + var that = this + const socket = wx.connectSocket({ + url: SERVER_WSS_HOST + "/chat", + fail: function () { + wx.showToast({ + title: '打开websocket失败', + }) + } + }) + socket.onOpen(() => { + 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 + } + }) + }) + socket.onError(msg => { + console.log('Socket onError', msg) + that.setData({ + socket: { + socket: null, + isOpen: 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']) { + robContent = data['data'] + } else { + robContent = that.processData(data['data'], suggests, that.data.lastContent) + num_in_conversation = data['data']['data']['num_in_conversation'] + } + 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: '消息发送失败', + }) + } + }) + }) + } else { + this.data.socket.socket.send({ + data: JSON.stringify(data), + fail: err => { + console.log(err) + wx.showToast({ + title: '消息发送失败', + }) + } + }) + } + }, + onUnload: function () { + if (this.data.socket.isOpen) { + this.data.socket.socket.close({ + code: 1000, + reason: "Page Unload" + }) + } } -}); +}); \ No newline at end of file diff --git a/new-bing/app.py b/new-bing/app.py index 0757f37..5fe530c 100644 --- a/new-bing/app.py +++ b/new-bing/app.py @@ -1,5 +1,6 @@ # coding=utf-8 +import json as raw_json import logging import os import re @@ -12,6 +13,7 @@ from sanic.response import json from EdgeGPT import Chatbot, ConversationStyle logger = logging.getLogger(__name__) +logger.setLevel(logging.INFO) APPID = os.environ.get('WXAPPID') APPSECRET = os.environ.get('WXAPPSECRET') @@ -23,6 +25,13 @@ BAK_COOKIE1 = os.environ.get('COOKIE_FILE2', '') LOCK = threading.Lock() BOT_LOCK = threading.Lock() +bots = {} + +app = Sanic('new-bing') +app.config.REQUEST_TIMEOUT = 900 +app.config.RESPONSE_TIMEOUT = 900 +app.config.WEBSOCKET_PING_INTERVAL = 15 +app.config.WEBSOCKET_PING_TIMEOUT = 15 def reset_cookie(): @@ -40,10 +49,30 @@ def reset_cookie(): LOCK.release() -app = Sanic('new-bing') -app.config.REQUEST_TIMEOUT = 900 -app.config.RESPONSE_TIMEOUT = 900 -bots = {} +@app.websocket('/chat') +async def ws_chat(request, ws): + while True: + data = raw_json.loads(await ws.recv()) + logger.warn('Receive data: %s', data) + sid = data['sid'] + q = data['q'] + async for response in get_bot(sid).ask_stream(q, conversation_style=ConversationStyle.creative): + final, res = response + if final: + processed_data = await process_data(res, q, sid, auto_reset=1) + if processed_data['data']['status'] == 'Throttled': + reset_cookie() + await get_bot(sid).reset() + processed_data['data']['suggests'].append(q) + await ws.send(raw_json.dumps({ + 'final': final, + 'data': processed_data + })) + else: + await ws.send(raw_json.dumps({ + 'final': final, + 'data': res + })) def get_bot(sid): @@ -58,24 +87,16 @@ def get_bot(sid): async def do_chat(request): + logger.warn('Request payload: %s', request.json) return await get_bot(request.json.get('sid')).ask( request.json.get('q'), conversation_style=ConversationStyle.creative ) -@app.post('/chat') -async def chat(request): - res = await do_chat(request) - auto_reset = request.json.get('auto_reset', '') - sid = request.json.get('sid') - status = res['item']['result']['value'] - if status == 'Throttled': - reset_cookie() - await get_bot(sid).reset() - res = await do_chat(request) - status = res['item']['result']['value'] +async def process_data(res, q, sid, auto_reset=None): text = '' suggests = [] + status = res['item']['result']['value'] if status == 'Success': item = res['item']['messages'] if len(item) >= 2: @@ -89,18 +110,16 @@ async def chat(request): text = re.sub(r'\[\^\d+\^\]', '', text) suggests = [x['text'] for x in item[1]['suggestedResponses']] if 'suggestedResponses' in item[1] else [] else: - text = '抱歉,未搜索到结果,请重试。' + text = '抱歉,未搜索到结果。' logger.error('响应异常:%s', res) - suggests = [request.json.get('q')] - # 结束本轮对话 + suggests = [q] if res['type'] == 2: await get_bot(sid).reset() - text = '抱歉,未搜索到结果,已结束本轮对话。' + text += '\n\n已结束本轮对话。' msg = res['item']['result']['message'] if 'message' in res['item']['result'] else '' - # 自动reset if auto_reset and ('New topic' in text or 'has expired' in msg): await get_bot(sid).reset() - return json({ + return { 'data': { 'status': status, 'text': text, @@ -109,8 +128,22 @@ async def chat(request): 'num_in_conversation': res['item']['throttling']['numUserMessagesInConversation'] if 'throttling' in res['item'] else -1, }, - 'cookie': os.environ.get('COOKIE_FILE') - }) + 'cookie': os.environ.get('COOKIE_FILE'), + } + + +@app.post('/chat') +async def chat(request): + res = await do_chat(request) + auto_reset = request.json.get('auto_reset', '') + sid = request.json.get('sid') + data = await process_data(res, request.json.get('q'), sid, auto_reset) + if data['data']['status'] == 'Throttled': + reset_cookie() + await get_bot(sid).reset() + res = await do_chat(request) + data = await process_data(res, request.json.get('q'), sid, auto_reset) + return json(data) @app.route('/reset')