Skip to content
This repository has been archived by the owner on May 16, 2023. It is now read-only.

Commit

Permalink
API增加连续对话功能
Browse files Browse the repository at this point in the history
  • Loading branch information
XiaoXinYo committed Mar 12, 2023
1 parent 330c98a commit 052290c
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 22 deletions.
34 changes: 18 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ Bing Chat服务端,通过WebSocket/API实现通讯.
4. 运行bing_chat.py.
## 参数
### 请求
名称|必填|中文名
---|---|---
style|是|风格,balanced代表平衡,creative代表创造,precise代表精确
question|是|问题
名称|必填|中文名|说明
---|---|---|---
token|否|令牌|当请求API时,填则为连续对话,不填则为新对话,值可在响应中获取
style|是|风格|balanced代表平衡,creative代表创造,precise代表精确
question|是|问题|

:WebSocket发送需JSON格式.
### 响应
Expand All @@ -28,46 +29,47 @@ data|数据|
answer|回答|
urls|链接|
done|完成|部分传输是否完成,当连接/ws_stream时存在
reset|重置|下次对话是否被重置,当为WebSocket时存在(code为500时也会被重置)
reset|重置|下次对话是否被重置(code为500时也会被重置)
token|令牌|用于连续对话,当请求API时存在
### 整体传输
> 等待Bing Chat响应完后返回.
#### WebSocket
连接/ws.
```
{"code": 200, "message": "success", "data": {answer:"您好,这是必应。", urls:[{"title": "The New Bing - Learn More", "url": "https://www.bing.com/new"}], "reset": false}}
{"code": 200, "message": "success", "data": {"answer": "您好,这是必应。", "urls":[{"title": "The New Bing - Learn More", "url": "https://www.bing.com/new"}], "reset": false}}
```
#### API
1. 请求方式: GET/POST.
2. 请求地址: /api.
```
{"code": 200, "message": "success", "data": {answer:"您好,这是必应。", urls:[{"title": "The New Bing - Learn More", "url": "https://www.bing.com/new"}]}}
{"code": 200, "message": "success", "data": {"answer": "您好,这是必应。", "urls":[{"title": "The New Bing - Learn More", "url": "https://www.bing.com/new"}], "reset": false, "token": "7953d67b-eac2-457e-a2ee-fedc8ba53599"}}
```
### 流传输
> 一部分一部分返回.
1. WebSocket连接/ws_stream.
2. 当部分传输完成时,将会返回整体,done改为true,url才会有值.
```
{"code": 200, "message": "success", "data": {answer:"您。", urls:[], "done": false, "reset": false}}
{"code": 200, "message": "success", "data": {"answer": "您。", "urls": [], "done": false, "reset": false}}
{"code": 200, "message": "success", "data": {answer:"好", urls:[], "done": false, "reset": false}}
{"code": 200, "message": "success", "data": {"answer": "好", "urls": [], "done": false, "reset": false}}
{"code": 200, "message": "success", "data": {answer:",", urls:[], "done": false, "reset": false}}
{"code": 200, "message": "success", "data": {"answer": ",", "urls": [], "done": false, "reset": false}}
{"code": 200, "message": "success", "data": {answer:"这。", urls:[], "done": false, "reset": false}}
{"code": 200, "message": "success", "data": {"answer": "这。", "urls": [], "done": false, "reset": false}}
{"code": 200, "message": "success", "data": {answer:"是", urls:[], "done": false, "reset": false}}
{"code": 200, "message": "success", "data": {"answer": "是", "urls": [], "done": false, "reset": false}}
{"code": 200, "message": "success", "data": {answer:"必应", urls:[], "done": false, "reset": false}}
{"code": 200, "message": "success", "data": {"answer": "必应", "urls": [], "done": false, "reset": false}}
{"code": 200, "message": "success", "data": {answer:"。", urls:[], "done": false, "reset": false}}
{"code": 200, "message": "success", "data": {"answer": "。", "urls": [], "done": false, "reset": false}}
{"code": 200, "message": "success", "data": {answer:"您好,这是必应。", urls:[{"title": "The New Bing - Learn More", "url": "https://www.bing.com/new"}], "done": true, "reset": false}}
{"code": 200, "message": "success", "data": {"answer": "您好,这是必应。", "urls": [{"title": "The New Bing - Learn More", "url": "https://www.bing.com/new"}], "done": true, "reset": false}}
```
## emm
1. 页面写的有点丑,有能力的大神,可以pull request一下,如果你有的example也可以提交.
2. 搭建好建议不要对外开放,因为目前Bing Chat24小时内有次数限制.
3. 至于反应快慢的问题,要看回答文本的长度,如果文本长度过长,回复时间会比较长.
4. 关于整体传输和流传输,整体传输由于要等待Bing完全响应才能开始传输,所以时间要久一点。流传输会先返回一部分,所以看起来比较快,但其实最终的完成时间都是一样的.
5. 连续对话问题:只有websocket才能保持对话,api每次请求都会重置对话。但对于api来说,你可以每次请求都带上上一次的问题和回复,这样就可以保持对话了.
5. 连续对话问题:websocket是默认支持连续对话的。对于API来说,如果需要进行连续对话,首先需要在第一次请求时获取token,然后在后续请求中带上token,就可以实现连续对话了.
45 changes: 39 additions & 6 deletions bing_chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
from typing import Union
from fastapi import FastAPI, Request, WebSocket, Response
from fastapi.middleware.cors import CORSMiddleware
import asyncio
import uvicorn
import EdgeGPT
import uuid
import time
import json
import re

