返回提交历史
Modified
g4f/Provider/bing/conversation.py
+3
-2
Modified
g4f/Provider/needs_auth/OpenaiChat.py
+20
-28
Modified
g4f/Provider/openai/har_file.py
+19
-13
Modified
g4f/gui/server/api.py
+4
-4
Added
g4f/providers/conversation.py
+2
-0
XFEstudio/gpt4free
No arkose token and .har files
95bab66d
代码差异
5 个文件
+48
-47
@@ -3,8 +3,9 @@ from __future__ import annotations
3
3
from aiohttp import ClientSession
4
4
from ...requests import raise_for_status
5
5
from ...errors import RateLimitError
6
from ...providers.conversation import BaseConversation
6
7
7
class Conversation:
8
class Conversation(BaseConversation):
8
9
"""
9
10
Represents a conversation with specific attributes.
10
11
"""
@@ -32,7 +33,7 @@ async def create_conversation(session: ClientSession, headers: dict, tone: str)
32
33
Returns:
33
34
Conversation: An instance representing the created conversation.
34
35
"""
35
if tone == "copilot":
36
if tone == "Copilot":
36
37
url = "https://copilot.microsoft.com/turing/conversation/create?bundleVersion=1.1634.3-nodesign2"
37
38
else:
38
39
url = "https://www.bing.com/turing/conversation/create?bundleVersion=1.1626.1"
@@ -3,10 +3,10 @@ from __future__ import annotations
3
3
import asyncio
4
4
import uuid
5
5
import json
6
import os
7
6
import base64
8
7
import time
9
8
from aiohttp import ClientWebSocketResponse
9
from copy import copy
10
10
11
11
try:
12
12
import webview
@@ -22,13 +22,13 @@ except ImportError:
22
22
pass
23
23
24
24
from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin
25
from ..helper import get_cookies
26
25
from ...webdriver import get_browser
27
26
from ...typing import AsyncResult, Messages, Cookies, ImageType, Union, AsyncIterator
28
27
from ...requests import get_args_from_browser, raise_for_status
29
28
from ...requests.aiohttp import StreamSession
30
29
from ...image import to_image, to_bytes, ImageResponse, ImageRequest
31
from ...errors import MissingRequirementsError, MissingAuthError, ProviderNotWorkingError
30
from ...errors import MissingAuthError
31
from ...providers.conversation import BaseConversation
32
32
from ..openai.har_file import getArkoseAndAccessToken
33
33
from ... import debug
34
34
@@ -56,11 +56,6 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
56
56
prompt: str = None,
57
57
model: str = "",
58
58
messages: Messages = [],
59
history_disabled: bool = False,
60
action: str = "next",
61
conversation_id: str = None,
62
parent_id: str = None,
63
image: ImageType = None,
64
59
**kwargs
65
60
) -> Response:
66
61
"""
@@ -89,12 +84,7 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
89
84
generator = cls.create_async_generator(
90
85
model,
91
86
messages,
92
history_disabled=history_disabled,
93
action=action,
94
conversation_id=conversation_id,
95
parent_id=parent_id,
96
image=image,
97
response_fields=True,
87
return_conversation=True,
98
88
**kwargs
99
89
)
100
90
return Response(
@@ -209,7 +199,7 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
209
199
} for message in messages]
210
200
211
201
# Check if there is an image response
212
if image_request:
202
if image_request is not None:
213
203
# Change content in last user message
214
204
messages[-1]["content"] = {
215
205
"content_type": "multimodal_text",
@@ -308,10 +298,11 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
308
298
history_disabled: bool = True,
309
299
action: str = "next",
310
300
conversation_id: str = None,
301
conversation: Conversation = None,
311
302
parent_id: str = None,
312
303
image: ImageType = None,
313
304
image_name: str = None,
314
response_fields: bool = False,
305
return_conversation: bool = False,
315
306
**kwargs
316
307
) -> AsyncResult:
317
308
"""
@@ -330,7 +321,7 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
330
321
conversation_id (str): ID of the conversation.
331
322
parent_id (str): ID of the parent message.
332
323
image (ImageType): Image to include in the conversation.
333
response_fields (bool): Flag to include response fields in the output.
324
return_conversation (bool): Flag to include response fields in the output.
334
325
**kwargs: Additional keyword arguments.
335
326
336
327
Yields:
@@ -387,6 +378,8 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
387
378
arkose_token, api_key, cookies = await getArkoseAndAccessToken(proxy)
388
379
cls._create_request_args(cookies)
389
380
cls._set_api_key(api_key)
381
if arkose_token is None:
382
raise MissingAuthError("No arkose token found in .har file")
390
383
391
384
try:
392
385
image_request = await cls.upload_image(session, cls._headers, image, image_name) if image else None
@@ -396,7 +389,8 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
396
389
print(f"{e.__class__.__name__}: {e}")
397
390
398
391
model = cls.get_model(model).replace("gpt-3.5-turbo", "text-davinci-002-render-sha")
399
fields = ResponseFields()
392
fields = Conversation() if conversation is None else copy(conversation)
393
fields.finish_reason = None
400
394
while fields.finish_reason is None:
401
395
conversation_id = conversation_id if fields.conversation_id is None else fields.conversation_id
402
396
parent_id = parent_id if fields.message_id is None else fields.message_id
@@ -422,8 +416,6 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
422
416
}
423
417
if need_arkose:
424
418
headers["OpenAI-Sentinel-Arkose-Token"] = arkose_token
425
headers["OpenAI-Sentinel-Chat-Requirements-Token"] = chat_token
426
427
419
async with session.post(
428
420
f"{cls.url}/backend-api/conversation",
429
421
json=data,
@@ -432,15 +424,15 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
432
424
cls._update_request_args(session)
433
425
await raise_for_status(response)
434
426
async for chunk in cls.iter_messages_chunk(response.iter_lines(), session, fields):
435
if response_fields:
436
response_fields = False
427
if return_conversation:
428
return_conversation = False
437
429
yield fields
438
430
yield chunk
439
431
if not auto_continue:
440
432
break
441
433
action = "continue"
442
434
await asyncio.sleep(5)
443
if history_disabled and auto_continue:
435
if history_disabled and auto_continue and not return_conversation:
444
436
await cls.delete_conversation(session, cls._headers, fields.conversation_id)
445
437
446
438
@staticmethod
@@ -458,7 +450,7 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
458
450
cls,
459
451
messages: AsyncIterator,
460
452
session: StreamSession,
461
fields: ResponseFields
453
fields: Conversation
462
454
) -> AsyncIterator:
463
455
last_message: int = 0
464
456
async for message in messages:
@@ -487,7 +479,7 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
487
479
break
488
480
489
481
@classmethod
490
async def iter_messages_line(cls, session: StreamSession, line: bytes, fields: ResponseFields) -> AsyncIterator:
482
async def iter_messages_line(cls, session: StreamSession, line: bytes, fields: Conversation) -> AsyncIterator:
491
483
if not line.startswith(b"data: "):
492
484
return
493
485
elif line.startswith(b"data: [DONE]"):
@@ -618,7 +610,7 @@ this.fetch = async (url, options) => {
618
610
@classmethod
619
611
def _update_request_args(cls, session: StreamSession):
620
612
for c in session.cookie_jar if hasattr(session, "cookie_jar") else session.cookies.jar:
621
cls._cookies[c.name if hasattr(c, "name") else c.key] = c.value
613
cls._cookies[c.key if hasattr(c, "key") else c.name] = c.value
622
614
cls._update_cookie_header()
623
615
624
616
@classmethod
@@ -631,7 +623,7 @@ this.fetch = async (url, options) => {
631
623
def _update_cookie_header(cls):
632
624
cls._headers["Cookie"] = cls._format_cookies(cls._cookies)
633
625
634
class ResponseFields:
626
class Conversation(BaseConversation):
635
627
"""
636
628
Class to encapsulate response fields.
637
629
"""
@@ -664,7 +656,7 @@ class Response():
664
656
self._generator = None
665
657
chunks = []
666
658
async for chunk in self._generator:
667
if isinstance(chunk, ResponseFields):
659
if isinstance(chunk, Conversation):
668
660
self._fields = chunk
669
661
else:
670
662
yield chunk
@@ -11,11 +11,6 @@ from copy import deepcopy
11
11
from .crypt import decrypt, encrypt
12
12
from ...requests import StreamSession
13
13
14
arkPreURL = "https://tcr9i.chat.openai.com/fc/gt2/public_key/35536E1E-65B4-4D96-9D97-6ADB7EFF8147"
15
sessionUrl = "https://chat.openai.com/api/auth/session"
16
chatArk = None
17
accessToken = None
18
19
14
class arkReq:
20
15
def __init__(self, arkURL, arkBx, arkHeader, arkBody, arkCookies, userAgent):
21
16
self.arkURL = arkURL
@@ -25,15 +20,24 @@ class arkReq:
25
20
self.arkCookies = arkCookies
26
21
self.userAgent = userAgent
27
22
23
arkPreURL = "https://tcr9i.chat.openai.com/fc/gt2/public_key/35536E1E-65B4-4D96-9D97-6ADB7EFF8147"
24
sessionUrl = "https://chat.openai.com/api/auth/session"
25
chatArk: arkReq = None
26
accessToken: str = None
27
cookies: dict = None
28
28
29
def readHAR():
29
30
dirPath = "./"
30
31
harPath = []
31
32
chatArks = []
32
33
accessToken = None
34
cookies = {}
33
35
for root, dirs, files in os.walk(dirPath):
34
36
for file in files:
35
37
if file.endswith(".har"):
36
38
harPath.append(os.path.join(root, file))
39
if harPath:
40
break
37
41
if not harPath:
38
42
raise RuntimeError("No .har file found")
39
43
for path in harPath:
@@ -48,11 +52,12 @@ def readHAR():
48
52
chatArks.append(parseHAREntry(v))
49
53
elif v['request']['url'] == sessionUrl:
50
54
accessToken = json.loads(v["response"]["content"]["text"]).get("accessToken")
51
if not chatArks:
52
RuntimeError("No arkose requests found in .har files")
55
cookies = {c['name']: c['value'] for c in v['request']['cookies']}
53
56
if not accessToken:
54
57
RuntimeError("No accessToken found in .har files")
55
return chatArks.pop(), accessToken
58
if not chatArks:
59
return None, accessToken, cookies
60
return chatArks.pop(), accessToken, cookies
56
61
57
62
def parseHAREntry(entry) -> arkReq:
58
63
tmpArk = arkReq(
@@ -60,7 +65,7 @@ def parseHAREntry(entry) -> arkReq:
60
65
arkBx="",
61
66
arkHeader={h['name'].lower(): h['value'] for h in entry['request']['headers'] if h['name'].lower() not in ['content-length', 'cookie'] and not h['name'].startswith(':')},
62
67
arkBody={p['name']: unquote(p['value']) for p in entry['request']['postData']['params'] if p['name'] not in ['rnd']},
63
arkCookies=[{'name': c['name'], 'value': c['value'], 'expires': c['expires']} for c in entry['request']['cookies']],
68
arkCookies={c['name']: c['value'] for c in entry['request']['cookies']},
64
69
userAgent=""
65
70
)
66
71
tmpArk.userAgent = tmpArk.arkHeader.get('user-agent', '')
@@ -81,7 +86,6 @@ def genArkReq(chatArk: arkReq) -> arkReq:
81
86
tmpArk.arkBody['bda'] = base64.b64encode(bda.encode()).decode()
82
87
tmpArk.arkBody['rnd'] = str(random.random())
83
88
tmpArk.arkHeader['x-ark-esync-value'] = bw
84
tmpArk.arkCookies = {cookie['name']: cookie['value'] for cookie in tmpArk.arkCookies}
85
89
return tmpArk
86
90
87
91
async def sendRequest(tmpArk: arkReq, proxy: str = None):
@@ -117,8 +121,10 @@ def getN() -> str:
117
121
return base64.b64encode(timestamp.encode()).decode()
118
122
119
123
async def getArkoseAndAccessToken(proxy: str):
120
global chatArk, accessToken
124
global chatArk, accessToken, cookies
121
125
if chatArk is None or accessToken is None:
122
chatArk, accessToken = readHAR()
126
chatArk, accessToken, cookies = readHAR()
127
if chatArk is None:
128
return None, accessToken, cookies
123
129
newReq = genArkReq(chatArk)
124
return await sendRequest(newReq, proxy), accessToken, newReq.arkCookies
130
return await sendRequest(newReq, proxy), accessToken, cookies
@@ -39,9 +39,9 @@ from g4f.errors import VersionNotFoundError
39
39
from g4f.Provider import ProviderType, __providers__, __map__
40
40
from g4f.providers.base_provider import ProviderModelMixin
41
41
from g4f.Provider.bing.create_images import patch_provider
42
from g4f.Provider.Bing import Conversation
42
from g4f.providers.conversation import BaseConversation
43
43
44
conversations: dict[str, Conversation] = {}
44
conversations: dict[str, BaseConversation] = {}
45
45
46
46
class Api():
47
47
@@ -230,14 +230,14 @@ class Api():
230
230
if first:
231
231
first = False
232
232
yield self._format_json("provider", get_last_provider(True))
233
if isinstance(chunk, Conversation):
233
if isinstance(chunk, BaseConversation):
234
234
conversations[conversation_id] = chunk
235
235
yield self._format_json("conversation", conversation_id)
236
236
elif isinstance(chunk, Exception):
237
237
logging.exception(chunk)
238
238
yield self._format_json("message", get_error_message(chunk))
239
239
else:
240
yield self._format_json("content", chunk)
240
yield self._format_json("content", str(chunk))
241
241
except Exception as e:
242
242
logging.exception(e)
243
243
yield self._format_json('error', get_error_message(e))
@@ -0,0 +1,2 @@
1
class BaseConversation:
2
...