Skip to content

Commit

Permalink
Add assistants (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
SommerEngineering authored Jul 14, 2024
1 parent 88aefe1 commit 58c9d8a
Show file tree
Hide file tree
Showing 33 changed files with 778 additions and 12 deletions.
2 changes: 1 addition & 1 deletion app/MindWork AI Studio/Chat/ContentBlockComponent.razor
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@using AIStudio.Tools
@using MudBlazor

<MudCard Class="my-2 rounded-lg" Outlined="@true">
<MudCard Class="@this.CardClasses" Outlined="@true">
<MudCardHeader>
<CardHeaderAvatar>
<MudAvatar Color="@this.Role.ToColor()">
Expand Down
8 changes: 8 additions & 0 deletions app/MindWork AI Studio/Chat/ContentBlockComponent.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ public partial class ContentBlockComponent : ComponentBase
[Parameter]
public DateTimeOffset Time { get; init; }

/// <summary>
/// Optional CSS classes.
/// </summary>
[Parameter]
public string Class { get; set; } = string.Empty;

[Inject]
private Rust Rust { get; init; } = null!;

Expand Down Expand Up @@ -107,4 +113,6 @@ private async Task CopyToClipboard()
break;
}
}

private string CardClasses => $"my-2 rounded-lg {this.Class}";
}
39 changes: 39 additions & 0 deletions app/MindWork AI Studio/Components/AssistantBase.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
@using AIStudio.Chat
<MudText Typo="Typo.h3" Class="mb-2 mr-3">
@this.Title
</MudText>

<InnerScrolling HeaderHeight="12.3em">
<ChildContent>
<MudForm @ref="@this.form" @bind-IsValid="@this.inputIsValid" @bind-Errors="@this.inputIssues" Class="pr-2">
<MudText Typo="Typo.body1" Align="Align.Justify" Class="mb-6">
@this.Description
</MudText>

@if (this.Body is not null)
{
@this.Body
}
</MudForm>

@if (this.inputIssues.Any())
{
<MudPaper Class="pr-2 mt-3" Outlined="@true">
<MudText Typo="Typo.h6">Issues</MudText>
<MudList Clickable="@true">
@foreach (var issue in this.inputIssues)
{
<MudListItem Icon="@Icons.Material.Filled.Error" IconColor="Color.Error">
@issue
</MudListItem>
}
</MudList>
</MudPaper>
}

@if (this.resultingContentBlock is not null)
{
<ContentBlockComponent Role="@this.resultingContentBlock.Role" Type="@this.resultingContentBlock.ContentType" Time="@this.resultingContentBlock.Time" Content="@this.resultingContentBlock.Content" Class="mr-2"/>
}
</ChildContent>
</InnerScrolling>
104 changes: 104 additions & 0 deletions app/MindWork AI Studio/Components/AssistantBase.razor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
using AIStudio.Chat;
using AIStudio.Provider;
using AIStudio.Settings;

using Microsoft.AspNetCore.Components;

namespace AIStudio.Components;

public abstract partial class AssistantBase : ComponentBase
{
[Inject]
protected SettingsManager SettingsManager { get; set; } = null!;

[Inject]
protected IJSRuntime JsRuntime { get; init; } = null!;

[Inject]
protected Random RNG { get; set; } = null!;

protected abstract string Title { get; }

protected abstract string Description { get; }

protected abstract string SystemPrompt { get; }

private protected virtual RenderFragment? Body => null;

protected AIStudio.Settings.Provider selectedProvider;
protected MudForm? form;
protected bool inputIsValid;

private ChatThread? chatThread;
private ContentBlock? resultingContentBlock;
private string[] inputIssues = [];

#region Overrides of ComponentBase

protected override async Task OnAfterRenderAsync(bool firstRender)
{
// Reset the validation when not editing and on the first render.
// We don't want to show validation errors when the user opens the dialog.
if(firstRender)
this.form?.ResetValidation();

await base.OnAfterRenderAsync(firstRender);
}

#endregion

protected void CreateChatThread()
{
this.chatThread = new()
{
WorkspaceId = Guid.Empty,
ChatId = Guid.NewGuid(),
Name = string.Empty,
Seed = this.RNG.Next(),
SystemPrompt = this.SystemPrompt,
Blocks = [],
};
}

protected DateTimeOffset AddUserRequest(string request)
{
var time = DateTimeOffset.Now;
this.chatThread!.Blocks.Add(new ContentBlock
{
Time = time,
ContentType = ContentType.TEXT,
Role = ChatRole.USER,
Content = new ContentText
{
Text = request,
},
});

return time;
}

protected async Task AddAIResponseAsync(DateTimeOffset time)
{
var aiText = new ContentText
{
// We have to wait for the remote
// for the content stream:
InitialRemoteWait = true,
};

this.resultingContentBlock = new ContentBlock
{
Time = time,
ContentType = ContentType.TEXT,
Role = ChatRole.AI,
Content = aiText,
};

this.chatThread?.Blocks.Add(this.resultingContentBlock);

// Use the selected provider to get the AI response.
// By awaiting this line, we wait for the entire
// content to be streamed.
await aiText.CreateFromProviderAsync(this.selectedProvider.UsedProvider.CreateProvider(this.selectedProvider.InstanceName, this.selectedProvider.Hostname), this.JsRuntime, this.SettingsManager, this.selectedProvider.Model, this.chatThread);
}
}
19 changes: 19 additions & 0 deletions app/MindWork AI Studio/Components/AssistantBaseCore.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;

namespace AIStudio.Components;

//
// See https://stackoverflow.com/a/77300384/2258393 for why this class is needed
//

public abstract class AssistantBaseCore : AssistantBase
{
private protected sealed override RenderFragment Body => this.BuildRenderTree;

// Allow content to be provided by a .razor file but without
// overriding the content of the base class
protected new virtual void BuildRenderTree(RenderTreeBuilder builder)
{
}
}
26 changes: 26 additions & 0 deletions app/MindWork AI Studio/Components/Blocks/AssistantBlock.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<MudItem xs="3">
<MudCard Outlined="@true" Style="border-width: 2px; border-color: #0d47a1; border-radius: 12px; border-style: solid;">
<MudCardHeader>
<CardHeaderContent>
<MudStack AlignItems="AlignItems.Center" Row="@true">
<MudIcon Icon="@this.Icon" Size="Size.Large" Color="Color.Primary"/>
<MudText Typo="Typo.h6">
@this.Name
</MudText>
</MudStack>
</CardHeaderContent>
</MudCardHeader>
<MudCardContent>
<MudStack>
<MudText>
@this.Description
</MudText>
</MudStack>
</MudCardContent>
<MudCardActions>
<MudButton Size="Size.Large" Variant="Variant.Filled" StartIcon="@this.Icon" Color="Color.Default" Href="@this.Link">
@this.ButtonText
</MudButton>
</MudCardActions>
</MudCard>
</MudItem>
21 changes: 21 additions & 0 deletions app/MindWork AI Studio/Components/Blocks/AssistantBlock.razor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Microsoft.AspNetCore.Components;

namespace AIStudio.Components.Blocks;

public partial class AssistantBlock : ComponentBase
{
[Parameter]
public string Name { get; set; } = string.Empty;

[Parameter]
public string Description { get; set; } = string.Empty;

[Parameter]
public string Icon { get; set; } = Icons.Material.Filled.DisabledByDefault;

[Parameter]
public string ButtonText { get; set; } = "Start";

[Parameter]
public string Link { get; set; } = string.Empty;
}
3 changes: 2 additions & 1 deletion app/MindWork AI Studio/Components/Blocks/Changelog.Logs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ public readonly record struct Log(int Build, string Display, string Filename)

