using AIStudio.Tools.PluginSystem; namespace AIStudio.Provider.HuggingFace; public static class HFInferenceProviderExtensions { private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(HFInferenceProviderExtensions).Namespace, nameof(HFInferenceProviderExtensions)); /// /// The slug Hugging Face uses for this inference provider. /// /// The inference provider. /// The slug, or an empty string for the routing strategies, which name no provider. public static string EndpointsId(this HFInferenceProvider provider) => provider switch { HFInferenceProvider.BASETEN => "baseten", HFInferenceProvider.CEREBRAS => "cerebras", HFInferenceProvider.COHERE => "cohere", HFInferenceProvider.DEEPINFRA => "deepinfra", HFInferenceProvider.FEATHERLESS_AI => "featherless-ai", HFInferenceProvider.FIREWORKS => "fireworks-ai", HFInferenceProvider.GROQ => "groq", HFInferenceProvider.NOVITA => "novita", HFInferenceProvider.NSCALE => "nscale", HFInferenceProvider.OVHCLOUD => "ovhcloud", HFInferenceProvider.PUBLIC_AI => "publicai", HFInferenceProvider.SCALEWAY => "scaleway", HFInferenceProvider.TOGETHER_AI => "together", HFInferenceProvider.ZAI => "zai-org", _ => string.Empty, }; /// /// The suffix which tells the router where to send the request. /// /// /// The router serves every provider through one endpoint. Which provider answers is decided by /// a suffix on the model name, e.g. "google/gemma-4-31B-it:novita". Without a suffix, the router /// picks the fastest provider itself. /// /// The inference provider. /// The suffix including its colon, or an empty string when the router should choose. public static string ModelSuffix(this HFInferenceProvider provider) => provider switch { HFInferenceProvider.NONE or HFInferenceProvider.AUTOMATIC => string.Empty, HFInferenceProvider.CHEAPEST => ":cheapest", HFInferenceProvider.PREFERRED => ":preferred", _ => $":{provider.EndpointsId()}", }; /// /// Whether this inference provider serves models to chat with. /// /// The inference provider. /// True, when the provider serves chat models. public static bool SupportsChat(this HFInferenceProvider provider) => provider is not HFInferenceProvider.NONE; /// /// Whether this inference provider creates embeddings for us. /// /// /// Embeddings are a much shorter story than chatting. The router serves them nowhere near its /// own endpoint, only through the route of a provider, and only two of those answer the /// OpenAI-compatible form we send. The routing strategies are out by their nature: without a /// named provider there is no route to address. /// /// The inference provider. /// True, when we can create embeddings through this provider. public static bool SupportsEmbeddings(this HFInferenceProvider provider) => provider is HFInferenceProvider.TOGETHER_AI or HFInferenceProvider.DEEPINFRA; /// /// Whether this inference provider transcribes audio for us. /// /// /// The same two providers as for embeddings, and for the same reason: transcription lives on a /// provider's own route, and only these two answer the OpenAI-compatible form there. Others do /// transcribe for Hugging Face, but not in a shape we could send an audio file to: fal-ai and /// Replicate both turn the request down with "Model not supported by provider". /// /// The inference provider. /// True, when we can transcribe audio through this provider. public static bool SupportsTranscription(this HFInferenceProvider provider) => provider is HFInferenceProvider.TOGETHER_AI or HFInferenceProvider.DEEPINFRA; /// /// The base URL of the provider's own OpenAI-compatible route. /// /// /// Only chatting goes through the router's own endpoint. Everything else has to address the /// provider directly, and they do not agree on where their OpenAI-compatible API sits: DeepInfra /// keeps it below an additional "openai" segment, and answers the path without it with /// "Not allowed to POST /v1/embeddings for provider deepinfra". /// /// The inference provider. /// The base URL, or an empty string when the provider has no such route. public static string ProviderBaseURL(this HFInferenceProvider provider) => provider switch { HFInferenceProvider.TOGETHER_AI => "https://router.huggingface.co/together/v1/", HFInferenceProvider.DEEPINFRA => "https://router.huggingface.co/deepinfra/v1/openai/", _ => string.Empty, }; /// /// Removes the routing suffix from a model, if it carries one. /// /// /// The suffix says where a request goes, not what the model is. Everything asking what a model /// can do has to look at the bare name: "google/gemma-4-31B-it:novita" is the same model as /// "google/gemma-4-31B-it", and a name detection which never heard of the suffix would miss it. /// Model IDs on the hub are written as "org/model" and carry no colon of their own, so the last /// colon always starts the suffix. /// /// The model as it is configured. /// The model without its routing suffix. public static Model WithoutRoutingSuffix(this Model model) { var separatorIndex = model.Id.LastIndexOf(':'); return separatorIndex is -1 ? model : model with { Id = model.Id[..separatorIndex] }; } /// /// The value to filter the Hugging Face model catalog by. /// /// The inference provider. /// The provider slug, or "all" when no particular provider was chosen. public static string CatalogFilter(this HFInferenceProvider provider) { var slug = provider.EndpointsId(); return string.IsNullOrEmpty(slug) ? "all" : slug; } public static string ToName(this HFInferenceProvider provider) => provider switch { HFInferenceProvider.AUTOMATIC => TB("Automatic: the fastest provider"), HFInferenceProvider.CHEAPEST => TB("Automatic: the cheapest provider"), HFInferenceProvider.PREFERRED => TB("Automatic: your preferred order"), HFInferenceProvider.BASETEN => "Baseten", HFInferenceProvider.CEREBRAS => "Cerebras", HFInferenceProvider.COHERE => "Cohere", HFInferenceProvider.DEEPINFRA => "DeepInfra", HFInferenceProvider.FEATHERLESS_AI => "Featherless AI", HFInferenceProvider.FIREWORKS => "Fireworks AI", HFInferenceProvider.GROQ => "Groq", HFInferenceProvider.NOVITA => "Novita", HFInferenceProvider.NSCALE => "Nscale", HFInferenceProvider.OVHCLOUD => "OVHcloud", HFInferenceProvider.PUBLIC_AI => "Public AI", HFInferenceProvider.SCALEWAY => "Scaleway", HFInferenceProvider.TOGETHER_AI => "Together AI", HFInferenceProvider.ZAI => "Z.ai", _ => string.Empty, }; }