mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-05 02:47:21 +00:00
Moved all extension methods into extension blocks (#1155)
This commit is contained in:
1 parent
acc7d09fa2
commit
c0a75f39ac
138 files changed
+5884
-4954
No files matched your search
@@ -7,50 +7,53 @@ public static class ConfidenceLevelExtensions
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(ConfidenceLevelExtensions).Namespace, nameof(ConfidenceLevelExtensions));
|
||||
|
||||
public static string GetName(this ConfidenceLevel level) => level switch
|
||||
extension(ConfidenceLevel level)
|
||||
{
|
||||
ConfidenceLevel.NONE => TB("No provider selected"),
|
||||
public string GetName() => level switch
|
||||
{
|
||||
ConfidenceLevel.NONE => TB("No provider selected"),
|
||||
|
||||
ConfidenceLevel.UNTRUSTED => TB("Untrusted"),
|
||||
ConfidenceLevel.UNKNOWN => TB("Unknown"),
|
||||
ConfidenceLevel.VERY_LOW => TB("Very Low"),
|
||||
ConfidenceLevel.LOW => TB("Low"),
|
||||
ConfidenceLevel.MODERATE => TB("Moderate"),
|
||||
ConfidenceLevel.MEDIUM => TB("Medium"),
|
||||
ConfidenceLevel.HIGH => TB("High"),
|
||||
ConfidenceLevel.UNTRUSTED => TB("Untrusted"),
|
||||
ConfidenceLevel.UNKNOWN => TB("Unknown"),
|
||||
ConfidenceLevel.VERY_LOW => TB("Very Low"),
|
||||
ConfidenceLevel.LOW => TB("Low"),
|
||||
ConfidenceLevel.MODERATE => TB("Moderate"),
|
||||
ConfidenceLevel.MEDIUM => TB("Medium"),
|
||||
ConfidenceLevel.HIGH => TB("High"),
|
||||
|
||||
_ => TB("Unknown confidence level"),
|
||||
};
|
||||
|
||||
public static string GetColor(this ConfidenceLevel level, SettingsManager settingsManager) => (level, settingsManager.IsDarkMode) switch
|
||||
{
|
||||
(ConfidenceLevel.NONE, false) => "#cccccc",
|
||||
(ConfidenceLevel.NONE, true) => "#666666",
|
||||
_ => TB("Unknown confidence level"),
|
||||
};
|
||||
|
||||
(ConfidenceLevel.UNKNOWN, false) => "#777777",
|
||||
(ConfidenceLevel.UNKNOWN, true) => "#aaaaaa",
|
||||
public string GetColor(SettingsManager settingsManager) => (level, settingsManager.IsDarkMode) switch
|
||||
{
|
||||
(ConfidenceLevel.NONE, false) => "#cccccc",
|
||||
(ConfidenceLevel.NONE, true) => "#666666",
|
||||
|
||||
(ConfidenceLevel.UNKNOWN, false) => "#777777",
|
||||
(ConfidenceLevel.UNKNOWN, true) => "#aaaaaa",
|
||||
|
||||
(ConfidenceLevel.UNTRUSTED, false) => "#ff0000",
|
||||
(ConfidenceLevel.UNTRUSTED, true) => "#800000",
|
||||
(ConfidenceLevel.UNTRUSTED, false) => "#ff0000",
|
||||
(ConfidenceLevel.UNTRUSTED, true) => "#800000",
|
||||
|
||||
(ConfidenceLevel.VERY_LOW, false) => "#ff6600",
|
||||
(ConfidenceLevel.VERY_LOW, true) => "#803300",
|
||||
(ConfidenceLevel.VERY_LOW, false) => "#ff6600",
|
||||
(ConfidenceLevel.VERY_LOW, true) => "#803300",
|
||||
|
||||
(ConfidenceLevel.LOW, false) => "#ffcc00",
|
||||
(ConfidenceLevel.LOW, true) => "#806600",
|
||||
(ConfidenceLevel.LOW, false) => "#ffcc00",
|
||||
(ConfidenceLevel.LOW, true) => "#806600",
|
||||
|
||||
(ConfidenceLevel.MODERATE, false) => "#99cc00",
|
||||
(ConfidenceLevel.MODERATE, true) => "#4d6600",
|
||||
(ConfidenceLevel.MODERATE, false) => "#99cc00",
|
||||
(ConfidenceLevel.MODERATE, true) => "#4d6600",
|
||||
|
||||
(ConfidenceLevel.MEDIUM, false) => "#86b300",
|
||||
(ConfidenceLevel.MEDIUM, true) => "#394d00",
|
||||
(ConfidenceLevel.MEDIUM, false) => "#86b300",
|
||||
(ConfidenceLevel.MEDIUM, true) => "#394d00",
|
||||
|
||||
(ConfidenceLevel.HIGH, false) => "#009933",
|
||||
(ConfidenceLevel.HIGH, true) => "#004d1a",
|
||||
(ConfidenceLevel.HIGH, false) => "#009933",
|
||||
(ConfidenceLevel.HIGH, true) => "#004d1a",
|
||||
|
||||
(_, false) => "#cc6600",
|
||||
(_, true) => "#663300",
|
||||
};
|
||||
|
||||
public static string SetColorStyle(this ConfidenceLevel level, SettingsManager settingsManager) => $"--confidence-color: {level.GetColor(settingsManager)};";
|
||||
(_, false) => "#cc6600",
|
||||
(_, true) => "#663300",
|
||||
};
|
||||
|
||||
public string SetColorStyle(SettingsManager settingsManager) => $"--confidence-color: {level.GetColor(settingsManager)};";
|
||||
}
|
||||
}
|
||||
@@ -6,153 +6,153 @@ public static class HFInferenceProviderExtensions
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(HFInferenceProviderExtensions).Namespace, nameof(HFInferenceProviderExtensions));
|
||||
|
||||
/// <summary>
|
||||
/// The slug Hugging Face uses for this inference provider.
|
||||
/// </summary>
|
||||
/// <param name="provider">The inference provider.</param>
|
||||
/// <returns>The slug, or an empty string for the routing strategies, which name no provider.</returns>
|
||||
public static string EndpointsId(this HFInferenceProvider provider) => provider switch
|
||||
extension(HFInferenceProvider provider)
|
||||
{
|
||||
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",
|
||||
/// <summary>
|
||||
/// The slug Hugging Face uses for this inference provider.
|
||||
/// </summary>
|
||||
/// <returns>The slug, or an empty string for the routing strategies, which name no provider.</returns>
|
||||
public string EndpointsId() => 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,
|
||||
};
|
||||
_ => string.Empty,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The suffix which tells the router where to send the request.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
/// <param name="provider">The inference provider.</param>
|
||||
/// <returns>The suffix including its colon, or an empty string when the router should choose.</returns>
|
||||
public static string ModelSuffix(this HFInferenceProvider provider) => provider switch
|
||||
{
|
||||
HFInferenceProvider.NONE or HFInferenceProvider.AUTOMATIC => string.Empty,
|
||||
/// <summary>
|
||||
/// The suffix which tells the router where to send the request.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
/// <returns>The suffix including its colon, or an empty string when the router should choose.</returns>
|
||||
public string ModelSuffix() => provider switch
|
||||
{
|
||||
HFInferenceProvider.NONE or HFInferenceProvider.AUTOMATIC => string.Empty,
|
||||
|
||||
HFInferenceProvider.CHEAPEST => ":cheapest",
|
||||
HFInferenceProvider.PREFERRED => ":preferred",
|
||||
HFInferenceProvider.CHEAPEST => ":cheapest",
|
||||
HFInferenceProvider.PREFERRED => ":preferred",
|
||||
|
||||
_ => $":{provider.EndpointsId()}",
|
||||
};
|
||||
_ => $":{provider.EndpointsId()}",
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Whether this inference provider serves models to chat with.
|
||||
/// </summary>
|
||||
/// <param name="provider">The inference provider.</param>
|
||||
/// <returns>True, when the provider serves chat models.</returns>
|
||||
public static bool SupportsChat(this HFInferenceProvider provider) => provider is not HFInferenceProvider.NONE;
|
||||
/// <summary>
|
||||
/// Whether this inference provider serves models to chat with.
|
||||
/// </summary>
|
||||
/// <returns>True, when the provider serves chat models.</returns>
|
||||
public bool SupportsChat() => provider is not HFInferenceProvider.NONE;
|
||||
|
||||
/// <summary>
|
||||
/// Whether this inference provider creates embeddings for us.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
/// <param name="provider">The inference provider.</param>
|
||||
/// <returns>True, when we can create embeddings through this provider.</returns>
|
||||
public static bool SupportsEmbeddings(this HFInferenceProvider provider) => provider is HFInferenceProvider.TOGETHER_AI or HFInferenceProvider.DEEPINFRA;
|
||||
/// <summary>
|
||||
/// Whether this inference provider creates embeddings for us.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
/// <returns>True, when we can create embeddings through this provider.</returns>
|
||||
public bool SupportsEmbeddings() => provider is HFInferenceProvider.TOGETHER_AI or HFInferenceProvider.DEEPINFRA;
|
||||
|
||||
/// <summary>
|
||||
/// Whether this inference provider transcribes audio for us.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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".
|
||||
/// </remarks>
|
||||
/// <param name="provider">The inference provider.</param>
|
||||
/// <returns>True, when we can transcribe audio through this provider.</returns>
|
||||
public static bool SupportsTranscription(this HFInferenceProvider provider) => provider is HFInferenceProvider.TOGETHER_AI or HFInferenceProvider.DEEPINFRA;
|
||||
/// <summary>
|
||||
/// Whether this inference provider transcribes audio for us.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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".
|
||||
/// </remarks>
|
||||
/// <returns>True, when we can transcribe audio through this provider.</returns>
|
||||
public bool SupportsTranscription() => provider is HFInferenceProvider.TOGETHER_AI or HFInferenceProvider.DEEPINFRA;
|
||||
|
||||
/// <summary>
|
||||
/// The base URL of the provider's own OpenAI-compatible route.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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".
|
||||
/// </remarks>
|
||||
/// <param name="provider">The inference provider.</param>
|
||||
/// <returns>The base URL, or an empty string when the provider has no such route.</returns>
|
||||
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/",
|
||||
/// <summary>
|
||||
/// The base URL of the provider's own OpenAI-compatible route.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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".
|
||||
/// </remarks>
|
||||
/// <returns>The base URL, or an empty string when the provider has no such route.</returns>
|
||||
public string ProviderBaseURL() => provider switch
|
||||
{
|
||||
HFInferenceProvider.TOGETHER_AI => "https://router.huggingface.co/together/v1/",
|
||||
HFInferenceProvider.DEEPINFRA => "https://router.huggingface.co/deepinfra/v1/openai/",
|
||||
|
||||
_ => string.Empty,
|
||||
};
|
||||
_ => string.Empty,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The value to filter the Hugging Face model catalog by.
|
||||
/// </summary>
|
||||
/// <returns>The provider slug, or "all" when no particular provider was chosen.</returns>
|
||||
public string CatalogFilter()
|
||||
{
|
||||
var slug = provider.EndpointsId();
|
||||
return string.IsNullOrEmpty(slug) ? "all" : slug;
|
||||
}
|
||||
|
||||
public string ToName() => 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,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the routing suffix from a model, if it carries one.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
/// <param name="model">The model as it is configured.</param>
|
||||
/// <returns>The model without its routing suffix.</returns>
|
||||
public static Model WithoutRoutingSuffix(this Model model)
|
||||
extension(Model model)
|
||||
{
|
||||
var separatorIndex = model.Id.LastIndexOf(':');
|
||||
return separatorIndex is -1 ? model : model with { Id = model.Id[..separatorIndex] };
|
||||
/// <summary>
|
||||
/// Removes the routing suffix from a model, if it carries one.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
/// <returns>The model without its routing suffix.</returns>
|
||||
public Model WithoutRoutingSuffix()
|
||||
{
|
||||
var separatorIndex = model.Id.LastIndexOf(':');
|
||||
return separatorIndex is -1 ? model : model with { Id = model.Id[..separatorIndex] };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The value to filter the Hugging Face model catalog by.
|
||||
/// </summary>
|
||||
/// <param name="provider">The inference provider.</param>
|
||||
/// <returns>The provider slug, or "all" when no particular provider was chosen.</returns>
|
||||
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,
|
||||
};
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -5,41 +5,47 @@ public static class LLMProvidersIconExtensions
|
||||
private const string ICON_ROOT = "/images/provider-icons";
|
||||
private const string SVG_DATA_URL_PREFIX = "data:image/svg+xml;base64,";
|
||||
|
||||
public static string GetIconUrl(this AIStudio.Settings.Provider provider, bool isDarkMode)
|
||||
=> provider.UsedLLMProvider.GetIconUrl(isDarkMode, provider.CustomIconDataUrl);
|
||||
|
||||
public static string GetIconUrl(this LLMProviders provider, bool isDarkMode, string? customIconDataUrl)
|
||||
extension(AIStudio.Settings.Provider provider)
|
||||
{
|
||||
if (customIconDataUrl?.StartsWith(SVG_DATA_URL_PREFIX, StringComparison.Ordinal) == true)
|
||||
return customIconDataUrl;
|
||||
|
||||
return provider.GetIconUrl(isDarkMode);
|
||||
public string GetIconUrl(bool isDarkMode)
|
||||
=> provider.UsedLLMProvider.GetIconUrl(isDarkMode, provider.CustomIconDataUrl);
|
||||
}
|
||||
|
||||
public static string GetIconUrl(this LLMProviders provider, bool isDarkMode) => provider switch
|
||||
extension(LLMProviders provider)
|
||||
{
|
||||
LLMProviders.NONE => $"{ICON_ROOT}/provider{DarkVariant(isDarkMode)}.svg",
|
||||
LLMProviders.OPEN_AI => $"{ICON_ROOT}/openai{DarkVariant(isDarkMode)}.svg",
|
||||
LLMProviders.ANTHROPIC => $"{ICON_ROOT}/anthropic{DarkVariant(isDarkMode)}.svg",
|
||||
LLMProviders.MISTRAL => $"{ICON_ROOT}/mistral.svg",
|
||||
LLMProviders.GOOGLE => $"{ICON_ROOT}/google.svg",
|
||||
LLMProviders.X => $"{ICON_ROOT}/x{DarkVariant(isDarkMode)}.svg",
|
||||
LLMProviders.DEEP_SEEK => $"{ICON_ROOT}/deepseek.svg",
|
||||
LLMProviders.ALIBABA_CLOUD => $"{ICON_ROOT}/alibaba-cloud.svg",
|
||||
LLMProviders.PERPLEXITY => $"{ICON_ROOT}/perplexity.svg",
|
||||
LLMProviders.OPEN_ROUTER => $"{ICON_ROOT}/openrouter.svg",
|
||||
LLMProviders.HETZNER => $"{ICON_ROOT}/hetzner.svg",
|
||||
LLMProviders.IONOS => $"{ICON_ROOT}/ionos.svg",
|
||||
LLMProviders.LITE_LLM => $"{ICON_ROOT}/litellm.svg",
|
||||
LLMProviders.REQUESTY => $"{ICON_ROOT}/requesty.svg",
|
||||
LLMProviders.GROQ => $"{ICON_ROOT}/groq.svg",
|
||||
LLMProviders.FIREWORKS => $"{ICON_ROOT}/fireworks.svg",
|
||||
LLMProviders.HUGGINGFACE => $"{ICON_ROOT}/hugging-face.svg",
|
||||
LLMProviders.SELF_HOSTED => $"{ICON_ROOT}/self-hosted{DarkVariant(isDarkMode)}.svg",
|
||||
LLMProviders.HELMHOLTZ => $"{ICON_ROOT}/helmholtz.svg",
|
||||
LLMProviders.GWDG => $"{ICON_ROOT}/gwdg.svg",
|
||||
_ => $"{ICON_ROOT}/provider{DarkVariant(isDarkMode)}.svg",
|
||||
};
|
||||
public string GetIconUrl(bool isDarkMode, string? customIconDataUrl)
|
||||
{
|
||||
if (customIconDataUrl?.StartsWith(SVG_DATA_URL_PREFIX, StringComparison.Ordinal) == true)
|
||||
return customIconDataUrl;
|
||||
|
||||
return provider.GetIconUrl(isDarkMode);
|
||||
}
|
||||
|
||||
public string GetIconUrl(bool isDarkMode) => provider switch
|
||||
{
|
||||
LLMProviders.NONE => $"{ICON_ROOT}/provider{DarkVariant(isDarkMode)}.svg",
|
||||
LLMProviders.OPEN_AI => $"{ICON_ROOT}/openai{DarkVariant(isDarkMode)}.svg",
|
||||
LLMProviders.ANTHROPIC => $"{ICON_ROOT}/anthropic{DarkVariant(isDarkMode)}.svg",
|
||||
LLMProviders.MISTRAL => $"{ICON_ROOT}/mistral.svg",
|
||||
LLMProviders.GOOGLE => $"{ICON_ROOT}/google.svg",
|
||||
LLMProviders.X => $"{ICON_ROOT}/x{DarkVariant(isDarkMode)}.svg",
|
||||
LLMProviders.DEEP_SEEK => $"{ICON_ROOT}/deepseek.svg",
|
||||
LLMProviders.ALIBABA_CLOUD => $"{ICON_ROOT}/alibaba-cloud.svg",
|
||||
LLMProviders.PERPLEXITY => $"{ICON_ROOT}/perplexity.svg",
|
||||
LLMProviders.OPEN_ROUTER => $"{ICON_ROOT}/openrouter.svg",
|
||||
LLMProviders.HETZNER => $"{ICON_ROOT}/hetzner.svg",
|
||||
LLMProviders.IONOS => $"{ICON_ROOT}/ionos.svg",
|
||||
LLMProviders.LITE_LLM => $"{ICON_ROOT}/litellm.svg",
|
||||
LLMProviders.REQUESTY => $"{ICON_ROOT}/requesty.svg",
|
||||
LLMProviders.GROQ => $"{ICON_ROOT}/groq.svg",
|
||||
LLMProviders.FIREWORKS => $"{ICON_ROOT}/fireworks.svg",
|
||||
LLMProviders.HUGGINGFACE => $"{ICON_ROOT}/hugging-face.svg",
|
||||
LLMProviders.SELF_HOSTED => $"{ICON_ROOT}/self-hosted{DarkVariant(isDarkMode)}.svg",
|
||||
LLMProviders.HELMHOLTZ => $"{ICON_ROOT}/helmholtz.svg",
|
||||
LLMProviders.GWDG => $"{ICON_ROOT}/gwdg.svg",
|
||||
_ => $"{ICON_ROOT}/provider{DarkVariant(isDarkMode)}.svg",
|
||||
};
|
||||
}
|
||||
|
||||
private static string DarkVariant(bool isDarkMode) => isDarkMode ? "-dark" : string.Empty;
|
||||
}
|
||||
@@ -6,16 +6,19 @@ public static class ModelLoadFailureReasonExtensions
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(ModelLoadFailureReasonExtensions).Namespace, nameof(ModelLoadFailureReasonExtensions));
|
||||
|
||||
public static string ToUserMessage(this ModelLoadFailureReason failureReason, string providerName) => failureReason switch
|
||||
extension(ModelLoadFailureReason failureReason)
|
||||
{
|
||||
ModelLoadFailureReason.INVALID_OR_MISSING_API_KEY => string.Format(TB("We could not load models from '{0}'. The API key is probably missing, invalid, or expired."), providerName),
|
||||
ModelLoadFailureReason.AUTHENTICATION_OR_PERMISSION_ERROR => string.Format(TB("We could not load models from '{0}'. The account or API key does not have the required permissions."), providerName),
|
||||
ModelLoadFailureReason.INSUFFICIENT_QUOTA => string.Format(TB("We could not load models from '{0}' because the account appears to have no API credits left."), providerName),
|
||||
ModelLoadFailureReason.TOO_MANY_REQUESTS => string.Format(TB("We could not load models from '{0}' because too many requests were sent. Please wait a moment and try again."), providerName),
|
||||
ModelLoadFailureReason.PROVIDER_UNAVAILABLE => string.Format(TB("We could not load models from '{0}' because the provider is currently unavailable or could not be reached."), providerName),
|
||||
ModelLoadFailureReason.INVALID_RESPONSE => string.Format(TB("We could not load models from '{0}' because the provider returned an unexpected response."), providerName),
|
||||
ModelLoadFailureReason.UNKNOWN => string.Format(TB("We could not load models from '{0}' due to an unknown error."), providerName),
|
||||
public string ToUserMessage(string providerName) => failureReason switch
|
||||
{
|
||||
ModelLoadFailureReason.INVALID_OR_MISSING_API_KEY => string.Format(TB("We could not load models from '{0}'. The API key is probably missing, invalid, or expired."), providerName),
|
||||
ModelLoadFailureReason.AUTHENTICATION_OR_PERMISSION_ERROR => string.Format(TB("We could not load models from '{0}'. The account or API key does not have the required permissions."), providerName),
|
||||
ModelLoadFailureReason.INSUFFICIENT_QUOTA => string.Format(TB("We could not load models from '{0}' because the account appears to have no API credits left."), providerName),
|
||||
ModelLoadFailureReason.TOO_MANY_REQUESTS => string.Format(TB("We could not load models from '{0}' because too many requests were sent. Please wait a moment and try again."), providerName),
|
||||
ModelLoadFailureReason.PROVIDER_UNAVAILABLE => string.Format(TB("We could not load models from '{0}' because the provider is currently unavailable or could not be reached."), providerName),
|
||||
ModelLoadFailureReason.INVALID_RESPONSE => string.Format(TB("We could not load models from '{0}' because the provider returned an unexpected response."), providerName),
|
||||
ModelLoadFailureReason.UNKNOWN => string.Format(TB("We could not load models from '{0}' due to an unknown error."), providerName),
|
||||
|
||||
_ => string.Empty,
|
||||
};
|
||||
_ => string.Empty,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -4,22 +4,25 @@ namespace AIStudio.Provider.OpenAI;
|
||||
|
||||
public static class SystemPromptRoleExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Spells a system prompt role the way OpenAI's APIs expect it.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A role no rule states becomes "developer". OpenAI's current documentation names no other, a
|
||||
/// model the rules do not know is almost always one released after they were written, and the
|
||||
/// older generations which still want "system" say so in their families.
|
||||
/// </remarks>
|
||||
/// <param name="role">The role the model profile states.</param>
|
||||
/// <returns>The role, as OpenAI names it.</returns>
|
||||
public static string ToOpenAIRole(this SystemPromptRole role) => role switch
|
||||
extension(SystemPromptRole role)
|
||||
{
|
||||
SystemPromptRole.SYSTEM => "system",
|
||||
SystemPromptRole.DEVELOPER => "developer",
|
||||
SystemPromptRole.USER => "user",
|
||||
/// <summary>
|
||||
/// Spells a system prompt role the way OpenAI's APIs expect it.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A role no rule states becomes "developer". OpenAI's current documentation names no other, a
|
||||
/// model the rules do not know is almost always one released after they were written, and the
|
||||
/// older generations which still want "system" say so in their families.
|
||||
/// </remarks>
|
||||
/// <returns>The role, as OpenAI names it.</returns>
|
||||
public string ToOpenAIRole() => role switch
|
||||
{
|
||||
SystemPromptRole.SYSTEM => "system",
|
||||
SystemPromptRole.DEVELOPER => "developer",
|
||||
SystemPromptRole.USER => "user",
|
||||
|
||||
_ => "developer",
|
||||
};
|
||||
_ => "developer",
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -6,42 +6,45 @@ public static class ProviderRequestFailureReasonExtensions
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(ProviderRequestFailureReasonExtensions).Namespace, nameof(ProviderRequestFailureReasonExtensions));
|
||||
|
||||
/// <summary>
|
||||
/// Names the kind of failure in a few words.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Meant as a label beside the full message, so a list of failures can be scanned instead of
|
||||
/// read: twenty entries which all say API key are one problem, not twenty.
|
||||
/// </remarks>
|
||||
public static string GetName(this ProviderRequestFailureReason failureReason) => failureReason switch
|
||||
extension(ProviderRequestFailureReason failureReason)
|
||||
{
|
||||
ProviderRequestFailureReason.INSUFFICIENT_QUOTA => TB("No credits left"),
|
||||
ProviderRequestFailureReason.TOO_MANY_REQUESTS => TB("Too many requests"),
|
||||
ProviderRequestFailureReason.MODEL_NOT_SUPPORTED_BY_PROVIDER => TB("Model not offered"),
|
||||
ProviderRequestFailureReason.INVALID_OR_MISSING_API_KEY => TB("API key problem"),
|
||||
ProviderRequestFailureReason.AUTHENTICATION_OR_PERMISSION_ERROR => TB("Not permitted"),
|
||||
ProviderRequestFailureReason.PROVIDER_UNAVAILABLE => TB("Provider unreachable"),
|
||||
ProviderRequestFailureReason.MODEL_NOT_FOUND => TB("Model unknown"),
|
||||
ProviderRequestFailureReason.CONTEXT_LENGTH_EXCEEDED => TB("Text too long"),
|
||||
ProviderRequestFailureReason.EMBEDDINGS_NOT_SUPPORTED => TB("No embeddings"),
|
||||
ProviderRequestFailureReason.INVALID_RESPONSE => TB("Unreadable answer"),
|
||||
ProviderRequestFailureReason.UNKNOWN => TB("Unknown cause"),
|
||||
/// <summary>
|
||||
/// Names the kind of failure in a few words.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Meant as a label beside the full message, so a list of failures can be scanned instead of
|
||||
/// read: twenty entries which all say API key are one problem, not twenty.
|
||||
/// </remarks>
|
||||
public string GetName() => failureReason switch
|
||||
{
|
||||
ProviderRequestFailureReason.INSUFFICIENT_QUOTA => TB("No credits left"),
|
||||
ProviderRequestFailureReason.TOO_MANY_REQUESTS => TB("Too many requests"),
|
||||
ProviderRequestFailureReason.MODEL_NOT_SUPPORTED_BY_PROVIDER => TB("Model not offered"),
|
||||
ProviderRequestFailureReason.INVALID_OR_MISSING_API_KEY => TB("API key problem"),
|
||||
ProviderRequestFailureReason.AUTHENTICATION_OR_PERMISSION_ERROR => TB("Not permitted"),
|
||||
ProviderRequestFailureReason.PROVIDER_UNAVAILABLE => TB("Provider unreachable"),
|
||||
ProviderRequestFailureReason.MODEL_NOT_FOUND => TB("Model unknown"),
|
||||
ProviderRequestFailureReason.CONTEXT_LENGTH_EXCEEDED => TB("Text too long"),
|
||||
ProviderRequestFailureReason.EMBEDDINGS_NOT_SUPPORTED => TB("No embeddings"),
|
||||
ProviderRequestFailureReason.INVALID_RESPONSE => TB("Unreadable answer"),
|
||||
ProviderRequestFailureReason.UNKNOWN => TB("Unknown cause"),
|
||||
|
||||
_ => string.Empty,
|
||||
};
|
||||
_ => string.Empty,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the way out of this failure is in the provider settings.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only for the failures a setting actually fixes. Pointing at the settings for a provider
|
||||
/// which is merely overloaded would send the user looking for a mistake they never made.
|
||||
/// </remarks>
|
||||
public static bool IsFixedInProviderSettings(this ProviderRequestFailureReason failureReason) => failureReason is
|
||||
ProviderRequestFailureReason.INVALID_OR_MISSING_API_KEY or
|
||||
ProviderRequestFailureReason.AUTHENTICATION_OR_PERMISSION_ERROR or
|
||||
ProviderRequestFailureReason.MODEL_NOT_FOUND or
|
||||
ProviderRequestFailureReason.MODEL_NOT_SUPPORTED_BY_PROVIDER or
|
||||
ProviderRequestFailureReason.EMBEDDINGS_NOT_SUPPORTED or
|
||||
ProviderRequestFailureReason.CONTEXT_LENGTH_EXCEEDED;
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the way out of this failure is in the provider settings.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only for the failures a setting actually fixes. Pointing at the settings for a provider
|
||||
/// which is merely overloaded would send the user looking for a mistake they never made.
|
||||
/// </remarks>
|
||||
public bool IsFixedInProviderSettings() => failureReason is
|
||||
ProviderRequestFailureReason.INVALID_OR_MISSING_API_KEY or
|
||||
ProviderRequestFailureReason.AUTHENTICATION_OR_PERMISSION_ERROR or
|
||||
ProviderRequestFailureReason.MODEL_NOT_FOUND or
|
||||
ProviderRequestFailureReason.MODEL_NOT_SUPPORTED_BY_PROVIDER or
|
||||
ProviderRequestFailureReason.EMBEDDINGS_NOT_SUPPORTED or
|
||||
ProviderRequestFailureReason.CONTEXT_LENGTH_EXCEEDED;
|
||||
}
|
||||
}
|
||||
@@ -2,141 +2,143 @@ namespace AIStudio.Provider.SelfHosted;
|
||||
|
||||
public static class HostExtensions
|
||||
{
|
||||
public static string Name(this Host host) => host switch
|
||||
{
|
||||
Host.NONE => "None",
|
||||
|
||||
Host.LM_STUDIO => "LM Studio",
|
||||
Host.LLAMA_CPP => "llama.cpp",
|
||||
Host.WHISPER_CPP => "whisper.cpp",
|
||||
Host.OLLAMA => "ollama",
|
||||
Host.VLLM => "vLLM",
|
||||
Host.LLMMAN => "llmman",
|
||||
|
||||
_ => "Unknown",
|
||||
};
|
||||
|
||||
public static string BaseURL(this Host host) => host switch
|
||||
{
|
||||
_ => "/v1/",
|
||||
};
|
||||
|
||||
public static string ChatURL(this Host host) => host switch
|
||||
{
|
||||
_ => "chat/completions",
|
||||
};
|
||||
|
||||
public static string TranscriptionURL(this Host host) => host switch
|
||||
{
|
||||
_ => "audio/transcriptions",
|
||||
};
|
||||
|
||||
public static string EmbeddingURL(this Host host) => host switch
|
||||
{
|
||||
_ => "embeddings",
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The largest image file, in bytes, which the engine accepts in a chat request, where we know of one.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Like the limit of a cloud provider, see LLMProvidersExtensions.GetMaxImageSizeBytes, this
|
||||
/// belongs to the API of the engine, not to the model. What we actually send is asked through
|
||||
/// IImageSourceExtensions.MaxImageSizeBytesFor.
|
||||
/// </remarks>
|
||||
/// <param name="host">The engine.</param>
|
||||
/// <returns>The size limit of one image file, or null when the engine states none we know of.</returns>
|
||||
public static long? GetMaxImageSizeBytes(this Host host) => host switch
|
||||
extension(Host host)
|
||||
{
|
||||
//
|
||||
// llmman answers a chat request larger than 2 MiB with 413: its route /v1/chat/completions
|
||||
// keeps the default limit of its web framework, read on 2026-10-22 at
|
||||
// https://github.com/llmmanorg/llmman/blob/main/src/cmd/serve.rs. An image of 1 MiB takes
|
||||
// about 1.33 MiB as base64, which leaves room for the text of the conversation:
|
||||
//
|
||||
Host.LLMMAN => 1_048_576,
|
||||
|
||||
_ => null,
|
||||
};
|
||||
|
||||
public static bool IsChatSupported(this Host host)
|
||||
{
|
||||
switch (host)
|
||||
public string Name() => host switch
|
||||
{
|
||||
case Host.WHISPER_CPP:
|
||||
return false;
|
||||
Host.NONE => "None",
|
||||
|
||||
Host.LM_STUDIO => "LM Studio",
|
||||
Host.LLAMA_CPP => "llama.cpp",
|
||||
Host.WHISPER_CPP => "whisper.cpp",
|
||||
Host.OLLAMA => "ollama",
|
||||
Host.VLLM => "vLLM",
|
||||
Host.LLMMAN => "llmman",
|
||||
|
||||
_ => "Unknown",
|
||||
};
|
||||
|
||||
public string BaseURL() => host switch
|
||||
{
|
||||
_ => "/v1/",
|
||||
};
|
||||
|
||||
public string ChatURL() => host switch
|
||||
{
|
||||
_ => "chat/completions",
|
||||
};
|
||||
|
||||
public string TranscriptionURL() => host switch
|
||||
{
|
||||
_ => "audio/transcriptions",
|
||||
};
|
||||
|
||||
public string EmbeddingURL() => host switch
|
||||
{
|
||||
_ => "embeddings",
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The largest image file, in bytes, which the engine accepts in a chat request, where we know of one.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Like the limit of a cloud provider, see LLMProvidersExtensions.GetMaxImageSizeBytes, this
|
||||
/// belongs to the API of the engine, not to the model. What we actually send is asked through
|
||||
/// IImageSourceExtensions.MaxImageSizeBytesFor.
|
||||
/// </remarks>
|
||||
/// <returns>The size limit of one image file, or null when the engine states none we know of.</returns>
|
||||
public long? GetMaxImageSizeBytes() => host switch
|
||||
{
|
||||
//
|
||||
// llmman answers a chat request larger than 2 MiB with 413: its route /v1/chat/completions
|
||||
// keeps the default limit of its web framework, read on 2026-10-22 at
|
||||
// https://github.com/llmmanorg/llmman/blob/main/src/cmd/serve.rs. An image of 1 MiB takes
|
||||
// about 1.33 MiB as base64, which leaves room for the text of the conversation:
|
||||
//
|
||||
Host.LLMMAN => 1_048_576,
|
||||
|
||||
_ => null,
|
||||
};
|
||||
|
||||
public bool IsChatSupported()
|
||||
{
|
||||
switch (host)
|
||||
{
|
||||
case Host.WHISPER_CPP:
|
||||
return false;
|
||||
|
||||
default:
|
||||
case Host.OLLAMA:
|
||||
case Host.VLLM:
|
||||
case Host.LM_STUDIO:
|
||||
case Host.LLAMA_CPP:
|
||||
case Host.LLMMAN:
|
||||
return true;
|
||||
default:
|
||||
case Host.OLLAMA:
|
||||
case Host.VLLM:
|
||||
case Host.LM_STUDIO:
|
||||
case Host.LLAMA_CPP:
|
||||
case Host.LLMMAN:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsEmbeddingSupported(this Host host)
|
||||
{
|
||||
switch (host)
|
||||
|
||||
public bool IsEmbeddingSupported()
|
||||
{
|
||||
case Host.LM_STUDIO:
|
||||
case Host.OLLAMA:
|
||||
case Host.VLLM:
|
||||
case Host.LLMMAN:
|
||||
return true;
|
||||
switch (host)
|
||||
{
|
||||
case Host.LM_STUDIO:
|
||||
case Host.OLLAMA:
|
||||
case Host.VLLM:
|
||||
case Host.LLMMAN:
|
||||
return true;
|
||||
|
||||
default:
|
||||
case Host.LLAMA_CPP:
|
||||
return false;
|
||||
default:
|
||||
case Host.LLAMA_CPP:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsTranscriptionSupported(this Host host)
|
||||
{
|
||||
switch (host)
|
||||
{
|
||||
case Host.OLLAMA:
|
||||
case Host.VLLM:
|
||||
case Host.WHISPER_CPP:
|
||||
case Host.LLMMAN:
|
||||
return true;
|
||||
|
||||
default:
|
||||
case Host.LM_STUDIO:
|
||||
case Host.LLAMA_CPP:
|
||||
return false;
|
||||
public bool IsTranscriptionSupported()
|
||||
{
|
||||
switch (host)
|
||||
{
|
||||
case Host.OLLAMA:
|
||||
case Host.VLLM:
|
||||
case Host.WHISPER_CPP:
|
||||
case Host.LLMMAN:
|
||||
return true;
|
||||
|
||||
default:
|
||||
case Host.LM_STUDIO:
|
||||
case Host.LLAMA_CPP:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the engine answers the models route with the models it serves.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the only place which says so. The provider asks it before it loads the models of a
|
||||
/// chat, embedding, or transcription list, and the dialogs ask it before they offer to reload
|
||||
/// them; a new engine therefore needs no more than its line here. whisper.cpp is not among
|
||||
/// them: it serves the one model it was started with and has no route to list it, so the
|
||||
/// provider offers that model under a fixed name instead. llama.cpp is, even though builds
|
||||
/// older than the route answer it with 404; the provider handles those builds itself.
|
||||
/// </remarks>
|
||||
/// <param name="host">The engine.</param>
|
||||
/// <returns>True when the models can be loaded from the engine; otherwise, false.</returns>
|
||||
public static bool IsModelListSupported(this Host host)
|
||||
{
|
||||
switch (host)
|
||||
/// <summary>
|
||||
/// Whether the engine answers the models route with the models it serves.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the only place which says so. The provider asks it before it loads the models of a
|
||||
/// chat, embedding, or transcription list, and the dialogs ask it before they offer to reload
|
||||
/// them; a new engine therefore needs no more than its line here. whisper.cpp is not among
|
||||
/// them: it serves the one model it was started with and has no route to list it, so the
|
||||
/// provider offers that model under a fixed name instead. llama.cpp is, even though builds
|
||||
/// older than the route answer it with 404; the provider handles those builds itself.
|
||||
/// </remarks>
|
||||
/// <returns>True when the models can be loaded from the engine; otherwise, false.</returns>
|
||||
public bool IsModelListSupported()
|
||||
{
|
||||
case Host.LLAMA_CPP:
|
||||
case Host.OLLAMA:
|
||||
case Host.LM_STUDIO:
|
||||
case Host.VLLM:
|
||||
case Host.LLMMAN:
|
||||
return true;
|
||||
switch (host)
|
||||
{
|
||||
case Host.LLAMA_CPP:
|
||||
case Host.OLLAMA:
|
||||
case Host.LM_STUDIO:
|
||||
case Host.VLLM:
|
||||
case Host.LLMMAN:
|
||||
return true;
|
||||
|
||||
default:
|
||||
case Host.NONE:
|
||||
case Host.WHISPER_CPP:
|
||||
return false;
|
||||
default:
|
||||
case Host.NONE:
|
||||
case Host.WHISPER_CPP:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user