diff --git a/stable.toml b/dev.toml similarity index 95% rename from stable.toml rename to dev.toml index 342690c..8bb2bc3 100644 --- a/stable.toml +++ b/dev.toml @@ -5,8 +5,8 @@ requires = ["setuptools>=61.0"] build-backend = "setuptools.build_meta" [project] -name = "re_edge_gpt" -version = "0.0.17" +name = "re_edge_gpt_dev" +version = "0.0.18" authors = [ { name = "JE-Chen", email = "jechenmailman@gmail.com" }, ] diff --git a/pyproject.toml b/pyproject.toml index a8f0e8f..aadd17c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,8 +5,8 @@ requires = ["setuptools>=61.0"] build-backend = "setuptools.build_meta" [project] -name = "re_edge_gpt_dev" -version = "0.0.17" +name = "re_edge_gpt" +version = "0.0.18" authors = [ { name = "JE-Chen", email = "jechenmailman@gmail.com" }, ] diff --git a/re_edge_gpt/chathub.py b/re_edge_gpt/chathub.py index ac8a514..caf1654 100644 --- a/re_edge_gpt/chathub.py +++ b/re_edge_gpt/chathub.py @@ -1,6 +1,5 @@ import asyncio import json -import os import ssl import sys from time import time @@ -20,6 +19,7 @@ from .conversation_style import CONVERSATION_STYLE_TYPE from .proxy import get_proxy from .request import ChatHubRequest +from .upload_image import upload_image, upload_image_url from .utilities import append_identifier from .utilities import get_ran_hex from .utilities import guess_locale @@ -50,6 +50,7 @@ def __init__( client_id=conversation.struct["clientId"], conversation_id=conversation.struct["conversationId"], ) + self.conversation_id = conversation.struct["conversationId"] or self.request.conversation_id self.cookies = cookies self.proxy: str = get_proxy(proxy) self.session = httpx.AsyncClient( @@ -68,7 +69,7 @@ async def get_conversation( conversation_signature: str = None, client_id: str = None, ) -> dict: - conversation_id = conversation_id or self.request.conversation_id + self.conversation_id = conversation_id or self.request.conversation_id conversation_signature = ( conversation_signature or self.request.conversation_signature ) @@ -101,6 +102,8 @@ async def ask_stream( webpage_context: Union[str, None] = None, search_result: bool = False, locale: str = guess_locale(), + # Use for attachment + attachment: dict = None, ) -> Generator[bool, Union[dict, str], None]: """ """ if self.encrypted_conversation_signature is not None: @@ -119,6 +122,15 @@ async def ask_stream( proxy=self.proxy, ) await _initial_handshake(wss) + # Image + image_url = None + if attachment is not None: + if attachment.get("image_url") is not None: + response = await upload_image_url(**attachment, conversation_id=self.conversation_id) + else: + response = await upload_image(**attachment) + if response: + image_url = f"https://www.bing.com/images/blob?bcid={response}" # Construct a ChatHub request self.request.update( prompt=prompt, @@ -126,6 +138,7 @@ async def ask_stream( webpage_context=webpage_context, search_result=search_result, locale=locale, + image_url=image_url, ) # Send request await wss.send_str(append_identifier(self.request.struct)) diff --git a/re_edge_gpt/re_edge_gpt.py b/re_edge_gpt/re_edge_gpt.py index 49682aa..a904126 100644 --- a/re_edge_gpt/re_edge_gpt.py +++ b/re_edge_gpt/re_edge_gpt.py @@ -94,6 +94,7 @@ async def ask( search_result: bool = False, locale: str = guess_locale(), simplify_response: bool = False, + attachment: dict[str, str] = None ): """ Ask a question to the bot @@ -115,6 +116,7 @@ async def ask( webpage_context=webpage_context, search_result=search_result, locale=locale, + attachment=attachment, ): if final: if not simplify_response: diff --git a/re_edge_gpt/request.py b/re_edge_gpt/request.py index 27927bf..9a8dabb 100644 --- a/re_edge_gpt/request.py +++ b/re_edge_gpt/request.py @@ -31,13 +31,8 @@ def update( webpage_context: Union[str, None] = None, search_result: bool = False, locale: str = guess_locale(), + image_url: str = None ) -> None: - options = [ - "deepleo", - "enable_debug_commands", - "disable_emoji_spoken_text", - "enablemm", - ] if conversation_style: if not isinstance(conversation_style, ConversationStyle): conversation_style = getattr(ConversationStyle, conversation_style) @@ -65,7 +60,20 @@ def update( "arguments": [ { "source": "cib", - "optionsSets": options, + "optionsSets": [ + "nlu_direct_response_filter", + "deepleo", + "disable_emoji_spoken_text", + "responsible_ai_policy_235", + "enablemm", + "iycapbing", + "iyxapbing", + "dv3sugg", + "iyoloxap", + "iyoloneutral", + "gencontentv3", + "nojbf", + ], "allowedMessageTypes": [ "ActionRequest", "Chat", @@ -79,30 +87,30 @@ def update( "AdsQuery", "SemanticSerp", "GenerateContentQuery", - "SearchQuery", + "SearchQuery" ], "sliceIds": [ "winmuid1tf", - "styleoff", - "ccadesk", - "smsrpsuppv4cf", - "ssrrcache", - "contansperf", - "crchatrev", - "winstmsg2tf", - "creatgoglt", - "creatorv2t", - "sydconfigoptt", - "adssqovroff", - "530pstho", - "517opinion", - "418dhlth", - "512sprtic1s0", - "emsgpr", - "525ptrcps0", + "newmma-prod", + "imgchatgptv2", + "tts2", + "voicelang2", + "anssupfotest", + "emptyoson", + "tempcacheread", + "temptacache", + "ctrlworkpay", + "winlongmsg2tf", + "628fabocs0", + "531rai268s0", + "602refusal", + "621alllocs0", + "621docxfmtho", + "621preclsvn", + "330uaug", "529rweas0", - "515oscfing2s0", - "524vidansgs0", + "0626snptrcs0", + "619dagslnv1nr" ], "verbosity": "verbose", "traceId": get_ran_hex(32), @@ -119,6 +127,8 @@ def update( "messageType": "Chat", "messageId": message_id, "requestId": message_id, + "imageUrl": image_url if image_url else None, + "originalImageUrl": image_url if image_url else None, }, "tone": conversation_style.name.capitalize(), # Make first letter uppercase "requestId": message_id, diff --git a/re_edge_gpt/upload_image.py b/re_edge_gpt/upload_image.py new file mode 100644 index 0000000..67254a3 --- /dev/null +++ b/re_edge_gpt/upload_image.py @@ -0,0 +1,60 @@ +import base64 +import json + +import aiohttp + +payload = { + "imageInfo": {}, + "knowledgeRequest": { + "invokedSkills": ["ImageById"], + "subscriptionId": "Bing.Chat.Multimodal", + "invokedSkillsRequestData": {"enableFaceBlur": True}, + "convoData": { + "convoid": "", + "convotone": "Balanced" + } + } +} + + +async def upload_image_url(image_url: str, conversation_id: str, proxy: str = None, face_blur: bool = True): + async with aiohttp.ClientSession( + headers={"Referer": "https://www.bing.com/search?q=Bing+AI&showconv=1&FORM=hpcodx"}, + ) as session: + url = "https://www.bing.com/images/kblob" + + new_payload = payload + new_payload.get("knowledgeRequest").update( + {"invokedSkillsRequestData": {"enableFaceBlur": face_blur}}) + new_payload.get("imageInfo").update({"url": image_url}) + new_payload.get("knowledgeRequest").get("convoData").update({"convoid": conversation_id}) + data = aiohttp.FormData() + data.add_field('knowledgeRequest', json.dumps(new_payload), content_type="application/json") + async with session.post(url, data=data, proxy=proxy) as resp: + return (await resp.json())["blobId"] + + +async def upload_image(filename: str = None, base64_image: str = None, proxy: str = None, face_blur: bool = True): + async with aiohttp.ClientSession( + headers={"Referer": "https://www.bing.com/search?q=Bing+AI&showconv=1&FORM=hpcodx"}, + ) as session: + url = "https://www.bing.com/images/kblob" + + new_payload = payload.get("knowledgeRequest").update( + {"invokedSkillsRequestData": {"enableFaceBlur": face_blur}}) + + if filename is not None: + with open(filename, 'rb') as f: + file_data = f.read() + image_base64 = base64.b64encode(file_data) + elif base64_image is not None: + image_base64 = base64_image + else: + raise Exception('no image provided') + + data = aiohttp.FormData() + data.add_field('knowledgeRequest', json.dumps(new_payload), content_type="application/json") + data.add_field('imageBase64', image_base64, content_type="application/octet-stream") + + async with session.post(url, data=data, proxy=proxy) as resp: + return (await resp.json())["blobId"] diff --git a/test/unit_test/manual_test/test_bot_with_file.py b/test/unit_test/manual_test/test_bot_with_file.py new file mode 100644 index 0000000..e822007 --- /dev/null +++ b/test/unit_test/manual_test/test_bot_with_file.py @@ -0,0 +1,43 @@ +import asyncio +import json +from pathlib import Path + +from re_edge_gpt import Chatbot +from re_edge_gpt import ConversationStyle + + +# If you are using jupyter pls install this package +# from nest_asyncio import apply + + +async def test_ask() -> None: + bot = None + try: + cookies: list[dict] = json.loads(open( + str(Path(str(Path.cwd()) + "/bing_cookies.json")), encoding="utf-8").read()) + bot = await Chatbot.create(cookies=cookies) + response = await bot.ask( + prompt="What does this image show?", + conversation_style=ConversationStyle.balanced, + simplify_response=True, + attachment={"image_url": r"https://images.yourstory.com/cs/2/96eabe90392211eb93f18319e8c07a74/Image54nh-1683225460858.jpg"}) + # If you are using non ascii char you need set ensure_ascii=False + print(json.dumps(response, indent=2, ensure_ascii=False)) + # Raw response + # print(response) + assert response + except Exception as error: + raise error + finally: + if bot is not None: + await bot.close() + + +if __name__ == "__main__": + # If you are using jupyter pls use nest_asyncio apply() + # apply() + try: + loop = asyncio.get_running_loop() + except RuntimeError: + loop = asyncio.get_event_loop() + loop.run_until_complete(test_ask())