huggingface-hub 0.31.0rc0__py3-none-any.whl → 1.1.3__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.
- huggingface_hub/__init__.py +145 -46
- huggingface_hub/_commit_api.py +168 -119
- huggingface_hub/_commit_scheduler.py +15 -15
- huggingface_hub/_inference_endpoints.py +15 -12
- huggingface_hub/_jobs_api.py +301 -0
- huggingface_hub/_local_folder.py +18 -3
- huggingface_hub/_login.py +31 -63
- huggingface_hub/_oauth.py +460 -0
- huggingface_hub/_snapshot_download.py +239 -80
- huggingface_hub/_space_api.py +5 -5
- huggingface_hub/_tensorboard_logger.py +15 -19
- huggingface_hub/_upload_large_folder.py +172 -76
- huggingface_hub/_webhooks_payload.py +3 -3
- huggingface_hub/_webhooks_server.py +13 -25
- huggingface_hub/{commands → cli}/__init__.py +1 -15
- huggingface_hub/cli/_cli_utils.py +173 -0
- huggingface_hub/cli/auth.py +147 -0
- huggingface_hub/cli/cache.py +841 -0
- huggingface_hub/cli/download.py +189 -0
- huggingface_hub/cli/hf.py +60 -0
- huggingface_hub/cli/inference_endpoints.py +377 -0
- huggingface_hub/cli/jobs.py +772 -0
- huggingface_hub/cli/lfs.py +175 -0
- huggingface_hub/cli/repo.py +315 -0
- huggingface_hub/cli/repo_files.py +94 -0
- huggingface_hub/{commands/env.py → cli/system.py} +10 -13
- huggingface_hub/cli/upload.py +294 -0
- huggingface_hub/cli/upload_large_folder.py +117 -0
- huggingface_hub/community.py +20 -12
- huggingface_hub/constants.py +38 -53
- huggingface_hub/dataclasses.py +609 -0
- huggingface_hub/errors.py +80 -30
- huggingface_hub/fastai_utils.py +30 -41
- huggingface_hub/file_download.py +435 -351
- huggingface_hub/hf_api.py +2050 -1124
- huggingface_hub/hf_file_system.py +269 -152
- huggingface_hub/hub_mixin.py +43 -63
- huggingface_hub/inference/_client.py +347 -434
- huggingface_hub/inference/_common.py +133 -121
- huggingface_hub/inference/_generated/_async_client.py +397 -541
- huggingface_hub/inference/_generated/types/__init__.py +5 -1
- huggingface_hub/inference/_generated/types/automatic_speech_recognition.py +3 -3
- huggingface_hub/inference/_generated/types/base.py +10 -7
- huggingface_hub/inference/_generated/types/chat_completion.py +59 -23
- huggingface_hub/inference/_generated/types/depth_estimation.py +2 -2
- huggingface_hub/inference/_generated/types/document_question_answering.py +2 -2
- huggingface_hub/inference/_generated/types/feature_extraction.py +2 -2
- huggingface_hub/inference/_generated/types/fill_mask.py +2 -2
- huggingface_hub/inference/_generated/types/image_to_image.py +6 -2
- huggingface_hub/inference/_generated/types/image_to_video.py +60 -0
- huggingface_hub/inference/_generated/types/sentence_similarity.py +3 -3
- huggingface_hub/inference/_generated/types/summarization.py +2 -2
- huggingface_hub/inference/_generated/types/table_question_answering.py +5 -5
- huggingface_hub/inference/_generated/types/text2text_generation.py +2 -2
- huggingface_hub/inference/_generated/types/text_generation.py +10 -10
- huggingface_hub/inference/_generated/types/text_to_video.py +2 -2
- huggingface_hub/inference/_generated/types/token_classification.py +2 -2
- huggingface_hub/inference/_generated/types/translation.py +2 -2
- huggingface_hub/inference/_generated/types/zero_shot_classification.py +2 -2
- huggingface_hub/inference/_generated/types/zero_shot_image_classification.py +2 -2
- huggingface_hub/inference/_generated/types/zero_shot_object_detection.py +1 -3
- huggingface_hub/inference/_mcp/__init__.py +0 -0
- huggingface_hub/inference/_mcp/_cli_hacks.py +88 -0
- huggingface_hub/inference/_mcp/agent.py +100 -0
- huggingface_hub/inference/_mcp/cli.py +247 -0
- huggingface_hub/inference/_mcp/constants.py +81 -0
- huggingface_hub/inference/_mcp/mcp_client.py +395 -0
- huggingface_hub/inference/_mcp/types.py +45 -0
- huggingface_hub/inference/_mcp/utils.py +128 -0
- huggingface_hub/inference/_providers/__init__.py +82 -7
- huggingface_hub/inference/_providers/_common.py +129 -27
- huggingface_hub/inference/_providers/black_forest_labs.py +6 -6
- huggingface_hub/inference/_providers/cerebras.py +1 -1
- huggingface_hub/inference/_providers/clarifai.py +13 -0
- huggingface_hub/inference/_providers/cohere.py +20 -3
- huggingface_hub/inference/_providers/fal_ai.py +183 -56
- huggingface_hub/inference/_providers/featherless_ai.py +38 -0
- huggingface_hub/inference/_providers/fireworks_ai.py +18 -0
- huggingface_hub/inference/_providers/groq.py +9 -0
- huggingface_hub/inference/_providers/hf_inference.py +69 -30
- huggingface_hub/inference/_providers/hyperbolic.py +4 -4
- huggingface_hub/inference/_providers/nebius.py +33 -5
- huggingface_hub/inference/_providers/novita.py +5 -5
- huggingface_hub/inference/_providers/nscale.py +44 -0
- huggingface_hub/inference/_providers/openai.py +3 -1
- huggingface_hub/inference/_providers/publicai.py +6 -0
- huggingface_hub/inference/_providers/replicate.py +31 -13
- huggingface_hub/inference/_providers/sambanova.py +18 -4
- huggingface_hub/inference/_providers/scaleway.py +28 -0
- huggingface_hub/inference/_providers/together.py +20 -5
- huggingface_hub/inference/_providers/wavespeed.py +138 -0
- huggingface_hub/inference/_providers/zai_org.py +17 -0
- huggingface_hub/lfs.py +33 -100
- huggingface_hub/repocard.py +34 -38
- huggingface_hub/repocard_data.py +57 -57
- huggingface_hub/serialization/__init__.py +0 -1
- huggingface_hub/serialization/_base.py +12 -15
- huggingface_hub/serialization/_dduf.py +8 -8
- huggingface_hub/serialization/_torch.py +69 -69
- huggingface_hub/utils/__init__.py +19 -8
- huggingface_hub/utils/_auth.py +7 -7
- huggingface_hub/utils/_cache_manager.py +92 -147
- huggingface_hub/utils/_chunk_utils.py +2 -3
- huggingface_hub/utils/_deprecation.py +1 -1
- huggingface_hub/utils/_dotenv.py +55 -0
- huggingface_hub/utils/_experimental.py +7 -5
- huggingface_hub/utils/_fixes.py +0 -10
- huggingface_hub/utils/_git_credential.py +5 -5
- huggingface_hub/utils/_headers.py +8 -30
- huggingface_hub/utils/_http.py +398 -239
- huggingface_hub/utils/_pagination.py +4 -4
- huggingface_hub/utils/_parsing.py +98 -0
- huggingface_hub/utils/_paths.py +5 -5
- huggingface_hub/utils/_runtime.py +61 -24
- huggingface_hub/utils/_safetensors.py +21 -21
- huggingface_hub/utils/_subprocess.py +9 -9
- huggingface_hub/utils/_telemetry.py +4 -4
- huggingface_hub/{commands/_cli_utils.py → utils/_terminal.py} +4 -4
- huggingface_hub/utils/_typing.py +25 -5
- huggingface_hub/utils/_validators.py +55 -74
- huggingface_hub/utils/_verification.py +167 -0
- huggingface_hub/utils/_xet.py +64 -17
- huggingface_hub/utils/_xet_progress_reporting.py +162 -0
- huggingface_hub/utils/insecure_hashlib.py +3 -5
- huggingface_hub/utils/logging.py +8 -11
- huggingface_hub/utils/tqdm.py +5 -4
- {huggingface_hub-0.31.0rc0.dist-info → huggingface_hub-1.1.3.dist-info}/METADATA +94 -85
- huggingface_hub-1.1.3.dist-info/RECORD +155 -0
- {huggingface_hub-0.31.0rc0.dist-info → huggingface_hub-1.1.3.dist-info}/WHEEL +1 -1
- huggingface_hub-1.1.3.dist-info/entry_points.txt +6 -0
- huggingface_hub/commands/delete_cache.py +0 -474
- huggingface_hub/commands/download.py +0 -200
- huggingface_hub/commands/huggingface_cli.py +0 -61
- huggingface_hub/commands/lfs.py +0 -200
- huggingface_hub/commands/repo_files.py +0 -128
- huggingface_hub/commands/scan_cache.py +0 -181
- huggingface_hub/commands/tag.py +0 -159
- huggingface_hub/commands/upload.py +0 -314
- huggingface_hub/commands/upload_large_folder.py +0 -129
- huggingface_hub/commands/user.py +0 -304
- huggingface_hub/commands/version.py +0 -37
- huggingface_hub/inference_api.py +0 -217
- huggingface_hub/keras_mixin.py +0 -500
- huggingface_hub/repository.py +0 -1477
- huggingface_hub/serialization/_tensorflow.py +0 -95
- huggingface_hub/utils/_hf_folder.py +0 -68
- huggingface_hub-0.31.0rc0.dist-info/RECORD +0 -135
- huggingface_hub-0.31.0rc0.dist-info/entry_points.txt +0 -6
- {huggingface_hub-0.31.0rc0.dist-info → huggingface_hub-1.1.3.dist-info/licenses}/LICENSE +0 -0
- {huggingface_hub-0.31.0rc0.dist-info → huggingface_hub-1.1.3.dist-info}/top_level.txt +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import base64
|
|
2
2
|
import time
|
|
3
3
|
from abc import ABC
|
|
4
|
-
from typing import Any,
|
|
4
|
+
from typing import Any, Optional, Union
|
|
5
5
|
from urllib.parse import urlparse
|
|
6
6
|
|
|
7
7
|
from huggingface_hub import constants
|
|
8
8
|
from huggingface_hub.hf_api import InferenceProviderMapping
|
|
9
|
-
from huggingface_hub.inference._common import RequestParameters, _as_dict
|
|
9
|
+
from huggingface_hub.inference._common import RequestParameters, _as_dict, _as_url
|
|
10
10
|
from huggingface_hub.inference._providers._common import TaskProviderHelper, filter_none
|
|
11
11
|
from huggingface_hub.utils import get_session, hf_raise_for_status
|
|
12
12
|
from huggingface_hub.utils.logging import get_logger
|
|
@@ -22,7 +22,7 @@ class FalAITask(TaskProviderHelper, ABC):
|
|
|
22
22
|
def __init__(self, task: str):
|
|
23
23
|
super().__init__(provider="fal-ai", base_url="https://fal.run", task=task)
|
|
24
24
|
|
|
25
|
-
def _prepare_headers(self, headers:
|
|
25
|
+
def _prepare_headers(self, headers: dict, api_key: str) -> dict[str, Any]:
|
|
26
26
|
headers = super()._prepare_headers(headers, api_key)
|
|
27
27
|
if not api_key.startswith("hf_"):
|
|
28
28
|
headers["authorization"] = f"Key {api_key}"
|
|
@@ -32,13 +32,67 @@ class FalAITask(TaskProviderHelper, ABC):
|
|
|
32
32
|
return f"/{mapped_model}"
|
|
33
33
|
|
|
34
34
|
|
|
35
|
+
class FalAIQueueTask(TaskProviderHelper, ABC):
|
|
36
|
+
def __init__(self, task: str):
|
|
37
|
+
super().__init__(provider="fal-ai", base_url="https://queue.fal.run", task=task)
|
|
38
|
+
|
|
39
|
+
def _prepare_headers(self, headers: dict, api_key: str) -> dict[str, Any]:
|
|
40
|
+
headers = super()._prepare_headers(headers, api_key)
|
|
41
|
+
if not api_key.startswith("hf_"):
|
|
42
|
+
headers["authorization"] = f"Key {api_key}"
|
|
43
|
+
return headers
|
|
44
|
+
|
|
45
|
+
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
|
|
46
|
+
if api_key.startswith("hf_"):
|
|
47
|
+
# Use the queue subdomain for HF routing
|
|
48
|
+
return f"/{mapped_model}?_subdomain=queue"
|
|
49
|
+
return f"/{mapped_model}"
|
|
50
|
+
|
|
51
|
+
def get_response(
|
|
52
|
+
self,
|
|
53
|
+
response: Union[bytes, dict],
|
|
54
|
+
request_params: Optional[RequestParameters] = None,
|
|
55
|
+
) -> Any:
|
|
56
|
+
response_dict = _as_dict(response)
|
|
57
|
+
|
|
58
|
+
request_id = response_dict.get("request_id")
|
|
59
|
+
if not request_id:
|
|
60
|
+
raise ValueError("No request ID found in the response")
|
|
61
|
+
if request_params is None:
|
|
62
|
+
raise ValueError(
|
|
63
|
+
f"A `RequestParameters` object should be provided to get {self.task} responses with Fal AI."
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# extract the base url and query params
|
|
67
|
+
parsed_url = urlparse(request_params.url)
|
|
68
|
+
# a bit hacky way to concatenate the provider name without parsing `parsed_url.path`
|
|
69
|
+
base_url = f"{parsed_url.scheme}://{parsed_url.netloc}{'/fal-ai' if parsed_url.netloc == 'router.huggingface.co' else ''}"
|
|
70
|
+
query_param = f"?{parsed_url.query}" if parsed_url.query else ""
|
|
71
|
+
|
|
72
|
+
# extracting the provider model id for status and result urls
|
|
73
|
+
# from the response as it might be different from the mapped model in `request_params.url`
|
|
74
|
+
model_id = urlparse(response_dict.get("response_url")).path
|
|
75
|
+
status_url = f"{base_url}{str(model_id)}/status{query_param}"
|
|
76
|
+
result_url = f"{base_url}{str(model_id)}{query_param}"
|
|
77
|
+
|
|
78
|
+
status = response_dict.get("status")
|
|
79
|
+
logger.info("Generating the output.. this can take several minutes.")
|
|
80
|
+
while status != "COMPLETED":
|
|
81
|
+
time.sleep(_POLLING_INTERVAL)
|
|
82
|
+
status_response = get_session().get(status_url, headers=request_params.headers)
|
|
83
|
+
hf_raise_for_status(status_response)
|
|
84
|
+
status = status_response.json().get("status")
|
|
85
|
+
|
|
86
|
+
return get_session().get(result_url, headers=request_params.headers).json()
|
|
87
|
+
|
|
88
|
+
|
|
35
89
|
class FalAIAutomaticSpeechRecognitionTask(FalAITask):
|
|
36
90
|
def __init__(self):
|
|
37
91
|
super().__init__("automatic-speech-recognition")
|
|
38
92
|
|
|
39
93
|
def _prepare_payload_as_dict(
|
|
40
|
-
self, inputs: Any, parameters:
|
|
41
|
-
) -> Optional[
|
|
94
|
+
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
|
|
95
|
+
) -> Optional[dict]:
|
|
42
96
|
if isinstance(inputs, str) and inputs.startswith(("http://", "https://")):
|
|
43
97
|
# If input is a URL, pass it directly
|
|
44
98
|
audio_url = inputs
|
|
@@ -54,7 +108,7 @@ class FalAIAutomaticSpeechRecognitionTask(FalAITask):
|
|
|
54
108
|
|
|
55
109
|
return {"audio_url": audio_url, **filter_none(parameters)}
|
|
56
110
|
|
|
57
|
-
def get_response(self, response: Union[bytes,
|
|
111
|
+
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
|
|
58
112
|
text = _as_dict(response)["text"]
|
|
59
113
|
if not isinstance(text, str):
|
|
60
114
|
raise ValueError(f"Unexpected output format from FalAI API. Expected string, got {type(text)}.")
|
|
@@ -66,9 +120,9 @@ class FalAITextToImageTask(FalAITask):
|
|
|
66
120
|
super().__init__("text-to-image")
|
|
67
121
|
|
|
68
122
|
def _prepare_payload_as_dict(
|
|
69
|
-
self, inputs: Any, parameters:
|
|
70
|
-
) -> Optional[
|
|
71
|
-
payload:
|
|
123
|
+
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
|
|
124
|
+
) -> Optional[dict]:
|
|
125
|
+
payload: dict[str, Any] = {
|
|
72
126
|
"prompt": inputs,
|
|
73
127
|
**filter_none(parameters),
|
|
74
128
|
}
|
|
@@ -91,7 +145,7 @@ class FalAITextToImageTask(FalAITask):
|
|
|
91
145
|
|
|
92
146
|
return payload
|
|
93
147
|
|
|
94
|
-
def get_response(self, response: Union[bytes,
|
|
148
|
+
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
|
|
95
149
|
url = _as_dict(response)["images"][0]["url"]
|
|
96
150
|
return get_session().get(url).content
|
|
97
151
|
|
|
@@ -101,72 +155,145 @@ class FalAITextToSpeechTask(FalAITask):
|
|
|
101
155
|
super().__init__("text-to-speech")
|
|
102
156
|
|
|
103
157
|
def _prepare_payload_as_dict(
|
|
104
|
-
self, inputs: Any, parameters:
|
|
105
|
-
) -> Optional[
|
|
158
|
+
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
|
|
159
|
+
) -> Optional[dict]:
|
|
106
160
|
return {"text": inputs, **filter_none(parameters)}
|
|
107
161
|
|
|
108
|
-
def get_response(self, response: Union[bytes,
|
|
162
|
+
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
|
|
109
163
|
url = _as_dict(response)["audio"]["url"]
|
|
110
164
|
return get_session().get(url).content
|
|
111
165
|
|
|
112
166
|
|
|
113
|
-
class FalAITextToVideoTask(
|
|
167
|
+
class FalAITextToVideoTask(FalAIQueueTask):
|
|
114
168
|
def __init__(self):
|
|
115
169
|
super().__init__("text-to-video")
|
|
116
170
|
|
|
117
|
-
def _prepare_base_url(self, api_key: str) -> str:
|
|
118
|
-
if api_key.startswith("hf_"):
|
|
119
|
-
return super()._prepare_base_url(api_key)
|
|
120
|
-
else:
|
|
121
|
-
logger.info(f"Calling '{self.provider}' provider directly.")
|
|
122
|
-
return "https://queue.fal.run"
|
|
123
|
-
|
|
124
|
-
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
|
|
125
|
-
if api_key.startswith("hf_"):
|
|
126
|
-
# Use the queue subdomain for HF routing
|
|
127
|
-
return f"/{mapped_model}?_subdomain=queue"
|
|
128
|
-
return f"/{mapped_model}"
|
|
129
|
-
|
|
130
171
|
def _prepare_payload_as_dict(
|
|
131
|
-
self, inputs: Any, parameters:
|
|
132
|
-
) -> Optional[
|
|
172
|
+
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
|
|
173
|
+
) -> Optional[dict]:
|
|
133
174
|
return {"prompt": inputs, **filter_none(parameters)}
|
|
134
175
|
|
|
135
176
|
def get_response(
|
|
136
177
|
self,
|
|
137
|
-
response: Union[bytes,
|
|
178
|
+
response: Union[bytes, dict],
|
|
138
179
|
request_params: Optional[RequestParameters] = None,
|
|
139
180
|
) -> Any:
|
|
140
|
-
|
|
181
|
+
output = super().get_response(response, request_params)
|
|
182
|
+
url = _as_dict(output)["video"]["url"]
|
|
183
|
+
return get_session().get(url).content
|
|
141
184
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
185
|
+
|
|
186
|
+
class FalAIImageToImageTask(FalAIQueueTask):
|
|
187
|
+
def __init__(self):
|
|
188
|
+
super().__init__("image-to-image")
|
|
189
|
+
|
|
190
|
+
def _prepare_payload_as_dict(
|
|
191
|
+
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
|
|
192
|
+
) -> Optional[dict]:
|
|
193
|
+
image_url = _as_url(inputs, default_mime_type="image/jpeg")
|
|
194
|
+
if "target_size" in parameters:
|
|
195
|
+
parameters["image_size"] = parameters.pop("target_size")
|
|
196
|
+
payload: dict[str, Any] = {
|
|
197
|
+
"image_url": image_url,
|
|
198
|
+
**filter_none(parameters),
|
|
199
|
+
}
|
|
200
|
+
if provider_mapping_info.adapter_weights_path is not None:
|
|
201
|
+
lora_path = constants.HUGGINGFACE_CO_URL_TEMPLATE.format(
|
|
202
|
+
repo_id=provider_mapping_info.hf_model_id,
|
|
203
|
+
revision="main",
|
|
204
|
+
filename=provider_mapping_info.adapter_weights_path,
|
|
148
205
|
)
|
|
206
|
+
payload["loras"] = [{"path": lora_path, "scale": 1}]
|
|
149
207
|
|
|
150
|
-
|
|
151
|
-
parsed_url = urlparse(request_params.url)
|
|
152
|
-
# a bit hacky way to concatenate the provider name without parsing `parsed_url.path`
|
|
153
|
-
base_url = f"{parsed_url.scheme}://{parsed_url.netloc}{'/fal-ai' if parsed_url.netloc == 'router.huggingface.co' else ''}"
|
|
154
|
-
query_param = f"?{parsed_url.query}" if parsed_url.query else ""
|
|
208
|
+
return payload
|
|
155
209
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
210
|
+
def get_response(
|
|
211
|
+
self,
|
|
212
|
+
response: Union[bytes, dict],
|
|
213
|
+
request_params: Optional[RequestParameters] = None,
|
|
214
|
+
) -> Any:
|
|
215
|
+
output = super().get_response(response, request_params)
|
|
216
|
+
url = _as_dict(output)["images"][0]["url"]
|
|
217
|
+
return get_session().get(url).content
|
|
161
218
|
|
|
162
|
-
status = response_dict.get("status")
|
|
163
|
-
logger.info("Generating the video.. this can take several minutes.")
|
|
164
|
-
while status != "COMPLETED":
|
|
165
|
-
time.sleep(_POLLING_INTERVAL)
|
|
166
|
-
status_response = get_session().get(status_url, headers=request_params.headers)
|
|
167
|
-
hf_raise_for_status(status_response)
|
|
168
|
-
status = status_response.json().get("status")
|
|
169
219
|
|
|
170
|
-
|
|
171
|
-
|
|
220
|
+
class FalAIImageToVideoTask(FalAIQueueTask):
|
|
221
|
+
def __init__(self):
|
|
222
|
+
super().__init__("image-to-video")
|
|
223
|
+
|
|
224
|
+
def _prepare_payload_as_dict(
|
|
225
|
+
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
|
|
226
|
+
) -> Optional[dict]:
|
|
227
|
+
image_url = _as_url(inputs, default_mime_type="image/jpeg")
|
|
228
|
+
payload: dict[str, Any] = {
|
|
229
|
+
"image_url": image_url,
|
|
230
|
+
**filter_none(parameters),
|
|
231
|
+
}
|
|
232
|
+
if provider_mapping_info.adapter_weights_path is not None:
|
|
233
|
+
lora_path = constants.HUGGINGFACE_CO_URL_TEMPLATE.format(
|
|
234
|
+
repo_id=provider_mapping_info.hf_model_id,
|
|
235
|
+
revision="main",
|
|
236
|
+
filename=provider_mapping_info.adapter_weights_path,
|
|
237
|
+
)
|
|
238
|
+
payload["loras"] = [{"path": lora_path, "scale": 1}]
|
|
239
|
+
return payload
|
|
240
|
+
|
|
241
|
+
def get_response(
|
|
242
|
+
self,
|
|
243
|
+
response: Union[bytes, dict],
|
|
244
|
+
request_params: Optional[RequestParameters] = None,
|
|
245
|
+
) -> Any:
|
|
246
|
+
output = super().get_response(response, request_params)
|
|
247
|
+
url = _as_dict(output)["video"]["url"]
|
|
172
248
|
return get_session().get(url).content
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
class FalAIImageSegmentationTask(FalAIQueueTask):
|
|
252
|
+
def __init__(self):
|
|
253
|
+
super().__init__("image-segmentation")
|
|
254
|
+
|
|
255
|
+
def _prepare_payload_as_dict(
|
|
256
|
+
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
|
|
257
|
+
) -> Optional[dict]:
|
|
258
|
+
image_url = _as_url(inputs, default_mime_type="image/png")
|
|
259
|
+
payload: dict[str, Any] = {
|
|
260
|
+
"image_url": image_url,
|
|
261
|
+
**filter_none(parameters),
|
|
262
|
+
"sync_mode": True,
|
|
263
|
+
}
|
|
264
|
+
return payload
|
|
265
|
+
|
|
266
|
+
def get_response(
|
|
267
|
+
self,
|
|
268
|
+
response: Union[bytes, dict],
|
|
269
|
+
request_params: Optional[RequestParameters] = None,
|
|
270
|
+
) -> Any:
|
|
271
|
+
result = super().get_response(response, request_params)
|
|
272
|
+
result_dict = _as_dict(result)
|
|
273
|
+
|
|
274
|
+
if "image" not in result_dict:
|
|
275
|
+
raise ValueError(f"Response from fal ai image-segmentation API does not contain an image: {result_dict}")
|
|
276
|
+
|
|
277
|
+
image_data = result_dict["image"]
|
|
278
|
+
if "url" not in image_data:
|
|
279
|
+
raise ValueError(f"Image data from fal ai image-segmentation API does not contain a URL: {image_data}")
|
|
280
|
+
|
|
281
|
+
image_url = image_data["url"]
|
|
282
|
+
|
|
283
|
+
if isinstance(image_url, str) and image_url.startswith("data:"):
|
|
284
|
+
if "," in image_url:
|
|
285
|
+
mask_base64 = image_url.split(",", 1)[1]
|
|
286
|
+
else:
|
|
287
|
+
raise ValueError(f"Invalid data URL format: {image_url}")
|
|
288
|
+
else:
|
|
289
|
+
# or it's a regular URL, fetch it
|
|
290
|
+
mask_response = get_session().get(image_url)
|
|
291
|
+
hf_raise_for_status(mask_response)
|
|
292
|
+
mask_base64 = base64.b64encode(mask_response.content).decode()
|
|
293
|
+
|
|
294
|
+
return [
|
|
295
|
+
{
|
|
296
|
+
"label": "mask",
|
|
297
|
+
"mask": mask_base64,
|
|
298
|
+
}
|
|
299
|
+
]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from typing import Any, Optional, Union
|
|
2
|
+
|
|
3
|
+
from huggingface_hub.hf_api import InferenceProviderMapping
|
|
4
|
+
from huggingface_hub.inference._common import RequestParameters, _as_dict
|
|
5
|
+
|
|
6
|
+
from ._common import BaseConversationalTask, BaseTextGenerationTask, filter_none
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
_PROVIDER = "featherless-ai"
|
|
10
|
+
_BASE_URL = "https://api.featherless.ai"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class FeatherlessTextGenerationTask(BaseTextGenerationTask):
|
|
14
|
+
def __init__(self):
|
|
15
|
+
super().__init__(provider=_PROVIDER, base_url=_BASE_URL)
|
|
16
|
+
|
|
17
|
+
def _prepare_payload_as_dict(
|
|
18
|
+
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
|
|
19
|
+
) -> Optional[dict]:
|
|
20
|
+
params = filter_none(parameters.copy())
|
|
21
|
+
params["max_tokens"] = params.pop("max_new_tokens", None)
|
|
22
|
+
|
|
23
|
+
return {"prompt": inputs, **params, "model": provider_mapping_info.provider_id}
|
|
24
|
+
|
|
25
|
+
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
|
|
26
|
+
output = _as_dict(response)["choices"][0]
|
|
27
|
+
return {
|
|
28
|
+
"generated_text": output["text"],
|
|
29
|
+
"details": {
|
|
30
|
+
"finish_reason": output.get("finish_reason"),
|
|
31
|
+
"seed": output.get("seed"),
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class FeatherlessConversationalTask(BaseConversationalTask):
|
|
37
|
+
def __init__(self):
|
|
38
|
+
super().__init__(provider=_PROVIDER, base_url=_BASE_URL)
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
from typing import Any, Optional
|
|
2
|
+
|
|
3
|
+
from huggingface_hub.hf_api import InferenceProviderMapping
|
|
4
|
+
|
|
1
5
|
from ._common import BaseConversationalTask
|
|
2
6
|
|
|
3
7
|
|
|
@@ -7,3 +11,17 @@ class FireworksAIConversationalTask(BaseConversationalTask):
|
|
|
7
11
|
|
|
8
12
|
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
|
|
9
13
|
return "/inference/v1/chat/completions"
|
|
14
|
+
|
|
15
|
+
def _prepare_payload_as_dict(
|
|
16
|
+
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
|
|
17
|
+
) -> Optional[dict]:
|
|
18
|
+
payload = super()._prepare_payload_as_dict(inputs, parameters, provider_mapping_info)
|
|
19
|
+
response_format = parameters.get("response_format")
|
|
20
|
+
if isinstance(response_format, dict) and response_format.get("type") == "json_schema":
|
|
21
|
+
json_schema_details = response_format.get("json_schema")
|
|
22
|
+
if isinstance(json_schema_details, dict) and "schema" in json_schema_details:
|
|
23
|
+
payload["response_format"] = { # type: ignore [index]
|
|
24
|
+
"type": "json_object",
|
|
25
|
+
"schema": json_schema_details["schema"],
|
|
26
|
+
}
|
|
27
|
+
return payload
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from ._common import BaseConversationalTask
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class GroqConversationalTask(BaseConversationalTask):
|
|
5
|
+
def __init__(self):
|
|
6
|
+
super().__init__(provider="groq", base_url="https://api.groq.com")
|
|
7
|
+
|
|
8
|
+
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
|
|
9
|
+
return "/openai/v1/chat/completions"
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from functools import lru_cache
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from typing import Any,
|
|
4
|
+
from typing import Any, Optional, Union
|
|
5
|
+
from urllib.parse import urlparse, urlunparse
|
|
5
6
|
|
|
6
7
|
from huggingface_hub import constants
|
|
7
8
|
from huggingface_hub.hf_api import InferenceProviderMapping
|
|
8
|
-
from huggingface_hub.inference._common import
|
|
9
|
+
from huggingface_hub.inference._common import (
|
|
10
|
+
MimeBytes,
|
|
11
|
+
RequestParameters,
|
|
12
|
+
_b64_encode,
|
|
13
|
+
_bytes_to_dict,
|
|
14
|
+
_open_as_mime_bytes,
|
|
15
|
+
)
|
|
9
16
|
from huggingface_hub.inference._providers._common import TaskProviderHelper, filter_none
|
|
10
17
|
from huggingface_hub.utils import build_hf_headers, get_session, get_token, hf_raise_for_status
|
|
11
18
|
|
|
@@ -26,7 +33,9 @@ class HFInferenceTask(TaskProviderHelper):
|
|
|
26
33
|
|
|
27
34
|
def _prepare_mapping_info(self, model: Optional[str]) -> InferenceProviderMapping:
|
|
28
35
|
if model is not None and model.startswith(("http://", "https://")):
|
|
29
|
-
return InferenceProviderMapping(
|
|
36
|
+
return InferenceProviderMapping(
|
|
37
|
+
provider="hf-inference", providerId=model, hf_model_id=model, task=self.task, status="live"
|
|
38
|
+
)
|
|
30
39
|
model_id = model if model is not None else _fetch_recommended_models().get(self.task)
|
|
31
40
|
if model_id is None:
|
|
32
41
|
raise ValueError(
|
|
@@ -34,7 +43,9 @@ class HFInferenceTask(TaskProviderHelper):
|
|
|
34
43
|
" explicitly. Visit https://huggingface.co/tasks for more info."
|
|
35
44
|
)
|
|
36
45
|
_check_supported_task(model_id, self.task)
|
|
37
|
-
return InferenceProviderMapping(
|
|
46
|
+
return InferenceProviderMapping(
|
|
47
|
+
provider="hf-inference", providerId=model_id, hf_model_id=model_id, task=self.task, status="live"
|
|
48
|
+
)
|
|
38
49
|
|
|
39
50
|
def _prepare_url(self, api_key: str, mapped_model: str) -> str:
|
|
40
51
|
# hf-inference provider can handle URLs (e.g. Inference Endpoints or TGI deployment)
|
|
@@ -49,29 +60,29 @@ class HFInferenceTask(TaskProviderHelper):
|
|
|
49
60
|
)
|
|
50
61
|
|
|
51
62
|
def _prepare_payload_as_dict(
|
|
52
|
-
self, inputs: Any, parameters:
|
|
53
|
-
) -> Optional[
|
|
63
|
+
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
|
|
64
|
+
) -> Optional[dict]:
|
|
54
65
|
if isinstance(inputs, bytes):
|
|
55
66
|
raise ValueError(f"Unexpected binary input for task {self.task}.")
|
|
56
67
|
if isinstance(inputs, Path):
|
|
57
68
|
raise ValueError(f"Unexpected path input for task {self.task} (got {inputs})")
|
|
58
|
-
return {"inputs": inputs, "parameters":
|
|
69
|
+
return filter_none({"inputs": inputs, "parameters": parameters})
|
|
59
70
|
|
|
60
71
|
|
|
61
72
|
class HFInferenceBinaryInputTask(HFInferenceTask):
|
|
62
73
|
def _prepare_payload_as_dict(
|
|
63
|
-
self, inputs: Any, parameters:
|
|
64
|
-
) -> Optional[
|
|
74
|
+
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
|
|
75
|
+
) -> Optional[dict]:
|
|
65
76
|
return None
|
|
66
77
|
|
|
67
78
|
def _prepare_payload_as_bytes(
|
|
68
79
|
self,
|
|
69
80
|
inputs: Any,
|
|
70
|
-
parameters:
|
|
81
|
+
parameters: dict,
|
|
71
82
|
provider_mapping_info: InferenceProviderMapping,
|
|
72
|
-
extra_payload: Optional[
|
|
73
|
-
) -> Optional[
|
|
74
|
-
parameters = filter_none(
|
|
83
|
+
extra_payload: Optional[dict],
|
|
84
|
+
) -> Optional[MimeBytes]:
|
|
85
|
+
parameters = filter_none(parameters)
|
|
75
86
|
extra_payload = extra_payload or {}
|
|
76
87
|
has_parameters = len(parameters) > 0 or len(extra_payload) > 0
|
|
77
88
|
|
|
@@ -81,12 +92,13 @@ class HFInferenceBinaryInputTask(HFInferenceTask):
|
|
|
81
92
|
|
|
82
93
|
# Send inputs as raw content when no parameters are provided
|
|
83
94
|
if not has_parameters:
|
|
84
|
-
|
|
85
|
-
data_as_bytes = data if isinstance(data, bytes) else data.read()
|
|
86
|
-
return data_as_bytes
|
|
95
|
+
return _open_as_mime_bytes(inputs)
|
|
87
96
|
|
|
88
97
|
# Otherwise encode as b64
|
|
89
|
-
return
|
|
98
|
+
return MimeBytes(
|
|
99
|
+
json.dumps({"inputs": _b64_encode(inputs), "parameters": parameters, **extra_payload}).encode("utf-8"),
|
|
100
|
+
mime_type="application/json",
|
|
101
|
+
)
|
|
90
102
|
|
|
91
103
|
|
|
92
104
|
class HFInferenceConversational(HFInferenceTask):
|
|
@@ -94,15 +106,22 @@ class HFInferenceConversational(HFInferenceTask):
|
|
|
94
106
|
super().__init__("conversational")
|
|
95
107
|
|
|
96
108
|
def _prepare_payload_as_dict(
|
|
97
|
-
self, inputs: Any, parameters:
|
|
98
|
-
) -> Optional[
|
|
109
|
+
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
|
|
110
|
+
) -> Optional[dict]:
|
|
111
|
+
payload = filter_none(parameters)
|
|
99
112
|
mapped_model = provider_mapping_info.provider_id
|
|
100
113
|
payload_model = parameters.get("model") or mapped_model
|
|
101
114
|
|
|
102
115
|
if payload_model is None or payload_model.startswith(("http://", "https://")):
|
|
103
116
|
payload_model = "dummy"
|
|
104
117
|
|
|
105
|
-
|
|
118
|
+
response_format = parameters.get("response_format")
|
|
119
|
+
if isinstance(response_format, dict) and response_format.get("type") == "json_schema":
|
|
120
|
+
payload["response_format"] = {
|
|
121
|
+
"type": "json_object",
|
|
122
|
+
"value": response_format["json_schema"]["schema"],
|
|
123
|
+
}
|
|
124
|
+
return {**payload, "model": payload_model, "messages": inputs}
|
|
106
125
|
|
|
107
126
|
def _prepare_url(self, api_key: str, mapped_model: str) -> str:
|
|
108
127
|
base_url = (
|
|
@@ -114,22 +133,30 @@ class HFInferenceConversational(HFInferenceTask):
|
|
|
114
133
|
|
|
115
134
|
|
|
116
135
|
def _build_chat_completion_url(model_url: str) -> str:
|
|
117
|
-
|
|
118
|
-
|
|
136
|
+
parsed = urlparse(model_url)
|
|
137
|
+
path = parsed.path.rstrip("/")
|
|
119
138
|
|
|
120
|
-
#
|
|
121
|
-
if
|
|
122
|
-
model_url
|
|
139
|
+
# If the path already ends with /chat/completions, we're done!
|
|
140
|
+
if path.endswith("/chat/completions"):
|
|
141
|
+
return model_url
|
|
123
142
|
|
|
143
|
+
# Append /chat/completions if not already present
|
|
144
|
+
if path.endswith("/v1"):
|
|
145
|
+
new_path = path + "/chat/completions"
|
|
146
|
+
# If path was empty or just "/", set the full path
|
|
147
|
+
elif not path:
|
|
148
|
+
new_path = "/v1/chat/completions"
|
|
124
149
|
# Append /v1/chat/completions if not already present
|
|
125
|
-
|
|
126
|
-
|
|
150
|
+
else:
|
|
151
|
+
new_path = path + "/v1/chat/completions"
|
|
127
152
|
|
|
128
|
-
|
|
153
|
+
# Reconstruct the URL with the new path and original query parameters.
|
|
154
|
+
new_parsed = parsed._replace(path=new_path)
|
|
155
|
+
return str(urlunparse(new_parsed))
|
|
129
156
|
|
|
130
157
|
|
|
131
158
|
@lru_cache(maxsize=1)
|
|
132
|
-
def _fetch_recommended_models() ->
|
|
159
|
+
def _fetch_recommended_models() -> dict[str, Optional[str]]:
|
|
133
160
|
response = get_session().get(f"{constants.ENDPOINT}/api/tasks", headers=build_hf_headers())
|
|
134
161
|
hf_raise_for_status(response)
|
|
135
162
|
return {task: next(iter(details["widgetModels"]), None) for task, details in response.json().items()}
|
|
@@ -183,7 +210,19 @@ class HFInferenceFeatureExtractionTask(HFInferenceTask):
|
|
|
183
210
|
def __init__(self):
|
|
184
211
|
super().__init__("feature-extraction")
|
|
185
212
|
|
|
186
|
-
def
|
|
213
|
+
def _prepare_payload_as_dict(
|
|
214
|
+
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
|
|
215
|
+
) -> Optional[dict]:
|
|
216
|
+
if isinstance(inputs, bytes):
|
|
217
|
+
raise ValueError(f"Unexpected binary input for task {self.task}.")
|
|
218
|
+
if isinstance(inputs, Path):
|
|
219
|
+
raise ValueError(f"Unexpected path input for task {self.task} (got {inputs})")
|
|
220
|
+
|
|
221
|
+
# Parameters are sent at root-level for feature-extraction task
|
|
222
|
+
# See specs: https://github.com/huggingface/huggingface.js/blob/main/packages/tasks/src/tasks/feature-extraction/spec/input.json
|
|
223
|
+
return {"inputs": inputs, **filter_none(parameters)}
|
|
224
|
+
|
|
225
|
+
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
|
|
187
226
|
if isinstance(response, bytes):
|
|
188
227
|
return _bytes_to_dict(response)
|
|
189
228
|
return response
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import base64
|
|
2
|
-
from typing import Any,
|
|
2
|
+
from typing import Any, Optional, Union
|
|
3
3
|
|
|
4
4
|
from huggingface_hub.hf_api import InferenceProviderMapping
|
|
5
5
|
from huggingface_hub.inference._common import RequestParameters, _as_dict
|
|
@@ -14,8 +14,8 @@ class HyperbolicTextToImageTask(TaskProviderHelper):
|
|
|
14
14
|
return "/v1/images/generations"
|
|
15
15
|
|
|
16
16
|
def _prepare_payload_as_dict(
|
|
17
|
-
self, inputs: Any, parameters:
|
|
18
|
-
) -> Optional[
|
|
17
|
+
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
|
|
18
|
+
) -> Optional[dict]:
|
|
19
19
|
mapped_model = provider_mapping_info.provider_id
|
|
20
20
|
parameters = filter_none(parameters)
|
|
21
21
|
if "num_inference_steps" in parameters:
|
|
@@ -29,7 +29,7 @@ class HyperbolicTextToImageTask(TaskProviderHelper):
|
|
|
29
29
|
parameters["height"] = 512
|
|
30
30
|
return {"prompt": inputs, "model_name": mapped_model, **parameters}
|
|
31
31
|
|
|
32
|
-
def get_response(self, response: Union[bytes,
|
|
32
|
+
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
|
|
33
33
|
response_dict = _as_dict(response)
|
|
34
34
|
return base64.b64decode(response_dict["images"][0]["image"])
|
|
35
35
|
|