Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add image upload using URL | File path | base64 #58

Merged
merged 1 commit into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions stable.toml → dev.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" },
]
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" },
]
Expand Down
17 changes: 15 additions & 2 deletions re_edge_gpt/chathub.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import asyncio
import json
import os
import ssl
import sys
from time import time
Expand All @@ -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
Expand Down Expand Up @@ -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(
Expand All @@ -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
)
Expand Down Expand Up @@ -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:
Expand All @@ -119,13 +122,23 @@ 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,
conversation_style=conversation_style,
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))
Expand Down
2 changes: 2 additions & 0 deletions re_edge_gpt/re_edge_gpt.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:
Expand Down
64 changes: 37 additions & 27 deletions re_edge_gpt/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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",
Expand All @@ -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),
Expand All @@ -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,
Expand Down
60 changes: 60 additions & 0 deletions re_edge_gpt/upload_image.py
Original file line number Diff line number Diff line change
@@ -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"]
43 changes: 43 additions & 0 deletions test/unit_test/manual_test/test_bot_with_file.py
Original file line number Diff line number Diff line change
@@ -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())