Voice et bot modif
This commit is contained in:
parent
189d56026b
commit
7333a22bcd
10774 changed files with 634644 additions and 933308 deletions
|
|
@ -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:
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -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})
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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"],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"],
|
||||
|
|
|
|||
|
|
@ -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"],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"])
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"])
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue