返回提交历史
Modified
g4f/Provider/Blackbox2.py
+1
-0
Modified
g4f/Provider/Copilot.py
+5
-4
Modified
g4f/Provider/DarkAI.py
+17
-29
Modified
g4f/Provider/needs_auth/Cerebras.py
+4
-19
Modified
g4f/Provider/needs_auth/Groq.py
+4
-3
Modified
g4f/Provider/needs_auth/HuggingFace.py
+24
-12
Modified
g4f/Provider/needs_auth/HuggingFaceAPI.py
+2
-1
Modified
g4f/Provider/needs_auth/OpenaiAPI.py
+28
-4
Modified
g4f/Provider/needs_auth/__init__.py
+1
-0
Added
g4f/Provider/needs_auth/xAI.py
+22
-0
Modified
g4f/__init__.py
+6
-9
Modified
g4f/api/__init__.py
+6
-7
Modified
g4f/client/service.py
+2
-5
Modified
g4f/cookies.py
+15
-13
Modified
g4f/gui/client/index.html
+5
-1
Modified
g4f/providers/retry_provider.py
+15
-14
XFEstudio/gpt4free
Improved ignored providers support, Add get_models to OpenaiAPI, HuggingFace and Groq Add xAI provider
ff66df14
代码差异
16 个文件
+157
-121
@@ -34,6 +34,7 @@ class Blackbox2(AsyncGeneratorProvider, ProviderModelMixin):
34
34
model: str,
35
35
messages: Messages,
36
36
proxy: str = None,
37
prompt: str = None,
37
38
max_retries: int = 3,
38
39
delay: int = 1,
39
40
**kwargs
@@ -123,11 +123,12 @@ class Copilot(AbstractProvider, ProviderModelMixin):
123
123
prompt = format_prompt(messages)
124
124
if len(prompt) > 10000:
125
125
if len(messages) > 6:
126
prompt = format_prompt(messages[:3]+messages[-3:])
127
elif len(messages) > 2:
128
prompt = format_prompt(messages[:2]+messages[-1:])
126
prompt = format_prompt(messages[:3] + messages[-3:])
129
127
if len(prompt) > 10000:
130
prompt = messages[-1]["content"]
128
if len(messages) > 2:
129
prompt = format_prompt(messages[:2] + messages[-1:])
130
if len(prompt) > 10000:
131
prompt = messages[-1]["content"]
131
132
debug.log(f"Copilot: Trim messages to: {len(prompt)}")
132
133
debug.log(f"Copilot: Created conversation: {conversation_id}")
133
134
else:
@@ -4,38 +4,26 @@ import json
4
4
from aiohttp import ClientSession
5
5
6
6
from ..typing import AsyncResult, Messages
7
from ..requests.raise_for_status import raise_for_status
7
8
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
8
9
from .helper import format_prompt
9
10
10
11
11
class DarkAI(AsyncGeneratorProvider, ProviderModelMixin):
12
12
url = "https://darkai.foundation/chat"
13
13
api_endpoint = "https://darkai.foundation/chat"
14
14
working = True
15
15
supports_stream = True
16
supports_system_message = True
17
supports_message_history = True
18
16
19
17
default_model = 'llama-3-70b'
20
18
models = [
21
19
'gpt-4o', # Uncensored
22
20
'gpt-3.5-turbo', # Uncensored
23
21
default_model,
24
22
]
25
26
23
model_aliases = {
27
24
"llama-3.1-70b": "llama-3-70b",
28
25
}
29
26
30
@classmethod
31
def get_model(cls, model: str) -> str:
32
if model in cls.models:
33
return model
34
elif model in cls.model_aliases:
35
return cls.model_aliases[model]
36
else:
37
return cls.default_model
38
39
27
@classmethod
40
28
async def create_async_generator(
41
29
cls,
@@ -45,7 +33,7 @@ class DarkAI(AsyncGeneratorProvider, ProviderModelMixin):
45
33
**kwargs
46
34
) -> AsyncResult:
47
35
model = cls.get_model(model)
48
36
49
37
headers = {
50
38
"accept": "text/event-stream",
51
39
"content-type": "application/json",
@@ -58,24 +46,24 @@ class DarkAI(AsyncGeneratorProvider, ProviderModelMixin):
58
46
"model": model,
59
47
}
60
48
async with session.post(cls.api_endpoint, json=data, proxy=proxy) as response:
61
response.raise_for_status()
62
full_text = ""
63
async for chunk in response.content:
64
if chunk:
49
await raise_for_status(response)
50
first = True
51
async for line in response.content:
52
if line:
65
53
try:
66
chunk_str = chunk.decode().strip()
67
if chunk_str.startswith('data: '):
68
chunk_data = json.loads(chunk_str[6:])
54
line_str = line.decode().strip()
55
if line_str.startswith('data: '):
56
chunk_data = json.loads(line_str[6:])
69
57
if chunk_data['event'] == 'text-chunk':
70
full_text += chunk_data['data']['text']
58
chunk = chunk_data['data']['text']
59
if first:
60
chunk = chunk.lstrip()
61
if chunk:
62
first = False
63
yield chunk
71
64
elif chunk_data['event'] == 'stream-end':
72
if full_text:
73
yield full_text.strip()
74
65
return
75
66
except json.JSONDecodeError:
76
67
pass
77
68
except Exception:
78
pass
79
80
if full_text:
81
yield full_text.strip()
69
pass
@@ -1,6 +1,5 @@
1
1
from __future__ import annotations
2
2
3
import requests
4
3
from aiohttp import ClientSession
5
4
6
5
from .OpenaiAPI import OpenaiAPI
@@ -11,35 +10,21 @@ from ...cookies import get_cookies
11
10
class Cerebras(OpenaiAPI):
12
11
label = "Cerebras Inference"
13
12
url = "https://inference.cerebras.ai/"
13
api_base = "https://api.cerebras.ai/v1"
14
14
working = True
15
15
default_model = "llama3.1-70b"
16
fallback_models = [
16
models = [
17
17
"llama3.1-70b",
18
18
"llama3.1-8b",
19
19
]
20
20
model_aliases = {"llama-3.1-70b": "llama3.1-70b", "llama-3.1-8b": "llama3.1-8b"}
21
21
22
@classmethod
23
def get_models(cls, api_key: str = None):
24
if not cls.models:
25
try:
26
headers = {}
27
if api_key:
28
headers["authorization"] = f"Bearer ${api_key}"
29
response = requests.get(f"https://api.cerebras.ai/v1/models", headers=headers)
30
raise_for_status(response)
31
data = response.json()
32
cls.models = [model.get("model") for model in data.get("models")]
33
except Exception:
34
cls.models = cls.fallback_models
35
return cls.models
36
37
22
@classmethod
38
23
async def create_async_generator(
39
24
cls,
40
25
model: str,
41
26
messages: Messages,
42
api_base: str = "https://api.cerebras.ai/v1",
27
api_base: str = api_base,
43
28
api_key: str = None,
44
29
cookies: Cookies = None,
45
30
**kwargs
@@ -62,4 +47,4 @@ class Cerebras(OpenaiAPI):
62
47
},
63
48
**kwargs
64
49
):
65
yield chunk
50
yield chunk
@@ -6,9 +6,10 @@ from ...typing import AsyncResult, Messages
6
6
class Groq(OpenaiAPI):
7
7
label = "Groq"
8
8
url = "https://console.groq.com/playground"
9
api_base = "https://api.groq.com/openai/v1"
9
10
working = True
10
11
default_model = "mixtral-8x7b-32768"
11
models = [
12
fallback_models = [
12
13
"distil-whisper-large-v3-en",
13
14
"gemma2-9b-it",
14
15
"gemma-7b-it",
@@ -35,9 +36,9 @@ class Groq(OpenaiAPI):
35
36
cls,
36
37
model: str,
37
38
messages: Messages,
38
api_base: str = "https://api.groq.com/openai/v1",
39
api_base: str = api_base,
39
40
**kwargs
40
41
) -> AsyncResult:
41
42
return super().create_async_generator(
42
43
model, messages, api_base=api_base, **kwargs
43
)
44
)
@@ -6,8 +6,8 @@ import random
6
6
import requests
7
7
8
8
from ...typing import AsyncResult, Messages
9
from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin
10
from ...errors import ModelNotFoundError, ModelNotSupportedError
9
from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin, format_prompt
10
from ...errors import ModelNotFoundError, ModelNotSupportedError, ResponseError
11
11
from ...requests import StreamSession, raise_for_status
12
12
from ...image import ImageResponse
13
13
@@ -28,9 +28,11 @@ class HuggingFace(AsyncGeneratorProvider, ProviderModelMixin):
28
28
cls.models = [model["id"] for model in requests.get(url).json()]
29
29
cls.models.append("meta-llama/Llama-3.2-11B-Vision-Instruct")
30
30
cls.models.append("nvidia/Llama-3.1-Nemotron-70B-Instruct-HF")
31
cls.models.sort()
31
32
if not cls.image_models:
32
33
url = "https://huggingface.co/api/models?pipeline_tag=text-to-image"
33
34
cls.image_models = [model["id"] for model in requests.get(url).json() if model["trendingScore"] >= 20]
35
cls.image_models.sort()
34
36
cls.models.extend(cls.image_models)
35
37
return cls.models
36
38
@@ -89,19 +91,27 @@ class HuggingFace(AsyncGeneratorProvider, ProviderModelMixin):
89
91
) as session:
90
92
if payload is None:
91
93
async with session.get(f"https://huggingface.co/api/models/{model}") as response:
94
await raise_for_status(response)
92
95
model_data = await response.json()
93
if "config" in model_data and "tokenizer_config" in model_data["config"] and "eos_token" in model_data["config"]["tokenizer_config"]:
96
model_type = None
97
if "config" in model_data and "model_type" in model_data["config"]:
98
model_type = model_data["config"]["model_type"]
99
if model_type in ("gpt2", "gpt_neo", "gemma", "gemma2"):
100
inputs = format_prompt(messages)
101
elif "config" in model_data and "tokenizer_config" in model_data["config"] and "eos_token" in model_data["config"]["tokenizer_config"]:
94
102
eos_token = model_data["config"]["tokenizer_config"]["eos_token"]
95
if eos_token == "</s>":
96
inputs = format_prompt_mistral(messages)
103
if eos_token in ("<|endoftext|>", "<eos>", "</s>"):
104
inputs = format_prompt_custom(messages, eos_token)
97
105
elif eos_token == "<|im_end|>":
98
106
inputs = format_prompt_qwen(messages)
99
107
elif eos_token == "<|eot_id|>":
100
108
inputs = format_prompt_llama(messages)
101
109
else:
102
inputs = format_prompt(messages)
110
inputs = format_prompt_default(messages)
103
111
else:
104
inputs = format_prompt(messages)
112
inputs = format_prompt_default(messages)
113
if model_type == "gpt2" and max_new_tokens >= 1024:
114
params["max_new_tokens"] = 512
105
115
payload = {"inputs": inputs, "parameters": params, "stream": stream}
106
116
107
117
async with session.post(f"{api_base.rstrip('/')}/models/{model}", json=payload) as response:
@@ -113,6 +123,8 @@ class HuggingFace(AsyncGeneratorProvider, ProviderModelMixin):
113
123
async for line in response.iter_lines():
114
124
if line.startswith(b"data:"):
115
125
data = json.loads(line[5:])
126
if "error" in data:
127
raise ResponseError(data["error"])
116
128
if not data["token"]["special"]:
117
129
chunk = data["token"]["text"]
118
130
if first:
@@ -128,7 +140,7 @@ class HuggingFace(AsyncGeneratorProvider, ProviderModelMixin):
128
140
else:
129
141
yield (await response.json())[0]["generated_text"].strip()
130
142
131
def format_prompt(messages: Messages) -> str:
143
def format_prompt_default(messages: Messages) -> str:
132
144
system_messages = [message["content"] for message in messages if message["role"] == "system"]
133
145
question = " ".join([messages[-1]["content"], *system_messages])
134
146
history = "".join([
@@ -146,9 +158,9 @@ def format_prompt_qwen(messages: Messages) -> str:
146
158
def format_prompt_llama(messages: Messages) -> str:
147
159
return "<|begin_of_text|>" + "".join([
148
160
f"<|start_header_id|>{message['role']}<|end_header_id|>\n\n{message['content']}\n<|eot_id|>\n" for message in messages
149
]) + "<|start_header_id|>assistant<|end_header_id|>\\n\\n"
150
151
def format_prompt_mistral(messages: Messages) -> str:
161
]) + "<|start_header_id|>assistant<|end_header_id|>\n\n"
162
163
def format_prompt_custom(messages: Messages, end_token: str = "</s>") -> str:
152
164
return "".join([
153
f"<|{message['role']}|>\n{message['content']}'</s>\n" for message in messages
165
f"<|{message['role']}|>\n{message['content']}{end_token}\n" for message in messages
154
166
]) + "<|assistant|>\n"
@@ -7,6 +7,7 @@ from ...typing import AsyncResult, Messages
7
7
class HuggingFaceAPI(OpenaiAPI):
8
8
label = "HuggingFace (Inference API)"
9
9
url = "https://api-inference.huggingface.co"
10
api_base = "https://api-inference.huggingface.co/v1"
10
11
working = True
11
12
default_model = "meta-llama/Llama-3.2-11B-Vision-Instruct"
12
13
default_vision_model = default_model
@@ -19,7 +20,7 @@ class HuggingFaceAPI(OpenaiAPI):
19
20
cls,
20
21
model: str,
21
22
messages: Messages,
22
api_base: str = "https://api-inference.huggingface.co/v1",
23
api_base: str = api_base,
23
24
max_tokens: int = 500,
24
25
**kwargs
25
26
) -> AsyncResult:
@@ -1,6 +1,7 @@
1
1
from __future__ import annotations
2
2
3
3
import json
4
import requests
4
5
5
6
from ..helper import filter_none
6
7
from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin, FinishReason
@@ -8,15 +9,35 @@ from ...typing import Union, Optional, AsyncResult, Messages, ImagesType
8
9
from ...requests import StreamSession, raise_for_status
9
10
from ...errors import MissingAuthError, ResponseError
10
11
from ...image import to_data_uri
12
from ... import debug
11
13
12
14
class OpenaiAPI(AsyncGeneratorProvider, ProviderModelMixin):
13
15
label = "OpenAI API"
14
16
url = "https://platform.openai.com"
17
api_base = "https://api.openai.com/v1"
15
18
working = True
16
19
needs_auth = True
17
20
supports_message_history = True
18
21
supports_system_message = True
19
22
default_model = ""
23
fallback_models = []
24
25
@classmethod
26
def get_models(cls, api_key: str = None):
27
if not cls.models:
28
try:
29
headers = {}
30
if api_key is not None:
31
headers["authorization"] = f"Bearer {api_key}"
32
response = requests.get(f"{cls.api_base}/models", headers=headers)
33
raise_for_status(response)
34
data = response.json()
35
cls.models = [model.get("id") for model in data.get("data")]
36
cls.models.sort()
37
except Exception as e:
38
debug.log(e)
39
cls.models = cls.fallback_models
40
return cls.models
20
41
21
42
@classmethod
22
43
async def create_async_generator(
@@ -27,7 +48,7 @@ class OpenaiAPI(AsyncGeneratorProvider, ProviderModelMixin):
27
48
timeout: int = 120,
28
49
images: ImagesType = None,
29
50
api_key: str = None,
30
api_base: str = "https://api.openai.com/v1",
51
api_base: str = api_base,
31
52
temperature: float = None,
32
53
max_tokens: int = None,
33
54
top_p: float = None,
@@ -47,14 +68,14 @@ class OpenaiAPI(AsyncGeneratorProvider, ProviderModelMixin):
47
68
*[{
48
69
"type": "image_url",
49
70
"image_url": {"url": to_data_uri(image)}
50
} for image, image_name in images],
71
} for image, _ in images],
51
72
{
52
73
"type": "text",
53
74
"text": messages[-1]["content"]
54
75
}
55
76
]
56
77
async with StreamSession(
57
proxies={"all": proxy},
78
proxy=proxy,
58
79
headers=cls.get_headers(stream, api_key, headers),
59
80
timeout=timeout,
60
81
impersonate=impersonate,
@@ -111,7 +132,10 @@ class OpenaiAPI(AsyncGeneratorProvider, ProviderModelMixin):
111
132
if "error_message" in data:
112
133
raise ResponseError(data["error_message"])
113
134
elif "error" in data:
114
raise ResponseError(f'Error {data["error"]["code"]}: {data["error"]["message"]}')
135
if "code" in data["error"]:
136
raise ResponseError(f'Error {data["error"]["code"]}: {data["error"]["message"]}')
137
else:
138
raise ResponseError(data["error"]["message"])
115
139
116
140
@classmethod
117
141
def get_headers(cls, stream: bool, api_key: str = None, headers: dict = None) -> dict:
@@ -26,3 +26,4 @@ from .Replicate import Replicate
26
26
from .Theb import Theb
27
27
from .ThebApi import ThebApi
28
28
from .WhiteRabbitNeo import WhiteRabbitNeo
29
from .xAI import xAI
@@ -0,0 +1,22 @@
1
from __future__ import annotations
2
3
from .OpenaiAPI import OpenaiAPI
4
from ...typing import AsyncResult, Messages
5
6
class xAI(OpenaiAPI):
7
label = "xAI"
8
url = "https://console.x.ai"
9
api_base = "https://api.x.ai/v1"
10
working = True
11
12
@classmethod
13
def create_async_generator(
14
cls,
15
model: str,
16
messages: Messages,
17
api_base: str = api_base,
18
**kwargs
19
) -> AsyncResult:
20
return super().create_async_generator(
21
model, messages, api_base=api_base, **kwargs
22
)
@@ -2,16 +2,15 @@ from __future__ import annotations
2
2
3
3
import os
4
4
import logging
5
from typing import Union, Optional
5
from typing import Union, Optional, Coroutine
6
6
7
7
from . import debug, version
8
8
from .models import Model
9
9
from .client import Client, AsyncClient
10
10
from .typing import Messages, CreateResult, AsyncResult, ImageType
11
from .errors import StreamNotSupportedError, ModelNotAllowedError
11
from .errors import StreamNotSupportedError
12
12
from .cookies import get_cookies, set_cookies
13
13
from .providers.types import ProviderType
14
from .providers.base_provider import AsyncGeneratorProvider
15
14
from .client.service import get_model_and_provider, get_last_provider
16
15
17
16
#Configure "g4f" logger
@@ -30,14 +29,13 @@ class ChatCompletion:
30
29
stream : bool = False,
31
30
image : ImageType = None,
32
31
image_name: Optional[str] = None,
33
ignored: list[str] = None,
34
32
ignore_working: bool = False,
35
33
ignore_stream: bool = False,
36
34
**kwargs) -> Union[CreateResult, str]:
37
35
model, provider = get_model_and_provider(
38
36
model, provider, stream,
39
ignored, ignore_working,
40
ignore_stream or kwargs.get("ignore_stream_and_auth")
37
ignore_working,
38
ignore_stream
41
39
)
42
40
if image is not None:
43
41
kwargs["images"] = [(image, image_name)]
@@ -55,10 +53,9 @@ class ChatCompletion:
55
53
messages : Messages,
56
54
provider : Union[ProviderType, str, None] = None,
57
55
stream : bool = False,
58
ignored : list[str] = None,
59
56
ignore_working: bool = False,
60
**kwargs) -> Union[AsyncResult, str]:
61
model, provider = get_model_and_provider(model, provider, False, ignored, ignore_working)
57
**kwargs) -> Union[AsyncResult, Coroutine[str]]:
58
model, provider = get_model_and_provider(model, provider, False, ignore_working)
62
59
63
60
if stream:
64
61
if hasattr(provider, "create_async_generator"):
@@ -84,6 +84,11 @@ def create_app():
84
84
if not AppConfig.ignore_cookie_files:
85
85
read_cookie_files()
86
86
87
if AppConfig.ignored_providers:
88
for provider in AppConfig.ignored_providers:
89
if provider in ProviderUtils.convert:
90
ProviderUtils.convert[provider].working = False
91
87
92
return app
88
93
89
94
def create_app_debug():
@@ -151,7 +156,7 @@ class ErrorResponseMessageModel(BaseModel):
151
156
152
157
class FileResponseModel(BaseModel):
153
158
filename: str
154
159
155
160
class ErrorResponse(Response):
156
161
media_type = "application/json"
157
162
@@ -183,12 +188,6 @@ class AppConfig:
183
188
for key, value in data.items():
184
189
setattr(cls, key, value)
185
190
186
list_ignored_providers: list[str] = None
187
188
def set_list_ignored_providers(ignored: list[str]):
189
global list_ignored_providers
190
list_ignored_providers = ignored
191
192
191
class Api:
193
192
def __init__(self, app: FastAPI) -> None:
194
193
self.app = app