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.
Files changed (150) hide show
  1. huggingface_hub/__init__.py +145 -46
  2. huggingface_hub/_commit_api.py +168 -119
  3. huggingface_hub/_commit_scheduler.py +15 -15
  4. huggingface_hub/_inference_endpoints.py +15 -12
  5. huggingface_hub/_jobs_api.py +301 -0
  6. huggingface_hub/_local_folder.py +18 -3
  7. huggingface_hub/_login.py +31 -63
  8. huggingface_hub/_oauth.py +460 -0
  9. huggingface_hub/_snapshot_download.py +239 -80
  10. huggingface_hub/_space_api.py +5 -5
  11. huggingface_hub/_tensorboard_logger.py +15 -19
  12. huggingface_hub/_upload_large_folder.py +172 -76
  13. huggingface_hub/_webhooks_payload.py +3 -3
  14. huggingface_hub/_webhooks_server.py +13 -25
  15. huggingface_hub/{commands → cli}/__init__.py +1 -15
  16. huggingface_hub/cli/_cli_utils.py +173 -0
  17. huggingface_hub/cli/auth.py +147 -0
  18. huggingface_hub/cli/cache.py +841 -0
  19. huggingface_hub/cli/download.py +189 -0
  20. huggingface_hub/cli/hf.py +60 -0
  21. huggingface_hub/cli/inference_endpoints.py +377 -0
  22. huggingface_hub/cli/jobs.py +772 -0
  23. huggingface_hub/cli/lfs.py +175 -0
  24. huggingface_hub/cli/repo.py +315 -0
  25. huggingface_hub/cli/repo_files.py +94 -0
  26. huggingface_hub/{commands/env.py → cli/system.py} +10 -13
  27. huggingface_hub/cli/upload.py +294 -0
  28. huggingface_hub/cli/upload_large_folder.py +117 -0
  29. huggingface_hub/community.py +20 -12
  30. huggingface_hub/constants.py +38 -53
  31. huggingface_hub/dataclasses.py +609 -0
  32. huggingface_hub/errors.py +80 -30
  33. huggingface_hub/fastai_utils.py +30 -41
  34. huggingface_hub/file_download.py +435 -351
  35. huggingface_hub/hf_api.py +2050 -1124
  36. huggingface_hub/hf_file_system.py +269 -152
  37. huggingface_hub/hub_mixin.py +43 -63
  38. huggingface_hub/inference/_client.py +347 -434
  39. huggingface_hub/inference/_common.py +133 -121
  40. huggingface_hub/inference/_generated/_async_client.py +397 -541
  41. huggingface_hub/inference/_generated/types/__init__.py +5 -1
  42. huggingface_hub/inference/_generated/types/automatic_speech_recognition.py +3 -3
  43. huggingface_hub/inference/_generated/types/base.py +10 -7
  44. huggingface_hub/inference/_generated/types/chat_completion.py +59 -23
  45. huggingface_hub/inference/_generated/types/depth_estimation.py +2 -2
  46. huggingface_hub/inference/_generated/types/document_question_answering.py +2 -2
  47. huggingface_hub/inference/_generated/types/feature_extraction.py +2 -2
  48. huggingface_hub/inference/_generated/types/fill_mask.py +2 -2
  49. huggingface_hub/inference/_generated/types/image_to_image.py +6 -2
  50. huggingface_hub/inference/_generated/types/image_to_video.py +60 -0
  51. huggingface_hub/inference/_generated/types/sentence_similarity.py +3 -3
  52. huggingface_hub/inference/_generated/types/summarization.py +2 -2
  53. huggingface_hub/inference/_generated/types/table_question_answering.py +5 -5
  54. huggingface_hub/inference/_generated/types/text2text_generation.py +2 -2
  55. huggingface_hub/inference/_generated/types/text_generation.py +10 -10
  56. huggingface_hub/inference/_generated/types/text_to_video.py +2 -2
  57. huggingface_hub/inference/_generated/types/token_classification.py +2 -2
  58. huggingface_hub/inference/_generated/types/translation.py +2 -2
  59. huggingface_hub/inference/_generated/types/zero_shot_classification.py +2 -2
  60. huggingface_hub/inference/_generated/types/zero_shot_image_classification.py +2 -2
  61. huggingface_hub/inference/_generated/types/zero_shot_object_detection.py +1 -3
  62. huggingface_hub/inference/_mcp/__init__.py +0 -0
  63. huggingface_hub/inference/_mcp/_cli_hacks.py +88 -0
  64. huggingface_hub/inference/_mcp/agent.py +100 -0
  65. huggingface_hub/inference/_mcp/cli.py +247 -0
  66. huggingface_hub/inference/_mcp/constants.py +81 -0
  67. huggingface_hub/inference/_mcp/mcp_client.py +395 -0
  68. huggingface_hub/inference/_mcp/types.py +45 -0
  69. huggingface_hub/inference/_mcp/utils.py +128 -0
  70. huggingface_hub/inference/_providers/__init__.py +82 -7
  71. huggingface_hub/inference/_providers/_common.py +129 -27
  72. huggingface_hub/inference/_providers/black_forest_labs.py +6 -6
  73. huggingface_hub/inference/_providers/cerebras.py +1 -1
  74. huggingface_hub/inference/_providers/clarifai.py +13 -0
  75. huggingface_hub/inference/_providers/cohere.py +20 -3
  76. huggingface_hub/inference/_providers/fal_ai.py +183 -56
  77. huggingface_hub/inference/_providers/featherless_ai.py +38 -0
  78. huggingface_hub/inference/_providers/fireworks_ai.py +18 -0
  79. huggingface_hub/inference/_providers/groq.py +9 -0
  80. huggingface_hub/inference/_providers/hf_inference.py +69 -30
  81. huggingface_hub/inference/_providers/hyperbolic.py +4 -4
  82. huggingface_hub/inference/_providers/nebius.py +33 -5
  83. huggingface_hub/inference/_providers/novita.py +5 -5
  84. huggingface_hub/inference/_providers/nscale.py +44 -0
  85. huggingface_hub/inference/_providers/openai.py +3 -1
  86. huggingface_hub/inference/_providers/publicai.py +6 -0
  87. huggingface_hub/inference/_providers/replicate.py +31 -13
  88. huggingface_hub/inference/_providers/sambanova.py +18 -4
  89. huggingface_hub/inference/_providers/scaleway.py +28 -0
  90. huggingface_hub/inference/_providers/together.py +20 -5
  91. huggingface_hub/inference/_providers/wavespeed.py +138 -0
  92. huggingface_hub/inference/_providers/zai_org.py +17 -0
  93. huggingface_hub/lfs.py +33 -100
  94. huggingface_hub/repocard.py +34 -38
  95. huggingface_hub/repocard_data.py +57 -57
  96. huggingface_hub/serialization/__init__.py +0 -1
  97. huggingface_hub/serialization/_base.py +12 -15
  98. huggingface_hub/serialization/_dduf.py +8 -8
  99. huggingface_hub/serialization/_torch.py +69 -69
  100. huggingface_hub/utils/__init__.py +19 -8
  101. huggingface_hub/utils/_auth.py +7 -7
  102. huggingface_hub/utils/_cache_manager.py +92 -147
  103. huggingface_hub/utils/_chunk_utils.py +2 -3
  104. huggingface_hub/utils/_deprecation.py +1 -1
  105. huggingface_hub/utils/_dotenv.py +55 -0
  106. huggingface_hub/utils/_experimental.py +7 -5
  107. huggingface_hub/utils/_fixes.py +0 -10
  108. huggingface_hub/utils/_git_credential.py +5 -5
  109. huggingface_hub/utils/_headers.py +8 -30
  110. huggingface_hub/utils/_http.py +398 -239
  111. huggingface_hub/utils/_pagination.py +4 -4
  112. huggingface_hub/utils/_parsing.py +98 -0
  113. huggingface_hub/utils/_paths.py +5 -5
  114. huggingface_hub/utils/_runtime.py +61 -24
  115. huggingface_hub/utils/_safetensors.py +21 -21
  116. huggingface_hub/utils/_subprocess.py +9 -9
  117. huggingface_hub/utils/_telemetry.py +4 -4
  118. huggingface_hub/{commands/_cli_utils.py → utils/_terminal.py} +4 -4
  119. huggingface_hub/utils/_typing.py +25 -5
  120. huggingface_hub/utils/_validators.py +55 -74
  121. huggingface_hub/utils/_verification.py +167 -0
  122. huggingface_hub/utils/_xet.py +64 -17
  123. huggingface_hub/utils/_xet_progress_reporting.py +162 -0
  124. huggingface_hub/utils/insecure_hashlib.py +3 -5
  125. huggingface_hub/utils/logging.py +8 -11
  126. huggingface_hub/utils/tqdm.py +5 -4
  127. {huggingface_hub-0.31.0rc0.dist-info → huggingface_hub-1.1.3.dist-info}/METADATA +94 -85
  128. huggingface_hub-1.1.3.dist-info/RECORD +155 -0
  129. {huggingface_hub-0.31.0rc0.dist-info → huggingface_hub-1.1.3.dist-info}/WHEEL +1 -1
  130. huggingface_hub-1.1.3.dist-info/entry_points.txt +6 -0
  131. huggingface_hub/commands/delete_cache.py +0 -474
  132. huggingface_hub/commands/download.py +0 -200
  133. huggingface_hub/commands/huggingface_cli.py +0 -61
  134. huggingface_hub/commands/lfs.py +0 -200
  135. huggingface_hub/commands/repo_files.py +0 -128
  136. huggingface_hub/commands/scan_cache.py +0 -181
  137. huggingface_hub/commands/tag.py +0 -159
  138. huggingface_hub/commands/upload.py +0 -314
  139. huggingface_hub/commands/upload_large_folder.py +0 -129
  140. huggingface_hub/commands/user.py +0 -304
  141. huggingface_hub/commands/version.py +0 -37
  142. huggingface_hub/inference_api.py +0 -217
  143. huggingface_hub/keras_mixin.py +0 -500
  144. huggingface_hub/repository.py +0 -1477
  145. huggingface_hub/serialization/_tensorflow.py +0 -95
  146. huggingface_hub/utils/_hf_folder.py +0 -68
  147. huggingface_hub-0.31.0rc0.dist-info/RECORD +0 -135
  148. huggingface_hub-0.31.0rc0.dist-info/entry_points.txt +0 -6
  149. {huggingface_hub-0.31.0rc0.dist-info → huggingface_hub-1.1.3.dist-info/licenses}/LICENSE +0 -0
  150. {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 Dict, Literal, Optional, Union
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 NebiusConversationalTask, NebiusTextGenerationTask, NebiusTextToImageTask
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 .replicate import ReplicateTask, ReplicateTextToImageTask, ReplicateTextToSpeechTask
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
- PROVIDERS: Dict[PROVIDER_T, Dict[str, TaskProviderHelper]] = {
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
- "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."
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, Dict, Optional, Union
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: Dict[str, Dict[str, InferenceProviderMapping]] = {
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
- def filter_none(d: Dict[str, Any]) -> Dict[str, Any]:
37
- return {k: v for k, v in d.items() if v is not None}
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: Dict[str, Any],
53
- headers: Dict,
79
+ parameters: dict[str, Any],
80
+ headers: dict,
54
81
  model: Optional[str],
55
82
  api_key: Optional[str],
56
- extra_payload: Optional[Dict[str, Any]] = None,
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, task=self.task, model=provider_mapping_info.provider_id, json=payload, data=data, headers=headers
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, Dict],
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 `huggingface-cli login`."
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 = _fetch_inference_provider_mapping(model).get(self.provider)
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 _prepare_headers(self, headers: Dict, api_key: str) -> Dict:
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: Dict, provider_mapping_info: InferenceProviderMapping
178
- ) -> Optional[Dict]:
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: Dict,
250
+ parameters: dict,
190
251
  provider_mapping_info: InferenceProviderMapping,
191
- extra_payload: Optional[Dict],
192
- ) -> Optional[bytes]:
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, inputs: Any, parameters: Dict, provider_mapping_info: InferenceProviderMapping
215
- ) -> Optional[Dict]:
216
- return {"messages": inputs, **filter_none(parameters), "model": provider_mapping_info.provider_id}
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: Dict, provider_mapping_info: InferenceProviderMapping
233
- ) -> Optional[Dict]:
234
- return {"prompt": inputs, **filter_none(parameters), "model": provider_mapping_info.provider_id}
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) -> Dict:
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: Dict, dict2: Dict) -> Dict:
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, Dict, Optional, Union
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: Dict, api_key: str) -> Dict:
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: Dict, provider_mapping_info: InferenceProviderMapping
33
- ) -> Optional[Dict]:
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, Dict], request_params: Optional[RequestParameters] = None) -> Any:
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: Dict = response.json() # type: ignore
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}. "
@@ -1,4 +1,4 @@
1
- from huggingface_hub.inference._providers._common import BaseConversationalTask
1
+ from ._common import BaseConversationalTask
2
2
 
3
3
 
4
4
  class CerebrasConversationalTask(BaseConversationalTask):
@@ -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 huggingface_hub.inference._providers._common import (
2
- BaseConversationalTask,
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