Voice et bot modif

This commit is contained in:
pi 2026-06-16 17:09:34 +00:00
parent 189d56026b
commit 7333a22bcd
10774 changed files with 634644 additions and 933308 deletions

View file

@ -1,4 +1,4 @@
from typing import Literal, Optional, Union
from typing import Literal, Union
from huggingface_hub.inference._providers.featherless_ai import (
FeatherlessConversationalTask,
@ -11,6 +11,7 @@ from .black_forest_labs import BlackForestLabsTextToImageTask
from .cerebras import CerebrasConversationalTask
from .clarifai import ClarifaiConversationalTask
from .cohere import CohereConversationalTask
from .deepinfra import DeepInfraConversationalTask, DeepInfraTextGenerationTask
from .fal_ai import (
FalAIAutomaticSpeechRecognitionTask,
FalAIImageSegmentationTask,
@ -37,6 +38,7 @@ from .nebius import (
)
from .novita import NovitaConversationalTask, NovitaTextGenerationTask, NovitaTextToVideoTask
from .nscale import NscaleConversationalTask, NscaleTextToImageTask
from .nvidia import NvidiaConversationalTask
from .openai import OpenAIConversationalTask
from .ovhcloud import OVHcloudConversationalTask
from .publicai import PublicAIConversationalTask
@ -49,7 +51,16 @@ from .replicate import (
)
from .sambanova import SambanovaConversationalTask, SambanovaFeatureExtractionTask
from .scaleway import ScalewayConversationalTask, ScalewayFeatureExtractionTask
from .together import TogetherConversationalTask, TogetherTextGenerationTask, TogetherTextToImageTask
from .together import (
TogetherConversationalTask,
TogetherFeatureExtractionTask,
TogetherImageToImageTask,
TogetherImageToVideoTask,
TogetherTextGenerationTask,
TogetherTextToImageTask,
TogetherTextToSpeechTask,
TogetherTextToVideoTask,
)
from .wavespeed import (
WavespeedAIImageToImageTask,
WavespeedAIImageToVideoTask,
@ -67,6 +78,7 @@ PROVIDER_T = Literal[
"cerebras",
"clarifai",
"cohere",
"deepinfra",
"fal-ai",
"featherless-ai",
"fireworks-ai",
@ -76,6 +88,7 @@ PROVIDER_T = Literal[
"nebius",
"novita",
"nscale",
"nvidia",
"openai",
"ovhcloud",
"publicai",
@ -104,6 +117,10 @@ PROVIDERS: dict[PROVIDER_T, dict[str, TaskProviderHelper]] = {
"cohere": {
"conversational": CohereConversationalTask(),
},
"deepinfra": {
"conversational": DeepInfraConversationalTask(),
"text-generation": DeepInfraTextGenerationTask(),
},
"fal-ai": {
"automatic-speech-recognition": FalAIAutomaticSpeechRecognitionTask(),
"text-to-image": FalAITextToImageTask(),
@ -171,6 +188,9 @@ PROVIDERS: dict[PROVIDER_T, dict[str, TaskProviderHelper]] = {
"conversational": NscaleConversationalTask(),
"text-to-image": NscaleTextToImageTask(),
},
"nvidia": {
"conversational": NvidiaConversationalTask(),
},
"openai": {
"conversational": OpenAIConversationalTask(),
},
@ -196,9 +216,14 @@ PROVIDERS: dict[PROVIDER_T, dict[str, TaskProviderHelper]] = {
"feature-extraction": ScalewayFeatureExtractionTask(),
},
"together": {
"text-to-image": TogetherTextToImageTask(),
"conversational": TogetherConversationalTask(),
"feature-extraction": TogetherFeatureExtractionTask(),
"image-to-image": TogetherImageToImageTask(),
"image-to-video": TogetherImageToVideoTask(),
"text-generation": TogetherTextGenerationTask(),
"text-to-image": TogetherTextToImageTask(),
"text-to-speech": TogetherTextToSpeechTask(),
"text-to-video": TogetherTextToVideoTask(),
},
"wavespeed": {
"text-to-image": WavespeedAITextToImageTask(),
@ -213,9 +238,7 @@ PROVIDERS: dict[PROVIDER_T, dict[str, TaskProviderHelper]] = {
}
def get_provider_helper(
provider: Optional[PROVIDER_OR_POLICY_T], task: str, model: Optional[str]
) -> TaskProviderHelper:
def get_provider_helper(provider: PROVIDER_OR_POLICY_T | None, task: str, model: str | None) -> TaskProviderHelper:
"""Get provider helper instance by name and task.
Args:

View file

@ -1,5 +1,5 @@
from functools import lru_cache
from typing import Any, Optional, Union, overload
from typing import Any, overload
from huggingface_hub import constants
from huggingface_hub.hf_api import InferenceProviderMapping
@ -25,6 +25,7 @@ HARDCODED_MODEL_INFERENCE_MAPPING: dict[str, dict[str, InferenceProviderMapping]
"cerebras": {},
"cohere": {},
"clarifai": {},
"deepinfra": {},
"fal-ai": {},
"fireworks-ai": {},
"groq": {},
@ -32,6 +33,7 @@ HARDCODED_MODEL_INFERENCE_MAPPING: dict[str, dict[str, InferenceProviderMapping]
"hyperbolic": {},
"nebius": {},
"nscale": {},
"nvidia": {},
"ovhcloud": {},
"replicate": {},
"sambanova": {},
@ -48,7 +50,7 @@ def filter_none(obj: dict[str, Any]) -> dict[str, Any]: ...
def filter_none(obj: list[Any]) -> list[Any]: ...
def filter_none(obj: Union[dict[str, Any], list[Any]]) -> Union[dict[str, Any], list[Any]]:
def filter_none(obj: dict[str, Any] | list[Any]) -> dict[str, Any] | list[Any]:
if isinstance(obj, dict):
cleaned: dict[str, Any] = {}
for k, v in obj.items():
@ -79,9 +81,9 @@ class TaskProviderHelper:
inputs: Any,
parameters: dict[str, Any],
headers: dict,
model: Optional[str],
api_key: Optional[str],
extra_payload: Optional[dict[str, Any]] = None,
model: str | None,
api_key: str | None,
extra_payload: dict[str, Any] | None = None,
) -> RequestParameters:
"""
Prepare the request to be sent to the provider.
@ -128,8 +130,8 @@ class TaskProviderHelper:
def get_response(
self,
response: Union[bytes, dict],
request_params: Optional[RequestParameters] = None,
response: bytes | dict,
request_params: RequestParameters | None = None,
) -> Any:
"""
Return the response in the expected format.
@ -137,7 +139,7 @@ class TaskProviderHelper:
Override this method in subclasses for customized response handling."""
return response
def _prepare_api_key(self, api_key: Optional[str]) -> str:
def _prepare_api_key(self, api_key: str | None) -> str:
"""Return the API key to use for the request.
Usually not overwritten in subclasses."""
@ -149,7 +151,7 @@ class TaskProviderHelper:
)
return api_key
def _prepare_mapping_info(self, model: Optional[str]) -> InferenceProviderMapping:
def _prepare_mapping_info(self, model: str | None) -> InferenceProviderMapping:
"""Return the mapped model ID to use for the request.
Usually not overwritten in subclasses."""
@ -187,7 +189,7 @@ class TaskProviderHelper:
return provider_mapping
def _normalize_headers(
self, headers: dict[str, Any], payload: Optional[dict[str, Any]], data: Optional[MimeBytes]
self, headers: dict[str, Any], payload: dict[str, Any] | None, data: MimeBytes | None
) -> dict[str, Any]:
"""Normalize the headers to use for the request.
@ -237,7 +239,7 @@ class TaskProviderHelper:
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
"""Return the payload to use for the request, as a dict.
Override this method in subclasses for customized payloads.
@ -250,8 +252,8 @@ class TaskProviderHelper:
inputs: Any,
parameters: dict,
provider_mapping_info: InferenceProviderMapping,
extra_payload: Optional[dict],
) -> Optional[MimeBytes]:
extra_payload: dict | None,
) -> MimeBytes | None:
"""Return the body to use for the request, as bytes.
Override this method in subclasses for customized body data.
@ -274,10 +276,10 @@ class BaseConversationalTask(TaskProviderHelper):
def _prepare_payload_as_dict(
self,
inputs: list[Union[dict, ChatCompletionInputMessage]],
inputs: list[dict | ChatCompletionInputMessage],
parameters: dict,
provider_mapping_info: InferenceProviderMapping,
) -> Optional[dict]:
) -> dict | None:
return filter_none({"messages": inputs, **parameters, "model": provider_mapping_info.provider_id})
@ -302,7 +304,7 @@ class AutoRouterConversationalTask(BaseConversationalTask):
else:
return self.base_url # No `/auto` suffix in the URL
def _prepare_mapping_info(self, model: Optional[str]) -> InferenceProviderMapping:
def _prepare_mapping_info(self, model: str | None) -> InferenceProviderMapping:
"""
In auto-router, we don't need to fetch provider mapping info.
We just return a dummy mapping info with provider_id set to the HF model ID.
@ -333,7 +335,7 @@ class BaseTextGenerationTask(TaskProviderHelper):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
return filter_none({"prompt": inputs, **parameters, "model": provider_mapping_info.provider_id})

View file

@ -1,5 +1,5 @@
import time
from typing import Any, Optional, Union
from typing import Any
from huggingface_hub.hf_api import InferenceProviderMapping
from huggingface_hub.inference._common import RequestParameters, _as_dict
@ -30,7 +30,7 @@ class BlackForestLabsTextToImageTask(TaskProviderHelper):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
parameters = filter_none(parameters)
if "num_inference_steps" in parameters:
parameters["steps"] = parameters.pop("num_inference_steps")
@ -39,7 +39,7 @@ class BlackForestLabsTextToImageTask(TaskProviderHelper):
return {"prompt": inputs, **parameters}
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
"""
Polling mechanism for Black Forest Labs since the API is asynchronous.
"""

View file

@ -1,4 +1,4 @@
from typing import Any, Optional
from typing import Any
from huggingface_hub.hf_api import InferenceProviderMapping
@ -18,13 +18,13 @@ class CohereConversationalTask(BaseConversationalTask):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
payload = super()._prepare_payload_as_dict(inputs, parameters, provider_mapping_info)
response_format = parameters.get("response_format")
if isinstance(response_format, dict) and response_format.get("type") == "json_schema":
json_schema_details = response_format.get("json_schema")
if isinstance(json_schema_details, dict) and "schema" in json_schema_details:
payload["response_format"] = { # type: ignore [index]
payload["response_format"] = { # type: ignore
"type": "json_object",
"schema": json_schema_details["schema"],
}

View file

@ -0,0 +1,44 @@
from typing import Any
from huggingface_hub.hf_api import InferenceProviderMapping
from huggingface_hub.inference._common import RequestParameters, _as_dict
from ._common import BaseConversationalTask, BaseTextGenerationTask, filter_none
_PROVIDER = "deepinfra"
_BASE_URL = "https://api.deepinfra.com"
class DeepInfraTextGenerationTask(BaseTextGenerationTask):
def __init__(self):
super().__init__(provider=_PROVIDER, base_url=_BASE_URL)
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
return "/v1/openai/completions"
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> dict | None:
params = filter_none(parameters.copy())
params["max_tokens"] = params.pop("max_new_tokens", None)
return {"prompt": inputs, **params, "model": provider_mapping_info.provider_id}
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
output = _as_dict(response)["choices"][0]
return {
"generated_text": output["text"],
"details": {
"finish_reason": output.get("finish_reason"),
"seed": output.get("seed"),
},
}
class DeepInfraConversationalTask(BaseConversationalTask):
def __init__(self):
super().__init__(provider=_PROVIDER, base_url=_BASE_URL)
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
return "/v1/openai/chat/completions"

View file

@ -1,7 +1,7 @@
import base64
import time
from abc import ABC
from typing import Any, Optional, Union
from typing import Any
from urllib.parse import urlparse
from huggingface_hub import constants
@ -50,8 +50,8 @@ class FalAIQueueTask(TaskProviderHelper, ABC):
def get_response(
self,
response: Union[bytes, dict],
request_params: Optional[RequestParameters] = None,
response: bytes | dict,
request_params: RequestParameters | None = None,
) -> Any:
response_dict = _as_dict(response)
@ -92,7 +92,7 @@ class FalAIAutomaticSpeechRecognitionTask(FalAITask):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
if isinstance(inputs, str) and inputs.startswith(("http://", "https://")):
# If input is a URL, pass it directly
audio_url = inputs
@ -108,7 +108,7 @@ class FalAIAutomaticSpeechRecognitionTask(FalAITask):
return {"audio_url": audio_url, **filter_none(parameters)}
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
text = _as_dict(response)["text"]
if not isinstance(text, str):
raise ValueError(f"Unexpected output format from FalAI API. Expected string, got {type(text)}.")
@ -121,7 +121,7 @@ class FalAITextToImageTask(FalAITask):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
payload: dict[str, Any] = {
"prompt": inputs,
**filter_none(parameters),
@ -145,7 +145,7 @@ class FalAITextToImageTask(FalAITask):
return payload
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
url = _as_dict(response)["images"][0]["url"]
return get_session().get(url).content
@ -156,10 +156,10 @@ class FalAITextToSpeechTask(FalAITask):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
return {"text": inputs, **filter_none(parameters)}
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
url = _as_dict(response)["audio"]["url"]
return get_session().get(url).content
@ -170,13 +170,13 @@ class FalAITextToVideoTask(FalAIQueueTask):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
return {"prompt": inputs, **filter_none(parameters)}
def get_response(
self,
response: Union[bytes, dict],
request_params: Optional[RequestParameters] = None,
response: bytes | dict,
request_params: RequestParameters | None = None,
) -> Any:
output = super().get_response(response, request_params)
url = _as_dict(output)["video"]["url"]
@ -189,12 +189,13 @@ class FalAIImageToImageTask(FalAIQueueTask):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
image_url = _as_url(inputs, default_mime_type="image/jpeg")
if "target_size" in parameters:
parameters["image_size"] = parameters.pop("target_size")
payload: dict[str, Any] = {
"image_url": image_url,
"image_urls": [image_url],
**filter_none(parameters),
}
if provider_mapping_info.adapter_weights_path is not None:
@ -209,8 +210,8 @@ class FalAIImageToImageTask(FalAIQueueTask):
def get_response(
self,
response: Union[bytes, dict],
request_params: Optional[RequestParameters] = None,
response: bytes | dict,
request_params: RequestParameters | None = None,
) -> Any:
output = super().get_response(response, request_params)
url = _as_dict(output)["images"][0]["url"]
@ -223,7 +224,7 @@ class FalAIImageToVideoTask(FalAIQueueTask):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
image_url = _as_url(inputs, default_mime_type="image/jpeg")
payload: dict[str, Any] = {
"image_url": image_url,
@ -240,8 +241,8 @@ class FalAIImageToVideoTask(FalAIQueueTask):
def get_response(
self,
response: Union[bytes, dict],
request_params: Optional[RequestParameters] = None,
response: bytes | dict,
request_params: RequestParameters | None = None,
) -> Any:
output = super().get_response(response, request_params)
url = _as_dict(output)["video"]["url"]
@ -254,7 +255,7 @@ class FalAIImageSegmentationTask(FalAIQueueTask):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
image_url = _as_url(inputs, default_mime_type="image/png")
payload: dict[str, Any] = {
"image_url": image_url,
@ -265,8 +266,8 @@ class FalAIImageSegmentationTask(FalAIQueueTask):
def get_response(
self,
response: Union[bytes, dict],
request_params: Optional[RequestParameters] = None,
response: bytes | dict,
request_params: RequestParameters | None = None,
) -> Any:
result = super().get_response(response, request_params)
result_dict = _as_dict(result)

View file

@ -1,4 +1,4 @@
from typing import Any, Optional, Union
from typing import Any
from huggingface_hub.hf_api import InferenceProviderMapping
from huggingface_hub.inference._common import RequestParameters, _as_dict
@ -16,13 +16,13 @@ class FeatherlessTextGenerationTask(BaseTextGenerationTask):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
params = filter_none(parameters.copy())
params["max_tokens"] = params.pop("max_new_tokens", None)
return {"prompt": inputs, **params, "model": provider_mapping_info.provider_id}
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
output = _as_dict(response)["choices"][0]
return {
"generated_text": output["text"],

View file

@ -1,4 +1,4 @@
from typing import Any, Optional
from typing import Any
from huggingface_hub.hf_api import InferenceProviderMapping
@ -14,13 +14,13 @@ class FireworksAIConversationalTask(BaseConversationalTask):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
payload = super()._prepare_payload_as_dict(inputs, parameters, provider_mapping_info)
response_format = parameters.get("response_format")
if isinstance(response_format, dict) and response_format.get("type") == "json_schema":
json_schema_details = response_format.get("json_schema")
if isinstance(json_schema_details, dict) and "schema" in json_schema_details:
payload["response_format"] = { # type: ignore [index]
payload["response_format"] = { # type: ignore
"type": "json_object",
"schema": json_schema_details["schema"],
}

View file

@ -1,7 +1,7 @@
import json
from functools import lru_cache
from pathlib import Path
from typing import Any, Optional, Union
from typing import Any
from urllib.parse import urlparse, urlunparse
from huggingface_hub import constants
@ -27,11 +27,11 @@ class HFInferenceTask(TaskProviderHelper):
task=task,
)
def _prepare_api_key(self, api_key: Optional[str]) -> str:
def _prepare_api_key(self, api_key: str | None) -> str:
# special case: for HF Inference we allow not providing an API key
return api_key or get_token() # type: ignore[return-value]
return api_key or get_token() # type: ignore
def _prepare_mapping_info(self, model: Optional[str]) -> InferenceProviderMapping:
def _prepare_mapping_info(self, model: str | None) -> InferenceProviderMapping:
if model is not None and model.startswith(("http://", "https://")):
return InferenceProviderMapping(
provider="hf-inference", providerId=model, hf_model_id=model, task=self.task, status="live"
@ -61,7 +61,7 @@ class HFInferenceTask(TaskProviderHelper):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
if isinstance(inputs, bytes):
raise ValueError(f"Unexpected binary input for task {self.task}.")
if isinstance(inputs, Path):
@ -72,7 +72,7 @@ class HFInferenceTask(TaskProviderHelper):
class HFInferenceBinaryInputTask(HFInferenceTask):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
return None
def _prepare_payload_as_bytes(
@ -80,8 +80,8 @@ class HFInferenceBinaryInputTask(HFInferenceTask):
inputs: Any,
parameters: dict,
provider_mapping_info: InferenceProviderMapping,
extra_payload: Optional[dict],
) -> Optional[MimeBytes]:
extra_payload: dict | None,
) -> MimeBytes | None:
parameters = filter_none(parameters)
extra_payload = extra_payload or {}
has_parameters = len(parameters) > 0 or len(extra_payload) > 0
@ -107,7 +107,7 @@ class HFInferenceConversational(HFInferenceTask):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
payload = filter_none(parameters)
mapped_model = provider_mapping_info.provider_id
payload_model = parameters.get("model") or mapped_model
@ -156,7 +156,7 @@ def _build_chat_completion_url(model_url: str) -> str:
@lru_cache(maxsize=1)
def _fetch_recommended_models() -> dict[str, Optional[str]]:
def _fetch_recommended_models() -> dict[str, str | None]:
response = get_session().get(f"{constants.ENDPOINT}/api/tasks", headers=build_hf_headers())
hf_raise_for_status(response)
return {task: next(iter(details["widgetModels"]), None) for task, details in response.json().items()}
@ -212,7 +212,7 @@ class HFInferenceFeatureExtractionTask(HFInferenceTask):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
if isinstance(inputs, bytes):
raise ValueError(f"Unexpected binary input for task {self.task}.")
if isinstance(inputs, Path):
@ -222,7 +222,7 @@ class HFInferenceFeatureExtractionTask(HFInferenceTask):
# See specs: https://github.com/huggingface/huggingface.js/blob/main/packages/tasks/src/tasks/feature-extraction/spec/input.json
return {"inputs": inputs, **filter_none(parameters)}
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
if isinstance(response, bytes):
return _bytes_to_dict(response)
return response

View file

@ -1,5 +1,5 @@
import base64
from typing import Any, Optional, Union
from typing import Any
from huggingface_hub.hf_api import InferenceProviderMapping
from huggingface_hub.inference._common import RequestParameters, _as_dict
@ -15,7 +15,7 @@ class HyperbolicTextToImageTask(TaskProviderHelper):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
mapped_model = provider_mapping_info.provider_id
parameters = filter_none(parameters)
if "num_inference_steps" in parameters:
@ -29,7 +29,7 @@ class HyperbolicTextToImageTask(TaskProviderHelper):
parameters["height"] = 512
return {"prompt": inputs, "model_name": mapped_model, **parameters}
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
response_dict = _as_dict(response)
return base64.b64decode(response_dict["images"][0]["image"])

View file

@ -1,5 +1,5 @@
import base64
from typing import Any, Optional, Union
from typing import Any
from huggingface_hub.hf_api import InferenceProviderMapping
from huggingface_hub.inference._common import RequestParameters, _as_dict
@ -15,7 +15,7 @@ class NebiusTextGenerationTask(BaseTextGenerationTask):
def __init__(self):
super().__init__(provider="nebius", base_url="https://api.studio.nebius.ai")
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
output = _as_dict(response)["choices"][0]
return {
"generated_text": output["text"],
@ -32,13 +32,13 @@ class NebiusConversationalTask(BaseConversationalTask):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
payload = super()._prepare_payload_as_dict(inputs, parameters, provider_mapping_info)
response_format = parameters.get("response_format")
if isinstance(response_format, dict) and response_format.get("type") == "json_schema":
json_schema_details = response_format.get("json_schema")
if isinstance(json_schema_details, dict) and "schema" in json_schema_details:
payload["guided_json"] = json_schema_details["schema"] # type: ignore [index]
payload["guided_json"] = json_schema_details["schema"] # type: ignore
return payload
@ -51,7 +51,7 @@ class NebiusTextToImageTask(TaskProviderHelper):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
mapped_model = provider_mapping_info.provider_id
parameters = filter_none(parameters)
if "guidance_scale" in parameters:
@ -61,7 +61,7 @@ class NebiusTextToImageTask(TaskProviderHelper):
return {"prompt": inputs, **parameters, "model": mapped_model}
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
response_dict = _as_dict(response)
return base64.b64decode(response_dict["data"][0]["b64_json"])
@ -75,9 +75,9 @@ class NebiusFeatureExtractionTask(TaskProviderHelper):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
return {"input": inputs, "model": provider_mapping_info.provider_id}
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
embeddings = _as_dict(response)["data"]
return [embedding["embedding"] for embedding in embeddings]

View file

@ -1,4 +1,4 @@
from typing import Any, Optional, Union
from typing import Any
from huggingface_hub.hf_api import InferenceProviderMapping
from huggingface_hub.inference._common import RequestParameters, _as_dict
@ -23,7 +23,7 @@ class NovitaTextGenerationTask(BaseTextGenerationTask):
# there is no v1/ route for novita
return "/v3/openai/completions"
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
output = _as_dict(response)["choices"][0]
return {
"generated_text": output["text"],
@ -52,10 +52,10 @@ class NovitaTextToVideoTask(TaskProviderHelper):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
return {"prompt": inputs, **filter_none(parameters)}
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
response_dict = _as_dict(response)
if not (
isinstance(response_dict, dict)

View file

@ -1,5 +1,5 @@
import base64
from typing import Any, Optional, Union
from typing import Any
from huggingface_hub.hf_api import InferenceProviderMapping
from huggingface_hub.inference._common import RequestParameters, _as_dict
@ -21,7 +21,7 @@ class NscaleTextToImageTask(TaskProviderHelper):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
mapped_model = provider_mapping_info.provider_id
# Combine all parameters except inputs and parameters
parameters = filter_none(parameters)
@ -39,6 +39,6 @@ class NscaleTextToImageTask(TaskProviderHelper):
}
return payload
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
response_dict = _as_dict(response)
return base64.b64decode(response_dict["data"][0]["b64_json"])

View file

@ -0,0 +1,6 @@
from huggingface_hub.inference._providers._common import BaseConversationalTask
class NvidiaConversationalTask(BaseConversationalTask):
def __init__(self):
super().__init__(provider="nvidia", base_url="https://integrate.api.nvidia.com")

View file

@ -1,5 +1,3 @@
from typing import Optional
from huggingface_hub.hf_api import InferenceProviderMapping
from huggingface_hub.inference._providers._common import BaseConversationalTask
@ -8,7 +6,7 @@ class OpenAIConversationalTask(BaseConversationalTask):
def __init__(self):
super().__init__(provider="openai", base_url="https://api.openai.com")
def _prepare_api_key(self, api_key: Optional[str]) -> str:
def _prepare_api_key(self, api_key: str | None) -> str:
if api_key is None:
raise ValueError("You must provide an api_key to work with OpenAI API.")
if api_key.startswith("hf_"):
@ -17,7 +15,7 @@ class OpenAIConversationalTask(BaseConversationalTask):
)
return api_key
def _prepare_mapping_info(self, model: Optional[str]) -> InferenceProviderMapping:
def _prepare_mapping_info(self, model: str | None) -> InferenceProviderMapping:
if model is None:
raise ValueError("Please provide an OpenAI model ID, e.g. `gpt-4o` or `o1`.")
return InferenceProviderMapping(

View file

@ -1,4 +1,4 @@
from typing import Any, Optional, Union
from typing import Any
from huggingface_hub.hf_api import InferenceProviderMapping
from huggingface_hub.inference._common import RequestParameters, _as_dict, _as_url
@ -26,7 +26,7 @@ class ReplicateTask(TaskProviderHelper):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
mapped_model = provider_mapping_info.provider_id
payload: dict[str, Any] = {"input": {"prompt": inputs, **filter_none(parameters)}}
if ":" in mapped_model:
@ -34,7 +34,7 @@ class ReplicateTask(TaskProviderHelper):
payload["version"] = version
return payload
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
response_dict = _as_dict(response)
if response_dict.get("output") is None:
raise TimeoutError(
@ -53,8 +53,8 @@ class ReplicateTextToImageTask(ReplicateTask):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
payload: dict = super()._prepare_payload_as_dict(inputs, parameters, provider_mapping_info) # type: ignore[assignment]
) -> dict | None:
payload: dict = super()._prepare_payload_as_dict(inputs, parameters, provider_mapping_info) # type: ignore
if provider_mapping_info.adapter_weights_path is not None:
payload["input"]["lora_weights"] = f"https://huggingface.co/{provider_mapping_info.hf_model_id}"
return payload
@ -66,8 +66,8 @@ class ReplicateTextToSpeechTask(ReplicateTask):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
payload: dict = super()._prepare_payload_as_dict(inputs, parameters, provider_mapping_info) # type: ignore[assignment]
) -> dict | None:
payload: dict = super()._prepare_payload_as_dict(inputs, parameters, provider_mapping_info) # type: ignore
payload["input"]["text"] = payload["input"].pop("prompt") # rename "prompt" to "text" for TTS
return payload
@ -81,7 +81,7 @@ class ReplicateAutomaticSpeechRecognitionTask(ReplicateTask):
inputs: Any,
parameters: dict,
provider_mapping_info: InferenceProviderMapping,
) -> Optional[dict]:
) -> dict | None:
mapped_model = provider_mapping_info.provider_id
audio_url = _as_url(inputs, default_mime_type="audio/wav")
@ -97,7 +97,7 @@ class ReplicateAutomaticSpeechRecognitionTask(ReplicateTask):
return payload
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
response_dict = _as_dict(response)
output = response_dict.get("output")
@ -111,7 +111,7 @@ class ReplicateAutomaticSpeechRecognitionTask(ReplicateTask):
if isinstance(first_item, dict):
output = first_item
text: Optional[str] = None
text: str | None = None
if isinstance(output, dict):
transcription = output.get("transcription")
if isinstance(transcription, str):
@ -139,10 +139,19 @@ class ReplicateImageToImageTask(ReplicateTask):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
image_url = _as_url(inputs, default_mime_type="image/jpeg")
payload: dict[str, Any] = {"input": {"input_image": image_url, **filter_none(parameters)}}
# Different Replicate models expect the image in different keys
payload: dict[str, Any] = {
"input": {
"image": image_url,
"images": [image_url],
"input_image": image_url,
"input_images": [image_url],
**filter_none(parameters),
}
}
mapped_model = provider_mapping_info.provider_id
if ":" in mapped_model:

View file

@ -1,4 +1,4 @@
from typing import Any, Optional, Union
from typing import Any
from huggingface_hub.hf_api import InferenceProviderMapping
from huggingface_hub.inference._common import RequestParameters, _as_dict
@ -11,7 +11,7 @@ class SambanovaConversationalTask(BaseConversationalTask):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
response_format_config = parameters.get("response_format")
if isinstance(response_format_config, dict):
if response_format_config.get("type") == "json_schema":
@ -33,10 +33,10 @@ class SambanovaFeatureExtractionTask(TaskProviderHelper):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
parameters = filter_none(parameters)
return {"input": inputs, "model": provider_mapping_info.provider_id, **parameters}
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
embeddings = _as_dict(response)["data"]
return [embedding["embedding"] for embedding in embeddings]

View file

@ -1,4 +1,4 @@
from typing import Any, Dict, Optional, Union
from typing import Any
from huggingface_hub.inference._common import RequestParameters, _as_dict
@ -18,11 +18,11 @@ class ScalewayFeatureExtractionTask(TaskProviderHelper):
return "/v1/embeddings"
def _prepare_payload_as_dict(
self, inputs: Any, parameters: Dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[Dict]:
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> dict | None:
parameters = filter_none(parameters)
return {"input": inputs, "model": provider_mapping_info.provider_id, **parameters}
def get_response(self, response: Union[bytes, Dict], request_params: Optional[RequestParameters] = None) -> Any:
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
embeddings = _as_dict(response)["data"]
return [embedding["embedding"] for embedding in embeddings]

View file

@ -1,20 +1,38 @@
import base64
import time
from abc import ABC
from typing import Any, Optional, Union
from typing import Any
from huggingface_hub.hf_api import InferenceProviderMapping
from huggingface_hub.inference._common import RequestParameters, _as_dict
from huggingface_hub.inference._common import (
RequestParameters,
_as_dict,
_as_url,
)
from huggingface_hub.inference._providers._common import (
BaseConversationalTask,
BaseTextGenerationTask,
TaskProviderHelper,
filter_none,
)
from huggingface_hub.utils import get_session, hf_raise_for_status, logging
logger = logging.get_logger(__name__)
_PROVIDER = "together"
_BASE_URL = "https://api.together.xyz"
# Polling interval for async video generation (in seconds).
_VIDEO_POLLING_INTERVAL = 2.0
# Upper bound on status polls (initial response may already be terminal; each further poll is one attempt).
_VIDEO_MAX_POLL_ATTEMPTS = 150 # ~5 minutes at _VIDEO_POLLING_INTERVAL
# Job statuses that mean "keep polling". Together returns "queued" before transitioning to
# "in_progress", so we must treat both as pending.
_VIDEO_PENDING_STATUSES = {"queued", "in_progress"}
class TogetherTask(TaskProviderHelper, ABC):
"""Base class for Together API tasks."""
@ -23,12 +41,16 @@ class TogetherTask(TaskProviderHelper, ABC):
super().__init__(provider=_PROVIDER, base_url=_BASE_URL, task=task)
def _prepare_route(self, mapped_model: str, api_key: str) -> str:
if self.task == "text-to-image":
return "/v1/images/generations"
elif self.task == "conversational":
return "/v1/chat/completions"
elif self.task == "text-generation":
return "/v1/completions"
match self.task:
case "text-to-image" | "image-to-image":
return "/v1/images/generations"
case "text-to-speech":
return "/v1/audio/speech"
case "feature-extraction":
return "/v1/embeddings"
case "text-to-video" | "image-to-video":
# Video creation lives under /v2 (see https://docs.together.ai/reference/create-videos).
return "/v2/videos"
raise ValueError(f"Unsupported task '{self.task}' for Together API.")
@ -36,7 +58,7 @@ class TogetherTextGenerationTask(BaseTextGenerationTask):
def __init__(self):
super().__init__(provider=_PROVIDER, base_url=_BASE_URL)
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
output = _as_dict(response)["choices"][0]
return {
"generated_text": output["text"],
@ -53,17 +75,23 @@ class TogetherConversationalTask(BaseConversationalTask):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
payload = super()._prepare_payload_as_dict(inputs, parameters, provider_mapping_info)
response_format = parameters.get("response_format")
if isinstance(response_format, dict) and response_format.get("type") == "json_schema":
json_schema_details = response_format.get("json_schema")
if isinstance(json_schema_details, dict) and "schema" in json_schema_details:
payload["response_format"] = { # type: ignore [index]
"type": "json_object",
"schema": json_schema_details["schema"],
}
if payload is None:
return None
# Together accepts response_format `{type: "json_schema", schema: <schema>}` (flattened),
# so unwrap the OpenAI-style `{type: "json_schema", json_schema: {schema}}` envelope.
response_format = payload.get("response_format")
if (
isinstance(response_format, dict)
and response_format.get("type") == "json_schema"
and isinstance(response_format.get("json_schema"), dict)
and "schema" in response_format["json_schema"]
):
payload["response_format"] = {
"type": "json_schema",
"schema": response_format["json_schema"]["schema"],
}
return payload
@ -73,16 +101,191 @@ class TogetherTextToImageTask(TogetherTask):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
mapped_model = provider_mapping_info.provider_id
parameters = filter_none(parameters)
if "num_inference_steps" in parameters:
parameters["steps"] = parameters.pop("num_inference_steps")
if "guidance_scale" in parameters:
parameters["guidance"] = parameters.pop("guidance_scale")
return {"prompt": inputs, "response_format": "base64", **parameters, "model": mapped_model}
def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
response_dict = _as_dict(response)
return base64.b64decode(response_dict["data"][0]["b64_json"])
class TogetherImageToImageTask(TogetherTask):
def __init__(self):
super().__init__("image-to-image")
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> dict | None:
mapped_model = provider_mapping_info.provider_id
image_url = _as_url(inputs, default_mime_type="image/jpeg")
# Filter `None` values first: the client always passes `"prompt": None` when the user
# omits the argument, so popping before filtering would yield `None` instead of the
# `""` default and send `"prompt": null` to Together (rejected by Flux Kontext).
parameters = filter_none(parameters)
prompt = parameters.pop("prompt", "")
if "num_inference_steps" in parameters:
parameters["steps"] = parameters.pop("num_inference_steps")
# Together exposes two mutually-exclusive image inputs (see
# https://docs.together.ai/docs/image-to-image): FLUX.1 Kontext only accepts
# `image_url`; FLUX.2 [dev] and Google models (Gemini 3 Pro Image, Flash Image
# 2.5) only accept `reference_images`. FLUX.2 [pro]/[flex] accept either but
# `reference_images` is the documented default. Use `image_url` only for
# FLUX.1 Kontext models and `reference_images` for everything else.
lowered = mapped_model.lower()
use_image_url = "kontext" in lowered and "flux.1" in lowered
image_field: dict[str, Any] = {"image_url": image_url} if use_image_url else {"reference_images": [image_url]}
return {
"prompt": prompt,
**image_field,
"response_format": "base64",
**parameters,
"model": mapped_model,
}
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
response_dict = _as_dict(response)
return base64.b64decode(response_dict["data"][0]["b64_json"])
class TogetherFeatureExtractionTask(TogetherTask):
def __init__(self):
super().__init__("feature-extraction")
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> dict | None:
return {
"input": inputs,
"model": provider_mapping_info.provider_id,
**filter_none(parameters),
}
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
return [item["embedding"] for item in _as_dict(response)["data"]]
class TogetherTextToSpeechTask(TogetherTask):
def __init__(self):
super().__init__("text-to-speech")
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> dict | None:
# `voice` is required by the Together API and is model-specific
# (see https://docs.together.ai/docs/text-to-speech#supported-voices),
# so we don't set a default and let the API surface a clear error if missing.
return {
"input": inputs,
"model": provider_mapping_info.provider_id,
**filter_none(parameters),
}
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
if isinstance(response, bytes):
return response
raise ValueError(f"Expected raw audio bytes for text-to-speech, got {type(response).__name__}.")
def _normalize_video_parameters(parameters: dict) -> dict:
"""Map HF inference-client conventions onto Together's video API parameter names."""
parameters = filter_none(parameters)
if "num_inference_steps" in parameters:
parameters["steps"] = parameters.pop("num_inference_steps")
if "target_size" in parameters:
target_size = parameters.pop("target_size")
if "width" in target_size:
parameters["width"] = target_size["width"]
if "height" in target_size:
parameters["height"] = target_size["height"]
return parameters
class TogetherVideoTask(TogetherTask, ABC):
"""Base class for Together's asynchronous video generation tasks."""
def get_response(self, response: bytes | dict, request_params: RequestParameters | None = None) -> Any:
if request_params is None:
raise ValueError("A `RequestParameters` object is required to poll Together video jobs.")
job = _as_dict(response)
job_id = job.get("id")
if not job_id:
raise ValueError("No job ID found in Together video generation response.")
# Status polling lives at the same /v2/videos URL with the job ID appended.
status_url = f"{request_params.url}/{job_id}"
logger.info("Generating video, polling for completion...")
# Together usually returns `status: "queued"` on the initial POST, but the field is
# optional per the spec — treat a missing status as "still pending" and poll, rather
# than falling through to the "unexpected status" error below.
status = job.get("status")
for _ in range(_VIDEO_MAX_POLL_ATTEMPTS):
if status is not None and status not in _VIDEO_PENDING_STATUSES:
break
time.sleep(_VIDEO_POLLING_INTERVAL)
status_response = get_session().get(status_url, headers=request_params.headers)
hf_raise_for_status(status_response)
job = status_response.json()
status = job.get("status")
if status is not None and status not in _VIDEO_PENDING_STATUSES:
break
else:
raise ValueError(
"Timed out while waiting for Together video generation "
f"— aborting after {_VIDEO_MAX_POLL_ATTEMPTS} status polls"
)
if status == "failed":
error = job.get("error") or {}
raise RuntimeError(f"Together video generation failed: {error.get('message') or 'Unknown error'}")
if status != "completed":
raise RuntimeError(f"Unexpected Together video job status: {status!r}")
video_url = (job.get("outputs") or {}).get("video_url")
if not video_url:
raise ValueError("No video URL found in completed Together video job.")
video_response = get_session().get(video_url)
hf_raise_for_status(video_response)
return video_response.content
class TogetherTextToVideoTask(TogetherVideoTask):
def __init__(self):
super().__init__("text-to-video")
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> dict | None:
return {
"prompt": inputs,
"model": provider_mapping_info.provider_id,
**_normalize_video_parameters(parameters),
}
class TogetherImageToVideoTask(TogetherVideoTask):
def __init__(self):
super().__init__("image-to-video")
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> dict | None:
# Together expects each keyframe as `{input_image, frame: "first" | "last"}`
# for i2v models. See https://docs.together.ai/docs/inference/videos/reference-and-keyframes.
# Note: `input_image` accepts a data URL or an HTTP(S) URL but the field is capped
# at ~60KB — users with larger inputs should host the image and pass `frame_images`
# directly via `extra_body`.
return {
"model": provider_mapping_info.provider_id,
"frame_images": [{"input_image": _as_url(inputs, default_mime_type="image/png"), "frame": "first"}],
**_normalize_video_parameters(parameters),
}

View file

@ -1,7 +1,7 @@
import base64
import time
from abc import ABC
from typing import Any, Optional, Union
from typing import Any
from urllib.parse import urlparse
from huggingface_hub.hf_api import InferenceProviderMapping
@ -26,8 +26,8 @@ class WavespeedAITask(TaskProviderHelper, ABC):
def get_response(
self,
response: Union[bytes, dict],
request_params: Optional[RequestParameters] = None,
response: bytes | dict,
request_params: RequestParameters | None = None,
) -> Any:
response_dict = _as_dict(response)
data = response_dict.get("data", {})
@ -91,7 +91,7 @@ class WavespeedAITextToImageTask(WavespeedAITask):
inputs: Any,
parameters: dict,
provider_mapping_info: InferenceProviderMapping,
) -> Optional[dict]:
) -> dict | None:
return {"prompt": inputs, **filter_none(parameters)}
@ -109,7 +109,7 @@ class WavespeedAIImageToImageTask(WavespeedAITask):
inputs: Any,
parameters: dict,
provider_mapping_info: InferenceProviderMapping,
) -> Optional[dict]:
) -> dict | None:
# Convert inputs to image (URL or base64)
if isinstance(inputs, str) and inputs.startswith(("http://", "https://")):
image = inputs

View file

@ -1,6 +1,6 @@
import time
from abc import ABC
from typing import Any, Optional, Union
from typing import Any
from huggingface_hub.hf_api import InferenceProviderMapping
from huggingface_hub.inference._common import RequestParameters, _as_dict
@ -50,7 +50,7 @@ class ZaiTextToImageTask(ZaiTask):
def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
) -> dict | None:
width = parameters.pop("width", None)
height = parameters.pop("height", None)
size = None
@ -69,8 +69,8 @@ class ZaiTextToImageTask(ZaiTask):
def get_response(
self,
response: Union[bytes, dict],
request_params: Optional[RequestParameters] = None,
response: bytes | dict,
request_params: RequestParameters | None = None,
) -> Any:
"""Handle async response by polling for results."""
response_dict = _as_dict(response)