Spaces:
Paused
Paused
Hansimov
commited on
Commit
•
44c5e78
0
Parent(s):
:gem: [Feature] Enable chat with Bing from unauthenticated users
Browse files- .gitignore +1 -0
- README.md +3 -0
- chathub_request_constructor.py +178 -0
- conversation_creater.py +160 -0
- cookies_constructor.py +9 -0
.gitignore
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
__pycache__
|
README.md
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
## Bing-Chat-API
|
2 |
+
|
3 |
+
A successor of [EdgeGPT](https://github.com/acheong08/EdgeGPT) by [acheong08](https://github.com/acheong08).
|
chathub_request_constructor.py
ADDED
@@ -0,0 +1,178 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import random
|
2 |
+
import uuid
|
3 |
+
from datetime import datetime
|
4 |
+
|
5 |
+
|
6 |
+
def generate_random_hex_str(length: int = 32) -> str:
|
7 |
+
return "".join(random.choice("0123456789abcdef") for _ in range(length))
|
8 |
+
|
9 |
+
|
10 |
+
def generate_random_uuid():
|
11 |
+
return str(uuid.uuid4())
|
12 |
+
|
13 |
+
|
14 |
+
def get_locale():
|
15 |
+
return "en-US"
|
16 |
+
|
17 |
+
|
18 |
+
def get_timestamp_str():
|
19 |
+
now = datetime.now()
|
20 |
+
now_utc = datetime.utcnow()
|
21 |
+
timezone_offset = now - now_utc
|
22 |
+
offset_seconds = timezone_offset.total_seconds()
|
23 |
+
offset_hours = int(offset_seconds // 3600)
|
24 |
+
offset_minutes = int((offset_seconds % 3600) // 60)
|
25 |
+
offset_string = f"{offset_hours:+03d}:{offset_minutes:02d}"
|
26 |
+
timestamp_str = datetime.now().strftime("%Y-%m-%dT%H:%M:%S") + offset_string
|
27 |
+
# print(timestamp_str)
|
28 |
+
return timestamp_str
|
29 |
+
|
30 |
+
|
31 |
+
def get_prompt():
|
32 |
+
return "Hello, who are you?"
|
33 |
+
|
34 |
+
|
35 |
+
class ChathubRequestConstructor:
|
36 |
+
def __init__(
|
37 |
+
self,
|
38 |
+
conversation_style: str,
|
39 |
+
client_id: str,
|
40 |
+
conversation_id: str,
|
41 |
+
invocation_id: int = 0,
|
42 |
+
):
|
43 |
+
self.client_id = client_id
|
44 |
+
self.conversation_id = conversation_id
|
45 |
+
self.message_id = generate_random_uuid()
|
46 |
+
self.invocation_id = invocation_id
|
47 |
+
self.conversation_style = conversation_style
|
48 |
+
self.construct()
|
49 |
+
|
50 |
+
def construct(self):
|
51 |
+
self.request_message = {
|
52 |
+
"arguments": [
|
53 |
+
{
|
54 |
+
"source": "cib",
|
55 |
+
"optionsSets": [
|
56 |
+
"nlu_direct_response_filter",
|
57 |
+
"deepleo",
|
58 |
+
"disable_emoji_spoken_text",
|
59 |
+
"responsible_ai_policy_235",
|
60 |
+
"enablemm",
|
61 |
+
"dv3sugg",
|
62 |
+
"autosave",
|
63 |
+
"uquopt",
|
64 |
+
"enelecintl",
|
65 |
+
"gndeleccf",
|
66 |
+
"gndlogcf",
|
67 |
+
"logprobsc",
|
68 |
+
"fluxprod",
|
69 |
+
"eredirecturl",
|
70 |
+
],
|
71 |
+
"allowedMessageTypes": [
|
72 |
+
"ActionRequest",
|
73 |
+
"Chat",
|
74 |
+
"ConfirmationCard",
|
75 |
+
"Context",
|
76 |
+
"InternalSearchQuery",
|
77 |
+
"InternalSearchResult",
|
78 |
+
"Disengaged",
|
79 |
+
"InternalLoaderMessage",
|
80 |
+
"InvokeAction",
|
81 |
+
"Progress",
|
82 |
+
"RenderCardRequest",
|
83 |
+
"RenderContentRequest",
|
84 |
+
"AdsQuery",
|
85 |
+
"SemanticSerp",
|
86 |
+
"GenerateContentQuery",
|
87 |
+
"SearchQuery",
|
88 |
+
],
|
89 |
+
"sliceIds": [
|
90 |
+
"cruisecf",
|
91 |
+
"adssqovr",
|
92 |
+
"gbacf",
|
93 |
+
"bggrey",
|
94 |
+
"1366cf",
|
95 |
+
"vnextvoice",
|
96 |
+
"caccnctat3",
|
97 |
+
"specedgecf",
|
98 |
+
"inosanewsmob",
|
99 |
+
"wrapnoins",
|
100 |
+
"readaloud",
|
101 |
+
"autotts",
|
102 |
+
"styleoffall",
|
103 |
+
"rwt2",
|
104 |
+
"dismmaslp",
|
105 |
+
"1117gndelecs0",
|
106 |
+
"713logprobsc",
|
107 |
+
"1118wcpdcl",
|
108 |
+
"1119backos",
|
109 |
+
"1103gndlog",
|
110 |
+
"1107reviewss0",
|
111 |
+
"fluxnosearch",
|
112 |
+
"727nrprdrt3",
|
113 |
+
"codecreator1",
|
114 |
+
"kchero50cf",
|
115 |
+
"cacmuidarb",
|
116 |
+
],
|
117 |
+
"verbosity": "verbose",
|
118 |
+
"scenario": "SERP",
|
119 |
+
"plugins": [
|
120 |
+
{"id": "c310c353-b9f0-4d76-ab0d-1dd5e979cf68"},
|
121 |
+
],
|
122 |
+
"traceId": generate_random_hex_str(),
|
123 |
+
"conversationHistoryOptionsSets": [
|
124 |
+
"autosave",
|
125 |
+
"savemem",
|
126 |
+
"uprofupd",
|
127 |
+
"uprofgen",
|
128 |
+
],
|
129 |
+
"isStartOfSession": self.invocation_id == 0,
|
130 |
+
"requestId": self.message_id,
|
131 |
+
"message": {
|
132 |
+
"locale": get_locale(), # "en-US"
|
133 |
+
"market": get_locale(), # "en-US"
|
134 |
+
"region": get_locale()[-2:], # "US"
|
135 |
+
"location": "lat:47.639557;long:-122.128159;re=1000m;",
|
136 |
+
"locationHints": [
|
137 |
+
{
|
138 |
+
"SourceType": 1,
|
139 |
+
"RegionType": 2,
|
140 |
+
"Center": {
|
141 |
+
"Latitude": 38.668399810791016,
|
142 |
+
"Longitude": -121.14900207519531,
|
143 |
+
},
|
144 |
+
"Radius": 24902,
|
145 |
+
"Name": "Folsom, California",
|
146 |
+
"Accuracy": 24902,
|
147 |
+
"FDConfidence": 0.5,
|
148 |
+
"CountryName": "United States",
|
149 |
+
"CountryConfidence": 8,
|
150 |
+
"Admin1Name": "California",
|
151 |
+
"PopulatedPlaceName": "Folsom",
|
152 |
+
"PopulatedPlaceConfidence": 5,
|
153 |
+
"PostCodeName": "95630",
|
154 |
+
"UtcOffset": -8,
|
155 |
+
"Dma": 862,
|
156 |
+
}
|
157 |
+
],
|
158 |
+
"userIpAddress": "192.55.55.51",
|
159 |
+
"timestamp": get_timestamp_str(), # "2023-11-20T12:50:17+08:00",
|
160 |
+
"author": "user",
|
161 |
+
"inputMethod": "Keyboard",
|
162 |
+
"text": get_prompt(),
|
163 |
+
"messageType": "Chat",
|
164 |
+
"requestId": self.message_id, # "a6ecd3aa-1007-6959-52fb-9e23f34e86be",
|
165 |
+
"messageId": self.message_id, # "a6ecd3aa-1007-6959-52fb-9e23f34e86be",
|
166 |
+
},
|
167 |
+
"tone": self.conversation_style.capitalize(),
|
168 |
+
"spokenTextMode": "None",
|
169 |
+
"conversationId": self.conversation_id, # "51D|BingProd|30FA137663F2BDBA514A0F31EE0A99E082B5AF8C0DA05696D2A5C6B56C10CF99",
|
170 |
+
"participant": {
|
171 |
+
"id": self.client_id, # "1055519195774559",
|
172 |
+
},
|
173 |
+
}
|
174 |
+
],
|
175 |
+
"invocationId": str(self.invocation_id),
|
176 |
+
"target": "chat",
|
177 |
+
"type": 4,
|
178 |
+
}
|
conversation_creater.py
ADDED
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import aiohttp
|
2 |
+
import asyncio
|
3 |
+
import certifi
|
4 |
+
import httpx
|
5 |
+
import json
|
6 |
+
import pprint
|
7 |
+
import ssl
|
8 |
+
import urllib
|
9 |
+
|
10 |
+
from chathub_request_constructor import ChathubRequestConstructor
|
11 |
+
from cookies_constructor import CookiesConstructor
|
12 |
+
|
13 |
+
ssl_context = ssl.create_default_context()
|
14 |
+
ssl_context.load_verify_locations(certifi.where())
|
15 |
+
|
16 |
+
http_proxy = "http://localhost:11111"
|
17 |
+
|
18 |
+
|
19 |
+
class ConversationCreator:
|
20 |
+
conversation_create_url = "https://www.bing.com/turing/conversation/create"
|
21 |
+
|
22 |
+
def __init__(self, cookies={}):
|
23 |
+
self.cookies = cookies
|
24 |
+
self.construct_cookies()
|
25 |
+
|
26 |
+
def construct_cookies(self):
|
27 |
+
self.httpx_cookies = httpx.Cookies()
|
28 |
+
for key, val in self.cookies.items():
|
29 |
+
self.httpx_cookies.set(key, val)
|
30 |
+
|
31 |
+
def create(self, proxy=None):
|
32 |
+
self.response = httpx.get(
|
33 |
+
self.conversation_create_url,
|
34 |
+
proxies=http_proxy if proxy is None else proxy,
|
35 |
+
cookies=self.httpx_cookies,
|
36 |
+
)
|
37 |
+
self.response_content = json.loads(self.response.content.decode("utf-8"))
|
38 |
+
self.response_headers = dict(self.response.headers)
|
39 |
+
pprint.pprint(self.response_content)
|
40 |
+
# pprint.pprint(self.response_headers)
|
41 |
+
|
42 |
+
|
43 |
+
def serialize_websockets_message(msg: dict) -> str:
|
44 |
+
return json.dumps(msg, ensure_ascii=False) + "\x1e"
|
45 |
+
|
46 |
+
|
47 |
+
class ConversationChatter:
|
48 |
+
def __init__(
|
49 |
+
self,
|
50 |
+
sec_access_token=None,
|
51 |
+
client_id=None,
|
52 |
+
conversation_id=None,
|
53 |
+
invocation_id=0,
|
54 |
+
cookies={},
|
55 |
+
):
|
56 |
+
self.sec_access_token = sec_access_token
|
57 |
+
self.client_id = client_id
|
58 |
+
self.conversation_id = conversation_id
|
59 |
+
self.invocation_id = invocation_id
|
60 |
+
self.cookies = cookies
|
61 |
+
self.ws_url = (
|
62 |
+
"wss://sydney.bing.com/sydney/ChatHub"
|
63 |
+
+ f"?sec_access_token={urllib.parse.quote(self.sec_access_token)}"
|
64 |
+
)
|
65 |
+
# print(f"sec_access_token: {self.sec_access_token}")
|
66 |
+
|
67 |
+
async def init_handshake(self, wss):
|
68 |
+
await wss.send_str(
|
69 |
+
serialize_websockets_message({"protocol": "json", "version": 1})
|
70 |
+
)
|
71 |
+
await wss.receive_str()
|
72 |
+
await wss.send_str(serialize_websockets_message({"type": 6}))
|
73 |
+
|
74 |
+
async def stream_chat(self, prompt=""):
|
75 |
+
self.aio_session = aiohttp.ClientSession(cookies=self.cookies)
|
76 |
+
request_headers = {
|
77 |
+
"Accept-Encoding": " gzip, deflate, br",
|
78 |
+
"Accept-Language": "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7",
|
79 |
+
"Cache-Control": "no-cache",
|
80 |
+
"Connection": "Upgrade",
|
81 |
+
"Host": "sydney.bing.com",
|
82 |
+
"Origin": "https://www.bing.com",
|
83 |
+
"Pragma": "no-cache",
|
84 |
+
"Sec-Websocket-Extensions": "permessage-deflate; client_max_window_bits",
|
85 |
+
# "Sec-Websocket-Key": "**********************==",
|
86 |
+
"Sec-Websocket-Version": "13",
|
87 |
+
"Upgrade": "websocket",
|
88 |
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
|
89 |
+
}
|
90 |
+
wss = await self.aio_session.ws_connect(
|
91 |
+
self.ws_url,
|
92 |
+
headers=request_headers,
|
93 |
+
ssl=ssl_context,
|
94 |
+
proxy=http_proxy,
|
95 |
+
)
|
96 |
+
|
97 |
+
await self.init_handshake(wss)
|
98 |
+
chathub_request_construtor = ChathubRequestConstructor(
|
99 |
+
conversation_style="precise",
|
100 |
+
client_id=self.client_id,
|
101 |
+
conversation_id=self.conversation_id,
|
102 |
+
invocation_id=self.invocation_id,
|
103 |
+
)
|
104 |
+
chathub_request_construtor.construct()
|
105 |
+
|
106 |
+
await wss.send_str(
|
107 |
+
serialize_websockets_message(chathub_request_construtor.request_message)
|
108 |
+
)
|
109 |
+
while not wss.closed:
|
110 |
+
response_lines_str = await wss.receive_str()
|
111 |
+
if isinstance(response_lines_str, str):
|
112 |
+
response_lines = response_lines_str.split("\x1e")
|
113 |
+
else:
|
114 |
+
continue
|
115 |
+
for line in response_lines:
|
116 |
+
if not line:
|
117 |
+
continue
|
118 |
+
data = json.loads(line)
|
119 |
+
if data.get("type") == 1:
|
120 |
+
arguments = data["arguments"][0]
|
121 |
+
if arguments.get("throttling"):
|
122 |
+
throttling = arguments.get("throttling")
|
123 |
+
pprint.pprint(throttling)
|
124 |
+
if arguments.get("messages"):
|
125 |
+
messages = arguments.get("messages")[0]
|
126 |
+
html_str = messages["adaptiveCards"][0]["body"][0]["text"]
|
127 |
+
# pprint.pprint(html_str)
|
128 |
+
elif data.get("type") == 2:
|
129 |
+
if data.get("item"):
|
130 |
+
item = data.get("item")
|
131 |
+
for message in item.get("messages"):
|
132 |
+
author = message["author"]
|
133 |
+
message_text = message["text"]
|
134 |
+
print(f"[{author}]: {message_text}")
|
135 |
+
elif data.get("type") == 3:
|
136 |
+
print("[Finished]")
|
137 |
+
await wss.close()
|
138 |
+
break
|
139 |
+
else:
|
140 |
+
# pprint.pprint(data)
|
141 |
+
continue
|
142 |
+
|
143 |
+
|
144 |
+
if __name__ == "__main__":
|
145 |
+
# cookies_constructor = CookiesConstructor()
|
146 |
+
# cookies_constructor.construct()
|
147 |
+
|
148 |
+
creator = ConversationCreator()
|
149 |
+
creator.create()
|
150 |
+
|
151 |
+
chatter = ConversationChatter(
|
152 |
+
sec_access_token=creator.response_headers[
|
153 |
+
"x-sydney-encryptedconversationsignature"
|
154 |
+
],
|
155 |
+
client_id=creator.response_content["clientId"],
|
156 |
+
conversation_id=creator.response_content["conversationId"],
|
157 |
+
)
|
158 |
+
loop = asyncio.get_event_loop()
|
159 |
+
loop.run_until_complete(chatter.stream_chat())
|
160 |
+
loop.close()
|
cookies_constructor.py
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
class CookiesConstructor:
|
2 |
+
def __init__(self) -> None:
|
3 |
+
self.cookies_list = [
|
4 |
+
]
|
5 |
+
|
6 |
+
def construct(self):
|
7 |
+
self.cookies = {}
|
8 |
+
for cookie in self.cookies_list:
|
9 |
+
self.cookies[cookie["name"]] = cookie["value"]
|