Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 31 additions & 31 deletions docs/source/en/guides/inference.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/huggingface_hub/inference/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ class InferenceClient:
Note: for better compatibility with OpenAI's client, `model` has been aliased as `base_url`. Those 2
arguments are mutually exclusive. If a URL is passed as `model` or `base_url` for chat completion, the `(/v1)/chat/completions` suffix path will be appended to the URL.
provider (`str`, *optional*):
Name of the provider to use for inference. Can be `"black-forest-labs"`, `"cerebras"`, `"clarifai"`, `"cohere"`, `"fal-ai"`, `"featherless-ai"`, `"fireworks-ai"`, `"groq"`, `"hf-inference"`, `"hyperbolic"`, `"nebius"`, `"novita"`, `"nscale"`, `"openai"`, `"ovhcloud"`, `"publicai"`, `"replicate"`, `"sambanova"`, `"scaleway"`, `"together"`, `"wavespeed"` or `"zai-org"`.
Name of the provider to use for inference. Can be `"black-forest-labs"`, `"cerebras"`, `"clarifai"`, `"cohere"`, `"fal-ai"`, `"featherless-ai"`, `"fireworks-ai"`, `"groq"`, `"hf-inference"`, `"hyperbolic"`, `"mokzu"`, `"nebius"`, `"novita"`, `"nscale"`, `"openai"`, `"ovhcloud"`, `"publicai"`, `"replicate"`, `"sambanova"`, `"scaleway"`, `"together"`, `"wavespeed"` or `"zai-org"`.
Defaults to "auto" i.e. the first of the providers available for the model, sorted by the user's order in https://hf.co/settings/inference-providers.
If model is a URL or `base_url` is passed, then `provider` is not used.
token (`str`, *optional*):
Expand Down
2 changes: 1 addition & 1 deletion src/huggingface_hub/inference/_generated/_async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class AsyncInferenceClient:
Note: for better compatibility with OpenAI's client, `model` has been aliased as `base_url`. Those 2
arguments are mutually exclusive. If a URL is passed as `model` or `base_url` for chat completion, the `(/v1)/chat/completions` suffix path will be appended to the URL.
provider (`str`, *optional*):
Name of the provider to use for inference. Can be `"black-forest-labs"`, `"cerebras"`, `"clarifai"`, `"cohere"`, `"fal-ai"`, `"featherless-ai"`, `"fireworks-ai"`, `"groq"`, `"hf-inference"`, `"hyperbolic"`, `"nebius"`, `"novita"`, `"nscale"`, `"openai"`, `"ovhcloud"`, `"publicai"`, `"replicate"`, `"sambanova"`, `"scaleway"`, `"together"`, `"wavespeed"` or `"zai-org"`.
Name of the provider to use for inference. Can be `"black-forest-labs"`, `"cerebras"`, `"clarifai"`, `"cohere"`, `"fal-ai"`, `"featherless-ai"`, `"fireworks-ai"`, `"groq"`, `"hf-inference"`, `"hyperbolic"`, `"mokzu"`, `"nebius"`, `"novita"`, `"nscale"`, `"openai"`, `"ovhcloud"`, `"publicai"`, `"replicate"`, `"sambanova"`, `"scaleway"`, `"together"`, `"wavespeed"` or `"zai-org"`.
Defaults to "auto" i.e. the first of the providers available for the model, sorted by the user's order in https://hf.co/settings/inference-providers.
If model is a URL or `base_url` is passed, then `provider` is not used.
token (`str`, *optional*):
Expand Down
5 changes: 5 additions & 0 deletions src/huggingface_hub/inference/_providers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
HFInferenceTask,
)
from .hyperbolic import HyperbolicTextGenerationTask, HyperbolicTextToImageTask
from .mokzu import MokzuImageToVideoTask
from .nebius import (
NebiusConversationalTask,
NebiusFeatureExtractionTask,
Expand Down Expand Up @@ -73,6 +74,7 @@
"groq",
"hf-inference",
"hyperbolic",
"mokzu",
"nebius",
"novita",
"nscale",
Expand Down Expand Up @@ -156,6 +158,9 @@
"conversational": HyperbolicTextGenerationTask("conversational"),
"text-generation": HyperbolicTextGenerationTask("text-generation"),
},
"mokzu": {
"image-to-video": MokzuImageToVideoTask(),
},
"nebius": {
"text-to-image": NebiusTextToImageTask(),
"conversational": NebiusConversationalTask(),
Expand Down
1 change: 1 addition & 0 deletions src/huggingface_hub/inference/_providers/_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"groq": {},
"hf-inference": {},
"hyperbolic": {},
"mokzu": {},
"nebius": {},
"nscale": {},
"ovhcloud": {},
Expand Down
48 changes: 48 additions & 0 deletions src/huggingface_hub/inference/_providers/mokzu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import base64
from typing import Any, Optional, Union

from huggingface_hub.hf_api import InferenceProviderMapping
from huggingface_hub.inference._common import RequestParameters, _as_dict, _as_url
from huggingface_hub.inference._providers._common import TaskProviderHelper, filter_none


class MokzuImageToVideoTask(TaskProviderHelper):
def __init__(self):
super().__init__(provider="mokzu", base_url="https://api.mokzu.com", task="image-to-video")

def _prepare_route(self, mapped_model: str, api_key: str) -> str:
return "/v1/image-to-video"

def _prepare_payload_as_dict(
self, inputs: Any, parameters: dict, provider_mapping_info: InferenceProviderMapping
) -> Optional[dict]:
# Inputs can be bytes (image data) or dict with image and prompt
if isinstance(inputs, bytes):
encoded = base64.b64encode(inputs).decode("utf-8")
payload = {"image": encoded, **filter_none(parameters)}
elif isinstance(inputs, dict):
# For dict input, expect 'image' (bytes or base64) and optional 'prompt'
image_data = inputs.get("image", "")
if isinstance(image_data, bytes):
image_data = base64.b64encode(image_data).decode("utf-8")
payload = {
"image": image_data,
"prompt": inputs.get("prompt", ""),
**filter_none(parameters)
}
else:
# Assume string (base64 or URL)
payload = {"image": inputs, **filter_none(parameters)}

# Ensure prompt exists
if "prompt" not in payload:
payload["prompt"] = parameters.get("prompt", "")

return payload

def get_response(self, response: Union[bytes, dict], request_params: Optional[RequestParameters] = None) -> Any:
response_dict = _as_dict(response)
video_url = response_dict.get("video_url", "")
if video_url:
return _as_url(video_url, default_mime_type="video/mp4")
raise ValueError("No video_url in response")
62 changes: 62 additions & 0 deletions tests/test_inference_providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
HFInferenceTask,
)
from huggingface_hub.inference._providers.hyperbolic import HyperbolicTextGenerationTask, HyperbolicTextToImageTask
from huggingface_hub.inference._providers.mokzu import MokzuImageToVideoTask
from huggingface_hub.inference._providers.nebius import NebiusFeatureExtractionTask, NebiusTextToImageTask
from huggingface_hub.inference._providers.novita import NovitaConversationalTask, NovitaTextGenerationTask
from huggingface_hub.inference._providers.nscale import NscaleConversationalTask, NscaleTextToImageTask
Expand Down Expand Up @@ -1217,6 +1218,67 @@ def test_text_to_image_get_response(self):
assert response == dummy_image


