返回提交历史
Modified
g4f/Provider/PollinationsAI.py
+6
-3
Modified
g4f/Provider/PollinationsImage.py
+2
-0
Modified
g4f/Provider/hf/HuggingChat.py
+2
-1
Modified
g4f/Provider/hf/HuggingFaceAPI.py
+9
-7
Modified
g4f/Provider/hf/HuggingFaceInference.py
+41
-32
Modified
g4f/Provider/hf/__init__.py
+1
-1
Modified
g4f/Provider/needs_auth/DeepSeekAPI.py
+0
-1
Modified
g4f/Provider/needs_auth/OpenaiAccount.py
+2
-1
Modified
g4f/Provider/template/OpenaiTemplate.py
+1
-1
Modified
g4f/client/__init__.py
+2
-2
Modified
g4f/gui/client/static/js/chat.v1.js
+14
-6
Modified
g4f/gui/server/api.py
+2
-2
Modified
g4f/image/copy_images.py
+1
-1
Modified
g4f/providers/retry_provider.py
+1
-1
XFEstudio/gpt4free
Show only free providers by default
470b7954
代码差异
14 个文件
+84
-59
@@ -123,9 +123,6 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
123
123
if model not in cls.image_models:
124
124
raise
125
125
126
if not cache and seed is None:
127
seed = random.randint(1000, 999999)
128
129
126
if model in cls.image_models:
130
127
async for chunk in cls._generate_image(
131
128
model=model,
@@ -134,6 +131,7 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
134
131
width=width,
135
132
height=height,
136
133
seed=seed,
134
cache=cache,
137
135
nologo=nologo,
138
136
private=private,
139
137
enhance=enhance,
@@ -165,11 +163,14 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
165
163
width: int,
166
164
height: int,
167
165
seed: Optional[int],
166
cache: bool,
168
167
nologo: bool,
169
168
private: bool,
170
169
enhance: bool,
171
170
safe: bool
172
171
) -> AsyncResult:
172
if not cache and seed is None:
173
seed = random.randint(9999, 99999999)
173
174
params = {
174
175
"seed": str(seed) if seed is not None else None,
175
176
"width": str(width),
@@ -207,6 +208,8 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
207
208
seed: Optional[int],
208
209
cache: bool
209
210
) -> AsyncResult:
211
if not cache and seed is None:
212
seed = random.randint(9999, 99999999)
210
213
json_mode = False
211
214
if response_format and response_format.get("type") == "json_object":
212
215
json_mode = True
@@ -28,6 +28,7 @@ class PollinationsImage(PollinationsAI):
28
28
width: int = 1024,
29
29
height: int = 1024,
30
30
seed: Optional[int] = None,
31
cache: bool = False,
31
32
nologo: bool = True,
32
33
private: bool = False,
33
34
enhance: bool = False,
@@ -41,6 +42,7 @@ class PollinationsImage(PollinationsAI):
41
42
width=width,
42
43
height=height,
43
44
seed=seed,
45
cache=cache,
44
46
nologo=nologo,
45
47
private=private,
46
48
enhance=enhance,
@@ -8,7 +8,8 @@ import base64
8
8
from typing import AsyncIterator
9
9
10
10
try:
11
from curl_cffi.requests import Session, CurlMime
11
from curl_cffi.requests import Session
12
from curl_cffi import CurlMime
12
13
has_curl_cffi = True
13
14
except ImportError:
14
15
has_curl_cffi = False
@@ -4,6 +4,7 @@ from ...providers.types import Messages
4
4
from ...typing import ImagesType
5
5
from ...requests import StreamSession, raise_for_status
6
6
from ...errors import ModelNotSupportedError
7
from ...providers.helper import get_last_user_message
7
8
from ..template.OpenaiTemplate import OpenaiTemplate
8
9
from .models import model_aliases, vision_models, default_vision_model
9
10
from .HuggingChat import HuggingChat
@@ -22,7 +23,7 @@ class HuggingFaceAPI(OpenaiTemplate):
22
23
vision_models = vision_models
23
24
model_aliases = model_aliases
24
25
25
pipeline_tag: dict[str, str] = {}
26
pipeline_tags: dict[str, str] = {}
26
27
27
28
@classmethod
28
29
def get_models(cls, **kwargs):
@@ -36,8 +37,8 @@ class HuggingFaceAPI(OpenaiTemplate):
36
37
37
38
@classmethod
38
39
async def get_pipline_tag(cls, model: str, api_key: str = None):
39
if model in cls.pipeline_tag:
40
return cls.pipeline_tag[model]
40
if model in cls.pipeline_tags:
41
return cls.pipeline_tags[model]
41
42
async with StreamSession(
42
43
timeout=30,
43
44
headers=cls.get_headers(False, api_key),
@@ -45,8 +46,8 @@ class HuggingFaceAPI(OpenaiTemplate):
45
46
async with session.get(f"https://huggingface.co/api/models/{model}") as response:
46
47
await raise_for_status(response)
47
48
model_data = await response.json()
48
cls.pipeline_tag[model] = model_data.get("pipeline_tag")
49
return cls.pipeline_tag[model]
49
cls.pipeline_tags[model] = model_data.get("pipeline_tag")
50
return cls.pipeline_tags[model]
50
51
51
52
@classmethod
52
53
async def create_async_generator(
@@ -73,10 +74,11 @@ class HuggingFaceAPI(OpenaiTemplate):
73
74
if len(messages) > 6:
74
75
messages = messages[:3] + messages[-3:]
75
76
if calculate_lenght(messages) > max_inputs_lenght:
77
last_user_message = [{"role": "user", "content": get_last_user_message(messages)}]
76
78
if len(messages) > 2:
77
messages = [m for m in messages if m["role"] == "system"] + messages[-1:]
79
messages = [m for m in messages if m["role"] == "system"] + last_user_message
78
80
if len(messages) > 1 and calculate_lenght(messages) > max_inputs_lenght:
79
messages = [messages[-1]]
81
messages = last_user_message
80
82
debug.log(f"Messages trimmed from: {start} to: {calculate_lenght(messages)}")
81
83
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):
82
84
yield chunk
@@ -7,7 +7,7 @@ import requests
7
7
8
8
from ...typing import AsyncResult, Messages
9
9
from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin, format_prompt
10
from ...errors import ModelNotFoundError, ModelNotSupportedError, ResponseError
10
from ...errors import ModelNotSupportedError, ResponseError
11
11
from ...requests import StreamSession, raise_for_status
12
12
from ...providers.response import FinishReason, ImageResponse
13
13
from ..helper import format_image_prompt, get_last_user_message
@@ -24,6 +24,8 @@ class HuggingFaceInference(AsyncGeneratorProvider, ProviderModelMixin):
24
24
model_aliases = model_aliases
25
25
image_models = image_models
26
26
27
model_data: dict[str, dict] = {}
28
27
29
@classmethod
28
30
def get_models(cls) -> list[str]:
29
31
if not cls.models:
@@ -43,6 +45,17 @@ class HuggingFaceInference(AsyncGeneratorProvider, ProviderModelMixin):
43
45
cls.models = models
44
46
return cls.models
45
47
48
@classmethod
49
async def get_model_data(cls, session: StreamSession, model: str) -> str:
50
if model in cls.model_data:
51
return cls.model_data[model]
52
async with session.get(f"https://huggingface.co/api/models/{model}") as response:
53
if response.status == 404:
54
raise ModelNotSupportedError(f"Model is not supported: {model} in: {cls.__name__}")
55
await raise_for_status(response)
56
cls.model_data[model] = await response.json()
57
return cls.model_data[model]
58
46
59
@classmethod
47
60
async def create_async_generator(
48
61
cls,
@@ -96,41 +109,37 @@ class HuggingFaceInference(AsyncGeneratorProvider, ProviderModelMixin):
96
109
timeout=600
97
110
) as session:
98
111
if payload is None:
99
async with session.get(f"https://huggingface.co/api/models/{model}") as response:
100
if response.status == 404:
101
raise ModelNotSupportedError(f"Model is not supported: {model} in: {cls.__name__}")
102
await raise_for_status(response)
103
model_data = await response.json()
104
pipeline_tag = model_data.get("pipeline_tag")
105
if pipeline_tag == "text-to-image":
106
stream = False
107
inputs = format_image_prompt(messages, prompt)
108
payload = {"inputs": inputs, "parameters": {"seed": random.randint(0, 2**32) if seed is None else seed, **extra_data}}
109
elif pipeline_tag in ("text-generation", "image-text-to-text"):
110
model_type = None
111
if "config" in model_data and "model_type" in model_data["config"]:
112
model_type = model_data["config"]["model_type"]
113
debug.log(f"Model type: {model_type}")
112
model_data = await cls.get_model_data(session, model)
113
pipeline_tag = model_data.get("pipeline_tag")
114
if pipeline_tag == "text-to-image":
115
stream = False
116
inputs = format_image_prompt(messages, prompt)
117
payload = {"inputs": inputs, "parameters": {"seed": random.randint(0, 2**32) if seed is None else seed, **extra_data}}
118
elif pipeline_tag in ("text-generation", "image-text-to-text"):
119
model_type = None
120
if "config" in model_data and "model_type" in model_data["config"]:
121
model_type = model_data["config"]["model_type"]
122
debug.log(f"Model type: {model_type}")
123
inputs = get_inputs(messages, model_data, model_type, do_continue)
124
debug.log(f"Inputs len: {len(inputs)}")
125
if len(inputs) > 4096:
126
if len(messages) > 6:
127
messages = messages[:3] + messages[-3:]
128
else:
129
messages = [m for m in messages if m["role"] == "system"] + [{"role": "user", "content": get_last_user_message(messages)}]
114
130
inputs = get_inputs(messages, model_data, model_type, do_continue)
115
debug.log(f"Inputs len: {len(inputs)}")
116
if len(inputs) > 4096:
117
if len(messages) > 6:
118
messages = messages[:3] + messages[-3:]
119
else:
120
messages = [m for m in messages if m["role"] == "system"] + [get_last_user_message(messages)]
121
inputs = get_inputs(messages, model_data, model_type, do_continue)
122
debug.log(f"New len: {len(inputs)}")
123
if model_type == "gpt2" and max_tokens >= 1024:
124
params["max_new_tokens"] = 512
125
if seed is not None:
126
params["seed"] = seed
127
payload = {"inputs": inputs, "parameters": params, "stream": stream}
128
else:
129
raise ModelNotSupportedError(f"Model is not supported: {model} in: {cls.__name__} pipeline_tag: {pipeline_tag}")
131
debug.log(f"New len: {len(inputs)}")
132
if model_type == "gpt2" and max_tokens >= 1024:
133
params["max_new_tokens"] = 512
134
if seed is not None:
135
params["seed"] = seed
136
payload = {"inputs": inputs, "parameters": params, "stream": stream}
137
else:
138
raise ModelNotSupportedError(f"Model is not supported: {model} in: {cls.__name__} pipeline_tag: {pipeline_tag}")
130
139
131
140
async with session.post(f"{api_base.rstrip('/')}/models/{model}", json=payload) as response:
132
141
if response.status == 404:
133
raise ModelNotFoundError(f"Model is not supported: {model}")
142
raise ModelNotSupportedError(f"Model is not supported: {model}")
134
143
await raise_for_status(response)
135
144
if stream:
136
145
first = True
@@ -36,7 +36,7 @@ class HuggingFace(AsyncGeneratorProvider, ProviderModelMixin):
36
36
messages: Messages,
37
37
**kwargs
38
38
) -> AsyncResult:
39
if "api_key" not in kwargs and "images" not in kwargs and random.random() >= 0.5:
39
if "images" not in kwargs and "deepseek" in model or random.random() >= 0.5:
40
40
try:
41
41
is_started = False
42
42
async for chunk in HuggingFaceInference.create_async_generator(model, messages, **kwargs):
@@ -13,7 +13,6 @@ from ...errors import MissingAuthError
13
13
from ...requests import get_args_from_nodriver, get_nodriver
14
14
from ...providers.response import AuthResult, RequestLogin, Reasoning, JsonConversation, FinishReason
15
15
from ...typing import AsyncResult, Messages
16
from ... import debug
17
16
try:
18
17
from curl_cffi import requests
19
18
from dsk.api import DeepSeekAPI, AuthenticationError, DeepSeekPOW
@@ -4,4 +4,5 @@ from .OpenaiChat import OpenaiChat
4
4
5
5
class OpenaiAccount(OpenaiChat):
6
6
needs_auth = True
7
parent = "OpenaiChat"
7
parent = "OpenaiChat"
8
use_nodriver = False # Show (Auth) in the model name
@@ -65,7 +65,7 @@ class OpenaiTemplate(AsyncGeneratorProvider, ProviderModelMixin, RaiseErrorMixin
65
65
prompt: str = None,
66
66
headers: dict = None,
67
67
impersonate: str = None,
68
extra_parameters: list[str] = ["tools", "parallel_tool_calls", "", "reasoning_effort", "logit_bias"],
68
extra_parameters: list[str] = ["tools", "parallel_tool_calls", "tool_choice", "reasoning_effort", "logit_bias"],
69
69
extra_data: dict = {},
70
70
**kwargs
71
71
) -> AsyncResult:
@@ -365,7 +365,7 @@ class Images:
365
365
break
366
366
except Exception as e:
367
367
error = e
368
debug.error(e, name=f"{provider.__name__} {type(e).__name__}")
368
debug.error(f"{provider.__name__} {type(e).__name__}: {e}")
369
369
else:
370
370
response = await self._generate_image_response(provider_handler, provider_name, model, prompt, **kwargs)
371
371
@@ -460,7 +460,7 @@ class Images:
460
460
break
461
461
except Exception as e:
462
462
error = e
463
debug.error(e, name=f"{provider.__name__} {type(e).__name__}")
463
debug.error(f"{provider.__name__} {type(e).__name__}: {e}")
464
464
else:
465
465
response = await self._generate_image_response(provider_handler, provider_name, model, prompt, **kwargs)
466
466
@@ -1932,7 +1932,7 @@ const load_provider_option = (input, provider_name) => {
1932
1932
providerSelect.querySelectorAll(`option[data-parent="${provider_name}"]`).forEach(
1933
1933
(el) => el.removeAttribute("disabled")
1934
1934
);
1935
settings.querySelector(`.field:has(#${provider_name}-api_key)`)?.classList.remove("hidden");
1935
//settings.querySelector(`.field:has(#${provider_name}-api_key)`)?.classList.remove("hidden");
1936
1936
} else {
1937
1937
modelSelect.querySelectorAll(`option[data-providers*="${provider_name}"]`).forEach(
1938
1938
(el) => {
@@ -1947,7 +1947,7 @@ const load_provider_option = (input, provider_name) => {
1947
1947
providerSelect.querySelectorAll(`option[data-parent="${provider_name}"]`).forEach(
1948
1948
(el) => el.setAttribute("disabled", "disabled")
1949
1949
);
1950
settings.querySelector(`.field:has(#${provider_name}-api_key)`)?.classList.add("hidden");
1950
//settings.querySelector(`.field:has(#${provider_name}-api_key)`)?.classList.add("hidden");
1951
1951
}
1952
1952
};
1953
1953
@@ -2039,13 +2039,13 @@ async function on_api() {
2039
2039
2040
2040
if (provider.parent) {
2041
2041
if (!login_urls[provider.parent]) {
2042
login_urls[provider.parent] = [provider.label, provider.login_url, [provider.name]];
2042
login_urls[provider.parent] = [provider.label, provider.login_url, [provider.name], provider.auth];
2043
2043
} else {
2044
2044
login_urls[provider.parent][2].push(provider.name);
2045
2045
}
2046
2046
} else if (provider.login_url) {
2047
2047
if (!login_urls[provider.name]) {
2048
login_urls[provider.name] = [provider.label, provider.login_url, []];
2048
login_urls[provider.name] = [provider.label, provider.login_url, [], provider.auth];
2049
2049
} else {
2050
2050
login_urls[provider.name][0] = provider.label;
2051
2051
login_urls[provider.name][1] = provider.login_url;
@@ -2068,9 +2068,10 @@ async function on_api() {
2068
2068
if (!provider.parent) {
2069
2069
let option = document.createElement("div");
2070
2070
option.classList.add("provider-item");
2071
let api_key = appStorage.getItem(`${provider.name}-api_key`);
2071
2072
option.innerHTML = `
2072
2073
<span class="label">Enable ${provider.label}</span>
2073
<input id="Provider${provider.name}" type="checkbox" name="Provider${provider.name}" value="${provider.name}" class="provider" checked="">
2074
<input id="Provider${provider.name}" type="checkbox" name="Provider${provider.name}" value="${provider.name}" class="provider" ${'checked="checked"' ? !provider.auth || api_key : ''}/>
2074
2075
<label for="Provider${provider.name}" class="toogle" title="Remove provider from dropdown"></label>
2075
2076
`;
2076
2077
option.querySelector("input").addEventListener("change", (event) => load_provider_option(event.target, provider.name));
@@ -2102,7 +2103,7 @@ async function on_api() {
2102
2103
`;
2103
2104
settings.querySelector(".paper").appendChild(providersListContainer);
2104
2105
2105
for (let [name, [label, login_url, childs]] of Object.entries(login_urls)) {
2106
for (let [name, [label, login_url, childs, auth]] of Object.entries(login_urls)) {
2106
2107
if (!login_url && !is_demo) {
2107
2108
continue;
2108
2109
}
@@ -2113,6 +2114,13 @@ async function on_api() {
2113
2114
<label for="${name}-api_key" class="label" title="">${label}:</label>
2114
2115
<input type="text" id="${name}-api_key" name="${name}[api_key]" class="${childs}" placeholder="api_key" autocomplete="off"/>
2115
2116
` + (login_url ? `<a href="${login_url}" target="_blank" title="Login to ${label}">Get API key</a>` : "");
2117
if (auth) {
2118
providerBox.querySelector("input").addEventListener("input", (event) => {
2119
const input = document.getElementById(`Provider${name}`);
2120
input.checked = !!event.target.value;
2121
load_provider_option(input, name);
2122
});
2123
}
2116
2124
providersListContainer.querySelector(".collapsible-content").appendChild(providerBox);
2117
2125
}
2118
2126
@@ -143,7 +143,7 @@ class Api:
143
143
def decorated_log(text: str, file = None):
144
144
debug.logs.append(text)
145
145
if debug.logging:
146
debug.log_handler(text, file)
146
debug.log_handler(text, file=file)
147
147
debug.log = decorated_log
148
148
proxy = os.environ.get("G4F_PROXY")
149
149
provider = kwargs.get("provider")
@@ -187,7 +187,7 @@ class Api:
187
187
yield self._format_json("conversation_id", conversation_id)
188
188
elif isinstance(chunk, Exception):
189
189
logger.exception(chunk)
190
debug.error(e)
190
debug.error(chunk)
191
191
yield self._format_json('message', get_error_message(chunk), error=type(chunk).__name__)
192
192
elif isinstance(chunk, PreviewResponse):
193
193
yield self._format_json("preview", chunk.to_string())