返回提交历史
Modified
g4f/Provider/PollinationsAI.py
+134
-118
Modified
g4f/Provider/Qwen.py
+18
-15
XFEstudio/gpt4free
Qwen Catch error (#3186)
90627d59
代码差异
2 个文件
+152
-133
@@ -61,6 +61,7 @@ FOLLOWUPS_DEVELOPER_MESSAGE = [{
61
61
"content": "Provide conversation options.",
62
62
}]
63
63
64
64
65
class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
65
66
label = "Pollinations AI 🌸"
66
67
url = "https://pollinations.ai"
@@ -110,6 +111,7 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
110
111
elif alias in cls.swap_model_aliases:
111
112
alias = cls.swap_model_aliases[alias]
112
113
return alias.replace("-instruct", "").replace("qwen-", "qwen").replace("qwen", "qwen-")
114
113
115
if not cls._models_loaded:
114
116
try:
115
117
# Update of image models
@@ -121,12 +123,12 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
121
123
122
124
# Combine image models without duplicates
123
125
image_models = cls.image_models.copy() # Start with default model
124
126
125
127
# Add extra image models if not already in the list
126
128
for model in new_image_models:
127
129
if model not in image_models:
128
130
image_models.append(model)
129
131
130
132
cls.image_models = image_models
131
133
132
134
text_response = requests.get("https://g4f.dev/api/pollinations.ai/models")
@@ -192,36 +194,37 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
192
194
193
195
@classmethod
194
196
async def create_async_generator(
195
cls,
196
model: str,
197
messages: Messages,
198
stream: bool = True,
199
proxy: str = None,
200
cache: bool = None,
201
referrer: str = STATIC_URL,
202
api_key: str = None,
203
extra_body: dict = None,
204
# Image generation parameters
205
prompt: str = None,
206
aspect_ratio: str = None,
207
width: int = None,
208
height: int = None,
209
seed: Optional[int] = None,
210
nologo: bool = True,
211
private: bool = False,
212
enhance: bool = None,
213
safe: bool = False,
214
transparent: bool = False,
215
n: int = 1,
216
# Text generation parameters
217
media: MediaListType = None,
218
temperature: float = None,
219
presence_penalty: float = None,
220
top_p: float = None,
221
frequency_penalty: float = None,
222
response_format: Optional[dict] = None,
223
extra_parameters: list[str] = ["tools", "parallel_tool_calls", "tool_choice", "reasoning_effort", "logit_bias", "voice", "modalities", "audio"],
224
**kwargs
197
cls,
198
model: str,
199
messages: Messages,
200
stream: bool = True,
201
proxy: str = None,
202
cache: bool = None,
203
referrer: str = STATIC_URL,
204
api_key: str = None,
205
extra_body: dict = None,
206
# Image generation parameters
207
prompt: str = None,
208
aspect_ratio: str = None,
209
width: int = None,
210
height: int = None,
211
seed: Optional[int] = None,
212
nologo: bool = True,
213
private: bool = False,
214
enhance: bool = None,
215
safe: bool = False,
216
transparent: bool = False,
217
n: int = 1,
218
# Text generation parameters
219
media: MediaListType = None,
220
temperature: float = None,
221
presence_penalty: float = None,
222
top_p: float = None,
223
frequency_penalty: float = None,
224
response_format: Optional[dict] = None,
225
extra_parameters: list[str] = ["tools", "parallel_tool_calls", "tool_choice", "reasoning_effort",
226
"logit_bias", "voice", "modalities", "audio"],
227
**kwargs
225
228
) -> AsyncResult:
226
229
if cache is None:
227
230
cache = kwargs.get("action") == "next"
@@ -241,23 +244,23 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
241
244
debug.log(f"Using model: {model}")
242
245
if model in cls.image_models:
243
246
async for chunk in cls._generate_image(
244
model="gptimage" if model == "transparent" else model,
245
prompt=format_media_prompt(messages, prompt),
246
media=media,
247
proxy=proxy,
248
aspect_ratio=aspect_ratio,
249
width=width,
250
height=height,
251
seed=seed,
252
cache=cache,
253
nologo=nologo,
254
private=private,
255
enhance=enhance,
256
safe=safe,
257
transparent=transparent or model == "transparent",
258
n=n,
259
referrer=referrer,
260
api_key=api_key
247
model="gptimage" if model == "transparent" else model,
248
prompt=format_media_prompt(messages, prompt),
249
media=media,
250
proxy=proxy,
251
aspect_ratio=aspect_ratio,
252
width=width,
253
height=height,
254
seed=seed,
255
cache=cache,
256
nologo=nologo,
257
private=private,
258
enhance=enhance,
259
safe=safe,
260
transparent=transparent or model == "transparent",
261
n=n,
262
referrer=referrer,
263
api_key=api_key
261
264
):
262
265
yield chunk
263
266
else:
@@ -272,47 +275,47 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
272
275
}
273
276
model = cls.default_audio_model
274
277
async for result in cls._generate_text(
275
model=model,
276
messages=messages,
277
media=media,
278
proxy=proxy,
279
temperature=temperature,
280
presence_penalty=presence_penalty,
281
top_p=top_p,
282
frequency_penalty=frequency_penalty,
283
response_format=response_format,
284
seed=seed,
285
cache=cache,
286
stream=stream,
287
extra_parameters=extra_parameters,
288
referrer=referrer,
289
api_key=api_key,
290
extra_body=extra_body,
291
**kwargs
278
model=model,
279
messages=messages,
280
media=media,
281
proxy=proxy,
282
temperature=temperature,
283
presence_penalty=presence_penalty,
284
top_p=top_p,
285
frequency_penalty=frequency_penalty,
286
response_format=response_format,
287
seed=seed,
288
cache=cache,
289
stream=stream,
290
extra_parameters=extra_parameters,
291
referrer=referrer,
292
api_key=api_key,
293
extra_body=extra_body,
294
**kwargs
292
295
):
293
296
yield result
294
297
295
298
@classmethod
296
299
async def _generate_image(
297
cls,
298
model: str,
299
prompt: str,
300
media: MediaListType,
301
proxy: str,
302
aspect_ratio: str,
303
width: int,
304
height: int,
305
seed: Optional[int],
306
cache: bool,
307
nologo: bool,
308
private: bool,
309
enhance: bool,
310
safe: bool,
311
transparent: bool,
312
n: int,
313
referrer: str,
314
api_key: str,
315
timeout: int = 120
300
cls,
301
model: str,
302
prompt: str,
303
media: MediaListType,
304
proxy: str,
305
aspect_ratio: str,
306
width: int,
307
height: int,
308
seed: Optional[int],
309
cache: bool,
310
nologo: bool,
311
private: bool,
312
enhance: bool,
313
safe: bool,
314
transparent: bool,
315
n: int,
316
referrer: str,
317
api_key: str,
318
timeout: int = 120
316
319
) -> AsyncResult:
317
320
if enhance is None:
318
321
enhance = True if model == "flux" else False
@@ -339,37 +342,47 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
339
342
encoded_prompt = prompt.strip(". \n")
340
343
if model == "gptimage" and aspect_ratio is not None:
341
344
encoded_prompt = f"{encoded_prompt} aspect-ratio: {aspect_ratio}"
342
encoded_prompt = quote_plus(encoded_prompt)[:4096-len(cls.image_api_endpoint)-len(query)-8].rstrip("%")
345
encoded_prompt = quote_plus(encoded_prompt)[:4096 - len(cls.image_api_endpoint) - len(query) - 8].rstrip("%")
343
346
url = f"{cls.image_api_endpoint}prompt/{encoded_prompt}?{query}"
347
344
348
def get_url_with_seed(i: int, seed: Optional[int] = None):
345
349
if model == "gptimage":
346
350
return url
347
351
if i == 0:
348
352
if not cache and seed is None:
349
seed = random.randint(0, 2**32)
353
seed = random.randint(0, 2 ** 32)
350
354
else:
351
seed = random.randint(0, 2**32)
355
seed = random.randint(0, 2 ** 32)
352
356
return f"{url}&seed={seed}" if seed else url
357
353
358
headers = {"referer": referrer}
354
359
if api_key:
355
360
headers["authorization"] = f"Bearer {api_key}"
356
361
async with ClientSession(
357
headers=DEFAULT_HEADERS,
358
connector=get_connector(proxy=proxy),
359
timeout=ClientTimeout(timeout)
362
headers=DEFAULT_HEADERS,
363
connector=get_connector(proxy=proxy),
364
timeout=ClientTimeout(timeout)
360
365
) as session:
361
366
responses = set()
362
367
yield Reasoning(label=f"Generating {n} {'image' if n == 1 else 'images'}")
363
368
finished = 0
364
369
start = time.time()
370
365
371
async def get_image(responses: set, i: int, seed: Optional[int] = None):
366
372
try:
367
async with session.get(get_url_with_seed(i, seed), allow_redirects=False, headers=headers) as response:
373
async with session.get(get_url_with_seed(i, seed), allow_redirects=False,
374
headers=headers) as response:
368
375
await raise_for_status(response)
369
376
except Exception as e:
370
377
responses.add(e)
371
378
debug.error(f"Error fetching image: {e}")
372
responses.add(ImageResponse(str(response.url), prompt, {"headers": headers}))
379
if response.headers['content-type'].startswith("image/"):
380
responses.add(ImageResponse(str(response.url), prompt, {"headers": headers}))
381
else:
382
t_ = await response.text()
383
debug.error(f"UnHandel Error fetching image: {t_}")
384
responses.add(t_)
385
373
386
tasks: list[asyncio.Task] = []
374
387
for i in range(int(n)):
375
388
tasks.append(asyncio.create_task(get_image(responses, i, seed)))
@@ -386,8 +399,9 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
386
399
raise item
387
400
else:
388
401
finished += 1
389
yield Reasoning(label=f"Image {finished}/{n} failed after {time.time() - start:.2f}s: {item}")
390
else:
402
yield Reasoning(
403
label=f"Image {finished}/{n} failed after {time.time() - start:.2f}s: {item}")
404
else:
391
405
finished += 1
392
406
yield Reasoning(label=f"Image {finished}/{n} generated in {time.time() - start:.2f}s")
393
407
yield item
@@ -397,27 +411,27 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
397
411
398
412
@classmethod
399
413
async def _generate_text(
400
cls,
401
model: str,
402
messages: Messages,
403
media: MediaListType,
404
proxy: str,
405
temperature: float,
406
presence_penalty: float,
407
top_p: float,
408
frequency_penalty: float,
409
response_format: Optional[dict],
410
seed: Optional[int],
411
cache: bool,
412
stream: bool,
413
extra_parameters: list[str],
414
referrer: str,
415
api_key: str,
416
extra_body: dict,
417
**kwargs
414
cls,
415
model: str,
416
messages: Messages,
417
media: MediaListType,
418
proxy: str,
419
temperature: float,
420
presence_penalty: float,
421
top_p: float,
422
frequency_penalty: float,
423
response_format: Optional[dict],
424
seed: Optional[int],
425
cache: bool,
426
stream: bool,
427
extra_parameters: list[str],
428
referrer: str,
429
api_key: str,
430
extra_body: dict,
431
**kwargs
418
432
) -> AsyncResult:
419
433
if not cache and seed is None:
420
seed = random.randint(0, 2**32)
434
seed = random.randint(0, 2 ** 32)
421
435
422
436
async with ClientSession(headers=DEFAULT_HEADERS, connector=get_connector(proxy=proxy)) as session:
423
437
extra_body.update({param: kwargs[param] for param in extra_parameters if param in kwargs})
@@ -440,7 +454,7 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
440
454
frequency_penalty=frequency_penalty,
441
455
response_format=response_format,
442
456
stream=stream,
443
seed=None if model =="grok" else seed,
457
seed=None if model == "grok" else seed,
444
458
referrer=referrer,
445
459
**extra_body
446
460
)
@@ -451,7 +465,8 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
451
465
if response.status in (400, 500):
452
466
debug.error(f"Error: {response.status} - Bad Request: {data}")
453
467
full_resposne = []
454
async for chunk in read_response(response, stream, format_media_prompt(messages), cls.get_dict(), kwargs.get("download_media", True)):
468
async for chunk in read_response(response, stream, format_media_prompt(messages), cls.get_dict(),
469
kwargs.get("download_media", True)):
455
470
if isinstance(chunk, str):
456
471
full_resposne.append(chunk)
457
472
yield chunk
@@ -479,7 +494,8 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
479
494
async with session.post(cls.openai_endpoint, json=data, headers=headers) as response:
480
495
try:
481
496
await raise_for_status(response)
482
tool_calls = (await response.json()).get("choices", [{}])[0].get("message", {}).get("tool_calls", [])
497
tool_calls = (await response.json()).get("choices", [{}])[0].get("message", {}).get(
498
"tool_calls", [])
483
499
if tool_calls:
484
500
arguments = json.loads(tool_calls.pop().get("function", {}).get("arguments"))
485
501
if arguments.get("title"):
@@ -487,4 +503,4 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
487
503
if arguments.get("followups"):
488
504
yield SuggestedFollowups(arguments.get("followups"))
489
505
except Exception as e:
490
debug.error("Error generating title and followups:", e)
506
debug.error("Error generating title and followups:", e)
@@ -8,7 +8,7 @@ from time import time
8
8
from typing import Literal, Optional
9
9
10
10
import aiohttp
11
from ..errors import RateLimitError
11
from ..errors import RateLimitError, ResponseError
12
12
from ..typing import AsyncResult, Messages, MediaListType
13
13
from ..providers.response import JsonConversation, Reasoning, Usage, ImageResponse, FinishReason
14
14
from ..requests import sse_stream
@@ -97,20 +97,20 @@ class Qwen(AsyncGeneratorProvider, ProviderModelMixin):
97
97
98
98
@classmethod
99
99
async def create_async_generator(
100
cls,
101
model: str,
102
messages: Messages,
103
media: MediaListType = None,
104
conversation: JsonConversation = None,
105
proxy: str = None,
106
timeout: int = 120,
107
stream: bool = True,
108
enable_thinking: bool = True,
109
chat_type: Literal[
110
"t2t", "search", "artifacts", "web_dev", "deep_research", "t2i", "image_edit", "t2v"
111
] = "t2t",
112
aspect_ratio: Optional[Literal["1:1", "4:3", "3:4", "16:9", "9:16"]] = None,
113
**kwargs
100
cls,
101
model: str,
102
messages: Messages,
103
media: MediaListType = None,
104
conversation: JsonConversation = None,
105
proxy: str = None,
106
timeout: int = 120,
107
stream: bool = True,
108
enable_thinking: bool = True,
109
chat_type: Literal[
110
"t2t", "search", "artifacts", "web_dev", "deep_research", "t2i", "image_edit", "t2v"
111
] = "t2t",
112
aspect_ratio: Optional[Literal["1:1", "4:3", "3:4", "16:9", "9:16"]] = None,
113
**kwargs
114
114
) -> AsyncResult:
115
115
"""
116
116
chat_type:
@@ -265,6 +265,9 @@ class Qwen(AsyncGeneratorProvider, ProviderModelMixin):
265
265
usage = None
266
266
async for chunk in sse_stream(resp):
267
267
try:
268
error = chunk.get("error", {})
269
if error:
270
raise ResponseError(f'{error["code"]}: {error["details"]}')
268
271
usage = chunk.get("usage", usage)
269
272
choices = chunk.get("choices", [])
270
273
if not choices: continue