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,18 +1,27 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import Literal, Optional, Union
|
|
2
2
|
|
|
3
|
+
from huggingface_hub.inference._providers.featherless_ai import (
|
|
4
|
+
FeatherlessConversationalTask,
|
|
5
|
+
FeatherlessTextGenerationTask,
|
|
6
|
+
)
|
|
3
7
|
from huggingface_hub.utils import logging
|
|
4
8
|
|
|
5
|
-
from ._common import TaskProviderHelper, _fetch_inference_provider_mapping
|
|
9
|
+
from ._common import AutoRouterConversationalTask, TaskProviderHelper, _fetch_inference_provider_mapping
|
|
6
10
|
from .black_forest_labs import BlackForestLabsTextToImageTask
|
|
7
11
|
from .cerebras import CerebrasConversationalTask
|
|
12
|
+
from .clarifai import ClarifaiConversationalTask
|
|
8
13
|
from .cohere import CohereConversationalTask
|
|
9
14
|
from .fal_ai import (
|
|
10
15
|
FalAIAutomaticSpeechRecognitionTask,
|
|
16
|
+
FalAIImageSegmentationTask,
|
|
17
|
+
FalAIImageToImageTask,
|
|
18
|
+
FalAIImageToVideoTask,
|
|
11
19
|
FalAITextToImageTask,
|
|
12
20
|
FalAITextToSpeechTask,
|
|
13
21
|
FalAITextToVideoTask,
|
|
14
22
|
)
|
|
15
23
|
from .fireworks_ai import FireworksAIConversationalTask
|
|
24
|
+
from .groq import GroqConversationalTask
|
|
16
25
|
from .hf_inference import (
|
|
17
26
|
HFInferenceBinaryInputTask,
|
|
18
27
|
HFInferenceConversational,
|
|
@@ -20,12 +29,27 @@ from .hf_inference import (
|
|
|
20
29
|
HFInferenceTask,
|
|
21
30
|
)
|
|
22
31
|
from .hyperbolic import HyperbolicTextGenerationTask, HyperbolicTextToImageTask
|
|
23
|
-
from .nebius import
|
|
32
|
+
from .nebius import (
|
|
33
|
+
NebiusConversationalTask,
|
|
34
|
+
NebiusFeatureExtractionTask,
|
|
35
|
+
NebiusTextGenerationTask,
|
|
36
|
+
NebiusTextToImageTask,
|
|
37
|
+
)
|
|
24
38
|
from .novita import NovitaConversationalTask, NovitaTextGenerationTask, NovitaTextToVideoTask
|
|
39
|
+
from .nscale import NscaleConversationalTask, NscaleTextToImageTask
|
|
25
40
|
from .openai import OpenAIConversationalTask
|
|
26
|
-
from .
|
|
41
|
+
from .publicai import PublicAIConversationalTask
|
|
42
|
+
from .replicate import ReplicateImageToImageTask, ReplicateTask, ReplicateTextToImageTask, ReplicateTextToSpeechTask
|
|
27
43
|
from .sambanova import SambanovaConversationalTask, SambanovaFeatureExtractionTask
|
|
44
|
+
from .scaleway import ScalewayConversationalTask, ScalewayFeatureExtractionTask
|
|
28
45
|
from .together import TogetherConversationalTask, TogetherTextGenerationTask, TogetherTextToImageTask
|
|
46
|
+
from .wavespeed import (
|
|
47
|
+
WavespeedAIImageToImageTask,
|
|
48
|
+
WavespeedAIImageToVideoTask,
|
|
49
|
+
WavespeedAITextToImageTask,
|
|
50
|
+
WavespeedAITextToVideoTask,
|
|
51
|
+
)
|
|
52
|
+
from .zai_org import ZaiConversationalTask
|
|
29
53
|
|
|
30
54
|
|
|
31
55
|
logger = logging.get_logger(__name__)
|
|
@@ -34,28 +58,41 @@ logger = logging.get_logger(__name__)
|
|
|
34
58
|
PROVIDER_T = Literal[
|
|
35
59
|
"black-forest-labs",
|
|
36
60
|
"cerebras",
|
|
61
|
+
"clarifai",
|
|
37
62
|
"cohere",
|
|
38
63
|
"fal-ai",
|
|
64
|
+
"featherless-ai",
|
|
39
65
|
"fireworks-ai",
|
|
66
|
+
"groq",
|
|
40
67
|
"hf-inference",
|
|
41
68
|
"hyperbolic",
|
|
42
69
|
"nebius",
|
|
43
70
|
"novita",
|
|
71
|
+
"nscale",
|
|
44
72
|
"openai",
|
|
73
|
+
"publicai",
|
|
45
74
|
"replicate",
|
|
46
75
|
"sambanova",
|
|
76
|
+
"scaleway",
|
|
47
77
|
"together",
|
|
78
|
+
"wavespeed",
|
|
79
|
+
"zai-org",
|
|
48
80
|
]
|
|
49
81
|
|
|
50
82
|
PROVIDER_OR_POLICY_T = Union[PROVIDER_T, Literal["auto"]]
|
|
51
83
|
|
|
52
|
-
|
|
84
|
+
CONVERSATIONAL_AUTO_ROUTER = AutoRouterConversationalTask()
|
|
85
|
+
|
|
86
|
+
PROVIDERS: dict[PROVIDER_T, dict[str, TaskProviderHelper]] = {
|
|
53
87
|
"black-forest-labs": {
|
|
54
88
|
"text-to-image": BlackForestLabsTextToImageTask(),
|
|
55
89
|
},
|
|
56
90
|
"cerebras": {
|
|
57
91
|
"conversational": CerebrasConversationalTask(),
|
|
58
92
|
},
|
|
93
|
+
"clarifai": {
|
|
94
|
+
"conversational": ClarifaiConversationalTask(),
|
|
95
|
+
},
|
|
59
96
|
"cohere": {
|
|
60
97
|
"conversational": CohereConversationalTask(),
|
|
61
98
|
},
|
|
@@ -64,10 +101,20 @@ PROVIDERS: Dict[PROVIDER_T, Dict[str, TaskProviderHelper]] = {
|
|
|
64
101
|
"text-to-image": FalAITextToImageTask(),
|
|
65
102
|
"text-to-speech": FalAITextToSpeechTask(),
|
|
66
103
|
"text-to-video": FalAITextToVideoTask(),
|
|
104
|
+
"image-to-video": FalAIImageToVideoTask(),
|
|
105
|
+
"image-to-image": FalAIImageToImageTask(),
|
|
106
|
+
"image-segmentation": FalAIImageSegmentationTask(),
|
|
107
|
+
},
|
|
108
|
+
"featherless-ai": {
|
|
109
|
+
"conversational": FeatherlessConversationalTask(),
|
|
110
|
+
"text-generation": FeatherlessTextGenerationTask(),
|
|
67
111
|
},
|
|
68
112
|
"fireworks-ai": {
|
|
69
113
|
"conversational": FireworksAIConversationalTask(),
|
|
70
114
|
},
|
|
115
|
+
"groq": {
|
|
116
|
+
"conversational": GroqConversationalTask(),
|
|
117
|
+
},
|
|
71
118
|
"hf-inference": {
|
|
72
119
|
"text-to-image": HFInferenceTask("text-to-image"),
|
|
73
120
|
"conversational": HFInferenceConversational(),
|
|
@@ -105,16 +152,25 @@ PROVIDERS: Dict[PROVIDER_T, Dict[str, TaskProviderHelper]] = {
|
|
|
105
152
|
"text-to-image": NebiusTextToImageTask(),
|
|
106
153
|
"conversational": NebiusConversationalTask(),
|
|
107
154
|
"text-generation": NebiusTextGenerationTask(),
|
|
155
|
+
"feature-extraction": NebiusFeatureExtractionTask(),
|
|
108
156
|
},
|
|
109
157
|
"novita": {
|
|
110
158
|
"text-generation": NovitaTextGenerationTask(),
|
|
111
159
|
"conversational": NovitaConversationalTask(),
|
|
112
160
|
"text-to-video": NovitaTextToVideoTask(),
|
|
113
161
|
},
|
|
162
|
+
"nscale": {
|
|
163
|
+
"conversational": NscaleConversationalTask(),
|
|
164
|
+
"text-to-image": NscaleTextToImageTask(),
|
|
165
|
+
},
|
|
114
166
|
"openai": {
|
|
115
167
|
"conversational": OpenAIConversationalTask(),
|
|
116
168
|
},
|
|
169
|
+
"publicai": {
|
|
170
|
+
"conversational": PublicAIConversationalTask(),
|
|
171
|
+
},
|
|
117
172
|
"replicate": {
|
|
173
|
+
"image-to-image": ReplicateImageToImageTask(),
|
|
118
174
|
"text-to-image": ReplicateTextToImageTask(),
|
|
119
175
|
"text-to-speech": ReplicateTextToSpeechTask(),
|
|
120
176
|
"text-to-video": ReplicateTask("text-to-video"),
|
|
@@ -123,11 +179,24 @@ PROVIDERS: Dict[PROVIDER_T, Dict[str, TaskProviderHelper]] = {
|
|
|
123
179
|
"conversational": SambanovaConversationalTask(),
|
|
124
180
|
"feature-extraction": SambanovaFeatureExtractionTask(),
|
|
125
181
|
},
|
|
182
|
+
"scaleway": {
|
|
183
|
+
"conversational": ScalewayConversationalTask(),
|
|
184
|
+
"feature-extraction": ScalewayFeatureExtractionTask(),
|
|
185
|
+
},
|
|
126
186
|
"together": {
|
|
127
187
|
"text-to-image": TogetherTextToImageTask(),
|
|
128
188
|
"conversational": TogetherConversationalTask(),
|
|
129
189
|
"text-generation": TogetherTextGenerationTask(),
|
|
130
190
|
},
|
|
191
|
+
"wavespeed": {
|
|
192
|
+
"text-to-image": WavespeedAITextToImageTask(),
|
|
193
|
+
"text-to-video": WavespeedAITextToVideoTask(),
|
|
194
|
+
"image-to-image": WavespeedAIImageToImageTask(),
|
|
195
|
+
"image-to-video": WavespeedAIImageToVideoTask(),
|
|
196
|
+
},
|
|
197
|
+
"zai-org": {
|
|
198
|
+
"conversational": ZaiConversationalTask(),
|
|
199
|
+
},
|
|
131
200
|
}
|
|
132
201
|
|
|
133
202
|
|
|
@@ -154,15 +223,21 @@ def get_provider_helper(
|
|
|
154
223
|
|
|
155
224
|
if provider is None:
|
|
156
225
|
logger.info(
|
|
157
|
-
"
|
|
226
|
+
"No provider specified for task `conversational`. Defaulting to server-side auto routing."
|
|
227
|
+
if task == "conversational"
|
|
228
|
+
else "Defaulting to 'auto' which will select the first provider available for the model, sorted by the user's order in https://hf.co/settings/inference-providers."
|
|
158
229
|
)
|
|
159
230
|
provider = "auto"
|
|
160
231
|
|
|
161
232
|
if provider == "auto":
|
|
162
233
|
if model is None:
|
|
163
234
|
raise ValueError("Specifying a model is required when provider is 'auto'")
|
|
235
|
+
if task == "conversational":
|
|
236
|
+
# Special case: we have a dedicated auto-router for conversational models. No need to fetch provider mapping.
|
|
237
|
+
return CONVERSATIONAL_AUTO_ROUTER
|
|
238
|
+
|
|
164
239
|
provider_mapping = _fetch_inference_provider_mapping(model)
|
|
165
|
-
provider = next(iter(provider_mapping))
|
|
240
|
+
provider = next(iter(provider_mapping)).provider
|
|
166
241
|
|
|
167
242
|
provider_tasks = PROVIDERS.get(provider) # type: ignore
|
|
168
243
|
if provider_tasks is None:
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
from functools import lru_cache
|
|
2
|
-
from typing import Any,
|
|
2
|
+
from typing import Any, Optional, Union, overload
|
|
3
3
|
|
|
4
4
|
from huggingface_hub import constants
|
|
5
5
|
from huggingface_hub.hf_api import InferenceProviderMapping
|
|
6
|
-
from huggingface_hub.inference._common import RequestParameters
|
|
6
|
+
from huggingface_hub.inference._common import MimeBytes, RequestParameters
|
|
7
|
+
from huggingface_hub.inference._generated.types.chat_completion import ChatCompletionInputMessage
|
|
7
8
|
from huggingface_hub.utils import build_hf_headers, get_token, logging
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
logger = logging.get_logger(__name__)
|
|
11
12
|
|
|
13
|
+
|
|
12
14
|
# Dev purposes only.
|
|
13
15
|
# If you want to try to run inference for a new model locally before it's registered on huggingface.co
|
|
14
16
|
# for a given Inference Provider, you can add it to the following dictionary.
|
|
15
|
-
HARDCODED_MODEL_INFERENCE_MAPPING:
|
|
17
|
+
HARDCODED_MODEL_INFERENCE_MAPPING: dict[str, dict[str, InferenceProviderMapping]] = {
|
|
16
18
|
# "HF model ID" => InferenceProviderMapping object initialized with "Model ID on Inference Provider's side"
|
|
17
19
|
#
|
|
18
20
|
# Example:
|
|
@@ -22,19 +24,44 @@ HARDCODED_MODEL_INFERENCE_MAPPING: Dict[str, Dict[str, InferenceProviderMapping]
|
|
|
22
24
|
# status="live")
|
|
23
25
|
"cerebras": {},
|
|
24
26
|
"cohere": {},
|
|
27
|
+
"clarifai": {},
|
|
25
28
|
"fal-ai": {},
|
|
26
29
|
"fireworks-ai": {},
|
|
30
|
+
"groq": {},
|
|
27
31
|
"hf-inference": {},
|
|
28
32
|
"hyperbolic": {},
|
|
29
33
|
"nebius": {},
|
|
34
|
+
"nscale": {},
|
|
30
35
|
"replicate": {},
|
|
31
36
|
"sambanova": {},
|
|
37
|
+
"scaleway": {},
|
|
32
38
|
"together": {},
|
|
39
|
+
"wavespeed": {},
|
|
40
|
+
"zai-org": {},
|
|
33
41
|
}
|
|
34
42
|
|
|
35
43
|
|
|
36
|
-
|
|
37
|
-
|
|
44
|
+
@overload
|
|
45
|
+
def filter_none(obj: dict[str, Any]) -> dict[str, Any]: ...
|
|
46
|
+
@overload
|
|
47
|
+
def filter_none(obj: list[Any]) -> list[Any]: ...
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def filter_none(obj: Union[dict[str, Any], list[Any]]) -> Union[dict[str, Any], list[Any]]:
|
|
51
|
+
if isinstance(obj, dict):
|
|
52
|
+
cleaned: dict[str, Any] = {}
|
|
53
|
+
for k, v in obj.items():
|
|
54
|
+
if v is None:
|
|
55
|
+
continue
|
|
56
|
+
if isinstance(v, (dict, list)):
|
|
57
|
+
v = filter_none(v)
|
|
58
|
+
cleaned[k] = v
|
|
59
|
+
return cleaned
|
|
60
|
+
|
|
61
|
+
if isinstance(obj, list):
|
|
62
|
+
return [filter_none(v) if isinstance(v, (dict, list)) else v for v in obj]
|
|
63
|
+
|
|
64
|
+
raise ValueError(f"Expected dict or list, got {type(obj)}")
|
|
38
65
|
|
|
39
66
|
|
|
40
67
|
class TaskProviderHelper:
|
|
@@ -49,11 +76,11 @@ class TaskProviderHelper:
|
|
|
49
76
|
self,
|
|
50
77
|
*,
|
|
51
78
|
inputs: Any,
|
|
52
|
-
parameters:
|
|
53
|
-
headers:
|
|
79
|
+
parameters: dict[str, Any],
|
|
80
|
+
headers: dict,
|
|
54
81
|
model: Optional[str],
|
|
55
82
|
api_key: Optional[str],
|
|
56
|
-
extra_payload: Optional[
|
|
83
|
+
extra_payload: Optional[dict[str, Any]] = None,
|
|
57
84
|
) -> RequestParameters:
|
|
58
85
|
"""
|
|
59
86
|
Prepare the request to be sent to the provider.
|
|
@@ -75,7 +102,7 @@ class TaskProviderHelper:
|
|
|
75
102
|
# prepare payload (to customize in subclasses)
|
|
76
103
|
payload = self._prepare_payload_as_dict(inputs, parameters, provider_mapping_info=provider_mapping_info)
|
|
77
104
|
if payload is not None:
|
|
78
|
-
payload = recursive_merge(payload, extra_payload or {})
|
|
105
|
+
payload = recursive_merge(payload, filter_none(extra_payload or {}))
|
|
79
106
|
|
|
80
107
|
# body data (to customize in subclasses)
|
|
81
108
|
data = self._prepare_payload_as_bytes(inputs, parameters, provider_mapping_info, extra_payload)
|
|
@@ -85,13 +112,22 @@ class TaskProviderHelper:
|
|
|
85
112
|
raise ValueError("Both payload and data cannot be set in the same request.")
|
|
86
113
|
if payload is None and data is None:
|
|
87
114
|
raise ValueError("Either payload or data must be set in the request.")
|
|
115
|
+
|
|
116
|
+
# normalize headers to lowercase and add content-type if not present
|
|
117
|
+
normalized_headers = self._normalize_headers(headers, payload, data)
|
|
118
|
+
|
|
88
119
|
return RequestParameters(
|
|
89
|
-
url=url,
|
|
120
|
+
url=url,
|
|
121
|
+
task=self.task,
|
|
122
|
+
model=provider_mapping_info.provider_id,
|
|
123
|
+
json=payload,
|
|
124
|
+
data=data,
|
|
125
|
+
headers=normalized_headers,
|
|
90
126
|
)
|
|
91
127
|
|
|
92
128
|
def get_response(
|
|
93
129
|
self,
|
|
94
|
-
response: Union[bytes,
|
|
130
|
+
response: Union[bytes, dict],
|
|
95
131
|
request_params: Optional[RequestParameters] = None,
|
|
96
132
|
) -> Any:
|
|
97
133
|
"""
|
|
@@ -108,7 +144,7 @@ class TaskProviderHelper:
|
|
|
108
144
|
api_key = get_token()
|
|
109
145
|
if api_key is None:
|
|
110
146
|
raise ValueError(
|
|
111
|
-
f"You must provide an api_key to work with {self.provider} API or log in with `
|
|
147
|
+
f"You must provide an api_key to work with {self.provider} API or log in with `hf auth login`."
|
|
112
148
|
)
|
|
113
149
|
return api_key
|
|
114
150
|
|
|
@@ -123,7 +159,12 @@ class TaskProviderHelper:
|
|
|
123
159
|
if HARDCODED_MODEL_INFERENCE_MAPPING.get(self.provider, {}).get(model):
|
|
124
160
|
return HARDCODED_MODEL_INFERENCE_MAPPING[self.provider][model]
|
|
125
161
|
|
|
126
|
-
provider_mapping =
|
|
162
|
+
provider_mapping = None
|
|
163
|
+
for mapping in _fetch_inference_provider_mapping(model):
|
|
164
|
+
if mapping.provider == self.provider:
|
|
165
|
+
provider_mapping = mapping
|
|
166
|
+
break
|
|
167
|
+
|
|
127
168
|
if provider_mapping is None:
|
|
128
169
|
raise ValueError(f"Model {model} is not supported by provider {self.provider}.")
|
|
129
170
|
|
|
@@ -137,9 +178,29 @@ class TaskProviderHelper:
|
|
|
137
178
|
logger.warning(
|
|
138
179
|
f"Model {model} is in staging mode for provider {self.provider}. Meant for test purposes only."
|
|
139
180
|
)
|
|
181
|
+
if provider_mapping.status == "error":
|
|
182
|
+
logger.warning(
|
|
183
|
+
f"Our latest automated health check on model '{model}' for provider '{self.provider}' did not complete successfully. "
|
|
184
|
+
"Inference call might fail."
|
|
185
|
+
)
|
|
140
186
|
return provider_mapping
|
|
141
187
|
|
|
142
|
-
def
|
|
188
|
+
def _normalize_headers(
|
|
189
|
+
self, headers: dict[str, Any], payload: Optional[dict[str, Any]], data: Optional[MimeBytes]
|
|
190
|
+
) -> dict[str, Any]:
|
|
191
|
+
"""Normalize the headers to use for the request.
|
|
192
|
+
|
|
193
|
+
Override this method in subclasses for customized headers.
|
|
194
|
+
"""
|
|
195
|
+
normalized_headers = {key.lower(): value for key, value in headers.items() if value is not None}
|
|
196
|
+
if normalized_headers.get("content-type") is None:
|
|
197
|
+
if data is not None and data.mime_type is not None:
|
|
198
|
+
normalized_headers["content-type"] = data.mime_type
|
|
199
|
+
elif payload is not None:
|
|
200
|
+
normalized_headers["content-type"] = "application/json"
|
|
201
|
+
return normalized_headers
|
|
202
|
+
|
|
203
|
+
def _prepare_headers(self, headers: dict, api_key: str) -> dict[str, Any]:
|
|
143
204
|
"""Return the headers to use for the request.
|
|
144
205
|
|
|
145
206
|
Override this method in subclasses for customized headers.
|
|
@@ -174,8 +235,8 @@ class TaskProviderHelper:
|
|
|
174
235
|
return ""
|
|
175
236
|
|
|
176
237
|
def _prepare_payload_as_dict(
|
|
177
|
-
self, inputs: Any, parameters:
|
|
178
|
-
) -> Optional[
|
|
238
|
+
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
|
|
239
|
+
) -> Optional[dict]:
|
|
179
240
|
"""Return the payload to use for the request, as a dict.
|
|
180
241
|
|
|
181
242
|
Override this method in subclasses for customized payloads.
|
|
@@ -186,10 +247,10 @@ class TaskProviderHelper:
|
|
|
186
247
|
def _prepare_payload_as_bytes(
|
|
187
248
|
self,
|
|
188
249
|
inputs: Any,
|
|
189
|
-
parameters:
|
|
250
|
+
parameters: dict,
|
|
190
251
|
provider_mapping_info: InferenceProviderMapping,
|
|
191
|
-
extra_payload: Optional[
|
|
192
|
-
) -> Optional[
|
|
252
|
+
extra_payload: Optional[dict],
|
|
253
|
+
) -> Optional[MimeBytes]:
|
|
193
254
|
"""Return the body to use for the request, as bytes.
|
|
194
255
|
|
|
195
256
|
Override this method in subclasses for customized body data.
|
|
@@ -211,9 +272,50 @@ class BaseConversationalTask(TaskProviderHelper):
|
|
|
211
272
|
return "/v1/chat/completions"
|
|
212
273
|
|
|
213
274
|
def _prepare_payload_as_dict(
|
|
214
|
-
self,
|
|
215
|
-
|
|
216
|
-
|
|
275
|
+
self,
|
|
276
|
+
inputs: list[Union[dict, ChatCompletionInputMessage]],
|
|
277
|
+
parameters: dict,
|
|
278
|
+
provider_mapping_info: InferenceProviderMapping,
|
|
279
|
+
) -> Optional[dict]:
|
|
280
|
+
return filter_none({"messages": inputs, **parameters, "model": provider_mapping_info.provider_id})
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class AutoRouterConversationalTask(BaseConversationalTask):
|
|
284
|
+
"""
|
|
285
|
+
Auto-router for conversational tasks.
|
|
286
|
+
|
|
287
|
+
We let the Hugging Face router select the best provider for the model, based on availability and user preferences.
|
|
288
|
+
This is a special case since the selection is done server-side (avoid 1 API call to fetch provider mapping).
|
|
289
|
+
"""
|
|
290
|
+
|
|
291
|
+
def __init__(self):
|
|
292
|
+
super().__init__(provider="auto", base_url="https://router.huggingface.co")
|
|
293
|
+
|
|
294
|
+
def _prepare_base_url(self, api_key: str) -> str:
|
|
295
|
+
"""Return the base URL to use for the request.
|
|
296
|
+
|
|
297
|
+
Usually not overwritten in subclasses."""
|
|
298
|
+
# Route to the proxy if the api_key is a HF TOKEN
|
|
299
|
+
if not api_key.startswith("hf_"):
|
|
300
|
+
raise ValueError("Cannot select auto-router when using non-Hugging Face API key.")
|
|
301
|
+
else:
|
|
302
|
+
return self.base_url # No `/auto` suffix in the URL
|
|
303
|
+
|
|
304
|
+
def _prepare_mapping_info(self, model: Optional[str]) -> InferenceProviderMapping:
|
|
305
|
+
"""
|
|
306
|
+
In auto-router, we don't need to fetch provider mapping info.
|
|
307
|
+
We just return a dummy mapping info with provider_id set to the HF model ID.
|
|
308
|
+
"""
|
|
309
|
+
if model is None:
|
|
310
|
+
raise ValueError("Please provide an HF model ID.")
|
|
311
|
+
|
|
312
|
+
return InferenceProviderMapping(
|
|
313
|
+
provider="auto",
|
|
314
|
+
hf_model_id=model,
|
|
315
|
+
providerId=model,
|
|
316
|
+
status="live",
|
|
317
|
+
task="conversational",
|
|
318
|
+
)
|
|
217
319
|
|
|
218
320
|
|
|
219
321
|
class BaseTextGenerationTask(TaskProviderHelper):
|
|
@@ -229,13 +331,13 @@ class BaseTextGenerationTask(TaskProviderHelper):
|
|
|
229
331
|
return "/v1/completions"
|
|
230
332
|
|
|
231
333
|
def _prepare_payload_as_dict(
|
|
232
|
-
self, inputs: Any, parameters:
|
|
233
|
-
) -> Optional[
|
|
234
|
-
return {"prompt": inputs, **
|
|
334
|
+
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
|
|
335
|
+
) -> Optional[dict]:
|
|
336
|
+
return filter_none({"prompt": inputs, **parameters, "model": provider_mapping_info.provider_id})
|
|
235
337
|
|
|
236
338
|
|
|
237
339
|
@lru_cache(maxsize=None)
|
|
238
|
-
def _fetch_inference_provider_mapping(model: str) ->
|
|
340
|
+
def _fetch_inference_provider_mapping(model: str) -> list["InferenceProviderMapping"]:
|
|
239
341
|
"""
|
|
240
342
|
Fetch provider mappings for a model from the Hub.
|
|
241
343
|
"""
|
|
@@ -248,7 +350,7 @@ def _fetch_inference_provider_mapping(model: str) -> Dict:
|
|
|
248
350
|
return provider_mapping
|
|
249
351
|
|
|
250
352
|
|
|
251
|
-
def recursive_merge(dict1:
|
|
353
|
+
def recursive_merge(dict1: dict, dict2: dict) -> dict:
|
|
252
354
|
return {
|
|
253
355
|
**dict1,
|
|
254
356
|
**{
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import time
|
|
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
|
|
@@ -18,7 +18,7 @@ class BlackForestLabsTextToImageTask(TaskProviderHelper):
|
|
|
18
18
|
def __init__(self):
|
|
19
19
|
super().__init__(provider="black-forest-labs", base_url="https://api.us1.bfl.ai", task="text-to-image")
|
|
20
20
|
|
|
21
|
-
def _prepare_headers(self, headers:
|
|
21
|
+
def _prepare_headers(self, headers: dict, api_key: str) -> dict[str, Any]:
|
|
22
22
|
headers = super()._prepare_headers(headers, api_key)
|
|
23
23
|
if not api_key.startswith("hf_"):
|
|
24
24
|
_ = headers.pop("authorization")
|
|
@@ -29,8 +29,8 @@ class BlackForestLabsTextToImageTask(TaskProviderHelper):
|
|
|
29
29
|
return f"/v1/{mapped_model}"
|
|
30
30
|
|
|
31
31
|
def _prepare_payload_as_dict(
|
|
32
|
-
self, inputs: Any, parameters:
|
|
33
|
-
) -> Optional[
|
|
32
|
+
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
|
|
33
|
+
) -> Optional[dict]:
|
|
34
34
|
parameters = filter_none(parameters)
|
|
35
35
|
if "num_inference_steps" in parameters:
|
|
36
36
|
parameters["steps"] = parameters.pop("num_inference_steps")
|
|
@@ -39,7 +39,7 @@ class BlackForestLabsTextToImageTask(TaskProviderHelper):
|
|
|
39
39
|
|
|
40
40
|
return {"prompt": inputs, **parameters}
|
|
41
41
|
|
|
42
|
-
def get_response(self, response: Union[bytes,
|
|
42
|
+
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
|
|
43
43
|
"""
|
|
44
44
|
Polling mechanism for Black Forest Labs since the API is asynchronous.
|
|
45
45
|
"""
|
|
@@ -50,7 +50,7 @@ class BlackForestLabsTextToImageTask(TaskProviderHelper):
|
|
|
50
50
|
|
|
51
51
|
response = session.get(url, headers={"Content-Type": "application/json"}) # type: ignore
|
|
52
52
|
response.raise_for_status() # type: ignore
|
|
53
|
-
response_json:
|
|
53
|
+
response_json: dict = response.json() # type: ignore
|
|
54
54
|
status = response_json.get("status")
|
|
55
55
|
logger.info(
|
|
56
56
|
f"Polling generation result from {url}. Current status: {status}. "
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from ._common import BaseConversationalTask
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
_PROVIDER = "clarifai"
|
|
5
|
+
_BASE_URL = "https://api.clarifai.com"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ClarifaiConversationalTask(BaseConversationalTask):
|
|
9
|
+
def __init__(self):
|
|
10
|
+
super().__init__(provider=_PROVIDER, base_url=_BASE_URL)
|
|
11
|
+
|
|
12
|
+
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
|
|
13
|
+
return "/v2/ext/openai/v1/chat/completions"
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
from typing import Any, Optional
|
|
2
|
+
|
|
3
|
+
from huggingface_hub.hf_api import InferenceProviderMapping
|
|
4
|
+
|
|
5
|
+
from ._common import BaseConversationalTask
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
_PROVIDER = "cohere"
|
|
@@ -13,3 +15,18 @@ class CohereConversationalTask(BaseConversationalTask):
|
|
|
13
15
|
|
|
14
16
|
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
|
|
15
17
|
return "/compatibility/v1/chat/completions"
|
|
18
|
+
|
|
19
|
+
def _prepare_payload_as_dict(
|
|
20
|
+
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
|
|
21
|
+
) -> Optional[dict]:
|
|
22
|
+
payload = super()._prepare_payload_as_dict(inputs, parameters, provider_mapping_info)
|
|
23
|
+
response_format = parameters.get("response_format")
|
|
24
|
+
if isinstance(response_format, dict) and response_format.get("type") == "json_schema":
|
|
25
|
+
json_schema_details = response_format.get("json_schema")
|
|
26
|
+
if isinstance(json_schema_details, dict) and "schema" in json_schema_details:
|
|
27
|
+
payload["response_format"] = { # type: ignore [index]
|
|
28
|
+
"type": "json_object",
|
|
29
|
+
"schema": json_schema_details["schema"],
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return payload
|