返回提交历史
Modified
g4f/Provider/Bing.py
+84
-35
Modified
g4f/Provider/bing/conversation.py
+5
-2
Modified
g4f/gui/client/static/js/chat.v1.js
+3
-1
Modified
g4f/gui/server/api.py
+20
-7
Modified
g4f/gui/server/backend.py
+1
-1
XFEstudio/gpt4free
Add conversation support for Bing
47783560
代码差异
5 个文件
+113
-46
@@ -51,6 +51,7 @@ class Bing(AsyncGeneratorProvider, ProviderModelMixin):
51
51
tone: str = None,
52
52
image: ImageType = None,
53
53
web_search: bool = False,
54
context: str = None,
54
55
**kwargs
55
56
) -> AsyncResult:
56
57
"""
@@ -67,7 +68,8 @@ class Bing(AsyncGeneratorProvider, ProviderModelMixin):
67
68
:return: An asynchronous result object.
68
69
"""
69
70
prompt = messages[-1]["content"]
70
context = create_context(messages[:-1]) if len(messages) > 1 else None
71
if context is None:
72
context = create_context(messages[:-1]) if len(messages) > 1 else None
71
73
if tone is None:
72
74
tone = tone if model.startswith("gpt-4") else model
73
75
tone = cls.get_model("" if tone is None else tone.lower())
@@ -126,7 +128,7 @@ class Defaults:
126
128
"ActionRequest","Chat",
127
129
"ConfirmationCard", "Context",
128
130
"InternalSearchQuery", #"InternalSearchResult",
129
"Disengaged", #"InternalLoaderMessage",
131
#"Disengaged", "InternalLoaderMessage",
130
132
"Progress", "RenderCardRequest",
131
133
"RenderContentRequest", "AdsQuery",
132
134
"SemanticSerp", "GenerateContentQuery",
@@ -160,30 +162,62 @@ class Defaults:
160
162
}
161
163
162
164
optionsSets = {
163
"balanced": [
164
"nlu_direct_response_filter", "deepleo",
165
"disable_emoji_spoken_text", "responsible_ai_policy_235",
166
"enablemm", "dv3sugg", "autosave",
167
"iyxapbing", "iycapbing",
168
"galileo", "saharagenconv5", "gldcl1p",
169
"gpt4tmncnp"
170
],
171
"creative": [
172
"nlu_direct_response_filter", "deepleo",
173
"disable_emoji_spoken_text", "responsible_ai_policy_235",
174
"enablemm", "dv3sugg",
175
"iyxapbing", "iycapbing",
176
"h3imaginative", "techinstgnd", "hourthrot", "clgalileo", "gencontentv3",
177
"gpt4tmncnp"
178
],
179
"precise": [
180
"nlu_direct_response_filter", "deepleo",
181
"disable_emoji_spoken_text", "responsible_ai_policy_235",
182
"enablemm", "dv3sugg",
183
"iyxapbing", "iycapbing",
184
"h3precise", "techinstgnd", "hourthrot", "techinstgnd", "hourthrot",
185
"clgalileo", "gencontentv3"
186
],
165
"balanced": {
166
"default": [
167
"nlu_direct_response_filter", "deepleo",
168
"disable_emoji_spoken_text", "responsible_ai_policy_235",
169
"enablemm", "dv3sugg", "autosave",
170
"iyxapbing", "iycapbing",
171
"galileo", "saharagenconv5", "gldcl1p",
172
"gpt4tmncnp"
173
],
174
"nosearch": [
175
"nlu_direct_response_filter", "deepleo",
176
"disable_emoji_spoken_text", "responsible_ai_policy_235",
177
"enablemm", "dv3sugg", "autosave",
178
"iyxapbing", "iycapbing",
179
"galileo", "sunoupsell", "base64filter", "uprv4p1upd",
180
"hourthrot", "noctprf", "gndlogcf", "nosearchall"
181
]
182
},
183
"creative": {
184
"default": [
185
"nlu_direct_response_filter", "deepleo",
186
"disable_emoji_spoken_text", "responsible_ai_policy_235",
187
"enablemm", "dv3sugg",
188
"iyxapbing", "iycapbing",
189
"h3imaginative", "techinstgnd", "hourthrot", "clgalileo", "gencontentv3",
190
"gpt4tmncnp"
191
],
192
"nosearch": [
193
"nlu_direct_response_filter", "deepleo",
194
"disable_emoji_spoken_text", "responsible_ai_policy_235",
195
"enablemm", "dv3sugg", "autosave",
196
"iyxapbing", "iycapbing",
197
"h3imaginative", "sunoupsell", "base64filter", "uprv4p1upd",
198
"hourthrot", "noctprf", "gndlogcf", "nosearchall",
199
"clgalileo", "nocache", "up4rp14bstcst"
200
]
201
},
202
"precise": {
203
"default": [
204
"nlu_direct_response_filter", "deepleo",
205
"disable_emoji_spoken_text", "responsible_ai_policy_235",
206
"enablemm", "dv3sugg",
207
"iyxapbing", "iycapbing",
208
"h3precise", "techinstgnd", "hourthrot", "techinstgnd", "hourthrot",
209
"clgalileo", "gencontentv3"
210
],
211
"nosearch": [
212
"nlu_direct_response_filter", "deepleo",
213
"disable_emoji_spoken_text", "responsible_ai_policy_235",
214
"enablemm", "dv3sugg", "autosave",
215
"iyxapbing", "iycapbing",
216
"h3precise", "sunoupsell", "base64filter", "uprv4p1upd",
217
"hourthrot", "noctprf", "gndlogcf", "nosearchall",
218
"clgalileo", "nocache", "up4rp14bstcst"
219
]
220
},
187
221
"copilot": [
188
222
"nlu_direct_response_filter", "deepleo",
189
223
"disable_emoji_spoken_text", "responsible_ai_policy_235",
@@ -244,7 +278,8 @@ def create_message(
244
278
context: str = None,
245
279
image_request: ImageRequest = None,
246
280
web_search: bool = False,
247
gpt4_turbo: bool = False
281
gpt4_turbo: bool = False,
282
new_conversation: bool = True
248
283
) -> str:
249
284
"""
250
285
Creates a message for the Bing API with specified parameters.
@@ -259,7 +294,12 @@ def create_message(
259
294
:return: A formatted string message for the Bing API.
260
295
"""
261
296
262
options_sets = []
297
options_sets = Defaults.optionsSets[tone]
298
if not web_search and "nosearch" in options_sets:
299
options_sets = options_sets["nosearch"]
300
elif "default" in options_sets:
301
options_sets = options_sets["default"]
302
options_sets = options_sets.copy()
263
303
if gpt4_turbo:
264
304
options_sets.append("dlgpt4t")
265
305
@@ -267,7 +307,7 @@ def create_message(
267
307
struct = {
268
308
"arguments":[{
269
309
"source": "cib",
270
"optionsSets": [*Defaults.optionsSets[tone], *options_sets],
310
"optionsSets": options_sets,
271
311
"allowedMessageTypes": Defaults.allowedMessageTypes,
272
312
"sliceIds": Defaults.sliceIds[tone],
273
313
"verbosity": "verbose",
@@ -276,7 +316,7 @@ def create_message(
276
316
"traceId": get_random_hex(40),
277
317
"conversationHistoryOptionsSets": ["autosave","savemem","uprofupd","uprofgen"],
278
318
"gptId": "copilot",
279
"isStartOfSession": True,
319
"isStartOfSession": new_conversation,
280
320
"requestId": request_id,
281
321
"message":{
282
322
**Defaults.location,
@@ -330,7 +370,7 @@ async def stream_generate(
330
370
conversation: Conversation = None,
331
371
return_conversation: bool = False,
332
372
raise_apology: bool = False,
333
max_retries: int = 5,
373
max_retries: int = None,
334
374
sleep_retry: int = 15,
335
375
**kwargs
336
376
):
@@ -348,6 +388,8 @@ async def stream_generate(
348
388
:return: An asynchronous generator yielding responses.
349
389
"""
350
390
headers = create_headers(cookies)
391
new_conversation = conversation is None
392
max_retries = (5 if new_conversation else 0) if max_retries is None else max_retries
351
393
async with ClientSession(
352
394
timeout=ClientTimeout(total=timeout), connector=connector
353
395
) as session:
@@ -357,9 +399,9 @@ async def stream_generate(
357
399
do_read = True
358
400
try:
359
401
if conversation is None:
360
conversation = await create_conversation(session, headers)
361
if return_conversation:
362
yield conversation
402
conversation = await create_conversation(session, headers, tone)
403
if return_conversation:
404
yield conversation
363
405
except ResponseStatusError as e:
364
406
max_retries -= 1
365
407
if max_retries < 1:
@@ -372,6 +414,8 @@ async def stream_generate(
372
414
373
415
image_request = await upload_image(session, image, getattr(Tones, tone), headers) if image else None
374
416
async with session.ws_connect(
417
'wss://s.copilot.microsoft.com/sydney/ChatHub'
418
if tone == "copilot" else
375
419
'wss://sydney.bing.com/sydney/ChatHub',
376
420
autoping=False,
377
421
params={'sec_access_token': conversation.conversationSignature},
@@ -380,7 +424,12 @@ async def stream_generate(
380
424
await wss.send_str(format_message({'protocol': 'json', 'version': 1}))
381
425
await wss.send_str(format_message({"type": 6}))
382
426
await wss.receive(timeout=timeout)
383
await wss.send_str(create_message(conversation, prompt, tone, context, image_request, web_search, gpt4_turbo))
427
await wss.send_str(create_message(
428
conversation, prompt, tone,
429
context if new_conversation else None,
430
image_request, web_search, gpt4_turbo,
431
new_conversation
432
))
384
433
response_txt = ''
385
434
returned_text = ''
386
435
message_id = None
@@ -20,7 +20,7 @@ class Conversation:
20
20
self.clientId = clientId
21
21
self.conversationSignature = conversationSignature
22
22
23
async def create_conversation(session: ClientSession, headers: dict) -> Conversation:
23
async def create_conversation(session: ClientSession, headers: dict, tone: str) -> Conversation:
24
24
"""
25
25
Create a new conversation asynchronously.
26
26
@@ -31,7 +31,10 @@ async def create_conversation(session: ClientSession, headers: dict) -> Conversa
31
31
Returns:
32
32
Conversation: An instance representing the created conversation.
33
33
"""
34
url = "https://www.bing.com/turing/conversation/create?bundleVersion=1.1626.1"
34
if tone == "copilot":
35
url = "https://copilot.microsoft.com/turing/conversation/create?bundleVersion=1.1634.3-nodesign2"
36
else:
37
url = "https://www.bing.com/turing/conversation/create?bundleVersion=1.1626.1"
35
38
async with session.get(url, headers=headers) as response:
36
39
await raise_for_status(response, "Failed to create conversation")
37
40
data = await response.json()
@@ -198,7 +198,9 @@ const prepare_messages = (messages, filter_last_message=true) => {
198
198
}
199
199
200
200
async function add_message_chunk(message) {
201
if (message.type == "provider") {
201
if (message.type == "conversation") {
202
console.info("Conversation used:", message.conversation)
203
} else if (message.type == "provider") {
202
204
window.provider_result = message.provider;
203
205
window.content.querySelector('.provider').innerHTML = `
204
206
<a href="${message.provider.url}" target="_blank">
@@ -13,8 +13,12 @@ from g4f.errors import VersionNotFoundError
13
13
from g4f.Provider import ProviderType, __providers__, __map__
14
14
from g4f.providers.base_provider import ProviderModelMixin
15
15
from g4f.Provider.bing.create_images import patch_provider
16
from g4f.Provider.Bing import Conversation
17
18
conversations: dict[str, Conversation] = {}
19
20
class Api():
16
21
17
class Api():
18
22
def get_models(self) -> list[str]:
19
23
"""
20
24
Return a list of all models.
@@ -73,7 +77,8 @@ class Api():
73
77
def get_conversation(self, options: dict, **kwargs) -> Iterator:
74
78
window = webview.active_window()
75
79
for message in self._create_response_stream(
76
self._prepare_conversation_kwargs(options, kwargs)
80
self._prepare_conversation_kwargs(options, kwargs),
81
options.get("conversation_id")
77
82
):
78
83
window.evaluate_js(f"this.add_message_chunk({json.dumps(message)})")
79
84
@@ -101,6 +106,10 @@ class Api():
101
106
from .internet import get_search_message
102
107
messages[-1]["content"] = get_search_message(messages[-1]["content"])
103
108
109
conversation_id = json_data.get("conversation_id")
110
if conversation_id and conversation_id in conversations:
111
kwargs["conversation"] = conversations[conversation_id]
112
104
113
model = json_data.get('model')
105
114
model = model if model else models.default
106
115
patch = patch_provider if json_data.get('patch_provider') else None
@@ -112,10 +121,11 @@ class Api():
112
121
"stream": True,
113
122
"ignore_stream": True,
114
123
"patch_provider": patch,
124
"return_conversation": True,
115
125
**kwargs
116
126
}
117
127
118
def _create_response_stream(self, kwargs) -> Iterator:
128
def _create_response_stream(self, kwargs, conversation_id: str) -> Iterator:
119
129
"""
120
130
Creates and returns a streaming response for the conversation.
121
131
@@ -133,12 +143,15 @@ class Api():
133
143
for chunk in ChatCompletion.create(**kwargs):
134
144
if first:
135
145
first = False
136
yield self._format_json('provider', get_last_provider(True))
137
if isinstance(chunk, Exception):
146
yield self._format_json("provider", get_last_provider(True))
147
if isinstance(chunk, Conversation):
148
conversations[conversation_id] = chunk
149
yield self._format_json("conversation", conversation_id)
150
elif isinstance(chunk, Exception):
138
151
logging.exception(chunk)
139
yield self._format_json('message', get_error_message(chunk))
152
yield self._format_json("message", get_error_message(chunk))
140
153
else:
141
yield self._format_json('content', chunk)
154
yield self._format_json("content", chunk)
142
155
except Exception as e:
143
156
logging.exception(e)
144
157
yield self._format_json('error', get_error_message(e))
@@ -85,7 +85,7 @@ class Backend_Api(Api):
85
85
kwargs = self._prepare_conversation_kwargs(json_data, kwargs)
86
86
87
87
return self.app.response_class(
88
self._create_response_stream(kwargs),
88
self._create_response_stream(kwargs, json_data.get("conversation_id")),
89
89
mimetype='text/event-stream'
90
90
)
91
91