diff --git a/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs b/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs index 8c7c9d72..f0903ded 100644 --- a/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs +++ b/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs @@ -162,13 +162,17 @@ public sealed class ProviderAnthropic(ILogger logger) : BaseProvider("https://ap }.AsEnumerable()); } - #pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously /// public Task> GetImageModels(string? apiKeyProvisional = null, CancellationToken token = default) { return Task.FromResult(Enumerable.Empty()); } - #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously + + /// + public Task> GetEmbeddingModels(string? apiKeyProvisional = null, CancellationToken token = default) + { + return Task.FromResult(Enumerable.Empty()); + } #endregion } \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs b/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs index a48582be..c60e3fe6 100644 --- a/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs +++ b/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs @@ -155,6 +155,12 @@ public class ProviderFireworks(ILogger logger) : BaseProvider("https://api.firew { return Task.FromResult(Enumerable.Empty()); } + + /// + public Task> GetEmbeddingModels(string? apiKeyProvisional = null, CancellationToken token = default) + { + return Task.FromResult(Enumerable.Empty()); + } #endregion } \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/Google/ProviderGoogle.cs b/app/MindWork AI Studio/Provider/Google/ProviderGoogle.cs index 9e523ddb..226d4cb1 100644 --- a/app/MindWork AI Studio/Provider/Google/ProviderGoogle.cs +++ b/app/MindWork AI Studio/Provider/Google/ProviderGoogle.cs @@ -146,9 +146,15 @@ public class ProviderGoogle(ILogger logger) : BaseProvider("https://generativela #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously /// - public Task> GetTextModels(string? apiKeyProvisional = null, CancellationToken token = default) + public async Task> GetTextModels(string? apiKeyProvisional = null, CancellationToken token = default) { - return this.LoadModels(token, apiKeyProvisional); + var modelResponse = await this.LoadModels(token, apiKeyProvisional); + if(modelResponse == default) + return []; + + return modelResponse.Models.Where(model => + model.Name.StartsWith("models/gemini-", StringComparison.InvariantCultureIgnoreCase)) + .Select(n => new Provider.Model(n.Name.Replace("models/", string.Empty), n.DisplayName)); } /// @@ -157,9 +163,20 @@ public class ProviderGoogle(ILogger logger) : BaseProvider("https://generativela return Task.FromResult(Enumerable.Empty()); } + public async Task> GetEmbeddingModels(string? apiKeyProvisional = null, CancellationToken token = default) + { + var modelResponse = await this.LoadModels(token, apiKeyProvisional); + if(modelResponse == default) + return []; + + return modelResponse.Models.Where(model => + model.Name.StartsWith("models/text-embedding-", StringComparison.InvariantCultureIgnoreCase)) + .Select(n => new Provider.Model(n.Name.Replace("models/", string.Empty), n.DisplayName)); + } + #endregion - private async Task> LoadModels(CancellationToken token, string? apiKeyProvisional = null) + private async Task LoadModels(CancellationToken token, string? apiKeyProvisional = null) { var secretKey = apiKeyProvisional switch { @@ -170,19 +187,17 @@ public class ProviderGoogle(ILogger logger) : BaseProvider("https://generativela _ => null, } }; - + if (secretKey is null) - return []; + return default; var request = new HttpRequestMessage(HttpMethod.Get, $"models?key={secretKey}"); var response = await this.httpClient.SendAsync(request, token); if(!response.IsSuccessStatusCode) - return []; + return default; var modelResponse = await response.Content.ReadFromJsonAsync(token); - return modelResponse.Models.Where(model => - model.Name.StartsWith("models/gemini-", StringComparison.InvariantCultureIgnoreCase)) - .Select(n => new Provider.Model(n.Name.Replace("models/", string.Empty), n.DisplayName)); + return modelResponse; } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/Groq/ProviderGroq.cs b/app/MindWork AI Studio/Provider/Groq/ProviderGroq.cs index 1340a3a6..703a449f 100644 --- a/app/MindWork AI Studio/Provider/Groq/ProviderGroq.cs +++ b/app/MindWork AI Studio/Provider/Groq/ProviderGroq.cs @@ -158,6 +158,12 @@ public class ProviderGroq(ILogger logger) : BaseProvider("https://api.groq.com/o { return Task.FromResult>(Array.Empty()); } + + /// + public Task> GetEmbeddingModels(string? apiKeyProvisional = null, CancellationToken token = default) + { + return Task.FromResult(Enumerable.Empty()); + } #endregion diff --git a/app/MindWork AI Studio/Provider/IProvider.cs b/app/MindWork AI Studio/Provider/IProvider.cs index ef3214bb..6f32a75b 100644 --- a/app/MindWork AI Studio/Provider/IProvider.cs +++ b/app/MindWork AI Studio/Provider/IProvider.cs @@ -53,4 +53,12 @@ public interface IProvider /// The cancellation token. /// The list of image models. public Task> GetImageModels(string? apiKeyProvisional = null, CancellationToken token = default); + + /// + /// Load all possible embedding models that can be used with this provider. + /// + /// The provisional API key to use. Useful when the user is adding a new provider. When null, the stored API key is used. + /// The cancellation token. + /// The list of embedding models. + public Task> GetEmbeddingModels(string? apiKeyProvisional = null, CancellationToken token = default); } \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs b/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs index 23296669..6d2a10b9 100644 --- a/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs +++ b/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs @@ -148,6 +148,37 @@ public sealed class ProviderMistral(ILogger logger) : BaseProvider("https://api. /// public async Task> GetTextModels(string? apiKeyProvisional = null, CancellationToken token = default) + { + var modelResponse = await this.LoadModelList(apiKeyProvisional, token); + if(modelResponse == default) + return []; + + return modelResponse.Data.Where(n => + !n.Id.StartsWith("code", StringComparison.InvariantCulture) && + !n.Id.Contains("embed", StringComparison.InvariantCulture)) + .Select(n => new Provider.Model(n.Id, null)); + } + + /// + public async Task> GetEmbeddingModels(string? apiKeyProvisional = null, CancellationToken token = default) + { + var modelResponse = await this.LoadModelList(apiKeyProvisional, token); + if(modelResponse == default) + return []; + + return modelResponse.Data.Where(n => n.Id.Contains("embed", StringComparison.InvariantCulture)) + .Select(n => new Provider.Model(n.Id, null)); + } + + /// + public Task> GetImageModels(string? apiKeyProvisional = null, CancellationToken token = default) + { + return Task.FromResult(Enumerable.Empty()); + } + + #endregion + + private async Task LoadModelList(string? apiKeyProvisional, CancellationToken token) { var secretKey = apiKeyProvisional switch { @@ -160,29 +191,16 @@ public sealed class ProviderMistral(ILogger logger) : BaseProvider("https://api. }; if (secretKey is null) - return []; + return default; var request = new HttpRequestMessage(HttpMethod.Get, "models"); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", secretKey); var response = await this.httpClient.SendAsync(request, token); if(!response.IsSuccessStatusCode) - return []; + return default; var modelResponse = await response.Content.ReadFromJsonAsync(token); - return modelResponse.Data.Where(n => - !n.Id.StartsWith("code", StringComparison.InvariantCulture) && - !n.Id.Contains("embed", StringComparison.InvariantCulture)) - .Select(n => new Provider.Model(n.Id, null)); + return modelResponse; } - - #pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously - /// - public Task> GetImageModels(string? apiKeyProvisional = null, CancellationToken token = default) - { - return Task.FromResult(Enumerable.Empty()); - } - #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously - - #endregion } \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/NoProvider.cs b/app/MindWork AI Studio/Provider/NoProvider.cs index f6a6079b..6efcc381 100644 --- a/app/MindWork AI Studio/Provider/NoProvider.cs +++ b/app/MindWork AI Studio/Provider/NoProvider.cs @@ -15,6 +15,8 @@ public class NoProvider : IProvider public Task> GetTextModels(string? apiKeyProvisional = null, CancellationToken token = default) => Task.FromResult>([]); public Task> GetImageModels(string? apiKeyProvisional = null, CancellationToken token = default) => Task.FromResult>([]); + + public Task> GetEmbeddingModels(string? apiKeyProvisional = null, CancellationToken token = default) => Task.FromResult>([]); public async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatChatThread, [EnumeratorCancellation] CancellationToken token = default) { diff --git a/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs b/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs index 3ca5ac0e..bae64478 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs @@ -161,6 +161,12 @@ public sealed class ProviderOpenAI(ILogger logger) : BaseProvider("https://api.o { return this.LoadModels(["dall-e-"], token, apiKeyProvisional); } + + /// + public Task> GetEmbeddingModels(string? apiKeyProvisional = null, CancellationToken token = default) + { + return this.LoadModels(["text-embedding-"], token, apiKeyProvisional); + } #endregion diff --git a/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs b/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs index f50b34c7..e1bbfbae 100644 --- a/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs +++ b/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs @@ -200,13 +200,16 @@ public sealed class ProviderSelfHosted(ILogger logger, Settings.Provider provide } } - #pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously /// public Task> GetImageModels(string? apiKeyProvisional = null, CancellationToken token = default) { return Task.FromResult(Enumerable.Empty()); } - #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously + + public Task> GetEmbeddingModels(string? apiKeyProvisional = null, CancellationToken token = default) + { + return Task.FromResult(Enumerable.Empty()); + } #endregion } \ No newline at end of file