AI-Studio/app/MindWork AI Studio/Chat/ContentBlockComponent.razor.cs

125 lines
3.7 KiB
C#
Raw Normal View History

2025-01-02 14:24:15 +00:00
using AIStudio.Settings;
using Microsoft.AspNetCore.Components;
2024-09-01 18:10:03 +00:00
using RustService = AIStudio.Tools.RustService;
namespace AIStudio.Chat;
2024-05-04 09:11:09 +00:00
/// <summary>
/// The UI component for a chat content block, i.e., for any IContent.
/// </summary>
public partial class ContentBlockComponent : ComponentBase
{
2024-05-04 09:11:09 +00:00
/// <summary>
/// The role of the chat content block.
/// </summary>
[Parameter]
public ChatRole Role { get; init; } = ChatRole.NONE;
/// <summary>
/// The content.
/// </summary>
[Parameter]
public IContent Content { get; init; } = new ContentText();
/// <summary>
/// The content type.
/// </summary>
[Parameter]
public ContentType Type { get; init; } = ContentType.NONE;
/// <summary>
/// When was the content created?
/// </summary>
[Parameter]
public DateTimeOffset Time { get; init; }
2024-07-14 19:46:17 +00:00
/// <summary>
/// Optional CSS classes.
/// </summary>
[Parameter]
public string Class { get; set; } = string.Empty;
2024-05-04 09:11:09 +00:00
[Inject]
2024-09-01 18:10:03 +00:00
private RustService RustService { get; init; } = null!;
2024-05-04 09:11:09 +00:00
[Inject]
private ISnackbar Snackbar { get; init; } = null!;
2025-01-02 14:24:15 +00:00
[Inject]
private SettingsManager SettingsManager { get; init; } = null!;
2024-05-04 09:11:09 +00:00
private bool HideContent { get; set; }
#region Overrides of ComponentBase
protected override async Task OnInitializedAsync()
{
// Register the streaming events:
this.Content.StreamingDone = this.AfterStreaming;
this.Content.StreamingEvent = () => this.InvokeAsync(this.StateHasChanged);
await base.OnInitializedAsync();
}
/// <summary>
/// Gets called when the content stream ended.
/// </summary>
private async Task AfterStreaming()
{
// Might be called from a different thread, so we need to invoke the UI thread:
2024-10-28 14:41:00 +00:00
await this.InvokeAsync(async () =>
2024-05-04 09:11:09 +00:00
{
//
// Issue we try to solve: When the content changes during streaming,
// Blazor might fail to see all changes made to the render tree.
// This happens mostly when Markdown code blocks are streamed.
//
// Hide the content for a short time:
this.HideContent = true;
// Let Blazor update the UI, i.e., to see the render tree diff:
this.StateHasChanged();
// Show the content again:
this.HideContent = false;
// Let Blazor update the UI, i.e., to see the render tree diff:
this.StateHasChanged();
2024-10-28 14:41:00 +00:00
// Inform the chat that the streaming is done:
await MessageBus.INSTANCE.SendMessage<bool>(this, Event.CHAT_STREAMING_DONE);
2024-05-04 09:11:09 +00:00
});
}
#endregion
/// <summary>
/// Copy this block's content to the clipboard.
/// </summary>
private async Task CopyToClipboard()
{
switch (this.Type)
{
case ContentType.TEXT:
var textContent = (ContentText) this.Content;
2024-09-01 18:10:03 +00:00
await this.RustService.CopyText2Clipboard(this.Snackbar, textContent.Text);
2024-05-04 09:11:09 +00:00
break;
default:
this.Snackbar.Add("Cannot copy this content type to clipboard!", Severity.Error, config =>
{
config.Icon = Icons.Material.Filled.ContentCopy;
config.IconSize = Size.Large;
config.IconColor = Color.Error;
});
break;
}
}
2024-07-14 19:46:17 +00:00
private string CardClasses => $"my-2 rounded-lg {this.Class}";
2025-01-02 14:24:15 +00:00
private CodeBlockTheme CodeColorPalette => this.SettingsManager.IsDarkMode ? CodeBlockTheme.Dark : CodeBlockTheme.Default;
}