summaryrefslogtreecommitdiffstats
path: root/g4f/Provider/Bing.py
diff options
context:
space:
mode:
Diffstat (limited to 'g4f/Provider/Bing.py')
-rw-r--r--g4f/Provider/Bing.py230
1 files changed, 126 insertions, 104 deletions
diff --git a/g4f/Provider/Bing.py b/g4f/Provider/Bing.py
index 50e29d23..34687866 100644
--- a/g4f/Provider/Bing.py
+++ b/g4f/Provider/Bing.py
@@ -15,12 +15,18 @@ from .bing.upload_image import upload_image
from .bing.create_images import create_images
from .bing.conversation import Conversation, create_conversation, delete_conversation
-class Tones():
+class Tones:
+ """
+ Defines the different tone options for the Bing provider.
+ """
creative = "Creative"
balanced = "Balanced"
precise = "Precise"
class Bing(AsyncGeneratorProvider):
+ """
+ Bing provider for generating responses using the Bing API.
+ """
url = "https://bing.com/chat"
working = True
supports_message_history = True
@@ -38,6 +44,19 @@ class Bing(AsyncGeneratorProvider):
web_search: bool = False,
**kwargs
) -> AsyncResult:
+ """
+ Creates an asynchronous generator for producing responses from Bing.
+
+ :param model: The model to use.
+ :param messages: Messages to process.
+ :param proxy: Proxy to use for requests.
+ :param timeout: Timeout for requests.
+ :param cookies: Cookies for the session.
+ :param tone: The tone of the response.
+ :param image: The image type to be used.
+ :param web_search: Flag to enable or disable web search.
+ :return: An asynchronous result object.
+ """
if len(messages) < 2:
prompt = messages[0]["content"]
context = None
@@ -56,65 +75,48 @@ class Bing(AsyncGeneratorProvider):
return stream_generate(prompt, tone, image, context, proxy, cookies, web_search, gpt4_turbo, timeout)
-def create_context(messages: Messages):
+def create_context(messages: Messages) -> str:
+ """
+ Creates a context string from a list of messages.
+
+ :param messages: A list of message dictionaries.
+ :return: A string representing the context created from the messages.
+ """
return "".join(
- f"[{message['role']}]" + ("(#message)" if message['role']!="system" else "(#additional_instructions)") + f"\n{message['content']}\n\n"
+ f"[{message['role']}]" + ("(#message)" if message['role'] != "system" else "(#additional_instructions)") + f"\n{message['content']}\n\n"
for message in messages
)
class Defaults:
+ """
+ Default settings and configurations for the Bing provider.
+ """
delimiter = "\x1e"
ip_address = f"13.{random.randint(104, 107)}.{random.randint(0, 255)}.{random.randint(0, 255)}"
+ # List of allowed message types for Bing responses
allowedMessageTypes = [
- "ActionRequest",
- "Chat",
- "Context",
- # "Disengaged", unwanted
- "Progress",
- # "AdsQuery", unwanted
- "SemanticSerp",
- "GenerateContentQuery",
- "SearchQuery",
- # The following message types should not be added so that it does not flood with
- # useless messages (such as "Analyzing images" or "Searching the web") while it's retrieving the AI response
- # "InternalSearchQuery",
- # "InternalSearchResult",
- "RenderCardRequest",
- # "RenderContentRequest"
+ "ActionRequest", "Chat", "Context", "Progress", "SemanticSerp",
+ "GenerateContentQuery", "SearchQuery", "RenderCardRequest"
]
sliceIds = [
- 'abv2',
- 'srdicton',
- 'convcssclick',
- 'stylewv2',
- 'contctxp2tf',
- '802fluxv1pc_a',
- '806log2sphs0',
- '727savemem',
- '277teditgnds0',
- '207hlthgrds0',
+ 'abv2', 'srdicton', 'convcssclick', 'stylewv2', 'contctxp2tf',
+ '802fluxv1pc_a', '806log2sphs0', '727savemem', '277teditgnds0', '207hlthgrds0'
]
+ # Default location settings
location = {
- "locale": "en-US",
- "market": "en-US",
- "region": "US",
- "locationHints": [
- {
- "country": "United States",
- "state": "California",
- "city": "Los Angeles",
- "timezoneoffset": 8,
- "countryConfidence": 8,
- "Center": {"Latitude": 34.0536909, "Longitude": -118.242766},
- "RegionType": 2,
- "SourceType": 1,
- }
- ],
+ "locale": "en-US", "market": "en-US", "region": "US",
+ "locationHints": [{
+ "country": "United States", "state": "California", "city": "Los Angeles",
+ "timezoneoffset": 8, "countryConfidence": 8,
+ "Center": {"Latitude": 34.0536909, "Longitude": -118.242766},
+ "RegionType": 2, "SourceType": 1
+ }],
}
+ # Default headers for requests
headers = {
'accept': '*/*',
'accept-language': 'en-US,en;q=0.9',
@@ -139,23 +141,13 @@ class Defaults:
}
optionsSets = [
- 'nlu_direct_response_filter',
- 'deepleo',
- 'disable_emoji_spoken_text',
- 'responsible_ai_policy_235',
- 'enablemm',
- 'iyxapbing',
- 'iycapbing',
- 'gencontentv3',
- 'fluxsrtrunc',
- 'fluxtrunc',
- 'fluxv1',
- 'rai278',
- 'replaceurl',
- 'eredirecturl',
- 'nojbfedge'
+ 'nlu_direct_response_filter', 'deepleo', 'disable_emoji_spoken_text',
+ 'responsible_ai_policy_235', 'enablemm', 'iyxapbing', 'iycapbing',
+ 'gencontentv3', 'fluxsrtrunc', 'fluxtrunc', 'fluxv1', 'rai278',
+ 'replaceurl', 'eredirecturl', 'nojbfedge'
]
+ # Default cookies
cookies = {
'SRCHD' : 'AF=NOFORM',
'PPLState' : '1',
@@ -166,6 +158,12 @@ class Defaults:
}
def format_message(msg: dict) -> str:
+ """
+ Formats a message dictionary into a JSON string with a delimiter.
+
+ :param msg: The message dictionary to format.
+ :return: A formatted string representation of the message.
+ """
return json.dumps(msg, ensure_ascii=False) + Defaults.delimiter
def create_message(
@@ -177,7 +175,20 @@ def create_message(
web_search: bool = False,
gpt4_turbo: bool = False
) -> str:
+ """
+ Creates a message for the Bing API with specified parameters.
+
+ :param conversation: The current conversation object.
+ :param prompt: The user's input prompt.
+ :param tone: The desired tone for the response.
+ :param context: Additional context for the prompt.
+ :param image_response: The response if an image is involved.
+ :param web_search: Flag to enable web search.
+ :param gpt4_turbo: Flag to enable GPT-4 Turbo.
+ :return: A formatted string message for the Bing API.
+ """
options_sets = Defaults.optionsSets
+ # Append tone-specific options
if tone == Tones.creative:
options_sets.append("h3imaginative")
elif tone == Tones.precise:
@@ -186,54 +197,49 @@ def create_message(
options_sets.append("galileo")
else:
options_sets.append("harmonyv3")
-
+
+ # Additional configurations based on parameters
if not web_search:
options_sets.append("nosearchall")
-
if gpt4_turbo:
options_sets.append("dlgpt4t")
-
+
request_id = str(uuid.uuid4())
struct = {
- 'arguments': [
- {
- 'source': 'cib',
- 'optionsSets': options_sets,
- 'allowedMessageTypes': Defaults.allowedMessageTypes,
- 'sliceIds': Defaults.sliceIds,
- 'traceId': os.urandom(16).hex(),
- 'isStartOfSession': True,
+ 'arguments': [{
+ 'source': 'cib', 'optionsSets': options_sets,
+ 'allowedMessageTypes': Defaults.allowedMessageTypes,
+ 'sliceIds': Defaults.sliceIds,
+ 'traceId': os.urandom(16).hex(), 'isStartOfSession': True,
+ 'requestId': request_id,
+ 'message': {
+ **Defaults.location,
+ 'author': 'user',
+ 'inputMethod': 'Keyboard',
+ 'text': prompt,
+ 'messageType': 'Chat',
'requestId': request_id,
- 'message': {**Defaults.location, **{
- 'author': 'user',
- 'inputMethod': 'Keyboard',
- 'text': prompt,
- 'messageType': 'Chat',
- 'requestId': request_id,
- 'messageId': request_id,
- }},
- "verbosity": "verbose",
- "scenario": "SERP",
- "plugins":[
- {"id":"c310c353-b9f0-4d76-ab0d-1dd5e979cf68", "category": 1}
- ] if web_search else [],
- 'tone': tone,
- 'spokenTextMode': 'None',
- 'conversationId': conversation.conversationId,
- 'participant': {
- 'id': conversation.clientId
- },
- }
- ],
+ 'messageId': request_id
+ },
+ "verbosity": "verbose",
+ "scenario": "SERP",
+ "plugins": [{"id": "c310c353-b9f0-4d76-ab0d-1dd5e979cf68", "category": 1}] if web_search else [],
+ 'tone': tone,
+ 'spokenTextMode': 'None',
+ 'conversationId': conversation.conversationId,
+ 'participant': {'id': conversation.clientId},
+ }],
'invocationId': '1',
'target': 'chat',
'type': 4
}
- if image_response.get('imageUrl') and image_response.get('originalImageUrl'):
+
+ if image_response and image_response.get('imageUrl') and image_response.get('originalImageUrl'):
struct['arguments'][0]['message']['originalImageUrl'] = image_response.get('originalImageUrl')
struct['arguments'][0]['message']['imageUrl'] = image_response.get('imageUrl')
struct['arguments'][0]['experienceType'] = None
struct['arguments'][0]['attachedFileInfo'] = {"fileName": None, "fileType": None}
+
if context:
struct['arguments'][0]['previousMessages'] = [{
"author": "user",
@@ -242,30 +248,46 @@ def create_message(
"messageType": "Context",
"messageId": "discover-web--page-ping-mriduna-----"
}]
+
return format_message(struct)
async def stream_generate(
- prompt: str,
- tone: str,
- image: ImageType = None,
- context: str = None,
- proxy: str = None,
- cookies: dict = None,
- web_search: bool = False,
- gpt4_turbo: bool = False,
- timeout: int = 900
- ):
+ prompt: str,
+ tone: str,
+ image: ImageType = None,
+ context: str = None,
+ proxy: str = None,
+ cookies: dict = None,
+ web_search: bool = False,
+ gpt4_turbo: bool = False,
+ timeout: int = 900
+):
+ """
+ Asynchronously streams generated responses from the Bing API.
+
+ :param prompt: The user's input prompt.
+ :param tone: The desired tone for the response.
+ :param image: The image type involved in the response.
+ :param context: Additional context for the prompt.
+ :param proxy: Proxy settings for the request.
+ :param cookies: Cookies for the session.
+ :param web_search: Flag to enable web search.
+ :param gpt4_turbo: Flag to enable GPT-4 Turbo.
+ :param timeout: Timeout for the request.
+ :return: An asynchronous generator yielding responses.
+ """
headers = Defaults.headers
if cookies:
headers["Cookie"] = "; ".join(f"{k}={v}" for k, v in cookies.items())
+
async with ClientSession(
- timeout=ClientTimeout(total=timeout),
- headers=headers
+ timeout=ClientTimeout(total=timeout), headers=headers
) as session:
conversation = await create_conversation(session, proxy)
image_response = await upload_image(session, image, tone, proxy) if image else None
if image_response:
yield image_response
+
try:
async with session.ws_connect(
'wss://sydney.bing.com/sydney/ChatHub',
@@ -289,7 +311,7 @@ async def stream_generate(
if obj is None or not obj:
continue
response = json.loads(obj)
- if response.get('type') == 1 and response['arguments'][0].get('messages'):
+ if response and response.get('type') == 1 and response['arguments'][0].get('messages'):
message = response['arguments'][0]['messages'][0]
image_response = None
if (message['contentOrigin'] != 'Apology'):