返回提交历史
Modified
g4f/Provider/PollinationsAI.py
+28
-27
XFEstudio/gpt4free
fix: Update API endpoints and improve authentication handling in PollinationsAI provider
233fb6fc
代码差异
1 个文件
+28
-27
@@ -24,6 +24,7 @@ from ..providers.response import ImageResponse, Reasoning, VideoResponse, JsonRe
24
24
from ..tools.media import render_messages
25
25
from ..tools.run_tools import AuthManager
26
26
from ..cookies import get_cookies_dir
27
from ..tools.files import secure_filename
27
28
from .template.OpenaiTemplate import read_response
28
29
from .. import debug
29
30
@@ -31,7 +32,6 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
31
32
label = "Pollinations AI 🌸"
32
33
url = "https://pollinations.ai"
33
34
login_url = "https://enter.pollinations.ai"
34
api_key = "pk", "_B9YJX5SBohhm2ePq"
35
35
active_by_default = True
36
36
working = True
37
37
supports_system_message = True
@@ -44,7 +44,9 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
44
44
gen_text_api_endpoint = "https://gen.pollinations.ai/v1/chat/completions"
45
45
image_models_endpoint = "https://gen.pollinations.ai/image/models"
46
46
text_models_endpoint = "https://gen.pollinations.ai/text/models"
47
BALANCE_ENDPOINT = "https://gen.pollinations.ai/account/balance"
47
balance_endpoint = "https://api.gpt4free.workers.dev/api/pollinations/account/balance"
48
worker_api_endpoint = "https://api.gpt4free.workers.dev/api/pollinations/chat/completions"
49
worker_models_endpoint = "https://api.gpt4free.workers.dev/api/pollinations/text/models"
48
50
49
51
# Models configuration
50
52
default_model = "openai"
@@ -56,8 +58,6 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
56
58
image_models = [default_image_model, "turbo", "kontext"]
57
59
audio_models = {}
58
60
vision_models = [default_vision_model]
59
_gen_models_loaded = False
60
_free_models_loaded = False
61
61
model_aliases = {
62
62
"gpt-4.1-nano": "openai-fast",
63
63
"llama-4-scout": "llamascout",
@@ -74,12 +74,15 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
74
74
}
75
75
swap_model_aliases = {v: k for k, v in model_aliases.items()}
76
76
balance: Optional[float] = None
77
current_models_endpoint: Optional[str] = None
77
78
78
79
@classmethod
79
80
def get_balance(cls, api_key: str, timeout: Optional[float] = None) -> Optional[float]:
80
81
try:
81
headers = {"authorization": f"Bearer {api_key}"}
82
response = requests.get(cls.BALANCE_ENDPOINT, headers=headers, timeout=timeout)
82
headers = None
83
if api_key:
84
headers = {"authorization": f"Bearer {api_key}"}
85
response = requests.get(cls.balance_endpoint, headers=headers, timeout=timeout)
83
86
response.raise_for_status()
84
87
data = response.json()
85
88
cls.balance = float(data.get("balance", 0.0))
@@ -103,17 +106,18 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
103
106
104
107
if not api_key:
105
108
api_key = AuthManager.load_api_key(cls)
106
if not api_key or api_key.startswith("g4f_") or api_key.startswith("gfs_"):
107
api_key = "".join(cls.api_key)
108
109
if cls.balance or cls.balance is None and cls.get_balance(api_key, timeout) and cls.balance > 0:
110
debug.log(f"Authenticated with Pollinations AI using API key.")
109
if (not api_key or api_key.startswith("g4f_") or api_key.startswith("gfs_")) and cls.balance or cls.balance is None and cls.get_balance(api_key, timeout) and cls.balance > 0:
110
debug.log(f"Authenticated with Pollinations AI using G4F API.")
111
models_url = cls.worker_models_endpoint
112
elif api_key:
113
debug.log(f"Using Pollinations AI with provided API key.")
114
models_url = cls.gen_text_api_endpoint
111
115
else:
112
116
debug.log(f"Using Pollinations AI without authentication.")
113
api_key = None
117
models_url = cls.text_models_endpoint
114
118
115
if not cls._free_models_loaded or api_key and not cls._gen_models_loaded:
116
path = Path(get_cookies_dir()) / "models" / datetime.today().strftime('%Y-%m-%d') / f"{cls.__name__}{'-auth' if api_key else ''}.json"
119
if cls.current_models_endpoint != models_url:
120
path = Path(get_cookies_dir()) / "models" / datetime.today().strftime('%Y-%m-%d') / f"{secure_filename(models_url)}.json"
117
121
if path.exists():
118
122
try:
119
123
data = path.read_text()
@@ -180,10 +184,7 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
180
184
cls.swap_model_aliases = {v: k for k, v in cls.model_aliases.items()}
181
185
182
186
finally:
183
if api_key:
184
cls._gen_models_loaded = True
185
else:
186
cls._free_models_loaded = True
187
cls.current_models_endpoint = models_url
187
188
# Return unique models across all categories
188
189
all_models = cls.text_models.copy()
189
190
all_models.extend(cls.image_models)
@@ -262,7 +263,7 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
262
263
has_audio = True
263
264
break
264
265
model = "openai-audio" if has_audio else cls.default_model
265
if cls.get_models(api_key=api_key, timeout=kwargs.get("timeout")):
266
if cls.get_models(api_key=api_key, timeout=kwargs.get("timeout", 15)):
266
267
if model in cls.model_aliases:
267
268
model = cls.model_aliases[model]
268
269
debug.log(f"Using model: {model}")
@@ -480,17 +481,17 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
480
481
seed=None if "tools" in extra_body else seed,
481
482
**extra_body
482
483
)
484
if (not api_key or api_key.startswith("g4f_") or api_key.startswith("gfs_")) and cls.balance and cls.balance > 0:
485
endpoint = cls.worker_api_endpoint
486
elif api_key:
487
endpoint = cls.gen_text_api_endpoint
488
else:
489
endpoint = cls.text_api_endpoint
483
490
headers = None
484
if api_key and not api_key.startswith("g4f_") and not api_key.startswith("gfs_"):
491
if api_key:
485
492
headers = {"authorization": f"Bearer {api_key}"}
486
elif cls.balance and cls.balance > 0:
487
headers = {"authorization": f"Bearer {''.join(cls.api_key)}"}
488
493
yield JsonRequest.from_dict(data)
489
if headers:
490
url = cls.gen_text_api_endpoint
491
else:
492
url = cls.text_api_endpoint
493
async with session.post(url, json=data, headers=headers) as response:
494
async with session.post(endpoint, json=data, headers=headers) as response:
494
495
if response.status in (400, 500):
495
496
debug.error(f"Error: {response.status} - Bad Request: {data}")
496
497
async for chunk in read_response(response, stream, format_media_prompt(messages), cls.get_dict(),