mirror of
				https://github.com/MindWorkAI/AI-Studio.git
				synced 2025-10-26 05:40:21 +00:00 
			
		
		
		
	Implemented the "my tasks" assistant (#137)
This commit is contained in:
		
							parent
							
								
									7a5f2d4aec
								
							
						
					
					
						commit
						09f5b83e66
					
				| @ -94,7 +94,7 @@ | ||||
|                 Reset | ||||
|             </MudButton> | ||||
|              | ||||
|             @if (this.AllowProfiles) | ||||
|             @if (this.AllowProfiles && this.ShowProfileSelection) | ||||
|             { | ||||
|                 <ProfileSelection MarginLeft="" @bind-CurrentProfile="@this.currentProfile"/> | ||||
|             } | ||||
|  | ||||
| @ -58,6 +58,8 @@ public abstract partial class AssistantBase : ComponentBase | ||||
| 
 | ||||
|     protected virtual bool AllowProfiles => true; | ||||
| 
 | ||||
|     protected virtual bool ShowProfileSelection => true; | ||||
|      | ||||
|     protected virtual bool ShowDedicatedProgress => false; | ||||
| 
 | ||||
|     protected virtual ChatThread ConvertToChatThread => this.chatThread ?? new(); | ||||
| @ -69,12 +71,12 @@ public abstract partial class AssistantBase : ComponentBase | ||||
|     protected AIStudio.Settings.Provider providerSettings; | ||||
|     protected MudForm? form; | ||||
|     protected bool inputIsValid; | ||||
|     protected Profile currentProfile = Profile.NO_PROFILE; | ||||
|      | ||||
|     protected ChatThread? chatThread; | ||||
|     private ContentBlock? resultingContentBlock; | ||||
|     private string[] inputIssues = []; | ||||
|     private bool isProcessing; | ||||
|     private Profile currentProfile = Profile.NO_PROFILE; | ||||
|      | ||||
|     #region Overrides of ComponentBase | ||||
| 
 | ||||
|  | ||||
| @ -0,0 +1,11 @@ | ||||
| @attribute [Route(Routes.ASSISTANT_MY_TASKS)] | ||||
| @inherits AssistantBaseCore | ||||
| 
 | ||||
| <ProfileFormSelection Validation="@this.ValidateProfile" @bind-Profile="@this.currentProfile"/> | ||||
| <MudTextField T="string" @bind-Text="@this.inputText" Validation="@this.ValidatingText" AdornmentIcon="@Icons.Material.Filled.DocumentScanner" Adornment="Adornment.Start" Label="Text or email" Variant="Variant.Outlined" Lines="12" AutoGrow="@true" MaxLines="24" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> | ||||
| <EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelectingOptional())" @bind-Value="@this.selectedTargetLanguage" Icon="@Icons.Material.Filled.Translate" Label="Target language" AllowOther="@true" OtherValue="CommonLanguages.OTHER" @bind-OtherInput="@this.customTargetLanguage" ValidateOther="@this.ValidateCustomLanguage" LabelOther="Custom target language" /> | ||||
| <ProviderSelection @bind-ProviderSettings="@this.providerSettings" ValidateProvider="@this.ValidatingProvider"/> | ||||
| 
 | ||||
| <MudButton Variant="Variant.Filled" Class="mb-3" OnClick="() => this.AnalyzeText()"> | ||||
|     Analyze text | ||||
| </MudButton> | ||||
| @ -0,0 +1,119 @@ | ||||
| using AIStudio.Settings; | ||||
| 
 | ||||
| namespace AIStudio.Assistants.MyTasks; | ||||
| 
 | ||||
