mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2025-08-21 04:12:56 +00:00
First version before review from Thorsten
This commit is contained in:
parent
85a867459e
commit
5f2da6acf6
10
app/MindWork AI Studio/Chat/ChatRoles.cs
Normal file
10
app/MindWork AI Studio/Chat/ChatRoles.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace AIStudio.Chat;
|
||||||
|
|
||||||
|
public static class ChatRoles
|
||||||
|
{
|
||||||
|
public static IEnumerable<ChatRole> ChatTemplateRoles()
|
||||||
|
{
|
||||||
|
yield return ChatRole.SYSTEM;
|
||||||
|
yield return ChatRole.AI;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
@inherits SettingsPanelBase
|
||||||
|
|
||||||
|
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.Person4" HeaderText="@T("Configure Chat Templates")">
|
||||||
|
<MudText Typo="Typo.h4" Class="mb-3">
|
||||||
|
@T("Your Chat Templates")
|
||||||
|
</MudText>
|
||||||
|
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
|
||||||
|
@T("Store personal data about yourself in various profiles so that the AIs know your personal context. This saves you from having to explain your context each time, for example, in every chat. When you have different roles, you can create a profile for each role.")
|
||||||
|
</MudJustifiedText>
|
||||||
|
|
||||||
|
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
|
||||||
|
@T("Are you a project manager in a research facility? You might want to create a profile for your project management activities, one for your scientific work, and a profile for when you need to write program code. In these profiles, you can record how much experience you have or which methods you like or dislike using. Later, you can choose when and where you want to use each profile.")
|
||||||
|
</MudJustifiedText>
|
||||||
|
<MudTable Items="@this.SettingsManager.ConfigurationData.ChatTemplates" Hover="@true" Class="border-dashed border rounded-lg">
|
||||||
|
<ColGroup>
|
||||||
|
<col style="width: 3em;"/>
|
||||||
|
<col/>
|
||||||
|
<col style="width: 40em;"/>
|
||||||
|
</ColGroup>
|
||||||
|
<HeaderContent>
|
||||||
|
<MudTh>#</MudTh>
|
||||||
|
<MudTh>@T("Chat Template Name")</MudTh>
|
||||||
|
<MudTh>@T("Actions")</MudTh>
|
||||||
|
</HeaderContent>
|
||||||
|
<RowTemplate>
|
||||||
|
<MudTd>@context.Num</MudTd>
|
||||||
|
<MudTd>@context.Name</MudTd>
|
||||||
|
<MudTd>
|
||||||
|
<MudStack Row="true" Class="mb-2 mt-2" Wrap="Wrap.Wrap">
|
||||||
|
<MudTooltip Text="@T("Edit")">
|
||||||
|
<MudIconButton Variant="Variant.Filled" Color="Color.Info" Icon="@Icons.Material.Filled.Edit" OnClick="() => this.EditChatTemplate(context)"/>
|
||||||
|
</MudTooltip>
|
||||||
|
<MudTooltip Text="@T("Delete")">
|
||||||
|
<MudIconButton Variant="Variant.Filled" Color="Color.Error" Icon="@Icons.Material.Filled.Delete" OnClick="() => this.DeleteChatTemplate(context)"/>
|
||||||
|
</MudTooltip>
|
||||||
|
</MudStack>
|
||||||
|
</MudTd>
|
||||||
|
</RowTemplate>
|
||||||
|
</MudTable>
|
||||||
|
|
||||||
|
@if(this.SettingsManager.ConfigurationData.ChatTemplates.Count == 0)
|
||||||
|
{
|
||||||
|
<MudText Typo="Typo.h6" Class="mt-3">
|
||||||
|
@T("No chat templates configured yet.")
|
||||||
|
</MudText>
|
||||||
|
}
|
||||||
|
|
||||||
|
<MudButton Variant="Variant.Filled" Color="@Color.Primary" StartIcon="@Icons.Material.Filled.AddRoad" Class="mt-3 mb-6" OnClick="@this.AddChatTemplate">
|
||||||
|
@T("Add Chat Template")
|
||||||
|
</MudButton>
|
||||||
|
</ExpansionPanel>
|
@ -0,0 +1,74 @@
|
|||||||
|
using AIStudio.Dialogs;
|
||||||
|
using AIStudio.Settings;
|
||||||
|
|
||||||
|
using DialogOptions = AIStudio.Dialogs.DialogOptions;
|
||||||
|
|
||||||
|
namespace AIStudio.Components.Settings;
|
||||||
|
|
||||||
|
public partial class SettingsPanelChatTemplates : SettingsPanelBase
|
||||||
|
{
|
||||||
|
private async Task AddChatTemplate()
|
||||||
|
{
|
||||||
|
var dialogParameters = new DialogParameters<ChatTemplateDialog>
|
||||||
|
{
|
||||||
|
{ x => x.IsEditing, false },
|
||||||
|
};
|
||||||
|
|
||||||
|
var dialogReference = await this.DialogService.ShowAsync<ChatTemplateDialog>(T("Add Chat Template"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||||
|
var dialogResult = await dialogReference.Result;
|
||||||
|
if (dialogResult is null || dialogResult.Canceled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var addedChatTemplate = (ChatTemplate)dialogResult.Data!;
|
||||||
|
addedChatTemplate = addedChatTemplate with { Num = this.SettingsManager.ConfigurationData.NextChatTemplateNum++ };
|
||||||
|
|
||||||
|
this.SettingsManager.ConfigurationData.ChatTemplates.Add(addedChatTemplate);
|
||||||
|
|
||||||
|
await this.SettingsManager.StoreSettings();
|
||||||
|
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task EditChatTemplate(ChatTemplate chatTemplate)
|
||||||
|
{
|
||||||
|
// TODO: additionall messages übergeben
|
||||||
|
var dialogParameters = new DialogParameters<ChatTemplateDialog>
|
||||||
|
{
|
||||||
|
{ x => x.DataNum, chatTemplate.Num },
|
||||||
|
{ x => x.DataId, chatTemplate.Id },
|
||||||
|
{ x => x.DataName, chatTemplate.Name },
|
||||||
|
{ x => x.DataSystemPrompt, chatTemplate.NeedToKnow },
|
||||||
|
// { x => x.DataActions, chatTemplate.Actions },
|
||||||
|
{ x => x.IsEditing, true },
|
||||||
|
// {x => x.AdditionalMessages, chatTemplate}, TODO
|
||||||
|
};
|
||||||
|
|
||||||
|
var dialogReference = await this.DialogService.ShowAsync<ChatTemplateDialog>(T("Edit Chat Template"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||||
|
var dialogResult = await dialogReference.Result;
|
||||||
|
if (dialogResult is null || dialogResult.Canceled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var editedChatTemplate = (ChatTemplate)dialogResult.Data!;
|
||||||
|
this.SettingsManager.ConfigurationData.ChatTemplates[this.SettingsManager.ConfigurationData.ChatTemplates.IndexOf(chatTemplate)] = editedChatTemplate;
|
||||||
|
|
||||||
|
await this.SettingsManager.StoreSettings();
|
||||||
|
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DeleteChatTemplate(ChatTemplate chatTemplate)
|
||||||
|
{
|
||||||
|
var dialogParameters = new DialogParameters
|
||||||
|
{
|
||||||
|
{ "Message", string.Format(T("Are you sure you want to delete the chat template '{0}'?"), chatTemplate.Name) },
|
||||||
|
};
|
||||||
|
|
||||||
|
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>(T("Delete Chat Template"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||||
|
var dialogResult = await dialogReference.Result;
|
||||||
|
if (dialogResult is null || dialogResult.Canceled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.SettingsManager.ConfigurationData.ChatTemplates.Remove(chatTemplate);
|
||||||
|
await this.SettingsManager.StoreSettings();
|
||||||
|
|
||||||
|
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||||
|
}
|
||||||
|
}
|
130
app/MindWork AI Studio/Dialogs/ChatTemplateDialog.razor
Normal file
130
app/MindWork AI Studio/Dialogs/ChatTemplateDialog.razor
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
@inherits MSGComponentBase
|
||||||
|
@inject ISnackbar Snackbar
|
||||||
|
|
||||||
|
<MudDialog>
|
||||||
|
<DialogContent>
|
||||||
|
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
|
||||||
|
@T("Store chat templates.")
|
||||||
|
</MudJustifiedText>
|
||||||
|
|
||||||
|
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
|
||||||
|
@T("Are you always using the same prompts and want a way of automatically using them?")
|
||||||
|
</MudJustifiedText>
|
||||||
|
|
||||||
|
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
|
||||||
|
@T("The name of the chat template is mandatory. Each chat template must have a unique name.")
|
||||||
|
</MudJustifiedText>
|
||||||
|
<MudForm @ref="@this.form" @bind-IsValid="@this.dataIsValid" @bind-Errors="@this.dataIssues">
|
||||||
|
@* ReSharper disable once CSharpWarnings::CS8974 *@
|
||||||
|
<MudTextField
|
||||||
|
T="string"
|
||||||
|
@bind-Text="@this.DataName"
|
||||||
|
Label="@T("Chat Template Name")"
|
||||||
|
Class="mb-3"
|
||||||
|
Immediate="@true"
|
||||||
|
MaxLength="40"
|
||||||
|
Counter="40"
|
||||||
|
Adornment="Adornment.Start"
|
||||||
|
AdornmentIcon="@Icons.Material.Filled.Badge"
|
||||||
|
AdornmentColor="Color.Info"
|
||||||
|
Validation="@this.ValidateName"
|
||||||
|
Variant="Variant.Outlined"
|
||||||
|
UserAttributes="@SPELLCHECK_ATTRIBUTES"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MudTextField
|
||||||
|
T="string"
|
||||||
|
@bind-Text="@this.DataSystemPrompt"
|
||||||
|
Validation="@this.ValidateSystemPrompt"
|
||||||
|
AdornmentIcon="@Icons.Material.Filled.ListAlt"
|
||||||
|
Adornment="Adornment.Start"
|
||||||
|
Immediate="@true"
|
||||||
|
Label="@T("What system prompt do you want to use?")"
|
||||||
|
Variant="Variant.Outlined"
|
||||||
|
Lines="6"
|
||||||
|
AutoGrow="@true"
|
||||||
|
MaxLines="12"
|
||||||
|
MaxLength="444"
|
||||||
|
Counter="444"
|
||||||
|
Class="mb-3"
|
||||||
|
UserAttributes="@SPELLCHECK_ATTRIBUTES"
|
||||||
|
HelperText="@T("Tell the AI your system prompt.")"
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
<MudTable Items="@additionalMessagesEntries" RowEditPreview="BackupItem" RowEditCancel="ResetItemToOriginalValues" RowEditCommit="ItemHasBeenCommitted" CanCancelEdit="true" CommitEditTooltip="Commit Changes" Elevation="10" Outlined="true">
|
||||||
|
<ToolBarContent>
|
||||||
|
<MudText Typo="Typo.h6">Additional messages</MudText>
|
||||||
|
<MudSpacer />
|
||||||
|
<MudButton Color="Color.Primary" Variant="Variant.Filled" OnClick="AddInitialMessage" StartIcon="@Icons.Material.Filled.Add" Disabled="@initialAddButtonDisabled">Start using messages</MudButton>
|
||||||
|
</ToolBarContent>
|
||||||
|
<HeaderContent>
|
||||||
|
<MudTh>Role</MudTh>
|
||||||
|
<MudTh>Entry</MudTh>
|
||||||
|
<MudTh>Actions</MudTh>
|
||||||
|
</HeaderContent>
|
||||||
|
<RowTemplate>
|
||||||
|
<MudTd DataLabel="Role">@context.Role</MudTd>
|
||||||
|
<MudTd DataLabel="Message">@context.Entry</MudTd>
|
||||||
|
<MudTd style="text-align: center">
|
||||||
|
<MudIconButton Icon="@Icons.Material.Filled.Add"
|
||||||
|
Color="Color.Success"
|
||||||
|
Size="Size.Small"
|
||||||
|
OnClick="@(() => AddNewMessageBelow(context))"
|
||||||
|
/>
|
||||||
|
<MudIconButton Icon="@Icons.Material.Filled.Delete"
|
||||||
|
Color="Color.Error"
|
||||||
|
Size="Size.Small"
|
||||||
|
OnClick="@(() => RemoveMessage(context))"
|
||||||
|
/>
|
||||||
|
</MudTd>
|
||||||
|
</RowTemplate>
|
||||||
|
<RowEditingTemplate>
|
||||||
|
<MudTd DataLabel="Role">
|
||||||
|
<MudSelect @bind-Value="context.Role" Required>
|
||||||
|
@foreach (var role in availableRoles)
|
||||||
|
{
|
||||||
|
<MudSelectItem Value="@role">@role</MudSelectItem>
|
||||||
|
}
|
||||||
|
</MudSelect>
|
||||||
|
</MudTd>
|
||||||
|
<MudTd DataLabel="Message">
|
||||||
|
<MudTextField @bind-Value="context.Entry" Required />
|
||||||
|
</MudTd>
|
||||||
|
<MudTd style="text-align: center">
|
||||||
|
<MudIconButton Icon="@Icons.Material.Filled.Add"
|
||||||
|
Color="Color.Success"
|
||||||
|
Size="Size.Small"
|
||||||
|
OnClick="@(() => AddNewMessageBelow(context))"
|
||||||
|
/>
|
||||||
|
<MudIconButton Icon="@Icons.Material.Filled.Delete"
|
||||||
|
Color="Color.Error"
|
||||||
|
Size="Size.Small"
|
||||||
|
OnClick="@(() => RemoveMessage(context))"
|
||||||
|
/>
|
||||||
|
</MudTd>
|
||||||
|
</RowEditingTemplate>
|
||||||
|
<PagerContent>
|
||||||
|
<MudTablePager />
|
||||||
|
</PagerContent>
|
||||||
|
</MudTable>
|
||||||
|
|
||||||
|
</MudForm>
|
||||||
|
<Issues IssuesData="@this.dataIssues"/>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<MudButton OnClick="@this.Cancel" Variant="Variant.Filled">
|
||||||
|
@T("Cancel")
|
||||||
|
</MudButton>
|
||||||
|
<MudButton OnClick="@this.Store" Variant="Variant.Filled" Color="Color.Primary">
|
||||||
|
@if(this.IsEditing)
|
||||||
|
{
|
||||||
|
@T("Update")
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@T("Add")
|
||||||
|
}
|
||||||
|
</MudButton>
|
||||||
|
</DialogActions>
|
||||||
|
</MudDialog>
|
233
app/MindWork AI Studio/Dialogs/ChatTemplateDialog.razor.cs
Normal file
233
app/MindWork AI Studio/Dialogs/ChatTemplateDialog.razor.cs
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
using AIStudio.Chat;
|
||||||
|
using AIStudio.Components;
|
||||||
|
using AIStudio.Settings;
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
|
namespace AIStudio.Dialogs;
|
||||||
|
|
||||||
|
public partial class ChatTemplateDialog : MSGComponentBase
|
||||||
|
{
|
||||||
|
[CascadingParameter]
|
||||||
|
private IMudDialogInstance MudDialog { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The chat template's number in the list.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public uint DataNum { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The chat template's ID.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public string DataId { get; set; } = Guid.NewGuid().ToString();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The chat template name chosen by the user.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public string DataName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// What is the system prompt?
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public string DataSystemPrompt { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Should the dialog be in editing mode?
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public bool IsEditing { get; init; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public List<EntryItem> AdditionalMessages { get; set; } = [];
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
private ILogger<ProviderDialog> Logger { get; init; } = null!;
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, object?> SPELLCHECK_ATTRIBUTES = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The list of used chat template names. We need this to check for uniqueness.
|
||||||
|
/// </summary>
|
||||||
|
private List<string> UsedNames { get; set; } = [];
|
||||||
|
|
||||||
|
private bool dataIsValid;
|
||||||
|
private string[] dataIssues = [];
|
||||||
|
private string dataEditingPreviousName = string.Empty;
|
||||||
|
|
||||||
|
private EntryItem messageEntryBeforeEdit;
|
||||||
|
private readonly List<EntryItem> additionalMessagesEntries = [];
|
||||||
|
private readonly List<string> availableRoles = ["User", "Assistant"];
|
||||||
|
private bool initialAddButtonDisabled = false;
|
||||||
|
|
||||||
|
// We get the form reference from Blazor code to validate it manually:
|
||||||
|
private MudForm form = null!;
|
||||||
|
|
||||||
|
private ChatTemplate CreateChatTemplateSettings() => new()
|
||||||
|
{
|
||||||
|
Num = this.DataNum,
|
||||||
|
Id = this.DataId,
|
||||||
|
|
||||||
|
Name = this.DataName,
|
||||||
|
NeedToKnow = this.DataSystemPrompt,
|
||||||
|
// AdditionalMessages = this.additionalMessagesEntries,
|
||||||
|
Actions = string.Empty,
|
||||||
|
};
|
||||||
|
|
||||||
|
private void RemoveMessage(EntryItem item)
|
||||||
|
{
|
||||||
|
this.additionalMessagesEntries.Remove(item);
|
||||||
|
this.Snackbar.Add("Entry removed", Severity.Info);
|
||||||
|
this.initialAddButtonDisabled = this.additionalMessagesEntries.Count > 0;
|
||||||
|
|
||||||
|
// ChatRoles.ChatTemplateRoles() // TODO: -> darauf foreach für alle Rollen in der Tabelle
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddInitialMessage()
|
||||||
|
{
|
||||||
|
var newEntry = new EntryItem
|
||||||
|
{
|
||||||
|
Role = availableRoles[0], // Default to first role ("User")
|
||||||
|
Entry = "Your message"
|
||||||
|
};
|
||||||
|
|
||||||
|
this.additionalMessagesEntries.Add(newEntry);
|
||||||
|
this.Snackbar.Add("Initial entry added", Severity.Success);
|
||||||
|
this.initialAddButtonDisabled = this.additionalMessagesEntries.Count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddNewMessageBelow(EntryItem currentItem)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Create new entry with a valid role
|
||||||
|
var newEntry = new EntryItem
|
||||||
|
{
|
||||||
|
Role = availableRoles.FirstOrDefault(role => role != currentItem.Role) ?? availableRoles[0], // Default to role not used in the previous entry
|
||||||
|
Entry = "Your message"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Rest of the method remains the same
|
||||||
|
var index = this.additionalMessagesEntries.IndexOf(currentItem);
|
||||||
|
|
||||||
|
if (index >= 0)
|
||||||
|
{
|
||||||
|
this.additionalMessagesEntries.Insert(index + 1, newEntry);
|
||||||
|
this.Snackbar.Add("New entry added", Severity.Success);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.additionalMessagesEntries.Add(newEntry);
|
||||||
|
this.Snackbar.Add("New entry added", Severity.Success);
|
||||||
|
}
|
||||||
|
this.initialAddButtonDisabled = this.additionalMessagesEntries.Count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BackupItem(object element)
|
||||||
|
{
|
||||||
|
this.messageEntryBeforeEdit = new()
|
||||||
|
{
|
||||||
|
Role = ((EntryItem)element).Role,
|
||||||
|
Entry = ((EntryItem)element).Entry
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ItemHasBeenCommitted(object element)
|
||||||
|
{
|
||||||
|
this.Snackbar.Add("Changes saved", Severity.Success);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResetItemToOriginalValues(object element)
|
||||||
|
{
|
||||||
|
((EntryItem)element).Role = this.messageEntryBeforeEdit.Role;
|
||||||
|
((EntryItem)element).Entry = this.messageEntryBeforeEdit.Entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EntryItem
|
||||||
|
{
|
||||||
|
public required string Role { get; set; }
|
||||||
|
public required string Entry { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Overrides of ComponentBase
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
// Configure the spellchecking for the instance name input:
|
||||||
|
this.SettingsManager.InjectSpellchecking(SPELLCHECK_ATTRIBUTES);
|
||||||
|
|
||||||
|
// Load the used instance names:
|
||||||
|
this.UsedNames = this.SettingsManager.ConfigurationData.ChatTemplates.Select(x => x.Name.ToLowerInvariant()).ToList();
|
||||||
|
|
||||||
|
// When editing, we need to load the data:
|
||||||
|
if(this.IsEditing)
|
||||||
|
{
|
||||||
|
this.dataEditingPreviousName = this.DataName.ToLowerInvariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
await base.OnInitializedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
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(!this.IsEditing && firstRender)
|
||||||
|
this.form.ResetValidation();
|
||||||
|
|
||||||
|
await base.OnAfterRenderAsync(firstRender);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private async Task Store()
|
||||||
|
{
|
||||||
|
await this.form.Validate();
|
||||||
|
|
||||||
|
// When the data is not valid, we don't store it:
|
||||||
|
if (!this.dataIsValid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Use the data model to store the chat template.
|
||||||
|
// We just return this data to the parent component:
|
||||||
|
var addedChatTemplateSettings = this.CreateChatTemplateSettings();
|
||||||
|
|
||||||
|
if(this.IsEditing)
|
||||||
|
this.Logger.LogInformation($"Edited chat template '{addedChatTemplateSettings.Name}'.");
|
||||||
|
else
|
||||||
|
this.Logger.LogInformation($"Created chat template '{addedChatTemplateSettings.Name}'.");
|
||||||
|
|
||||||
|
this.MudDialog.Close(DialogResult.Ok(addedChatTemplateSettings));
|
||||||
|
}
|
||||||
|
|
||||||
|
private string? ValidateSystemPrompt(string text)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(this.DataSystemPrompt))// && string.IsNullOrWhiteSpace(this.DataActions))
|
||||||
|
return T("Please enter the system prompt.");
|
||||||
|
|
||||||
|
if(text.Length > 444)
|
||||||
|
return T("The text must not exceed 444 characters.");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string? ValidateName(string name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(name))
|
||||||
|
return T("Please enter a name for the chat template.");
|
||||||
|
|
||||||
|
if (name.Length > 40)
|
||||||
|
return T("The chat template name must not exceed 40 characters.");
|
||||||
|
|
||||||
|
// The instance name must be unique:
|
||||||
|
var lowerName = name.ToLowerInvariant();
|
||||||
|
if (lowerName != this.dataEditingPreviousName && this.UsedNames.Contains(lowerName))
|
||||||
|
return T("The chat template name must be unique; the chosen name is already in use.");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cancel() => this.MudDialog.Cancel();
|
||||||
|
}
|
@ -16,6 +16,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
<SettingsPanelProfiles AvailableLLMProvidersFunc="() => this.availableLLMProviders"/>
|
<SettingsPanelProfiles AvailableLLMProvidersFunc="() => this.availableLLMProviders"/>
|
||||||
|
<SettingsPanelChatTemplates AvailableLLMProvidersFunc="() => this.availableLLMProviders"/>
|
||||||
<SettingsPanelApp AvailableLLMProvidersFunc="() => this.availableLLMProviders"/>
|
<SettingsPanelApp AvailableLLMProvidersFunc="() => this.availableLLMProviders"/>
|
||||||
<SettingsPanelChat AvailableLLMProvidersFunc="() => this.availableLLMProviders"/>
|
<SettingsPanelChat AvailableLLMProvidersFunc="() => this.availableLLMProviders"/>
|
||||||
<SettingsPanelWorkspaces AvailableLLMProvidersFunc="() => this.availableLLMProviders"/>
|
<SettingsPanelWorkspaces AvailableLLMProvidersFunc="() => this.availableLLMProviders"/>
|
||||||
|
64
app/MindWork AI Studio/Settings/ChatTemplate.cs
Normal file
64
app/MindWork AI Studio/Settings/ChatTemplate.cs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
using AIStudio.Tools.PluginSystem;
|
||||||
|
|
||||||
|
namespace AIStudio.Settings;
|
||||||
|
|
||||||
|
public readonly record struct ChatTemplate(uint Num, string Id, string Name, string NeedToKnow, string Actions) //, CategoryTypes.List AdditionalMessages)
|
||||||
|
{
|
||||||
|
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(Profile).Namespace, nameof(Profile));
|
||||||
|
|
||||||
|
public static readonly Profile NO_PROFILE = new()
|
||||||
|
{
|
||||||
|
Name = TB("Use no profile"),
|
||||||
|
NeedToKnow = string.Empty,
|
||||||
|
Actions = string.Empty,
|
||||||
|
Id = Guid.Empty.ToString(),
|
||||||
|
Num = uint.MaxValue,
|
||||||
|
// AdditionalMessages = [],
|
||||||
|
};
|
||||||
|
|
||||||
|
#region Overrides of ValueType
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a string that represents the profile in a human-readable format.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A string that represents the profile in a human-readable format.</returns>
|
||||||
|
public override string ToString() => this.Name;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public string ToSystemPrompt()
|
||||||
|
{
|
||||||
|
if(this.Num == uint.MaxValue)
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
var needToKnow =
|
||||||
|
$"""
|
||||||
|
What should you know about the user?
|
||||||
|
|
||||||
|
```
|
||||||
|
{this.NeedToKnow}
|
||||||
|
```
|
||||||
|
""";
|
||||||
|
|
||||||
|
var actions =
|
||||||
|
$"""
|
||||||
|
The user wants you to consider the following things.
|
||||||
|
|
||||||
|
```
|
||||||
|
{this.Actions}
|
||||||
|
```
|
||||||
|
""";
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(this.NeedToKnow))
|
||||||
|
return actions;
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(this.Actions))
|
||||||
|
return needToKnow;
|
||||||
|
|
||||||
|
return $"""
|
||||||
|
{needToKnow}
|
||||||
|
|
||||||
|
{actions}
|
||||||
|
""";
|
||||||
|
}
|
||||||
|
}
|
@ -36,6 +36,11 @@ public sealed class Data
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public List<Profile> Profiles { get; init; } = [];
|
public List<Profile> Profiles { get; init; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List of configured chat templates.
|
||||||
|
/// </summary>
|
||||||
|
public List<ChatTemplate> ChatTemplates { get; init; } = [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// List of enabled plugins.
|
/// List of enabled plugins.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -61,6 +66,11 @@ public sealed class Data
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public uint NextProfileNum { get; set; } = 1;
|
public uint NextProfileNum { get; set; } = 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The next chat template number to use.
|
||||||
|
/// </summary>
|
||||||
|
public uint NextChatTemplateNum { get; set; } = 1;
|
||||||
|
|
||||||
public DataApp App { get; init; } = new();
|
public DataApp App { get; init; } = new();
|
||||||
|
|
||||||
public DataChat Chat { get; init; } = new();
|
public DataChat Chat { get; init; } = new();
|
||||||
|
Loading…
Reference in New Issue
Block a user