public static readonly Log[] LOGS =
[
new (161, "v0.7.1, build 161 (2024-07-13 12:44 UTC)", "v0.7.1.md"),
new (162, "v0.8.0, build 162 (2024-07-14 19:39 UTC)", "v0.8.0.md"),
new (161, "v0.7.1, build 161 (2024-07-13 11:42 UTC)", "v0.7.1.md"),
new (160, "v0.7.0, build 160 (2024-07-13 08:21 UTC)", "v0.7.0.md"),
new (159, "v0.6.3, build 159 (2024-07-03 18:26 UTC)", "v0.6.3.md"),
new (158, "v0.6.2, build 158 (2024-07-01 18:03 UTC)", "v0.6.2.md"),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@inherits AIStudio.Tools.MSGComponentBase
@inherits MSGComponentBase

<div class="d-flex flex-column" style="@this.Height">
<div class="flex-auto overflow-auto">
Expand Down
3 changes: 3 additions & 0 deletions app/MindWork AI Studio/Components/Layout/MainLayout.razor
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
<MudTooltip Text="Chat" Placement="Placement.Right">
<MudNavLink Href="/chat" Icon="@Icons.Material.Filled.Chat">Chat</MudNavLink>
</MudTooltip>
<MudTooltip Text="Assistants" Placement="Placement.Right">
<MudNavLink Href="/assistants" Icon="@Icons.Material.Filled.Apps">Assistants</MudNavLink>
</MudTooltip>
<MudTooltip Text="Supporters" Placement="Placement.Right">
<MudNavLink Href="/supporters" Icon="@Icons.Material.Filled.Favorite" IconColor="Color.Error">Supporters</MudNavLink>
</MudTooltip>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using AIStudio.Tools;

using Microsoft.AspNetCore.Components;

namespace AIStudio.Tools;
namespace AIStudio.Components;

public abstract class MSGComponentBase : ComponentBase, IDisposable, IMessageBusReceiver
{
Expand Down
11 changes: 11 additions & 0 deletions app/MindWork AI Studio/Components/Pages/Assistants.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@page "/assistants"

<MudText Typo="Typo.h3" Class="mb-2 mr-3">
Assistants
</MudText>

<MudGrid>
<AssistantBlock Name="Icon Finder" Description="Using a LLM to find an icon for a given context." Icon="@Icons.Material.Filled.FindInPage" Link="/assistant/icons"/>
<AssistantBlock Name="Text Summarizer" Description="Using a LLM to summarize a given text." Icon="@Icons.Material.Filled.TextSnippet" Link="/assistant/summarizer"/>
<AssistantBlock Name="Translator" Description="Translate text into another language." Icon="@Icons.Material.Filled.Translate" Link="/assistant/translator"/>
</MudGrid>
5 changes: 5 additions & 0 deletions app/MindWork AI Studio/Components/Pages/Assistants.razor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using Microsoft.AspNetCore.Components;

namespace AIStudio.Components.Pages;

public partial class Assistants : ComponentBase;
2 changes: 1 addition & 1 deletion app/MindWork AI Studio/Components/Pages/Chat.razor
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
@using AIStudio.Chat
@using AIStudio.Settings

@inherits AIStudio.Tools.MSGComponentBase
@inherits MSGComponentBase

<MudText Typo="Typo.h3" Class="mb-2 mr-3">
@if (this.chatThread is not null && this.chatThread.WorkspaceId != Guid.Empty)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
@page "/assistant/icons"
@using AIStudio.Settings
@inherits AssistantBaseCore

<MudTextField T="string" @bind-Text="@this.inputContext" Validation="@this.ValidatingContext" AdornmentIcon="@Icons.Material.Filled.Description" Adornment="Adornment.Start" Label="Your context" Variant="Variant.Outlined" Lines="3" AutoGrow="@true" MaxLines="12" Class="mb-3"/>

<MudStack Row="@true" AlignItems="AlignItems.Center" Class="mb-3">
<MudSelect T="IconSources" @bind-Value="@this.selectedIconSource" AdornmentIcon="@Icons.Material.Filled.Source" Adornment="Adornment.Start" Label="Your icon source" Variant="Variant.Outlined" Margin="Margin.Dense">
@foreach (var source in Enum.GetValues<IconSources>())
{
<MudSelectItem Value="@source">@source.Name()</MudSelectItem>
}
</MudSelect>
@if (this.selectedIconSource is not IconSources.GENERIC)
{
<MudButton Href="@this.selectedIconSource.URL()" Target="_blank" Variant="Variant.Filled" Size="Size.Medium">Open website</MudButton>
}
</MudStack>

<MudSelect T="Provider" @bind-Value="@this.selectedProvider" Validation="@this.ValidatingProvider" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Apps" Margin="Margin.Dense" Label="Provider" Class="mb-3 rounded-lg" Variant="Variant.Outlined">
@foreach (var provider in this.SettingsManager.ConfigurationData.Providers)
{
<MudSelectItem Value="@provider"/>
}
</MudSelect>

<MudButton Variant="Variant.Filled" Class="mb-3" OnClick="() => this.FindIcon()">
Find icon
</MudButton>
Loading

0 comments on commit 58c9d8a

Please sign in to comment.