| public partial class AssistantMyTasks : AssistantBaseCore | ||||
| { | ||||
|     protected override Tools.Components Component => Tools.Components.MY_TASKS_ASSISTANT; | ||||
|      | ||||
|     protected override string Title => "My Tasks"; | ||||
|      | ||||
|     protected override string Description => | ||||
|         """
 | ||||
|         You received a cryptic email that was sent to many recipients and you are now wondering | ||||
|         if you need to do something? Copy the email into the input field. You also need to select | ||||
|         a personal profile. In this profile, you should describe your role in the organization. | ||||
|         The AI will then try to give you hints on what your tasks might be. | ||||
|         """;
 | ||||
|      | ||||
|     protected override string SystemPrompt =>  | ||||
|         $"""
 | ||||
|         You are a friendly and professional business expert. You receive business emails, protocols, | ||||
|         reports, etc. as input. Additionally, you know the user's role in the organization. The user | ||||
|         wonders if any tasks arise for them in their role based on the text. You now try to give hints | ||||
|         and advice on whether and what the user should do. When you believe there are no tasks for the | ||||
|         user, you tell them this. You consider typical business etiquette in your advice. | ||||
|          | ||||
|         You write your advice in the following language: {this.SystemPromptLanguage()}. | ||||
|         """;
 | ||||
|      | ||||
|     protected override IReadOnlyList<IButtonData> FooterButtons => []; | ||||
| 
 | ||||
|     protected override bool ShowProfileSelection => false; | ||||
| 
 | ||||
|     protected override void ResetFrom() | ||||
|     { | ||||
|         this.inputText = string.Empty; | ||||
|         if (!this.MightPreselectValues()) | ||||
|         { | ||||
|             this.selectedTargetLanguage = CommonLanguages.AS_IS; | ||||
|             this.customTargetLanguage = string.Empty; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     protected override bool MightPreselectValues() | ||||
|     { | ||||
|         if (this.SettingsManager.ConfigurationData.MyTasks.PreselectOptions) | ||||
|         { | ||||
|             this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.MyTasks.PreselectedTargetLanguage; | ||||
|             this.customTargetLanguage = this.SettingsManager.ConfigurationData.MyTasks.PreselectOtherLanguage; | ||||
|             return true; | ||||
|         } | ||||
|          | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     private string inputText = string.Empty; | ||||
|     private CommonLanguages selectedTargetLanguage = CommonLanguages.AS_IS; | ||||
|     private string customTargetLanguage = string.Empty; | ||||
|      | ||||
|     #region Overrides of ComponentBase | ||||
| 
 | ||||
|     protected override async Task OnInitializedAsync() | ||||
|     { | ||||
|         var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages<string>(Event.SEND_TO_MY_TASKS_ASSISTANT).FirstOrDefault(); | ||||
|         if (deferredContent is not null) | ||||
|             this.inputText = deferredContent; | ||||
|          | ||||
|         await base.OnInitializedAsync(); | ||||
|     } | ||||
| 
 | ||||
|     #endregion | ||||
|      | ||||
|     private string? ValidatingText(string text) | ||||
|     { | ||||
|         if(string.IsNullOrWhiteSpace(text)) | ||||
|             return "Please provide some text as input. For example, an email."; | ||||
|          | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     private string? ValidateProfile(Profile profile) | ||||
|     { | ||||
|         if(profile == default || profile == Profile.NO_PROFILE) | ||||
|             return "Please select one of your profiles."; | ||||
|          | ||||
|         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 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 async Task AnalyzeText() | ||||
|     { | ||||
|         await this.form!.Validate(); | ||||
|         if (!this.inputIsValid) | ||||
|             return; | ||||
|          | ||||
|         this.CreateChatThread(); | ||||
|         var time = this.AddUserRequest(this.inputText); | ||||
| 
 | ||||
|         await this.AddAIResponseAsync(time); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										10
									
								
								app/MindWork AI Studio/Components/ProfileFormSelection.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/MindWork AI Studio/Components/ProfileFormSelection.razor
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| @using AIStudio.Settings | ||||
| 
 | ||||
| <MudSelect T="Profile" Strict="@true" Value="@this.Profile" ValueChanged="@this.SelectionChanged" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Person4" Margin="Margin.Dense" Label="Select one of your profiles" Variant="Variant.Outlined" Class="mb-3" Validation="@this.Validation"> | ||||
|     @foreach (var profile in this.SettingsManager.ConfigurationData.Profiles.GetAllProfiles()) | ||||
|     { | ||||
|         <MudSelectItem Value="profile"> | ||||
|             @profile.Name | ||||
|         </MudSelectItem> | ||||
|     } | ||||
| </MudSelect> | ||||
| @ -0,0 +1,26 @@ | ||||
| using AIStudio.Settings; | ||||
| 
 | ||||
| using Microsoft.AspNetCore.Components; | ||||
| 
 | ||||
| namespace AIStudio.Components; | ||||
| 
 | ||||
| public partial class ProfileFormSelection : ComponentBase | ||||
| { | ||||
|     [Parameter] | ||||
|     public Profile Profile { get; set; } = Profile.NO_PROFILE; | ||||
|      | ||||
|     [Parameter] | ||||
|     public EventCallback<Profile> ProfileChanged { get; set; } | ||||
|      | ||||
|     [Parameter] | ||||
|     public Func<Profile, string?> Validation { get; set; } = _ => null; | ||||
|      | ||||
|     [Inject] | ||||
|     private SettingsManager SettingsManager { get; init; } = null!; | ||||
|      | ||||
|     private async Task SelectionChanged(Profile profile) | ||||
|     { | ||||
|         this.Profile = profile; | ||||
|         await this.ProfileChanged.InvokeAsync(profile); | ||||
|     } | ||||
| } | ||||
| @ -22,6 +22,7 @@ | ||||
|     </MudText> | ||||
|     <MudStack Row="@true" Wrap="@Wrap.Wrap" Class="mb-3"> | ||||
|         <AssistantBlock Name="E-Mail" Description="Generate an e-mail for a given context." Icon="@Icons.Material.Filled.Email" Link="@Routes.ASSISTANT_EMAIL"/> | ||||
|         <AssistantBlock Name="My Tasks" Description="Analyze a text or an email for tasks you need to complete." Icon="@Icons.Material.Filled.Task" Link="@Routes.ASSISTANT_MY_TASKS"/> | ||||
|         <AssistantBlock Name="Agenda Planner" Description="Generate an agenda for a given meeting, seminar, etc." Icon="@Icons.Material.Filled.CalendarToday" Link="@Routes.ASSISTANT_AGENDA"/> | ||||
|         <AssistantBlock Name="Legal Check" Description="Ask a question about a legal document." Icon="@Icons.Material.Filled.Gavel" Link="@Routes.ASSISTANT_LEGAL_CHECK"/> | ||||
|         <AssistantBlock Name="Icon Finder" Description="Using a LLM to find an icon for a given context." Icon="@Icons.Material.Filled.FindInPage" Link="@Routes.ASSISTANT_ICON_FINDER"/> | ||||
|  | ||||
| @ -300,6 +300,19 @@ | ||||
|             </MudPaper> | ||||
|         </ExpansionPanel> | ||||
| 
 | ||||
|         <ExpansionPanel HeaderIcon="@Icons.Material.Filled.Task" HeaderText="Assistant: My Tasks"> | ||||
|             <MudPaper Class="pa-3 mb-8 border-dashed border rounded-lg"> | ||||
|                 <ConfigurationOption OptionDescription="Preselect options?" LabelOn="Options are preselected" LabelOff="No options are preselected" State="@(() => this.SettingsManager.ConfigurationData.MyTasks.PreselectOptions)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.MyTasks.PreselectOptions = updatedState)" OptionHelp="When enabled, you can preselect options. This is might be useful when you prefer a specific language or LLM model."/> | ||||
|                 <ConfigurationSelect OptionDescription="Preselect the language" Disabled="@(() => !this.SettingsManager.ConfigurationData.MyTasks.PreselectOptions)" SelectedValue="@(() => this.SettingsManager.ConfigurationData.MyTasks.PreselectedTargetLanguage)" Data="@ConfigurationSelectDataFactory.GetCommonLanguagesOptionalData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.MyTasks.PreselectedTargetLanguage = selectedValue)" OptionHelp="Which language should be preselected?"/> | ||||
|                 @if (this.SettingsManager.ConfigurationData.MyTasks.PreselectedTargetLanguage is CommonLanguages.OTHER) | ||||
|                 { | ||||
|                     <ConfigurationText OptionDescription="Preselect another language" Disabled="@(() => !this.SettingsManager.ConfigurationData.MyTasks.PreselectOptions)" Icon="@Icons.Material.Filled.Translate" Text="@(() => this.SettingsManager.ConfigurationData.MyTasks.PreselectOtherLanguage)" TextUpdate="@(updatedText => this.SettingsManager.ConfigurationData.MyTasks.PreselectOtherLanguage = updatedText)"/> | ||||
|                 } | ||||
|                 <ConfigurationSelect OptionDescription="Preselect one of your profiles?" Disabled="@(() => !this.SettingsManager.ConfigurationData.MyTasks.PreselectOptions)" SelectedValue="@(() => this.SettingsManager.ConfigurationData.MyTasks.PreselectedProfile)" Data="@ConfigurationSelectDataFactory.GetProfilesData(this.SettingsManager.ConfigurationData.Profiles)" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.MyTasks.PreselectedProfile = selectedValue)" OptionHelp="Would you like to preselect one of your profiles?"/> | ||||
|                 <ConfigurationProviderSelection Data="@this.availableProviders" Disabled="@(() => !this.SettingsManager.ConfigurationData.MyTasks.PreselectOptions)" SelectedValue="@(() => this.SettingsManager.ConfigurationData.MyTasks.PreselectedProvider)" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.MyTasks.PreselectedProvider = selectedValue)"/> | ||||
|             </MudPaper> | ||||
|         </ExpansionPanel> | ||||
|          | ||||
|         <ExpansionPanel HeaderIcon="@Icons.Material.Filled.TextFields" HeaderText="Agent: Text Content Cleaner Options"> | ||||
|             <MudPaper Class="pa-3 mb-8 border-dashed border rounded-lg"> | ||||
|                 <MudText Typo="Typo.body1" Class="mb-3"> | ||||
|  | ||||
| @ -20,5 +20,6 @@ public sealed partial class Routes | ||||
|     public const string ASSISTANT_EMAIL = "/assistant/email"; | ||||
|     public const string ASSISTANT_LEGAL_CHECK = "/assistant/legal-check"; | ||||
|     public const string ASSISTANT_SYNONYMS = "/assistant/synonyms"; | ||||
|     public const string ASSISTANT_MY_TASKS = "/assistant/my-tasks"; | ||||
|     // ReSharper restore InconsistentNaming | ||||
| } | ||||
| @ -58,4 +58,6 @@ public sealed class Data | ||||
|     public DataLegalCheck LegalCheck { get; set; } = new(); | ||||
|      | ||||
|     public DataSynonyms Synonyms { get; set; } = new(); | ||||
| 
 | ||||
|     public DataMyTasks MyTasks { get; set; } = new(); | ||||
| } | ||||
							
								
								
									
										29
									
								
								app/MindWork AI Studio/Settings/DataModel/DataMyTasks.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								app/MindWork AI Studio/Settings/DataModel/DataMyTasks.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| namespace AIStudio.Settings.DataModel; | ||||
| 
 | ||||
| public sealed class DataMyTasks | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Do you want to preselect any options? | ||||
|     /// </summary> | ||||
|     public bool PreselectOptions { get; set; } | ||||
|      | ||||
|     /// <summary> | ||||
|     /// Preselect the target language? | ||||
|     /// </summary> | ||||
|     public CommonLanguages PreselectedTargetLanguage { get; set; } | ||||
|      | ||||
|     /// <summary> | ||||
|     /// Preselect any other language? | ||||
|     /// </summary> | ||||
|     public string PreselectOtherLanguage { get; set; } = string.Empty; | ||||
|      | ||||
|     /// <summary> | ||||
|     /// The preselected provider. | ||||
|     /// </summary> | ||||
|     public string PreselectedProvider { get; set; } = string.Empty; | ||||
|      | ||||
|     /// <summary> | ||||
|     /// Preselect a profile? | ||||
|     /// </summary> | ||||
|     public string PreselectedProfile { get; set; } = string.Empty; | ||||
| } | ||||
| @ -129,6 +129,7 @@ public sealed class SettingsManager(ILogger<SettingsManager> logger) | ||||
|             Tools.Components.EMAIL_ASSISTANT => this.ConfigurationData.EMail.PreselectOptions ? this.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.ConfigurationData.EMail.PreselectedProvider) : default, | ||||
|             Tools.Components.LEGAL_CHECK_ASSISTANT => this.ConfigurationData.LegalCheck.PreselectOptions ? this.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.ConfigurationData.LegalCheck.PreselectedProvider) : default, | ||||
|             Tools.Components.SYNONYMS_ASSISTANT => this.ConfigurationData.Synonyms.PreselectOptions ? this.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.ConfigurationData.Synonyms.PreselectedProvider) : default, | ||||
|             Tools.Components.MY_TASKS_ASSISTANT => this.ConfigurationData.MyTasks.PreselectOptions ? this.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.ConfigurationData.MyTasks.PreselectedProvider) : default, | ||||
|              | ||||
|             _ => default, | ||||
|         }; | ||||
| @ -148,6 +149,7 @@ public sealed class SettingsManager(ILogger<SettingsManager> logger) | ||||
|             Tools.Components.CODING_ASSISTANT => this.ConfigurationData.Coding.PreselectOptions ? this.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == this.ConfigurationData.Coding.PreselectedProfile) : default, | ||||
|             Tools.Components.EMAIL_ASSISTANT => this.ConfigurationData.EMail.PreselectOptions ? this.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == this.ConfigurationData.EMail.PreselectedProfile) : default, | ||||
|             Tools.Components.LEGAL_CHECK_ASSISTANT => this.ConfigurationData.LegalCheck.PreselectOptions ? this.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == this.ConfigurationData.LegalCheck.PreselectedProfile) : default, | ||||
|             Tools.Components.MY_TASKS_ASSISTANT => this.ConfigurationData.MyTasks.PreselectOptions ? this.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == this.ConfigurationData.MyTasks.PreselectedProfile) : default, | ||||
| 
 | ||||
