返回提交历史
Modified
g4f/Provider/GLM.py
+1
-1
Modified
g4f/Provider/LambdaChat.py
+1
-2
Modified
g4f/Provider/PollinationsAI.py
+3
-3
Modified
g4f/Provider/PollinationsImage.py
+2
-2
Modified
g4f/Provider/needs_auth/GeminiCLI.py
+32
-9
Modified
g4f/Provider/needs_auth/GeminiPro.py
+1
-3
Modified
g4f/Provider/needs_auth/LMArena.py
+6
-0
Modified
g4f/Provider/needs_auth/hf/HuggingChat.py
+1
-0
Modified
g4f/config.py
+2
-1
Modified
g4f/gui/server/api.py
+2
-0
Modified
g4f/providers/response.py
+9
-0
XFEstudio/gpt4free
Update provider configurations to set 'working' status to False; refactor tool handling in GeminiCLI and enhance response structure in Usage class
aa0aade9
代码差异
11 个文件
+60
-21
@@ -18,7 +18,7 @@ from .base_provider import AsyncGeneratorProvider, ProviderModelMixin, AuthFileM
18
18
class GLM(AsyncGeneratorProvider, ProviderModelMixin, AuthFileMixin):
19
19
url = "https://chat.z.ai"
20
20
api_endpoint = "https://chat.z.ai/api/chat/completions"
21
working = True
21
working = False
22
22
active_by_default = True
23
23
default_model = "GLM-4.5"
24
24
@@ -11,7 +11,6 @@ from ..requests import raise_for_status
11
11
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
12
12
from .helper import get_last_user_message
13
13
from ..providers.response import TitleGeneration, Reasoning, FinishReason
14
from ..errors import ModelNotFoundError
15
14
from .. import debug
16
15
17
16
@@ -20,7 +19,7 @@ class LambdaChat(AsyncGeneratorProvider, ProviderModelMixin):
20
19
url = "https://lambda.chat"
21
20
conversation_url = f"{url}/conversation"
22
21
23
working = True
22
working = False
24
23
active_by_default = True
25
24
26
25
default_model = "deepseek-llama3.3-70b"
@@ -18,7 +18,7 @@ from ..requests.aiohttp import get_connector
18
18
from ..image import use_aspect_ratio
19
19
from ..providers.response import ImageResponse, Reasoning, TitleGeneration, SuggestedFollowups, JsonRequest
20
20
from ..tools.media import render_messages
21
from ..config import STATIC_URL
21
from ..config import REFFERER_URL
22
22
from .template.OpenaiTemplate import read_response
23
23
from .. import debug
24
24
@@ -168,7 +168,7 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
168
168
stream: bool = True,
169
169
proxy: str = None,
170
170
cache: bool = None,
171
referrer: str = STATIC_URL,
171
referrer: str = REFFERER_URL,
172
172
api_key: str = None,
173
173
extra_body: dict = None,
174
174
# Image generation parameters
@@ -422,7 +422,7 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
422
422
frequency_penalty=frequency_penalty,
423
423
response_format=response_format,
424
424
stream=stream,
425
seed=None if model == "grok" else seed,
425
seed=None if "tools" in extra_body else seed,
426
426
referrer=referrer,
427
427
**extra_body
428
428
)
@@ -4,7 +4,7 @@ from typing import Optional
4
4
5
5
from .helper import format_media_prompt
6
6
from ..typing import AsyncResult, Messages, MediaListType
7
from ..config import STATIC_URL
7
from ..config import REFFERER_URL
8
8
from .PollinationsAI import PollinationsAI
9
9
10
10
class PollinationsImage(PollinationsAI):
@@ -37,7 +37,7 @@ class PollinationsImage(PollinationsAI):
37
37
messages: Messages,
38
38
media: MediaListType = None,
39
39
proxy: str = None,
40
referrer: str = STATIC_URL,
40
referrer: str = REFFERER_URL,
41
41
api_key: str = None,
42
42
prompt: str = None,
43
43
aspect_ratio: str = None,
@@ -353,6 +353,21 @@ class GeminiCLIProvider():
353
353
if system_prompt:
354
354
requestData["system_instruction"] = {"parts": {"text": system_prompt}}
355
355
356
# Convert OpenAI-style tools to Gemini format
357
gemini_tools = None
358
if tools:
359
function_declarations = []
360
for tool in tools:
361
if tool.get("type") == "function" and "function" in tool:
362
func = tool["function"]
363
function_declarations.append({
364
"name": func.get("name"),
365
"description": func.get("description", ""),
366
"parameters": func.get("parameters", {})
367
})
368
if function_declarations:
369
gemini_tools = [{"functionDeclarations": function_declarations}]
370
356
371
# Compose request body
357
372
req_body = {
358
373
"model": model,
@@ -373,13 +388,13 @@ class GeminiCLIProvider():
373
388
"includeThoughts": True
374
389
} if thinking_budget else None,
375
390
},
376
"tools": tools or [],
391
"tools": gemini_tools,
377
392
"toolConfig": {
378
393
"functionCallingConfig": {
379
394
"mode": tool_choice.upper(),
380
"allowedFunctionNames": [tool["function"]["name"] for tool in tools]
395
"allowedFunctionNames": [fd["name"] for fd in function_declarations]
381
396
}
382
} if tool_choice else None,
397
} if tool_choice and gemini_tools else None,
383
398
**requestData
384
399
},
385
400
}
@@ -485,12 +500,20 @@ class GeminiCLIProvider():
485
500
yield ImageResponse(file_data.get("fileUri"))
486
501
487
502
if tool_calls:
488
yield ToolCalls(tool_calls)
489
if usage_metadata:
490
yield Usage(
491
promptTokens=usage_metadata.get("promptTokenCount", 0),
492
completionTokens=usage_metadata.get("candidatesTokenCount", 0),
493
)
503
# Convert Gemini tool calls to OpenAI format
504
openai_tool_calls = []
505
for i, tc in enumerate(tool_calls):
506
openai_tool_calls.append({
507
"id": f"call_{i}_{tc.get('name', 'unknown')}",
508
"type": "function",
509
"function": {
510
"name": tc.get("name"),
511
"arguments": json.dumps(tc.get("args", {}))
512
}
513
})
514
yield ToolCalls(openai_tool_calls)
515
if usage_metadata:
516
yield Usage(**usage_metadata)
494
517
495
518
class GeminiCLI(AsyncGeneratorProvider, ProviderModelMixin):
496
519
label = "Google Gemini CLI"
@@ -31,10 +31,8 @@ class GeminiPro(AsyncGeneratorProvider, ProviderModelMixin):
31
31
default_model = "gemini-2.5-flash"
32
32
default_vision_model = default_model
33
33
fallback_models = [
34
"gemini-2.0-flash",
35
"gemini-2.0-flash-lite",
36
"gemini-2.0-flash-thinking-exp",
37
34
"gemini-2.5-flash",
35
"gemini-2.5-flash-lite",
38
36
"gemma-3-1b-it",
39
37
"gemma-3-12b-it",
40
38
"gemma-3-27b-it",
@@ -598,6 +598,12 @@ class LMArena(AsyncGeneratorProvider, ProviderModelMixin, AuthFileMixin):
598
598
button = await page.select('[type="submit"]:has([data-sentry-element="ArrowUp"])')
599
599
if button:
600
600
await button.click()
601
button = await page.find("Agree")
602
if button:
603
await button.click()
604
else:
605
debug.log("No 'Agree' button found, skipping.")
606
await asyncio.sleep(1)
601
607
element = await page.select('[style="display: grid;"]')
602
608
if element:
603
609
await click_trunstile(page, 'document.querySelector(\'[style="display: grid;"]\')')
@@ -36,6 +36,7 @@ class HuggingChat(AsyncAuthedProvider, ProviderModelMixin):
36
36
url = f"{origin}/chat"
37
37
38
38
working = True
39
active_by_default = True
39
40
use_nodriver = True
40
41
supports_stream = True
41
42
needs_auth = True
@@ -25,7 +25,8 @@ CUSTOM_COOKIES_DIR = "./har_and_cookies"
25
25
ORGANIZATION = "gpt4free"
26
26
GITHUB_REPOSITORY = f"xtekky/{ORGANIZATION}"
27
27
STATIC_DOMAIN = f"{PACKAGE_NAME}.dev"
28
STATIC_URL = f"https://static.{STATIC_DOMAIN}/"
28
STATIC_URL = f"https://{ORGANIZATION}.github.io/"
29
REFFERER_URL = f"https://{STATIC_DOMAIN}/"
29
30
DIST_DIR = f"./{STATIC_DOMAIN}/dist"
30
31
DEFAULT_MODEL = "openai/gpt-oss-120b"
31
32
JSDELIVR_URL = "https://cdn.jsdelivr.net/"
@@ -275,6 +275,8 @@ class Api:
275
275
yield self._format_json("log", chunk.log)
276
276
elif isinstance(chunk, ContinueResponse):
277
277
yield self._format_json("continue", chunk.log)
278
elif isinstance(chunk, ToolCalls):
279
yield self._format_json("tool_calls", chunk.list)
278
280
elif isinstance(chunk, RawResponse):
279
281
yield self._format_json(chunk.type, **chunk.get_dict())
280
282
elif isinstance(chunk, JsonRequest):
@@ -204,6 +204,9 @@ class Usage(JsonMixin, HiddenResponse):
204
204
input_tokens: int = None,
205
205
output_tokens: int = None,
206
206
output_tokens_details: Dict = None,
207
promptTokenCount: int = None,
208
candidatesTokenCount: int = None,
209
totalTokenCount: int = None,
207
210
**kwargs
208
211
):
209
212
if promptTokens is not None:
@@ -214,6 +217,12 @@ class Usage(JsonMixin, HiddenResponse):
214
217
kwargs["prompt_tokens"] = input_tokens
215
218
if output_tokens is not None:
216
219
kwargs["completion_tokens"] = output_tokens
220
if promptTokenCount is not None:
221
kwargs["prompt_tokens"] = promptTokenCount
222
if candidatesTokenCount is not None:
223
kwargs["completion_tokens"] = candidatesTokenCount
224
if totalTokenCount is not None:
225
kwargs["total_tokens"] = totalTokenCount
217
226
if output_tokens_details is not None:
218
227
for key, value in output_tokens_details.items():
219
228
kwargs[key] = value