Skip to content

Commit

Permalink
Implemented the "my tasks" assistant (#137)
Browse files Browse the repository at this point in the history
  • Loading branch information
SommerEngineering authored Sep 9, 2024
1 parent 7a5f2d4 commit 09f5b83
Show file tree
Hide file tree
Showing 16 changed files with 224 additions and 2 deletions.
2 changes: 1 addition & 1 deletion app/MindWork AI Studio/Assistants/AssistantBase.razor
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
Reset
</MudButton>

@if (this.AllowProfiles)
@if (this.AllowProfiles && this.ShowProfileSelection)
{
<ProfileSelection MarginLeft="" @bind-CurrentProfile="@this.currentProfile"/>
}
Expand Down
4 changes: 3 additions & 1 deletion app/MindWork AI Studio/Assistants/AssistantBase.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ public abstract partial class AssistantBase : ComponentBase
protected virtual bool ShowResult => true;

protected virtual bool AllowProfiles => true;

protected virtual bool ShowProfileSelection => true;

protected virtual bool ShowDedicatedProgress => false;

Expand All @@ -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

Expand Down
11 changes: 11 additions & 0 deletions app/MindWork AI Studio/Assistants/MyTasks/AssistantMyTasks.razor
Original file line number Diff line number Diff line change
@@ -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>
119 changes: 119 additions & 0 deletions app/MindWork AI Studio/Assistants/MyTasks/AssistantMyTasks.razor.cs
Original file line number Diff line number Diff line change
@@ -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 changes: 10 additions & 0 deletions app/MindWork AI Studio/Components/ProfileFormSelection.razor
Original file line number Diff line number Diff line change
@@ -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>
26 changes: 26 additions & 0 deletions app/MindWork AI Studio/Components/ProfileFormSelection.razor.cs
Original file line number Diff line number Diff line change
@@ -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);
}
}
1 change: 1 addition & 0 deletions app/MindWork AI Studio/Pages/Assistants.razor
Original file line number Diff line number Diff line change
Expand Up @@ -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"/>
Expand Down
13 changes: 13 additions & 0 deletions app/MindWork AI Studio/Pages/Settings.razor
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,19 @@
<ConfigurationProviderSelection Data="@this.availableProviders" Disabled="@(() => !this.SettingsManager.ConfigurationData.Synonyms.PreselectOptions)" SelectedValue="@(() => this.SettingsManager.ConfigurationData.Synonyms.PreselectedProvider)" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.Synonyms.PreselectedProvider = selectedValue)"/>
</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">
Expand Down
1 change: 1 addition & 0 deletions app/MindWork AI Studio/Routes.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
2 changes: 2 additions & 0 deletions app/MindWork AI Studio/Settings/DataModel/Data.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 29 additions & 0 deletions app/MindWork AI Studio/Settings/DataModel/DataMyTasks.cs
Original file line number Diff line number Diff line change
@@ -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;
}
2 changes: 2 additions & 0 deletions app/MindWork AI Studio/Settings/SettingsManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ public Provider GetPreselectedProvider(Tools.Components component)
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,
};
Expand All @@ -148,6 +149,7 @@ public Profile GetPreselectedProfile(Tools.Components component)
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,
};
Expand Down
1 change: 1 addition & 0 deletions app/MindWork AI Studio/Tools/Components.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public enum Components
EMAIL_ASSISTANT,
LEGAL_CHECK_ASSISTANT,
SYNONYMS_ASSISTANT,
MY_TASKS_ASSISTANT,

CHAT,
}
1 change: 1 addition & 0 deletions app/MindWork AI Studio/Tools/Event.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
2 changes: 2 additions & 0 deletions app/MindWork AI Studio/Tools/SendToExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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",

Expand All @@ -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),

Expand Down
2 changes: 2 additions & 0 deletions app/MindWork AI Studio/wwwroot/changelog/v0.9.8.md
Original file line number Diff line number Diff line change
@@ -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.

0 comments on commit 09f5b83

Please sign in to comment.