XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 1
返回提交历史

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
hlohaus <983577+hlohaus@users.noreply.github.com>
提交于

代码差异

3 个文件 +30 -75
Modified g4f/Provider/Copilot.py +2 -2
@@ -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)
Modified g4f/Provider/PollinationsAI.py +3 -71
@@ -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
Modified g4f/api/__init__.py +25 -2
@@ -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