From 6836fd25b5fc441c8e09fb8fc86740456b261e00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peer=20Sch=C3=BCtt?= <20603780+peerschuett@users.noreply.github.com> Date: Fri, 20 Mar 2026 14:57:25 +0100 Subject: [PATCH] First working prototype for PromptOptimizer assistant --- .../Assistants/AssistantBase.razor | 12 + .../Assistants/AssistantBase.razor.cs | 4 + .../AssistantPromptOptimizer.razor | 106 ++++ .../AssistantPromptOptimizer.razor.cs | 490 ++++++++++++++++++ .../PromptOptimizationResult.cs | 33 ++ .../PromptOptimizer/prompting_guideline.md | 85 +++ .../Dialogs/PromptingGuidelineDialog.razor | 26 + .../Dialogs/PromptingGuidelineDialog.razor.cs | 22 + app/MindWork AI Studio/Pages/Assistants.razor | 2 + app/MindWork AI Studio/Routes.razor.cs | 1 + .../Settings/ConfigurableAssistant.cs | 1 + .../Tools/AssistantVisibilityExtensions.cs | 1 + app/MindWork AI Studio/Tools/Components.cs | 3 +- .../Tools/ComponentsExtensions.cs | 4 +- app/MindWork AI Studio/Tools/Event.cs | 1 + 15 files changed, 789 insertions(+), 2 deletions(-) create mode 100644 app/MindWork AI Studio/Assistants/PromptOptimizer/AssistantPromptOptimizer.razor create mode 100644 app/MindWork AI Studio/Assistants/PromptOptimizer/AssistantPromptOptimizer.razor.cs create mode 100644 app/MindWork AI Studio/Assistants/PromptOptimizer/PromptOptimizationResult.cs create mode 100644 app/MindWork AI Studio/Assistants/PromptOptimizer/prompting_guideline.md create mode 100644 app/MindWork AI Studio/Dialogs/PromptingGuidelineDialog.razor create mode 100644 app/MindWork AI Studio/Dialogs/PromptingGuidelineDialog.razor.cs diff --git a/app/MindWork AI Studio/Assistants/AssistantBase.razor b/app/MindWork AI Studio/Assistants/AssistantBase.razor index 3268612d..4760b622 100644 --- a/app/MindWork AI Studio/Assistants/AssistantBase.razor +++ b/app/MindWork AI Studio/Assistants/AssistantBase.razor @@ -8,6 +8,13 @@ @this.Title + + + + @if (this.HeaderActions is not null) + { + @this.HeaderActions + } @if (this.HasSettingsPanel) { @@ -71,6 +78,11 @@ } } } + + @if (this.ShowResult && this.AfterResultContent is not null) + { + @this.AfterResultContent + }
diff --git a/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs b/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs index 632722ab..1b1503b6 100644 --- a/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs +++ b/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs @@ -81,6 +81,10 @@ public abstract partial class AssistantBase : AssistantLowerBase wher protected virtual ChatThread ConvertToChatThread => this.chatThread ?? new(); + private protected virtual RenderFragment? HeaderActions => null; + + private protected virtual RenderFragment? AfterResultContent => null; + protected virtual IReadOnlyList FooterButtons => []; protected virtual bool HasSettingsPanel => typeof(TSettings) != typeof(NoSettingsPanel); diff --git a/app/MindWork AI Studio/Assistants/PromptOptimizer/AssistantPromptOptimizer.razor b/app/MindWork AI Studio/Assistants/PromptOptimizer/AssistantPromptOptimizer.razor new file mode 100644 index 00000000..615266e0 --- /dev/null +++ b/app/MindWork AI Studio/Assistants/PromptOptimizer/AssistantPromptOptimizer.razor @@ -0,0 +1,106 @@ +@attribute [Route(Routes.ASSISTANT_PROMPT_OPTIMIZER)] +@inherits AssistantBaseCore + + + + +@if (!this.useCustomPromptGuide) +{ + + + + + + + + + + + + + + + + + + + + +} + + + + @T("View default prompt guide") + + + + @T("Use custom prompt guide") + + + @if (this.useCustomPromptGuide) + { + + } + + + + + @T("View") + + + + + + + + + diff --git a/app/MindWork AI Studio/Assistants/PromptOptimizer/AssistantPromptOptimizer.razor.cs b/app/MindWork AI Studio/Assistants/PromptOptimizer/AssistantPromptOptimizer.razor.cs new file mode 100644 index 00000000..8b8b0b2f --- /dev/null +++ b/app/MindWork AI Studio/Assistants/PromptOptimizer/AssistantPromptOptimizer.razor.cs @@ -0,0 +1,490 @@ +using System.Text.Json; +using System.Text.RegularExpressions; + +using AIStudio.Chat; +using AIStudio.Dialogs; +using AIStudio.Dialogs.Settings; +using Microsoft.AspNetCore.Components; + +#if !DEBUG +using System.Reflection; +using Microsoft.Extensions.FileProviders; +#endif + +namespace AIStudio.Assistants.PromptOptimizer; + +public partial class AssistantPromptOptimizer : AssistantBaseCore +{ + private static readonly Regex JSON_CODE_FENCE_REGEX = new( + pattern: """```(?:json)?\s*(?\{[\s\S]*\})\s*```""", + options: RegexOptions.Compiled | RegexOptions.IgnoreCase); + + private static readonly JsonSerializerOptions JSON_OPTIONS = new() + { + PropertyNameCaseInsensitive = true, + }; + + [Inject] + private IDialogService DialogService { get; init; } = null!; + + protected override Tools.Components Component => Tools.Components.PROMPT_OPTIMIZER_ASSISTANT; + + protected override string Title => T("Prompt Optimizer"); + + protected override string Description => T("Optimize a prompt using your prompt guideline and get targeted recommendations for future versions."); + + protected override string SystemPrompt => + """ + You are an expert prompt optimization assistant. + You optimize user prompts while preserving the original intent. + You must return valid JSON only and no extra markdown or commentary. + """; + + protected override bool AllowProfiles => false; + + protected override bool ShowDedicatedProgress => true; + + protected override bool ShowEntireChatThread => true; + + protected override Func Result2Copy => () => this.optimizedPrompt; + + protected override IReadOnlyList FooterButtons => + [ + new SendToButton + { + Self = Tools.Components.PROMPT_OPTIMIZER_ASSISTANT, + UseResultingContentBlockData = false, + GetText = () => string.IsNullOrWhiteSpace(this.optimizedPrompt) ? this.inputPrompt : this.optimizedPrompt, + }, + ]; + + protected override string SubmitText => T("Optimize prompt"); + + protected override Func SubmitAction => this.OptimizePromptAsync; + + protected override ChatThread ConvertToChatThread => (this.chatThread ?? new()) with + { + SystemPrompt = SystemPrompts.DEFAULT, + }; + + protected override void ResetForm() + { + this.inputPrompt = string.Empty; + this.selectedTargetLanguage = CommonLanguages.AS_IS; + this.customTargetLanguage = string.Empty; + this.importantAspects = string.Empty; + this.useCustomPromptGuide = false; + this.customPromptGuideFiles.Clear(); + this.currentCustomPromptGuidePath = string.Empty; + this.customPromptingGuidelineContent = string.Empty; + this.ResetGuidelineSummaryToDefault(); + this.ResetOutput(); + } + + protected override bool MightPreselectValues() => false; + + protected override async Task OnInitializedAsync() + { + this.ResetGuidelineSummaryToDefault(); + + var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages(Event.SEND_TO_PROMPT_OPTIMIZER_ASSISTANT).FirstOrDefault(); + if (deferredContent is not null) + this.inputPrompt = deferredContent; + + await base.OnInitializedAsync(); + } + + private string inputPrompt = string.Empty; + private CommonLanguages selectedTargetLanguage; + private string customTargetLanguage = string.Empty; + private string importantAspects = string.Empty; + private bool useCustomPromptGuide; + private HashSet customPromptGuideFiles = []; + private string currentCustomPromptGuidePath = string.Empty; + private string customPromptingGuidelineContent = string.Empty; + private bool isLoadingCustomPromptGuide; + + private string optimizedPrompt = string.Empty; + private string recClarityDirectness = string.Empty; + private string recExamplesContext = string.Empty; + private string recSequentialSteps = string.Empty; + private string recStructureMarkers = string.Empty; + private string recRoleDefinition = string.Empty; + private string recLanguageChoice = string.Empty; + + private bool HasOptimizationResult => !string.IsNullOrWhiteSpace(this.optimizedPrompt); + private bool CanPreviewCustomPromptGuide => this.useCustomPromptGuide && this.customPromptGuideFiles.Count > 0; + private string CustomPromptGuideFileName => this.customPromptGuideFiles.Count switch + { + 0 => T("No file selected"), + _ => this.customPromptGuideFiles.First().FileName + }; + + private string? ValidateInputPrompt(string text) + { + if (string.IsNullOrWhiteSpace(text)) + return T("Please provide a prompt or prompt description."); + + return null; + } + + private string? ValidateCustomLanguage(string language) + { + if (this.selectedTargetLanguage == CommonLanguages.OTHER && string.IsNullOrWhiteSpace(language)) + return T("Please provide a custom language."); + + return null; + } + + private string SystemPromptLanguage() + { + var language = this.selectedTargetLanguage switch + { + CommonLanguages.AS_IS => "the source language of the input prompt", + CommonLanguages.OTHER => this.customTargetLanguage, + _ => this.selectedTargetLanguage.Name(), + }; + + if (string.IsNullOrWhiteSpace(language)) + return "the source language of the input prompt"; + + return language; + } + + private async Task OptimizePromptAsync() + { + await this.form!.Validate(); + if (!this.inputIsValid) + return; + + this.ClearInputIssues(); + this.ResetOutput(); + + var promptingGuideline = await this.GetPromptingGuidelineForOptimizationAsync(); + if (string.IsNullOrWhiteSpace(promptingGuideline)) + { + if (this.useCustomPromptGuide) + this.AddInputIssue(T("Please attach and load a valid custom prompt guide file.")); + else + this.AddInputIssue(T("The prompting guideline file could not be loaded. Please verify 'prompting_guideline.md' in Assistants/PromptOptimizer.")); + return; + } + + this.CreateChatThread(); + var requestTime = this.AddUserRequest(this.BuildOptimizationRequest(promptingGuideline), hideContentFromUser: true); + var aiResponse = await this.AddAIResponseAsync(requestTime, hideContentFromUser: true); + + if (!TryParseOptimizationResult(aiResponse, out var parsedResult)) + { + this.optimizedPrompt = aiResponse.Trim(); + this.recClarityDirectness = T("Add clearer goals and explicit quality expectations."); + this.recExamplesContext = T("Add short examples and background context for your specific use case."); + this.recSequentialSteps = T("Break the task into numbered steps if order matters."); + this.recStructureMarkers = T("Use headings or markers to separate context, task, and constraints."); + this.recRoleDefinition = T("Define a role for the model to focus output style and expertise."); + this.recLanguageChoice = T("Use English for complex prompts and explicitly request response language if needed."); + this.AddInputIssue(T("The model response was not in the expected JSON format. The raw response is shown as optimized prompt.")); + this.AddVisibleOptimizedPromptBlock(); + return; + } + + this.ApplyOptimizationResult(parsedResult); + this.AddVisibleOptimizedPromptBlock(); + } + + private string BuildOptimizationRequest(string promptingGuideline) + { + return + $$""" + # Prompting Guideline + + {{promptingGuideline}} + + + # Task + Optimize the user's prompt according to the prompting guideline. + Preserve the original intent. + Ensure the optimized prompt is in {{this.SystemPromptLanguage()}}. + {{this.PromptImportantAspects()}} + + # User Input Prompt + + {{this.inputPrompt}} + + + # Output Requirements + Return valid JSON only (no markdown code fence, no additional text), using exactly this schema: + { + "optimized_prompt": "string", + "recommendations": { + "clarity_and_directness": "string", + "examples_and_context": "string", + "sequential_steps": "string", + "structure_with_markers": "string", + "role_definition": "string", + "language_choice": "string" + } + } + + # Recommendation style + Keep each recommendation concise and actionable. Mention what to improve in a future prompt version. + """; + } + + private string PromptImportantAspects() + { + if (string.IsNullOrWhiteSpace(this.importantAspects)) + return string.Empty; + + return + $""" + Additional emphasis for the optimization: + + {this.importantAspects} + + """; + } + + private static bool TryParseOptimizationResult(string rawResponse, out PromptOptimizationResult parsedResult) + { + parsedResult = new(); + + if (TryDeserialize(rawResponse, out parsedResult)) + return true; + + var codeFenceMatch = JSON_CODE_FENCE_REGEX.Match(rawResponse); + if (codeFenceMatch.Success) + { + var codeFenceJson = codeFenceMatch.Groups["json"].Value; + if (TryDeserialize(codeFenceJson, out parsedResult)) + return true; + } + + var firstBrace = rawResponse.IndexOf('{'); + var lastBrace = rawResponse.LastIndexOf('}'); + if (firstBrace >= 0 && lastBrace > firstBrace) + { + var objectText = rawResponse[firstBrace..(lastBrace + 1)]; + if (TryDeserialize(objectText, out parsedResult)) + return true; + } + + return false; + } + + private static bool TryDeserialize(string json, out PromptOptimizationResult parsedResult) + { + parsedResult = new(); + + if (string.IsNullOrWhiteSpace(json)) + return false; + + try + { + var probe = JsonSerializer.Deserialize(json, JSON_OPTIONS); + if (probe is null || string.IsNullOrWhiteSpace(probe.OptimizedPrompt)) + return false; + + probe.Recommendations ??= new PromptOptimizationRecommendations(); + parsedResult = probe; + return true; + } + catch + { + return false; + } + } + + private void ApplyOptimizationResult(PromptOptimizationResult optimizationResult) + { + this.optimizedPrompt = optimizationResult.OptimizedPrompt.Trim(); + this.recClarityDirectness = this.EmptyFallback(optimizationResult.Recommendations.ClarityAndDirectness); + this.recExamplesContext = this.EmptyFallback(optimizationResult.Recommendations.ExamplesAndContext); + this.recSequentialSteps = this.EmptyFallback(optimizationResult.Recommendations.SequentialSteps); + this.recStructureMarkers = this.EmptyFallback(optimizationResult.Recommendations.StructureWithMarkers); + this.recRoleDefinition = this.EmptyFallback(optimizationResult.Recommendations.RoleDefinition); + this.recLanguageChoice = this.EmptyFallback(optimizationResult.Recommendations.LanguageChoice); + } + + private string EmptyFallback(string text) + { + if (string.IsNullOrWhiteSpace(text)) + return T("No further recommendation in this area."); + + return text.Trim(); + } + + private void ResetOutput() + { + this.optimizedPrompt = string.Empty; + } + + private void ResetGuidelineSummaryToDefault() + { + this.recClarityDirectness = T("Use clear, explicit instructions and directly state quality expectations."); + this.recExamplesContext = T("Include short examples and context that explain the purpose behind requirements."); + this.recSequentialSteps = T("Prefer numbered steps when task order matters."); + this.recStructureMarkers = T("Separate context, task, constraints, and output format with headings or markers."); + this.recRoleDefinition = T("Assign a role to shape tone, expertise, and focus."); + this.recLanguageChoice = T("For complex tasks, write prompts in English and request response language explicitly if needed."); + } + + private void AddVisibleOptimizedPromptBlock() + { + if (string.IsNullOrWhiteSpace(this.optimizedPrompt)) + return; + + if (this.chatThread is null) + return; + + var visibleResponseContent = new ContentText + { + Text = this.optimizedPrompt, + }; + + this.chatThread.Blocks.Add(new ContentBlock + { + Time = DateTimeOffset.Now, + ContentType = ContentType.TEXT, + Role = ChatRole.AI, + HideFromUser = false, + Content = visibleResponseContent, + }); + } + + private static async Task ReadPromptingGuidelineAsync() + { +#if DEBUG + var guidelinePath = Path.Join(Environment.CurrentDirectory, "Assistants", "PromptOptimizer", "prompting_guideline.md"); + return File.Exists(guidelinePath) + ? await File.ReadAllTextAsync(guidelinePath) + : string.Empty; +#else + var resourceFileProvider = new ManifestEmbeddedFileProvider(Assembly.GetAssembly(type: typeof(Program))!, "Assistants/PromptOptimizer"); + var file = resourceFileProvider.GetFileInfo("prompting_guideline.md"); + if (!file.Exists) + return string.Empty; + + await using var fileStream = file.CreateReadStream(); + using var reader = new StreamReader(fileStream); + return await reader.ReadToEndAsync(); +#endif + } + + private async Task GetPromptingGuidelineForOptimizationAsync() + { + if (!this.useCustomPromptGuide) + return await ReadPromptingGuidelineAsync(); + + if (this.customPromptGuideFiles.Count == 0) + return string.Empty; + + if (!string.IsNullOrWhiteSpace(this.customPromptingGuidelineContent)) + return this.customPromptingGuidelineContent; + + var fileAttachment = this.customPromptGuideFiles.First(); + await this.LoadCustomPromptGuidelineContentAsync(fileAttachment); + return this.customPromptingGuidelineContent; + } + + private async Task SetUseCustomPromptGuide(bool useCustom) + { + this.useCustomPromptGuide = useCustom; + if (!useCustom) + return; + + if (this.customPromptGuideFiles.Count == 0) + return; + + var fileAttachment = this.customPromptGuideFiles.First(); + if (string.IsNullOrWhiteSpace(this.customPromptingGuidelineContent)) + await this.LoadCustomPromptGuidelineContentAsync(fileAttachment); + } + + private async Task OnCustomPromptGuideFilesChanged(HashSet files) + { + if (files.Count == 0) + { + this.customPromptGuideFiles.Clear(); + this.currentCustomPromptGuidePath = string.Empty; + this.customPromptingGuidelineContent = string.Empty; + return; + } + + // Keep only a single file and prefer the newly attached one over the previous selection. + var selected = files.FirstOrDefault(file => !string.Equals(file.FilePath, this.currentCustomPromptGuidePath, StringComparison.OrdinalIgnoreCase)) + ?? files.First(); + + this.customPromptGuideFiles = [ selected ]; + this.currentCustomPromptGuidePath = selected.FilePath; + + if (files.Count > 1) + this.Snackbar.Add(T("Replaced the previously selected custom prompt guide file."), Severity.Info); + + await this.LoadCustomPromptGuidelineContentAsync(selected); + } + + private async Task LoadCustomPromptGuidelineContentAsync(FileAttachment fileAttachment) + { + if (!fileAttachment.Exists) + { + this.customPromptingGuidelineContent = string.Empty; + this.Snackbar.Add(T("The selected custom prompt guide file could not be found."), Severity.Warning); + return; + } + + try + { + this.isLoadingCustomPromptGuide = true; + this.customPromptingGuidelineContent = await UserFile.LoadFileData(fileAttachment.FilePath, this.RustService, this.DialogService); + if (string.IsNullOrWhiteSpace(this.customPromptingGuidelineContent)) + this.Snackbar.Add(T("The custom prompt guide file is empty or could not be read."), Severity.Warning); + } + catch + { + this.customPromptingGuidelineContent = string.Empty; + this.Snackbar.Add(T("Failed to load custom prompt guide content."), Severity.Error); + } + finally + { + this.isLoadingCustomPromptGuide = false; + this.StateHasChanged(); + } + } + + private async Task OpenPromptingGuidelineDialog() + { + var promptingGuideline = await ReadPromptingGuidelineAsync(); + if (string.IsNullOrWhiteSpace(promptingGuideline)) + { + this.Snackbar.Add(T("The prompting guideline file could not be loaded."), Severity.Warning); + return; + } + + var dialogParameters = new DialogParameters + { + { x => x.GuidelineMarkdown, promptingGuideline } + }; + + var dialogReference = await this.DialogService.ShowAsync(T("Prompting Guideline"), dialogParameters, AIStudio.Dialogs.DialogOptions.FULLSCREEN); + await dialogReference.Result; + } + + private async Task OpenCustomPromptGuideDialog() + { + if (this.customPromptGuideFiles.Count == 0) + return; + + var fileAttachment = this.customPromptGuideFiles.First(); + if (string.IsNullOrWhiteSpace(this.customPromptingGuidelineContent) && !this.isLoadingCustomPromptGuide) + await this.LoadCustomPromptGuidelineContentAsync(fileAttachment); + + var dialogParameters = new DialogParameters + { + { x => x.Document, fileAttachment }, + { x => x.FileContent, this.customPromptingGuidelineContent }, + }; + + await this.DialogService.ShowAsync(T("Custom Prompt Guide Preview"), dialogParameters, AIStudio.Dialogs.DialogOptions.FULLSCREEN); + } +} diff --git a/app/MindWork AI Studio/Assistants/PromptOptimizer/PromptOptimizationResult.cs b/app/MindWork AI Studio/Assistants/PromptOptimizer/PromptOptimizationResult.cs new file mode 100644 index 00000000..88a78374 --- /dev/null +++ b/app/MindWork AI Studio/Assistants/PromptOptimizer/PromptOptimizationResult.cs @@ -0,0 +1,33 @@ +using System.Text.Json.Serialization; + +namespace AIStudio.Assistants.PromptOptimizer; + +public sealed class PromptOptimizationResult +{ + [JsonPropertyName("optimized_prompt")] + public string OptimizedPrompt { get; set; } = string.Empty; + + [JsonPropertyName("recommendations")] + public PromptOptimizationRecommendations Recommendations { get; set; } = new(); +} + +public sealed class PromptOptimizationRecommendations +{ + [JsonPropertyName("clarity_and_directness")] + public string ClarityAndDirectness { get; set; } = string.Empty; + + [JsonPropertyName("examples_and_context")] + public string ExamplesAndContext { get; set; } = string.Empty; + + [JsonPropertyName("sequential_steps")] + public string SequentialSteps { get; set; } = string.Empty; + + [JsonPropertyName("structure_with_markers")] + public string StructureWithMarkers { get; set; } = string.Empty; + + [JsonPropertyName("role_definition")] + public string RoleDefinition { get; set; } = string.Empty; + + [JsonPropertyName("language_choice")] + public string LanguageChoice { get; set; } = string.Empty; +} diff --git a/app/MindWork AI Studio/Assistants/PromptOptimizer/prompting_guideline.md b/app/MindWork AI Studio/Assistants/PromptOptimizer/prompting_guideline.md new file mode 100644 index 00000000..e505ee72 --- /dev/null +++ b/app/MindWork AI Studio/Assistants/PromptOptimizer/prompting_guideline.md @@ -0,0 +1,85 @@ +# 1 – Be Clear and Direct + +LLMs respond best to clear, explicit instructions. Being specific about your desired output improves results. If you want high-quality work, ask for it directly rather than expecting the model to guess. + +Think of the LLM as a skilled new employee: They do not know your specific workflows yet. The more precisely you explain what you want, the better the result. + +**Golden Rule:** If a colleague would be confused by your prompt without extra context, the LLM will be too. + +**Less Effective:** +```text +Create an analytics dashboard +``` + +**More Effective:** +```text +Create an analytics dashboard. Include relevant features and interactions. Go beyond the basics to create a fully-featured implementation. +``` + +# 2 – Add Examples and Context to Improve Performance + +Providing examples, context, or the reason behind your instructions helps the model understand your goals. + +**Less Effective:** +```text +NEVER use ellipses +``` + +**More Effective:** +```text +Your response will be read aloud by a text-to-speech engine, so never use ellipses since the engine will not know how to pronounce them. +``` + +The model can generalize from the explanation. + +# 3 – Use Sequential Steps + +When the order of tasks matters, provide instructions as a numbered list. + +**Example:** +```text +1. Analyze the provided text for key themes. +2. Extract the top 5 most frequent terms. +3. Format the output as a table with columns: Term, Frequency, Context. +``` + +# 4 – Structure Prompts with Markers + +Headings (e.g., `#` or `###`) or quotation marks (`"""`) help the model parse complex prompts, especially when mixing instructions, context, and data. + +**Less Effective:** +```text +{text input here} + +Summarize the text above as a bullet point list of the most important points. +``` + +**More Effective:** +```text +# Text: +"""{text input here}""" + +# Task: +Summarize the text above as a bullet point list of the most important points. +``` + +# 5 – Give the LLM a Role + +Setting a role in your prompt focuses the LLM's behavior and tone. Even a single sentence makes a difference. + +**Example:** +```text +You are a helpful coding assistant specializing in Python. +``` +```text +You are a senior marketing expert with 10 years of experience in the aerospace industry. +``` + +# 6 – Prompt Language + +LLMs are primarily trained on English text. They generally perform best with prompts written in **English**, especially for complex tasks. + +* **Recommendation:** Write your prompts in English. +* **If needed:** You can ask the LLM to respond in your native language (e.g., "Answer in German"). +* **Note:** This is especially important for smaller models, which may have limited multilingual capabilities. + diff --git a/app/MindWork AI Studio/Dialogs/PromptingGuidelineDialog.razor b/app/MindWork AI Studio/Dialogs/PromptingGuidelineDialog.razor new file mode 100644 index 00000000..db50e32b --- /dev/null +++ b/app/MindWork AI Studio/Dialogs/PromptingGuidelineDialog.razor @@ -0,0 +1,26 @@ +@inherits MSGComponentBase + + + + + @T("The full prompting guideline used by the Prompt Optimizer.") + + + +
+ +
+
+
+ + + @T("Close") + + +
diff --git a/app/MindWork AI Studio/Dialogs/PromptingGuidelineDialog.razor.cs b/app/MindWork AI Studio/Dialogs/PromptingGuidelineDialog.razor.cs new file mode 100644 index 00000000..f8672cd9 --- /dev/null +++ b/app/MindWork AI Studio/Dialogs/PromptingGuidelineDialog.razor.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNetCore.Components; +using AIStudio.Components; + +namespace AIStudio.Dialogs; + +public partial class PromptingGuidelineDialog : MSGComponentBase +{ + [CascadingParameter] + private IMudDialogInstance MudDialog { get; set; } = null!; + + [Parameter] + public string GuidelineMarkdown { get; set; } = string.Empty; + + private void Close() => this.MudDialog.Cancel(); + + private CodeBlockTheme CodeColorPalette => this.SettingsManager.IsDarkMode ? CodeBlockTheme.Dark : CodeBlockTheme.Default; + + private MudMarkdownStyling MarkdownStyling => new() + { + CodeBlock = { Theme = this.CodeColorPalette }, + }; +} diff --git a/app/MindWork AI Studio/Pages/Assistants.razor b/app/MindWork AI Studio/Pages/Assistants.razor index 8e4896dc..3a05b19c 100644 --- a/app/MindWork AI Studio/Pages/Assistants.razor +++ b/app/MindWork AI Studio/Pages/Assistants.razor @@ -15,6 +15,7 @@ (Components.TRANSLATION_ASSISTANT, PreviewFeatures.NONE), (Components.GRAMMAR_SPELLING_ASSISTANT, PreviewFeatures.NONE), (Components.REWRITE_ASSISTANT, PreviewFeatures.NONE), + (Components.PROMPT_OPTIMIZER_ASSISTANT, PreviewFeatures.NONE), (Components.SYNONYMS_ASSISTANT, PreviewFeatures.NONE) )) { @@ -26,6 +27,7 @@ + } diff --git a/app/MindWork AI Studio/Routes.razor.cs b/app/MindWork AI Studio/Routes.razor.cs index 92ff3067..594170ac 100644 --- a/app/MindWork AI Studio/Routes.razor.cs +++ b/app/MindWork AI Studio/Routes.razor.cs @@ -14,6 +14,7 @@ public sealed partial class Routes // ReSharper disable InconsistentNaming public const string ASSISTANT_TRANSLATION = "/assistant/translation"; public const string ASSISTANT_REWRITE = "/assistant/rewrite-improve"; + public const string ASSISTANT_PROMPT_OPTIMIZER = "/assistant/prompt-optimizer"; public const string ASSISTANT_ICON_FINDER = "/assistant/icons"; public const string ASSISTANT_GRAMMAR_SPELLING = "/assistant/grammar-spelling"; public const string ASSISTANT_SUMMARIZER = "/assistant/summarizer"; diff --git a/app/MindWork AI Studio/Settings/ConfigurableAssistant.cs b/app/MindWork AI Studio/Settings/ConfigurableAssistant.cs index f1076d9e..3b9bb625 100644 --- a/app/MindWork AI Studio/Settings/ConfigurableAssistant.cs +++ b/app/MindWork AI Studio/Settings/ConfigurableAssistant.cs @@ -11,6 +11,7 @@ public enum ConfigurableAssistant GRAMMAR_SPELLING_ASSISTANT, ICON_FINDER_ASSISTANT, REWRITE_ASSISTANT, + PROMPT_OPTIMIZER_ASSISTANT, TRANSLATION_ASSISTANT, AGENDA_ASSISTANT, CODING_ASSISTANT, diff --git a/app/MindWork AI Studio/Tools/AssistantVisibilityExtensions.cs b/app/MindWork AI Studio/Tools/AssistantVisibilityExtensions.cs index cb4e7fdc..8ab8eb88 100644 --- a/app/MindWork AI Studio/Tools/AssistantVisibilityExtensions.cs +++ b/app/MindWork AI Studio/Tools/AssistantVisibilityExtensions.cs @@ -47,6 +47,7 @@ public static class AssistantVisibilityExtensions Components.GRAMMAR_SPELLING_ASSISTANT => ConfigurableAssistant.GRAMMAR_SPELLING_ASSISTANT, Components.ICON_FINDER_ASSISTANT => ConfigurableAssistant.ICON_FINDER_ASSISTANT, Components.REWRITE_ASSISTANT => ConfigurableAssistant.REWRITE_ASSISTANT, + Components.PROMPT_OPTIMIZER_ASSISTANT => ConfigurableAssistant.PROMPT_OPTIMIZER_ASSISTANT, Components.TRANSLATION_ASSISTANT => ConfigurableAssistant.TRANSLATION_ASSISTANT, Components.AGENDA_ASSISTANT => ConfigurableAssistant.AGENDA_ASSISTANT, Components.CODING_ASSISTANT => ConfigurableAssistant.CODING_ASSISTANT, diff --git a/app/MindWork AI Studio/Tools/Components.cs b/app/MindWork AI Studio/Tools/Components.cs index 02718736..4b8f47f3 100644 --- a/app/MindWork AI Studio/Tools/Components.cs +++ b/app/MindWork AI Studio/Tools/Components.cs @@ -7,6 +7,7 @@ public enum Components GRAMMAR_SPELLING_ASSISTANT, ICON_FINDER_ASSISTANT, REWRITE_ASSISTANT, + PROMPT_OPTIMIZER_ASSISTANT, TRANSLATION_ASSISTANT, AGENDA_ASSISTANT, CODING_ASSISTANT, @@ -32,4 +33,4 @@ public enum Components AGENT_TEXT_CONTENT_CLEANER, AGENT_DATA_SOURCE_SELECTION, AGENT_RETRIEVAL_CONTEXT_VALIDATION, -} \ No newline at end of file +} diff --git a/app/MindWork AI Studio/Tools/ComponentsExtensions.cs b/app/MindWork AI Studio/Tools/ComponentsExtensions.cs index 70f06380..dfbae19f 100644 --- a/app/MindWork AI Studio/Tools/ComponentsExtensions.cs +++ b/app/MindWork AI Studio/Tools/ComponentsExtensions.cs @@ -35,6 +35,7 @@ public static class ComponentsExtensions Components.ICON_FINDER_ASSISTANT => TB("Icon Finder Assistant"), Components.TRANSLATION_ASSISTANT => TB("Translation Assistant"), Components.REWRITE_ASSISTANT => TB("Rewrite Assistant"), + Components.PROMPT_OPTIMIZER_ASSISTANT => TB("Prompt Optimizer Assistant"), Components.AGENDA_ASSISTANT => TB("Agenda Assistant"), Components.CODING_ASSISTANT => TB("Coding Assistant"), Components.EMAIL_ASSISTANT => TB("E-Mail Assistant"), @@ -57,6 +58,7 @@ public static class ComponentsExtensions Components.AGENDA_ASSISTANT => new(Event.SEND_TO_AGENDA_ASSISTANT, Routes.ASSISTANT_AGENDA), Components.CODING_ASSISTANT => new(Event.SEND_TO_CODING_ASSISTANT, Routes.ASSISTANT_CODING), Components.REWRITE_ASSISTANT => new(Event.SEND_TO_REWRITE_ASSISTANT, Routes.ASSISTANT_REWRITE), + Components.PROMPT_OPTIMIZER_ASSISTANT => new(Event.SEND_TO_PROMPT_OPTIMIZER_ASSISTANT, Routes.ASSISTANT_PROMPT_OPTIMIZER), Components.EMAIL_ASSISTANT => new(Event.SEND_TO_EMAIL_ASSISTANT, Routes.ASSISTANT_EMAIL), Components.TRANSLATION_ASSISTANT => new(Event.SEND_TO_TRANSLATION_ASSISTANT, Routes.ASSISTANT_TRANSLATION), Components.ICON_FINDER_ASSISTANT => new(Event.SEND_TO_ICON_FINDER_ASSISTANT, Routes.ASSISTANT_ICON_FINDER), @@ -167,4 +169,4 @@ public static class ComponentsExtensions _ => ChatTemplate.NO_CHAT_TEMPLATE, }; -} \ No newline at end of file +} diff --git a/app/MindWork AI Studio/Tools/Event.cs b/app/MindWork AI Studio/Tools/Event.cs index 6e899a79..a9a4f223 100644 --- a/app/MindWork AI Studio/Tools/Event.cs +++ b/app/MindWork AI Studio/Tools/Event.cs @@ -45,6 +45,7 @@ public enum Event SEND_TO_GRAMMAR_SPELLING_ASSISTANT, SEND_TO_ICON_FINDER_ASSISTANT, SEND_TO_REWRITE_ASSISTANT, + SEND_TO_PROMPT_OPTIMIZER_ASSISTANT, SEND_TO_TRANSLATION_ASSISTANT, SEND_TO_AGENDA_ASSISTANT, SEND_TO_CODING_ASSISTANT,