XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/gpt4free

Add conversation support for Bing

47783560
Heiner Lohaus <hlohaus@users.noreply.github.com>
提交于

代码差异

5 个文件 +113 -46
Modified g4f/Provider/Bing.py +84 -35
@@ -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
Modified g4f/Provider/bing/conversation.py +5 -2
@@ -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()
Modified g4f/gui/client/static/js/chat.v1.js +3 -1
@@ -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">
Modified g4f/gui/server/api.py +20 -7
@@ -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))
Modified g4f/gui/server/backend.py +1 -1
@@ -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