返回提交历史
Modified
etc/unittest/integration.py
+1
-1
Modified
g4f/Provider/Bing.py
+68
-55
Modified
g4f/Provider/MetaAI.py
+63
-31
Added
g4f/Provider/MetaAIAccount.py
+21
-0
Modified
g4f/Provider/You.py
+5
-2
Modified
g4f/Provider/__init__.py
+1
-0
Modified
g4f/Provider/bing/conversation.py
+4
-5
Modified
g4f/Provider/needs_auth/OpenaiChat.py
+8
-15
Modified
g4f/Provider/you/har_file.py
+23
-35
Modified
g4f/gui/client/static/js/chat.v1.js
+6
-2
Modified
g4f/gui/server/api.py
+3
-0
Modified
g4f/image.py
+10
-1
Modified
g4f/requests/aiohttp.py
+4
-1
Modified
g4f/requests/defaults.py
+21
-15
XFEstudio/gpt4free
Fix Bing Provider, Add Account Support for Meta AI Use default headers in OpenaiChat
db2d6cff
代码差异
14 个文件
+238
-163
@@ -10,7 +10,7 @@ except ImportError:
10
10
from g4f.client import Client, ChatCompletion
11
11
from g4f.Provider import Bing, OpenaiChat, DuckDuckGo
12
12
13
DEFAULT_MESSAGES = [{"role": "system", "content": 'Response in json, Example: {"success: true"}'},
13
DEFAULT_MESSAGES = [{"role": "system", "content": 'Response in json, Example: {"success": false}'},
14
14
{"role": "user", "content": "Say success true in json"}]
15
15
16
16
class TestProviderIntegration(unittest.TestCase):
@@ -7,13 +7,13 @@ import time
7
7
import asyncio
8
8
from urllib import parse
9
9
from datetime import datetime, date
10
from aiohttp import ClientSession, ClientTimeout, BaseConnector, WSMsgType
11
10
12
11
from ..typing import AsyncResult, Messages, ImageType, Cookies
13
12
from ..image import ImageRequest
14
from ..errors import ResponseStatusError, RateLimitError
13
from ..errors import ResponseError, ResponseStatusError, RateLimitError
14
from ..requests import StreamSession, DEFAULT_HEADERS
15
15
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
16
from .helper import get_connector, get_random_hex
16
from .helper import get_random_hex
17
17
from .bing.upload_image import upload_image
18
18
from .bing.conversation import Conversation, create_conversation, delete_conversation
19
19
from .BingCreateImages import BingCreateImages
@@ -49,7 +49,6 @@ class Bing(AsyncGeneratorProvider, ProviderModelMixin):
49
49
timeout: int = 900,
50
50
api_key: str = None,
51
51
cookies: Cookies = None,
52
connector: BaseConnector = None,
53
52
tone: str = None,
54
53
image: ImageType = None,
55
54
web_search: bool = False,
@@ -79,7 +78,6 @@ class Bing(AsyncGeneratorProvider, ProviderModelMixin):
79
78
80
79
return stream_generate(
81
80
prompt, tone, image, context, cookies, api_key,
82
get_connector(connector, proxy, True),
83
81
proxy, web_search, gpt4_turbo, timeout,
84
82
**kwargs
85
83
)
@@ -102,25 +100,53 @@ def get_ip_address() -> str:
102
100
return f"13.{random.randint(104, 107)}.{random.randint(0, 255)}.{random.randint(0, 255)}"
103
101
104
102
def get_default_cookies():
103
#muid = get_random_hex().upper()
104
sid = get_random_hex().upper()
105
guid = get_random_hex().upper()
106
isodate = date.today().isoformat()
107
timestamp = int(time.time())
108
zdate = "0001-01-01T00:00:00.0000000"
105
109
return {
106
'SRCHD' : 'AF=NOFORM',
107
'PPLState' : '1',
108
'KievRPSSecAuth': '',
109
'SUID' : '',
110
'SRCHUSR' : f'DOB={date.today().strftime("%Y%m%d")}&T={int(time.time())}',
111
'SRCHHPGUSR' : f'HV={int(time.time())}',
112
'BCP' : 'AD=1&AL=1&SM=1',
113
'_Rwho' : f'u=d&ts={date.today().isoformat()}',
110
"_C_Auth": "",
111
#"MUID": muid,
112
#"MUIDB": muid,
113
"_EDGE_S": f"F=1&SID={sid}",
114
"_EDGE_V": "1",
115
"SRCHD": "AF=hpcodx",
116
"SRCHUID": f"V=2&GUID={guid}&dmnchg=1",
117
"_RwBf": (
118
f"r=0&ilt=1&ihpd=0&ispd=0&rc=3&rb=0&gb=0&rg=200&pc=0&mtu=0&rbb=0&g=0&cid="
119
f"&clo=0&v=1&l={isodate}&lft={zdate}&aof=0&ard={zdate}"
120
f"&rwdbt={zdate}&rwflt={zdate}&o=2&p=&c=&t=0&s={zdate}"
121
f"&ts={isodate}&rwred=0&wls=&wlb="
122
"&wle=&ccp=&cpt=&lka=0&lkt=0&aad=0&TH="
123
),
124
'_Rwho': f'u=d&ts={isodate}',
125
"_SS": f"SID={sid}&R=3&RB=0&GB=0&RG=200&RP=0",
126
"SRCHUSR": f"DOB={date.today().strftime('%Y%m%d')}&T={timestamp}",
127
"SRCHHPGUSR": f"HV={int(time.time())}",
128
"BCP": "AD=1&AL=1&SM=1",
129
"ipv6": f"hit={timestamp}",
130
'_C_ETH' : '1',
114
131
}
115
132
116
def create_headers(cookies: Cookies = None, api_key: str = None) -> dict:
133
async def create_headers(cookies: Cookies = None, api_key: str = None) -> dict:
117
134
if cookies is None:
135
# import nodriver as uc
136
# browser = await uc.start(headless=False)
137
# page = await browser.get(Defaults.home)
138
# await asyncio.sleep(10)
139
# cookies = {}
140
# for c in await page.browser.cookies.get_all():
141
# if c.domain.endswith(".bing.com"):
142
# cookies[c.name] = c.value
143
# user_agent = await page.evaluate("window.navigator.userAgent")
144
# await page.close()
118
145
cookies = get_default_cookies()
119
146
if api_key is not None:
120
147
cookies["_U"] = api_key
121
148
headers = Defaults.headers.copy()
122
149
headers["cookie"] = "; ".join(f"{k}={v}" for k, v in cookies.items())
123
headers["x-forwarded-for"] = get_ip_address()
124
150
return headers
125
151
126
152
class Defaults:
@@ -246,25 +272,13 @@ class Defaults:
246
272
}
247
273
248
274
# Default headers for requests
249
home = 'https://www.bing.com/chat?q=Bing+AI&FORM=hpcodx'
275
home = "https://www.bing.com/chat?q=Microsoft+Copilot&FORM=hpcodx"
250
276
headers = {
251
'sec-ch-ua': '"Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
252
'sec-ch-ua-mobile': '?0',
253
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
254
'sec-ch-ua-arch': '"x86"',
255
'sec-ch-ua-full-version': '"122.0.6261.69"',
256
'accept': 'application/json',
257
'sec-ch-ua-platform-version': '"15.0.0"',
277
**DEFAULT_HEADERS,
278
"accept": "application/json",
279
"referer": home,
258
280
"x-ms-client-request-id": str(uuid.uuid4()),
259
'sec-ch-ua-full-version-list': '"Chromium";v="122.0.6261.69", "Not(A:Brand";v="24.0.0.0", "Google Chrome";v="122.0.6261.69"',
260
'x-ms-useragent': 'azsdk-js-api-client-factory/1.0.0-beta.1 core-rest-pipeline/1.12.3 OS/Windows',
261
'sec-ch-ua-model': '""',
262
'sec-ch-ua-platform': '"Windows"',
263
'sec-fetch-site': 'same-origin',
264
'sec-fetch-mode': 'cors',
265
'sec-fetch-dest': 'empty',
266
'referer': home,
267
'accept-language': 'en-US,en;q=0.9',
281
"x-ms-useragent": "azsdk-js-api-client-factory/1.0.0-beta.1 core-rest-pipeline/1.15.1 OS/Windows",
268
282
}
269
283
270
284
def format_message(msg: dict) -> str:
@@ -368,7 +382,6 @@ async def stream_generate(
368
382
context: str = None,
369
383
cookies: dict = None,
370
384
api_key: str = None,
371
connector: BaseConnector = None,
372
385
proxy: str = None,
373
386
web_search: bool = False,
374
387
gpt4_turbo: bool = False,
@@ -393,14 +406,12 @@ async def stream_generate(
393
406
:param timeout: Timeout for the request.
394
407
:return: An asynchronous generator yielding responses.
395
408
"""
396
headers = create_headers(cookies, api_key)
409
headers = await create_headers(cookies, api_key)
397
410
new_conversation = conversation is None
398
411
max_retries = (5 if new_conversation else 0) if max_retries is None else max_retries
399
async with ClientSession(
400
timeout=ClientTimeout(total=timeout), connector=connector
401
) as session:
402
first = True
403
while first or conversation is None:
412
first = True
413
while first or conversation is None:
414
async with StreamSession(timeout=timeout, proxy=proxy) as session:
404
415
first = False
405
416
do_read = True
406
417
try:
@@ -408,13 +419,13 @@ async def stream_generate(
408
419
conversation = await create_conversation(session, headers, tone)
409
420
if return_conversation:
410
421
yield conversation
411
except ResponseStatusError as e:
422
except (ResponseStatusError, RateLimitError) as e:
412
423
max_retries -= 1
413
424
if max_retries < 1:
414
425
raise e
415
426
if debug.logging:
416
427
print(f"Bing: Retry: {e}")
417
headers = create_headers()
428
headers = await create_headers()
418
429
await asyncio.sleep(sleep_retry)
419
430
continue
420
431
@@ -434,7 +445,7 @@ async def stream_generate(
434
445
) as wss:
435
446
await wss.send_str(format_message({'protocol': 'json', 'version': 1}))
436
447
await wss.send_str(format_message({"type": 6}))
437
await wss.receive(timeout=timeout)
448
await wss.receive_str()
438
449
await wss.send_str(create_message(
439
450
conversation, prompt, tone,
440
451
context if new_conversation else None,
@@ -445,16 +456,15 @@ async def stream_generate(
445
456
returned_text = ''
446
457
message_id = None
447
458
while do_read:
448
msg = await wss.receive(timeout=timeout)
449
if msg.type == WSMsgType.CLOSED:
450
break
451
if msg.type != WSMsgType.TEXT or not msg.data:
452
continue
453
objects = msg.data.split(Defaults.delimiter)
459
msg = await wss.receive_str()
460
objects = msg.split(Defaults.delimiter)
454
461
for obj in objects:
455
462
if obj is None or not obj:
456
463
continue
457
response = json.loads(obj)
464
try:
465
response = json.loads(obj)
466
except json.JSONDecodeError:
467
continue
458
468
if response and response.get('type') == 1 and response['arguments'][0].get('messages'):
459
469
message = response['arguments'][0]['messages'][0]
460
470
if message_id is not None and message_id != message["messageId"]:
@@ -462,7 +472,7 @@ async def stream_generate(
462
472
message_id = message["messageId"]
463
473
image_response = None
464
474
if (raise_apology and message['contentOrigin'] == 'Apology'):
465
raise RuntimeError("Apology Response Error")
475
raise ResponseError("Apology Response Error")
466
476
if 'adaptiveCards' in message:
467
477
card = message['adaptiveCards'][0]['body'][0]
468
478
if "text" in card:
@@ -488,6 +498,7 @@ async def stream_generate(
488
498
yield image_response
489
499
elif response.get('type') == 2:
490
500
result = response['item']['result']
501
do_read = False
491
502
if result.get('error'):
492
503
max_retries -= 1
493
504
if max_retries < 1:
@@ -497,10 +508,12 @@ async def stream_generate(
497
508
raise RuntimeError(f"{result['value']}: {result['message']}")
498
509
if debug.logging:
499
510
print(f"Bing: Retry: {result['value']}: {result['message']}")
500
headers = create_headers()
501
do_read = False
511
headers = await create_headers()
502
512
conversation = None
503
513
await asyncio.sleep(sleep_retry)
504
break
505
return
506
await delete_conversation(session, conversation, headers)
514
break
515
elif response.get('type') == 3:
516
do_read = False
517
break
518
if conversation is not None:
519
await delete_conversation(session, conversation, headers)
@@ -1,3 +1,5 @@
1
from __future__ import annotations
2
1
3
import json
2
4
import uuid
3
5
import random
@@ -8,6 +10,8 @@ from aiohttp import ClientSession, BaseConnector
8
10
9
11
from ..typing import AsyncResult, Messages, Cookies
10
12
from ..requests import raise_for_status, DEFAULT_HEADERS
13
from ..image import ImageResponse, ImagePreview
14
from ..errors import ResponseError
11
15
from .base_provider import AsyncGeneratorProvider
12
16
from .helper import format_prompt, get_connector
13
17
@@ -22,6 +26,7 @@ class AbraGeoBlockedError(Exception):
22
26
pass
23
27
24
28
class MetaAI(AsyncGeneratorProvider):
29
label = "Meta AI"
25
30
url = "https://www.meta.ai"
26
31
working = True
27
32
@@ -38,11 +43,10 @@ class MetaAI(AsyncGeneratorProvider):
38
43
proxy: str = None,
39
44
**kwargs
40
45
) -> AsyncResult:
41
#cookies = get_cookies(".meta.ai", False, True)
42
46
async for chunk in cls(proxy).prompt(format_prompt(messages)):
43
47
yield chunk
44
48
45
async def get_access_token(self, birthday: str = "1999-01-01") -> str:
49
async def update_access_token(self, birthday: str = "1999-01-01"):
46
50
url = "https://www.meta.ai/api/graphql/"
47
51
48
52
payload = {
@@ -66,25 +70,37 @@ class MetaAI(AsyncGeneratorProvider):
66
70
async with self.session.post(url, headers=headers, cookies=self.cookies, data=payload) as response:
67
71
await raise_for_status(response, "Fetch access_token failed")
68
72
auth_json = await response.json(content_type=None)
69
access_token = auth_json["data"]["xab_abra_accept_terms_of_service"]["new_temp_user_auth"]["access_token"]
70
return access_token
73
self.access_token = auth_json["data"]["xab_abra_accept_terms_of_service"]["new_temp_user_auth"]["access_token"]
71
74
72
75
async def prompt(self, message: str, cookies: Cookies = None) -> AsyncResult:
76
if self.cookies is None:
77
await self.update_cookies(cookies)
73
78
if cookies is not None:
74
self.cookies = cookies
75
79
self.access_token = None
76
if self.cookies is None:
77
self.cookies = await self.get_cookies()
78
if self.access_token is None:
79
self.access_token = await self.get_access_token()
80
if self.access_token is None and cookies is None:
81
await self.update_access_token()
80
82
81
url = "https://graph.meta.ai/graphql?locale=user"
82
#url = "https://www.meta.ai/api/graphql/"
83
if self.access_token is None:
84
url = "https://www.meta.ai/api/graphql/"
85
payload = {"lsd": self.lsd, 'fb_dtsg': self.dtsg}
86
headers = {'x-fb-lsd': self.lsd}
87
else:
88
url = "https://graph.meta.ai/graphql?locale=user"
89
payload = {"access_token": self.access_token}
90
headers = {}
91
headers = {
92
'content-type': 'application/x-www-form-urlencoded',
93
'cookie': "; ".join([f"{k}={v}" for k, v in cookies.items()]),
94
'origin': 'https://www.meta.ai',
95
'referer': 'https://www.meta.ai/',
96
'x-asbd-id': '129477',
97
'x-fb-friendly-name': 'useAbraSendMessageMutation',
98
**headers
99
}
83
100
payload = {
84
"access_token": self.access_token,
85
#"lsd": cookies["lsd"],
86
"fb_api_caller_class": "RelayModern",
87
"fb_api_req_friendly_name": "useAbraSendMessageMutation",
101
**payload,
102
'fb_api_caller_class': 'RelayModern',
103
'fb_api_req_friendly_name': 'useAbraSendMessageMutation',
88
104
"variables": json.dumps({
89
105
"message": {"sensitive_string_value": message},
90
106
"externalConversationId": str(uuid.uuid4()),
@@ -98,19 +114,16 @@ class MetaAI(AsyncGeneratorProvider):
98
114
"__relay_internal__pv__AbraDebugDevOnlyrelayprovider": False,
99
115
"__relay_internal__pv__WebPixelRatiorelayprovider": 1,
100
116
}),
101
"server_timestamps": "true",
102
"doc_id": "7783822248314888",
103
}
104
headers = {
105
"x-asbd-id": "129477",
106
"x-fb-friendly-name": "useAbraSendMessageMutation",
107
#"x-fb-lsd": cookies["lsd"],
117
'server_timestamps': 'true',
118
'doc_id': '7783822248314888'
108
119
}
109
async with self.session.post(url, headers=headers, cookies=self.cookies, data=payload) as response:
120
async with self.session.post(url, headers=headers, data=payload) as response:
110
121
await raise_for_status(response, "Fetch response failed")
111
122
last_snippet_len = 0
112
123
fetch_id = None
113
124
async for line in response.content:
125
if b"<h1>Something Went Wrong</h1>" in line:
126
raise ResponseError("Response: Something Went Wrong")
114
127
try:
115
128
json_line = json.loads(line)
116
129
except json.JSONDecodeError:
@@ -119,7 +132,14 @@ class MetaAI(AsyncGeneratorProvider):
119
132
streaming_state = bot_response_message.get("streaming_state")
120
133
fetch_id = bot_response_message.get("fetch_id") or fetch_id
121
134
if streaming_state in ("STREAMING", "OVERALL_DONE"):
122
#imagine_card = bot_response_message["imagine_card"]
135
imagine_card = bot_response_message.get("imagine_card")
136
if imagine_card is not None:
137
imagine_session = imagine_card.get("session")
138
if imagine_session is not None:
139
imagine_medias = imagine_session.get("media_sets", {}).pop().get("imagine_media")
140
if imagine_medias is not None:
141
image_class = ImageResponse if streaming_state == "OVERALL_DONE" else ImagePreview
142
yield image_class([media["uri"] for media in imagine_medias], imagine_medias[0]["prompt"])
123
143
snippet = bot_response_message["snippet"]
124
144
new_snippet_len = len(snippet)
125
145
if new_snippet_len > last_snippet_len:
@@ -135,7 +155,7 @@ class MetaAI(AsyncGeneratorProvider):
135
155
if sources is not None:
136
156
yield sources
137
157
138
async def get_cookies(self, cookies: Cookies = None) -> Cookies:
158
async def update_cookies(self, cookies: Cookies = None):
139
159
async with self.session.get("https://www.meta.ai/", cookies=cookies) as response:
140
160
await raise_for_status(response, "Fetch home failed")
141
161
text = await response.text()
@@ -148,12 +168,20 @@ class MetaAI(AsyncGeneratorProvider):
148
168
"datr": self.extract_value(text, "datr"),
149
169
}
150
170
self.lsd = self.extract_value(text, start_str='"LSD",[],{"token":"', end_str='"}')
151
return cookies
171
self.dtsg = self.extract_value(text, start_str='"DTSGInitialData",[],{"token":"', end_str='"}')
172
self.cookies = cookies
152
173
153
174
async def fetch_sources(self, fetch_id: str) -> Sources:
154
url = "https://graph.meta.ai/graphql?locale=user"
175
if self.access_token is None:
176
url = "https://www.meta.ai/api/graphql/"
177
payload = {"lsd": self.lsd, 'fb_dtsg': self.dtsg}
178
headers = {'x-fb-lsd': self.lsd}
179
else:
180
url = "https://graph.meta.ai/graphql?locale=user"
181
payload = {"access_token": self.access_token}
182
headers = {}
155
183
payload = {
156
"access_token": self.access_token,
184
**payload,
157
185
"fb_api_caller_class": "RelayModern",
158
186
"fb_api_req_friendly_name": "AbraSearchPluginDialogQuery",
159
187
"variables": json.dumps({"abraMessageFetchID": fetch_id}),
@@ -163,18 +191,22 @@ class MetaAI(AsyncGeneratorProvider):
163
191
headers = {
164
192
"authority": "graph.meta.ai",
165
193
"x-fb-friendly-name": "AbraSearchPluginDialogQuery",
194
**headers
166
195
}
167
196
async with self.session.post(url, headers=headers, cookies=self.cookies, data=payload) as response:
168
197
await raise_for_status(response)
169
response_json = await response.json()
198
text = await response.text()
199
if "<h1>Something Went Wrong</h1>" in text:
200
raise ResponseError("Response: Something Went Wrong")
170
201
try:
202
response_json = json.loads(text)
171
203
message = response_json["data"]["message"]
172
204
if message is not None:
173
205
searchResults = message["searchResults"]
174
206
if searchResults is not None:
175
207
return Sources(searchResults["references"])
176
except (KeyError, TypeError):
177
raise RuntimeError(f"Response: {response_json}")
208
except (KeyError, TypeError, json.JSONDecodeError):
209
raise RuntimeError(f"Response: {text}")
178
210
179
211
@staticmethod
180
212
def extract_value(text: str, key: str = None, start_str = None, end_str = '",') -> str:
@@ -0,0 +1,21 @@
1
from __future__ import annotations
2
3
from ..typing import AsyncResult, Messages, Cookies
4
from .helper import format_prompt, get_cookies
5
from .MetaAI import MetaAI
6
7
class MetaAIAccount(MetaAI):
8
needs_auth = True
9
10
@classmethod
11
async def create_async_generator(
12
cls,
13
model: str,
14
messages: Messages,
15
proxy: str = None,
16
cookies: Cookies = None,
17
**kwargs
18
) -> AsyncResult:
19
cookies = get_cookies(".meta.ai", True, True) if cookies is None else cookies
20
async for chunk in cls(proxy).prompt(format_prompt(messages), cookies):
21
yield chunk
@@ -10,7 +10,7 @@ from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
10
10
from .helper import format_prompt
11
11
from ..image import ImageResponse, to_bytes, is_accepted_format
12
12
from ..requests import StreamSession, FormData, raise_for_status
13
from .you.har_file import get_dfp_telemetry_id
13
from .you.har_file import get_telemetry_ids
14
14
15
15
class You(AsyncGeneratorProvider, ProviderModelMixin):
16
16
url = "https://you.com"
@@ -35,6 +35,7 @@ class You(AsyncGeneratorProvider, ProviderModelMixin):
35
35
}
36
36
_cookies = None
37
37
_cookies_used = 0
38
_telemetry_ids = []
38
39
39
40
@classmethod
40
41
async def create_async_generator(
@@ -159,6 +160,8 @@ class You(AsyncGeneratorProvider, ProviderModelMixin):
159
160
160
161
@classmethod
161
162
async def create_cookies(cls, client: StreamSession) -> Cookies:
163
if not cls._telemetry_ids:
164
cls._telemetry_ids = await get_telemetry_ids()
162
165
user_uuid = str(uuid.uuid4())
163
166
async with client.post(
164
167
"https://web.stytch.com/sdk/v1/passwords",
@@ -170,7 +173,7 @@ class You(AsyncGeneratorProvider, ProviderModelMixin):
170
173
"Referer": "https://you.com/"
171
174
},
172
175
json={
173
"dfp_telemetry_id": await get_dfp_telemetry_id(),
176
"dfp_telemetry_id": cls._telemetry_ids.pop(),
174
177
"email": f"{user_uuid}@gmail.com",
175
178
"password": f"{user_uuid}#{user_uuid}",
176
179
"session_duration_minutes": 129600
@@ -43,6 +43,7 @@ from .Liaobots import Liaobots
43
43
from .Llama import Llama
44
44
from .Local import Local
45
45
from .MetaAI import MetaAI
46
from .MetaAIAccount import MetaAIAccount
46
47
from .PerplexityLabs import PerplexityLabs
47
48
from .Pi import Pi
48
49
from .ReplicateImage import ReplicateImage
@@ -1,7 +1,6 @@
1
1
from __future__ import annotations
2
2
3
from aiohttp import ClientSession
4
from ...requests import raise_for_status
3
from ...requests import StreamSession, raise_for_status
5
4
from ...errors import RateLimitError
6
5
from ...providers.conversation import BaseConversation
7
6
@@ -22,7 +21,7 @@ class Conversation(BaseConversation):
22
21
self.clientId = clientId
23
22
self.conversationSignature = conversationSignature
24
23
25
async def create_conversation(session: ClientSession, headers: dict, tone: str) -> Conversation:
24
async def create_conversation(session: StreamSession, headers: dict, tone: str) -> Conversation:
26
25
"""
27
26
Create a new conversation asynchronously.
28
27
@@ -49,7 +48,7 @@ async def create_conversation(session: ClientSession, headers: dict, tone: str)
49
48
raise RuntimeError('Empty fields: Failed to create conversation')
50
49
return Conversation(conversationId, clientId, conversationSignature)
51
50
52
async def list_conversations(session: ClientSession) -> list:
51
async def list_conversations(session: StreamSession) -> list:
53
52
"""
54
53
List all conversations asynchronously.
55
54
@@ -64,7 +63,7 @@ async def list_conversations(session: ClientSession) -> list:
64
63
response = await response.json()
65
64
return response["chats"]
66
65
67
async def delete_conversation(session: ClientSession, conversation: Conversation, headers: dict) -> bool:
66
async def delete_conversation(session: StreamSession, conversation: Conversation, headers: dict) -> bool:
68
67
"""
69
68
Delete a conversation asynchronously.
70
69
@@ -24,7 +24,7 @@ except ImportError:
24
24
from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin
25
25
from ...webdriver import get_browser
26
26
from ...typing import AsyncResult, Messages, Cookies, ImageType, AsyncIterator
27
from ...requests import get_args_from_browser, raise_for_status
27
from ...requests import DEFAULT_HEADERS, get_args_from_browser, raise_for_status
28
28
from ...requests.aiohttp import StreamSession
29
29
from ...image import to_image, to_bytes, ImageResponse, ImageRequest
30
30
from ...errors import MissingAuthError, ResponseError
@@ -360,7 +360,6 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
360
360
if debug.logging:
361
361
print("OpenaiChat: Load default_model failed")
362
362
print(f"{e.__class__.__name__}: {e}")
363
364
363
365
364
arkose_token = None
366
365
if cls.default_model is None:
@@ -377,7 +376,8 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
377
376
cls.default_model = cls.get_model(await cls.get_default_model(session, cls._headers))
378
377
379
378
async with session.post(
380
f"{cls.url}/backend-anon/sentinel/chat-requirements" if not cls._api_key else
379
f"{cls.url}/backend-anon/sentinel/chat-requirements"
380
if not cls._api_key else
381
381
f"{cls.url}/backend-api/sentinel/chat-requirements",
382
382
json={"conversation_mode_kind": "primary_assistant"},
383
383
headers=cls._headers
@@ -388,7 +388,7 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
388
388
blob = data["arkose"]["dx"]
389
389
need_arkose = data["arkose"]["required"]
390
390
chat_token = data["token"]
391
391
392
392
if debug.logging:
393
393
print(f'Arkose: {need_arkose} Turnstile: {data["turnstile"]["required"]}')
394
394
@@ -595,8 +595,7 @@ this.fetch = async (url, options) => {
595
595
print(f"Open nodriver with user_dir: {user_data_dir}")
596
596
browser = await uc.start(user_data_dir=user_data_dir)
597
597
page = await browser.get("https://chat.openai.com/")
598
while await page.find("[id^=headlessui-menu-button-]") is None:
599
await asyncio.sleep(1)
598
await page.select("[id^=headlessui-menu-button-]", 240)
600
599
api_key = await page.evaluate(
601
600
"(async () => {"
602
601
"let session = await fetch('/api/auth/session');"
@@ -662,16 +661,10 @@ this.fetch = async (url, options) => {
662
661
@staticmethod
663
662
def get_default_headers() -> dict:
664
663
return {
665
"accept-language": "en-US",
664
**DEFAULT_HEADERS,
666
665
"content-type": "application/json",
667
666
"oai-device-id": str(uuid.uuid4()),
668
667
"oai-language": "en-US",
669
"sec-ch-ua": "\"Google Chrome\";v=\"123\", \"Not:A-Brand\";v=\"8\", \"Chromium\";v=\"123\"",
670
"sec-ch-ua-mobile": "?0",
671
"sec-ch-ua-platform": "\"Linux\"",
672
"sec-fetch-dest": "empty",
673
"sec-fetch-mode": "cors",
674
"sec-fetch-site": "same-origin"
675
668
}
676
669
677
670
@staticmethod
@@ -696,11 +689,11 @@ this.fetch = async (url, options) => {
696
689
def _set_api_key(cls, api_key: str):
697
690
cls._api_key = api_key
698
691
cls._expires = int(time.time()) + 60 * 60 * 4
699
cls._headers["Authorization"] = f"Bearer {api_key}"
692
cls._headers["authorization"] = f"Bearer {api_key}"
700
693
701
694
@classmethod
702
695
def _update_cookie_header(cls):
703
cls._headers["Cookie"] = cls._format_cookies(cls._cookies)
696
cls._headers["cookie"] = cls._format_cookies(cls._cookies)
704
697
705
698
class Conversation(BaseConversation):
706
699
"""
@@ -3,11 +3,10 @@ from __future__ import annotations
3
3
import json
4
4
import os
5
5
import random
6
import uuid
7
import asyncio
8
6
import requests
9
7
10
8
from ...requests import StreamSession, raise_for_status
9
from ... import debug
11
10
12
11
class NoValidHarFileError(Exception):
13
12
...
@@ -67,60 +66,49 @@ async def sendRequest(tmpArk: arkReq, proxy: str = None):
67
66
return await response.text()
68
67
69
68
async def get_dfp_telemetry_id(proxy: str = None):
70
return await telemetry_id_with_driver(proxy)
71
69
global chatArks
72
70
if chatArks is None:
73
71
chatArks = readHAR()
74
72
return await sendRequest(random.choice(chatArks), proxy)
75
73
76
async def telemetry_id_with_driver(proxy: str = None):
77
from ...debug import logging
78
if logging:
79
print('getting telemetry_id for you.com with nodriver')
74
def read_telemetry_file() -> list:
75
with open("hardir/you.com_telemetry_ids.txt", "r") as f:
76
ids = f.readlines()
77
random.shuffle(ids)
78
return ids
79
80
async def get_telemetry_ids(proxy: str = None) -> list:
81
if debug.logging:
82
print('Getting telemetry_id for you.com with nodriver')
80
83
try:
81
import nodriver as uc
82
from nodriver import start, cdp, loop
84
from nodriver import start
83
85
except ImportError:
84
if logging:
85
print('nodriver not found, random uuid (may fail)')
86
return str(uuid.uuid4())
87
88
CAN_EVAL = False
89
payload_received = False
90
payload = None
91
86
if debug.logging:
87
print('Install "nodriver" package | pip install -U nodriver')
88
return read_telemetry_file()
92
89
try:
93
90
browser = await start()
94
91
tab = browser.main_tab
95
96
async def send_handler(event: cdp.network.RequestWillBeSent):
97
nonlocal CAN_EVAL, payload_received, payload
98
if 'telemetry.js' in event.request.url:
99
CAN_EVAL = True
100
if "/submit" in event.request.url:
101
payload = event.request.post_data
102
payload_received = True
103
104
tab.add_handler(cdp.network.RequestWillBeSent, send_handler)
105
92
await browser.get("https://you.com")
106
93
107
while not CAN_EVAL:
94
while not await tab.evaluate('"GetTelemetryID" in this'):
108
95
await tab.sleep(1)
109
96
110
await tab.evaluate('window.GetTelemetryID("public-token-live-507a52ad-7e69-496b-aee0-1c9863c7c819", "https://telemetry.stytch.com/submit");')
111
112
while not payload_received:
113
await tab.sleep(.1)
97
async def get_telemetry_id():
98
public_token = "public-token-live-507a52ad-7e69-496b-aee0-1c9863c7c819"
99
telemetry_url = "https://telemetry.stytch.com/submit"
100
return await tab.evaluate(f'this.GetTelemetryID("{public_token}", "{telemetry_url}");', await_promise=True)
114
101
115
except Exception as e:
116
print(f"Error occurred: {str(e)}")
102
# for _ in range(500):
103
# with open("hardir/you.com_telemetry_ids.txt", "a") as f:
104
# f.write((await get_telemetry_id()) + "\n")
117
105
106
return [await get_telemetry_id() for _ in range(10)]
118
107
finally:
119
108
try:
120
109
await tab.close()
121
110
except Exception as e:
122
111
print(f"Error occurred while closing tab: {str(e)}")
123
124
112
try:
125
113
await browser.stop()
126
114
except Exception as e:
@@ -41,7 +41,9 @@ appStorage = window.localStorage || {
41
41
length: 0
42
42
}
43
43
44
const markdown = window.markdownit();
44
const markdown = window.markdownit({
45
html: true,
46
});
45
47
const markdown_render = (content) => {
46
48
return markdown.render(content
47
49
.replaceAll(/<!-- generated images start -->|<!-- generated images end -->/gm, "")
@@ -312,6 +314,8 @@ async function add_message_chunk(message) {
312
314
window.error = message.error
313
315
console.error(message.error);
314
316
content_inner.innerHTML += `<p><strong>An error occured:</strong> ${message.error}</p>`;
317
} else if (message.type == "preview") {
318
content_inner.innerHTML = markdown_render(message.preview);
315
319
} else if (message.type == "content") {
316
320
window.text += message.content;
317
321
html = markdown_render(window.text);
@@ -545,7 +549,7 @@ const load_conversation = async (conversation_id, scroll=true) => {
545
549
last_model = item.provider?.model;
546
550
let next_i = parseInt(i) + 1;
547
551
let next_provider = item.provider ? item.provider : (messages.length > next_i ? messages[next_i].provider : null);
548
let provider_label = item.provider?.label ? item.provider?.label : item.provider?.name;
552
let provider_label = item.provider?.label ? item.provider.label : item.provider?.name;
549
553
let provider_link = item.provider?.name ? `<a href="${item.provider.url}" target="_blank">${provider_label}</a>` : "";
550
554
let provider = provider_link ? `
551
555
<div class="provider">
@@ -7,6 +7,7 @@ from typing import Iterator
7
7
from g4f import version, models
8
8
from g4f import get_last_provider, ChatCompletion
9
9
from g4f.errors import VersionNotFoundError
10
from g4f.image import ImagePreview
10
11
from g4f.Provider import ProviderType, __providers__, __map__
11
12
from g4f.providers.base_provider import ProviderModelMixin, FinishReason
12
13
from g4f.providers.conversation import BaseConversation
@@ -146,6 +147,8 @@ class Api():
146
147
elif isinstance(chunk, Exception):
147
148
logging.exception(chunk)
148
149
yield self._format_json("message", get_error_message(chunk))
150
elif isinstance(chunk, ImagePreview):
151
yield self._format_json("preview", chunk.to_string())
149
152
elif not isinstance(chunk, FinishReason):
150
153
yield self._format_json("content", str(chunk))
151
154
except Exception as e:
@@ -210,7 +210,9 @@ def format_images_markdown(images: Union[str, list], alt: str, preview: Union[st
210
210
if not isinstance(preview, list):
211
211
preview = [preview.replace('{image}', image) if preview else image for image in images]
212
212
result = "\n".join(
213
f"[]({image})" for idx, image in enumerate(images)
213
#f"[]({image})"
214
f'[<img src="{preview[idx]}" width="200" alt="#{idx+1} {alt}">]({image})'
215
for idx, image in enumerate(images)
214
216
)
215
217
start_flag = "<!-- generated images start -->\n"
216
218
end_flag = "<!-- generated images end -->\n"
@@ -259,6 +261,13 @@ class ImageResponse:
259
261
def get_list(self) -> list[str]:
260
262
return [self.images] if isinstance(self.images, str) else self.images
261
263
264
class ImagePreview(ImageResponse):
265
def __str__(self):
266
return ""
267
268
def to_string(self):
269
return super().__str__()
270
262
271
class ImageRequest:
263
272
def __init__(
264
273
self,