返回提交历史
Modified
g4f/Provider/needs_auth/Gemini.py
+14
-2
Modified
g4f/Provider/needs_auth/LMArena.py
+26
-46
Modified
g4f/Provider/needs_auth/OpenaiChat.py
+17
-9
Modified
g4f/Provider/template/OpenaiTemplate.py
+6
-2
XFEstudio/gpt4free
feat: Add get_quota method and refactor login methods in multiple providers
49d0cfe2
代码差异
4 个文件
+63
-59
@@ -105,7 +105,7 @@ class Gemini(AsyncGeneratorProvider, ProviderModelMixin):
105
105
rotate_tasks = {}
106
106
107
107
@classmethod
108
async def nodriver_login(cls, proxy: str = None) -> AsyncIterator[str]:
108
async def login(cls, proxy: str = None) -> AsyncIterator[str]:
109
109
if not has_nodriver:
110
110
debug.log("Skip nodriver login in Gemini provider")
111
111
return
@@ -146,6 +146,18 @@ class Gemini(AsyncGeneratorProvider, ProviderModelMixin):
146
146
cls._cookies["__Secure-1PSIDTS"] = new_1psidts
147
147
await asyncio.sleep(cls.refresh_interval)
148
148
149
@classmethod
150
async def get_quota(cls, **kwargs):
151
if not cls._cookies:
152
cls._cookies = get_cookies(GOOGLE_COOKIE_DOMAIN, False, True)
153
if not cls._cookies:
154
raise MissingAuthError('Missing or invalid "__Secure-1PSID" cookie')
155
async with ClientSession(
156
headers=REQUEST_HEADERS
157
) as session:
158
await cls.fetch_snlm0e(session, cls._cookies)
159
return cls._snlm0e
160
149
161
@classmethod
150
162
async def create_async_generator(
151
163
cls,
@@ -188,7 +200,7 @@ class Gemini(AsyncGeneratorProvider, ProviderModelMixin):
188
200
await cls.fetch_snlm0e(session, cls._cookies) if cls._cookies else None
189
201
if not cls._snlm0e:
190
202
try:
191
async for chunk in cls.nodriver_login(proxy):
203
async for chunk in cls.login(proxy):
192
204
yield chunk
193
205
except Exception as e:
194
206
raise MissingAuthError('Missing or invalid "__Secure-1PSID" cookie', e)
@@ -442,22 +442,8 @@ class LMArena(AsyncGeneratorProvider, ProviderModelMixin, AuthFileMixin):
442
442
return files
443
443
444
444
@classmethod
445
async def create_async_generator(
446
cls,
447
model: str,
448
messages: Messages,
449
conversation: JsonConversation = None,
450
media: MediaListType = None,
451
proxy: str = None,
452
timeout: int = None,
453
**kwargs
454
) -> AsyncResult:
455
if cls.share_url is None:
456
cls.share_url = os.getenv("G4F_SHARE_URL")
457
prompt = get_last_user_message(messages)
445
def read_args(cls, args: dict = {}):
458
446
cache_file = cls.get_cache_file()
459
args = kwargs.get("lmarena_args", {})
460
grecaptcha = kwargs.pop("grecaptcha", "")
461
447
if not args and cache_file.exists():
462
448
try:
463
449
with cache_file.open("r") as f:
@@ -466,35 +452,35 @@ class LMArena(AsyncGeneratorProvider, ProviderModelMixin, AuthFileMixin):
466
452
debug.log(f"Cache file {cache_file} is corrupted, removing it.")
467
453
cache_file.unlink()
468
454
args = None
469
force = False
455
return args
456
457
@classmethod
458
async def get_quota(cls, **kwargs):
459
args = cls.read_args()
460
if not args:
461
raise MissingAuthError("No authentication arguments found.")
462
return {key: len(value) if value else 0 for key, value in args.items()}
463
464
@classmethod
465
async def create_async_generator(
466
cls,
467
model: str,
468
messages: Messages,
469
conversation: JsonConversation = None,
470
media: MediaListType = None,
471
proxy: str = None,
472
timeout: int = None,
473
**kwargs
474
) -> AsyncResult:
475
prompt = get_last_user_message(messages)
476
cache_file = cls.get_cache_file()
477
args = cls.read_args(kwargs.get("lmarena_args", {}))
478
grecaptcha = kwargs.pop("grecaptcha", "")
470
479
for _ in range(2):
471
480
if args:
472
481
pass
473
elif has_nodriver or cls.share_url is None:
482
elif has_nodriver:
474
483
args, grecaptcha = await cls.get_args_from_nodriver(proxy)
475
476
elif not cls.looked:
477
cls.looked = True
478
try:
479
debug.log("No cache file found, trying to fetch from share URL.")
480
response = requests.get(cls.share_url, params={
481
"prompt": prompt,
482
"model": model,
483
"provider": cls.__name__
484
})
485
raise_for_status(response)
486
if response.headers.get("Content-Type", "").startswith("image/"):
487
yield ImageResponse(str(response.url), prompt)
488
else:
489
text, *args = response.text.split("\n" * 10 + "<!--", 1)
490
if args:
491
debug.log("Save args to cache file:", str(cache_file))
492
with cache_file.open("w") as f:
493
f.write(args[0].strip())
494
yield text
495
finally:
496
cls.looked = False
497
return
498
484
else:
499
485
raise MissingRequirementsError("No auth file found and nodriver is not available.")
500
486
@@ -587,21 +573,15 @@ class LMArena(AsyncGeneratorProvider, ProviderModelMixin, AuthFileMixin):
587
573
continue
588
574
except (RateLimitError) as error:
589
575
args = None
590
force = True
591
576
debug.error(error)
592
577
continue
593
578
except:
594
579
raise
595
if args and os.getenv("G4F_SHARE_AUTH") and not kwargs.get("action"):
596
yield "\n" * 10
597
yield "<!--"
598
yield json.dumps(args)
599
580
if args:
600
581
debug.log("Save args to cache file:", str(cache_file))
601
582
with cache_file.open("w") as f:
602
583
f.write(json.dumps(args))
603
584
604
605
585
def get_content_type(url: str) -> str:
606
586
if url.endswith(".webp"):
607
587
return "image/webp"
@@ -130,9 +130,17 @@ class OpenaiChat(AsyncAuthedProvider, ProviderModelMixin):
130
130
user = await response.json()
131
131
return {"id": user.get("id"), "name": user.get("name")}
132
132
133
@classmethod
134
async def login(cls, **kwargs):
135
cache_file = cls.get_cache_file()
136
async for chunk in cls.on_auth_async(**kwargs):
137
if isinstance(chunk, AuthResult):
138
cls.write_cache_file(cache_file, chunk)
139
return
140
133
141
@classmethod
134
142
async def on_auth_async(cls, proxy: str = None, **kwargs) -> AsyncIterator:
135
async for chunk in cls.login(proxy=proxy):
143
async for chunk in cls.login_generator(proxy=proxy):
136
144
yield chunk
137
145
yield AuthResult(
138
146
api_key=cls._api_key,
@@ -1037,14 +1045,14 @@ class OpenaiChat(AsyncAuthedProvider, ProviderModelMixin):
1037
1045
yield chunk
1038
1046
1039
1047
@classmethod
1040
async def login(
1041
cls,
1042
proxy: str = None,
1043
api_key: str = None,
1044
proof_token: str = None,
1045
cookies: Cookies = None,
1046
headers: dict = None,
1047
**kwargs
1048
async def login_generator(
1049
cls,
1050
proxy: str = None,
1051
api_key: str = None,
1052
proof_token: str = None,
1053
cookies: Cookies = None,
1054
headers: dict = None,
1055
**kwargs
1048
1056
) -> AsyncIterator:
1049
1057
if cls._expires is not None and (cls._expires - 60 * 10) < time.time():
1050
1058
cls._headers = cls._api_key = None
@@ -32,6 +32,7 @@ class OpenaiTemplate(AsyncGeneratorProvider, ProviderModelMixin, RaiseErrorMixin
32
32
add_user = True
33
33
use_image_size = False
34
34
max_tokens: int = None
35
_checked_api_keys: dict = {}
35
36
36
37
@classmethod
37
38
async def get_quota(cls, api_key: Optional[str] = None, **kwargs) -> dict:
@@ -49,8 +50,9 @@ class OpenaiTemplate(AsyncGeneratorProvider, ProviderModelMixin, RaiseErrorMixin
49
50
return await cls.test_api_key(api_key)
50
51
51
52
@classmethod
52
@lru_cache(maxsize=24)
53
53
async def test_api_key(cls, api_key: str):
54
if api_key in cls._checked_api_keys:
55
return cls._checked_api_keys[api_key]
54
56
url = f"{cls.base_url}/chat/completions"
55
57
headers = {
56
58
"authorization": f"Bearer {api_key}"
@@ -63,7 +65,9 @@ class OpenaiTemplate(AsyncGeneratorProvider, ProviderModelMixin, RaiseErrorMixin
63
65
async with StreamSession() as session:
64
66
async with session.post(url, headers=headers, json=json_data) as response:
65
67
await raise_for_status(response)
66
return await response.json()
68
result = await response.json()
69
cls._checked_api_keys[api_key] = result
70
return result
67
71
68
72
@classmethod
69
73
def is_provider_api_key(cls, api_key: str) -> bool: