Skip to content

Commit

Permalink
Add ERI server assistant (#231)
Browse files Browse the repository at this point in the history
  • Loading branch information
SommerEngineering authored Jan 1, 2025
1 parent cdf717a commit 8cbef49
Show file tree
Hide file tree
Showing 76 changed files with 3,581 additions and 153 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Things we are currently working on:
- [x] ~~App: Metadata for providers (which provider offers embeddings?) (PR [#205](https://github.com/MindWorkAI/AI-Studio/pull/205))~~
- [x] ~~App: Add an option to show preview features (PR [#222](https://github.com/MindWorkAI/AI-Studio/pull/222))~~
- [x] ~~App: Configure embedding providers (PR [#224](https://github.com/MindWorkAI/AI-Studio/pull/224))~~
- [x] ~~App: Implement an [ERI](https://github.com/MindWorkAI/ERI) server coding assistant (PR [#231](https://github.com/MindWorkAI/AI-Studio/pull/231))~~
- [ ] App: Management of data sources (local & external data via [ERI](https://github.com/MindWorkAI/ERI))
- [ ] Runtime: Extract data from txt / md / pdf / docx / xlsx files
- [ ] (*Optional*) Runtime: Implement internal embedding provider through [fastembed-rs](https://github.com/Anush008/fastembed-rs)
Expand Down
2 changes: 2 additions & 0 deletions app/MindWork AI Studio.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=AI/@EntryIndexedValue">AI</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=EDI/@EntryIndexedValue">EDI</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=ERI/@EntryIndexedValue">ERI</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=LLM/@EntryIndexedValue">LLM</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=LM/@EntryIndexedValue">LM</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MSG/@EntryIndexedValue">MSG</s:String>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ the logistical challenges that come with an increasing number of participants.
SystemPrompt = SystemPrompts.DEFAULT,
};

protected override void ResetFrom()
protected override void ResetForm()
{
this.inputContent = string.Empty;
this.contentLines.Clear();
Expand Down
15 changes: 13 additions & 2 deletions app/MindWork AI Studio/Assistants/AssistantBase.razor
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<InnerScrolling HeaderHeight="6em">
<ChildContent>
<MudForm @ref="@(this.form)" @bind-IsValid="@(this.inputIsValid)" @bind-Errors="@(this.inputIssues)" Class="pr-2">
<MudForm @ref="@(this.form)" @bind-IsValid="@(this.inputIsValid)" @bind-Errors="@(this.inputIssues)" FieldChanged="@this.TriggerFormChange" Class="pr-2">
<MudText Typo="Typo.body1" Align="Align.Justify" Class="mb-6">
@this.Description
</MudText>
Expand Down Expand Up @@ -35,11 +35,22 @@
<div id="@BEFORE_RESULT_DIV_ID" class="mt-3">
</div>

@if (this.ShowResult && this.resultingContentBlock is not null)
@if (this.ShowResult && !this.ShowEntireChatThread && this.resultingContentBlock is not null)
{
<ContentBlockComponent Role="@(this.resultingContentBlock.Role)" Type="@(this.resultingContentBlock.ContentType)" Time="@(this.resultingContentBlock.Time)" Content="@(this.resultingContentBlock.Content)"/>
}

@if(this.ShowResult && this.ShowEntireChatThread && this.chatThread is not null)
{
foreach (var block in this.chatThread.Blocks.OrderBy(n => n.Time))
{
@if (!block.HideFromUser)
{
<ContentBlockComponent Role="@block.Role" Type="@block.ContentType" Time="@block.Time" Content="@block.Content"/>
}
}
}

<div id="@AFTER_RESULT_DIV_ID" class="mt-3">
</div>
</ChildContent>
Expand Down
52 changes: 48 additions & 4 deletions app/MindWork AI Studio/Assistants/AssistantBase.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

using Microsoft.AspNetCore.Components;

using MudBlazor.Utilities;

using RustService = AIStudio.Tools.RustService;
using Timer = System.Timers.Timer;

namespace AIStudio.Assistants;

Expand Down Expand Up @@ -55,7 +58,7 @@ public abstract partial class AssistantBase : ComponentBase, IMessageBusReceiver
_ => string.Empty,
};

protected abstract void ResetFrom();
protected abstract void ResetForm();

protected abstract bool MightPreselectValues();

Expand All @@ -68,6 +71,8 @@ public abstract partial class AssistantBase : ComponentBase, IMessageBusReceiver
private protected virtual RenderFragment? Body => null;

protected virtual bool ShowResult => true;

protected virtual bool ShowEntireChatThread => false;

protected virtual bool AllowProfiles => true;

Expand All @@ -91,8 +96,10 @@ public abstract partial class AssistantBase : ComponentBase, IMessageBusReceiver
protected MudForm? form;
protected bool inputIsValid;
protected Profile currentProfile = Profile.NO_PROFILE;

protected ChatThread? chatThread;

private readonly Timer formChangeTimer = new(TimeSpan.FromSeconds(1.6));

private ContentBlock? resultingContentBlock;
private string[] inputIssues = [];
private bool isProcessing;
Expand All @@ -101,6 +108,13 @@ public abstract partial class AssistantBase : ComponentBase, IMessageBusReceiver

protected override async Task OnInitializedAsync()
{
this.formChangeTimer.AutoReset = false;
this.formChangeTimer.Elapsed += async (_, _) =>
{
this.formChangeTimer.Stop();
await this.OnFormChange();
};

this.MightPreselectValues();
this.providerSettings = this.SettingsManager.GetPreselectedProvider(this.Component);
this.currentProfile = this.SettingsManager.GetPreselectedProfile(this.Component);
Expand Down Expand Up @@ -161,7 +175,35 @@ public Task ProcessMessage<T>(ComponentBase? sendingComponent, Event triggeredEv

return null;
}

private void TriggerFormChange(FormFieldChangedEventArgs _)
{
this.formChangeTimer.Stop();
this.formChangeTimer.Start();
}

/// <summary>
/// This method is called after any form field has changed.
/// </summary>
/// <remarks>
/// This method is called after a delay of 1.6 seconds. This is to prevent
/// the method from being called too often. This method is called after
/// the user has stopped typing or selecting options.
/// </remarks>
protected virtual Task OnFormChange() => Task.CompletedTask;

/// <summary>
/// Add an issue to the UI.
/// </summary>
/// <param name="issue">The issue to add.</param>
protected void AddInputIssue(string issue)
{
Array.Resize(ref this.inputIssues, this.inputIssues.Length + 1);
this.inputIssues[^1] = issue;
this.inputIsValid = false;
this.StateHasChanged();
}

protected void CreateChatThread()
{
this.chatThread = new()
Expand Down Expand Up @@ -221,7 +263,7 @@ protected DateTimeOffset AddUserRequest(string request, bool hideContentFromUser
return time;
}

protected async Task<string> AddAIResponseAsync(DateTimeOffset time)
protected async Task<string> AddAIResponseAsync(DateTimeOffset time, bool hideContentFromUser = false)
{
var aiText = new ContentText
{
Expand All @@ -236,6 +278,7 @@ protected async Task<string> AddAIResponseAsync(DateTimeOffset time)
ContentType = ContentType.TEXT,
Role = ChatRole.AI,
Content = aiText,
HideFromUser = hideContentFromUser,
};

if (this.chatThread is not null)
Expand Down Expand Up @@ -313,7 +356,7 @@ private async Task InnerResetForm()
await this.JsRuntime.ClearDiv(RESULT_DIV_ID);
await this.JsRuntime.ClearDiv(AFTER_RESULT_DIV_ID);

this.ResetFrom();
this.ResetForm();
this.providerSettings = this.SettingsManager.GetPreselectedProvider(this.Component);

this.inputIsValid = false;
Expand Down Expand Up @@ -341,6 +384,7 @@ private async Task InnerResetForm()
public void Dispose()
{
this.MessageBus.Unregister(this);
this.formChangeTimer.Dispose();
}

#endregion
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Text;

using AIStudio.Components;
using AIStudio.Chat;
using AIStudio.Settings.DataModel;

namespace AIStudio.Assistants.BiasDay;
Expand Down Expand Up @@ -50,7 +50,7 @@ this bias.

protected override bool ShowReset => false;

protected override void ResetFrom()
protected override void ResetForm()
{
if (!this.MightPreselectValues())
{
Expand Down Expand Up @@ -124,7 +124,7 @@ private async Task TellBias()
{
var biasChat = new LoadChat
{
WorkspaceId = Workspaces.WORKSPACE_ID_BIAS,
WorkspaceId = KnownWorkspaces.BIAS_WORKSPACE_ID,
ChatId = this.SettingsManager.ConfigurationData.BiasOfTheDay.BiasOfTheDayChatId,
};

Expand All @@ -147,7 +147,7 @@ private async Task TellBias()
BiasCatalog.ALL_BIAS[this.SettingsManager.ConfigurationData.BiasOfTheDay.BiasOfTheDayId] :
BiasCatalog.GetRandomBias(this.SettingsManager.ConfigurationData.BiasOfTheDay.UsedBias);

var chatId = this.CreateChatThread(Workspaces.WORKSPACE_ID_BIAS, this.biasOfTheDay.Name);
var chatId = this.CreateChatThread(KnownWorkspaces.BIAS_WORKSPACE_ID, this.biasOfTheDay.Name);
this.SettingsManager.ConfigurationData.BiasOfTheDay.BiasOfTheDayId = this.biasOfTheDay.Id;
this.SettingsManager.ConfigurationData.BiasOfTheDay.BiasOfTheDayChatId = chatId;
this.SettingsManager.ConfigurationData.BiasOfTheDay.DateLastBiasDrawn = DateOnly.FromDateTime(DateTime.Now);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ messages. You can also help with code refactoring and optimization.

protected override Func<Task> SubmitAction => this.GetSupport;

protected override void ResetFrom()
protected override void ResetForm()
{
this.codingContexts.Clear();
this.compilerMessages = string.Empty;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<MudTextField T="string" @bind-Text="@this.CodingContext.Id" AdornmentIcon="@Icons.Material.Filled.Numbers" Adornment="Adornment.Start" Label="(Optional) Identifier" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<MudStack Row="@true" AlignItems="AlignItems.Center" Class="mb-3">
<MudStack Row="@true" Class="mb-3">
<MudSelect T="CommonCodingLanguages" @bind-Value="@this.CodingContext.Language" AdornmentIcon="@Icons.Material.Filled.Code" Adornment="Adornment.Start" Label="Language" Variant="Variant.Outlined" Margin="Margin.Dense">
@foreach (var language in Enum.GetValues<CommonCodingLanguages>())
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public partial class AssistantEMail : AssistantBaseCore
SystemPrompt = SystemPrompts.DEFAULT,
};

protected override void ResetFrom()
protected override void ResetForm()
{
this.inputBulletPoints = string.Empty;
this.bulletPointsLines.Clear();
Expand Down
9 changes: 9 additions & 0 deletions app/MindWork AI Studio/Assistants/ERI/AllowedLLMProviders.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace AIStudio.Assistants.ERI;

public enum AllowedLLMProviders
{
NONE,

ANY,
SELF_HOSTED,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace AIStudio.Assistants.ERI;

public static class AllowedLLMProvidersExtensions
{
public static string Description(this AllowedLLMProviders provider)
{
return provider switch
{
AllowedLLMProviders.NONE => "Please select what kind of LLM provider are allowed for this data source",
AllowedLLMProviders.ANY => "Any LLM provider is allowed: users might choose a cloud-based or a self-hosted provider",
AllowedLLMProviders.SELF_HOSTED => "Self-hosted LLM providers are allowed: users cannot choose any cloud-based provider",

_ => "Unknown option was selected"
};
}
}
Loading

0 comments on commit 8cbef49

Please sign in to comment.