|             _ => default, | ||||
|         }; | ||||
|  | ||||
| @ -14,6 +14,7 @@ public enum Components | ||||
|     EMAIL_ASSISTANT, | ||||
|     LEGAL_CHECK_ASSISTANT, | ||||
|     SYNONYMS_ASSISTANT, | ||||
|     MY_TASKS_ASSISTANT, | ||||
|      | ||||
|     CHAT, | ||||
| } | ||||
| @ -28,4 +28,5 @@ public enum Event | ||||
|     SEND_TO_EMAIL_ASSISTANT, | ||||
|     SEND_TO_LEGAL_CHECK_ASSISTANT, | ||||
|     SEND_TO_SYNONYMS_ASSISTANT, | ||||
|     SEND_TO_MY_TASKS_ASSISTANT, | ||||
| } | ||||
| @ -14,6 +14,7 @@ public static class SendToExtensions | ||||
|         Components.EMAIL_ASSISTANT => "E-Mail Assistant", | ||||
|         Components.LEGAL_CHECK_ASSISTANT => "Legal Check Assistant", | ||||
|         Components.SYNONYMS_ASSISTANT => "Synonym Assistant", | ||||
|         Components.MY_TASKS_ASSISTANT => "My Tasks Assistant", | ||||
|          | ||||
|         Components.CHAT => "New Chat", | ||||
|          | ||||
| @ -32,6 +33,7 @@ public static class SendToExtensions | ||||
|         Components.TEXT_SUMMARIZER_ASSISTANT => new(Event.SEND_TO_TEXT_SUMMARIZER_ASSISTANT, Routes.ASSISTANT_SUMMARIZER), | ||||
|         Components.LEGAL_CHECK_ASSISTANT => new(Event.SEND_TO_LEGAL_CHECK_ASSISTANT, Routes.ASSISTANT_LEGAL_CHECK), | ||||
|         Components.SYNONYMS_ASSISTANT => new(Event.SEND_TO_SYNONYMS_ASSISTANT, Routes.ASSISTANT_SYNONYMS), | ||||
|         Components.MY_TASKS_ASSISTANT => new(Event.SEND_TO_MY_TASKS_ASSISTANT, Routes.ASSISTANT_MY_TASKS), | ||||
|          | ||||
|         Components.CHAT => new(Event.SEND_TO_CHAT, Routes.CHAT), | ||||
|          | ||||
|  | ||||
							
								
								
									
										2
									
								
								app/MindWork AI Studio/wwwroot/changelog/v0.9.8.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								app/MindWork AI Studio/wwwroot/changelog/v0.9.8.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| # v0.9.8, build 183 (2024-09-09 13:00 UTC) | ||||
| - Added the "my tasks" assistant to analyze, e.g., business emails and extract related tasks for your role. | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user