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

XFEstudio/gpt4free

Fix api_key in HuggingFace provider Split PollinationsAI provider in two provider Update model list in CablyAI Return backup url, if copy images failed Update url for logging in UI

1d00be5b
hlohaus <983577+hlohaus@users.noreply.github.com>
提交于

代码差异

8 个文件 +95 -21
Modified g4f/Provider/CablyAI.py +4 -4
@@ -5,14 +5,14 @@ from .template import OpenaiTemplate
5 5
6 6 class CablyAI(OpenaiTemplate):
7 7 url = "https://cablyai.com"
8 login_url = None
8 login_url = url
9 9 needs_auth = False
10 10 api_base = "https://cablyai.com/v1"
11 11 working = True
12 12
13 default_model = "Cably-80B"
14 models = [default_model]
15 model_aliases = {"cably-80b": default_model}
13 default_model = "o3-mini-low"
14 fallback_models = [default_model, "Cably-80B"]
15 model_aliases = {"cably-80b": "Cably-80B"}
16 16
17 17 @classmethod
18 18 def create_async_generator(
Modified g4f/Provider/PollinationsAI.py +14 -10
@@ -11,6 +11,7 @@ from .helper import filter_none, format_image_prompt
11 11 from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
12 12 from ..typing import AsyncResult, Messages, ImagesType
13 13 from ..image import to_data_uri
14 from ..errors import ModelNotFoundError
14 15 from ..requests.raise_for_status import raise_for_status
15 16 from ..requests.aiohttp import get_connector
16 17 from ..providers.response import ImageResponse, ImagePreview, FinishReason, Usage, Reasoning
@@ -64,20 +65,20 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
64 65 "deepseek-r1": "deepseek-reasoner",
65 66
66 67 ### Image Models ###
67 "sdxl-turbo": "turbo",
68 "sdxl-turbo": "turbo",
69 "flux-schnell": "flux",
68 70 }
69 71 text_models = []
70 72
71 73 @classmethod
72 74 def get_models(cls, **kwargs):
73 if not cls.image_models:
75 if not cls.text_models:
74 76 url = "https://image.pollinations.ai/models"
75 77 response = requests.get(url)
76 78 raise_for_status(response)
77 cls.image_models = response.json()
78 cls.image_models = list(dict.fromkeys([*cls.image_models, *cls.extra_image_models]))
79 new_image_models = response.json()
80 cls.extra_image_models = list(dict.fromkeys([*cls.image_models, *cls.extra_image_models, *new_image_models]))
79 81
80 if not cls.text_models:
81 82 url = "https://text.pollinations.ai/models"
82 83 response = requests.get(url)
83 84 raise_for_status(response)
@@ -87,8 +88,7 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
87 88 if model not in cls.extra_text_models
88 89 ]
89 90 cls.text_models = list(dict.fromkeys(combined_text))
90
91 return list(dict.fromkeys([*cls.text_models, *cls.image_models]))
91 return cls.text_models
92 92
93 93 @classmethod
94 94 async def create_async_generator(
@@ -115,11 +115,15 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
115 115 ) -> AsyncResult:
116 116 if images is not None and not model:
117 117 model = cls.default_vision_model
118 model = cls.get_model(model)
118 try:
119 model = cls.get_model(model)
120 except ModelNotFoundError:
121 if model not in cls.extra_image_models:
122 raise
119 123 if not cache and seed is None:
120 seed = random.randint(0, 100000)
124 seed = random.randint(0, 10000)
121 125
122 if model in cls.image_models:
126 if model in cls.image_models and model not in cls.extra_image_models:
123 127 async for chunk in cls._generate_image(
124 128 model=model,
125 129 prompt=format_image_prompt(messages, prompt),
Added g4f/Provider/PollinationsImage.py +58 -0
@@ -0,0 +1,58 @@
1 from __future__ import annotations
2
3 from typing import Optional
4
5 from .helper import format_image_prompt
6 from ..typing import AsyncResult, Messages
7 from .PollinationsAI import PollinationsAI
8
9 class PollinationsImage(PollinationsAI):
10 # From: https://pollinations.ai/static/js/components/FeedImage/ImageEditor.js
11 image_models = [
12 "flux",
13 "flux-pro",
14 "flux-realism",
15 "flux-anime",
16 "flux-3d",
17 "flux-cablyai",
18 "turbo",
19 ]
20 default_model = "flux"
21 default_vision_model = None
22 default_image_model = default_model
23
24 @classmethod
25 def get_models(cls, **kwargs):
26 if not cls.models:
27 cls.models = list(dict.fromkeys([*cls.image_models, *cls.extra_image_models, *PollinationsAI.extra_image_models]))
28 return cls.models
29
30 @classmethod
31 async def create_async_generator(
32 cls,
33 model: str,
34 messages: Messages,
35 proxy: str = None,
36 prompt: str = None,
37 width: int = 1024,
38 height: int = 1024,
39 seed: Optional[int] = None,
40 nologo: bool = True,
41 private: bool = False,
42 enhance: bool = False,
43 safe: bool = False,
44 **kwargs
45 ) -> AsyncResult:
46 async for chunk in cls._generate_image(
47 model=model,
48 prompt=format_image_prompt(messages, prompt),
49 proxy=proxy,
50 width=width,
51 height=height,
52 seed=seed,
53 nologo=nologo,
54 private=private,
55 enhance=enhance,
56 safe=safe
57 ):
58 yield chunk
Modified g4f/Provider/__init__.py +1 -0
@@ -39,6 +39,7 @@ from .PerplexityLabs import PerplexityLabs
39 39 from .Pi import Pi
40 40 from .Pizzagpt import Pizzagpt
41 41 from .PollinationsAI import PollinationsAI
42 from .PollinationsImage import PollinationsImage
42 43 from .Prodia import Prodia
43 44 from .TeachAnything import TeachAnything
44 45 from .You import You
Modified g4f/Provider/hf/HuggingFaceAPI.py +3 -1
@@ -38,6 +38,7 @@ class HuggingFaceAPI(OpenaiTemplate):
38 38 model: str,
39 39 messages: Messages,
40 40 api_base: str = None,
41 api_key: str = None,
41 42 max_tokens: int = 2048,
42 43 max_inputs_lenght: int = 10000,
43 44 images: ImagesType = None,
@@ -50,6 +51,7 @@ class HuggingFaceAPI(OpenaiTemplate):
50 51 api_base = f"https://api-inference.huggingface.co/models/{model_name}/v1"
51 52 async with StreamSession(
52 53 timeout=30,
54 headers=cls.get_headers(False, api_key),
53 55 ) as session:
54 56 async with session.get(f"https://huggingface.co/api/models/{model}") as response:
55 57 if response.status == 404:
@@ -71,7 +73,7 @@ class HuggingFaceAPI(OpenaiTemplate):
71 73 if len(messages) > 1 and calculate_lenght(messages) > max_inputs_lenght:
72 74 messages = [messages[-1]]
73 75 debug.log(f"Messages trimmed from: {start} to: {calculate_lenght(messages)}")
74 async for chunk in super().create_async_generator(model, messages, api_base=api_base, max_tokens=max_tokens, images=images, **kwargs):
76 async for chunk in super().create_async_generator(model, messages, api_base=api_base, api_key=api_key, max_tokens=max_tokens, images=images, **kwargs):
75 77 yield chunk
76 78
77 79 def calculate_lenght(messages: Messages) -> int:
Modified g4f/gui/client/static/js/chat.v1.js +4 -4
@@ -1959,7 +1959,7 @@ async function on_api() {
1959 1959 messageInput.addEventListener("keydown", async (evt) => {
1960 1960 if (prompt_lock) return;
1961 1961 // If not mobile and not shift enter
1962 let do_enter = messageInput.value.endsWith("\n\n");
1962 let do_enter = messageInput.value.endsWith("\n\n\n\n");
1963 1963 if (do_enter || !window.matchMedia("(pointer:coarse)").matches && evt.keyCode === 13 && !evt.shiftKey) {
1964 1964 evt.preventDefault();
1965 1965 console.log("pressed enter");
@@ -2447,11 +2447,11 @@ async function api(ressource, args=null, files=null, message_id=null, scroll=tru
2447 2447 return;
2448 2448 }
2449 2449 } else if (args) {
2450 if (ressource == "log") {
2451 if (!document.getElementById("report_error").checked) {
2450 if (ressource in ("log", "usage")) {
2451 if (ressource == "log" && !document.getElementById("report_error").checked) {
2452 2452 return;
2453 2453 }
2454 url = `https://roxky-g4f-demo.hf.space${url}`;
2454 url = `https://roxky-g4f-backup.hf.space${url}`;
2455 2455 }
2456 2456 headers['content-type'] = 'application/json';
2457 2457 response = await fetch(url, {
Modified g4f/image/copy_images.py +10 -1
@@ -28,6 +28,15 @@ def get_image_extension(image: str) -> str:
28 28 def ensure_images_dir():
29 29 os.makedirs(images_dir, exist_ok=True)
30 30
31 def get_source_url(image: str, default: str = None) -> str:
32 source_url = image.split("url=", 1)
33 if len(source_url) > 1:
34 source_url = source_url[1]
35 source_url = source_url.replace("%2F", "/").replace("%3A", ":").replace("%3F", "?").replace("%3D", "=")
36 if source_url.startswith("https://"):
37 return source_url
38 return default
39
31 40 async def copy_images(
32 41 images: list[str],
33 42 cookies: Optional[Cookies] = None,
@@ -68,7 +77,7 @@ async def copy_images(
68 77 f.write(chunk)
69 78 except ClientError as e:
70 79 debug.log(f"copy_images failed: {e.__class__.__name__}: {e}")
71 return image
80 return get_source_url(image, image)
72 81 if "." not in target:
73 82 with open(target, "rb") as f:
74 83 extension = is_accepted_format(f.read(12)).split("/")[-1]
Modified g4f/tools/run_tools.py +1 -1
@@ -154,7 +154,7 @@ def iter_run_tools(
154 154 if not isinstance(chunk, str):
155 155 yield chunk
156 156 continue
157 if "<think>" in chunk:
157 if "<think>" in chunk and not "`<think>`" in chunk:
158 158 if chunk != "<think>":
159 159 chunk = chunk.split("<think>", 1)
160 160 if len(chunk) > 0 and chunk[0]: