2023-09-03 11:26:26 +03:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2024-10-19 22:33:06 +03:00
|
|
|
import json
|
|
|
|
import requests
|
2023-08-28 02:43:45 +03:00
|
|
|
|
Fix api streaming, fix AsyncClient (#2357)
* Fix api streaming, fix AsyncClient, Improve Client class, Some providers fixes, Update models list, Fix some tests, Update model list in Airforce provid
er, Add OpenAi image generation url to api, Fix reload and debug in api arguments, Fix websearch in gui
* Fix Cloadflare and Pi and AmigoChat provider
* Fix conversation support in DDG provider, Add cloudflare bypass with nodriver
* Fix unittests without curl_cffi
2024-11-16 15:19:51 +03:00
|
|
|
try:
|
|
|
|
from curl_cffi import requests as cf_reqs
|
|
|
|
has_curl_cffi = True
|
|
|
|
except ImportError:
|
|
|
|
has_curl_cffi = False
|
2024-08-29 09:03:32 +03:00
|
|
|
from ..typing import CreateResult, Messages
|
Fix api streaming, fix AsyncClient (#2357)
* Fix api streaming, fix AsyncClient, Improve Client class, Some providers fixes, Update models list, Fix some tests, Update model list in Airforce provid
er, Add OpenAi image generation url to api, Fix reload and debug in api arguments, Fix websearch in gui
* Fix Cloadflare and Pi and AmigoChat provider
* Fix conversation support in DDG provider, Add cloudflare bypass with nodriver
* Fix unittests without curl_cffi
2024-11-16 15:19:51 +03:00
|
|
|
from ..errors import MissingRequirementsError
|
2024-06-26 14:55:03 +03:00
|
|
|
from .base_provider import ProviderModelMixin, AbstractProvider
|
2024-08-29 09:03:32 +03:00
|
|
|
from .helper import format_prompt
|
2023-08-28 02:43:45 +03:00
|
|
|
|
2024-06-26 14:55:03 +03:00
|
|
|
class HuggingChat(AbstractProvider, ProviderModelMixin):
|
2024-08-29 09:03:32 +03:00
|
|
|
url = "https://huggingface.co/chat"
|
|
|
|
working = True
|
2024-06-26 14:55:03 +03:00
|
|
|
supports_stream = True
|
2024-08-29 09:03:32 +03:00
|
|
|
default_model = "meta-llama/Meta-Llama-3.1-70B-Instruct"
|
2024-09-12 21:35:31 +03:00
|
|
|
|
2024-01-23 07:02:14 +03:00
|
|
|
models = [
|
2024-09-12 21:43:28 +03:00
|
|
|
'meta-llama/Meta-Llama-3.1-70B-Instruct',
|
2024-09-12 17:55:39 +03:00
|
|
|
'CohereForAI/c4ai-command-r-plus-08-2024',
|
2024-09-25 08:01:39 +03:00
|
|
|
'Qwen/Qwen2.5-72B-Instruct',
|
2024-10-16 19:33:06 +03:00
|
|
|
'nvidia/Llama-3.1-Nemotron-70B-Instruct-HF',
|
2024-11-12 10:04:33 +03:00
|
|
|
'Qwen/Qwen2.5-Coder-32B-Instruct',
|
2024-10-03 00:40:04 +03:00
|
|
|
'meta-llama/Llama-3.2-11B-Vision-Instruct',
|
2024-09-25 20:05:39 +03:00
|
|
|
'NousResearch/Hermes-3-Llama-3.1-8B',
|
|
|
|
'mistralai/Mistral-Nemo-Instruct-2407',
|
|
|
|
'microsoft/Phi-3.5-mini-instruct',
|
2024-01-23 07:02:14 +03:00
|
|
|
]
|
2024-08-31 09:47:39 +03:00
|
|
|
|
2024-04-23 18:34:42 +03:00
|
|
|
model_aliases = {
|
2024-08-29 09:03:32 +03:00
|
|
|
"llama-3.1-70b": "meta-llama/Meta-Llama-3.1-70B-Instruct",
|
2024-09-12 17:55:39 +03:00
|
|
|
"command-r-plus": "CohereForAI/c4ai-command-r-plus-08-2024",
|
2024-09-25 08:01:39 +03:00
|
|
|
"qwen-2-72b": "Qwen/Qwen2.5-72B-Instruct",
|
2024-10-16 19:33:06 +03:00
|
|
|
"nemotron-70b": "nvidia/Llama-3.1-Nemotron-70B-Instruct-HF",
|
2024-11-12 10:04:33 +03:00
|
|
|
"qwen-2.5-coder-32b": "Qwen/Qwen2.5-Coder-32B-Instruct",
|
2024-10-03 00:40:04 +03:00
|
|
|
"llama-3.2-11b": "meta-llama/Llama-3.2-11B-Vision-Instruct",
|
2024-09-25 20:05:39 +03:00
|
|
|
"hermes-3": "NousResearch/Hermes-3-Llama-3.1-8B",
|
|
|
|
"mistral-nemo": "mistralai/Mistral-Nemo-Instruct-2407",
|
|
|
|
"phi-3.5-mini": "microsoft/Phi-3.5-mini-instruct",
|
2024-04-23 18:34:42 +03:00
|
|
|
}
|
2023-08-28 02:43:45 +03:00
|
|
|
|
2024-08-29 09:03:32 +03:00
|
|
|
@classmethod
|
|
|
|
def get_model(cls, model: str) -> str:
|
|
|
|
if model in cls.models:
|
|
|
|
return model
|
|
|
|
elif model in cls.model_aliases:
|
|
|
|
return cls.model_aliases[model]
|
|
|
|
else:
|
|
|
|
return cls.default_model
|
2024-08-31 09:47:39 +03:00
|
|
|
|
2024-03-25 23:06:51 +03:00
|
|
|
@classmethod
|
2024-06-26 14:55:03 +03:00
|
|
|
def create_completion(
|
2023-08-28 02:43:45 +03:00
|
|
|
cls,
|
|
|
|
model: str,
|
2023-10-09 14:33:20 +03:00
|
|
|
messages: Messages,
|
2024-06-26 14:55:03 +03:00
|
|
|
stream: bool,
|
2024-08-29 09:03:32 +03:00
|
|
|
**kwargs
|
|
|
|
) -> CreateResult:
|
Fix api streaming, fix AsyncClient (#2357)
* Fix api streaming, fix AsyncClient, Improve Client class, Some providers fixes, Update models list, Fix some tests, Update model list in Airforce provid
er, Add OpenAi image generation url to api, Fix reload and debug in api arguments, Fix websearch in gui
* Fix Cloadflare and Pi and AmigoChat provider
* Fix conversation support in DDG provider, Add cloudflare bypass with nodriver
* Fix unittests without curl_cffi
2024-11-16 15:19:51 +03:00
|
|
|
if not has_curl_cffi:
|
|
|
|
raise MissingRequirementsError('Install "curl_cffi" package | pip install -U curl_cffi')
|
2024-08-29 09:03:32 +03:00
|
|
|
model = cls.get_model(model)
|
2024-08-31 09:47:39 +03:00
|
|
|
|
2024-08-29 09:03:32 +03:00
|
|
|
if model in cls.models:
|
2024-08-16 23:25:38 +03:00
|
|
|
session = cf_reqs.Session()
|
|
|
|
session.headers = {
|
|
|
|
'accept': '*/*',
|
|
|
|
'accept-language': 'en',
|
|
|
|
'cache-control': 'no-cache',
|
|
|
|
'origin': 'https://huggingface.co',
|
|
|
|
'pragma': 'no-cache',
|
|
|
|
'priority': 'u=1, i',
|
|
|
|
'referer': 'https://huggingface.co/chat/',
|
|
|
|
'sec-ch-ua': '"Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"',
|
|
|
|
'sec-ch-ua-mobile': '?0',
|
2024-06-26 14:55:03 +03:00
|
|
|
'sec-ch-ua-platform': '"macOS"',
|
2024-08-16 23:25:38 +03:00
|
|
|
'sec-fetch-dest': 'empty',
|
|
|
|
'sec-fetch-mode': 'cors',
|
|
|
|
'sec-fetch-site': 'same-origin',
|
|
|
|
'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',
|
2024-06-26 14:55:03 +03:00
|
|
|
}
|
2024-08-31 09:47:39 +03:00
|
|
|
|
2024-06-26 14:55:03 +03:00
|
|
|
json_data = {
|
2024-08-16 23:25:38 +03:00
|
|
|
'model': model,
|
2024-06-26 14:55:03 +03:00
|
|
|
}
|
2024-08-31 09:47:39 +03:00
|
|
|
|
2024-08-16 23:25:38 +03:00
|
|
|
response = session.post('https://huggingface.co/chat/conversation', json=json_data)
|
2024-10-19 22:33:06 +03:00
|
|
|
if response.status_code != 200:
|
|
|
|
raise RuntimeError(f"Request failed with status code: {response.status_code}, response: {response.text}")
|
2024-08-31 09:47:39 +03:00
|
|
|
|
2024-10-19 22:33:06 +03:00
|
|
|
conversationId = response.json().get('conversationId')
|
2024-11-12 10:04:33 +03:00
|
|
|
|
|
|
|
# Get the data response and parse it properly
|
|
|
|
response = session.get(f'https://huggingface.co/chat/conversation/{conversationId}/__data.json?x-sveltekit-invalidated=11')
|
|
|
|
|
|
|
|
# Split the response content by newlines and parse each line as JSON
|
|
|
|
try:
|
|
|
|
json_data = None
|
|
|
|
for line in response.text.split('\n'):
|
|
|
|
if line.strip():
|
|
|
|
try:
|
|
|
|
parsed = json.loads(line)
|
|
|
|
if isinstance(parsed, dict) and "nodes" in parsed:
|
|
|
|
json_data = parsed
|
|
|
|
break
|
|
|
|
except json.JSONDecodeError:
|
|
|
|
continue
|
|
|
|
|
|
|
|
if not json_data:
|
|
|
|
raise RuntimeError("Failed to parse response data")
|
|
|
|
|
|
|
|
data: list = json_data["nodes"][1]["data"]
|
|
|
|
keys: list[int] = data[data[0]["messages"]]
|
|
|
|
message_keys: dict = data[keys[0]]
|
|
|
|
messageId: str = data[message_keys["id"]]
|
2024-08-31 09:47:39 +03:00
|
|
|
|
2024-11-12 10:04:33 +03:00
|
|
|
except (KeyError, IndexError, TypeError) as e:
|
|
|
|
raise RuntimeError(f"Failed to extract message ID: {str(e)}")
|
2024-06-26 14:55:03 +03:00
|
|
|
|
|
|
|
settings = {
|
2024-08-29 09:03:32 +03:00
|
|
|
"inputs": format_prompt(messages),
|
|
|
|
"id": messageId,
|
|
|
|
"is_retry": False,
|
|
|
|
"is_continue": False,
|
|
|
|
"web_search": False,
|
|
|
|
"tools": []
|
2024-06-26 14:55:03 +03:00
|
|
|
}
|
|
|
|
|
2024-08-16 23:25:38 +03:00
|
|
|
headers = {
|
|
|
|
'accept': '*/*',
|
|
|
|
'accept-language': 'en',
|
|
|
|
'cache-control': 'no-cache',
|
|
|
|
'origin': 'https://huggingface.co',
|
|
|
|
'pragma': 'no-cache',
|
|
|
|
'priority': 'u=1, i',
|
|
|
|
'referer': f'https://huggingface.co/chat/conversation/{conversationId}',
|
|
|
|
'sec-ch-ua': '"Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"',
|
|
|
|
'sec-ch-ua-mobile': '?0',
|
|
|
|
'sec-ch-ua-platform': '"macOS"',
|
|
|
|
'sec-fetch-dest': 'empty',
|
|
|
|
'sec-fetch-mode': 'cors',
|
|
|
|
'sec-fetch-site': 'same-origin',
|
|
|
|
'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',
|
|
|
|
}
|
|
|
|
|
|
|
|
files = {
|
2024-08-29 09:03:32 +03:00
|
|
|
'data': (None, json.dumps(settings, separators=(',', ':'))),
|
2023-08-28 02:43:45 +03:00
|
|
|
}
|
2024-04-22 21:02:17 +03:00
|
|
|
|
2024-11-12 10:04:33 +03:00
|
|
|
response = requests.post(
|
|
|
|
f'https://huggingface.co/chat/conversation/{conversationId}',
|
2024-08-16 23:25:38 +03:00
|
|
|
cookies=session.cookies,
|
|
|
|
headers=headers,
|
|
|
|
files=files,
|
2024-06-26 14:55:03 +03:00
|
|
|
)
|
2024-08-31 09:47:39 +03:00
|
|
|
|
2024-10-19 22:33:06 +03:00
|
|
|
full_response = ""
|
2024-06-26 14:55:03 +03:00
|
|
|
for line in response.iter_lines():
|
2024-10-19 22:33:06 +03:00
|
|
|
if not line:
|
|
|
|
continue
|
|
|
|
try:
|
|
|
|
line = json.loads(line)
|
|
|
|
except json.JSONDecodeError as e:
|
|
|
|
print(f"Failed to decode JSON: {line}, error: {e}")
|
|
|
|
continue
|
2024-06-26 14:55:03 +03:00
|
|
|
|
|
|
|
if "type" not in line:
|
|
|
|
raise RuntimeError(f"Response: {line}")
|
|
|
|
|
|
|
|
elif line["type"] == "stream":
|
2024-10-19 22:33:06 +03:00
|
|
|
token = line["token"].replace('\u0000', '')
|
|
|
|
full_response += token
|
2024-11-12 10:04:33 +03:00
|
|
|
if stream:
|
|
|
|
yield token
|
2024-08-31 09:47:39 +03:00
|
|
|
|
2024-06-26 14:55:03 +03:00
|
|
|
elif line["type"] == "finalAnswer":
|
2024-08-31 09:47:39 +03:00
|
|
|
break
|
2024-10-19 22:33:06 +03:00
|
|
|
|
|
|
|
full_response = full_response.replace('<|im_end|', '').replace('\u0000', '').strip()
|
|
|
|
|
2024-11-12 10:04:33 +03:00
|
|
|
if not stream:
|
|
|
|
yield full_response
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def supports_model(cls, model: str) -> bool:
|
|
|
|
"""Check if the model is supported by the provider."""
|
|
|
|
return model in cls.models or model in cls.model_aliases
|