返回提交历史
Modified
g4f/Provider/HuggingChat.py
+112
-89
XFEstudio/gpt4free
unpatch HuggingChat
ac0bd092
代码差异
1 个文件
+112
-89
@@ -1,20 +1,17 @@
1
1
from __future__ import annotations
2
2
3
import json
4
import requests
5
from aiohttp import ClientSession, BaseConnector
3
import json, requests, re
6
4
7
from ..typing import AsyncResult, Messages
8
from ..requests.raise_for_status import raise_for_status
9
from ..providers.conversation import BaseConversation
10
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
11
from .helper import format_prompt, get_connector, get_cookies
5
from curl_cffi import requests as cf_reqs
6
from ..typing import CreateResult, Messages
7
from .base_provider import ProviderModelMixin, AbstractProvider
8
from .helper import format_prompt, get_connector, get_cookies
12
9
13
class HuggingChat(AsyncGeneratorProvider, ProviderModelMixin):
14
url = "https://huggingface.co/chat"
15
working = True
16
needs_auth = True
17
default_model = "mistralai/Mixtral-8x7B-Instruct-v0.1"
10
class HuggingChat(AbstractProvider, ProviderModelMixin):
11
url = "https://huggingface.co/chat"
12
working = True
13
supports_stream = True
14
default_model = "mistralai/Mixtral-8x7B-Instruct-v0.1"
18
15
models = [
19
16
"HuggingFaceH4/zephyr-orpo-141b-A35b-v0.1",
20
17
'CohereForAI/c4ai-command-r-plus',
@@ -26,92 +23,118 @@ class HuggingChat(AsyncGeneratorProvider, ProviderModelMixin):
26
23
'microsoft/Phi-3-mini-4k-instruct',
27
24
'01-ai/Yi-1.5-34B-Chat'
28
25
]
26
29
27
model_aliases = {
30
28
"mistralai/Mistral-7B-Instruct-v0.1": "mistralai/Mistral-7B-Instruct-v0.2"
31
29
}
32
30
33
31
@classmethod
34
def get_models(cls):
35
if not cls.models:
36
url = f"{cls.url}/__data.json"
37
data = requests.get(url).json()["nodes"][0]["data"]
38
models = [data[key]["name"] for key in data[data[0]["models"]]]
39
cls.models = [data[key] for key in models]
40
return cls.models
41
42
@classmethod
43
async def create_async_generator(
32
def create_completion(
44
33
cls,
45
34
model: str,
46
35
messages: Messages,
47
stream: bool = True,
48
proxy: str = None,
49
connector: BaseConnector = None,
50
web_search: bool = False,
51
cookies: dict = None,
52
conversation: Conversation = None,
53
return_conversation: bool = False,
54
delete_conversation: bool = True,
36
stream: bool,
55
37
**kwargs
56
) -> AsyncResult:
57
options = {"model": cls.get_model(model)}
58
if cookies is None:
59
cookies = get_cookies("huggingface.co", False)
60
if return_conversation:
61
delete_conversation = False
38
) -> CreateResult:
39
40
if (model in cls.models) :
41
42
session = requests.Session()
43
headers = {
44
'accept': '*/*',
45
'accept-language': 'en,fr-FR;q=0.9,fr;q=0.8,es-ES;q=0.7,es;q=0.6,en-US;q=0.5,am;q=0.4,de;q=0.3',
46
'cache-control': 'no-cache',
47
'origin': 'https://huggingface.co',
48
'pragma': 'no-cache',
49
'priority': 'u=1, i',
50
'referer': 'https://huggingface.co/chat/',
51
'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"',
52
'sec-ch-ua-mobile': '?0',
53
'sec-ch-ua-platform': '"macOS"',
54
'sec-fetch-dest': 'empty',
55
'sec-fetch-mode': 'cors',
56
'sec-fetch-site': 'same-origin',
57
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
58
}
62
59
63
system_prompt = "\n".join([message["content"] for message in messages if message["role"] == "system"])
64
if system_prompt:
65
options["preprompt"] = system_prompt
66
messages = [message for message in messages if message["role"] != "system"]
67
headers = {
68
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36',
69
}
70
async with ClientSession(
71
cookies=cookies,
72
headers=headers,
73
connector=get_connector(connector, proxy)
74
) as session:
75
if conversation is None:
76
async with session.post(f"{cls.url}/conversation", json=options) as response:
77
await raise_for_status(response)
78
conversation_id = (await response.json())["conversationId"]
79
if return_conversation:
80
yield Conversation(conversation_id)
81
else:
82
conversation_id = conversation.conversation_id
83
async with session.get(f"{cls.url}/conversation/{conversation_id}/__data.json") as response:
84
await raise_for_status(response)
85
data: list = (await response.json())["nodes"][1]["data"]
86
keys: list[int] = data[data[0]["messages"]]
87
message_keys: dict = data[keys[0]]
88
message_id: str = data[message_keys["id"]]
89
options = {
90
"id": message_id,
91
"inputs": format_prompt(messages) if conversation is None else messages[-1]["content"],
92
"is_continue": False,
60
json_data = {
61
'searchEnabled': True,
62
'ethicsModalAccepted': True,
63
'ethicsModalAcceptedAt': None,
64
'activeModel': 'CohereForAI/c4ai-command-r-plus', # doesn't matter
65
'hideEmojiOnSidebar': False,
66
'shareConversationsWithModelAuthors': False,
67
'customPrompts': {},
68
'assistants': [],
69
'tools': {},
70
'disableStream': False,
71
'recentlySaved': False,
72
}
73
74
response = cf_reqs.post('https://huggingface.co/chat/settings', headers=headers, json=json_data)
75
session.cookies.update(response.cookies)
76
77
response = session.post('https://huggingface.co/chat/conversation',
78
headers=headers, json={'model': model})
79
80
conversationId = response.json()['conversationId']
81
response = session.get(f'https://huggingface.co/chat/conversation/{conversationId}/__data.json?x-sveltekit-invalidated=11',
82
headers=headers,
83
)
84
85
messageId = extract_id(response.json())
86
87
settings = {
88
"inputs": format_prompt(messages),
89
"id": messageId,
93
90
"is_retry": False,
94
"web_search": web_search
91
"is_continue": False,
92
"web_search": False,
93
94
# enable tools
95
"tools": {
96
"websearch": True,
97
"document_parser": False,
98
"query_calculator": False,
99
"image_generation": False,
100
"image_editing": False,
101
"fetch_url": False,
102
}
103
}
104
105
payload = {
106
"data": json.dumps(settings),
95
107
}
96
async with session.post(f"{cls.url}/conversation/{conversation_id}", json=options) as response:
97
first_token = True
98
async for line in response.content:
99
await raise_for_status(response)
100
line = json.loads(line)
101
if "type" not in line:
102
raise RuntimeError(f"Response: {line}")
103
elif line["type"] == "stream":
104
token = line["token"]
105
if first_token:
106
token = token.lstrip().replace('\u0000', '')
107
first_token = False
108
yield token
109
elif line["type"] == "finalAnswer":
110
break
111
if delete_conversation:
112
async with session.delete(f"{cls.url}/conversation/{conversation_id}") as response:
113
await raise_for_status(response)
114
108
115
class Conversation(BaseConversation):
116
def __init__(self, conversation_id: str) -> None:
117
self.conversation_id = conversation_id
109
response = session.post(f"https://huggingface.co/chat/conversation/{conversationId}",
110
headers=headers, data=payload, stream=True,
111
)
112
113
first_token = True
114
for line in response.iter_lines():
115
line = json.loads(line)
116
117
if "type" not in line:
118
raise RuntimeError(f"Response: {line}")
119
120
elif line["type"] == "stream":
121
token = line["token"]
122
if first_token:
123
token = token.lstrip().replace('\u0000', '')
124
first_token = False
125
#yield token
126
yield (token)
127
128
elif line["type"] == "finalAnswer":
129
break
130
131
def extract_id(response: dict) -> str:
132
data = response["nodes"][1]["data"]
133
uuid_pattern = re.compile(
134
r"^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$"
135
)
136
for item in data:
137
if type(item) == str and uuid_pattern.match(item):
138
return item
139
140
return None