From 6056d1ac36b6abd7bc895d33f34229d60b01790c Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 19 May 2024 12:32:42 +0200 Subject: [PATCH 01/20] Exclude build script from .NET solution view --- app/MindWork AI Studio/MindWork AI Studio.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/app/MindWork AI Studio/MindWork AI Studio.csproj b/app/MindWork AI Studio/MindWork AI Studio.csproj index 4dfe22b..6162913 100644 --- a/app/MindWork AI Studio/MindWork AI Studio.csproj +++ b/app/MindWork AI Studio/MindWork AI Studio.csproj @@ -26,6 +26,7 @@ + From 4713785fa63be46d28c078ed43fcacfd9e7d7be5 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 19 May 2024 16:05:06 +0200 Subject: [PATCH 02/20] Moved production-related imports behind a preprocessor directives --- app/MindWork AI Studio/Program.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/MindWork AI Studio/Program.cs b/app/MindWork AI Studio/Program.cs index a64921c..72f6f22 100644 --- a/app/MindWork AI Studio/Program.cs +++ b/app/MindWork AI Studio/Program.cs @@ -1,15 +1,16 @@ -using System.Reflection; - using AIStudio; using AIStudio.Components; using AIStudio.Settings; using AIStudio.Tools; -using Microsoft.Extensions.FileProviders; - using MudBlazor; using MudBlazor.Services; +#if !DEBUG +using System.Reflection; +using Microsoft.Extensions.FileProviders; +#endif + var builder = WebApplication.CreateBuilder(); builder.Services.AddMudServices(config => { From 8a42d1eb50ee22734aba7c002bfd3590bc716a59 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 19 May 2024 16:05:56 +0200 Subject: [PATCH 03/20] Hide CS8974 warnings, which are not avoidable when using MudBlazor validator methods --- app/MindWork AI Studio/MindWork AI Studio.csproj | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/MindWork AI Studio/MindWork AI Studio.csproj b/app/MindWork AI Studio/MindWork AI Studio.csproj index 6162913..aa0d895 100644 --- a/app/MindWork AI Studio/MindWork AI Studio.csproj +++ b/app/MindWork AI Studio/MindWork AI Studio.csproj @@ -20,7 +20,12 @@ false true true - IL2026 + + + IL2026, CS8974 From 3e1d1719684b939c2251be0da9cb1b1cc28ebd81 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 19 May 2024 16:06:35 +0200 Subject: [PATCH 04/20] Override the ToString method for models --- app/MindWork AI Studio/Provider/Model.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/MindWork AI Studio/Provider/Model.cs b/app/MindWork AI Studio/Provider/Model.cs index d8f8d05..af39709 100644 --- a/app/MindWork AI Studio/Provider/Model.cs +++ b/app/MindWork AI Studio/Provider/Model.cs @@ -4,4 +4,11 @@ namespace AIStudio.Provider; /// The data model for the model to use. /// /// The model's ID. -public readonly record struct Model(string Id); \ No newline at end of file +public readonly record struct Model(string Id) +{ + #region Overrides of ValueType + + public override string ToString() => string.IsNullOrWhiteSpace(this.Id) ? "no model selected" : this.Id; + + #endregion +} \ No newline at end of file From be0dc6766b668ba6ba625c69b8224de413c71d7d Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 19 May 2024 16:06:48 +0200 Subject: [PATCH 05/20] Spelling --- app/MindWork AI Studio/Provider/ImageURL.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/MindWork AI Studio/Provider/ImageURL.cs b/app/MindWork AI Studio/Provider/ImageURL.cs index 8d86e3b..2faef58 100644 --- a/app/MindWork AI Studio/Provider/ImageURL.cs +++ b/app/MindWork AI Studio/Provider/ImageURL.cs @@ -3,5 +3,5 @@ namespace AIStudio.Provider; /// /// An image URL. /// -/// The image URL. -public readonly record struct ImageURL(string url); \ No newline at end of file +/// The image URL. +public readonly record struct ImageURL(string URL); \ No newline at end of file From 38b74a07956d769ea97c81d34e626ba0be4e542d Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 19 May 2024 16:07:43 +0200 Subject: [PATCH 06/20] Added description for NoProvider --- app/MindWork AI Studio/Provider/Providers.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/app/MindWork AI Studio/Provider/Providers.cs b/app/MindWork AI Studio/Provider/Providers.cs index 83d3ad9..48c6638 100644 --- a/app/MindWork AI Studio/Provider/Providers.cs +++ b/app/MindWork AI Studio/Provider/Providers.cs @@ -25,6 +25,7 @@ public static class ExtensionsProvider { Providers.OPEN_AI => "OpenAI", + Providers.NONE => "No provider selected", _ => "Unknown", }; From 2a152880f42422c2821d070105378008d9f27d07 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 19 May 2024 16:09:52 +0200 Subject: [PATCH 07/20] Fixed handling of instance names while provider creation --- app/MindWork AI Studio/Components/Pages/Settings.razor.cs | 4 +--- app/MindWork AI Studio/Provider/Providers.cs | 7 ++++--- app/MindWork AI Studio/Settings/ProviderDialog.razor.cs | 7 ++----- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/app/MindWork AI Studio/Components/Pages/Settings.razor.cs b/app/MindWork AI Studio/Components/Pages/Settings.razor.cs index 94cc597..b97490d 100644 --- a/app/MindWork AI Studio/Components/Pages/Settings.razor.cs +++ b/app/MindWork AI Studio/Components/Pages/Settings.razor.cs @@ -88,9 +88,7 @@ public partial class Settings : ComponentBase if (dialogResult.Canceled) return; - var providerInstance = provider.UsedProvider.CreateProvider(); - providerInstance.InstanceName = provider.InstanceName; - + var providerInstance = provider.UsedProvider.CreateProvider(provider.InstanceName); var deleteSecretResponse = await this.SettingsManager.DeleteAPIKey(this.JsRuntime, providerInstance); if(deleteSecretResponse.Success) { diff --git a/app/MindWork AI Studio/Provider/Providers.cs b/app/MindWork AI Studio/Provider/Providers.cs index 48c6638..0c93f42 100644 --- a/app/MindWork AI Studio/Provider/Providers.cs +++ b/app/MindWork AI Studio/Provider/Providers.cs @@ -28,15 +28,16 @@ public static class ExtensionsProvider Providers.NONE => "No provider selected", _ => "Unknown", }; - + /// /// Creates a new provider instance based on the provider value. /// /// The provider value. + /// The used instance name. /// The provider instance. - public static IProvider CreateProvider(this Providers provider) => provider switch + public static IProvider CreateProvider(this Providers provider, string instanceName) => provider switch { - Providers.OPEN_AI => new ProviderOpenAI(), + Providers.OPEN_AI => new ProviderOpenAI { InstanceName = instanceName }, _ => new NoProvider(), }; diff --git a/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs b/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs index 51e602f..91cf2b3 100644 --- a/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs +++ b/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs @@ -72,12 +72,10 @@ public partial class ProviderDialog : ComponentBase if(this.IsEditing) { this.dataEditingPreviousInstanceName = this.DataInstanceName.ToLowerInvariant(); - var provider = this.DataProvider.CreateProvider(); + var provider = this.DataProvider.CreateProvider(this.DataInstanceName); if(provider is NoProvider) return; - provider.InstanceName = this.DataInstanceName; - // Load the API key: var requestedSecret = await this.SettingsManager.GetAPIKey(this.JsRuntime, provider); if(requestedSecret.Success) @@ -124,8 +122,7 @@ public partial class ProviderDialog : ComponentBase }; // We need to instantiate the provider to store the API key: - var provider = this.DataProvider.CreateProvider(); - provider.InstanceName = this.DataInstanceName; + var provider = this.DataProvider.CreateProvider(this.DataInstanceName); // Store the API key in the OS secure storage: var storeResponse = await this.SettingsManager.SetAPIKey(this.JsRuntime, provider, this.dataAPIKey); From a2a1642c767bf01564951859191d6edf79aa6f2a Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 19 May 2024 16:10:37 +0200 Subject: [PATCH 08/20] Included model to the provider data model --- app/MindWork AI Studio/Settings/Provider.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/MindWork AI Studio/Settings/Provider.cs b/app/MindWork AI Studio/Settings/Provider.cs index 4d32f01..3385d5a 100644 --- a/app/MindWork AI Studio/Settings/Provider.cs +++ b/app/MindWork AI Studio/Settings/Provider.cs @@ -8,7 +8,8 @@ namespace AIStudio.Settings; /// The provider's ID. /// The provider's instance name. Useful for multiple instances of the same provider, e.g., to distinguish between different OpenAI API keys. /// The provider used. -public readonly record struct Provider(string Id, string InstanceName, Providers UsedProvider) +/// The LLM model to use for chat. +public readonly record struct Provider(string Id, string InstanceName, Providers UsedProvider, Model Model) { #region Overrides of ValueType From fc1ad26f6a1b500a7989721f484d531ffdbd2aa2 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 19 May 2024 16:10:57 +0200 Subject: [PATCH 09/20] Show the chosen model for any provider --- app/MindWork AI Studio/Settings/Provider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/MindWork AI Studio/Settings/Provider.cs b/app/MindWork AI Studio/Settings/Provider.cs index 3385d5a..1c94814 100644 --- a/app/MindWork AI Studio/Settings/Provider.cs +++ b/app/MindWork AI Studio/Settings/Provider.cs @@ -20,7 +20,7 @@ public readonly record struct Provider(string Id, string InstanceName, Providers /// A string that represents the current provider in a human-readable format. public override string ToString() { - return $"{this.InstanceName} ({this.UsedProvider.ToName()})"; + return $"{this.InstanceName} ({this.UsedProvider.ToName()}, {this.Model})"; } #endregion From ec2dbb923cc88af61de274f95364bfefa38f2b24 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 19 May 2024 16:12:07 +0200 Subject: [PATCH 10/20] Added model selection --- .../Settings/ProviderDialog.razor | 11 ++++++ .../Settings/ProviderDialog.razor.cs | 37 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/app/MindWork AI Studio/Settings/ProviderDialog.razor b/app/MindWork AI Studio/Settings/ProviderDialog.razor index ed5a048..9a2d225 100644 --- a/app/MindWork AI Studio/Settings/ProviderDialog.razor +++ b/app/MindWork AI Studio/Settings/ProviderDialog.razor @@ -34,6 +34,17 @@ InputType="InputType.Password" Validation="@this.ValidatingAPIKey" /> + + + Reload + + @foreach (var model in this.availableModels) + { + @model + } + + + @if (this.dataIssues.Any()) diff --git a/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs b/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs index 91cf2b3..8e1f938 100644 --- a/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs +++ b/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs @@ -35,6 +35,12 @@ public partial class ProviderDialog : ComponentBase [Parameter] public Providers DataProvider { get; set; } = Providers.NONE; + /// + /// The LLM model to use, e.g., GPT-4o. + /// + [Parameter] + public Model DataModel { get; set; } + /// /// Should the dialog be in editing mode? /// @@ -60,6 +66,8 @@ public partial class ProviderDialog : ComponentBase // We get the form reference from Blazor code to validate it manually: private MudForm form = null!; + + private readonly List availableModels = new(); #region Overrides of ComponentBase @@ -79,7 +87,12 @@ public partial class ProviderDialog : ComponentBase // Load the API key: var requestedSecret = await this.SettingsManager.GetAPIKey(this.JsRuntime, provider); if(requestedSecret.Success) + { this.dataAPIKey = requestedSecret.Secret; + + // Now, we try to load the list of available models: + await this.ReloadModels(); + } else { this.dataAPIKeyStorageIssue = $"Failed to load the API key from the operating system. The message was: {requestedSecret.Issue}. You might ignore this message and provide the API key again."; @@ -119,6 +132,7 @@ public partial class ProviderDialog : ComponentBase Id = this.DataId, InstanceName = this.DataInstanceName, UsedProvider = this.DataProvider, + Model = this.DataModel, }; // We need to instantiate the provider to store the API key: @@ -144,6 +158,14 @@ public partial class ProviderDialog : ComponentBase return null; } + private string? ValidatingModel(Model model) + { + if (model == default) + return "Please select a model."; + + return null; + } + [GeneratedRegex("^[a-zA-Z0-9 ]+$")] private static partial Regex InstanceNameRegex(); @@ -185,4 +207,19 @@ public partial class ProviderDialog : ComponentBase } private void Cancel() => this.MudDialog.Cancel(); + + private async Task ReloadModels() + { + var provider = this.DataProvider.CreateProvider(this.DataInstanceName); + if(provider is NoProvider) + return; + + var models = await provider.GetTextModels(this.JsRuntime, this.SettingsManager); + + // Order descending by ID means that the newest models probably come first: + var orderedModels = models.OrderByDescending(n => n.Id); + + this.availableModels.Clear(); + this.availableModels.AddRange(orderedModels); + } } \ No newline at end of file From 5982559cebfcc1bba815ac24f41ca8719e21760a Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 19 May 2024 16:12:32 +0200 Subject: [PATCH 11/20] Fixed spacing between provider dialogs fields --- app/MindWork AI Studio/Settings/ProviderDialog.razor | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/MindWork AI Studio/Settings/ProviderDialog.razor b/app/MindWork AI Studio/Settings/ProviderDialog.razor index 9a2d225..829feb7 100644 --- a/app/MindWork AI Studio/Settings/ProviderDialog.razor +++ b/app/MindWork AI Studio/Settings/ProviderDialog.razor @@ -9,6 +9,7 @@ T="string" @bind-Text="@this.DataInstanceName" Label="Instance Name" + Class="mb-3" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Lightbulb" AdornmentColor="Color.Info" @@ -16,7 +17,7 @@ /> @* ReSharper disable once CSharpWarnings::CS8974 *@ - + @foreach (Providers provider in Enum.GetValues(typeof(Providers))) { @provider @@ -28,6 +29,7 @@ T="string" @bind-Text="@this.dataAPIKey" Label="API Key" + Class="mb-3" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.VpnKey" AdornmentColor="Color.Info" From 6da453e0221c0bdbcad2ea4ca9e7bbb07f81e753 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 19 May 2024 16:12:50 +0200 Subject: [PATCH 12/20] Fixed naming of variable --- app/MindWork AI Studio/Settings/ProviderDialog.razor.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs b/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs index 8e1f938..67945e3 100644 --- a/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs +++ b/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs @@ -56,7 +56,7 @@ public partial class ProviderDialog : ComponentBase /// /// The list of used instance names. We need this to check for uniqueness. /// - private List usedInstanceNames { get; set; } = []; + private List UsedInstanceNames { get; set; } = []; private bool dataIsValid; private string[] dataIssues = []; @@ -74,7 +74,7 @@ public partial class ProviderDialog : ComponentBase protected override async Task OnInitializedAsync() { // Load the used instance names: - this.usedInstanceNames = this.SettingsManager.ConfigurationData.Providers.Select(x => x.InstanceName.ToLowerInvariant()).ToList(); + this.UsedInstanceNames = this.SettingsManager.ConfigurationData.Providers.Select(x => x.InstanceName.ToLowerInvariant()).ToList(); // When editing, we need to load the data: if(this.IsEditing) @@ -189,7 +189,7 @@ public partial class ProviderDialog : ComponentBase // The instance name must be unique: var lowerInstanceName = instanceName.ToLowerInvariant(); - if (lowerInstanceName != this.dataEditingPreviousInstanceName && this.usedInstanceNames.Contains(lowerInstanceName)) + if (lowerInstanceName != this.dataEditingPreviousInstanceName && this.UsedInstanceNames.Contains(lowerInstanceName)) return "The instance name must be unique; the chosen name is already in use."; return null; From 722c7e943deaea0259b96834d29639ebd5978c2b Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 19 May 2024 16:14:05 +0200 Subject: [PATCH 13/20] Mode model loading returning enumerable list of data --- app/MindWork AI Studio/Provider/IProvider.cs | 4 ++-- app/MindWork AI Studio/Provider/NoProvider.cs | 4 ++-- app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/MindWork AI Studio/Provider/IProvider.cs b/app/MindWork AI Studio/Provider/IProvider.cs index 15403bf..7c5baeb 100644 --- a/app/MindWork AI Studio/Provider/IProvider.cs +++ b/app/MindWork AI Studio/Provider/IProvider.cs @@ -53,7 +53,7 @@ public interface IProvider /// The settings manager to access the API key. /// The cancellation token. /// The list of text models. - public Task> GetTextModels(IJSRuntime jsRuntime, SettingsManager settings, CancellationToken token = default); + public Task> GetTextModels(IJSRuntime jsRuntime, SettingsManager settings, CancellationToken token = default); /// /// Load all possible image models that can be used with this provider. @@ -62,5 +62,5 @@ public interface IProvider /// The settings manager to access the API key. /// The cancellation token. /// The list of image models. - public Task> GetImageModels(IJSRuntime jsRuntime, SettingsManager settings, CancellationToken token = default); + public Task> GetImageModels(IJSRuntime jsRuntime, SettingsManager settings, CancellationToken token = default); } \ 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 e505395..d65ea57 100644 --- a/app/MindWork AI Studio/Provider/NoProvider.cs +++ b/app/MindWork AI Studio/Provider/NoProvider.cs @@ -17,9 +17,9 @@ public class NoProvider : IProvider public string InstanceName { get; set; } = "None"; - public Task> GetTextModels(IJSRuntime jsRuntime, SettingsManager settings, CancellationToken token = default) => Task.FromResult>(new List()); + public Task> GetTextModels(IJSRuntime jsRuntime, SettingsManager settings, CancellationToken token = default) => Task.FromResult>([]); - public Task> GetImageModels(IJSRuntime jsRuntime, SettingsManager settings, CancellationToken token = default) => Task.FromResult>(new List()); + public Task> GetImageModels(IJSRuntime jsRuntime, SettingsManager settings, CancellationToken token = default) => Task.FromResult>([]); public async IAsyncEnumerable StreamChatCompletion(IJSRuntime jsRuntime, SettingsManager settings, 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 ed5abfe..cee36af 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs @@ -155,20 +155,20 @@ public sealed class ProviderOpenAI() : BaseProvider("https://api.openai.com/v1/" #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously /// - public async Task> GetTextModels(IJSRuntime jsRuntime, SettingsManager settings, CancellationToken token = default) + public Task> GetTextModels(IJSRuntime jsRuntime, SettingsManager settings, CancellationToken token = default) { return await this.LoadModels(jsRuntime, settings, "gpt-", token); } /// - public async Task> GetImageModels(IJSRuntime jsRuntime, SettingsManager settings, CancellationToken token = default) + public Task> GetImageModels(IJSRuntime jsRuntime, SettingsManager settings, CancellationToken token = default) { return await this.LoadModels(jsRuntime, settings, "dall-e-", token); } #endregion - private async Task> LoadModels(IJSRuntime jsRuntime, SettingsManager settings, string prefix, CancellationToken token) + private async Task> LoadModels(IJSRuntime jsRuntime, SettingsManager settings, string prefix, CancellationToken token) { var requestedSecret = await settings.GetAPIKey(jsRuntime, this); if(!requestedSecret.Success) From 0b4547d5b30e7324a898c396af828c9750168644 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 19 May 2024 16:14:30 +0200 Subject: [PATCH 14/20] Optimized method calls --- app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs b/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs index cee36af..f1d7e4d 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs @@ -157,13 +157,13 @@ public sealed class ProviderOpenAI() : BaseProvider("https://api.openai.com/v1/" /// public Task> GetTextModels(IJSRuntime jsRuntime, SettingsManager settings, CancellationToken token = default) { - return await this.LoadModels(jsRuntime, settings, "gpt-", token); + return this.LoadModels(jsRuntime, settings, "gpt-", token); } /// public Task> GetImageModels(IJSRuntime jsRuntime, SettingsManager settings, CancellationToken token = default) { - return await this.LoadModels(jsRuntime, settings, "dall-e-", token); + return this.LoadModels(jsRuntime, settings, "dall-e-", token); } #endregion From bd5daea248504f550c252546c77911fdaa8fa9f4 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 19 May 2024 16:14:49 +0200 Subject: [PATCH 15/20] Apply .NET 8 syntax --- .../Provider/OpenAI/ProviderOpenAI.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs b/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs index f1d7e4d..8abb5f3 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs @@ -171,18 +171,17 @@ public sealed class ProviderOpenAI() : BaseProvider("https://api.openai.com/v1/" private async Task> LoadModels(IJSRuntime jsRuntime, SettingsManager settings, string prefix, CancellationToken token) { var requestedSecret = await settings.GetAPIKey(jsRuntime, this); - if(!requestedSecret.Success) - return new List(); + if (!requestedSecret.Success) + return []; var request = new HttpRequestMessage(HttpMethod.Get, "models"); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", requestedSecret.Secret); - - var emptyList = new List(); + var response = await this.httpClient.SendAsync(request, token); if(!response.IsSuccessStatusCode) - return emptyList; + return []; var modelResponse = await response.Content.ReadFromJsonAsync(token); - return modelResponse.Data.Where(n => n.Id.StartsWith(prefix, StringComparison.InvariantCulture)).ToList(); + return modelResponse.Data.Where(n => n.Id.StartsWith(prefix, StringComparison.InvariantCulture)); } } \ No newline at end of file From 0b66aa7c79cc497dabe4586830817d80654daeee Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 19 May 2024 16:15:20 +0200 Subject: [PATCH 16/20] Replaced the static placeholder model with the chosen model --- app/MindWork AI Studio/Components/Pages/Chat.razor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/MindWork AI Studio/Components/Pages/Chat.razor.cs b/app/MindWork AI Studio/Components/Pages/Chat.razor.cs index e4acea8..5b5b4c3 100644 --- a/app/MindWork AI Studio/Components/Pages/Chat.razor.cs +++ b/app/MindWork AI Studio/Components/Pages/Chat.razor.cs @@ -102,7 +102,7 @@ public partial class Chat : ComponentBase // Use the selected provider to get the AI response. // By awaiting this line, we wait for the entire // content to be streamed. - await aiText.CreateFromProviderAsync(this.selectedProvider.UsedProvider.CreateProvider(), this.JsRuntime, this.SettingsManager, new Model("gpt-4o"), this.chatThread); + await aiText.CreateFromProviderAsync(this.selectedProvider.UsedProvider.CreateProvider(this.selectedProvider.InstanceName), this.JsRuntime, this.SettingsManager, this.selectedProvider.Model, this.chatThread); // Disable the stream state: this.isStreaming = false; From 1742d3464b8c35826f39be821e8bc41b1a10da52 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 19 May 2024 16:16:16 +0200 Subject: [PATCH 17/20] Added used model --- app/MindWork AI Studio/Components/Pages/Settings.razor | 7 +++++-- app/MindWork AI Studio/Components/Pages/Settings.razor.cs | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/MindWork AI Studio/Components/Pages/Settings.razor b/app/MindWork AI Studio/Components/Pages/Settings.razor index a450312..db36b85 100644 --- a/app/MindWork AI Studio/Components/Pages/Settings.razor +++ b/app/MindWork AI Studio/Components/Pages/Settings.razor @@ -8,19 +8,22 @@ + # + Instance Name Provider - Name + Model Actions - @context.UsedProvider @context.InstanceName + @context.UsedProvider + @context.Model Edit diff --git a/app/MindWork AI Studio/Components/Pages/Settings.razor.cs b/app/MindWork AI Studio/Components/Pages/Settings.razor.cs index b97490d..ce824e3 100644 --- a/app/MindWork AI Studio/Components/Pages/Settings.razor.cs +++ b/app/MindWork AI Studio/Components/Pages/Settings.razor.cs @@ -63,6 +63,7 @@ public partial class Settings : ComponentBase { x => x.DataId, provider.Id }, { x => x.DataInstanceName, provider.InstanceName }, { x => x.DataProvider, provider.UsedProvider }, + { x => x.DataModel, provider.Model }, { x => x.IsEditing, true }, }; From 25853bab86b451166e7ffd7473f1c477fea6af5a Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 19 May 2024 19:41:33 +0200 Subject: [PATCH 18/20] Fixed table cells width --- app/MindWork AI Studio/Components/Pages/Settings.razor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/MindWork AI Studio/Components/Pages/Settings.razor b/app/MindWork AI Studio/Components/Pages/Settings.razor index db36b85..eeb6e3b 100644 --- a/app/MindWork AI Studio/Components/Pages/Settings.razor +++ b/app/MindWork AI Studio/Components/Pages/Settings.razor @@ -7,8 +7,8 @@ - - + + From b485da7aa9ef06b6dcf857c9856fa0e6c8966a97 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 19 May 2024 19:42:15 +0200 Subject: [PATCH 19/20] Auto-enable button to reload models, when necessary data was provided --- app/MindWork AI Studio/Settings/ProviderDialog.razor | 2 +- app/MindWork AI Studio/Settings/ProviderDialog.razor.cs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/MindWork AI Studio/Settings/ProviderDialog.razor b/app/MindWork AI Studio/Settings/ProviderDialog.razor index 829feb7..0fac746 100644 --- a/app/MindWork AI Studio/Settings/ProviderDialog.razor +++ b/app/MindWork AI Studio/Settings/ProviderDialog.razor @@ -38,7 +38,7 @@ /> - Reload + Reload @foreach (var model in this.availableModels) { diff --git a/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs b/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs index 67945e3..6a668ae 100644 --- a/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs +++ b/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs @@ -208,6 +208,8 @@ public partial class ProviderDialog : ComponentBase private void Cancel() => this.MudDialog.Cancel(); + private bool CanLoadModels => !string.IsNullOrWhiteSpace(this.dataAPIKey) && this.DataProvider != Providers.NONE && !string.IsNullOrWhiteSpace(this.DataInstanceName); + private async Task ReloadModels() { var provider = this.DataProvider.CreateProvider(this.DataInstanceName); From 276a33a52e0220d1ff02dc6115d258049497ddfb Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 19 May 2024 20:28:25 +0200 Subject: [PATCH 20/20] Fixed missed row numbers of providers --- app/MindWork AI Studio/Components/Pages/Settings.razor | 2 +- .../Components/Pages/Settings.razor.cs | 9 +++++++++ app/MindWork AI Studio/Settings/Data.cs | 7 ++++++- app/MindWork AI Studio/Settings/Provider.cs | 3 ++- app/MindWork AI Studio/Settings/ProviderDialog.razor.cs | 7 +++++++ 5 files changed, 25 insertions(+), 3 deletions(-) diff --git a/app/MindWork AI Studio/Components/Pages/Settings.razor b/app/MindWork AI Studio/Components/Pages/Settings.razor index eeb6e3b..2820b10 100644 --- a/app/MindWork AI Studio/Components/Pages/Settings.razor +++ b/app/MindWork AI Studio/Components/Pages/Settings.razor @@ -20,7 +20,7 @@ Actions - + @context.Num @context.InstanceName @context.UsedProvider @context.Model diff --git a/app/MindWork AI Studio/Components/Pages/Settings.razor.cs b/app/MindWork AI Studio/Components/Pages/Settings.razor.cs index ce824e3..b287877 100644 --- a/app/MindWork AI Studio/Components/Pages/Settings.razor.cs +++ b/app/MindWork AI Studio/Components/Pages/Settings.razor.cs @@ -52,6 +52,8 @@ public partial class Settings : ComponentBase return; var addedProvider = (AIStudio.Settings.Provider)dialogResult.Data; + addedProvider = addedProvider with { Num = this.SettingsManager.ConfigurationData.NextProviderNum++ }; + this.SettingsManager.ConfigurationData.Providers.Add(addedProvider); await this.SettingsManager.StoreSettings(); } @@ -60,6 +62,7 @@ public partial class Settings : ComponentBase { var dialogParameters = new DialogParameters { + { x => x.DataNum, provider.Num }, { x => x.DataId, provider.Id }, { x => x.DataInstanceName, provider.InstanceName }, { x => x.DataProvider, provider.UsedProvider }, @@ -73,6 +76,12 @@ public partial class Settings : ComponentBase return; var editedProvider = (AIStudio.Settings.Provider)dialogResult.Data; + + // Set the provider number if it's not set. This is important for providers + // added before we started saving the provider number. + if(editedProvider.Num == 0) + editedProvider = editedProvider with { Num = this.SettingsManager.ConfigurationData.NextProviderNum++ }; + this.SettingsManager.ConfigurationData.Providers[this.SettingsManager.ConfigurationData.Providers.IndexOf(provider)] = editedProvider; await this.SettingsManager.StoreSettings(); } diff --git a/app/MindWork AI Studio/Settings/Data.cs b/app/MindWork AI Studio/Settings/Data.cs index ff89a31..465ebe6 100644 --- a/app/MindWork AI Studio/Settings/Data.cs +++ b/app/MindWork AI Studio/Settings/Data.cs @@ -14,7 +14,12 @@ public sealed class Data /// /// List of configured providers. /// - public List Providers { get; init; } = new(); + public List Providers { get; init; } = []; + + /// + /// The next provider number to use. + /// + public uint NextProviderNum { get; set; } = 1; /// /// Should we save energy? When true, we will update content streamed diff --git a/app/MindWork AI Studio/Settings/Provider.cs b/app/MindWork AI Studio/Settings/Provider.cs index 1c94814..d1f6194 100644 --- a/app/MindWork AI Studio/Settings/Provider.cs +++ b/app/MindWork AI Studio/Settings/Provider.cs @@ -5,11 +5,12 @@ namespace AIStudio.Settings; /// /// Data model for configured providers. /// +/// The provider's number. /// The provider's ID. /// The provider's instance name. Useful for multiple instances of the same provider, e.g., to distinguish between different OpenAI API keys. /// The provider used. /// The LLM model to use for chat. -public readonly record struct Provider(string Id, string InstanceName, Providers UsedProvider, Model Model) +public readonly record struct Provider(uint Num, string Id, string InstanceName, Providers UsedProvider, Model Model) { #region Overrides of ValueType diff --git a/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs b/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs index 6a668ae..1a267ca 100644 --- a/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs +++ b/app/MindWork AI Studio/Settings/ProviderDialog.razor.cs @@ -16,6 +16,12 @@ public partial class ProviderDialog : ComponentBase { [CascadingParameter] private MudDialogInstance MudDialog { get; set; } = null!; + + /// + /// The provider's number in the list. + /// + [Parameter] + public uint DataNum { get; set; } /// /// The provider's ID. @@ -129,6 +135,7 @@ public partial class ProviderDialog : ComponentBase // We just return this data to the parent component: var addedProvider = new Provider { + Num = this.DataNum, Id = this.DataId, InstanceName = this.DataInstanceName, UsedProvider = this.DataProvider,