mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-21 00:18:00 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50bf0baff7 | ||
|
|
83fe126c9f | ||
|
|
37b38e6a40 | ||
|
|
1d1af91f3e | ||
|
|
a18cb22263 | ||
|
|
f8e06faea5 | ||
|
|
8aeeda5dca | ||
|
|
909fbe89bb | ||
|
|
ea0ead58f8 | ||
|
|
3e59f23193 | ||
|
|
05a7e44de4 | ||
|
|
77e7e044e3 |
No files matched your search
@@ -1,5 +1,6 @@
|
|||||||
# MindWork AI Studio
|
# MindWork AI Studio
|
||||||

|

|
||||||
|

|
||||||
|
|
||||||
MindWork AI Studio is a desktop application available for macOS, Windows, and Linux. It provides a unified chat interface for Large Language Models (LLMs). You bring your own API key for the respective LLM provider to use the models. The API keys are securely stored by the operating system.
|
MindWork AI Studio is a desktop application available for macOS, Windows, and Linux. It provides a unified chat interface for Large Language Models (LLMs). You bring your own API key for the respective LLM provider to use the models. The API keys are securely stored by the operating system.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
@using Microsoft.AspNetCore.Components.Web
|
||||||
|
|
||||||
|
@* ReSharper disable Html.PathError *@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>MindWork AI Studio</title>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
|
<base href="/"/>
|
||||||
|
|
||||||
|
<link rel="icon" type="image/png" href="favicon.png"/>
|
||||||
|
<link href="system/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
|
||||||
|
<link href="system/MudBlazor.Markdown/MudBlazor.Markdown.min.css" rel="stylesheet" />
|
||||||
|
<link href="app.css" rel="stylesheet" />
|
||||||
|
<HeadOutlet/>
|
||||||
|
<script src="diff.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body style="overflow: hidden;">
|
||||||
|
<Routes @rendermode="new InteractiveServerRenderMode(prerender: false)"/>
|
||||||
|
<script src="_framework/blazor.web.js" autostart="false"></script>
|
||||||
|
<script src="boot.js"></script>
|
||||||
|
<script src="system/MudBlazor/MudBlazor.min.js"></script>
|
||||||
|
<script src="system/MudBlazor.Markdown/MudBlazor.Markdown.min.js"></script>
|
||||||
|
<script src="app.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
+1
-2
@@ -1,5 +1,4 @@
|
|||||||
@page "/assistant/agenda"
|
@attribute [Route(Routes.ASSISTANT_AGENDA)]
|
||||||
@using AIStudio.Tools
|
|
||||||
@inherits AssistantBaseCore
|
@inherits AssistantBaseCore
|
||||||
|
|
||||||
<MudTextField T="string" @bind-Text="@this.inputName" Validation="@this.ValidateName" Label="Meeting Name" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Tag" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="Name the meeting, seminar, etc." Placeholder="Weekly jour fixe" Class="mb-3"/>
|
<MudTextField T="string" @bind-Text="@this.inputName" Validation="@this.ValidateName" Label="Meeting Name" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Tag" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="Name the meeting, seminar, etc." Placeholder="Weekly jour fixe" Class="mb-3"/>
|
||||||
+78
-23
@@ -1,8 +1,9 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
using AIStudio.Chat;
|
||||||
using AIStudio.Tools;
|
using AIStudio.Tools;
|
||||||
|
|
||||||
namespace AIStudio.Components.Pages.Agenda;
|
namespace AIStudio.Assistants.Agenda;
|
||||||
|
|
||||||
public partial class AssistantAgenda : AssistantBaseCore
|
public partial class AssistantAgenda : AssistantBaseCore
|
||||||
{
|
{
|
||||||
@@ -93,6 +94,78 @@ public partial class AssistantAgenda : AssistantBaseCore
|
|||||||
- Mary Jane: Work package 3
|
- Mary Jane: Work package 3
|
||||||
""";
|
""";
|
||||||
|
|
||||||
|
protected override IReadOnlyList<IButtonData> FooterButtons =>
|
||||||
|
[
|
||||||
|
new SendToButton
|
||||||
|
{
|
||||||
|
Self = SendTo.AGENDA_ASSISTANT,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
protected override ChatThread ConvertToChatThread => (this.chatThread ?? new()) with
|
||||||
|
{
|
||||||
|
SystemPrompt = SystemPrompts.DEFAULT,
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override void ResetFrom()
|
||||||
|
{
|
||||||
|
this.inputContent = string.Empty;
|
||||||
|
this.contentLines.Clear();
|
||||||
|
this.selectedFoci = [];
|
||||||
|
this.justBriefly = [];
|
||||||
|
this.inputWhoIsPresenting = string.Empty;
|
||||||
|
if (!this.MightPreselectValues())
|
||||||
|
{
|
||||||
|
this.inputTopic = string.Empty;
|
||||||
|
this.inputName = string.Empty;
|
||||||
|
this.inputDuration = string.Empty;
|
||||||
|
this.inputStartTime = string.Empty;
|
||||||
|
this.inputObjective = string.Empty;
|
||||||
|
this.inputModerator = string.Empty;
|
||||||
|
this.selectedTargetLanguage = CommonLanguages.AS_IS;
|
||||||
|
this.customTargetLanguage = string.Empty;
|
||||||
|
this.introduceParticipants = false;
|
||||||
|
this.isMeetingVirtual = true;
|
||||||
|
this.inputLocation = string.Empty;
|
||||||
|
this.goingToDinner = false;
|
||||||
|
this.doingSocialActivity = false;
|
||||||
|
this.needToArriveAndDepart = false;
|
||||||
|
this.durationLunchBreak = 0;
|
||||||
|
this.durationBreaks = 0;
|
||||||
|
this.activeParticipation = false;
|
||||||
|
this.numberParticipants = NumberParticipants.NOT_SPECIFIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool MightPreselectValues()
|
||||||
|
{
|
||||||
|
if (this.SettingsManager.ConfigurationData.Agenda.PreselectOptions)
|
||||||
|
{
|
||||||
|
this.inputTopic = this.SettingsManager.ConfigurationData.Agenda.PreselectTopic;
|
||||||
|
this.inputName = this.SettingsManager.ConfigurationData.Agenda.PreselectName;
|
||||||
|
this.inputDuration = this.SettingsManager.ConfigurationData.Agenda.PreselectDuration;
|
||||||
|
this.inputStartTime = this.SettingsManager.ConfigurationData.Agenda.PreselectStartTime;
|
||||||
|
this.inputObjective = this.SettingsManager.ConfigurationData.Agenda.PreselectObjective;
|
||||||
|
this.inputModerator = this.SettingsManager.ConfigurationData.Agenda.PreselectModerator;
|
||||||
|
this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.Agenda.PreselectedTargetLanguage;
|
||||||
|
this.customTargetLanguage = this.SettingsManager.ConfigurationData.Agenda.PreselectedOtherLanguage;
|
||||||
|
this.introduceParticipants = this.SettingsManager.ConfigurationData.Agenda.PreselectIntroduceParticipants;
|
||||||
|
this.isMeetingVirtual = this.SettingsManager.ConfigurationData.Agenda.PreselectIsMeetingVirtual;
|
||||||
|
this.inputLocation = this.SettingsManager.ConfigurationData.Agenda.PreselectLocation;
|
||||||
|
this.goingToDinner = this.SettingsManager.ConfigurationData.Agenda.PreselectJointDinner;
|
||||||
|
this.doingSocialActivity = this.SettingsManager.ConfigurationData.Agenda.PreselectSocialActivity;
|
||||||
|
this.needToArriveAndDepart = this.SettingsManager.ConfigurationData.Agenda.PreselectArriveAndDepart;
|
||||||
|
this.durationLunchBreak = this.SettingsManager.ConfigurationData.Agenda.PreselectLunchTime;
|
||||||
|
this.durationBreaks = this.SettingsManager.ConfigurationData.Agenda.PreselectBreakTime;
|
||||||
|
this.activeParticipation = this.SettingsManager.ConfigurationData.Agenda.PreselectActiveParticipation;
|
||||||
|
this.numberParticipants = this.SettingsManager.ConfigurationData.Agenda.PreselectNumberParticipants;
|
||||||
|
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.Agenda.PreselectedProvider);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private string inputTopic = string.Empty;
|
private string inputTopic = string.Empty;
|
||||||
private string inputName = string.Empty;
|
private string inputName = string.Empty;
|
||||||
private string inputContent = string.Empty;
|
private string inputContent = string.Empty;
|
||||||
@@ -122,28 +195,10 @@ public partial class AssistantAgenda : AssistantBaseCore
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
if (this.SettingsManager.ConfigurationData.Agenda.PreselectOptions)
|
this.MightPreselectValues();
|
||||||
{
|
var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages<string>(Event.SEND_TO_AGENDA_ASSISTANT).FirstOrDefault();
|
||||||
this.inputTopic = this.SettingsManager.ConfigurationData.Agenda.PreselectTopic;
|
if (deferredContent is not null)
|
||||||
this.inputName = this.SettingsManager.ConfigurationData.Agenda.PreselectName;
|
this.inputContent = deferredContent;
|
||||||
this.inputDuration = this.SettingsManager.ConfigurationData.Agenda.PreselectDuration;
|
|
||||||
this.inputStartTime = this.SettingsManager.ConfigurationData.Agenda.PreselectStartTime;
|
|
||||||
this.inputObjective = this.SettingsManager.ConfigurationData.Agenda.PreselectObjective;
|
|
||||||
this.inputModerator = this.SettingsManager.ConfigurationData.Agenda.PreselectModerator;
|
|
||||||
this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.Agenda.PreselectedTargetLanguage;
|
|
||||||
this.customTargetLanguage = this.SettingsManager.ConfigurationData.Agenda.PreselectedOtherLanguage;
|
|
||||||
this.introduceParticipants = this.SettingsManager.ConfigurationData.Agenda.PreselectIntroduceParticipants;
|
|
||||||
this.isMeetingVirtual = this.SettingsManager.ConfigurationData.Agenda.PreselectIsMeetingVirtual;
|
|
||||||
this.inputLocation = this.SettingsManager.ConfigurationData.Agenda.PreselectLocation;
|
|
||||||
this.goingToDinner = this.SettingsManager.ConfigurationData.Agenda.PreselectJointDinner;
|
|
||||||
this.doingSocialActivity = this.SettingsManager.ConfigurationData.Agenda.PreselectSocialActivity;
|
|
||||||
this.needToArriveAndDepart = this.SettingsManager.ConfigurationData.Agenda.PreselectArriveAndDepart;
|
|
||||||
this.durationLunchBreak = this.SettingsManager.ConfigurationData.Agenda.PreselectLunchTime;
|
|
||||||
this.durationBreaks = this.SettingsManager.ConfigurationData.Agenda.PreselectBreakTime;
|
|
||||||
this.activeParticipation = this.SettingsManager.ConfigurationData.Agenda.PreselectActiveParticipation;
|
|
||||||
this.numberParticipants = this.SettingsManager.ConfigurationData.Agenda.PreselectNumberParticipants;
|
|
||||||
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.Agenda.PreselectedProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
namespace AIStudio.Components.Pages.Agenda;
|
namespace AIStudio.Assistants.Agenda;
|
||||||
|
|
||||||
public enum NumberParticipants
|
public enum NumberParticipants
|
||||||
{
|
{
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
namespace AIStudio.Components.Pages.Agenda;
|
namespace AIStudio.Assistants.Agenda;
|
||||||
|
|
||||||
public static class NumberParticipantsExtensions
|
public static class NumberParticipantsExtensions
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
@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>
|
||||||
|
<Issues IssuesData="@(this.inputIssues)"/>
|
||||||
|
|
||||||
|
@if (this.ShowDedicatedProgress && this.isProcessing)
|
||||||
|
{
|
||||||
|
<MudProgressLinear Color="Color.Primary" Indeterminate="true" Class="mb-6" />
|
||||||
|
}
|
||||||
|
|
||||||
|
<div id="@RESULT_DIV_ID" class="mr-2 mt-3">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if (this.ShowResult && this.resultingContentBlock is not null)
|
||||||
|
{
|
||||||
|
<ContentBlockComponent Role="@(this.resultingContentBlock.Role)" Type="@(this.resultingContentBlock.ContentType)" Time="@(this.resultingContentBlock.Time)" Content="@(this.resultingContentBlock.Content)"/>
|
||||||
|
}
|
||||||
|
|
||||||
|
<div id="@AFTER_RESULT_DIV_ID" class="mt-3">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if (this.FooterButtons.Count > 0)
|
||||||
|
{
|
||||||
|
<MudStack Row="@true" Wrap="Wrap.Wrap" Class="mt-3 mr-2">
|
||||||
|
@foreach (var button in this.FooterButtons)
|
||||||
|
{
|
||||||
|
switch (button)
|
||||||
|
{
|
||||||
|
case ButtonData buttonData when !string.IsNullOrWhiteSpace(buttonData.Tooltip):
|
||||||
|
<MudTooltip Text="@buttonData.Tooltip">
|
||||||
|
<MudButton Variant="Variant.Filled" Color="@buttonData.Color" StartIcon="@GetButtonIcon(buttonData.Icon)" OnClick="async () => await buttonData.AsyncAction()">
|
||||||
|
@buttonData.Text
|
||||||
|
</MudButton>
|
||||||
|
</MudTooltip>
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ButtonData buttonData:
|
||||||
|
<MudButton Variant="Variant.Filled" Color="@buttonData.Color" StartIcon="@GetButtonIcon(buttonData.Icon)" OnClick="async () => await buttonData.AsyncAction()">
|
||||||
|
@buttonData.Text
|
||||||
|
</MudButton>
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SendToButton sendToButton:
|
||||||
|
<MudMenu StartIcon="@Icons.Material.Filled.Apps" EndIcon="@Icons.Material.Filled.KeyboardArrowDown" Label="Send to ..." Variant="Variant.Filled" Color="Color.Info">
|
||||||
|
@foreach (var assistant in Enum.GetValues<SendTo>().OrderBy(n => n.Name().Length))
|
||||||
|
{
|
||||||
|
if(assistant is SendTo.NONE || sendToButton.Self == assistant)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
<MudMenuItem OnClick="() => this.SendToAssistant(assistant, sendToButton)">
|
||||||
|
@assistant.Name()
|
||||||
|
</MudMenuItem>
|
||||||
|
}
|
||||||
|
</MudMenu>
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<MudButton Variant="Variant.Filled" Color="Color.Warning" StartIcon="@Icons.Material.Filled.Refresh" OnClick="() => this.InnerResetForm()">
|
||||||
|
Reset
|
||||||
|
</MudButton>
|
||||||
|
</MudStack>
|
||||||
|
}
|
||||||
|
</ChildContent>
|
||||||
|
</InnerScrolling>
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
using AIStudio.Chat;
|
||||||
|
using AIStudio.Provider;
|
||||||
|
using AIStudio.Settings;
|
||||||
|
using AIStudio.Tools;
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
|
namespace AIStudio.Assistants;
|
||||||
|
|
||||||
|
public abstract partial class AssistantBase : ComponentBase
|
||||||
|
{
|
||||||
|
[Inject]
|
||||||
|
protected SettingsManager SettingsManager { get; set; } = null!;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
protected IJSRuntime JsRuntime { get; init; } = null!;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
protected ThreadSafeRandom RNG { get; init; } = null!;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
protected ISnackbar Snackbar { get; init; } = null!;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
protected Rust Rust { get; init; } = null!;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
protected NavigationManager NavigationManager { get; init; } = null!;
|
||||||
|
|
||||||
|
internal const string AFTER_RESULT_DIV_ID = "afterAssistantResult";
|
||||||
|
internal const string RESULT_DIV_ID = "assistantResult";
|
||||||
|
|
||||||
|
protected abstract string Title { get; }
|
||||||
|
|
||||||
|
protected abstract string Description { get; }
|
||||||
|
|
||||||
|
protected abstract string SystemPrompt { get; }
|
||||||
|
|
||||||
|
protected abstract void ResetFrom();
|
||||||
|
|
||||||
|
protected abstract bool MightPreselectValues();
|
||||||
|
|
||||||
|
private protected virtual RenderFragment? Body => null;
|
||||||
|
|
||||||
|
protected virtual bool ShowResult => true;
|
||||||
|
|
||||||
|
protected virtual bool ShowDedicatedProgress => false;
|
||||||
|
|
||||||
|
protected virtual ChatThread ConvertToChatThread => this.chatThread ?? new();
|
||||||
|
|
||||||
|
protected virtual IReadOnlyList<IButtonData> FooterButtons => [];
|
||||||
|
|
||||||
|
protected static readonly Dictionary<string, object?> USER_INPUT_ATTRIBUTES = new();
|
||||||
|
|
||||||
|
protected AIStudio.Settings.Provider providerSettings;
|
||||||
|
protected MudForm? form;
|
||||||
|
protected bool inputIsValid;
|
||||||
|
|
||||||
|
protected ChatThread? chatThread;
|
||||||
|
private ContentBlock? resultingContentBlock;
|
||||||
|
private string[] inputIssues = [];
|
||||||
|
private bool isProcessing;
|
||||||
|
|
||||||
|
#region Overrides of ComponentBase
|
||||||
|
|
||||||
|
protected override async Task OnParametersSetAsync()
|
||||||
|
{
|
||||||
|
// Configure the spellchecking for the user input:
|
||||||
|
this.SettingsManager.InjectSpellchecking(USER_INPUT_ATTRIBUTES);
|
||||||
|
|
||||||
|
await base.OnParametersSetAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 string? ValidatingProvider(AIStudio.Settings.Provider provider)
|
||||||
|
{
|
||||||
|
if(provider.UsedProvider == Providers.NONE)
|
||||||
|
return "Please select a provider.";
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
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<string> 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);
|
||||||
|
this.isProcessing = true;
|
||||||
|
this.StateHasChanged();
|
||||||
|
|
||||||
|
// 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.providerSettings.CreateProvider(), this.JsRuntime, this.SettingsManager, this.providerSettings.Model, this.chatThread);
|
||||||
|
|
||||||
|
this.isProcessing = false;
|
||||||
|
this.StateHasChanged();
|
||||||
|
|
||||||
|
// Return the AI response:
|
||||||
|
return aiText.Text;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async Task CopyToClipboard(string text)
|
||||||
|
{
|
||||||
|
await this.Rust.CopyText2Clipboard(this.JsRuntime, this.Snackbar, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? GetButtonIcon(string icon)
|
||||||
|
{
|
||||||
|
if(string.IsNullOrWhiteSpace(icon))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task SendToAssistant(SendTo destination, SendToButton sendToButton)
|
||||||
|
{
|
||||||
|
var contentToSend = sendToButton.UseResultingContentBlockData switch
|
||||||
|
{
|
||||||
|
false => sendToButton.GetText(),
|
||||||
|
true => this.resultingContentBlock?.Content switch
|
||||||
|
{
|
||||||
|
ContentText textBlock => textBlock.Text,
|
||||||
|
_ => string.Empty,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var (eventItem, path) = destination switch
|
||||||
|
{
|
||||||
|
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.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),
|
||||||
|
SendTo.TEXT_SUMMARIZER_ASSISTANT => (Event.SEND_TO_TEXT_SUMMARIZER_ASSISTANT, Routes.ASSISTANT_SUMMARIZER),
|
||||||
|
|
||||||
|
SendTo.CHAT => (Event.SEND_TO_CHAT, Routes.CHAT),
|
||||||
|
|
||||||
|
_ => (Event.NONE, Routes.ASSISTANTS),
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (destination)
|
||||||
|
{
|
||||||
|
case SendTo.CHAT:
|
||||||
|
MessageBus.INSTANCE.DeferMessage(this, eventItem, this.ConvertToChatThread);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
MessageBus.INSTANCE.DeferMessage(this, eventItem, contentToSend);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.NavigationManager.NavigateTo(path);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task InnerResetForm()
|
||||||
|
{
|
||||||
|
this.resultingContentBlock = null;
|
||||||
|
this.providerSettings = default;
|
||||||
|
|
||||||
|
await this.JsRuntime.ClearDiv(RESULT_DIV_ID);
|
||||||
|
await this.JsRuntime.ClearDiv(AFTER_RESULT_DIV_ID);
|
||||||
|
|
||||||
|
this.ResetFrom();
|
||||||
|
|
||||||
|
this.inputIsValid = false;
|
||||||
|
this.inputIssues = [];
|
||||||
|
|
||||||
|
this.form?.ResetValidation();
|
||||||
|
this.StateHasChanged();
|
||||||
|
this.form?.ResetValidation();
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -1,10 +1,10 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.AspNetCore.Components.Rendering;
|
using Microsoft.AspNetCore.Components.Rendering;
|
||||||
|
|
||||||
namespace AIStudio.Components;
|
namespace AIStudio.Assistants;
|
||||||
|
|
||||||
//
|
//
|
||||||
// See https://stackoverflow.com/a/77300384/2258393 for why this class is needed
|
// See https://stackoverflow.com/a/77300384/2258393 for why this class is necessary
|
||||||
//
|
//
|
||||||
|
|
||||||
public abstract class AssistantBaseCore : AssistantBase
|
public abstract class AssistantBaseCore : AssistantBase
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
@page "/assistant/coding"
|
@attribute [Route(Routes.ASSISTANT_CODING)]
|
||||||
@inherits AssistantBaseCore
|
@inherits AssistantBaseCore
|
||||||
|
|
||||||
<MudExpansionPanels Class="mb-3">
|
<MudExpansionPanels Class="mb-3">
|
||||||
+45
-9
@@ -1,6 +1,8 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace AIStudio.Components.Pages.Coding;
|
using AIStudio.Tools;
|
||||||
|
|
||||||
|
namespace AIStudio.Assistants.Coding;
|
||||||
|
|
||||||
public partial class AssistantCoding : AssistantBaseCore
|
public partial class AssistantCoding : AssistantBaseCore
|
||||||
{
|
{
|
||||||
@@ -24,6 +26,37 @@ public partial class AssistantCoding : AssistantBaseCore
|
|||||||
When the user asks in a different language than English, you answer in the same language!
|
When the user asks in a different language than English, you answer in the same language!
|
||||||
""";
|
""";
|
||||||
|
|
||||||
|
protected override IReadOnlyList<IButtonData> FooterButtons =>
|
||||||
|
[
|
||||||
|
new SendToButton
|
||||||
|
{
|
||||||
|
Self = SendTo.CODING_ASSISTANT,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
protected override void ResetFrom()
|
||||||
|
{
|
||||||
|
this.codingContexts.Clear();
|
||||||
|
this.compilerMessages = string.Empty;
|
||||||
|
this.questions = string.Empty;
|
||||||
|
if (!this.MightPreselectValues())
|
||||||
|
{
|
||||||
|
this.provideCompilerMessages = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool MightPreselectValues()
|
||||||
|
{
|
||||||
|
if (this.SettingsManager.ConfigurationData.Coding.PreselectOptions)
|
||||||
|
{
|
||||||
|
this.provideCompilerMessages = this.SettingsManager.ConfigurationData.Coding.PreselectCompilerMessages;
|
||||||
|
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.Coding.PreselectedProvider);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private readonly List<CodingContext> codingContexts = new();
|
private readonly List<CodingContext> codingContexts = new();
|
||||||
private bool provideCompilerMessages;
|
private bool provideCompilerMessages;
|
||||||
private string compilerMessages = string.Empty;
|
private string compilerMessages = string.Empty;
|
||||||
@@ -33,11 +66,10 @@ public partial class AssistantCoding : AssistantBaseCore
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
if (this.SettingsManager.ConfigurationData.Coding.PreselectOptions)
|
this.MightPreselectValues();
|
||||||
{
|
var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages<string>(Event.SEND_TO_CODING_ASSISTANT).FirstOrDefault();
|
||||||
this.provideCompilerMessages = this.SettingsManager.ConfigurationData.Coding.PreselectCompilerMessages;
|
if (deferredContent is not null)
|
||||||
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.Coding.PreselectedProvider);
|
this.questions = deferredContent;
|
||||||
}
|
|
||||||
|
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
}
|
}
|
||||||
@@ -87,9 +119,13 @@ public partial class AssistantCoding : AssistantBaseCore
|
|||||||
foreach (var codingContext in this.codingContexts)
|
foreach (var codingContext in this.codingContexts)
|
||||||
{
|
{
|
||||||
sbContext.AppendLine($"ID: {codingContext.Id}");
|
sbContext.AppendLine($"ID: {codingContext.Id}");
|
||||||
sbContext.AppendLine($"Language: {codingContext.Language.Name()}");
|
|
||||||
sbContext.AppendLine($"Other Language: {codingContext.OtherLanguage}");
|
if(codingContext.Language is not CommonCodingLanguages.OTHER)
|
||||||
sbContext.AppendLine($"Content:");
|
sbContext.AppendLine($"Language: {codingContext.Language.Name()}");
|
||||||
|
else
|
||||||
|
sbContext.AppendLine($"Language: {codingContext.OtherLanguage}");
|
||||||
|
|
||||||
|
sbContext.AppendLine("Content:");
|
||||||
sbContext.AppendLine("```");
|
sbContext.AppendLine("```");
|
||||||
sbContext.AppendLine(codingContext.Code);
|
sbContext.AppendLine(codingContext.Code);
|
||||||
sbContext.AppendLine("```");
|
sbContext.AppendLine("```");
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
namespace AIStudio.Components.Pages.Coding;
|
namespace AIStudio.Assistants.Coding;
|
||||||
|
|
||||||
public sealed class CodingContext(string id, CommonCodingLanguages language, string otherLanguage, string code)
|
public sealed class CodingContext(string id, CommonCodingLanguages language, string otherLanguage, string code)
|
||||||
{
|
{
|
||||||
File renamed without changes.
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.Pages.Coding;
|
namespace AIStudio.Assistants.Coding;
|
||||||
|
|
||||||
public partial class CodingContextItem : ComponentBase
|
public partial class CodingContextItem : ComponentBase
|
||||||
{
|
{
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
namespace AIStudio.Components.Pages.Coding;
|
namespace AIStudio.Assistants.Coding;
|
||||||
|
|
||||||
public static class CommonCodingLanguageExtensions
|
public static class CommonCodingLanguageExtensions
|
||||||
{
|
{
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
namespace AIStudio.Components.Pages.Coding;
|
namespace AIStudio.Assistants.Coding;
|
||||||
|
|
||||||
public enum CommonCodingLanguages
|
public enum CommonCodingLanguages
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
@attribute [Route(Routes.ASSISTANT_GRAMMAR_SPELLING)]
|
||||||
|
@inherits AssistantBaseCore
|
||||||
|
|
||||||
|
<MudTextField T="string" @bind-Text="@this.inputText" Validation="@this.ValidateText" AdornmentIcon="@Icons.Material.Filled.DocumentScanner" Adornment="Adornment.Start" Label="Your input to check" Variant="Variant.Outlined" Lines="6" AutoGrow="@true" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
|
||||||
|
<EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelectingOptional())" @bind-Value="@this.selectedTargetLanguage" Icon="@Icons.Material.Filled.Translate" Label="Language" AllowOther="@true" OtherValue="CommonLanguages.OTHER" @bind-OtherInput="@this.customTargetLanguage" ValidateOther="@this.ValidateCustomLanguage" LabelOther="Custom language" />
|
||||||
|
<ProviderSelection @bind-ProviderSettings="@this.providerSettings" ValidateProvider="@this.ValidatingProvider"/>
|
||||||
|
|
||||||
|
<MudButton Variant="Variant.Filled" Class="mb-3" OnClick="() => this.ProofreadText()">
|
||||||
|
Proofread
|
||||||
|
</MudButton>
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
using AIStudio.Chat;
|
||||||
|
using AIStudio.Tools;
|
||||||
|
|
||||||
|
namespace AIStudio.Assistants.GrammarSpelling;
|
||||||
|
|
||||||
|
public partial class AssistantGrammarSpelling : AssistantBaseCore
|
||||||
|
{
|
||||||
|
protected override string Title => "Grammar & Spelling Checker";
|
||||||
|
|
||||||
|
protected override string Description =>
|
||||||
|
"""
|
||||||
|
Check the grammar and spelling of a text.
|
||||||
|
""";
|
||||||
|
|
||||||
|
protected override string SystemPrompt =>
|
||||||
|
$"""
|
||||||
|
You are an expert in languages and their rules. For example, you know how US and UK English or German in
|
||||||
|
Germany and German in Austria differ. You receive text as input. You check the spelling and grammar of
|
||||||
|
this text according to the rules of {this.SystemPromptLanguage()}. You never add information. You
|
||||||
|
never ask the user for additional information. You do not attempt to improve the wording of the text.
|
||||||
|
Your response includes only the corrected text. Do not explain your changes. If no changes are needed,
|
||||||
|
you return the text unchanged.
|
||||||
|
""";
|
||||||
|
|
||||||
|
protected override bool ShowResult => false;
|
||||||
|
|
||||||
|
protected override bool ShowDedicatedProgress => true;
|
||||||
|
|
||||||
|
protected override IReadOnlyList<IButtonData> FooterButtons =>
|
||||||
|
[
|
||||||
|
new ButtonData("Copy result", Icons.Material.Filled.ContentCopy, Color.Default, string.Empty, () => this.CopyToClipboard(this.correctedText)),
|
||||||
|
new SendToButton
|
||||||
|
{
|
||||||
|
Self = SendTo.GRAMMAR_SPELLING_ASSISTANT,
|
||||||
|
UseResultingContentBlockData = false,
|
||||||
|
GetText = () => string.IsNullOrWhiteSpace(this.correctedText) ? this.inputText : this.correctedText
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
protected override ChatThread ConvertToChatThread => (this.chatThread ?? new()) with
|
||||||
|
{
|
||||||
|
SystemPrompt = SystemPrompts.DEFAULT,
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override void ResetFrom()
|
||||||
|
{
|
||||||
|
this.inputText = string.Empty;
|
||||||
|
this.correctedText = string.Empty;
|
||||||
|
if (!this.MightPreselectValues())
|
||||||
|
{
|
||||||
|
this.selectedTargetLanguage = CommonLanguages.AS_IS;
|
||||||
|
this.customTargetLanguage = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool MightPreselectValues()
|
||||||
|
{
|
||||||
|
if (this.SettingsManager.ConfigurationData.GrammarSpelling.PreselectOptions)
|
||||||
|
{
|
||||||
|
this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.GrammarSpelling.PreselectedTargetLanguage;
|
||||||
|
this.customTargetLanguage = this.SettingsManager.ConfigurationData.GrammarSpelling.PreselectedOtherLanguage;
|
||||||
|
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.GrammarSpelling.PreselectedProvider);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Overrides of ComponentBase
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
this.MightPreselectValues();
|
||||||
|
var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages<string>(Event.SEND_TO_GRAMMAR_SPELLING_ASSISTANT).FirstOrDefault();
|
||||||
|
if (deferredContent is not null)
|
||||||
|
this.inputText = deferredContent;
|
||||||
|
|
||||||
|
await base.OnInitializedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private string inputText = string.Empty;
|
||||||
|
private CommonLanguages selectedTargetLanguage;
|
||||||
|
private string customTargetLanguage = string.Empty;
|
||||||
|
private string correctedText = string.Empty;
|
||||||
|
|
||||||
|
private string? ValidateText(string text)
|
||||||
|
{
|
||||||
|
if(string.IsNullOrWhiteSpace(text))
|
||||||
|
return "Please provide a text as input. You might copy the desired text from a document or a website.";
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
var lang = this.selectedTargetLanguage switch
|
||||||
|
{
|
||||||
|
CommonLanguages.AS_IS => "the source language",
|
||||||
|
CommonLanguages.OTHER => this.customTargetLanguage,
|
||||||
|
|
||||||
|
_ => $"{this.selectedTargetLanguage.Name()}",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(lang))
|
||||||
|
return "the source language";
|
||||||
|
|
||||||
|
return lang;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ProofreadText()
|
||||||
|
{
|
||||||
|
await this.form!.Validate();
|
||||||
|
if (!this.inputIsValid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.CreateChatThread();
|
||||||
|
var time = this.AddUserRequest(this.inputText);
|
||||||
|
|
||||||
|
this.correctedText = await this.AddAIResponseAsync(time);
|
||||||
|
await this.JsRuntime.GenerateAndShowDiff(this.inputText, this.correctedText);
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
@page "/assistant/icons"
|
@attribute [Route(Routes.ASSISTANT_ICON_FINDER)]
|
||||||
@inherits AssistantBaseCore
|
@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" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
|
<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" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
|
||||||
+46
-16
@@ -1,25 +1,12 @@
|
|||||||
namespace AIStudio.Components.Pages.IconFinder;
|
using AIStudio.Tools;
|
||||||
|
|
||||||
|
namespace AIStudio.Assistants.IconFinder;
|
||||||
|
|
||||||
public partial class AssistantIconFinder : AssistantBaseCore
|
public partial class AssistantIconFinder : AssistantBaseCore
|
||||||
{
|
{
|
||||||
private string inputContext = string.Empty;
|
private string inputContext = string.Empty;
|
||||||
private IconSources selectedIconSource;
|
private IconSources selectedIconSource;
|
||||||
|
|
||||||
#region Overrides of ComponentBase
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
|
||||||
{
|
|
||||||
if (this.SettingsManager.ConfigurationData.IconFinder.PreselectOptions)
|
|
||||||
{
|
|
||||||
this.selectedIconSource = this.SettingsManager.ConfigurationData.IconFinder.PreselectedSource;
|
|
||||||
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.IconFinder.PreselectedProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
await base.OnInitializedAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
protected override string Title => "Icon Finder";
|
protected override string Title => "Icon Finder";
|
||||||
|
|
||||||
protected override string Description =>
|
protected override string Description =>
|
||||||
@@ -40,7 +27,50 @@ public partial class AssistantIconFinder : AssistantBaseCore
|
|||||||
related to the keyword "buildings" might be the best match. Provide your keywords in a Markdown list without
|
related to the keyword "buildings" might be the best match. Provide your keywords in a Markdown list without
|
||||||
quotation marks.
|
quotation marks.
|
||||||
""";
|
""";
|
||||||
|
|
||||||
|
protected override IReadOnlyList<IButtonData> FooterButtons =>
|
||||||
|
[
|
||||||
|
new SendToButton
|
||||||
|
{
|
||||||
|
Self = SendTo.ICON_FINDER_ASSISTANT,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
protected override void ResetFrom()
|
||||||
|
{
|
||||||
|
this.inputContext = string.Empty;
|
||||||
|
if (!this.MightPreselectValues())
|
||||||
|
{
|
||||||
|
this.selectedIconSource = IconSources.GENERIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool MightPreselectValues()
|
||||||
|
{
|
||||||
|
if (this.SettingsManager.ConfigurationData.IconFinder.PreselectOptions)
|
||||||
|
{
|
||||||
|
this.selectedIconSource = this.SettingsManager.ConfigurationData.IconFinder.PreselectedSource;
|
||||||
|
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.IconFinder.PreselectedProvider);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Overrides of ComponentBase
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
this.MightPreselectValues();
|
||||||
|
var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages<string>(Event.SEND_TO_ICON_FINDER_ASSISTANT).FirstOrDefault();
|
||||||
|
if (deferredContent is not null)
|
||||||
|
this.inputContext = deferredContent;
|
||||||
|
|
||||||
|
await base.OnInitializedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
private string? ValidatingContext(string context)
|
private string? ValidatingContext(string context)
|
||||||
{
|
{
|
||||||
if(string.IsNullOrWhiteSpace(context))
|
if(string.IsNullOrWhiteSpace(context))
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
namespace AIStudio.Components.Pages.IconFinder;
|
namespace AIStudio.Assistants.IconFinder;
|
||||||
|
|
||||||
public static class IconSourceExtensions
|
public static class IconSourceExtensions
|
||||||
{
|
{
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
namespace AIStudio.Components.Pages.IconFinder;
|
namespace AIStudio.Assistants.IconFinder;
|
||||||
|
|
||||||
public enum IconSources
|
public enum IconSources
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
@attribute [Route(Routes.ASSISTANT_REWRITE)]
|
||||||
|
@inherits AssistantBaseCore
|
||||||
|
|
||||||
|
<MudTextField T="string" @bind-Text="@this.inputText" Validation="@this.ValidateText" AdornmentIcon="@Icons.Material.Filled.DocumentScanner" Adornment="Adornment.Start" Label="Your input to improve" Variant="Variant.Outlined" Lines="6" AutoGrow="@true" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
|
||||||
|
<EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelectingOptional())" @bind-Value="@this.selectedTargetLanguage" Icon="@Icons.Material.Filled.Translate" Label="Language" AllowOther="@true" OtherValue="CommonLanguages.OTHER" @bind-OtherInput="@this.customTargetLanguage" ValidateOther="@this.ValidateCustomLanguage" LabelOther="Custom language" />
|
||||||
|
<EnumSelection T="WritingStyles" NameFunc="@(style => style.Name())" @bind-Value="@this.selectedWritingStyle" Icon="@Icons.Material.Filled.Edit" Label="Writing style" AllowOther="@false" />
|
||||||
|
<ProviderSelection @bind-ProviderSettings="@this.providerSettings" ValidateProvider="@this.ValidatingProvider"/>
|
||||||
|
|
||||||
|
<MudButton Variant="Variant.Filled" Class="mb-3" OnClick="() => this.RewriteText()">
|
||||||
|
Improve
|
||||||
|
</MudButton>
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
using AIStudio.Chat;
|
||||||
|
using AIStudio.Tools;
|
||||||
|
|
||||||
|
namespace AIStudio.Assistants.RewriteImprove;
|
||||||
|
|
||||||
|
public partial class AssistantRewriteImprove : AssistantBaseCore
|
||||||
|
{
|
||||||
|
protected override string Title => "Rewrite & Improve Text";
|
||||||
|
|
||||||
|
protected override string Description =>
|
||||||
|
"""
|
||||||
|
Rewrite and improve your text. Please note, that the capabilities of the different LLM providers will vary.
|
||||||
|
""";
|
||||||
|
|
||||||
|
protected override string SystemPrompt =>
|
||||||
|
$"""
|
||||||
|
You are an expert in language and style. You receive a text as input. First, you review the text. If no
|
||||||
|
changes are needed, you return the text without modifications. If a change is necessary, you improve the
|
||||||
|
text. You can also correct spelling and grammar issues. You never add additional information. You never
|
||||||
|
ask the user for additional information. Your response only contains the improved text. You do not explain
|
||||||
|
your changes. If no changes are needed, you return the text unchanged.
|
||||||
|
The style of the text: {this.selectedWritingStyle.Prompt()}. You follow the rules according
|
||||||
|
to {this.SystemPromptLanguage()} in all your changes.
|
||||||
|
""";
|
||||||
|
|
||||||
|
protected override bool ShowResult => false;
|
||||||
|
|
||||||
|
protected override bool ShowDedicatedProgress => true;
|
||||||
|
|
||||||
|
protected override IReadOnlyList<IButtonData> FooterButtons =>
|
||||||
|
[
|
||||||
|
new ButtonData("Copy result", Icons.Material.Filled.ContentCopy, Color.Default, string.Empty, () => this.CopyToClipboard(this.rewrittenText)),
|
||||||
|
new SendToButton
|
||||||
|
{
|
||||||
|
Self = SendTo.REWRITE_ASSISTANT,
|
||||||
|
UseResultingContentBlockData = false,
|
||||||
|
GetText = () => string.IsNullOrWhiteSpace(this.rewrittenText) ? this.inputText : this.rewrittenText,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
protected override ChatThread ConvertToChatThread => (this.chatThread ?? new()) with
|
||||||
|
{
|
||||||
|
SystemPrompt = SystemPrompts.DEFAULT,
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override void ResetFrom()
|
||||||
|
{
|
||||||
|
this.inputText = string.Empty;
|
||||||
|
this.rewrittenText = string.Empty;
|
||||||
|
if (!this.MightPreselectValues())
|
||||||
|
{
|
||||||
|
this.selectedTargetLanguage = CommonLanguages.AS_IS;
|
||||||
|
this.customTargetLanguage = string.Empty;
|
||||||
|
this.selectedWritingStyle = WritingStyles.NOT_SPECIFIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool MightPreselectValues()
|
||||||
|
{
|
||||||
|
if (this.SettingsManager.ConfigurationData.RewriteImprove.PreselectOptions)
|
||||||
|
{
|
||||||
|
this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.RewriteImprove.PreselectedTargetLanguage;
|
||||||
|
this.customTargetLanguage = this.SettingsManager.ConfigurationData.RewriteImprove.PreselectedOtherLanguage;
|
||||||
|
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.RewriteImprove.PreselectedProvider);
|
||||||
|
this.selectedWritingStyle = this.SettingsManager.ConfigurationData.RewriteImprove.PreselectedWritingStyle;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Overrides of ComponentBase
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
this.MightPreselectValues();
|
||||||
|
var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages<string>(Event.SEND_TO_REWRITE_ASSISTANT).FirstOrDefault();
|
||||||
|
if (deferredContent is not null)
|
||||||
|
this.inputText = deferredContent;
|
||||||
|
|
||||||
|
await base.OnInitializedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private string inputText = string.Empty;
|
||||||
|
private CommonLanguages selectedTargetLanguage;
|
||||||
|
private string customTargetLanguage = string.Empty;
|
||||||
|
private string rewrittenText = string.Empty;
|
||||||
|
private WritingStyles selectedWritingStyle;
|
||||||
|
|
||||||
|
private string? ValidateText(string text)
|
||||||
|
{
|
||||||
|
if(string.IsNullOrWhiteSpace(text))
|
||||||
|
return "Please provide a text as input. You might copy the desired text from a document or a website.";
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
var lang = this.selectedTargetLanguage switch
|
||||||
|
{
|
||||||
|
CommonLanguages.AS_IS => "the source language",
|
||||||
|
CommonLanguages.OTHER => this.customTargetLanguage,
|
||||||
|
|
||||||
|
_ => $"{this.selectedTargetLanguage.Name()}",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(lang))
|
||||||
|
return "the source language";
|
||||||
|
|
||||||
|
return lang;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RewriteText()
|
||||||
|
{
|
||||||
|
await this.form!.Validate();
|
||||||
|
if (!this.inputIsValid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.CreateChatThread();
|
||||||
|
var time = this.AddUserRequest(this.inputText);
|
||||||
|
|
||||||
|
this.rewrittenText = await this.AddAIResponseAsync(time);
|
||||||
|
await this.JsRuntime.GenerateAndShowDiff(this.inputText, this.rewrittenText);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
namespace AIStudio.Assistants.RewriteImprove;
|
||||||
|
|
||||||
|
public enum WritingStyles
|
||||||
|
{
|
||||||
|
NOT_SPECIFIED = 0,
|
||||||
|
|
||||||
|
EVERYDAY,
|
||||||
|
BUSINESS,
|
||||||
|
SCIENTIFIC,
|
||||||
|
JOURNALISTIC,
|
||||||
|
LITERARY,
|
||||||
|
TECHNICAL,
|
||||||
|
MARKETING,
|
||||||
|
ACADEMIC,
|
||||||
|
LEGAL,
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
namespace AIStudio.Assistants.RewriteImprove;
|
||||||
|
|
||||||
|
public static class WritingStylesExtensions
|
||||||
|
{
|
||||||
|
public static string Name(this WritingStyles style)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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.",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-2
@@ -1,5 +1,4 @@
|
|||||||
@page "/assistant/summarizer"
|
@attribute [Route(Routes.ASSISTANT_SUMMARIZER)]
|
||||||
@using AIStudio.Tools
|
|
||||||
@inherits AssistantBaseCore
|
@inherits AssistantBaseCore
|
||||||
|
|
||||||
@if (!this.SettingsManager.ConfigurationData.TextSummarizer.HideWebContentReader)
|
@if (!this.SettingsManager.ConfigurationData.TextSummarizer.HideWebContentReader)
|
||||||
+46
-9
@@ -1,6 +1,7 @@
|
|||||||
|
using AIStudio.Chat;
|
||||||
using AIStudio.Tools;
|
using AIStudio.Tools;
|
||||||
|
|
||||||
namespace AIStudio.Components.Pages.TextSummarizer;
|
namespace AIStudio.Assistants.TextSummarizer;
|
||||||
|
|
||||||
public partial class AssistantTextSummarizer : AssistantBaseCore
|
public partial class AssistantTextSummarizer : AssistantBaseCore
|
||||||
{
|
{
|
||||||
@@ -23,6 +24,46 @@ public partial class AssistantTextSummarizer : AssistantBaseCore
|
|||||||
a summary with the requested complexity. In any case, do not add any information.
|
a summary with the requested complexity. In any case, do not add any information.
|
||||||
""";
|
""";
|
||||||
|
|
||||||
|
protected override IReadOnlyList<IButtonData> FooterButtons =>
|
||||||
|
[
|
||||||
|
new SendToButton
|
||||||
|
{
|
||||||
|
Self = SendTo.TEXT_SUMMARIZER_ASSISTANT,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
protected override ChatThread ConvertToChatThread => (this.chatThread ?? new()) with
|
||||||
|
{
|
||||||
|
SystemPrompt = SystemPrompts.DEFAULT,
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override void ResetFrom()
|
||||||
|
{
|
||||||
|
this.inputText = string.Empty;
|
||||||
|
if(!this.MightPreselectValues())
|
||||||
|
{
|
||||||
|
this.selectedTargetLanguage = CommonLanguages.AS_IS;
|
||||||
|
this.customTargetLanguage = string.Empty;
|
||||||
|
this.selectedComplexity = Complexity.NO_CHANGE;
|
||||||
|
this.expertInField = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool MightPreselectValues()
|
||||||
|
{
|
||||||
|
if (this.SettingsManager.ConfigurationData.TextSummarizer.PreselectOptions)
|
||||||
|
{
|
||||||
|
this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.TextSummarizer.PreselectedTargetLanguage;
|
||||||
|
this.customTargetLanguage = this.SettingsManager.ConfigurationData.TextSummarizer.PreselectedOtherLanguage;
|
||||||
|
this.selectedComplexity = this.SettingsManager.ConfigurationData.TextSummarizer.PreselectedComplexity;
|
||||||
|
this.expertInField = this.SettingsManager.ConfigurationData.TextSummarizer.PreselectedExpertInField;
|
||||||
|
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.TextSummarizer.PreselectedProvider);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private string inputText = string.Empty;
|
private string inputText = string.Empty;
|
||||||
private bool isAgentRunning;
|
private bool isAgentRunning;
|
||||||
private CommonLanguages selectedTargetLanguage;
|
private CommonLanguages selectedTargetLanguage;
|
||||||
@@ -34,14 +75,10 @@ public partial class AssistantTextSummarizer : AssistantBaseCore
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
if(this.SettingsManager.ConfigurationData.TextSummarizer.PreselectOptions)
|
this.MightPreselectValues();
|
||||||
{
|
var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages<string>(Event.SEND_TO_TEXT_SUMMARIZER_ASSISTANT).FirstOrDefault();
|
||||||
this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.TextSummarizer.PreselectedTargetLanguage;
|
if (deferredContent is not null)
|
||||||
this.customTargetLanguage = this.SettingsManager.ConfigurationData.TextSummarizer.PreselectedOtherLanguage;
|
this.inputText = deferredContent;
|
||||||
this.selectedComplexity = this.SettingsManager.ConfigurationData.TextSummarizer.PreselectedComplexity;
|
|
||||||
this.expertInField = this.SettingsManager.ConfigurationData.TextSummarizer.PreselectedExpertInField;
|
|
||||||
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.TextSummarizer.PreselectedProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
namespace AIStudio.Components.Pages.TextSummarizer;
|
namespace AIStudio.Assistants.TextSummarizer;
|
||||||
|
|
||||||
public enum Complexity
|
public enum Complexity
|
||||||
{
|
{
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
namespace AIStudio.Components.Pages.TextSummarizer;
|
namespace AIStudio.Assistants.TextSummarizer;
|
||||||
|
|
||||||
public static class ComplexityExtensions
|
public static class ComplexityExtensions
|
||||||
{
|
{
|
||||||
+1
-2
@@ -1,5 +1,4 @@
|
|||||||
@page "/assistant/translation"
|
@attribute [Route(Routes.ASSISTANT_TRANSLATION)]
|
||||||
@using AIStudio.Tools
|
|
||||||
@inherits AssistantBaseCore
|
@inherits AssistantBaseCore
|
||||||
|
|
||||||
@if (!this.SettingsManager.ConfigurationData.Translation.HideWebContentReader)
|
@if (!this.SettingsManager.ConfigurationData.Translation.HideWebContentReader)
|
||||||
+46
-8
@@ -1,6 +1,7 @@
|
|||||||
|
using AIStudio.Chat;
|
||||||
using AIStudio.Tools;
|
using AIStudio.Tools;
|
||||||
|
|
||||||
namespace AIStudio.Components.Pages.Translation;
|
namespace AIStudio.Assistants.Translation;
|
||||||
|
|
||||||
public partial class AssistantTranslation : AssistantBaseCore
|
public partial class AssistantTranslation : AssistantBaseCore
|
||||||
{
|
{
|
||||||
@@ -19,6 +20,45 @@ public partial class AssistantTranslation : AssistantBaseCore
|
|||||||
language requires, e.g., shorter sentences, you should split the text into shorter sentences.
|
language requires, e.g., shorter sentences, you should split the text into shorter sentences.
|
||||||
""";
|
""";
|
||||||
|
|
||||||
|
protected override IReadOnlyList<IButtonData> FooterButtons =>
|
||||||
|
[
|
||||||
|
new SendToButton
|
||||||
|
{
|
||||||
|
Self = SendTo.TRANSLATION_ASSISTANT,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
protected override ChatThread ConvertToChatThread => (this.chatThread ?? new()) with
|
||||||
|
{
|
||||||
|
SystemPrompt = SystemPrompts.DEFAULT,
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override void ResetFrom()
|
||||||
|
{
|
||||||
|
this.inputText = string.Empty;
|
||||||
|
this.inputTextLastTranslation = string.Empty;
|
||||||
|
if (!this.MightPreselectValues())
|
||||||
|
{
|
||||||
|
this.liveTranslation = false;
|
||||||
|
this.selectedTargetLanguage = CommonLanguages.AS_IS;
|
||||||
|
this.customTargetLanguage = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool MightPreselectValues()
|
||||||
|
{
|
||||||
|
if (this.SettingsManager.ConfigurationData.Translation.PreselectOptions)
|
||||||
|
{
|
||||||
|
this.liveTranslation = this.SettingsManager.ConfigurationData.Translation.PreselectLiveTranslation;
|
||||||
|
this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.Translation.PreselectedTargetLanguage;
|
||||||
|
this.customTargetLanguage = this.SettingsManager.ConfigurationData.Translation.PreselectOtherLanguage;
|
||||||
|
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.Translation.PreselectedProvider);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private bool liveTranslation;
|
private bool liveTranslation;
|
||||||
private bool isAgentRunning;
|
private bool isAgentRunning;
|
||||||
private string inputText = string.Empty;
|
private string inputText = string.Empty;
|
||||||
@@ -30,13 +70,10 @@ public partial class AssistantTranslation : AssistantBaseCore
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
if (this.SettingsManager.ConfigurationData.Translation.PreselectOptions)
|
this.MightPreselectValues();
|
||||||
{
|
var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages<string>(Event.SEND_TO_TRANSLATION_ASSISTANT).FirstOrDefault();
|
||||||
this.liveTranslation = this.SettingsManager.ConfigurationData.Translation.PreselectLiveTranslation;
|
if (deferredContent is not null)
|
||||||
this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.Translation.PreselectedTargetLanguage;
|
this.inputText = deferredContent;
|
||||||
this.customTargetLanguage = this.SettingsManager.ConfigurationData.Translation.PreselectOtherLanguage;
|
|
||||||
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.Translation.PreselectedProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
}
|
}
|
||||||
@@ -69,6 +106,7 @@ public partial class AssistantTranslation : AssistantBaseCore
|
|||||||
|
|
||||||
private async Task TranslateText(bool force)
|
private async Task TranslateText(bool force)
|
||||||
{
|
{
|
||||||
|
await this.form!.Validate();
|
||||||
if (!this.inputIsValid)
|
if (!this.inputIsValid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
@using AIStudio
|
||||||
|
@using AIStudio.Tools
|
||||||
|
@using AIStudio.Components
|
||||||
|
@using MudBlazor
|
||||||
@@ -3,7 +3,7 @@ namespace AIStudio.Chat;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Data structure for a chat thread.
|
/// Data structure for a chat thread.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class ChatThread
|
public sealed record ChatThread
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The unique identifier of the chat thread.
|
/// The unique identifier of the chat thread.
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace AIStudio.Chat;
|
||||||
|
|
||||||
|
public static class SystemPrompts
|
||||||
|
{
|
||||||
|
public const string DEFAULT = "You are a helpful assistant!";
|
||||||
|
}
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
@* ReSharper disable Html.PathError *@
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<title>MindWork AI Studio</title>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
||||||
<base href="/"/>
|
|
||||||
|
|
||||||
<link rel="icon" type="image/png" href="favicon.png"/>
|
|
||||||
<link href="system/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
|
|
||||||
<link href="system/MudBlazor.Markdown/MudBlazor.Markdown.min.css" rel="stylesheet" />
|
|
||||||
<link href="app.css" rel="stylesheet" />
|
|
||||||
<HeadOutlet/>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body style="overflow: hidden;">
|
|
||||||
<Routes @rendermode="new InteractiveServerRenderMode(prerender: false)"/>
|
|
||||||
<script src="_framework/blazor.web.js" autostart="false"></script>
|
|
||||||
<script src="boot.js"></script>
|
|
||||||
<script src="system/MudBlazor/MudBlazor.min.js"></script>
|
|
||||||
<script src="system/MudBlazor.Markdown/MudBlazor.Markdown.min.js"></script>
|
|
||||||
<script src="app.js"></script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
@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>
|
|
||||||
<Issues IssuesData="@this.inputIssues"/>
|
|
||||||
|
|
||||||
@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>
|
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
using AIStudio.Chat;
|
|
||||||
using AIStudio.Provider;
|
|
||||||
using AIStudio.Settings;
|
|
||||||
using AIStudio.Tools;
|
|
||||||
|
|
||||||
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 ThreadSafeRandom RNG { get; init; } = null!;
|
|
||||||
|
|
||||||
protected abstract string Title { get; }
|
|
||||||
|
|
||||||
protected abstract string Description { get; }
|
|
||||||
|
|
||||||
protected abstract string SystemPrompt { get; }
|
|
||||||
|
|
||||||
private protected virtual RenderFragment? Body => null;
|
|
||||||
|
|
||||||
protected static readonly Dictionary<string, object?> USER_INPUT_ATTRIBUTES = new();
|
|
||||||
|
|
||||||
protected AIStudio.Settings.Provider providerSettings;
|
|
||||||
protected MudForm? form;
|
|
||||||
protected bool inputIsValid;
|
|
||||||
|
|
||||||
private ChatThread? chatThread;
|
|
||||||
private ContentBlock? resultingContentBlock;
|
|
||||||
private string[] inputIssues = [];
|
|
||||||
|
|
||||||
#region Overrides of ComponentBase
|
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
|
||||||
{
|
|
||||||
// Configure the spellchecking for the user input:
|
|
||||||
this.SettingsManager.InjectSpellchecking(USER_INPUT_ATTRIBUTES);
|
|
||||||
|
|
||||||
await base.OnParametersSetAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
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 string? ValidatingProvider(AIStudio.Settings.Provider provider)
|
|
||||||
{
|
|
||||||
if(provider.UsedProvider == Providers.NONE)
|
|
||||||
return "Please select a provider.";
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
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.providerSettings.CreateProvider(), this.JsRuntime, this.SettingsManager, this.providerSettings.Model, this.chatThread);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public partial class AssistantBlock : ComponentBase
|
public partial class AssistantBlock : ComponentBase
|
||||||
{
|
{
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
namespace AIStudio.Components.Blocks;
|
|
||||||
|
|
||||||
public interface ITreeItem;
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
namespace AIStudio.Components.Blocks;
|
|
||||||
|
|
||||||
public readonly record struct TreeDivider : ITreeItem;
|
|
||||||
+5
-1
@@ -1,4 +1,4 @@
|
|||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public partial class Changelog
|
public partial class Changelog
|
||||||
{
|
{
|
||||||
@@ -13,6 +13,10 @@ public partial class Changelog
|
|||||||
|
|
||||||
public static readonly Log[] LOGS =
|
public static readonly Log[] LOGS =
|
||||||
[
|
[
|
||||||
|
new (173, "v0.8.11, build 173 (2024-08-21 07:03 UTC)", "v0.8.11.md"),
|
||||||
|
new (172, "v0.8.10, build 172 (2024-08-18 19:44 UTC)", "v0.8.10.md"),
|
||||||
|
new (171, "v0.8.9, build 171 (2024-08-18 10:35 UTC)", "v0.8.9.md"),
|
||||||
|
new (170, "v0.8.8, build 170 (2024-08-14 06:30 UTC)", "v0.8.8.md"),
|
||||||
new (169, "v0.8.7, build 169 (2024-08-01 19:08 UTC)", "v0.8.7.md"),
|
new (169, "v0.8.7, build 169 (2024-08-01 19:08 UTC)", "v0.8.7.md"),
|
||||||
new (168, "v0.8.6, build 168 (2024-08-01 19:50 UTC)", "v0.8.6.md"),
|
new (168, "v0.8.6, build 168 (2024-08-01 19:50 UTC)", "v0.8.6.md"),
|
||||||
new (167, "v0.8.5, build 167 (2024-07-28 16:44 UTC)", "v0.8.5.md"),
|
new (167, "v0.8.5, build 167 (2024-07-28 16:44 UTC)", "v0.8.5.md"),
|
||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
@using AIStudio.Tools
|
|
||||||
<MudSelect T="Log" @bind-Value="@this.SelectedLog" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Schedule" Margin="Margin.Dense" Label="Changelog" Class="mb-2 rounded-lg" Variant="Variant.Outlined" SelectedValuesChanged="() => this.ReadLogAsync()" OnKeyUp="() => this.ReadLogAsync()">
|
<MudSelect T="Log" @bind-Value="@this.SelectedLog" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Schedule" Margin="Margin.Dense" Label="Changelog" Class="mb-2 rounded-lg" Variant="Variant.Outlined" SelectedValuesChanged="() => this.ReadLogAsync()" OnKeyUp="() => this.ReadLogAsync()">
|
||||||
@foreach (var log in LOGS)
|
@foreach (var log in LOGS)
|
||||||
{
|
{
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public partial class Changelog : ComponentBase
|
public partial class Changelog : ComponentBase
|
||||||
{
|
{
|
||||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configuration component for any boolean option.
|
/// Configuration component for any boolean option.
|
||||||
File renamed without changes.
+1
-1
@@ -3,7 +3,7 @@ using AIStudio.Tools;
|
|||||||
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public partial class ConfigurationProviderSelection : ComponentBase, IMessageBusReceiver, IDisposable
|
public partial class ConfigurationProviderSelection : ComponentBase, IMessageBusReceiver, IDisposable
|
||||||
{
|
{
|
||||||
File renamed without changes.
+1
-1
@@ -2,7 +2,7 @@ using AIStudio.Settings;
|
|||||||
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configuration component for selecting a value from a list.
|
/// Configuration component for selecting a value from a list.
|
||||||
File renamed without changes.
+1
-1
@@ -2,7 +2,7 @@ using System.Numerics;
|
|||||||
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public partial class ConfigurationSlider<T> : ConfigurationBase where T : struct, INumber<T>
|
public partial class ConfigurationSlider<T> : ConfigurationBase where T : struct, INumber<T>
|
||||||
{
|
{
|
||||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public partial class ConfigurationText : ConfigurationBase
|
public partial class ConfigurationText : ConfigurationBase
|
||||||
{
|
{
|
||||||
File renamed without changes.
+1
-1
@@ -2,7 +2,7 @@ using AIStudio.Settings;
|
|||||||
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public partial class EnumSelection<T> : EnumSelectionBase where T : struct, Enum
|
public partial class EnumSelection<T> : EnumSelectionBase where T : struct, Enum
|
||||||
{
|
{
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public abstract class EnumSelectionBase : ComponentBase
|
public abstract class EnumSelectionBase : ComponentBase
|
||||||
{
|
{
|
||||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public partial class ExpansionPanel : ComponentBase
|
public partial class ExpansionPanel : ComponentBase
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
|
public interface ITreeItem;
|
||||||
File renamed without changes.
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
using AIStudio.Components.Layout;
|
using AIStudio.Layout;
|
||||||
using AIStudio.Tools;
|
using AIStudio.Tools;
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public partial class InnerScrolling : MSGComponentBase
|
public partial class InnerScrolling : MSGComponentBase
|
||||||
{
|
{
|
||||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public partial class Issues : ComponentBase
|
public partial class Issues : ComponentBase
|
||||||
{
|
{
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
namespace AIStudio.Components.Layout;
|
|
||||||
|
|
||||||
public record NavBarItem(string Name, string Icon, Color IconColor, string Path, bool MatchAll);
|
|
||||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public partial class Motivation : ComponentBase
|
public partial class Motivation : ComponentBase
|
||||||
{
|
{
|
||||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public partial class MudTextList : ComponentBase
|
public partial class MudTextList : ComponentBase
|
||||||
{
|
{
|
||||||
File renamed without changes.
+1
-1
@@ -2,7 +2,7 @@ using System.Numerics;
|
|||||||
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public partial class MudTextSlider<T> : ComponentBase where T : struct, INumber<T>
|
public partial class MudTextSlider<T> : ComponentBase where T : struct, INumber<T>
|
||||||
{
|
{
|
||||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public partial class MudTextSwitch : ComponentBase
|
public partial class MudTextSwitch : ComponentBase
|
||||||
{
|
{
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
|
||||||
|
|
||||||
namespace AIStudio.Components.Pages;
|
|
||||||
|
|
||||||
public partial class Assistants : ComponentBase;
|
|
||||||
File renamed without changes.
+1
-1
@@ -2,7 +2,7 @@ using AIStudio.Tools;
|
|||||||
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public partial class ProcessComponent<T> : ComponentBase where T : struct, Enum
|
public partial class ProcessComponent<T> : ComponentBase where T : struct, Enum
|
||||||
{
|
{
|
||||||
File renamed without changes.
+1
-1
@@ -2,7 +2,7 @@ using AIStudio.Settings;
|
|||||||
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public partial class ProviderSelection : ComponentBase
|
public partial class ProviderSelection : ComponentBase
|
||||||
{
|
{
|
||||||
File renamed without changes.
+1
-1
@@ -5,7 +5,7 @@ using AIStudio.Tools;
|
|||||||
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public partial class ReadWebContent : ComponentBase
|
public partial class ReadWebContent : ComponentBase
|
||||||
{
|
{
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public enum ReadWebContentSteps
|
public enum ReadWebContentSteps
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
@typeparam T
|
||||||
|
|
||||||
|
<MudButtonGroup Color="@this.Color" Variant="Variant.Filled">
|
||||||
|
@if (string.IsNullOrWhiteSpace(this.Icon))
|
||||||
|
{
|
||||||
|
<MudButton OnClick="() => this.OnClick(this.selectedValue)">
|
||||||
|
@this.SelectedValueName()
|
||||||
|
</MudButton>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<MudButton StartIcon="@this.Icon" OnClick="() => this.OnClick(this.selectedValue)">
|
||||||
|
@this.SelectedValueName()
|
||||||
|
</MudButton>
|
||||||
|
}
|
||||||
|
<MudMenu Icon="@Icons.Material.Filled.ArrowDropDown" Style="align-self: auto;">
|
||||||
|
@foreach(var item in this.Items)
|
||||||
|
{
|
||||||
|
<MudMenuItem OnClick="() => this.SelectItem(item)">
|
||||||
|
@this.NameFunc(item)
|
||||||
|
</MudMenuItem>
|
||||||
|
}
|
||||||
|
</MudMenu>
|
||||||
|
</MudButtonGroup>
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
|
public partial class SplitButton<T> : ComponentBase
|
||||||
|
{
|
||||||
|
[Parameter]
|
||||||
|
public Color Color { get; set; } = Color.Default;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string Icon { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public IReadOnlyCollection<T> Items { get; set; } = [];
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public Func<T, string> NameFunc { get; set; } = _ => string.Empty;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public T? PreselectedValue { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public Func<T?, Task> OnClick { get; set; } = _ => Task.CompletedTask;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// What happens when the user selects an item by the dropdown?
|
||||||
|
/// Immediate = true means that the OnClick event is triggered immediately
|
||||||
|
/// after the user selects an item. Immediate = false means that the OnClick
|
||||||
|
/// event is triggered only when the user clicks the button.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public bool Immediate { get; set; }
|
||||||
|
|
||||||
|
#region Overrides of ComponentBase
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
if(this.PreselectedValue is not null)
|
||||||
|
this.selectedValue = this.PreselectedValue;
|
||||||
|
else
|
||||||
|
this.selectedValue = this.Items.FirstOrDefault();
|
||||||
|
|
||||||
|
await base.OnInitializedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private T? selectedValue;
|
||||||
|
|
||||||
|
private string SelectedValueName()
|
||||||
|
{
|
||||||
|
if(this.selectedValue is null)
|
||||||
|
return "Select...";
|
||||||
|
|
||||||
|
return this.NameFunc(this.selectedValue!);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SelectItem(T item)
|
||||||
|
{
|
||||||
|
this.selectedValue = item;
|
||||||
|
if(this.Immediate)
|
||||||
|
this.OnClick(this.selectedValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public partial class ThirdPartyComponent : ComponentBase
|
public partial class ThirdPartyComponent : ComponentBase
|
||||||
{
|
{
|
||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public readonly record struct TreeButton(WorkspaceBranch Branch, int Depth, string Text, string Icon, Func<Task> Action) : ITreeItem;
|
public readonly record struct TreeButton(WorkspaceBranch Branch, int Depth, string Text, string Icon, Func<Task> Action) : ITreeItem;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
|
public readonly record struct TreeDivider : ITreeItem;
|
||||||
+4
-2
@@ -1,4 +1,4 @@
|
|||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public class TreeItemData : ITreeItem
|
public class TreeItemData : ITreeItem
|
||||||
{
|
{
|
||||||
@@ -8,7 +8,7 @@ public class TreeItemData : ITreeItem
|
|||||||
|
|
||||||
public string Text { get; init; } = string.Empty;
|
public string Text { get; init; } = string.Empty;
|
||||||
|
|
||||||
public string ShortenedText => Text.Length > 30 ? this.Text[..30] + "..." : this.Text;
|
public string ShortenedText => this.Text.Length > 30 ? this.Text[..30] + "..." : this.Text;
|
||||||
|
|
||||||
public string Icon { get; init; } = string.Empty;
|
public string Icon { get; init; } = string.Empty;
|
||||||
|
|
||||||
@@ -18,5 +18,7 @@ public class TreeItemData : ITreeItem
|
|||||||
|
|
||||||
public bool Expandable { get; init; } = true;
|
public bool Expandable { get; init; } = true;
|
||||||
|
|
||||||
|
public DateTimeOffset LastEditTime { get; init; }
|
||||||
|
|
||||||
public IReadOnlyCollection<TreeItemData<ITreeItem>> Children { get; init; } = [];
|
public IReadOnlyCollection<TreeItemData<ITreeItem>> Children { get; init; } = [];
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public enum TreeItemType
|
public enum TreeItemType
|
||||||
{
|
{
|
||||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public partial class Vision : ComponentBase
|
public partial class Vision : ComponentBase
|
||||||
{
|
{
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public enum WorkspaceBranch
|
public enum WorkspaceBranch
|
||||||
{
|
{
|
||||||
File renamed without changes.
+49
-40
@@ -3,15 +3,15 @@ using System.Text.Json;
|
|||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
using AIStudio.Chat;
|
using AIStudio.Chat;
|
||||||
using AIStudio.Components.CommonDialogs;
|
using AIStudio.Dialogs;
|
||||||
using AIStudio.Settings;
|
using AIStudio.Settings;
|
||||||
using AIStudio.Tools;
|
using AIStudio.Tools;
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
using DialogOptions = AIStudio.Components.CommonDialogs.DialogOptions;
|
using DialogOptions = AIStudio.Dialogs.DialogOptions;
|
||||||
|
|
||||||
namespace AIStudio.Components.Blocks;
|
namespace AIStudio.Components;
|
||||||
|
|
||||||
public partial class Workspaces : ComponentBase
|
public partial class Workspaces : ComponentBase
|
||||||
{
|
{
|
||||||
@@ -109,42 +109,44 @@ public partial class Workspaces : ComponentBase
|
|||||||
|
|
||||||
private async Task<IReadOnlyCollection<TreeItemData<ITreeItem>>> LoadTemporaryChats()
|
private async Task<IReadOnlyCollection<TreeItemData<ITreeItem>>> LoadTemporaryChats()
|
||||||
{
|
{
|
||||||
var tempChildren = new List<TreeItemData<ITreeItem>>();
|
var tempChildren = new List<TreeItemData>();
|
||||||
|
|
||||||
//
|
// Get the temp root directory:
|
||||||
// Search for workspace folders in the data directory:
|
|
||||||
//
|
|
||||||
|
|
||||||
// Get the workspace root directory:
|
|
||||||
var temporaryDirectories = Path.Join(SettingsManager.DataDirectory, "tempChats");
|
var temporaryDirectories = Path.Join(SettingsManager.DataDirectory, "tempChats");
|
||||||
|
|
||||||
// Ensure the directory exists:
|
// Ensure the directory exists:
|
||||||
Directory.CreateDirectory(temporaryDirectories);
|
Directory.CreateDirectory(temporaryDirectories);
|
||||||
|
|
||||||
// Enumerate the workspace directories:
|
// Enumerate the chat directories:
|
||||||
foreach (var tempChatDirPath in Directory.EnumerateDirectories(temporaryDirectories))
|
foreach (var tempChatDirPath in Directory.EnumerateDirectories(temporaryDirectories))
|
||||||
{
|
{
|
||||||
// Read the `name` file:
|
// Read the `name` file:
|
||||||
var chatNamePath = Path.Join(tempChatDirPath, "name");
|
var chatNamePath = Path.Join(tempChatDirPath, "name");
|
||||||
var chatName = await File.ReadAllTextAsync(chatNamePath, Encoding.UTF8);
|
var chatName = await File.ReadAllTextAsync(chatNamePath, Encoding.UTF8);
|
||||||
|
|
||||||
tempChildren.Add(new TreeItemData<ITreeItem>
|
// Read the last change time of the chat:
|
||||||
|
var chatThreadPath = Path.Join(tempChatDirPath, "thread.json");
|
||||||
|
var lastEditTime = File.GetLastWriteTimeUtc(chatThreadPath);
|
||||||
|
|
||||||
|
tempChildren.Add(new TreeItemData
|
||||||
{
|
{
|
||||||
|
Type = TreeItemType.CHAT,
|
||||||
|
Depth = 1,
|
||||||
|
Branch = WorkspaceBranch.TEMPORARY_CHATS,
|
||||||
|
Text = chatName,
|
||||||
|
Icon = Icons.Material.Filled.Timer,
|
||||||
Expandable = false,
|
Expandable = false,
|
||||||
Value = new TreeItemData
|
Path = tempChatDirPath,
|
||||||
{
|
LastEditTime = lastEditTime,
|
||||||
Type = TreeItemType.CHAT,
|
|
||||||
Depth = 1,
|
|
||||||
Branch = WorkspaceBranch.TEMPORARY_CHATS,
|
|
||||||
Text = chatName,
|
|
||||||
Icon = Icons.Material.Filled.Timer,
|
|
||||||
Expandable = false,
|
|
||||||
Path = tempChatDirPath,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return tempChildren;
|
var result = new List<TreeItemData<ITreeItem>>(tempChildren.OrderByDescending(n => n.LastEditTime).Select(n => new TreeItemData<ITreeItem>
|
||||||
|
{
|
||||||
|
Expandable = false,
|
||||||
|
Value = n,
|
||||||
|
}));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> LoadWorkspaceName(Guid workspaceId)
|
public async Task<string> LoadWorkspaceName(Guid workspaceId)
|
||||||
@@ -205,7 +207,7 @@ public partial class Workspaces : ComponentBase
|
|||||||
|
|
||||||
private async Task<IReadOnlyCollection<TreeItemData<ITreeItem>>> LoadWorkspaceChats(string workspacePath)
|
private async Task<IReadOnlyCollection<TreeItemData<ITreeItem>>> LoadWorkspaceChats(string workspacePath)
|
||||||
{
|
{
|
||||||
var workspaceChats = new List<TreeItemData<ITreeItem>>();
|
var workspaceChats = new List<TreeItemData>();
|
||||||
|
|
||||||
// Enumerate the workspace directory:
|
// Enumerate the workspace directory:
|
||||||
foreach (var chatPath in Directory.EnumerateDirectories(workspacePath))
|
foreach (var chatPath in Directory.EnumerateDirectories(workspacePath))
|
||||||
@@ -213,30 +215,37 @@ public partial class Workspaces : ComponentBase
|
|||||||
// Read the `name` file:
|
// Read the `name` file:
|
||||||
var chatNamePath = Path.Join(chatPath, "name");
|
var chatNamePath = Path.Join(chatPath, "name");
|
||||||
var chatName = await File.ReadAllTextAsync(chatNamePath, Encoding.UTF8);
|
var chatName = await File.ReadAllTextAsync(chatNamePath, Encoding.UTF8);
|
||||||
|
|
||||||
|
// Read the last change time of the chat:
|
||||||
|
var chatThreadPath = Path.Join(chatPath, "thread.json");
|
||||||
|
var lastEditTime = File.GetLastWriteTimeUtc(chatThreadPath);
|
||||||
|
|
||||||
workspaceChats.Add(new TreeItemData<ITreeItem>
|
workspaceChats.Add(new TreeItemData
|
||||||
{
|
{
|
||||||
|
Type = TreeItemType.CHAT,
|
||||||
|
Depth = 2,
|
||||||
|
Branch = WorkspaceBranch.WORKSPACES,
|
||||||
|
Text = chatName,
|
||||||
|
Icon = Icons.Material.Filled.Chat,
|
||||||
Expandable = false,
|
Expandable = false,
|
||||||
Value = new TreeItemData
|
Path = chatPath,
|
||||||
{
|
LastEditTime = lastEditTime,
|
||||||
Type = TreeItemType.CHAT,
|
|
||||||
Depth = 2,
|
|
||||||
Branch = WorkspaceBranch.WORKSPACES,
|
|
||||||
Text = chatName,
|
|
||||||
Icon = Icons.Material.Filled.Chat,
|
|
||||||
Expandable = false,
|
|
||||||
Path = chatPath,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
workspaceChats.Add(new TreeItemData<ITreeItem>
|
var result = new List<TreeItemData<ITreeItem>>(workspaceChats.OrderByDescending(n => n.LastEditTime).Select(n => new TreeItemData<ITreeItem>
|
||||||
|
{
|
||||||
|
Expandable = false,
|
||||||
|
Value = n,
|
||||||
|
}));
|
||||||
|
|
||||||
|
result.Add(new()
|
||||||
{
|
{
|
||||||
Expandable = false,
|
Expandable = false,
|
||||||
Value = new TreeButton(WorkspaceBranch.WORKSPACES, 2, "Add chat",Icons.Material.Filled.AddComment, () => this.AddChat(workspacePath)),
|
Value = new TreeButton(WorkspaceBranch.WORKSPACES, 2, "Add chat",Icons.Material.Filled.AddComment, () => this.AddChat(workspacePath)),
|
||||||
});
|
});
|
||||||
|
|
||||||
return workspaceChats;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task StoreChat(ChatThread chat)
|
public async Task StoreChat(ChatThread chat)
|
||||||
@@ -1,12 +1,3 @@
|
|||||||
@using System.Net.Http
|
@using AIStudio
|
||||||
@using System.Net.Http.Json
|
@using AIStudio.Tools
|
||||||
@using Microsoft.AspNetCore.Components.Forms
|
|
||||||
@using Microsoft.AspNetCore.Components.Routing
|
|
||||||
@using Microsoft.AspNetCore.Components.Web
|
|
||||||
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
|
||||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
|
||||||
@using Microsoft.JSInterop
|
|
||||||
@using AIStudio
|
|
||||||
@using AIStudio.Components
|
|
||||||
@using AIStudio.Components.Blocks
|
|
||||||
@using MudBlazor
|
@using MudBlazor
|
||||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace AIStudio.Components.CommonDialogs;
|
namespace AIStudio.Dialogs;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A confirmation dialog that can be used to ask the user for confirmation.
|
/// A confirmation dialog that can be used to ask the user for confirmation.
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
namespace AIStudio.Components.CommonDialogs;
|
namespace AIStudio.Dialogs;
|
||||||
|
|
||||||
public static class DialogOptions
|
public static class DialogOptions
|
||||||
{
|
{
|
||||||
File renamed without changes.
Loaded 100 of 166 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user