class TestMokzuProvider:
def test_mokzu_image_to_video_payload_bytes(self):
helper = MokzuImageToVideoTask()
mapping_info = InferenceProviderMapping(
provider="mokzu",
hf_model_id="mokzu/image-to-video",
providerId="mokzu/image-to-video",
task="image-to-video",
status="live",
)
payload = helper._prepare_payload_as_dict(b"binaryimagedata", {"prompt": "a cat walking"}, mapping_info)
assert "image" in payload
assert payload["image"] == base64.b64encode(b"binaryimagedata").decode("utf-8")
assert payload["prompt"] == "a cat walking"

def test_mokzu_image_to_video_payload_dict(self):
helper = MokzuImageToVideoTask()
mapping_info = InferenceProviderMapping(
provider="mokzu",
hf_model_id="mokzu/image-to-video",
providerId="mokzu/image-to-video",
task="image-to-video",
status="live",
)
payload = helper._prepare_payload_as_dict(
{"image": b"binaryimagedata", "prompt": "a dog running"},
{"duration": 3},
mapping_info
)
assert payload["image"] == base64.b64encode(b"binaryimagedata").decode("utf-8")
assert payload["prompt"] == "a dog running"
assert payload["duration"] == 3

def test_mokzu_image_to_video_payload_base64(self):
helper = MokzuImageToVideoTask()
mapping_info = InferenceProviderMapping(
provider="mokzu",
hf_model_id="mokzu/image-to-video",
providerId="mokzu/image-to-video",
task="image-to-video",
status="live",
)
base64_img = base64.b64encode(b"testimage").decode("utf-8")
payload = helper._prepare_payload_as_dict(base64_img, {"prompt": "test"}, mapping_info)
assert payload["image"] == base64_img
assert payload["prompt"] == "test"

def test_mokzu_image_to_video_route(self):
helper = MokzuImageToVideoTask()
assert helper._prepare_route("mokzu/image-to-video", "api_key") == "/v1/image-to-video"

def test_mokzu_image_to_video_response(self):
helper = MokzuImageToVideoTask()
response = helper.get_response({"video_url": "https://mokzu.com/videos/output.mp4"})
assert response == "https://mokzu.com/videos/output.mp4"

def test_mokzu_image_to_video_response_error(self):
helper = MokzuImageToVideoTask()
with pytest.raises(ValueError, match="No video_url in response"):
helper.get_response({"error": "failed"})

class TestNebiusProvider:
def test_prepare_route_text_to_image(self):
helper = NebiusTextToImageTask()
Expand Down