返回提交历史
Modified
g4f/Provider/Copilot.py
+27
-24
Modified
g4f/Provider/You.py
+9
-6
Modified
g4f/Provider/needs_auth/Gemini.py
+13
-10
Modified
g4f/Provider/needs_auth/MicrosoftDesigner.py
+25
-22
Modified
g4f/Provider/needs_auth/OpenaiChat.py
+49
-46
Modified
g4f/client/__init__.py
+2
-2
Modified
g4f/providers/base_provider.py
+0
-1
Modified
g4f/requests/__init__.py
+66
-32
XFEstudio/gpt4free
Add lock file for nodriver, add finally stop browser to all calls
3e1e5056
代码差异
8 个文件
+191
-143
@@ -207,30 +207,33 @@ class Copilot(AbstractProvider, ProviderModelMixin):
207
207
208
208
async def get_access_token_and_cookies(url: str, proxy: str = None, target: str = "ChatAI",):
209
209
browser = await get_nodriver(proxy=proxy, user_data_dir="copilot")
210
page = await browser.get(url)
211
access_token = None
212
while access_token is None:
213
access_token = await page.evaluate("""
214
(() => {
215
for (var i = 0; i < localStorage.length; i++) {
216
try {
217
item = JSON.parse(localStorage.getItem(localStorage.key(i)));
218
if (item.credentialType == "AccessToken"
219
&& item.expiresOn > Math.floor(Date.now() / 1000)
220
&& item.target.includes("target")) {
221
return item.secret;
222
}
223
} catch(e) {}
224
}
225
})()
226
""".replace('"target"', json.dumps(target)))
227
if access_token is None:
228
await asyncio.sleep(1)
229
cookies = {}
230
for c in await page.send(nodriver.cdp.network.get_cookies([url])):
231
cookies[c.name] = c.value
232
await page.close()
233
return access_token, cookies
210
try:
211
page = await browser.get(url)
212
access_token = None
213
while access_token is None:
214
access_token = await page.evaluate("""
215
(() => {
216
for (var i = 0; i < localStorage.length; i++) {
217
try {
218
item = JSON.parse(localStorage.getItem(localStorage.key(i)));
219
if (item.credentialType == "AccessToken"
220
&& item.expiresOn > Math.floor(Date.now() / 1000)
221
&& item.target.includes("target")) {
222
return item.secret;
223
}
224
} catch(e) {}
225
}
226
})()
227
""".replace('"target"', json.dumps(target)))
228
if access_token is None:
229
await asyncio.sleep(1)
230
cookies = {}
231
for c in await page.send(nodriver.cdp.network.get_cookies([url])):
232
cookies[c.name] = c.value
233
await page.close()
234
return access_token, cookies
235
finally:
236
browser.stop()
234
237
235
238
def readHAR(url: str):
236
239
api_key = None
@@ -76,12 +76,15 @@ class You(AsyncGeneratorProvider, ProviderModelMixin):
76
76
cookies = get_cookies(".you.com")
77
77
except MissingRequirementsError:
78
78
browser = await get_nodriver(proxy=proxy)
79
page = await browser.get(cls.url)
80
await page.wait_for('[data-testid="user-profile-button"]', timeout=900)
81
cookies = {}
82
for c in await page.send(nodriver.cdp.network.get_cookies([cls.url])):
83
cookies[c.name] = c.value
84
await page.close()
79
try:
80
page = await browser.get(cls.url)
81
await page.wait_for('[data-testid="user-profile-button"]', timeout=900)
82
cookies = {}
83
for c in await page.send(nodriver.cdp.network.get_cookies([cls.url])):
84
cookies[c.name] = c.value
85
await page.close()
86
finally:
87
browser.stop()
85
88
async with StreamSession(
86
89
proxy=proxy,
87
90
impersonate="chrome",
@@ -78,16 +78,19 @@ class Gemini(AsyncGeneratorProvider, ProviderModelMixin):
78
78
print("Skip nodriver login in Gemini provider")
79
79
return
80
80
browser = await get_nodriver(proxy=proxy, user_data_dir="gemini")
81
login_url = os.environ.get("G4F_LOGIN_URL")
82
if login_url:
83
yield RequestLogin(cls.label, login_url)
84
page = await browser.get(f"{cls.url}/app")
85
await page.select("div.ql-editor.textarea", 240)
86
cookies = {}
87
for c in await page.send(nodriver.cdp.network.get_cookies([cls.url])):
88
cookies[c.name] = c.value
89
await page.close()
90
cls._cookies = cookies
81
try:
82
login_url = os.environ.get("G4F_LOGIN_URL")
83
if login_url:
84
yield RequestLogin(cls.label, login_url)
85
page = await browser.get(f"{cls.url}/app")
86
await page.select("div.ql-editor.textarea", 240)
87
cookies = {}
88
for c in await page.send(nodriver.cdp.network.get_cookies([cls.url])):
89
cookies[c.name] = c.value
90
await page.close()
91
cls._cookies = cookies
92
finally:
93
browser.stop()
91
94
92
95
@classmethod
93
96
async def create_async_generator(
@@ -143,25 +143,28 @@ def readHAR(url: str) -> tuple[str, str]:
143
143
144
144
async def get_access_token_and_user_agent(url: str, proxy: str = None):
145
145
browser = await get_nodriver(proxy=proxy, user_data_dir="designer")
146
page = await browser.get(url)
147
user_agent = await page.evaluate("navigator.userAgent")
148
access_token = None
149
while access_token is None:
150
access_token = await page.evaluate("""
151
(() => {
152
for (var i = 0; i < localStorage.length; i++) {
153
try {
154
item = JSON.parse(localStorage.getItem(localStorage.key(i)));
155
if (item.credentialType == "AccessToken"
156
&& item.expiresOn > Math.floor(Date.now() / 1000)
157
&& item.target.includes("designerappservice")) {
158
return item.secret;
159
}
160
} catch(e) {}
161
}
162
})()
163
""")
164
if access_token is None:
165
await asyncio.sleep(1)
166
await page.close()
167
return access_token, user_agent
146
try:
147
page = await browser.get(url)
148
user_agent = await page.evaluate("navigator.userAgent")
149
access_token = None
150
while access_token is None:
151
access_token = await page.evaluate("""
152
(() => {
153
for (var i = 0; i < localStorage.length; i++) {
154
try {
155
item = JSON.parse(localStorage.getItem(localStorage.key(i)));
156
if (item.credentialType == "AccessToken"
157
&& item.expiresOn > Math.floor(Date.now() / 1000)
158
&& item.target.includes("designerappservice")) {
159
return item.secret;
160
}
161
} catch(e) {}
162
}
163
})()
164
""")
165
if access_token is None:
166
await asyncio.sleep(1)
167
await page.close()
168
return access_token, user_agent
169
finally:
170
browser.stop()
@@ -624,53 +624,56 @@ class OpenaiChat(AsyncAuthedProvider, ProviderModelMixin):
624
624
@classmethod
625
625
async def nodriver_auth(cls, proxy: str = None):
626
626
browser = await get_nodriver(proxy=proxy)
627
page = browser.main_tab
628
def on_request(event: nodriver.cdp.network.RequestWillBeSent):
629
if event.request.url == start_url or event.request.url.startswith(conversation_url):
630
RequestConfig.headers = event.request.headers
631
elif event.request.url in (backend_url, backend_anon_url):
632
if "OpenAI-Sentinel-Proof-Token" in event.request.headers:
633
RequestConfig.proof_token = json.loads(base64.b64decode(
634
event.request.headers["OpenAI-Sentinel-Proof-Token"].split("gAAAAAB", 1)[-1].encode()
635
).decode())
636
if "OpenAI-Sentinel-Turnstile-Token" in event.request.headers:
637
RequestConfig.turnstile_token = event.request.headers["OpenAI-Sentinel-Turnstile-Token"]
638
if "Authorization" in event.request.headers:
639
cls._api_key = event.request.headers["Authorization"].split()[-1]
640
elif event.request.url == arkose_url:
641
RequestConfig.arkose_request = arkReq(
642
arkURL=event.request.url,
643
arkBx=None,
644
arkHeader=event.request.headers,
645
arkBody=event.request.post_data,
646
userAgent=event.request.headers.get("User-Agent")
647
)
648
await page.send(nodriver.cdp.network.enable())
649
page.add_handler(nodriver.cdp.network.RequestWillBeSent, on_request)
650
page = await browser.get(cls.url)
651
user_agent = await page.evaluate("window.navigator.userAgent")
652
await page.select("#prompt-textarea", 240)
653
await page.evaluate("document.getElementById('prompt-textarea').innerText = 'Hello'")
654
await page.evaluate("document.querySelector('[data-testid=\"send-button\"]').click()")
655
while True:
656
if cls._api_key is not None or not cls.needs_auth:
657
break
658
body = await page.evaluate("JSON.stringify(window.__remixContext)")
659
if body:
660
match = re.search(r'"accessToken":"(.*?)"', body)
661
if match:
662
cls._api_key = match.group(1)
627
try:
628
page = browser.main_tab
629
def on_request(event: nodriver.cdp.network.RequestWillBeSent):
630
if event.request.url == start_url or event.request.url.startswith(conversation_url):
631
RequestConfig.headers = event.request.headers
632
elif event.request.url in (backend_url, backend_anon_url):
633
if "OpenAI-Sentinel-Proof-Token" in event.request.headers:
634
RequestConfig.proof_token = json.loads(base64.b64decode(
635
event.request.headers["OpenAI-Sentinel-Proof-Token"].split("gAAAAAB", 1)[-1].encode()
636
).decode())
637
if "OpenAI-Sentinel-Turnstile-Token" in event.request.headers:
638
RequestConfig.turnstile_token = event.request.headers["OpenAI-Sentinel-Turnstile-Token"]
639
if "Authorization" in event.request.headers:
640
cls._api_key = event.request.headers["Authorization"].split()[-1]
641
elif event.request.url == arkose_url:
642
RequestConfig.arkose_request = arkReq(
643
arkURL=event.request.url,
644
arkBx=None,
645
arkHeader=event.request.headers,
646
arkBody=event.request.post_data,
647
userAgent=event.request.headers.get("User-Agent")
648
)
649
await page.send(nodriver.cdp.network.enable())
650
page.add_handler(nodriver.cdp.network.RequestWillBeSent, on_request)
651
page = await browser.get(cls.url)
652
user_agent = await page.evaluate("window.navigator.userAgent")
653
await page.select("#prompt-textarea", 240)
654
await page.evaluate("document.getElementById('prompt-textarea').innerText = 'Hello'")
655
await page.evaluate("document.querySelector('[data-testid=\"send-button\"]').click()")
656
while True:
657
if cls._api_key is not None or not cls.needs_auth:
663
658
break
664
await asyncio.sleep(1)
665
while True:
666
if RequestConfig.proof_token:
667
break
668
await asyncio.sleep(1)
669
RequestConfig.data_build = await page.evaluate("document.documentElement.getAttribute('data-build')")
670
RequestConfig.cookies = await page.send(get_cookies([cls.url]))
671
await page.close()
672
cls._create_request_args(RequestConfig.cookies, RequestConfig.headers, user_agent=user_agent)
673
cls._set_api_key(cls._api_key)
659
body = await page.evaluate("JSON.stringify(window.__remixContext)")
660
if body:
661
match = re.search(r'"accessToken":"(.*?)"', body)
662
if match:
663
cls._api_key = match.group(1)
664
break
665
await asyncio.sleep(1)
666
while True:
667
if RequestConfig.proof_token:
668
break
669
await asyncio.sleep(1)
670
RequestConfig.data_build = await page.evaluate("document.documentElement.getAttribute('data-build')")
671
RequestConfig.cookies = await page.send(get_cookies([cls.url]))
672
await page.close()
673
cls._create_request_args(RequestConfig.cookies, RequestConfig.headers, user_agent=user_agent)
674
cls._set_api_key(cls._api_key)
675
finally:
676
browser.stop()
674
677
675
678
@staticmethod
676
679
def get_default_headers() -> Dict[str, str]:
@@ -534,8 +534,8 @@ class AsyncCompletions:
534
534
self.provider if provider is None else provider,
535
535
stream,
536
536
ignore_working,
537
ignore_stream,,
538
has_images="images" in kwargs
537
ignore_stream,
538
has_images="images" in kwargs,
539
539
)
540
540
stop = [stop] if isinstance(stop, str) else stop
541
541
if ignore_stream:
@@ -425,7 +425,6 @@ class AsyncAuthedProvider(AsyncGeneratorProvider):
425
425
else:
426
426
auth_result = cls.on_auth(**kwargs)
427
427
for chunk in auth_result:
428
print(hasattr(chunk, "get_dict"))
429
428
if hasattr(chunk, "get_dict"):
430
429
auth_result = chunk
431
430
else:
@@ -1,9 +1,12 @@
1
1
from __future__ import annotations
2
2
3
3
import os
4
import time
5
import random
4
6
from urllib.parse import urlparse
5
7
from typing import Iterator
6
8
from http.cookies import Morsel
9
from pathlib import Path
7
10
try:
8
11
from curl_cffi.requests import Session, Response
9
12
from .curl_cffi import StreamResponse, StreamSession, FormData
@@ -37,6 +40,7 @@ from .. import debug
37
40
from .raise_for_status import raise_for_status
38
41
from ..errors import MissingRequirementsError
39
42
from ..typing import Cookies
43
from ..cookies import get_cookies_dir
40
44
from .defaults import DEFAULT_HEADERS, WEBVIEW_HAEDERS
41
45
42
46
if not has_curl_cffi:
@@ -83,35 +87,37 @@ async def get_args_from_nodriver(
83
87
callback: callable = None,
84
88
cookies: Cookies = None
85
89
) -> dict:
86
browser = await get_nodriver(proxy=proxy)
87
if debug.logging:
88
print(f"Open nodriver with url: {url}")
89
domain = urlparse(url).netloc
90
if cookies is None:
91
cookies = {}
92
else:
93
await browser.cookies.set_all(get_cookie_params_from_dict(cookies, url=url, domain=domain))
94
page = await browser.get(url)
95
user_agent = await page.evaluate("window.navigator.userAgent")
96
await page.wait_for("body:not(.no-js)", timeout=timeout)
97
if wait_for is not None:
98
await page.wait_for(wait_for, timeout=timeout)
99
if callback is not None:
100
await callback(page)
101
for c in await page.send(nodriver.cdp.network.get_cookies([url])):
102
cookies[c.name] = c.value
103
await page.close()
104
browser.stop()
105
return {
106
"impersonate": "chrome",
107
"cookies": cookies,
108
"headers": {
109
**DEFAULT_HEADERS,
110
"user-agent": user_agent,
111
"referer": url,
112
},
113
"proxy": proxy,
114
}
90
browser = await get_nodriver(proxy=proxy, timeout=timeout)
91
try:
92
if debug.logging:
93
print(f"Open nodriver with url: {url}")
94
domain = urlparse(url).netloc
95
if cookies is None:
96
cookies = {}
97
else:
98
await browser.cookies.set_all(get_cookie_params_from_dict(cookies, url=url, domain=domain))
99
page = await browser.get(url)
100
user_agent = await page.evaluate("window.navigator.userAgent")
101
await page.wait_for("body:not(.no-js)", timeout=timeout)
102
if wait_for is not None:
103
await page.wait_for(wait_for, timeout=timeout)
104
if callback is not None:
105
await callback(page)
106
for c in await page.send(nodriver.cdp.network.get_cookies([url])):
107
cookies[c.name] = c.value
108
await page.close()
109
return {
110
"impersonate": "chrome",
111
"cookies": cookies,
112
"headers": {
113
**DEFAULT_HEADERS,
114
"user-agent": user_agent,
115
"referer": url,
116
},
117
"proxy": proxy,
118
}
119
finally:
120
browser.stop()
115
121
116
122
def merge_cookies(cookies: Iterator[Morsel], response: Response) -> Cookies:
117
123
if cookies is None:
@@ -119,7 +125,13 @@ def merge_cookies(cookies: Iterator[Morsel], response: Response) -> Cookies:
119
125
for cookie in response.cookies.jar:
120
126
cookies[cookie.name] = cookie.value
121
127
122
async def get_nodriver(proxy: str = None, user_data_dir = "nodriver", browser_executable_path=None, **kwargs)-> Browser:
128
async def get_nodriver(
129
proxy: str = None,
130
user_data_dir = "nodriver",
131
timeout: int = 120,
132
browser_executable_path=None,
133
**kwargs
134
) -> Browser:
123
135
if not has_nodriver:
124
136
raise MissingRequirementsError('Install "nodriver" and "platformdirs" package | pip install -U nodriver platformdirs')
125
137
user_data_dir = user_config_dir(f"g4f-{user_data_dir}") if has_platformdirs else None
@@ -131,10 +143,32 @@ async def get_nodriver(proxy: str = None, user_data_dir = "nodriver", browser_ex
131
143
browser_executable_path = "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe"
132
144
if not os.path.exists(browser_executable_path):
133
145
browser_executable_path = None
146
lock_file = Path(get_cookies_dir()) / ".nodriver_is_open"
147
# Implement a short delay (milliseconds) to prevent race conditions.
148
await asyncio.sleep(0.1 * random.randint(0, 50))
149
if lock_file.exists():
150
opend_at = float(lock_file.read_text())
151
time_open = time.time() - opend_at
152
if timeout * 2 > time_open:
153
debug.log(f"Nodriver: Browser is already in use since {time_open} secs.")
154
for _ in range(timeout):
155
if lock_file.exists():
156
await asyncio.sleep(1)
157
else:
158
break
159
lock_file.write_text(str(time.time()))
134
160
debug.log(f"Open nodriver with user_dir: {user_data_dir}")
135
return await nodriver.start(
161
browser = await nodriver.start(
136
162
user_data_dir=user_data_dir,
137
163
browser_args=None if proxy is None else [f"--proxy-server={proxy}"],
138
164
browser_executable_path=browser_executable_path,
139
165
**kwargs
140
)
166
)
167
stop = browser.stop
168
def on_stop():
169
try:
170
stop()
171
finally:
172
lock_file.unlink(missing_ok=True)
173
browser.stop = on_stop
174
return browser