Expand All @@ -21,6 +24,7 @@
allow_headers=['*'],
)
STYLES = ['balanced', 'creative', 'precise']
CHATBOT = {}

def needReset(data: dict, answer: str) -> bool:
maxTimes = data.get('item').get('throttling').get('maxNumUserMessagesInConversation')
Expand Down Expand Up @@ -100,12 +104,25 @@ async def getrequestParameter(request: Request) -> dict:
data = await request.json()
return dict(data)

async def checkToken() -> None:
global CHATBOT
while True:
for token in CHATBOT.copy():
if time.time() - CHATBOT[token]['useTime'] > 5 * 60:
await CHATBOT[token]['chatBot'].close()
del CHATBOT[token]
await asyncio.sleep(60)

@APP.on_event('startup')
async def startup() -> None:
asyncio.get_event_loop().create_task(checkToken())

@APP.exception_handler(404)
def error404(request, exc) -> Response:
def error404(request: Request, exc: Exception) -> Response:
return GenerateResponse().error(404, '未找到文件')

@APP.exception_handler(500)
def error500(request, exc) -> Response:
def error500(request: Request, exc: Exception) -> Response:
return GenerateResponse().error(500, '未知错误')

@APP.websocket('/ws_stream')
Expand Down Expand Up @@ -139,7 +156,6 @@ async def wsStream(ws: WebSocket) -> str:
if not final:
answer = data[index:]
index = len(data)
#answer = re.sub(r'\[.*?\]', '', answer)
answer = re.sub(r'\[\^.*?\^]', '', answer)
if answer:
info['answer'] = answer
Expand Down Expand Up @@ -176,27 +192,44 @@ async def wsStream(ws: WebSocket) -> str:
@APP.route('/api', methods=['GET', 'POST'])
async def api(request: Request) -> Response:
parameters = await getrequestParameter(request)
token = parameters.get('token')
style = parameters.get('style')
question = parameters.get('question')
if not style or not question:
return GenerateResponse().error(110, '参数不能为空')
elif style not in STYLES:
return GenerateResponse().error(110, 'style不存在')

chatBot = EdgeGPT.Chatbot('./cookie.json')
global CHATBOT
if token in CHATBOT:
chatBot = CHATBOT[token]['chatBot']
CHATBOT[token]['useTime'] = time.time()
else:
chatBot = EdgeGPT.Chatbot('./cookie.json')
token = str(uuid.uuid4())
CHATBOT[token] = {}
CHATBOT[token]['chatBot'] = chatBot
CHATBOT[token]['useTime'] = time.time()
data = await chatBot.ask(question, getStyleEnum(style))

if data.get('item').get('result').get('value') == 'Throttled':
return GenerateResponse().error(120, '已上限,24小时后尝试')

info = {
'answer': '',
'urls': []
'urls': [],
'reset': False,
'token': token
}
answer = re.sub(r'\[\^.*?\^]', '', getAnswer(data))
answer = answer.rstrip()
info['answer'] = answer
info['urls'] = getUrl(data)

if needReset(data, answer):
await chatBot.reset()
info['reset'] = True

return GenerateResponse().success(info)

@APP.websocket('/ws')
Expand Down

0 comments on commit 052290c

Please sign in to comment.