diff --git a/app/MindWork AI Studio/Assistants/Agenda/AssistantAgenda.razor.cs b/app/MindWork AI Studio/Assistants/Agenda/AssistantAgenda.razor.cs index c6d9acb..b9f95a8 100644 --- a/app/MindWork AI Studio/Assistants/Agenda/AssistantAgenda.razor.cs +++ b/app/MindWork AI Studio/Assistants/Agenda/AssistantAgenda.razor.cs @@ -303,7 +303,7 @@ public partial class AssistantAgenda : AssistantBaseCore if(string.IsNullOrWhiteSpace(content)) return "Please provide some content for the agenda. What are the main points of the meeting or the seminar?"; - var lines = content.Split('\n'); + var lines = content.Split('\n', StringSplitOptions.RemoveEmptyEntries); foreach (var line in lines) if(!line.TrimStart().StartsWith('-')) return "Please start each line of your content list with a dash (-) to create a bullet point list."; @@ -363,6 +363,9 @@ public partial class AssistantAgenda : AssistantBaseCore private string PromptLanguage() { + if(this.selectedTargetLanguage is CommonLanguages.AS_IS) + return "Use the same language as the input."; + if(this.selectedTargetLanguage is CommonLanguages.OTHER) return this.customTargetLanguage; diff --git a/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs b/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs index b993a05..331c559 100644 --- a/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs +++ b/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs @@ -184,6 +184,7 @@ public abstract partial class AssistantBase : ComponentBase SendTo.AGENDA_ASSISTANT => (Event.SEND_TO_AGENDA_ASSISTANT, Routes.ASSISTANT_AGENDA), SendTo.CODING_ASSISTANT => (Event.SEND_TO_CODING_ASSISTANT, Routes.ASSISTANT_CODING), SendTo.REWRITE_ASSISTANT => (Event.SEND_TO_REWRITE_ASSISTANT, Routes.ASSISTANT_REWRITE), + SendTo.EMAIL_ASSISTANT => (Event.SEND_TO_EMAIL_ASSISTANT, Routes.ASSISTANT_EMAIL), SendTo.TRANSLATION_ASSISTANT => (Event.SEND_TO_TRANSLATION_ASSISTANT, Routes.ASSISTANT_TRANSLATION), SendTo.ICON_FINDER_ASSISTANT => (Event.SEND_TO_ICON_FINDER_ASSISTANT, Routes.ASSISTANT_ICON_FINDER), SendTo.GRAMMAR_SPELLING_ASSISTANT => (Event.SEND_TO_GRAMMAR_SPELLING_ASSISTANT, Routes.ASSISTANT_GRAMMAR_SPELLING), diff --git a/app/MindWork AI Studio/Assistants/EMail/AssistantEMail.razor b/app/MindWork AI Studio/Assistants/EMail/AssistantEMail.razor new file mode 100644 index 0000000..e8997aa --- /dev/null +++ b/app/MindWork AI Studio/Assistants/EMail/AssistantEMail.razor @@ -0,0 +1,27 @@ +@attribute [Route(Routes.ASSISTANT_EMAIL)] +@inherits AssistantBaseCore + + +@if (this.provideHistory) +{ + + + +} + + + + + @foreach (var contentLine in this.bulletPointsLines) + { + @contentLine + } + + + + + + + + Create e-mail + \ No newline at end of file diff --git a/app/MindWork AI Studio/Assistants/EMail/AssistantEMail.razor.cs b/app/MindWork AI Studio/Assistants/EMail/AssistantEMail.razor.cs new file mode 100644 index 0000000..686b928 --- /dev/null +++ b/app/MindWork AI Studio/Assistants/EMail/AssistantEMail.razor.cs @@ -0,0 +1,252 @@ +using System.Text; + +using AIStudio.Chat; +using AIStudio.Tools; + +namespace AIStudio.Assistants.EMail; + +public partial class AssistantEMail : AssistantBaseCore +{ + protected override string Title => "E-Mail"; + + protected override string Description => + """ + Provide a list of bullet points and some basic information for an e-mail. The assistant will generate an e-mail based on that input. + """; + + protected override string SystemPrompt => + $""" + You are an automated system that writes emails. {this.SystemPromptHistory()} The user provides you with bullet points on what + he want to address in the response. Regarding the writing style of the email: {this.selectedWritingStyle.Prompt()} + {this.SystemPromptGreeting()} {this.SystemPromptName()} You write the email in the following language: {this.SystemPromptLanguage()}. + """; + + protected override IReadOnlyList FooterButtons => + [ + new SendToButton + { + Self = SendTo.EMAIL_ASSISTANT, + }, + ]; + + protected override ChatThread ConvertToChatThread => (this.chatThread ?? new()) with + { + SystemPrompt = SystemPrompts.DEFAULT, + }; + + protected override void ResetFrom() + { + this.inputBulletPoints = string.Empty; + this.bulletPointsLines.Clear(); + this.selectedFoci = []; + this.provideHistory = false; + this.inputHistory = string.Empty; + if (!this.MightPreselectValues()) + { + this.inputName = string.Empty; + this.selectedTargetLanguage = CommonLanguages.AS_IS; + this.customTargetLanguage = string.Empty; + this.selectedWritingStyle = WritingStyles.NONE; + this.inputGreeting = string.Empty; + } + } + + protected override bool MightPreselectValues() + { + if (this.SettingsManager.ConfigurationData.EMail.PreselectOptions) + { + this.inputName = this.SettingsManager.ConfigurationData.EMail.SenderName; + this.inputGreeting = this.SettingsManager.ConfigurationData.EMail.Greeting; + this.selectedWritingStyle = this.SettingsManager.ConfigurationData.EMail.PreselectedWritingStyle; + this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.EMail.PreselectedTargetLanguage; + this.customTargetLanguage = this.SettingsManager.ConfigurationData.EMail.PreselectOtherLanguage; + this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.EMail.PreselectedProvider); + return true; + } + + return false; + } + + private const string PLACEHOLDER_BULLET_POINTS = """ + - The last meeting was good + - Thank you for feedback + - Next is milestone 3 + - I need your input by next Wednesday + """; + + private WritingStyles selectedWritingStyle = WritingStyles.NONE; + private string inputGreeting = string.Empty; + private string inputBulletPoints = string.Empty; + private readonly List bulletPointsLines = []; + private IEnumerable selectedFoci = new HashSet(); + private string inputName = string.Empty; + private CommonLanguages selectedTargetLanguage = CommonLanguages.AS_IS; + private string customTargetLanguage = string.Empty; + private bool provideHistory; + private string inputHistory = string.Empty; + + #region Overrides of ComponentBase + + protected override async Task OnInitializedAsync() + { + this.MightPreselectValues(); + var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages(Event.SEND_TO_EMAIL_ASSISTANT).FirstOrDefault(); + if (deferredContent is not null) + this.inputBulletPoints = deferredContent; + + await base.OnInitializedAsync(); + } + + #endregion + + private string? ValidateBulletPoints(string content) + { + if(string.IsNullOrWhiteSpace(content)) + return "Please provide some content for the e-mail."; + + var lines = content.Split('\n', StringSplitOptions.RemoveEmptyEntries); + foreach (var line in lines) + if(!line.TrimStart().StartsWith('-')) + return "Please start each line of your content list with a dash (-) to create a bullet point list."; + + return null; + } + + private string? ValidateTargetLanguage(CommonLanguages language) + { + if(language is CommonLanguages.AS_IS) + return "Please select a target language for the e-mail."; + + return null; + } + + private string? ValidateCustomLanguage(string language) + { + if(this.selectedTargetLanguage == CommonLanguages.OTHER && string.IsNullOrWhiteSpace(language)) + return "Please provide a custom language."; + + return null; + } + + private string? ValidateWritingStyle(WritingStyles style) + { + if(style == WritingStyles.NONE) + return "Please select a writing style for the e-mail."; + + return null; + } + + private string? ValidateHistory(string history) + { + if(this.provideHistory && string.IsNullOrWhiteSpace(history)) + return "Please provide some history for the e-mail."; + + return null; + } + + private void OnContentChanged(string content) + { + this.bulletPointsLines.Clear(); + var previousSelectedFoci = new HashSet(); + foreach (var line in content.AsSpan().EnumerateLines()) + { + var trimmedLine = line.Trim(); + if (trimmedLine.StartsWith("-")) + trimmedLine = trimmedLine[1..].Trim(); + + if (trimmedLine.Length == 0) + continue; + + var finalLine = trimmedLine.ToString(); + if(this.selectedFoci.Any(x => x.StartsWith(finalLine, StringComparison.InvariantCultureIgnoreCase))) + previousSelectedFoci.Add(finalLine); + + this.bulletPointsLines.Add(finalLine); + } + + this.selectedFoci = previousSelectedFoci; + } + + private string SystemPromptHistory() + { + if (this.provideHistory) + return "You receive the previous conversation as context."; + + return string.Empty; + } + + private string SystemPromptGreeting() + { + if(!string.IsNullOrWhiteSpace(this.inputGreeting)) + return $"Your greeting should consider the following formulation: {this.inputGreeting}."; + + return string.Empty; + } + + private string SystemPromptName() + { + if(!string.IsNullOrWhiteSpace(this.inputName)) + return $"For the closing phrase of the email, please use the following name: {this.inputName}."; + + return string.Empty; + } + + private string SystemPromptLanguage() + { + if(this.selectedTargetLanguage is CommonLanguages.AS_IS) + return "Use the same language as the input"; + + if(this.selectedTargetLanguage is CommonLanguages.OTHER) + return this.customTargetLanguage; + + return this.selectedTargetLanguage.Name(); + } + + private string PromptFoci() + { + if(!this.selectedFoci.Any()) + return string.Empty; + + var sb = new StringBuilder(); + sb.AppendLine("I want to amplify the following points:"); + foreach (var focus in this.selectedFoci) + sb.AppendLine($"- {focus}"); + + return sb.ToString(); + } + + private string PromptHistory() + { + if(!this.provideHistory) + return string.Empty; + + return $""" + The previous conversation was: + + ``` + {this.inputHistory} + ``` + """; + } + + private async Task CreateMail() + { + await this.form!.Validate(); + if (!this.inputIsValid) + return; + + this.CreateChatThread(); + var time = this.AddUserRequest( + $""" + {this.PromptHistory()} + + My bullet points for the e-mail are: + + {this.inputBulletPoints} + + {this.PromptFoci()} + """); + + await this.AddAIResponseAsync(time); + } +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Assistants/EMail/WritingStyles.cs b/app/MindWork AI Studio/Assistants/EMail/WritingStyles.cs new file mode 100644 index 0000000..dfc728a --- /dev/null +++ b/app/MindWork AI Studio/Assistants/EMail/WritingStyles.cs @@ -0,0 +1,11 @@ +namespace AIStudio.Assistants.EMail; + +public enum WritingStyles +{ + NONE = 0, + + BUSINESS_FORMAL, + BUSINESS_INFORMAL, + ACADEMIC, + PERSONAL, +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Assistants/EMail/WritingStylesExtensions.cs b/app/MindWork AI Studio/Assistants/EMail/WritingStylesExtensions.cs new file mode 100644 index 0000000..119f804 --- /dev/null +++ b/app/MindWork AI Studio/Assistants/EMail/WritingStylesExtensions.cs @@ -0,0 +1,24 @@ +namespace AIStudio.Assistants.EMail; + +public static class WritingStylesExtensions +{ + public static string Name(this WritingStyles style) => style switch + { + WritingStyles.ACADEMIC => "Academic", + WritingStyles.PERSONAL => "Personal", + WritingStyles.BUSINESS_FORMAL => "Business formal", + WritingStyles.BUSINESS_INFORMAL => "Business informal", + + _ => "Not specified", + }; + + public static string Prompt(this WritingStyles style) => style switch + { + WritingStyles.ACADEMIC => "Use an academic style for communication in an academic context like between students and professors.", + WritingStyles.PERSONAL => "Use a personal style for communication between friends and family.", + WritingStyles.BUSINESS_FORMAL => "Use a formal business style for this e-mail.", + WritingStyles.BUSINESS_INFORMAL => "Use an informal business style for this e-mail.", + + _ => "Use a formal business style for this e-mail.", + }; +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Assistants/RewriteImprove/WritingStylesExtensions.cs b/app/MindWork AI Studio/Assistants/RewriteImprove/WritingStylesExtensions.cs index 184346a..90a8886 100644 --- a/app/MindWork AI Studio/Assistants/RewriteImprove/WritingStylesExtensions.cs +++ b/app/MindWork AI Studio/Assistants/RewriteImprove/WritingStylesExtensions.cs @@ -2,39 +2,33 @@ namespace AIStudio.Assistants.RewriteImprove; public static class WritingStylesExtensions { - public static string Name(this WritingStyles style) + public static string Name(this WritingStyles style) => style switch { - return style switch - { - WritingStyles.EVERYDAY => "Everyday (personal texts, social media)", - WritingStyles.BUSINESS => "Business (business emails, reports, presentations)", - WritingStyles.SCIENTIFIC => "Scientific (scientific papers, research reports)", - WritingStyles.JOURNALISTIC => "Journalistic (magazines, newspapers, news)", - WritingStyles.LITERARY => "Literary (fiction, poetry)", - WritingStyles.TECHNICAL => "Technical (manuals, documentation)", - WritingStyles.MARKETING => "Marketing (advertisements, sales texts)", - WritingStyles.ACADEMIC => "Academic (essays, seminar papers)", - WritingStyles.LEGAL => "Legal (legal texts, contracts)", - - _ => "Not specified", - }; - } - - public static string Prompt(this WritingStyles style) + WritingStyles.EVERYDAY => "Everyday (personal texts, social media)", + WritingStyles.BUSINESS => "Business (business emails, reports, presentations)", + WritingStyles.SCIENTIFIC => "Scientific (scientific papers, research reports)", + WritingStyles.JOURNALISTIC => "Journalistic (magazines, newspapers, news)", + WritingStyles.LITERARY => "Literary (fiction, poetry)", + WritingStyles.TECHNICAL => "Technical (manuals, documentation)", + WritingStyles.MARKETING => "Marketing (advertisements, sales texts)", + WritingStyles.ACADEMIC => "Academic (essays, seminar papers)", + WritingStyles.LEGAL => "Legal (legal texts, contracts)", + + _ => "Not specified", + }; + + public static string Prompt(this WritingStyles style) => style switch { - return style switch - { - WritingStyles.EVERYDAY => "Use a everyday style like for personal texts, social media, and informal communication.", - WritingStyles.BUSINESS => "Use a business style like for business emails, reports, and presentations. Most important is clarity and professionalism.", - WritingStyles.SCIENTIFIC => "Use a scientific style like for scientific papers, research reports, and academic writing. Most important is precision and objectivity.", - WritingStyles.JOURNALISTIC => "Use a journalistic style like for magazines, newspapers, and news. Most important is readability and engaging content.", - WritingStyles.LITERARY => "Use a literary style like for fiction, poetry, and creative writing. Most important is creativity and emotional impact.", - WritingStyles.TECHNICAL => "Use a technical style like for manuals, documentation, and technical writing. Most important is clarity and precision.", - WritingStyles.MARKETING => "Use a marketing style like for advertisements, sales texts, and promotional content. Most important is persuasiveness and engagement.", - WritingStyles.ACADEMIC => "Use a academic style like for essays, seminar papers, and academic writing. Most important is clarity and objectivity.", - WritingStyles.LEGAL => "Use a legal style like for legal texts, contracts, and official documents. Most important is precision and legal correctness. Use formal legal language.", - - _ => "Keep the style of the text as it is.", - }; - } + WritingStyles.EVERYDAY => "Use a everyday style like for personal texts, social media, and informal communication.", + WritingStyles.BUSINESS => "Use a business style like for business emails, reports, and presentations. Most important is clarity and professionalism.", + WritingStyles.SCIENTIFIC => "Use a scientific style like for scientific papers, research reports, and academic writing. Most important is precision and objectivity.", + WritingStyles.JOURNALISTIC => "Use a journalistic style like for magazines, newspapers, and news. Most important is readability and engaging content.", + WritingStyles.LITERARY => "Use a literary style like for fiction, poetry, and creative writing. Most important is creativity and emotional impact.", + WritingStyles.TECHNICAL => "Use a technical style like for manuals, documentation, and technical writing. Most important is clarity and precision.", + WritingStyles.MARKETING => "Use a marketing style like for advertisements, sales texts, and promotional content. Most important is persuasiveness and engagement.", + WritingStyles.ACADEMIC => "Use a academic style like for essays, seminar papers, and academic writing. Most important is clarity and objectivity.", + WritingStyles.LEGAL => "Use a legal style like for legal texts, contracts, and official documents. Most important is precision and legal correctness. Use formal legal language.", + + _ => "Keep the style of the text as it is.", + }; } \ No newline at end of file diff --git a/app/MindWork AI Studio/Pages/Assistants.razor b/app/MindWork AI Studio/Pages/Assistants.razor index 82acbfe..6fecfd6 100644 --- a/app/MindWork AI Studio/Pages/Assistants.razor +++ b/app/MindWork AI Studio/Pages/Assistants.razor @@ -20,6 +20,7 @@ Business + diff --git a/app/MindWork AI Studio/Pages/Settings.razor b/app/MindWork AI Studio/Pages/Settings.razor index 7c6145e..4a7bd8c 100644 --- a/app/MindWork AI Studio/Pages/Settings.razor +++ b/app/MindWork AI Studio/Pages/Settings.razor @@ -193,10 +193,25 @@ { } - + + + + + + + + + @if (this.SettingsManager.ConfigurationData.EMail.PreselectedTargetLanguage is CommonLanguages.OTHER) + { + + } + + + + diff --git a/app/MindWork AI Studio/Routes.razor.cs b/app/MindWork AI Studio/Routes.razor.cs index 3d77083..f94fee1 100644 --- a/app/MindWork AI Studio/Routes.razor.cs +++ b/app/MindWork AI Studio/Routes.razor.cs @@ -17,5 +17,6 @@ public sealed partial class Routes public const string ASSISTANT_SUMMARIZER = "/assistant/summarizer"; public const string ASSISTANT_CODING = "/assistant/coding"; public const string ASSISTANT_AGENDA = "/assistant/agenda"; + public const string ASSISTANT_EMAIL = "/assistant/email"; // ReSharper restore InconsistentNaming } \ No newline at end of file diff --git a/app/MindWork AI Studio/Settings/ConfigurationSelectData.cs b/app/MindWork AI Studio/Settings/ConfigurationSelectData.cs index d3873d5..f879237 100644 --- a/app/MindWork AI Studio/Settings/ConfigurationSelectData.cs +++ b/app/MindWork AI Studio/Settings/ConfigurationSelectData.cs @@ -3,9 +3,13 @@ using AIStudio.Assistants.Coding; using AIStudio.Assistants.IconFinder; using AIStudio.Assistants.RewriteImprove; using AIStudio.Assistants.TextSummarizer; +using AIStudio.Assistants.EMail; using AIStudio.Settings.DataModel; using AIStudio.Tools; +using WritingStylesRewrite = AIStudio.Assistants.RewriteImprove.WritingStyles; +using WritingStylesEMail = AIStudio.Assistants.EMail.WritingStyles; + namespace AIStudio.Settings; /// @@ -101,9 +105,15 @@ public static class ConfigurationSelectDataFactory yield return new(number.Name(), number); } - public static IEnumerable> GetWritingStylesData() + public static IEnumerable> GetWritingStyles4RewriteData() { - foreach (var style in Enum.GetValues()) + foreach (var style in Enum.GetValues()) + yield return new(style.Name(), style); + } + + public static IEnumerable> GetWritingStyles4EMailData() + { + foreach (var style in Enum.GetValues()) yield return new(style.Name(), style); } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Settings/DataModel/Data.cs b/app/MindWork AI Studio/Settings/DataModel/Data.cs index 1a39c2f..66d50f1 100644 --- a/app/MindWork AI Studio/Settings/DataModel/Data.cs +++ b/app/MindWork AI Studio/Settings/DataModel/Data.cs @@ -42,4 +42,6 @@ public sealed class Data public DataGrammarSpelling GrammarSpelling { get; init; } = new(); public DataRewriteImprove RewriteImprove { get; init; } = new(); + + public DataEMail EMail { get; set; } = new(); } \ No newline at end of file diff --git a/app/MindWork AI Studio/Settings/DataModel/DataEMail.cs b/app/MindWork AI Studio/Settings/DataModel/DataEMail.cs new file mode 100644 index 0000000..710507f --- /dev/null +++ b/app/MindWork AI Studio/Settings/DataModel/DataEMail.cs @@ -0,0 +1,42 @@ +using AIStudio.Assistants.EMail; +using AIStudio.Tools; + +namespace AIStudio.Settings.DataModel; + +public sealed class DataEMail +{ + /// + /// Preselect any rewrite options? + /// + public bool PreselectOptions { get; set; } + + /// + /// Preselect the target language? + /// + public CommonLanguages PreselectedTargetLanguage { get; set; } + + /// + /// Preselect any other language? + /// + public string PreselectOtherLanguage { get; set; } = string.Empty; + + /// + /// Preselect any writing style? + /// + public WritingStyles PreselectedWritingStyle { get; set; } + + /// + /// Preselect a provider? + /// + public string PreselectedProvider { get; set; } = string.Empty; + + /// + /// Preselect a greeting phrase? + /// + public string Greeting { get; set; } = string.Empty; + + /// + /// Preselect the sender name for the closing salutation? + /// + public string SenderName { get; set; } = string.Empty; +} \ 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 8103e18..c5cfad7 100644 --- a/app/MindWork AI Studio/Tools/Event.cs +++ b/app/MindWork AI Studio/Tools/Event.cs @@ -25,4 +25,5 @@ public enum Event SEND_TO_CODING_ASSISTANT, SEND_TO_TEXT_SUMMARIZER_ASSISTANT, SEND_TO_CHAT, + SEND_TO_EMAIL_ASSISTANT, } \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/SendTo.cs b/app/MindWork AI Studio/Tools/SendTo.cs index 477f3b6..b29483a 100644 --- a/app/MindWork AI Studio/Tools/SendTo.cs +++ b/app/MindWork AI Studio/Tools/SendTo.cs @@ -11,6 +11,7 @@ public enum SendTo AGENDA_ASSISTANT, CODING_ASSISTANT, TEXT_SUMMARIZER_ASSISTANT, + EMAIL_ASSISTANT, CHAT, } \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/SendToExtensions.cs b/app/MindWork AI Studio/Tools/SendToExtensions.cs index 9e8a360..48b78e3 100644 --- a/app/MindWork AI Studio/Tools/SendToExtensions.cs +++ b/app/MindWork AI Studio/Tools/SendToExtensions.cs @@ -13,6 +13,7 @@ public static class SendToExtensions SendTo.REWRITE_ASSISTANT => "Rewrite Assistant", SendTo.AGENDA_ASSISTANT => "Agenda Assistant", SendTo.CODING_ASSISTANT => "Coding Assistant", + SendTo.EMAIL_ASSISTANT => "E-Mail Assistant", SendTo.CHAT => "New Chat", diff --git a/app/MindWork AI Studio/wwwroot/changelog/v0.8.12.md b/app/MindWork AI Studio/wwwroot/changelog/v0.8.12.md new file mode 100644 index 0000000..5bfdcbc --- /dev/null +++ b/app/MindWork AI Studio/wwwroot/changelog/v0.8.12.md @@ -0,0 +1,5 @@ +# v0.8.12, build 174 +- Added an e-mail writing assistant. +- Added the possibility to preselect some e-mail writing assistant options. +- Improved the content validation for the agenda assistant. +- Improved the language handling of the agenda assistant. \ No newline at end of file