返回提交历史
Modified
g4f/Provider/Airforce.py
+1
-4
Modified
g4f/Provider/AmigoChat.py
+2
-3
Modified
g4f/Provider/Copilot.py
+27
-1
Modified
g4f/Provider/DDG.py
+3
-5
Modified
g4f/Provider/Mhystical.py
+5
-11
Modified
g4f/Provider/needs_auth/GithubCopilot.py
+0
-1
Modified
g4f/Provider/needs_auth/HuggingFace.py
+53
-6
Modified
g4f/Provider/openai/new.py
+0
-1
Modified
g4f/api/__init__.py
+11
-9
Modified
g4f/gui/client/static/js/chat.v1.js
+8
-2
Modified
g4f/gui/server/api.py
+3
-0
XFEstudio/gpt4free
Add Clarity Token to Copilot, (#2482)
* Add Clarity Token to Copilot, Ignore disabled providers in gui, Read cookie files after upload * Add more chat templates to HuggingFace
a591c5d4
代码差异
11 个文件
+113
-43
@@ -32,8 +32,7 @@ class Airforce(AsyncGeneratorProvider, ProviderModelMixin):
32
32
api_endpoint_imagine2 = "https://api.airforce/imagine2"
33
33
34
34
working = True
35
needs_auth = True
36
supports_stream = True
35
supports_stream = False
37
36
supports_system_message = True
38
37
supports_message_history = True
39
38
@@ -41,9 +40,7 @@ class Airforce(AsyncGeneratorProvider, ProviderModelMixin):
41
40
default_image_model = "flux"
42
41
43
42
hidden_models = {"Flux-1.1-Pro"}
44
45
43
additional_models_imagine = ["flux-1.1-pro", "midjourney", "dall-e-3"]
46
47
44
model_aliases = {
48
45
# Alias mappings for models
49
46
"gpt-4": "gpt-4o",
@@ -13,7 +13,7 @@ MODELS = {
13
13
'chat': {
14
14
'gpt-4o-2024-11-20': {'persona_id': "gpt"},
15
15
'gpt-4o': {'persona_id': "summarizer"},
16
'gpt-4o-mini': {'persona_id': "gemini-1-5-flash"},
16
'gpt-4o-mini': {'persona_id': "amigo"},
17
17
18
18
'o1-preview-': {'persona_id': "openai-o-one"}, # Amigo, your balance is not enough to make the request, wait until 12 UTC or upgrade your plan
19
19
'o1-preview-2024-09-12-': {'persona_id': "orion"}, # Amigo, your balance is not enough to make the request, wait until 12 UTC or upgrade your plan
@@ -24,7 +24,7 @@ MODELS = {
24
24
'codellama/CodeLlama-34b-Instruct-hf': {'persona_id': "codellama-CodeLlama-34b-Instruct-hf"},
25
25
26
26
'gemini-1.5-pro': {'persona_id': "gemini-1-5-pro"}, # Amigo, your balance is not enough to make the request, wait until 12 UTC or upgrade your plan
27
'gemini-1.5-flash': {'persona_id': "amigo"},
27
'gemini-1.5-flash': {'persona_id': "gemini-1.5-flash"},
28
28
29
29
'claude-3-5-sonnet-20240620': {'persona_id': "claude"},
30
30
'claude-3-5-sonnet-20241022': {'persona_id': "clude-claude-3-5-sonnet-20241022"},
@@ -200,7 +200,6 @@ class AmigoChat(AsyncGeneratorProvider, ProviderModelMixin):
200
200
"temperature": temperature,
201
201
"top_p": top_p
202
202
}
203
print(data)
204
203
async with session.post(cls.chat_api_endpoint, json=data, timeout=timeout) as response:
205
204
await raise_for_status(response)
206
205
async for line in response.iter_lines():
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
3
3
import json
4
4
import asyncio
5
import base64
5
6
from http.cookiejar import CookieJar
6
7
from urllib.parse import quote
7
8
@@ -93,6 +94,20 @@ class Copilot(AbstractProvider, ProviderModelMixin):
93
94
) as session:
94
95
if cls._access_token is not None:
95
96
cls._cookies = session.cookies.jar
97
if cls._access_token is None:
98
try:
99
url = "https://copilot.microsoft.com/cl/eus-sc/collect"
100
headers = {
101
"Accept": "application/x-clarity-gzip",
102
"referrer": "https://copilot.microsoft.com/onboarding"
103
}
104
response = session.post(url, headers=headers, data=get_clarity())
105
clarity_token = json.loads(response.text.split(" ", maxsplit=1)[-1])[0]["value"]
106
debug.log(f"Copilot: Clarity Token: ...{clarity_token[-12:]}")
107
except Exception as e:
108
debug.log(f"Copilot: {e}")
109
else:
110
clarity_token = None
96
111
response = session.get("https://copilot.microsoft.com/c/api/user")
97
112
raise_for_status(response)
98
113
user = response.json().get('firstName')
@@ -125,6 +140,12 @@ class Copilot(AbstractProvider, ProviderModelMixin):
125
140
uploaded_images.append({"type":"image", "url": response.json().get("url")})
126
141
127
142
wss = session.ws_connect(cls.websocket_url)
143
if clarity_token is not None:
144
wss.send(json.dumps({
145
"event": "challengeResponse",
146
"token": clarity_token,
147
"method":"clarity"
148
}).encode(), CurlWsFlag.TEXT)
128
149
wss.send(json.dumps({
129
150
"event": "send",
130
151
"conversationId": conversation_id,
@@ -209,4 +230,9 @@ def readHAR(url: str):
209
230
if api_key is None:
210
231
raise NoValidHarFileError("No access token found in .har files")
211
232
212
return api_key, cookies
233
return api_key, cookies
234
235
def get_clarity() -> bytes:
236
#{"e":["0.7.58",5,7284,4779,"n59ae4ieqq","aln5en","1upufhz",1,0,0],"a":[[7323,12,65,217,324],[7344,12,65,214,329],[7385,12,65,211,334],[7407,12,65,210,337],[7428,12,65,209,338],[7461,12,65,209,339],[7497,12,65,209,339],[7531,12,65,208,340],[7545,12,65,208,342],[11654,13,65,208,342],[11728,14,65,208,342],[11728,9,65,208,342,17535,19455,0,0,0,"Annehmen",null,"52w7wqv1r.8ovjfyrpu",1],[7284,4,1,393,968,393,968,0,0,231,310,939,0],[12063,0,2,147,3,4,4,18,5,1,10,79,25,15],[12063,36,6,[11938,0]]]}
237
body = base64.b64decode("H4sIAAAAAAAAA23RwU7DMAwG4HfJ2aqS2E5ibjxH1cMOnQYqYZvUTQPx7vyJRGGAemj01XWcP+9udg+j80MetDhSyrEISc5GrqrtZnmaTydHbrdUnSsWYT2u+8Obo0Ce/IQvaDBmjkwhUlKKIRNHmQgosqEArWPRDQMx90rxeUMPzB1j+UJvwNIxhTvsPcXyX1T+rizE4juK3mEEhpAUg/JvzW1/+U/tB1LATmhqotoiweMea50PLy2vui4LOY3XfD1dwnkor5fn/e18XBFgm6fHjSzZmCyV7d3aRByAEYextaTHEH3i5pgKGVP/s+DScE5PuLKIpW6FnCi1gY3Rbpqmj0/DI/+L7QEAAA==")
238
return body
@@ -77,9 +77,7 @@ class DDG(AsyncGeneratorProvider, ProviderModelMixin):
77
77
if conversation is None:
78
78
conversation = Conversation(model)
79
79
is_new_conversation = True
80
81
debug.last_model = model
82
80
83
81
if conversation.vqd is None:
84
82
conversation.vqd = await cls.get_vqd(proxy, connector)
85
83
if not conversation.vqd:
@@ -91,7 +89,7 @@ class DDG(AsyncGeneratorProvider, ProviderModelMixin):
91
89
'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36',
92
90
'x-vqd-4': conversation.vqd,
93
91
}
94
92
95
93
async with ClientSession(headers=headers, connector=get_connector(connector, proxy)) as session:
96
94
if is_new_conversation:
97
95
conversation.message_history = [{"role": "user", "content": format_prompt(messages)}]
@@ -119,7 +117,7 @@ class DDG(AsyncGeneratorProvider, ProviderModelMixin):
119
117
async with session.post(cls.api_endpoint, json=data) as response:
120
118
conversation.vqd = response.headers.get("x-vqd-4")
121
119
await raise_for_status(response)
122
120
123
121
async for line in response.content:
124
122
if line:
125
123
decoded_line = line.decode('utf-8')
@@ -4,6 +4,7 @@ import json
4
4
import logging
5
5
from aiohttp import ClientSession
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
@@ -67,17 +68,10 @@ class Mhystical(AsyncGeneratorProvider, ProviderModelMixin):
67
68
"messages": [{"role": "user", "content": format_prompt(messages)}]
68
69
}
69
70
async with session.post(cls.api_endpoint, json=data, headers=headers, proxy=proxy) as response:
70
if response.status == 400:
71
yield "Error: API key is missing"
72
elif response.status == 429:
73
yield "Error: Rate limit exceeded"
74
elif response.status == 500:
75
yield "Error: Internal server error"
76
else:
77
response.raise_for_status()
78
response_text = await response.text()
79
filtered_response = cls.filter_response(response_text)
80
yield filtered_response
71
await raise_for_status(response)
72
response_text = await response.text()
73
filtered_response = cls.filter_response(response_text)
74
yield filtered_response
81
75
82
76
@staticmethod
83
77
def filter_response(response_text: str) -> str:
@@ -62,7 +62,6 @@ class GithubCopilot(AsyncGeneratorProvider, ProviderModelMixin):
62
62
if conversation is not None:
63
63
conversation_id = conversation.conversation_id
64
64
if conversation_id is None:
65
print(headers)
66
65
async with session.post("https://api.individual.githubcopilot.com/github/chat/threads", headers=headers) as response:
67
66
await raise_for_status(response)
68
67
conversation_id = (await response.json()).get("thread_id")
@@ -3,25 +3,37 @@ from __future__ import annotations
3
3
import json
4
4
import base64
5
5
import random
6
import requests
6
7
7
8
from ...typing import AsyncResult, Messages
8
9
from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin
9
from ...errors import ModelNotFoundError
10
from ...errors import ModelNotFoundError, ModelNotSupportedError
10
11
from ...requests import StreamSession, raise_for_status
11
12
from ...image import ImageResponse
12
13
13
14
from .HuggingChat import HuggingChat
14
15
15
16
class HuggingFace(AsyncGeneratorProvider, ProviderModelMixin):
16
url = "https://huggingface.co/chat"
17
url = "https://huggingface.co"
17
18
working = True
18
19
supports_message_history = True
19
20
default_model = HuggingChat.default_model
20
21
default_image_model = HuggingChat.default_image_model
21
models = HuggingChat.models
22
image_models = [default_image_model]
23
22
model_aliases = HuggingChat.model_aliases
24
23
24
@classmethod
25
def get_models(cls) -> list[str]:
26
if not cls.models:
27
url = "https://huggingface.co/api/models?inference=warm&pipeline_tag=text-generation"
28
cls.models = [model["id"] for model in requests.get(url).json()]
29
cls.models.append("meta-llama/Llama-3.2-11B-Vision-Instruct")
30
cls.models.append("nvidia/Llama-3.1-Nemotron-70B-Instruct-HF")
31
if not cls.image_models:
32
url = "https://huggingface.co/api/models?pipeline_tag=text-to-image"
33
cls.image_models = [model["id"] for model in requests.get(url).json() if model["trendingScore"] >= 20]
34
cls.models.extend(cls.image_models)
35
return cls.models
36
25
37
@classmethod
26
38
async def create_async_generator(
27
39
cls,
@@ -36,7 +48,10 @@ class HuggingFace(AsyncGeneratorProvider, ProviderModelMixin):
36
48
prompt: str = None,
37
49
**kwargs
38
50
) -> AsyncResult:
39
model = cls.get_model(model)
51
try:
52
model = cls.get_model(model)
53
except ModelNotSupportedError:
54
pass
40
55
headers = {
41
56
'accept': '*/*',
42
57
'accept-language': 'en',
@@ -55,6 +70,7 @@ class HuggingFace(AsyncGeneratorProvider, ProviderModelMixin):
55
70
}
56
71
if api_key is not None:
57
72
headers["Authorization"] = f"Bearer {api_key}"
73
payload = None
58
74
if model in cls.image_models:
59
75
stream = False
60
76
prompt = messages[-1]["content"] if prompt is None else prompt
@@ -66,12 +82,28 @@ class HuggingFace(AsyncGeneratorProvider, ProviderModelMixin):
66
82
"temperature": temperature,
67
83
**kwargs
68
84
}
69
payload = {"inputs": format_prompt(messages), "parameters": params, "stream": stream}
70
85
async with StreamSession(
71
86
headers=headers,
72
87
proxy=proxy,
73
88
timeout=600
74
89
) as session:
90
if payload is None:
91
async with session.get(f"https://huggingface.co/api/models/{model}") as response:
92
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"]:
94
eos_token = model_data["config"]["tokenizer_config"]["eos_token"]
95
if eos_token == "</s>":
96
inputs = format_prompt_mistral(messages)
97
elif eos_token == "<|im_end|>":
98
inputs = format_prompt_qwen(messages)
99
elif eos_token == "<|eot_id|>":
100
inputs = format_prompt_llama(messages)
101
else:
102
inputs = format_prompt(messages)
103
else:
104
inputs = format_prompt(messages)
105
payload = {"inputs": inputs, "parameters": params, "stream": stream}
106
75
107
async with session.post(f"{api_base.rstrip('/')}/models/{model}", json=payload) as response:
76
108
if response.status == 404:
77
109
raise ModelNotFoundError(f"Model is not supported: {model}")
@@ -105,3 +137,18 @@ def format_prompt(messages: Messages) -> str:
105
137
if message["role"] == "assistant"
106
138
])
107
139
return f"{history}<s>[INST] {question} [/INST]"
140
141
def format_prompt_qwen(messages: Messages) -> str:
142
return "".join([
143
f"<|im_start|>{message['role']}\n{message['content']}\n<|im_end|>\n" for message in messages
144
]) + "<|im_start|>assistant\n"
145
146
def format_prompt_llama(messages: Messages) -> str:
147
return "<|begin_of_text|>" + "".join([
148
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:
152
return "".join([
153
f"<|{message['role']}|>\n{message['content']}'</s>\n" for message in messages
154
]) + "<|assistant|>\n"
@@ -476,7 +476,6 @@ start_time = time.time()
476
476
477
477
def get_turnstile_token(dx: str, p: str) -> str:
478
478
decoded_bytes = base64.b64decode(dx)
479
# print(decoded_bytes.decode())
480
479
return process_turnstile_token(decoded_bytes.decode(), p)
481
480
482
481
@@ -470,15 +470,17 @@ class Api:
470
470
})
471
471
def upload_cookies(files: List[UploadFile]):
472
472
response_data = []
473
for file in files:
474
try:
475
if file and file.filename.endswith(".json") or file.filename.endswith(".har"):
476
filename = os.path.basename(file.filename)
477
with open(os.path.join(get_cookies_dir(), filename), 'wb') as f:
478
shutil.copyfileobj(file.file, f)
479
response_data.append({"filename": filename})
480
finally:
481
file.file.close()
473
if not AppConfig.ignore_cookie_files:
474
for file in files:
475
try:
476
if file and file.filename.endswith(".json") or file.filename.endswith(".har"):
477
filename = os.path.basename(file.filename)
478
with open(os.path.join(get_cookies_dir(), filename), 'wb') as f:
479
shutil.copyfileobj(file.file, f)
480
response_data.append({"filename": filename})
481
finally:
482
file.file.close()
483
read_cookie_files()
482
484
return response_data
483
485
484
486
@self.app.get("/v1/synthesize/{provider}", responses={
@@ -610,6 +610,7 @@ const ask_gpt = async (message_id, message_index = -1, regenerate = false, provi
610
610
const auto_continue = document.getElementById("auto_continue")?.checked;
611
611
const download_images = document.getElementById("download_images")?.checked;
612
612
let api_key = get_api_key_by_provider(provider);
613
const ignored = Array.from(settings.querySelectorAll("input.provider:not(:checked)")).map((el)=>el.value);
613
614
await api("conversation", {
614
615
id: message_id,
615
616
conversation_id: window.conversation_id,
@@ -620,6 +621,7 @@ const ask_gpt = async (message_id, message_index = -1, regenerate = false, provi
620
621
auto_continue: auto_continue,
621
622
download_images: download_images,
622
623
api_key: api_key,
624
ignored: ignored,
623
625
}, files, message_id);
624
626
if (!error_storage[message_id]) {
625
627
html = markdown_render(message_storage[message_id]);
@@ -1217,6 +1219,7 @@ function count_tokens(model, text) {
1217
1219
if (window.GPTTokenizer_cl100k_base) {
1218
1220
return GPTTokenizer_cl100k_base.encode(text).length;
1219
1221
}
1222
return 0;
1220
1223
}
1221
1224
1222
1225
function count_words(text) {
@@ -1256,6 +1259,10 @@ systemPrompt.addEventListener("input", function() {
1256
1259
});
1257
1260
1258
1261
window.addEventListener('load', async function() {
1262
await safe_load_conversation(window.conversation_id, false);
1263
});
1264
1265
window.addEventListener('DOMContentLoaded', async function() {
1259
1266
await on_load();
1260
1267
if (window.conversation_id == "{{chat_id}}") {
1261
1268
window.conversation_id = uuid();
@@ -1309,7 +1316,6 @@ async function on_api() {
1309
1316
let prompt_lock = false;
1310
1317
messageInput.addEventListener("keydown", async (evt) => {
1311
1318
if (prompt_lock) return;
1312
1313
1319
// If not mobile and not shift enter
1314
1320
if (!window.matchMedia("(pointer:coarse)").matches && evt.keyCode === 13 && !evt.shiftKey) {
1315
1321
evt.preventDefault();
@@ -1361,7 +1367,7 @@ async function on_api() {
1361
1367
option.innerHTML = `
1362
1368
<div class="field">
1363
1369
<span class="label">Enable ${provider.label}</span>
1364
<input id="Provider${provider.name}" type="checkbox" name="Provider${provider.name}" checked="">
1370
<input id="Provider${provider.name}" type="checkbox" name="Provider${provider.name}" value="${provider.name}" class="provider" checked="">
1365
1371
<label for="Provider${provider.name}" class="toogle" title="Remove provider from dropdown"></label>
1366
1372
</div>`;
1367
1373
option.querySelector("input").addEventListener("change", (event) => load_provider_option(event.target, provider.name));
@@ -106,6 +106,9 @@ class Api:
106
106
if provider in conversations and conversation_id in conversations[provider]:
107
107
kwargs["conversation"] = conversations[provider][conversation_id]
108
108
109
if json_data.get("ignored"):
110
kwargs["ignored"] = json_data["ignored"]
111
109
112
return {
110
113
"model": model,
111
114
"provider": provider,