返回提交历史
Modified
g4f/Provider/needs_auth/HuggingChat.py
+122
-118
Modified
g4f/gui/client/static/css/style.css
+5
-7
Modified
g4f/gui/client/static/js/chat.v1.js
+2
-28
XFEstudio/gpt4free
Add cookies to HuggingChat provider
e2c269cc
代码差异
3 个文件
+129
-153
@@ -1,16 +1,17 @@
1
1
from __future__ import annotations
2
2
3
3
import json
4
import requests
5
4
6
5
try:
7
from curl_cffi.requests import Session
6
from curl_cffi.requests import Session, CurlMime
8
7
has_curl_cffi = True
9
8
except ImportError:
10
9
has_curl_cffi = False
11
from ...typing import CreateResult, Messages
10
11
from ...typing import CreateResult, Messages, Cookies
12
12
from ...errors import MissingRequirementsError
13
13
from ...requests.raise_for_status import raise_for_status
14
from ...cookies import get_cookies
14
15
from ..base_provider import ProviderModelMixin, AbstractProvider
15
16
from ..helper import format_prompt
16
17
@@ -53,127 +54,130 @@ class HuggingChat(AbstractProvider, ProviderModelMixin):
53
54
model: str,
54
55
messages: Messages,
55
56
stream: bool,
57
web_search: bool = False,
58
cookies: Cookies = None,
56
59
**kwargs
57
60
) -> CreateResult:
58
61
if not has_curl_cffi:
59
62
raise MissingRequirementsError('Install "curl_cffi" package | pip install -U curl_cffi')
60
63
model = cls.get_model(model)
64
if cookies is None:
65
cookies = get_cookies("huggingface.co")
66
67
session = Session(cookies=cookies)
68
session.headers = {
69
'accept': '*/*',
70
'accept-language': 'en',
71
'cache-control': 'no-cache',
72
'origin': 'https://huggingface.co',
73
'pragma': 'no-cache',
74
'priority': 'u=1, i',
75
'referer': 'https://huggingface.co/chat/',
76
'sec-ch-ua': '"Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"',
77
'sec-ch-ua-mobile': '?0',
78
'sec-ch-ua-platform': '"macOS"',
79
'sec-fetch-dest': 'empty',
80
'sec-fetch-mode': 'cors',
81
'sec-fetch-site': 'same-origin',
82
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36',
83
}
84
json_data = {
85
'model': model,
86
}
87
response = session.post('https://huggingface.co/chat/conversation', json=json_data)
88
raise_for_status(response)
89
90
conversationId = response.json().get('conversationId')
61
91
62
if model in cls.models:
63
session = Session()
64
session.headers = {
65
'accept': '*/*',
66
'accept-language': 'en',
67
'cache-control': 'no-cache',
68
'origin': 'https://huggingface.co',
69
'pragma': 'no-cache',
70
'priority': 'u=1, i',
71
'referer': 'https://huggingface.co/chat/',
72
'sec-ch-ua': '"Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"',
73
'sec-ch-ua-mobile': '?0',
74
'sec-ch-ua-platform': '"macOS"',
75
'sec-fetch-dest': 'empty',
76
'sec-fetch-mode': 'cors',
77
'sec-fetch-site': 'same-origin',
78
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36',
79
}
80
json_data = {
81
'model': model,
82
}
83
response = session.post('https://huggingface.co/chat/conversation', json=json_data)
84
raise_for_status(response)
85
86
conversationId = response.json().get('conversationId')
87
88
# Get the data response and parse it properly
89
response = session.get(f'https://huggingface.co/chat/conversation/{conversationId}/__data.json?x-sveltekit-invalidated=11')
90
raise_for_status(response)
91
92
# Split the response content by newlines and parse each line as JSON
92
# Get the data response and parse it properly
93
response = session.get(f'https://huggingface.co/chat/conversation/{conversationId}/__data.json?x-sveltekit-invalidated=11')
94
raise_for_status(response)
95
96
# Split the response content by newlines and parse each line as JSON
97
try:
98
json_data = None
99
for line in response.text.split('\n'):
100
if line.strip():
101
try:
102
parsed = json.loads(line)
103
if isinstance(parsed, dict) and "nodes" in parsed:
104
json_data = parsed
105
break
106
except json.JSONDecodeError:
107
continue
108
109
if not json_data:
110
raise RuntimeError("Failed to parse response data")
111
112
data: list = json_data["nodes"][1]["data"]
113
keys: list[int] = data[data[0]["messages"]]
114
message_keys: dict = data[keys[0]]
115
messageId: str = data[message_keys["id"]]
116
117
except (KeyError, IndexError, TypeError) as e:
118
raise RuntimeError(f"Failed to extract message ID: {str(e)}")
119
120
settings = {
121
"inputs": format_prompt(messages),
122
"id": messageId,
123
"is_retry": False,
124
"is_continue": False,
125
"web_search": web_search,
126
"tools": []
127
}
128
129
headers = {
130
'accept': '*/*',
131
'accept-language': 'en',
132
'cache-control': 'no-cache',
133
'origin': 'https://huggingface.co',
134
'pragma': 'no-cache',
135
'priority': 'u=1, i',
136
'referer': f'https://huggingface.co/chat/conversation/{conversationId}',
137
'sec-ch-ua': '"Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"',
138
'sec-ch-ua-mobile': '?0',
139
'sec-ch-ua-platform': '"macOS"',
140
'sec-fetch-dest': 'empty',
141
'sec-fetch-mode': 'cors',
142
'sec-fetch-site': 'same-origin',
143
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36',
144
}
145
146
data = CurlMime()
147
data.addpart('data', data=json.dumps(settings, separators=(',', ':')))
148
149
response = session.post(
150
f'https://huggingface.co/chat/conversation/{conversationId}',
151
cookies=session.cookies,
152
headers=headers,
153
multipart=data,
154
stream=True
155
)
156
raise_for_status(response)
157
158
full_response = ""
159
for line in response.iter_lines():
160
if not line:
161
continue
93
162
try:
94
json_data = None
95
for line in response.text.split('\n'):
96
if line.strip():
97
try:
98
parsed = json.loads(line)
99
if isinstance(parsed, dict) and "nodes" in parsed:
100
json_data = parsed
101
break
102
except json.JSONDecodeError:
103
continue
104
105
if not json_data:
106
raise RuntimeError("Failed to parse response data")
107
108
data: list = json_data["nodes"][1]["data"]
109
keys: list[int] = data[data[0]["messages"]]
110
message_keys: dict = data[keys[0]]
111
messageId: str = data[message_keys["id"]]
112
113
except (KeyError, IndexError, TypeError) as e:
114
raise RuntimeError(f"Failed to extract message ID: {str(e)}")
115
116
settings = {
117
"inputs": format_prompt(messages),
118
"id": messageId,
119
"is_retry": False,
120
"is_continue": False,
121
"web_search": False,
122
"tools": []
123
}
124
125
headers = {
126
'accept': '*/*',
127
'accept-language': 'en',
128
'cache-control': 'no-cache',
129
'origin': 'https://huggingface.co',
130
'pragma': 'no-cache',
131
'priority': 'u=1, i',
132
'referer': f'https://huggingface.co/chat/conversation/{conversationId}',
133
'sec-ch-ua': '"Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"',
134
'sec-ch-ua-mobile': '?0',
135
'sec-ch-ua-platform': '"macOS"',
136
'sec-fetch-dest': 'empty',
137
'sec-fetch-mode': 'cors',
138
'sec-fetch-site': 'same-origin',
139
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36',
140
}
141
142
files = {
143
'data': (None, json.dumps(settings, separators=(',', ':'))),
144
}
145
146
response = requests.post(
147
f'https://huggingface.co/chat/conversation/{conversationId}',
148
cookies=session.cookies,
149
headers=headers,
150
files=files,
151
)
152
raise_for_status(response)
153
154
full_response = ""
155
for line in response.iter_lines():
156
if not line:
157
continue
158
try:
159
line = json.loads(line)
160
except json.JSONDecodeError as e:
161
print(f"Failed to decode JSON: {line}, error: {e}")
162
continue
163
164
if "type" not in line:
165
raise RuntimeError(f"Response: {line}")
166
167
elif line["type"] == "stream":
168
token = line["token"].replace('\u0000', '')
169
full_response += token
170
if stream:
171
yield token
172
173
elif line["type"] == "finalAnswer":
174
break
163
line = json.loads(line)
164
except json.JSONDecodeError as e:
165
print(f"Failed to decode JSON: {line}, error: {e}")
166
continue
175
167
176
full_response = full_response.replace('<|im_end|', '').replace('\u0000', '').strip()
168
if "type" not in line:
169
raise RuntimeError(f"Response: {line}")
170
171
elif line["type"] == "stream":
172
token = line["token"].replace('\u0000', '')
173
full_response += token
174
if stream:
175
yield token
176
177
elif line["type"] == "finalAnswer":
178
break
179
180
full_response = full_response.replace('<|im_end|', '').replace('\u0000', '').strip()
177
181
178
if not stream:
179
yield full_response
182
if not stream:
183
yield full_response
@@ -92,6 +92,10 @@ body {
92
92
height: 100vh;
93
93
}
94
94
95
a:-webkit-any-link {
96
color: var(--accent);
97
}
98
95
99
.row {
96
100
display: flex;
97
101
gap: 10px;
@@ -124,7 +128,7 @@ body {
124
128
125
129
.new_version a {
126
130
color: var(--colour-4);
127
text-decoration: underline dotted;
131
text-decoration: underline;
128
132
}
129
133
130
134
.conversations {
@@ -975,11 +979,6 @@ ul {
975
979
display: flex;
976
980
}
977
981
978
979
a:-webkit-any-link {
980
color: var(--accent);
981
}
982
983
982
.conversation .user-input textarea {
984
983
font-size: 15px;
985
984
width: 100%;
@@ -1021,7 +1020,6 @@ a:-webkit-any-link {
1021
1020
background-image: url('data:image/svg+xml;utf-8,<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M6 5C5.73478 5 5.48043 5.10536 5.29289 5.29289C5.10536 5.48043 5 5.73478 5 6V20C5 20.2652 5.10536 20.5196 5.29289 20.7071C5.48043 20.8946 5.73478 21 6 21H18C18.2652 21 18.5196 20.8946 18.7071 20.7071C18.8946 20.5196 19 20.2652 19 20V6C19 5.73478 18.8946 5.48043 18.7071 5.29289C18.5196 5.10536 18.2652 5 18 5H16C15.4477 5 15 4.55228 15 4C15 3.44772 15.4477 3 16 3H18C18.7956 3 19.5587 3.31607 20.1213 3.87868C20.6839 4.44129 21 5.20435 21 6V20C21 20.7957 20.6839 21.5587 20.1213 22.1213C19.5587 22.6839 18.7957 23 18 23H6C5.20435 23 4.44129 22.6839 3.87868 22.1213C3.31607 21.5587 3 20.7957 3 20V6C3 5.20435 3.31607 4.44129 3.87868 3.87868C4.44129 3.31607 5.20435 3 6 3H8C8.55228 3 9 3.44772 9 4C9 4.55228 8.55228 5 8 5H6Z" fill="white"/><path fill-rule="evenodd" clip-rule="evenodd" d="M7 3C7 1.89543 7.89543 1 9 1H15C16.1046 1 17 1.89543 17 3V5C17 6.10457 16.1046 7 15 7H9C7.89543 7 7 6.10457 7 5V3ZM15 3H9V5H15V3Z" fill="white"/></svg>');
1022
1021
background-repeat: no-repeat;
1023
1022
background-position: center;
1024
transition: background-color 200ms ease, transform 200ms ease-out
1025
1023
}
1026
1024
1027
1025
.hljs-copy-button:hover {
@@ -1065,6 +1065,7 @@ async function hide_sidebar() {
1065
1065
sidebar_button.classList.remove("rotated");
1066
1066
settings.classList.add("hidden");
1067
1067
chat.classList.remove("hidden");
1068
log_storage.classList.add("hidden");
1068
1069
if (window.location.pathname == "/menu/" || window.location.pathname == "/settings/") {
1069
1070
history.back();
1070
1071
}
@@ -1182,31 +1183,6 @@ const say_hello = async () => {
1182
1183
}
1183
1184
}
1184
1185
1185
// Theme storage for recurring viewers
1186
const storeTheme = function (theme) {
1187
appStorage.setItem("theme", theme);
1188
};
1189
1190
// set theme when visitor returns
1191
const setTheme = function () {
1192
const activeTheme = appStorage.getItem("theme");
1193
colorThemes.forEach((themeOption) => {
1194
if (themeOption.id === activeTheme) {
1195
themeOption.checked = true;
1196
}
1197
});
1198
// fallback for no :has() support
1199
document.documentElement.className = activeTheme;
1200
};
1201
1202
colorThemes.forEach((themeOption) => {
1203
themeOption.addEventListener("click", () => {
1204
storeTheme(themeOption.id);
1205
// fallback for no :has() support
1206
document.documentElement.className = themeOption.id;
1207
});
1208
});
1209
1210
1186
function count_tokens(model, text) {
1211
1187
if (model) {
1212
1188
if (window.llamaTokenizer)
@@ -1273,7 +1249,6 @@ window.addEventListener('pywebviewready', async function() {
1273
1249
});
1274
1250
1275
1251
async function on_load() {
1276
setTheme();
1277
1252
count_input();
1278
1253
1279
1254
if (/\/chat\/.+/.test(window.location.href)) {
@@ -1290,8 +1265,7 @@ async function on_api() {
1290
1265
if (prompt_lock) return;
1291
1266
1292
1267
// If not mobile
1293
if (!window.matchMedia("(pointer:coarse)").matches)
1294
if (evt.keyCode === 13 && !evt.shiftKey) {
1268
if (!window.matchMedia("(pointer:coarse)").matches && evt.keyCode === 13 && !evt.shiftKey) {
1295
1269
evt.preventDefault();
1296
1270
console.log("pressed enter");
1297
1271
prompt_lock = true;