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

XFEstudio/gpt4free

Add more default providers

52d4154a
hlohaus <hlohaus@users.noreply.github.com>
提交于

代码差异

11 个文件 +54 -49
Modified g4f/Provider/Pollinations.py +1 -0
@@ -43,6 +43,7 @@ class Pollinations(AsyncGeneratorProvider, ProviderModelMixin):
43 43 backup_url = "https://g4f.space/api/pollinations"
44 44 active_by_default = True
45 45 working = True
46 supports_native_tools = True
46 47
47 48 # API endpoints
48 49 text_api_endpoint = "https://text.pollinations.ai/openai"
Modified g4f/Provider/__init__.py +7 -3
@@ -265,9 +265,13 @@ def _resolve_provider(name: str) -> ProviderType:
265 265
266 266 return OpenRouterFree
267 267 elif name == "OrcaRouter":
268 from g4f.Provider.needs_auth.OrcaRouter import OrcaRouter
269
270 return OrcaRouter
268 from ..client.factory import AbstractClientFactory
269 _loaded_providers[name] = AbstractClientFactory.create_provider(
270 None, name.lower()
271 )
272 _loaded_providers[name].__name__ = name
273 _loaded_providers[name].active_by_default = True
274 return _loaded_providers[name]
271 275 elif name == "OpenaiAPI":
272 276 from g4f.Provider.needs_auth.OpenaiAPI import OpenaiAPI
273 277
Deleted g4f/Provider/needs_auth/OrcaRouter.py +0 -22
@@ -1,22 +0,0 @@
1 from __future__ import annotations
2
3 from ..template import OpenaiTemplate
4
5
6 class OrcaRouter(OpenaiTemplate):
7 label = "OrcaRouter"
8 url = "https://www.orcarouter.ai"
9 login_url = "https://www.orcarouter.ai"
10 base_url = "https://api.orcarouter.ai/v1"
11 working = True
12 needs_auth = True
13 default_model = "orcarouter/auto"
14
15 @classmethod
16 def get_headers(
17 cls, stream: bool, api_key: str = None, headers: dict = None
18 ) -> dict:
19 return {
20 **super().get_headers(stream, api_key, headers),
21 **({"Authorization": f"Bearer {api_key}"} if api_key else {}),
22 }
Modified g4f/Provider/needs_auth/__init__.py +0 -1
@@ -33,7 +33,6 @@ from .OpenaiAPI import OpenaiAPI
33 33 from .OpenaiChat import OpenaiChat
34 34 from .OpenRouter import OpenRouter
35 35 from .OpenRouter import OpenRouterFree
36 from .OrcaRouter import OrcaRouter
37 36 from .PerplexityApi import PerplexityApi
38 37 from .Pi import Pi
39 38 from .Puter import Puter
Modified g4f/Provider/template/OpenaiTemplate.py +0 -2
@@ -187,7 +187,6 @@ class OpenaiTemplate(AsyncGeneratorProvider, ProviderModelMixin, RaiseErrorMixin
187 187 model: str,
188 188 messages: Messages,
189 189 proxy: str = None,
190 timeout: int = 120,
191 190 conversation: JsonConversation = None,
192 191 media: MediaListType = None,
193 192 api_key: str = None,
@@ -230,7 +229,6 @@ class OpenaiTemplate(AsyncGeneratorProvider, ProviderModelMixin, RaiseErrorMixin
230 229 async with StreamSession(
231 230 proxy=proxy,
232 231 headers=cls.get_headers(stream, api_key, headers),
233 timeout=timeout,
234 232 impersonate=impersonate,
235 233 ) as session:
236 234 model = cls.get_model(model, api_key=api_key, base_url=base_url)
Modified g4f/api/__init__.py +12 -7
@@ -798,7 +798,7 @@ class Api:
798 798 }
799 799
800 800 @self.app.post("/v1/chat/completions", responses=responses)
801 @self.app.post("/api/{provider:path}/chat/completions", responses=responses)
801 @self.app.post("/{mode}/{provider:path}/chat/completions", responses=responses)
802 802 @self.app.post(
803 803 "/api/{provider}/{conversation_id}/chat/completions", responses=responses
804 804 )
@@ -807,10 +807,15 @@ class Api:
807 807 credentials: Annotated[
808 808 HTTPAuthorizationCredentials, Depends(Api.security)
809 809 ] = None,
810 provider: str = None,
811 conversation_id: str = None,
812 x_user: Annotated[str | None, Header()] = None,
810 mode: str | None = None,
811 provider: str | None = None,
812 conversation_id: str | None = None,
813 x_user: Annotated[str | None, Header()] | None = None,
813 814 ):
815 if mode == "raw":
816 config.raw = True
817 elif mode == "custom":
818 provider = f"{mode}:{provider}"
814 819 if provider is not None:
815 820 config.provider = provider
816 821 if config.provider is None:
@@ -972,9 +977,9 @@ class Api:
972 977 config: ResponsesConfig,
973 978 credentials: Annotated[
974 979 HTTPAuthorizationCredentials, Depends(Api.security)
975 ] = None,
976 provider: str = None,
977 x_user: Annotated[str | None, Header()] = None,
980 ] | None = None,
981 provider: str | None = None,
982 x_user: Annotated[str | None, Header(alias="X-User")] | None = None,
978 983 ):
979 984 if provider is not None:
980 985 config.provider = provider
Modified g4f/mcp/pa_provider.py +6 -6
@@ -318,10 +318,12 @@ def _load_workspace_module(
318 318 # Skip .pa.py files — those are providers, not importable modules
319 319 if not candidate.name.endswith(".pa.py"):
320 320 source_path = candidate
321 pkg_init = candidate.parent / "__init__.py"
321 322 break
322 323 if source_path is None:
323 324 for candidate in workspace.rglob(f"{name}/__init__.py"):
324 325 source_path = candidate
326 pkg_init = candidate
325 327 break
326 328
327 329 if source_path is None:
@@ -530,12 +532,10 @@ def _make_safe_globals(
530 532 """open() restricted to the workspace directory."""
531 533 path = Path(file)
532 534 if not path.is_absolute():
533 parent = file_path.parent if file_path else workspace
534 while parent != parent.parent:
535 path = parent / path.name
536 if path.exists():
537 break
538 parent = parent.parent
535 if file_path is None:
536 path = workspace / path
537 else:
538 path = file_path.parent / path.name
539 539 try:
540 540 resolved = path.resolve()
541 541 ws_resolved = workspace.resolve()
Modified g4f/models.py +3 -1
@@ -127,9 +127,11 @@ default = Model(
127 127 "GLM",
128 128 "Pollinations",
129 129 "Qwen",
130 "Together",
131 130 "TeachAnything",
132 131 "OpenaiChat",
132 "OrcaRouter",
133 "OpenCode",
134 "KiloCode",
133 135 ]
134 136 ),
135 137 )
Modified g4f/providers/any_provider.py +3 -3
@@ -82,7 +82,7 @@ LABELS = {
82 82 class AnyModelProviderMixin(ProviderModelMixin):
83 83 """Mixin to provide model-related methods for providers."""
84 84
85 default_model = "default"
85 default_model = "auto"
86 86 audio_models = audio_models
87 87 image_models = image_models
88 88 vision_models = vision_models
@@ -302,7 +302,7 @@ class AnyModelProviderMixin(ProviderModelMixin):
302 302 groups = {key: [] for key in LABELS.keys()}
303 303
304 304 # Always add default first
305 groups["default"].append("default")
305 groups["default"].append("auto")
306 306
307 307 groups["custom"] = list(RouterConfig.routes.keys())
308 308
@@ -408,7 +408,7 @@ class AnyProvider(AsyncGeneratorProvider, AnyModelProviderMixin):
408 408 **kwargs,
409 409 ) -> AsyncResult:
410 410 providers = []
411 if not model or model == cls.default_model:
411 if not model or model == cls.default_model or model == "default":
412 412 model = ""
413 413 has_image = False
414 414 has_audio = False
Modified g4f/providers/base_provider.py +18 -3
@@ -107,8 +107,15 @@ async def wait_for(response: AsyncIterator, timeout: int = None) -> AsyncIterato
107 107 if timeout is not None:
108 108 while True:
109 109 try:
110 yield await asyncio.wait_for(response.__anext__(), timeout=timeout)
110 async def wait_for_next():
111 try:
112 return await response.__anext__()
113 except TimeoutError as e:
114 raise TimeoutError(str(e) or "The operation timed out") from e
115 yield await asyncio.wait_for(wait_for_next(), timeout=timeout)
111 116 except TimeoutError as e:
117 if str(e):
118 raise TimeoutError(str(e)) from e
112 119 raise TimeoutError(
113 120 "The operation timed out after {} seconds".format(timeout)
114 121 ) from e
@@ -365,8 +372,8 @@ class ProviderModelMixin:
365 372
366 373 @classmethod
367 374 def get_model(cls, model: str, **kwargs) -> str:
368 if not model and cls.default_model is not None:
369 model = cls.default_model
375 if (not model or model == "auto") and cls.default_model is not None:
376 return cls.default_model
370 377 if cls.model_aliases is not None and model in cls.model_aliases:
371 378 alias = cls.model_aliases[model]
372 379 if isinstance(alias, list):
@@ -377,6 +384,14 @@ class ProviderModelMixin:
377 384 return selected_model
378 385 debug.log(f"{cls.__name__}: Using model '{alias}' for alias '{model}'")
379 386 return alias
387 for m in cls.get_models(**kwargs):
388 if not model or model == "auto":
389 if m == "auto" or m.endswith("/free"):
390 cls.default_model = m
391 return m
392 elif m.lower().endswith(model.lower()):
393 debug.log(f"{cls.__name__}: Using model '{m}'")
394 return m
380 395 return model
381 396
382 397
Modified g4f/providers/response.py +4 -1
@@ -3,6 +3,7 @@ from __future__ import annotations
3 3 import re
4 4 import base64
5 5 import html
6 import json
6 7 from typing import Union, Dict, List, Optional
7 8 from abc import abstractmethod
8 9 from urllib.parse import quote, unquote
@@ -208,7 +209,9 @@ class ObjectMixin:
208 209 class JsonResponse(ResponseType, ObjectMixin):
209 210 def __str__(self) -> str:
210 211 return str(self.get_dict())
211
212 def model_dump_json(self, *args, **kwargs) -> str:
213 """Return a JSON string representation of the object."""
214 return json.dumps(self.get_dict())
212 215
213 216 class HiddenResponse(ResponseType):
214 217 def __str__(self) -> str: