Added documentation

This commit is contained in:
Thorsten Sommer 2025-02-15 15:22:02 +01:00
parent a999f47366
commit 3567a42bb0
Signed by: tsommer
GPG Key ID: 371BBA77A02C0108

View File

@ -70,21 +70,40 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
// Apply the filters for the message bus:
this.ApplyFilters([], [ Event.HAS_CHAT_UNSAVED_CHANGES, Event.RESET_CHAT_STATE, Event.CHAT_STREAMING_DONE, Event.WORKSPACE_LOADED_CHAT_CHANGED ]); this.ApplyFilters([], [ Event.HAS_CHAT_UNSAVED_CHANGES, Event.RESET_CHAT_STATE, Event.CHAT_STREAMING_DONE, Event.WORKSPACE_LOADED_CHAT_CHANGED ]);
// Configure the spellchecking for the user input: // Configure the spellchecking for the user input:
this.SettingsManager.InjectSpellchecking(USER_INPUT_ATTRIBUTES); this.SettingsManager.InjectSpellchecking(USER_INPUT_ATTRIBUTES);
// Get the preselected profile:
this.currentProfile = this.SettingsManager.GetPreselectedProfile(Tools.Components.CHAT); this.currentProfile = this.SettingsManager.GetPreselectedProfile(Tools.Components.CHAT);
//
// Check for deferred messages of the kind 'SEND_TO_CHAT',
// aka the user sends an assistant result to the chat:
//
var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages<ChatThread>(Event.SEND_TO_CHAT).FirstOrDefault(); var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages<ChatThread>(Event.SEND_TO_CHAT).FirstOrDefault();
if (deferredContent is not null) if (deferredContent is not null)
{ {
//
// Yes, the user sent an assistant result to the chat.
//
// Use chat thread sent by the user:
this.ChatThread = deferredContent; this.ChatThread = deferredContent;
this.Logger.LogInformation($"The chat '{this.ChatThread.Name}' with {this.ChatThread.Blocks.Count} messages was deferred and will be rendered now."); this.Logger.LogInformation($"The chat '{this.ChatThread.Name}' with {this.ChatThread.Blocks.Count} messages was deferred and will be rendered now.");
await this.ChatThreadChanged.InvokeAsync(this.ChatThread); await this.ChatThreadChanged.InvokeAsync(this.ChatThread);
// We know already that the chat thread is not null,
// but we have to check it again for the nullability
// for the compiler:
if (this.ChatThread is not null) if (this.ChatThread is not null)
{ {
//
// Check if the chat thread has a name. If not, we
// generate the name now:
//
if (string.IsNullOrWhiteSpace(this.ChatThread.Name)) if (string.IsNullOrWhiteSpace(this.ChatThread.Name))
{ {
var firstUserBlock = this.ChatThread.Blocks.FirstOrDefault(x => x.Role == ChatRole.USER); var firstUserBlock = this.ChatThread.Blocks.FirstOrDefault(x => x.Role == ChatRole.USER);
@ -98,12 +117,19 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
} }
} }
//
// Check if the user wants to store the chat automatically:
//
if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is WorkspaceStorageBehavior.STORE_CHATS_AUTOMATICALLY) if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is WorkspaceStorageBehavior.STORE_CHATS_AUTOMATICALLY)
{ {
this.autoSaveEnabled = true; this.autoSaveEnabled = true;
this.mustStoreChat = true; this.mustStoreChat = true;
// Ensure the workspace exists: //
// When a standard workspace is used, we have to ensure
// that the workspace is available:
//
if(this.ChatThread.WorkspaceId == KnownWorkspaces.ERI_SERVER_WORKSPACE_ID) if(this.ChatThread.WorkspaceId == KnownWorkspaces.ERI_SERVER_WORKSPACE_ID)
await WorkspaceBehaviour.EnsureERIServerWorkspace(); await WorkspaceBehaviour.EnsureERIServerWorkspace();
@ -113,13 +139,30 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
} }
} }
//
// Check if the user wants to show the latest message after loading:
//
if (this.SettingsManager.ConfigurationData.Chat.ShowLatestMessageAfterLoading) if (this.SettingsManager.ConfigurationData.Chat.ShowLatestMessageAfterLoading)
{ {
//
// We cannot scroll to the bottom right now because the
// chat component is not rendered yet. We have to wait for
// the rendering process to finish. Thus, we set a flag
// to scroll to the bottom after the rendering process.:
//
this.mustScrollToBottomAfterRender = true; this.mustScrollToBottomAfterRender = true;
this.scrollRenderCountdown = 4; this.scrollRenderCountdown = 4;
this.StateHasChanged(); this.StateHasChanged();
} }
//
// Check if another component deferred the loading of a chat.
//
// This is used, e.g., for the bias-of-the-day component:
// when the bias for this day was already produced, the bias
// component sends a message to the chat component to load
// the chat with the bias:
//
var deferredLoading = MessageBus.INSTANCE.CheckDeferredMessages<LoadChat>(Event.LOAD_CHAT).FirstOrDefault(); var deferredLoading = MessageBus.INSTANCE.CheckDeferredMessages<LoadChat>(Event.LOAD_CHAT).FirstOrDefault();
if (deferredLoading != default) if (deferredLoading != default)
{ {
@ -128,6 +171,11 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
this.Logger.LogInformation($"The loading of the chat '{this.loadChat.ChatId}' was deferred and will be loaded now."); this.Logger.LogInformation($"The loading of the chat '{this.loadChat.ChatId}' was deferred and will be loaded now.");
} }
//
// When for whatever reason we have a chat thread, we have to
// ensure that the corresponding workspace id is set and the
// workspace name is loaded:
//
if (this.ChatThread is not null) if (this.ChatThread is not null)
{ {
this.currentWorkspaceId = this.ChatThread.WorkspaceId; this.currentWorkspaceId = this.ChatThread.WorkspaceId;
@ -135,6 +183,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
this.WorkspaceName(this.currentWorkspaceName); this.WorkspaceName(this.currentWorkspaceName);
} }
// Select the correct provider:
await this.SelectProviderWhenLoadingChat(); await this.SelectProviderWhenLoadingChat();
await base.OnInitializedAsync(); await base.OnInitializedAsync();
} }
@ -416,6 +465,10 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
private async Task StartNewChat(bool useSameWorkspace = false, bool deletePreviousChat = false) private async Task StartNewChat(bool useSameWorkspace = false, bool deletePreviousChat = false)
{ {
//
// Want the user to manage the chat storage manually? In that case, we have to ask the user
// about possible data loss:
//
if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is WorkspaceStorageBehavior.STORE_CHATS_MANUALLY && this.hasUnsavedChanges) if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is WorkspaceStorageBehavior.STORE_CHATS_MANUALLY && this.hasUnsavedChanges)
{ {
var dialogParameters = new DialogParameters var dialogParameters = new DialogParameters
@ -429,6 +482,9 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
return; return;
} }
//
// Delete the previous chat when desired and necessary:
//
if (this.ChatThread is not null && deletePreviousChat) if (this.ChatThread is not null && deletePreviousChat)
{ {
string chatPath; string chatPath;
@ -443,10 +499,16 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
await this.Workspaces.DeleteChat(chatPath, askForConfirmation: false, unloadChat: true); await this.Workspaces.DeleteChat(chatPath, askForConfirmation: false, unloadChat: true);
} }
//
// Reset our state:
//
this.isStreaming = false; this.isStreaming = false;
this.hasUnsavedChanges = false; this.hasUnsavedChanges = false;
this.userInput = string.Empty; this.userInput = string.Empty;
//
// Reset the LLM provider considering the user's settings:
//
switch (this.SettingsManager.ConfigurationData.Chat.AddChatProviderBehavior) switch (this.SettingsManager.ConfigurationData.Chat.AddChatProviderBehavior)
{ {
case AddChatProviderBehavior.ADDED_CHATS_USE_DEFAULT_PROVIDER: case AddChatProviderBehavior.ADDED_CHATS_USE_DEFAULT_PROVIDER:
@ -465,8 +527,16 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
break; break;
} }
//
// Reset the chat thread or create a new one:
//
if (!useSameWorkspace) if (!useSameWorkspace)
{ {
//
// When the user wants to start a new chat outside the current workspace,
// we have to reset the workspace id and the workspace name. Also, we have
// to reset the chat thread:
//
this.ChatThread = null; this.ChatThread = null;
this.currentWorkspaceId = Guid.Empty; this.currentWorkspaceId = Guid.Empty;
this.currentWorkspaceName = string.Empty; this.currentWorkspaceName = string.Empty;
@ -474,6 +544,11 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
} }
else else
{ {
//
// When the user wants to start a new chat in the same workspace, we have to
// reset the chat thread only. The workspace id and the workspace name remain
// the same:
//
this.ChatThread = new() this.ChatThread = new()
{ {
SelectedProvider = this.Provider.Id, SelectedProvider = this.Provider.Id,
@ -488,6 +563,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
} }
this.userInput = string.Empty; this.userInput = string.Empty;
// Notify the parent component about the change:
await this.ChatThreadChanged.InvokeAsync(this.ChatThread); await this.ChatThreadChanged.InvokeAsync(this.ChatThread);
} }