返回提交历史
Modified
g4f/Provider/template/OpenaiTemplate.py
+4
-0
Modified
g4f/cli/__init__.py
+9
-6
Modified
g4f/config.py
+3
-1
Modified
g4f/mcp/pa_provider.py
+1
-0
Modified
g4f/providers/any_provider.py
+6
-1
Modified
g4f/providers/base_provider.py
+2
-2
Modified
g4f/providers/retry_provider.py
+1
-1
Modified
requirements-slim.txt
+3
-1
Modified
requirements.txt
+3
-1
Modified
setup.py
+5
-0
XFEstudio/gpt4free
Update requirements
18014298
代码差异
10 个文件
+37
-13
@@ -91,6 +91,10 @@ class OpenaiTemplate(AsyncGeneratorProvider, ProviderModelMixin, RaiseErrorMixin
91
91
base_url = cls.base_url
92
92
if not cls.is_provider_api_key(api_key):
93
93
base_url = cls.backup_url
94
if base_url is None:
95
raise NotImplementedError("No base_url or backup_url specified.")
96
if base_url.startswith("https://g4f.space/") and not api_key:
97
api_key = AppConfig.g4f_space_api_key
94
98
elif cls.models_needs_auth and not api_key:
95
99
raise MissingAuthError("API key is required.")
96
100
response = requests.get(f"{base_url}/models", headers=cls.get_headers(False, api_key), verify=cls.ssl, timeout=timeout)
@@ -339,16 +339,19 @@ def main():
339
339
mode_parser = ArgumentParser(description="Select mode to run g4f in.", exit_on_error=False)
340
340
mode_parser.add_argument("mode", nargs="?", choices=["api", "gui", "client", "mcp", "auth", "dev", "systray", "tray"], default="api", help="Mode to run g4f in (default: api).")
341
341
342
# Preserve original remaining so the API parser gets all args if mode
343
# detection fails (e.g. `python -m g4f --port 8080` without a mode prefix).
344
original_remaining = remaining
345
342
try:
346
343
try:
347
344
args, remaining = mode_parser.parse_known_args(remaining)
348
345
except argparse.ArgumentError:
349
parser = get_api_parser(exit_on_error=False)
350
args = parser.parse_args(remaining)
351
run_api_args(args)
346
try:
347
parser = get_tray_parser(exit_on_error=False)
348
args = parser.parse_args(remaining)
349
run_tray_args(args)
350
except (argparse.ArgumentError, ImportError) as e:
351
print(e)
352
parser = get_api_parser(exit_on_error=False)
353
args = parser.parse_args(remaining)
354
run_api_args(args)
352
355
return
353
356
if args.mode == "auth":
354
357
parser = get_auth_parser()
@@ -52,6 +52,7 @@ class AppConfig:
52
52
timeout: int = DEFAULT_TIMEOUT
53
53
stream_timeout: int = DEFAULT_STREAM_TIMEOUT
54
54
disable_custom_api_key: bool = False
55
g4f_space_api_key: Optional[str] = None
55
56
56
57
@classmethod
57
58
def set_config(cls, **data):
@@ -67,4 +68,5 @@ class AppConfig:
67
68
cls.proxy = os.environ.get("G4F_PROXY", cls.proxy)
68
69
cls.model = os.environ.get("G4F_MODEL", cls.model)
69
70
cls.provider = os.environ.get("G4F_PROVIDER", cls.provider)
70
cls.disable_custom_api_key = os.environ.get("G4F_DISABLE_CUSTOM_API_KEY", str(cls.disable_custom_api_key)).lower() in ("true", "1", "yes")
71
cls.disable_custom_api_key = os.environ.get("G4F_DISABLE_CUSTOM_API_KEY", str(cls.disable_custom_api_key)).lower() in ("true", "1", "yes")
72
cls.g4f_space_api_key = os.environ.get("G4F_SPACE_API_KEY", cls.g4f_space_api_key)
@@ -224,6 +224,7 @@ def _make_restricted_import(allowed: FrozenSet[str]):
224
224
# Block the entire Provider package; only specific safe submodules are
225
225
# explicitly permitted via _ALLOWED_G4F_SUBPATHS below.
226
226
"g4f.Provider",
227
"g4f.config"
227
228
})
228
229
229
230
# Explicit allowlist for g4f sub-paths that would otherwise be blocked.
@@ -8,6 +8,7 @@ from ..errors import ModelNotFoundError
8
8
from ..image import is_data_an_audio
9
9
from ..providers.retry_provider import RotatedProvider
10
10
from ..providers.config_provider import RouterConfig, ConfigModelProvider
11
from ..client.factory import AbstractClientFactory
11
12
from ..Provider import __getattr__
12
13
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
13
14
from .. import Provider
@@ -469,6 +470,8 @@ class AnyProvider(AsyncGeneratorProvider, AnyModelProviderMixin):
469
470
for provider, alias in cls.model_map[model].items():
470
471
try:
471
472
provider_cls = Provider.__map__[provider]
473
if provider_cls.model_aliases is None:
474
provider_cls.model_aliases = {}
472
475
if model not in provider_cls.model_aliases:
473
476
provider_cls.model_aliases[model] = alias
474
477
providers.append(provider_cls)
@@ -501,6 +504,8 @@ class AnyProvider(AsyncGeneratorProvider, AnyModelProviderMixin):
501
504
if not has_api_key:
502
505
providers.sort(key=lambda p: bool(getattr(p, "needs_auth", False)))
503
506
507
providers.append(AbstractClientFactory.create_provider(None, "default"))
508
504
509
if len(providers) == 0:
505
510
raise ModelNotFoundError(
506
511
f"AnyProvider: Model {model} not found in any provider."
@@ -510,7 +515,7 @@ class AnyProvider(AsyncGeneratorProvider, AnyModelProviderMixin):
510
515
f"AnyProvider: Using providers: {[provider.__name__ for provider in providers]} for model '{model}'"
511
516
)
512
517
513
async for chunk in RotatedProvider(providers).create_async_generator(
518
async for chunk in RotatedProvider(providers, False).create_async_generator(
514
519
model, messages, stream=stream, media=media, api_key=api_key, **kwargs
515
520
):
516
521
yield chunk
@@ -268,7 +268,7 @@ class AsyncGeneratorProvider(AbstractProvider):
268
268
class ProviderModelMixin:
269
269
default_model: str = None
270
270
models: list[str] = []
271
model_aliases: dict[str, str] = {}
271
model_aliases: Optional[dict[str, str]] = None
272
272
models_count: dict = {}
273
273
image_models: list = []
274
274
vision_models: list = []
@@ -292,7 +292,7 @@ class ProviderModelMixin:
292
292
def get_model(cls, model: str, **kwargs) -> str:
293
293
if not model and cls.default_model is not None:
294
294
model = cls.default_model
295
if model in cls.model_aliases:
295
if cls.model_aliases is not None and model in cls.model_aliases:
296
296
alias = cls.model_aliases[model]
297
297
if isinstance(alias, list):
298
298
selected_model = random.choice(alias)
@@ -14,7 +14,7 @@ from ..errors import RetryProviderError, RetryNoProviderError
14
14
15
15
def _resolve_model(provider: Type[BaseProvider], model: str) -> str:
16
16
alias = model or getattr(provider, "default_model", None)
17
if hasattr(provider, "model_aliases"):
17
if getattr(provider, "model_aliases"):
18
18
alias = provider.model_aliases.get(model, model)
19
19
if isinstance(alias, list):
20
20
alias = random.choice(alias)
@@ -19,4 +19,6 @@ a2wsgi
19
19
python-dotenv
20
20
ddgs
21
21
cloudscraper
22
PyYAML
22
PyYAML
23
websocket-client
24
pystray
@@ -21,4 +21,6 @@ ddgs
21
21
cloudscraper
22
22
numpy
23
23
PyYAML
24
prompt_optimizer
24
prompt_optimizer
25
websocket-client
26
pystray
@@ -43,6 +43,9 @@ EXTRA_REQUIRE = {
43
43
"wasmtime",
44
44
"numpy",
45
45
"PyYAML",
46
"prompt_optimizer",
47
"websocket-client",
48
"pystray",
46
49
],
47
50
'slim': [
48
51
"curl_cffi>=0.6.2",
@@ -65,6 +68,8 @@ EXTRA_REQUIRE = {
65
68
"aiofile",
66
69
"cloudscraper",
67
70
"PyYAML",
71
"websocket-client",
72
"pystray",
68
73
],
69
74
"image": [
70
75
"pillow",