From 527b2076fe13e3c800ab7b44c105fca555e6e782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peer=20Sch=C3=BCtt?= <20603780+peerschuett@users.noreply.github.com> Date: Fri, 16 May 2025 15:54:46 +0200 Subject: [PATCH] System prompt works now! --- app/MindWork AI Studio/Chat/ChatThread.cs | 50 +++++++++++++++++-- .../Components/ChatComponent.razor | 1 + .../Components/ChatComponent.razor.cs | 32 +++++++++++- .../Components/ChatTemplateSelection.razor | 11 ++++ .../Components/ChatTemplateSelection.razor.cs | 28 +++++++++++ .../Settings/SettingsPanelChatTemplates.razor | 2 +- .../Dialogs/ChatTemplateDialog.razor | 32 ++++-------- .../Dialogs/ChatTemplateDialog.razor.cs | 3 +- .../Settings/ChatTemplate.cs | 3 +- .../Tools/ChatTemplateExtensions.cs | 13 +++++ 10 files changed, 146 insertions(+), 29 deletions(-) create mode 100644 app/MindWork AI Studio/Components/ChatTemplateSelection.razor create mode 100644 app/MindWork AI Studio/Components/ChatTemplateSelection.razor.cs create mode 100644 app/MindWork AI Studio/Tools/ChatTemplateExtensions.cs diff --git a/app/MindWork AI Studio/Chat/ChatThread.cs b/app/MindWork AI Studio/Chat/ChatThread.cs index ceb3041a..5b02397f 100644 --- a/app/MindWork AI Studio/Chat/ChatThread.cs +++ b/app/MindWork AI Studio/Chat/ChatThread.cs @@ -29,6 +29,11 @@ public sealed record ChatThread /// Specifies the profile selected for the chat thread. /// public string SelectedProfile { get; set; } = string.Empty; + + /// + /// Specifies the profile selected for the chat thread. + /// + public string SelectedChatTemplate { get; set; } = string.Empty; /// /// The data source options for this chat thread. @@ -69,6 +74,8 @@ public sealed record ChatThread /// The content blocks of the chat thread. /// public List Blocks { get; init; } = []; + + private bool allowProfile = true; /// /// Prepares the system prompt for the chat thread. @@ -84,16 +91,50 @@ public sealed record ChatThread /// The prepared system prompt. public string PrepareSystemPrompt(SettingsManager settingsManager, ChatThread chatThread, ILogger logger) { + + // + // Prepare the prompts using the chatTemplate: + // + string systemPromptTextWithChatTemplate; + var logMessage = $"Using no chat template for chat thread '{chatThread.Name}'."; + if (string.IsNullOrWhiteSpace(chatThread.SelectedChatTemplate)) + systemPromptTextWithChatTemplate = chatThread.SystemPrompt; + else + { + if(!Guid.TryParse(chatThread.SelectedChatTemplate, out var chatTeamplateId)) + systemPromptTextWithChatTemplate = chatThread.SystemPrompt; + else + { + if(chatThread.SelectedChatTemplate == ChatTemplate.NO_CHATTEMPLATE.Id || chatTeamplateId == Guid.Empty) + systemPromptTextWithChatTemplate = chatThread.SystemPrompt; + else + { + var chatTemplate = settingsManager.ConfigurationData.ChatTemplates.FirstOrDefault(x => x.Id == chatThread.SelectedChatTemplate); + if(chatTemplate == default) + systemPromptTextWithChatTemplate = chatThread.SystemPrompt; + else + { + logMessage = $"Using chat template '{chatTemplate.Name}' for chat thread '{chatThread.Name}'."; + this.allowProfile = chatTemplate.AllowProfileUsage; + systemPromptTextWithChatTemplate = $""" + {chatTemplate.ToSystemPrompt()} + """; + } + } + } + } + logger.LogInformation(logMessage); + var isAugmentedDataAvailable = !string.IsNullOrWhiteSpace(chatThread.AugmentedData); var systemPromptWithAugmentedData = isAugmentedDataAvailable switch { true => $""" - {chatThread.SystemPrompt} + {systemPromptTextWithChatTemplate} {chatThread.AugmentedData} """, - false => chatThread.SystemPrompt, + false => systemPromptTextWithChatTemplate, }; if(isAugmentedDataAvailable) @@ -101,12 +142,13 @@ public sealed record ChatThread else logger.LogInformation("No augmented data is available for the chat thread."); + // // Prepare the system prompt: // string systemPromptText; - var logMessage = $"Using no profile for chat thread '{chatThread.Name}'."; - if (string.IsNullOrWhiteSpace(chatThread.SelectedProfile)) + logMessage = $"Using no profile for chat thread '{chatThread.Name}'."; + if ((string.IsNullOrWhiteSpace(chatThread.SelectedProfile)) || (this.allowProfile is false)) systemPromptText = systemPromptWithAugmentedData; else { diff --git a/app/MindWork AI Studio/Components/ChatComponent.razor b/app/MindWork AI Studio/Components/ChatComponent.razor index 8973f9ac..fb1b2768 100644 --- a/app/MindWork AI Studio/Components/ChatComponent.razor +++ b/app/MindWork AI Studio/Components/ChatComponent.razor @@ -108,6 +108,7 @@ } + @if (PreviewFeatures.PRE_RAG_2024.IsEnabled(this.SettingsManager)) { diff --git a/app/MindWork AI Studio/Components/ChatComponent.razor.cs b/app/MindWork AI Studio/Components/ChatComponent.razor.cs index b1b9e2f0..5fce1335 100644 --- a/app/MindWork AI Studio/Components/ChatComponent.razor.cs +++ b/app/MindWork AI Studio/Components/ChatComponent.razor.cs @@ -46,6 +46,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable private DataSourceSelection? dataSourceSelectionComponent; private DataSourceOptions earlyDataSourceOptions = new(); private Profile currentProfile = Profile.NO_PROFILE; + private ChatTemplate currentChatTemplate = ChatTemplate.NO_CHATTEMPLATE; private bool hasUnsavedChanges; private bool mustScrollToBottomAfterRender; private InnerScrolling scrollingArea = null!; @@ -77,6 +78,9 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable // Get the preselected profile: this.currentProfile = this.SettingsManager.GetPreselectedProfile(Tools.Components.CHAT); + // Get the preselected chat template: + // this.currentChatTemplate = this.SettingsManager.GetPreselectedChatTemplate(Tools.Components.CHAT); // TODO + // // Check for deferred messages of the kind 'SEND_TO_CHAT', // aka the user sends an assistant result to the chat: @@ -320,6 +324,20 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable await this.ChatThreadChanged.InvokeAsync(this.ChatThread); } + + private async Task ChatTemplateWasChanged(ChatTemplate chatTemplate) + { + this.currentChatTemplate = chatTemplate; + if(this.ChatThread is null) + return; + + this.ChatThread = this.ChatThread with + { + SelectedChatTemplate = this.currentChatTemplate.Id, + }; + + await this.ChatThreadChanged.InvokeAsync(this.ChatThread); + } private IReadOnlyList GetAgentSelectedDataSources() { @@ -415,6 +433,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable { SelectedProvider = this.Provider.Id, SelectedProfile = this.currentProfile.Id, + SelectedChatTemplate = this.currentChatTemplate.Id, SystemPrompt = SystemPrompts.DEFAULT, WorkspaceId = this.currentWorkspaceId, ChatId = Guid.NewGuid(), @@ -432,9 +451,10 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable if (string.IsNullOrWhiteSpace(this.ChatThread.Name)) this.ChatThread.Name = this.ExtractThreadName(this.userInput); - // Update provider and profile: + // Update provider, profile and chat template: this.ChatThread.SelectedProvider = this.Provider.Id; this.ChatThread.SelectedProfile = this.currentProfile.Id; + this.ChatThread.SelectedChatTemplate = this.currentChatTemplate.Id; } var time = DateTimeOffset.Now; @@ -645,6 +665,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable { SelectedProvider = this.Provider.Id, SelectedProfile = this.currentProfile.Id, + SelectedChatTemplate = this.currentChatTemplate.Id, SystemPrompt = SystemPrompts.DEFAULT, WorkspaceId = this.currentWorkspaceId, ChatId = Guid.NewGuid(), @@ -756,6 +777,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable { var chatProvider = this.ChatThread?.SelectedProvider; var chatProfile = this.ChatThread?.SelectedProfile; + var chatChatTemplate = this.ChatThread?.SelectedChatTemplate; switch (this.SettingsManager.ConfigurationData.Chat.LoadingProviderBehavior) { @@ -783,6 +805,14 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable if(this.currentProfile == default) this.currentProfile = Profile.NO_PROFILE; } + + // Try to select the chat template: + if (!string.IsNullOrWhiteSpace(chatChatTemplate)) + { + this.currentChatTemplate = this.SettingsManager.ConfigurationData.ChatTemplates.FirstOrDefault(x => x.Id == chatChatTemplate); + if(this.currentChatTemplate == default) + this.currentChatTemplate = ChatTemplate.NO_CHATTEMPLATE; + } } private async Task ToggleWorkspaceOverlay() diff --git a/app/MindWork AI Studio/Components/ChatTemplateSelection.razor b/app/MindWork AI Studio/Components/ChatTemplateSelection.razor new file mode 100644 index 00000000..f20b2fbb --- /dev/null +++ b/app/MindWork AI Studio/Components/ChatTemplateSelection.razor @@ -0,0 +1,11 @@ +@inherits MSGComponentBase + + + @foreach (var chatTemplate in this.SettingsManager.ConfigurationData.ChatTemplates.GetAllChatTemplates()) + { + + @chatTemplate.Name + + } + + \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/ChatTemplateSelection.razor.cs b/app/MindWork AI Studio/Components/ChatTemplateSelection.razor.cs new file mode 100644 index 00000000..28d4f75b --- /dev/null +++ b/app/MindWork AI Studio/Components/ChatTemplateSelection.razor.cs @@ -0,0 +1,28 @@ +using AIStudio.Settings; + +using Microsoft.AspNetCore.Components; + +namespace AIStudio.Components; + +public partial class ChatTemplateSelection : MSGComponentBase +{ + [Parameter] + public ChatTemplate CurrentChatTemplate { get; set; } = ChatTemplate.NO_CHATTEMPLATE; + + [Parameter] + public EventCallback CurrentChatTemplateChanged { get; set; } + + [Parameter] + public string MarginLeft { get; set; } = "ml-3"; + + [Parameter] + public string MarginRight { get; set; } = string.Empty; + + private string MarginClass => $"{this.MarginLeft} {this.MarginRight}"; + + private async Task SelectionChanged(ChatTemplate chatTemplate) + { + this.CurrentChatTemplate = chatTemplate; + await this.CurrentChatTemplateChanged.InvokeAsync(chatTemplate); + } +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelChatTemplates.razor b/app/MindWork AI Studio/Components/Settings/SettingsPanelChatTemplates.razor index 5cf040db..e77788bf 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelChatTemplates.razor +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelChatTemplates.razor @@ -15,7 +15,7 @@ - + # diff --git a/app/MindWork AI Studio/Dialogs/ChatTemplateDialog.razor b/app/MindWork AI Studio/Dialogs/ChatTemplateDialog.razor index 7f2a728d..fbfaa710 100644 --- a/app/MindWork AI Studio/Dialogs/ChatTemplateDialog.razor +++ b/app/MindWork AI Studio/Dialogs/ChatTemplateDialog.razor @@ -46,14 +46,12 @@ Lines="6" AutoGrow="@true" MaxLines="12" - MaxLength="444" - Counter="444" Class="mb-3" UserAttributes="@SPELLCHECK_ATTRIBUTES" HelperText="@T("Tell the AI your system prompt.")" /> - + What should you know about the additional messages? TODO @@ -73,16 +71,20 @@ @context.Role - @context.Content + + @(context.Content is ContentText textContent ? textContent.Text : context.Content?.ToString()) + + OnClick="@(() => AddNewMessageBelow(context))" + Variant="Variant.Filled"/> + OnClick="@(() => RemoveMessage(context))" + Variant="Variant.Filled"/> @@ -90,24 +92,12 @@ @foreach (var role in availableRoles) { - @role + @role.ToName() } - - - - - + diff --git a/app/MindWork AI Studio/Dialogs/ChatTemplateDialog.razor.cs b/app/MindWork AI Studio/Dialogs/ChatTemplateDialog.razor.cs index b17cba59..e5c6ca96 100644 --- a/app/MindWork AI Studio/Dialogs/ChatTemplateDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/ChatTemplateDialog.razor.cs @@ -62,7 +62,7 @@ public partial class ChatTemplateDialog : MSGComponentBase // private readonly List additionalMessagesEntries = []; // private readonly List availableRoles = ["User", "Assistant"]; private readonly IEnumerable availableRoles = ChatRoles.ChatTemplateRoles().ToArray(); - private bool allowProfile = true; + private bool allowProfileUsage = true; // We get the form reference from Blazor code to validate it manually: private MudForm form = null!; @@ -75,6 +75,7 @@ public partial class ChatTemplateDialog : MSGComponentBase Name = this.DataName, SystemPrompt = this.DataSystemPrompt, AdditionalMessages = this.AdditionalMessages, + AllowProfileUsage = allowProfileUsage, }; private void RemoveMessage(ContentBlock item) diff --git a/app/MindWork AI Studio/Settings/ChatTemplate.cs b/app/MindWork AI Studio/Settings/ChatTemplate.cs index 72dbf953..4484b338 100644 --- a/app/MindWork AI Studio/Settings/ChatTemplate.cs +++ b/app/MindWork AI Studio/Settings/ChatTemplate.cs @@ -3,7 +3,7 @@ using AIStudio.Tools.PluginSystem; namespace AIStudio.Settings; -public readonly record struct ChatTemplate(uint Num, string Id, string Name, string SystemPrompt, List AdditionalMessages) +public readonly record struct ChatTemplate(uint Num, string Id, string Name, string SystemPrompt, List AdditionalMessages, bool AllowProfileUsage) { private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(ChatTemplate).Namespace, nameof(ChatTemplate)); @@ -14,6 +14,7 @@ public readonly record struct ChatTemplate(uint Num, string Id, string Name, str Id = Guid.Empty.ToString(), Num = uint.MaxValue, AdditionalMessages = [], + AllowProfileUsage = true, }; #region Overrides of ValueType diff --git a/app/MindWork AI Studio/Tools/ChatTemplateExtensions.cs b/app/MindWork AI Studio/Tools/ChatTemplateExtensions.cs new file mode 100644 index 00000000..b7b2f183 --- /dev/null +++ b/app/MindWork AI Studio/Tools/ChatTemplateExtensions.cs @@ -0,0 +1,13 @@ +using AIStudio.Settings; + +namespace AIStudio.Tools; + +public static class ChatTemplateExtensions +{ + public static IEnumerable GetAllChatTemplates(this IEnumerable chatTemplates) + { + yield return ChatTemplate.NO_CHATTEMPLATE; + foreach (var chatTemplate in chatTemplates) + yield return chatTemplate; + } +} \ No newline at end of file