bing-chat-api / conversation_connector.py
Hansimov's picture
:recycle: [Refactor] Prettify names and comments
e85c831
raw
history blame
5.37 kB
import aiohttp
import asyncio
import httpx
import json
import pprint
import urllib
from conversation_creator import ConversationCreator
from chathub_request_constructor import ChathubRequestConstructor
from message_parser import MessageParser
from logger.logger import logger
http_proxy = "http://localhost:11111" # Replace with yours
class ConversationConnectRequestHeadersConstructor:
def __init__(self):
self.construct()
def construct(self):
self.request_headers = {
"Accept-Encoding": " gzip, deflate, br",
"Accept-Language": "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7",
"Cache-Control": "no-cache",
"Connection": "Upgrade",
"Host": "sydney.bing.com",
"Origin": "https://www.bing.com",
"Pragma": "no-cache",
"Sec-Websocket-Extensions": "permessage-deflate; client_max_window_bits",
"Sec-Websocket-Version": "13",
"Upgrade": "websocket",
"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",
}
class ConversationConnector:
def __init__(
self,
conversation_style="pecise",
sec_access_token=None,
client_id=None,
conversation_id=None,
invocation_id=0,
cookies={},
):
self.conversation_style = conversation_style
self.sec_access_token = sec_access_token
self.quotelized_sec_access_token = urllib.parse.quote(self.sec_access_token)
self.client_id = client_id
self.conversation_id = conversation_id
self.invocation_id = invocation_id
self.cookies = cookies
self.ws_url = (
f"wss://sydney.bing.com/sydney/ChatHub"
f"?sec_access_token={self.quotelized_sec_access_token}"
)
async def wss_send(self, message):
serialized_websocket_message = json.dumps(message, ensure_ascii=False) + "\x1e"
await self.wss.send_str(serialized_websocket_message)
async def init_handshake(self):
await self.wss_send({"protocol": "json", "version": 1})
await self.wss.receive_str()
await self.wss_send({"type": 6})
async def init_wss_connection(self):
self.aiohttp_session = aiohttp.ClientSession(cookies=self.cookies)
request_headers_constructor = ConversationConnectRequestHeadersConstructor()
self.wss = await self.aiohttp_session.ws_connect(
self.ws_url,
headers=request_headers_constructor.request_headers,
proxy=http_proxy,
)
await self.init_handshake()
async def send_chathub_request(self, prompt):
chathub_request_constructor = ChathubRequestConstructor(
prompt=prompt,
conversation_style=self.conversation_style,
client_id=self.client_id,
conversation_id=self.conversation_id,
invocation_id=self.invocation_id,
)
self.connect_request_payload = chathub_request_constructor.request_payload
await self.wss_send(self.connect_request_payload)
async def stream_chat(self, prompt=""):
await self.init_wss_connection()
await self.send_chathub_request(prompt)
message_parser = MessageParser()
while not self.wss.closed:
response_lines_str = await self.wss.receive_str()
if isinstance(response_lines_str, str):
response_lines = response_lines_str.split("\x1e")
else:
continue
for line in response_lines:
if not line:
continue
data = json.loads(line)
# Stream: Meaningful Messages
if data.get("type") == 1:
message_parser.parse(data)
# Stream: List of all messages in the whole conversation
elif data.get("type") == 2:
if data.get("item"):
item = data.get("item")
logger.note("\n[Saving chat messages ...]")
# Stream: End of Conversation
elif data.get("type") == 3:
logger.success("[Finished]")
self.invocation_id += 1
await self.wss.close()
await self.aiohttp_session.close()
break
# Stream: Heartbeat Signal
elif data.get("type") == 6:
continue
# Stream: Not Monitored
else:
continue
if __name__ == "__main__":
creator = ConversationCreator()
creator.create()
connector = ConversationConnector(
sec_access_token=creator.response_headers[
"x-sydney-encryptedconversationsignature"
],
client_id=creator.response_content["clientId"],
conversation_id=creator.response_content["conversationId"],
)
prompt = "Today's weather of California"
# prompt = "Tell me your name. Your output should be no more than 3 words."
logger.success(f"\n[User]: ", end="")
logger.mesg(f"{prompt}")
logger.success(f"\n[Bing]:")
loop = asyncio.get_event_loop()
loop.run_until_complete(connector.stream_chat(prompt=prompt))
loop.close()