返回提交历史
Modified
g4f/Provider/Copilot.py
+2
-2
Modified
g4f/Provider/PollinationsAI.py
+3
-71
Modified
g4f/api/__init__.py
+25
-2
XFEstudio/gpt4free
Refactor Copilot and PollinationsAI classes for improved error handling and timeout adjustments; add rate limiting in API class based on user IP.
23218c4a
代码差异
3 个文件
+30
-75
@@ -284,7 +284,7 @@ class Copilot(AsyncAuthedProvider, ProviderModelMixin):
284
284
sources = {}
285
285
while not wss.closed:
286
286
try:
287
msg_txt, _ = await asyncio.wait_for(wss.recv(), 3 if done else timeout)
287
msg_txt, _ = await asyncio.wait_for(wss.recv(), 1 if done else timeout)
288
288
msg = json.loads(msg_txt)
289
289
except:
290
290
break
@@ -369,7 +369,7 @@ async def get_access_token_and_cookies(url: str, proxy: str = None, needs_auth:
369
369
button = await page.select("[data-testid=\"submit-button\"]")
370
370
if button:
371
371
await button.click()
372
turnstile = await page.select('#cf-turnstile', 300)
372
turnstile = await page.select('#cf-turnstile')
373
373
if turnstile:
374
374
debug.log("Found Element: 'cf-turnstile'")
375
375
await asyncio.sleep(3)
@@ -31,37 +31,6 @@ DEFAULT_HEADERS = {
31
31
"origin": "https://pollinations.ai",
32
32
}
33
33
34
FOLLOWUPS_TOOLS = [{
35
"type": "function",
36
"function": {
37
"name": "options",
38
"description": "Provides options for the conversation",
39
"parameters": {
40
"properties": {
41
"title": {
42
"title": "Conversation title. Prefixed with one or more emojies",
43
"type": "string"
44
},
45
"followups": {
46
"items": {
47
"type": "string"
48
},
49
"title": "Suggested 4 Followups (only user messages)",
50
"type": "array"
51
}
52
},
53
"title": "Conversation",
54
"type": "object"
55
}
56
}
57
}]
58
59
FOLLOWUPS_DEVELOPER_MESSAGE = [{
60
"role": "developer",
61
"content": "Provide conversation options.",
62
}]
63
64
65
34
class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
66
35
label = "Pollinations AI 🌸"
67
36
url = "https://pollinations.ai"
@@ -375,12 +344,12 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
375
344
await raise_for_status(response)
376
345
except Exception as e:
377
346
responses.add(e)
378
debug.error(f"Error fetching image: {e}")
347
debug.error(f"Error fetching image:", e)
379
348
if response.headers['content-type'].startswith("image/"):
380
349
responses.add(ImageResponse(str(response.url), prompt, {"headers": headers}))
381
350
else:
382
351
t_ = await response.text()
383
debug.error(f"UnHandel Error fetching image: {t_}")
352
debug.error(f"UnHandel Error fetching image:", t_)
384
353
responses.add(t_)
385
354
386
355
tasks: list[asyncio.Task] = []
@@ -465,43 +434,6 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
465
434
async with session.post(cls.openai_endpoint, json=data, headers=headers) as response:
466
435
if response.status in (400, 500):
467
436
debug.error(f"Error: {response.status} - Bad Request: {data}")
468
full_resposne = []
469
437
async for chunk in read_response(response, stream, format_media_prompt(messages), cls.get_dict(),
470
438
kwargs.get("download_media", True)):
471
if isinstance(chunk, str):
472
full_resposne.append(chunk)
473
yield chunk
474
if full_resposne:
475
full_content = "".join(full_resposne)
476
if kwargs.get("action") == "next" and model != "evil":
477
tool_messages = []
478
for message in messages:
479
if message.get("role") == "user":
480
if isinstance(message.get("content"), str):
481
tool_messages.append({"role": "user", "content": message.get("content")})
482
elif isinstance(message.get("content"), list):
483
next_value = message.get("content").pop()
484
if isinstance(next_value, dict):
485
next_value = next_value.get("text")
486
if next_value:
487
tool_messages.append({"role": "user", "content": next_value})
488
tool_messages.append({"role": "assistant", "content": full_content})
489
data = {
490
"model": "openai",
491
"messages": tool_messages + FOLLOWUPS_DEVELOPER_MESSAGE,
492
"tool_choice": "required",
493
"tools": FOLLOWUPS_TOOLS
494
}
495
async with session.post(cls.openai_endpoint, json=data, headers=headers) as response:
496
try:
497
await raise_for_status(response)
498
tool_calls = (await response.json()).get("choices", [{}])[0].get("message", {}).get(
499
"tool_calls", [])
500
if tool_calls:
501
arguments = json.loads(tool_calls.pop().get("function", {}).get("arguments"))
502
if arguments.get("title"):
503
yield TitleGeneration(arguments.get("title"))
504
if arguments.get("followups"):
505
yield SuggestedFollowups(arguments.get("followups"))
506
except Exception as e:
507
debug.error("Error generating title and followups:", e)
439
yield chunk
@@ -65,7 +65,7 @@ from g4f.client.helper import filter_none
65
65
from g4f.config import DEFAULT_PORT, DEFAULT_TIMEOUT, DEFAULT_STREAM_TIMEOUT
66
66
from g4f.image import EXTENSIONS_MAP, is_data_an_media, process_image
67
67
from g4f.image.copy_images import get_media_dir, copy_media, get_source_url
68
from g4f.errors import ProviderNotFoundError, ModelNotFoundError, MissingAuthError, NoValidHarFileError, MissingRequirementsError
68
from g4f.errors import ProviderNotFoundError, ModelNotFoundError, MissingAuthError, NoValidHarFileError, MissingRequirementsError, RateLimitError
69
69
from g4f.cookies import read_cookie_files, get_cookies_dir
70
70
from g4f.providers.types import ProviderType
71
71
from g4f.providers.response import AudioResponse
@@ -417,6 +417,8 @@ class Api:
417
417
})
418
418
return ErrorResponse.from_message("The model does not exist.", HTTP_404_NOT_FOUND)
419
419
420
most_wanted = {}
421
failure_counts = {}
420
422
responses = {
421
423
HTTP_200_OK: {"model": ChatCompletion},
422
424
HTTP_401_UNAUTHORIZED: {"model": ErrorResponseModel},
@@ -433,8 +435,29 @@ class Api:
433
435
provider: str = None,
434
436
conversation_id: str = None,
435
437
x_user: Annotated[str | None, Header()] = None,
436
cf_ipcountry: Annotated[str | None, Header()] = None
438
cf_ipcountry: Annotated[str | None, Header()] = None,
439
x_forwarded_for: Annotated[str | None, Header()] = None
437
440
):
441
if AppConfig.demo and x_forwarded_for is not None:
442
current_most_wanted = next(iter(most_wanted.values()), 0)
443
is_most_wanted = False
444
if x_forwarded_for in most_wanted:
445
if failure_counts.get(x_forwarded_for, 0) > 0:
446
failure_counts[x_forwarded_for] -= 1
447
most_wanted[x_forwarded_for] += 1
448
elif most_wanted[x_forwarded_for] >= current_most_wanted:
449
if x_forwarded_for not in failure_counts:
450
failure_counts[x_forwarded_for] = 0
451
failure_counts[x_forwarded_for] += 1
452
is_most_wanted = True
453
else:
454
most_wanted[x_forwarded_for] += 1
455
else:
456
most_wanted[x_forwarded_for] = 1
457
sorted_most_wanted = dict(sorted(most_wanted.items(), key=lambda item: item[1], reverse=True))
458
debug.log(f"Most wanted IPs: {sorted_most_wanted}")
459
if is_most_wanted:
460
raise RateLimitError("You are most wanted! Please wait before making another request.")
438
461
if provider is not None and provider not in Provider.__map__:
439
462
if provider in model_map:
440
463
config.model = provider