huggingface-hub 0.29.3rc0__py3-none-any.whl → 0.30.0rc0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of huggingface-hub might be problematic. Click here for more details.
- huggingface_hub/__init__.py +16 -1
- huggingface_hub/_commit_api.py +142 -4
- huggingface_hub/_space_api.py +15 -2
- huggingface_hub/_webhooks_server.py +2 -0
- huggingface_hub/commands/delete_cache.py +66 -20
- huggingface_hub/commands/upload.py +16 -2
- huggingface_hub/constants.py +44 -7
- huggingface_hub/errors.py +19 -0
- huggingface_hub/file_download.py +163 -35
- huggingface_hub/hf_api.py +349 -28
- huggingface_hub/hub_mixin.py +19 -4
- huggingface_hub/inference/_client.py +50 -69
- huggingface_hub/inference/_generated/_async_client.py +57 -76
- huggingface_hub/inference/_generated/types/__init__.py +1 -0
- huggingface_hub/inference/_generated/types/chat_completion.py +20 -10
- huggingface_hub/inference/_generated/types/image_to_image.py +2 -0
- huggingface_hub/inference/_providers/__init__.py +7 -1
- huggingface_hub/inference/_providers/_common.py +9 -5
- huggingface_hub/inference/_providers/black_forest_labs.py +5 -5
- huggingface_hub/inference/_providers/cohere.py +1 -1
- huggingface_hub/inference/_providers/fal_ai.py +64 -7
- huggingface_hub/inference/_providers/fireworks_ai.py +4 -1
- huggingface_hub/inference/_providers/hf_inference.py +41 -4
- huggingface_hub/inference/_providers/hyperbolic.py +3 -3
- huggingface_hub/inference/_providers/nebius.py +3 -3
- huggingface_hub/inference/_providers/novita.py +35 -5
- huggingface_hub/inference/_providers/openai.py +22 -0
- huggingface_hub/inference/_providers/replicate.py +3 -3
- huggingface_hub/inference/_providers/together.py +3 -3
- huggingface_hub/utils/__init__.py +8 -0
- huggingface_hub/utils/_http.py +4 -1
- huggingface_hub/utils/_runtime.py +11 -0
- huggingface_hub/utils/_xet.py +199 -0
- huggingface_hub/utils/tqdm.py +30 -2
- {huggingface_hub-0.29.3rc0.dist-info → huggingface_hub-0.30.0rc0.dist-info}/METADATA +3 -1
- {huggingface_hub-0.29.3rc0.dist-info → huggingface_hub-0.30.0rc0.dist-info}/RECORD +40 -38
- {huggingface_hub-0.29.3rc0.dist-info → huggingface_hub-0.30.0rc0.dist-info}/LICENSE +0 -0
- {huggingface_hub-0.29.3rc0.dist-info → huggingface_hub-0.30.0rc0.dist-info}/WHEEL +0 -0
- {huggingface_hub-0.29.3rc0.dist-info → huggingface_hub-0.30.0rc0.dist-info}/entry_points.txt +0 -0
- {huggingface_hub-0.29.3rc0.dist-info → huggingface_hub-0.30.0rc0.dist-info}/top_level.txt +0 -0
|
@@ -84,7 +84,11 @@ class TaskProviderHelper:
|
|
|
84
84
|
raise ValueError("Either payload or data must be set in the request.")
|
|
85
85
|
return RequestParameters(url=url, task=self.task, model=mapped_model, json=payload, data=data, headers=headers)
|
|
86
86
|
|
|
87
|
-
def get_response(
|
|
87
|
+
def get_response(
|
|
88
|
+
self,
|
|
89
|
+
response: Union[bytes, Dict],
|
|
90
|
+
request_params: Optional[RequestParameters] = None,
|
|
91
|
+
) -> Any:
|
|
88
92
|
"""
|
|
89
93
|
Return the response in the expected format.
|
|
90
94
|
|
|
@@ -142,7 +146,7 @@ class TaskProviderHelper:
|
|
|
142
146
|
|
|
143
147
|
Usually not overwritten in subclasses."""
|
|
144
148
|
base_url = self._prepare_base_url(api_key)
|
|
145
|
-
route = self._prepare_route(mapped_model)
|
|
149
|
+
route = self._prepare_route(mapped_model, api_key)
|
|
146
150
|
return f"{base_url.rstrip('/')}/{route.lstrip('/')}"
|
|
147
151
|
|
|
148
152
|
def _prepare_base_url(self, api_key: str) -> str:
|
|
@@ -157,7 +161,7 @@ class TaskProviderHelper:
|
|
|
157
161
|
logger.info(f"Calling '{self.provider}' provider directly.")
|
|
158
162
|
return self.base_url
|
|
159
163
|
|
|
160
|
-
def _prepare_route(self, mapped_model: str) -> str:
|
|
164
|
+
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
|
|
161
165
|
"""Return the route to use for the request.
|
|
162
166
|
|
|
163
167
|
Override this method in subclasses for customized routes.
|
|
@@ -192,7 +196,7 @@ class BaseConversationalTask(TaskProviderHelper):
|
|
|
192
196
|
def __init__(self, provider: str, base_url: str):
|
|
193
197
|
super().__init__(provider=provider, base_url=base_url, task="conversational")
|
|
194
198
|
|
|
195
|
-
def _prepare_route(self, mapped_model: str) -> str:
|
|
199
|
+
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
|
|
196
200
|
return "/v1/chat/completions"
|
|
197
201
|
|
|
198
202
|
def _prepare_payload_as_dict(self, inputs: Any, parameters: Dict, mapped_model: str) -> Optional[Dict]:
|
|
@@ -208,7 +212,7 @@ class BaseTextGenerationTask(TaskProviderHelper):
|
|
|
208
212
|
def __init__(self, provider: str, base_url: str):
|
|
209
213
|
super().__init__(provider=provider, base_url=base_url, task="text-generation")
|
|
210
214
|
|
|
211
|
-
def _prepare_route(self, mapped_model: str) -> str:
|
|
215
|
+
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
|
|
212
216
|
return "/v1/completions"
|
|
213
217
|
|
|
214
218
|
def _prepare_payload_as_dict(self, inputs: Any, parameters: Dict, mapped_model: str) -> Optional[Dict]:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import time
|
|
2
2
|
from typing import Any, Dict, Optional, Union
|
|
3
3
|
|
|
4
|
-
from huggingface_hub.inference._common import _as_dict
|
|
4
|
+
from huggingface_hub.inference._common import RequestParameters, _as_dict
|
|
5
5
|
from huggingface_hub.inference._providers._common import TaskProviderHelper, filter_none
|
|
6
6
|
from huggingface_hub.utils import logging
|
|
7
7
|
from huggingface_hub.utils._http import get_session
|
|
@@ -15,7 +15,7 @@ POLLING_INTERVAL = 1.0
|
|
|
15
15
|
|
|
16
16
|
class BlackForestLabsTextToImageTask(TaskProviderHelper):
|
|
17
17
|
def __init__(self):
|
|
18
|
-
super().__init__(provider="black-forest-labs", base_url="https://api.us1.bfl.ai
|
|
18
|
+
super().__init__(provider="black-forest-labs", base_url="https://api.us1.bfl.ai", task="text-to-image")
|
|
19
19
|
|
|
20
20
|
def _prepare_headers(self, headers: Dict, api_key: str) -> Dict:
|
|
21
21
|
headers = super()._prepare_headers(headers, api_key)
|
|
@@ -24,8 +24,8 @@ class BlackForestLabsTextToImageTask(TaskProviderHelper):
|
|
|
24
24
|
headers["X-Key"] = api_key
|
|
25
25
|
return headers
|
|
26
26
|
|
|
27
|
-
def _prepare_route(self, mapped_model: str) -> str:
|
|
28
|
-
return mapped_model
|
|
27
|
+
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
|
|
28
|
+
return f"/v1/{mapped_model}"
|
|
29
29
|
|
|
30
30
|
def _prepare_payload_as_dict(self, inputs: Any, parameters: Dict, mapped_model: str) -> Optional[Dict]:
|
|
31
31
|
parameters = filter_none(parameters)
|
|
@@ -36,7 +36,7 @@ class BlackForestLabsTextToImageTask(TaskProviderHelper):
|
|
|
36
36
|
|
|
37
37
|
return {"prompt": inputs, **parameters}
|
|
38
38
|
|
|
39
|
-
def get_response(self, response: Union[bytes, Dict]) -> Any:
|
|
39
|
+
def get_response(self, response: Union[bytes, Dict], request_params: Optional[RequestParameters] = None) -> Any:
|
|
40
40
|
"""
|
|
41
41
|
Polling mechanism for Black Forest Labs since the API is asynchronous.
|
|
42
42
|
"""
|
|
@@ -11,5 +11,5 @@ class CohereConversationalTask(BaseConversationalTask):
|
|
|
11
11
|
def __init__(self):
|
|
12
12
|
super().__init__(provider=_PROVIDER, base_url=_BASE_URL)
|
|
13
13
|
|
|
14
|
-
def _prepare_route(self, mapped_model: str) -> str:
|
|
14
|
+
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
|
|
15
15
|
return "/compatibility/v1/chat/completions"
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
import base64
|
|
2
|
+
import time
|
|
2
3
|
from abc import ABC
|
|
3
4
|
from typing import Any, Dict, Optional, Union
|
|
5
|
+
from urllib.parse import urlparse
|
|
4
6
|
|
|
5
|
-
from huggingface_hub.inference._common import _as_dict
|
|
7
|
+
from huggingface_hub.inference._common import RequestParameters, _as_dict
|
|
6
8
|
from huggingface_hub.inference._providers._common import TaskProviderHelper, filter_none
|
|
7
|
-
from huggingface_hub.utils import get_session
|
|
9
|
+
from huggingface_hub.utils import get_session, hf_raise_for_status
|
|
10
|
+
from huggingface_hub.utils.logging import get_logger
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
logger = get_logger(__name__)
|
|
14
|
+
|
|
15
|
+
# Arbitrary polling interval
|
|
16
|
+
_POLLING_INTERVAL = 0.5
|
|
8
17
|
|
|
9
18
|
|
|
10
19
|
class FalAITask(TaskProviderHelper, ABC):
|
|
@@ -17,7 +26,7 @@ class FalAITask(TaskProviderHelper, ABC):
|
|
|
17
26
|
headers["authorization"] = f"Key {api_key}"
|
|
18
27
|
return headers
|
|
19
28
|
|
|
20
|
-
def _prepare_route(self, mapped_model: str) -> str:
|
|
29
|
+
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
|
|
21
30
|
return f"/{mapped_model}"
|
|
22
31
|
|
|
23
32
|
|
|
@@ -41,7 +50,7 @@ class FalAIAutomaticSpeechRecognitionTask(FalAITask):
|
|
|
41
50
|
|
|
42
51
|
return {"audio_url": audio_url, **filter_none(parameters)}
|
|
43
52
|
|
|
44
|
-
def get_response(self, response: Union[bytes, Dict]) -> Any:
|
|
53
|
+
def get_response(self, response: Union[bytes, Dict], request_params: Optional[RequestParameters] = None) -> Any:
|
|
45
54
|
text = _as_dict(response)["text"]
|
|
46
55
|
if not isinstance(text, str):
|
|
47
56
|
raise ValueError(f"Unexpected output format from FalAI API. Expected string, got {type(text)}.")
|
|
@@ -61,7 +70,7 @@ class FalAITextToImageTask(FalAITask):
|
|
|
61
70
|
}
|
|
62
71
|
return {"prompt": inputs, **parameters}
|
|
63
72
|
|
|
64
|
-
def get_response(self, response: Union[bytes, Dict]) -> Any:
|
|
73
|
+
def get_response(self, response: Union[bytes, Dict], request_params: Optional[RequestParameters] = None) -> Any:
|
|
65
74
|
url = _as_dict(response)["images"][0]["url"]
|
|
66
75
|
return get_session().get(url).content
|
|
67
76
|
|
|
@@ -73,7 +82,7 @@ class FalAITextToSpeechTask(FalAITask):
|
|
|
73
82
|
def _prepare_payload_as_dict(self, inputs: Any, parameters: Dict, mapped_model: str) -> Optional[Dict]:
|
|
74
83
|
return {"lyrics": inputs, **filter_none(parameters)}
|
|
75
84
|
|
|
76
|
-
def get_response(self, response: Union[bytes, Dict]) -> Any:
|
|
85
|
+
def get_response(self, response: Union[bytes, Dict], request_params: Optional[RequestParameters] = None) -> Any:
|
|
77
86
|
url = _as_dict(response)["audio"]["url"]
|
|
78
87
|
return get_session().get(url).content
|
|
79
88
|
|
|
@@ -82,9 +91,57 @@ class FalAITextToVideoTask(FalAITask):
|
|
|
82
91
|
def __init__(self):
|
|
83
92
|
super().__init__("text-to-video")
|
|
84
93
|
|
|
94
|
+
def _prepare_base_url(self, api_key: str) -> str:
|
|
95
|
+
if api_key.startswith("hf_"):
|
|
96
|
+
return super()._prepare_base_url(api_key)
|
|
97
|
+
else:
|
|
98
|
+
logger.info(f"Calling '{self.provider}' provider directly.")
|
|
99
|
+
return "https://queue.fal.run"
|
|
100
|
+
|
|
101
|
+
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
|
|
102
|
+
if api_key.startswith("hf_"):
|
|
103
|
+
# Use the queue subdomain for HF routing
|
|
104
|
+
return f"/{mapped_model}?_subdomain=queue"
|
|
105
|
+
return f"/{mapped_model}"
|
|
106
|
+
|
|
85
107
|
def _prepare_payload_as_dict(self, inputs: Any, parameters: Dict, mapped_model: str) -> Optional[Dict]:
|
|
86
108
|
return {"prompt": inputs, **filter_none(parameters)}
|
|
87
109
|
|
|
88
|
-
def get_response(
|
|
110
|
+
def get_response(
|
|
111
|
+
self,
|
|
112
|
+
response: Union[bytes, Dict],
|
|
113
|
+
request_params: Optional[RequestParameters] = None,
|
|
114
|
+
) -> Any:
|
|
115
|
+
response_dict = _as_dict(response)
|
|
116
|
+
|
|
117
|
+
request_id = response_dict.get("request_id")
|
|
118
|
+
if not request_id:
|
|
119
|
+
raise ValueError("No request ID found in the response")
|
|
120
|
+
if request_params is None:
|
|
121
|
+
raise ValueError(
|
|
122
|
+
"A `RequestParameters` object should be provided to get text-to-video responses with Fal AI."
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
# extract the base url and query params
|
|
126
|
+
parsed_url = urlparse(request_params.url)
|
|
127
|
+
# a bit hacky way to concatenate the provider name without parsing `parsed_url.path`
|
|
128
|
+
base_url = f"{parsed_url.scheme}://{parsed_url.netloc}{'/fal-ai' if parsed_url.netloc == 'router.huggingface.co' else ''}"
|
|
129
|
+
query_param = f"?{parsed_url.query}" if parsed_url.query else ""
|
|
130
|
+
|
|
131
|
+
# extracting the provider model id for status and result urls
|
|
132
|
+
# from the response as it might be different from the mapped model in `request_params.url`
|
|
133
|
+
model_id = urlparse(response_dict.get("response_url")).path
|
|
134
|
+
status_url = f"{base_url}{str(model_id)}/status{query_param}"
|
|
135
|
+
result_url = f"{base_url}{str(model_id)}{query_param}"
|
|
136
|
+
|
|
137
|
+
status = response_dict.get("status")
|
|
138
|
+
logger.info("Generating the video.. this can take several minutes.")
|
|
139
|
+
while status != "COMPLETED":
|
|
140
|
+
time.sleep(_POLLING_INTERVAL)
|
|
141
|
+
status_response = get_session().get(status_url, headers=request_params.headers)
|
|
142
|
+
hf_raise_for_status(status_response)
|
|
143
|
+
status = status_response.json().get("status")
|
|
144
|
+
|
|
145
|
+
response = get_session().get(result_url, headers=request_params.headers).json()
|
|
89
146
|
url = _as_dict(response)["video"]["url"]
|
|
90
147
|
return get_session().get(url).content
|
|
@@ -3,4 +3,7 @@ from ._common import BaseConversationalTask
|
|
|
3
3
|
|
|
4
4
|
class FireworksAIConversationalTask(BaseConversationalTask):
|
|
5
5
|
def __init__(self):
|
|
6
|
-
super().__init__(provider="fireworks-ai", base_url="https://api.fireworks.ai
|
|
6
|
+
super().__init__(provider="fireworks-ai", base_url="https://api.fireworks.ai")
|
|
7
|
+
|
|
8
|
+
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
|
|
9
|
+
return "/inference/v1/chat/completions"
|
|
@@ -24,15 +24,16 @@ class HFInferenceTask(TaskProviderHelper):
|
|
|
24
24
|
return api_key or get_token() # type: ignore[return-value]
|
|
25
25
|
|
|
26
26
|
def _prepare_mapped_model(self, model: Optional[str]) -> str:
|
|
27
|
-
if model is not None:
|
|
27
|
+
if model is not None and model.startswith(("http://", "https://")):
|
|
28
28
|
return model
|
|
29
|
-
|
|
30
|
-
if
|
|
29
|
+
model_id = model if model is not None else _fetch_recommended_models().get(self.task)
|
|
30
|
+
if model_id is None:
|
|
31
31
|
raise ValueError(
|
|
32
32
|
f"Task {self.task} has no recommended model for HF Inference. Please specify a model"
|
|
33
33
|
" explicitly. Visit https://huggingface.co/tasks for more info."
|
|
34
34
|
)
|
|
35
|
-
|
|
35
|
+
_check_supported_task(model_id, self.task)
|
|
36
|
+
return model_id
|
|
36
37
|
|
|
37
38
|
def _prepare_url(self, api_key: str, mapped_model: str) -> str:
|
|
38
39
|
# hf-inference provider can handle URLs (e.g. Inference Endpoints or TGI deployment)
|
|
@@ -120,3 +121,39 @@ def _fetch_recommended_models() -> Dict[str, Optional[str]]:
|
|
|
120
121
|
response = get_session().get(f"{constants.ENDPOINT}/api/tasks", headers=build_hf_headers())
|
|
121
122
|
hf_raise_for_status(response)
|
|
122
123
|
return {task: next(iter(details["widgetModels"]), None) for task, details in response.json().items()}
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@lru_cache(maxsize=None)
|
|
127
|
+
def _check_supported_task(model: str, task: str) -> None:
|
|
128
|
+
from huggingface_hub.hf_api import HfApi
|
|
129
|
+
|
|
130
|
+
model_info = HfApi().model_info(model)
|
|
131
|
+
pipeline_tag = model_info.pipeline_tag
|
|
132
|
+
tags = model_info.tags or []
|
|
133
|
+
is_conversational = "conversational" in tags
|
|
134
|
+
if task in ("text-generation", "conversational"):
|
|
135
|
+
if pipeline_tag == "text-generation":
|
|
136
|
+
# text-generation + conversational tag -> both tasks allowed
|
|
137
|
+
if is_conversational:
|
|
138
|
+
return
|
|
139
|
+
# text-generation without conversational tag -> only text-generation allowed
|
|
140
|
+
if task == "text-generation":
|
|
141
|
+
return
|
|
142
|
+
raise ValueError(f"Model '{model}' doesn't support task '{task}'.")
|
|
143
|
+
|
|
144
|
+
if pipeline_tag == "text2text-generation":
|
|
145
|
+
if task == "text-generation":
|
|
146
|
+
return
|
|
147
|
+
raise ValueError(f"Model '{model}' doesn't support task '{task}'.")
|
|
148
|
+
|
|
149
|
+
if pipeline_tag == "image-text-to-text":
|
|
150
|
+
if is_conversational and task == "conversational":
|
|
151
|
+
return # Only conversational allowed if tagged as conversational
|
|
152
|
+
raise ValueError("Non-conversational image-text-to-text task is not supported.")
|
|
153
|
+
|
|
154
|
+
# For all other tasks, just check pipeline tag
|
|
155
|
+
if pipeline_tag != task:
|
|
156
|
+
raise ValueError(
|
|
157
|
+
f"Model '{model}' doesn't support task '{task}'. Supported tasks: '{pipeline_tag}', got: '{task}'"
|
|
158
|
+
)
|
|
159
|
+
return
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import base64
|
|
2
2
|
from typing import Any, Dict, Optional, Union
|
|
3
3
|
|
|
4
|
-
from huggingface_hub.inference._common import _as_dict
|
|
4
|
+
from huggingface_hub.inference._common import RequestParameters, _as_dict
|
|
5
5
|
from huggingface_hub.inference._providers._common import BaseConversationalTask, TaskProviderHelper, filter_none
|
|
6
6
|
|
|
7
7
|
|
|
@@ -9,7 +9,7 @@ class HyperbolicTextToImageTask(TaskProviderHelper):
|
|
|
9
9
|
def __init__(self):
|
|
10
10
|
super().__init__(provider="hyperbolic", base_url="https://api.hyperbolic.xyz", task="text-to-image")
|
|
11
11
|
|
|
12
|
-
def _prepare_route(self, mapped_model: str) -> str:
|
|
12
|
+
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
|
|
13
13
|
return "/v1/images/generations"
|
|
14
14
|
|
|
15
15
|
def _prepare_payload_as_dict(self, inputs: Any, parameters: Dict, mapped_model: str) -> Optional[Dict]:
|
|
@@ -25,7 +25,7 @@ class HyperbolicTextToImageTask(TaskProviderHelper):
|
|
|
25
25
|
parameters["height"] = 512
|
|
26
26
|
return {"prompt": inputs, "model_name": mapped_model, **parameters}
|
|
27
27
|
|
|
28
|
-
def get_response(self, response: Union[bytes, Dict]) -> Any:
|
|
28
|
+
def get_response(self, response: Union[bytes, Dict], request_params: Optional[RequestParameters] = None) -> Any:
|
|
29
29
|
response_dict = _as_dict(response)
|
|
30
30
|
return base64.b64decode(response_dict["images"][0]["image"])
|
|
31
31
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import base64
|
|
2
2
|
from typing import Any, Dict, Optional, Union
|
|
3
3
|
|
|
4
|
-
from huggingface_hub.inference._common import _as_dict
|
|
4
|
+
from huggingface_hub.inference._common import RequestParameters, _as_dict
|
|
5
5
|
from huggingface_hub.inference._providers._common import (
|
|
6
6
|
BaseConversationalTask,
|
|
7
7
|
BaseTextGenerationTask,
|
|
@@ -24,7 +24,7 @@ class NebiusTextToImageTask(TaskProviderHelper):
|
|
|
24
24
|
def __init__(self):
|
|
25
25
|
super().__init__(task="text-to-image", provider="nebius", base_url="https://api.studio.nebius.ai")
|
|
26
26
|
|
|
27
|
-
def _prepare_route(self, mapped_model: str) -> str:
|
|
27
|
+
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
|
|
28
28
|
return "/v1/images/generations"
|
|
29
29
|
|
|
30
30
|
def _prepare_payload_as_dict(self, inputs: Any, parameters: Dict, mapped_model: str) -> Optional[Dict]:
|
|
@@ -36,6 +36,6 @@ class NebiusTextToImageTask(TaskProviderHelper):
|
|
|
36
36
|
|
|
37
37
|
return {"prompt": inputs, **parameters, "model": mapped_model}
|
|
38
38
|
|
|
39
|
-
def get_response(self, response: Union[bytes, Dict]) -> Any:
|
|
39
|
+
def get_response(self, response: Union[bytes, Dict], request_params: Optional[RequestParameters] = None) -> Any:
|
|
40
40
|
response_dict = _as_dict(response)
|
|
41
41
|
return base64.b64decode(response_dict["data"][0]["b64_json"])
|
|
@@ -1,26 +1,56 @@
|
|
|
1
|
+
from typing import Any, Dict, Optional, Union
|
|
2
|
+
|
|
3
|
+
from huggingface_hub.inference._common import RequestParameters, _as_dict
|
|
1
4
|
from huggingface_hub.inference._providers._common import (
|
|
2
5
|
BaseConversationalTask,
|
|
3
6
|
BaseTextGenerationTask,
|
|
7
|
+
TaskProviderHelper,
|
|
8
|
+
filter_none,
|
|
4
9
|
)
|
|
10
|
+
from huggingface_hub.utils import get_session
|
|
5
11
|
|
|
6
12
|
|
|
7
13
|
_PROVIDER = "novita"
|
|
8
|
-
_BASE_URL = "https://api.novita.ai
|
|
14
|
+
_BASE_URL = "https://api.novita.ai"
|
|
9
15
|
|
|
10
16
|
|
|
11
17
|
class NovitaTextGenerationTask(BaseTextGenerationTask):
|
|
12
18
|
def __init__(self):
|
|
13
19
|
super().__init__(provider=_PROVIDER, base_url=_BASE_URL)
|
|
14
20
|
|
|
15
|
-
def _prepare_route(self, mapped_model: str) -> str:
|
|
21
|
+
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
|
|
16
22
|
# there is no v1/ route for novita
|
|
17
|
-
return "/completions"
|
|
23
|
+
return "/v3/openai/completions"
|
|
18
24
|
|
|
19
25
|
|
|
20
26
|
class NovitaConversationalTask(BaseConversationalTask):
|
|
21
27
|
def __init__(self):
|
|
22
28
|
super().__init__(provider=_PROVIDER, base_url=_BASE_URL)
|
|
23
29
|
|
|
24
|
-
def _prepare_route(self, mapped_model: str) -> str:
|
|
30
|
+
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
|
|
25
31
|
# there is no v1/ route for novita
|
|
26
|
-
return "/chat/completions"
|
|
32
|
+
return "/v3/openai/chat/completions"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class NovitaTextToVideoTask(TaskProviderHelper):
|
|
36
|
+
def __init__(self):
|
|
37
|
+
super().__init__(provider=_PROVIDER, base_url=_BASE_URL, task="text-to-video")
|
|
38
|
+
|
|
39
|
+
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
|
|
40
|
+
return f"/v3/hf/{mapped_model}"
|
|
41
|
+
|
|
42
|
+
def _prepare_payload_as_dict(self, inputs: Any, parameters: Dict, mapped_model: str) -> Optional[Dict]:
|
|
43
|
+
return {"prompt": inputs, **filter_none(parameters)}
|
|
44
|
+
|
|
45
|
+
def get_response(self, response: Union[bytes, Dict], request_params: Optional[RequestParameters] = None) -> Any:
|
|
46
|
+
response_dict = _as_dict(response)
|
|
47
|
+
if not (
|
|
48
|
+
isinstance(response_dict, dict)
|
|
49
|
+
and "video" in response_dict
|
|
50
|
+
and isinstance(response_dict["video"], dict)
|
|
51
|
+
and "video_url" in response_dict["video"]
|
|
52
|
+
):
|
|
53
|
+
raise ValueError("Expected response format: { 'video': { 'video_url': string } }")
|
|
54
|
+
|
|
55
|
+
video_url = response_dict["video"]["video_url"]
|
|
56
|
+
return get_session().get(video_url).content
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from huggingface_hub.inference._providers._common import BaseConversationalTask
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class OpenAIConversationalTask(BaseConversationalTask):
|
|
7
|
+
def __init__(self):
|
|
8
|
+
super().__init__(provider="openai", base_url="https://api.openai.com")
|
|
9
|
+
|
|
10
|
+
def _prepare_api_key(self, api_key: Optional[str]) -> str:
|
|
11
|
+
if api_key is None:
|
|
12
|
+
raise ValueError("You must provide an api_key to work with OpenAI API.")
|
|
13
|
+
if api_key.startswith("hf_"):
|
|
14
|
+
raise ValueError(
|
|
15
|
+
"OpenAI provider is not available through Hugging Face routing, please use your own OpenAI API key."
|
|
16
|
+
)
|
|
17
|
+
return api_key
|
|
18
|
+
|
|
19
|
+
def _prepare_mapped_model(self, model: Optional[str]) -> str:
|
|
20
|
+
if model is None:
|
|
21
|
+
raise ValueError("Please provide an OpenAI model ID, e.g. `gpt-4o` or `o1`.")
|
|
22
|
+
return model
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import Any, Dict, Optional, Union
|
|
2
2
|
|
|
3
|
-
from huggingface_hub.inference._common import _as_dict
|
|
3
|
+
from huggingface_hub.inference._common import RequestParameters, _as_dict
|
|
4
4
|
from huggingface_hub.inference._providers._common import TaskProviderHelper, filter_none
|
|
5
5
|
from huggingface_hub.utils import get_session
|
|
6
6
|
|
|
@@ -18,7 +18,7 @@ class ReplicateTask(TaskProviderHelper):
|
|
|
18
18
|
headers["Prefer"] = "wait"
|
|
19
19
|
return headers
|
|
20
20
|
|
|
21
|
-
def _prepare_route(self, mapped_model: str) -> str:
|
|
21
|
+
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
|
|
22
22
|
if ":" in mapped_model:
|
|
23
23
|
return "/v1/predictions"
|
|
24
24
|
return f"/v1/models/{mapped_model}/predictions"
|
|
@@ -30,7 +30,7 @@ class ReplicateTask(TaskProviderHelper):
|
|
|
30
30
|
payload["version"] = version
|
|
31
31
|
return payload
|
|
32
32
|
|
|
33
|
-
def get_response(self, response: Union[bytes, Dict]) -> Any:
|
|
33
|
+
def get_response(self, response: Union[bytes, Dict], request_params: Optional[RequestParameters] = None) -> Any:
|
|
34
34
|
response_dict = _as_dict(response)
|
|
35
35
|
if response_dict.get("output") is None:
|
|
36
36
|
raise TimeoutError(
|
|
@@ -2,7 +2,7 @@ import base64
|
|
|
2
2
|
from abc import ABC
|
|
3
3
|
from typing import Any, Dict, Optional, Union
|
|
4
4
|
|
|
5
|
-
from huggingface_hub.inference._common import _as_dict
|
|
5
|
+
from huggingface_hub.inference._common import RequestParameters, _as_dict
|
|
6
6
|
from huggingface_hub.inference._providers._common import (
|
|
7
7
|
BaseConversationalTask,
|
|
8
8
|
BaseTextGenerationTask,
|
|
@@ -21,7 +21,7 @@ class TogetherTask(TaskProviderHelper, ABC):
|
|
|
21
21
|
def __init__(self, task: str):
|
|
22
22
|
super().__init__(provider=_PROVIDER, base_url=_BASE_URL, task=task)
|
|
23
23
|
|
|
24
|
-
def _prepare_route(self, mapped_model: str) -> str:
|
|
24
|
+
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
|
|
25
25
|
if self.task == "text-to-image":
|
|
26
26
|
return "/v1/images/generations"
|
|
27
27
|
elif self.task == "conversational":
|
|
@@ -54,6 +54,6 @@ class TogetherTextToImageTask(TogetherTask):
|
|
|
54
54
|
|
|
55
55
|
return {"prompt": inputs, "response_format": "base64", **parameters, "model": mapped_model}
|
|
56
56
|
|
|
57
|
-
def get_response(self, response: Union[bytes, Dict]) -> Any:
|
|
57
|
+
def get_response(self, response: Union[bytes, Dict], request_params: Optional[RequestParameters] = None) -> Any:
|
|
58
58
|
response_dict = _as_dict(response)
|
|
59
59
|
return base64.b64decode(response_dict["data"][0]["b64_json"])
|
|
@@ -107,4 +107,12 @@ from ._subprocess import capture_output, run_interactive_subprocess, run_subproc
|
|
|
107
107
|
from ._telemetry import send_telemetry
|
|
108
108
|
from ._typing import is_jsonable, is_simple_optional_type, unwrap_simple_optional_type
|
|
109
109
|
from ._validators import smoothly_deprecate_use_auth_token, validate_hf_hub_args, validate_repo_id
|
|
110
|
+
from ._xet import (
|
|
111
|
+
XetConnectionInfo,
|
|
112
|
+
XetFileData,
|
|
113
|
+
XetTokenType,
|
|
114
|
+
fetch_xet_connection_info_from_repo_info,
|
|
115
|
+
parse_xet_file_data_from_response,
|
|
116
|
+
refresh_xet_connection_info,
|
|
117
|
+
)
|
|
110
118
|
from .tqdm import are_progress_bars_disabled, disable_progress_bars, enable_progress_bars, tqdm, tqdm_stream_file
|
huggingface_hub/utils/_http.py
CHANGED
|
@@ -453,7 +453,8 @@ def hf_raise_for_status(response: Response, endpoint_name: Optional[str] = None)
|
|
|
453
453
|
+ f"Repository Not Found for url: {response.url}."
|
|
454
454
|
+ "\nPlease make sure you specified the correct `repo_id` and"
|
|
455
455
|
" `repo_type`.\nIf you are trying to access a private or gated repo,"
|
|
456
|
-
" make sure you are authenticated."
|
|
456
|
+
" make sure you are authenticated. For more details, see"
|
|
457
|
+
" https://huggingface.co/docs/huggingface_hub/authentication"
|
|
457
458
|
)
|
|
458
459
|
raise _format(RepositoryNotFoundError, message, response) from e
|
|
459
460
|
|
|
@@ -577,6 +578,8 @@ def _curlify(request: requests.PreparedRequest) -> str:
|
|
|
577
578
|
body = request.body
|
|
578
579
|
if isinstance(body, bytes):
|
|
579
580
|
body = body.decode("utf-8", errors="ignore")
|
|
581
|
+
elif hasattr(body, "read"):
|
|
582
|
+
body = "<file-like object>" # Don't try to read it to avoid consuming the stream
|
|
580
583
|
if len(body) > 1000:
|
|
581
584
|
body = body[:1000] + " ... [truncated]"
|
|
582
585
|
parts += [("-d", body.replace("\n", ""))]
|
|
@@ -36,6 +36,7 @@ _CANDIDATES = {
|
|
|
36
36
|
"gradio": {"gradio"},
|
|
37
37
|
"graphviz": {"graphviz"},
|
|
38
38
|
"hf_transfer": {"hf_transfer"},
|
|
39
|
+
"hf_xet": {"hf_xet"},
|
|
39
40
|
"jinja": {"Jinja2"},
|
|
40
41
|
"keras": {"keras"},
|
|
41
42
|
"numpy": {"numpy"},
|
|
@@ -151,6 +152,15 @@ def get_hf_transfer_version() -> str:
|
|
|
151
152
|
return _get_version("hf_transfer")
|
|
152
153
|
|
|
153
154
|
|
|
155
|
+
# xet
|
|
156
|
+
def is_xet_available() -> bool:
|
|
157
|
+
return is_package_available("hf_xet")
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def get_xet_version() -> str:
|
|
161
|
+
return _get_version("hf_xet")
|
|
162
|
+
|
|
163
|
+
|
|
154
164
|
# keras
|
|
155
165
|
def is_keras_available() -> bool:
|
|
156
166
|
return is_package_available("keras")
|
|
@@ -357,6 +367,7 @@ def dump_environment_info() -> Dict[str, Any]:
|
|
|
357
367
|
info["numpy"] = get_numpy_version()
|
|
358
368
|
info["pydantic"] = get_pydantic_version()
|
|
359
369
|
info["aiohttp"] = get_aiohttp_version()
|
|
370
|
+
info["hf_xet"] = get_xet_version()
|
|
360
371
|
|
|
361
372
|
# Environment variables
|
|
362
373
|
info["ENDPOINT"] = constants.ENDPOINT
|