返回提交历史
Modified
g4f/Provider/needs_auth/HuggingChat.py
+45
-40
Modified
g4f/requests/__init__.py
+6
-9
XFEstudio/gpt4free
Add RequestLogin to HuggingChat
5651760c
代码差异
2 个文件
+51
-49
@@ -2,7 +2,9 @@ from __future__ import annotations
2
2
3
3
import json
4
4
import re
5
import os
5
6
import requests
7
from typing import AsyncIterator
6
8
7
9
try:
8
10
from curl_cffi.requests import Session, CurlMime
@@ -10,12 +12,13 @@ try:
10
12
except ImportError:
11
13
has_curl_cffi = False
12
14
13
from ..base_provider import ProviderModelMixin, AbstractProvider
15
from ..base_provider import ProviderModelMixin, AsyncAuthedProvider, AuthResult
14
16
from ..helper import format_prompt
15
from ...typing import CreateResult, Messages, Cookies
16
from ...errors import MissingRequirementsError
17
from ...typing import AsyncResult, Messages, Cookies
18
from ...errors import MissingRequirementsError, MissingAuthError, ResponseError
19
from ...requests import get_args_from_nodriver, DEFAULT_HEADERS
17
20
from ...requests.raise_for_status import raise_for_status
18
from ...providers.response import JsonConversation, ImageResponse, Sources, TitleGeneration, Reasoning
21
from ...providers.response import JsonConversation, ImageResponse, Sources, TitleGeneration, Reasoning, RequestLogin
19
22
from ...cookies import get_cookies
20
23
from ... import debug
21
24
@@ -23,7 +26,7 @@ class Conversation(JsonConversation):
23
26
def __init__(self, models: dict):
24
27
self.models: dict = models
25
28
26
class HuggingChat(AbstractProvider, ProviderModelMixin):
29
class HuggingChat(AsyncAuthedProvider, ProviderModelMixin):
27
30
url = "https://huggingface.co/chat"
28
31
29
32
working = True
@@ -85,41 +88,44 @@ class HuggingChat(AbstractProvider, ProviderModelMixin):
85
88
return cls.models
86
89
87
90
@classmethod
88
def create_completion(
91
async def on_auth_async(cls, cookies: Cookies = None, proxy: str = None, **kwargs) -> AsyncIterator:
92
if cookies is None:
93
cookies = get_cookies("huggingface.co")
94
if "hf-chat" in cookies:
95
yield AuthResult(
96
cookies=cookies,
97
impersonate="chrome",
98
headers=DEFAULT_HEADERS
99
)
100
return
101
login_url = os.environ.get("G4F_LOGIN_URL")
102
if login_url:
103
yield RequestLogin(cls.__name__, login_url)
104
yield AuthResult(
105
**await get_args_from_nodriver(
106
cls.url,
107
proxy=proxy,
108
wait_for='form[action="/chat/logout"]'
109
)
110
)
111
112
@classmethod
113
async def create_authed(
89
114
cls,
90
115
model: str,
91
116
messages: Messages,
92
stream: bool,
117
auth_result: AuthResult,
93
118
prompt: str = None,
94
119
return_conversation: bool = False,
95
120
conversation: Conversation = None,
96
121
web_search: bool = False,
97
cookies: Cookies = None,
98
122
**kwargs
99
) -> CreateResult:
123
) -> AsyncResult:
100
124
if not has_curl_cffi:
101
125
raise MissingRequirementsError('Install "curl_cffi" package | pip install -U curl_cffi')
102
126
model = cls.get_model(model)
103
if cookies is None:
104
cookies = get_cookies("huggingface.co")
105
127
106
session = Session(cookies=cookies)
107
session.headers = {
108
'accept': '*/*',
109
'accept-language': 'en',
110
'cache-control': 'no-cache',
111
'origin': 'https://huggingface.co',
112
'pragma': 'no-cache',
113
'priority': 'u=1, i',
114
'referer': 'https://huggingface.co/chat/',
115
'sec-ch-ua': '"Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"',
116
'sec-ch-ua-mobile': '?0',
117
'sec-ch-ua-platform': '"macOS"',
118
'sec-fetch-dest': 'empty',
119
'sec-fetch-mode': 'cors',
120
'sec-fetch-site': 'same-origin',
121
'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',
122
}
128
session = Session(**auth_result.get_dict())
123
129
124
130
if conversation is None or not hasattr(conversation, "models"):
125
131
conversation = Conversation({})
@@ -133,14 +139,14 @@ class HuggingChat(AbstractProvider, ProviderModelMixin):
133
139
inputs = format_prompt(messages)
134
140
else:
135
141
conversationId = conversation.models[model]["conversationId"]
136
conversation.models[model]["message_id"] = cls.fetch_message_id(session, conversationId)
142
conversation.models[model]["messageId"] = cls.fetch_message_id(session, conversationId)
137
143
inputs = messages[-1]["content"]
138
144
139
debug.log(f"Use model {model}: {json.dumps(conversation.models[model])}")
145
debug.log(f"Use: {json.dumps(conversation.models[model])}")
140
146
141
147
settings = {
142
148
"inputs": inputs,
143
"id": conversation.models[model]["message_id"],
149
"id": conversation.models[model]["messageId"],
144
150
"is_retry": False,
145
151
"is_continue": False,
146
152
"web_search": web_search,
@@ -176,7 +182,6 @@ class HuggingChat(AbstractProvider, ProviderModelMixin):
176
182
)
177
183
raise_for_status(response)
178
184
179
full_response = ""
180
185
sources = None
181
186
for line in response.iter_lines():
182
187
if not line:
@@ -189,10 +194,7 @@ class HuggingChat(AbstractProvider, ProviderModelMixin):
189
194
if "type" not in line:
190
195
raise RuntimeError(f"Response: {line}")
191
196
elif line["type"] == "stream":
192
token = line["token"].replace('\u0000', '')
193
full_response += token
194
if stream:
195
yield token
197
yield line["token"].replace('\u0000', '')
196
198
elif line["type"] == "finalAnswer":
197
199
break
198
200
elif line["type"] == "file":
@@ -208,9 +210,6 @@ class HuggingChat(AbstractProvider, ProviderModelMixin):
208
210
else:
209
211
pass #print(line)
210
212
211
full_response = full_response.replace('<|im_end|', '').strip()
212
if not stream:
213
yield full_response
214
213
if sources is not None:
215
214
yield sources
216
215
@@ -222,8 +221,9 @@ class HuggingChat(AbstractProvider, ProviderModelMixin):
222
221
'model': model,
223
222
}
224
223
response = session.post('https://huggingface.co/chat/conversation', json=json_data)
224
if response.status_code == 401:
225
raise MissingAuthError(response.text)
225
226
raise_for_status(response)
226
227
227
return response.json().get('conversationId')
228
228
229
229
@classmethod
@@ -248,6 +248,11 @@ class HuggingChat(AbstractProvider, ProviderModelMixin):
248
248
if not json_data:
249
249
raise RuntimeError("Failed to parse response data")
250
250
251
if json_data["nodes"][-1]["type"] == "error":
252
if json_data["nodes"][-1]["status"] == 403:
253
raise MissingAuthError(json_data["nodes"][-1]["error"]["message"])
254
raise ResponseError(json.dumps(json_data["nodes"][-1]))
255
251
256
data = json_data["nodes"][1]["data"]
252
257
keys = data[data[0]["messages"]]
253
258
message_keys = data[keys[-1]]
@@ -78,25 +78,22 @@ async def get_args_from_nodriver(
78
78
url: str,
79
79
proxy: str = None,
80
80
timeout: int = 120,
81
wait_for: str = None,
81
82
cookies: Cookies = None
82
83
) -> dict:
83
if not has_nodriver:
84
raise MissingRequirementsError('Install "nodriver" package | pip install -U nodriver')
84
browser = await get_nodriver(proxy=proxy)
85
85
if debug.logging:
86
86
print(f"Open nodriver with url: {url}")
87
browser = await nodriver.start(
88
browser_args=None if proxy is None else [f"--proxy-server={proxy}"],
89
)
90
87
domain = urlparse(url).netloc
91
88
if cookies is None:
92
89
cookies = {}
93
90
else:
94
91
await browser.cookies.set_all(get_cookie_params_from_dict(cookies, url=url, domain=domain))
95
92
page = await browser.get(url)
96
for c in await page.send(nodriver.cdp.network.get_cookies([url])):
97
cookies[c.name] = c.value
98
93
user_agent = await page.evaluate("window.navigator.userAgent")
99
94
await page.wait_for("body:not(.no-js)", timeout=timeout)
95
if wait_for is not None:
96
await page.wait_for(wait_for, timeout=timeout)
100
97
for c in await page.send(nodriver.cdp.network.get_cookies([url])):
101
98
cookies[c.name] = c.value
102
99
await page.close()
@@ -120,13 +117,13 @@ def merge_cookies(cookies: Iterator[Morsel], response: Response) -> Cookies:
120
117
121
118
async def get_nodriver(proxy: str = None, user_data_dir = "nodriver", browser_executable_path=None, **kwargs)-> Browser:
122
119
if not has_nodriver:
123
raise MissingRequirementsError('Install "nodriver" package | pip install -U nodriver')
120
raise MissingRequirementsError('Install "nodriver" and "platformdirs" package | pip install -U nodriver platformdirs')
124
121
user_data_dir = user_config_dir(f"g4f-{user_data_dir}") if has_platformdirs else None
125
122
if browser_executable_path is None:
126
123
try:
127
124
browser_executable_path = find_chrome_executable()
128
125
except FileNotFoundError:
129
# Default to Edge if Chrome is not found
126
# Default to Edge if Chrome is not available.
130
127
browser_executable_path = "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe"
131
128
if not os.path.exists(browser_executable_path):
132
129
browser_executable_path = None