mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2025-02-05 12:49:07 +00:00
Added a button to regenerate the last AI response (#247)
This commit is contained in:
parent
5e445f09fa
commit
b2ca49ab92
@ -102,12 +102,40 @@ public sealed record ChatThread
|
|||||||
/// Removes a content block from this chat thread.
|
/// Removes a content block from this chat thread.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="content">The content block to remove.</param>
|
/// <param name="content">The content block to remove.</param>
|
||||||
public void Remove(IContent content)
|
/// <param name="removeForRegenerate">Indicates whether the content block is removed for
|
||||||
|
/// regeneration purposes. True, when the content block is removed for regeneration purposes,
|
||||||
|
/// which will not remove the previous user block if it is hidden from the user.</param>
|
||||||
|
public void Remove(IContent content, bool removeForRegenerate = false)
|
||||||
{
|
{
|
||||||
var block = this.Blocks.FirstOrDefault(x => x.Content == content);
|
var block = this.Blocks.FirstOrDefault(x => x.Content == content);
|
||||||
if(block is null)
|
if(block is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Remove the previous user block if it is hidden from the user. Otherwise,
|
||||||
|
// the experience might be confusing for the user.
|
||||||
|
//
|
||||||
|
// Explanation, using the ERI assistant as an example:
|
||||||
|
// - The ERI assistant generates for every file a hidden user prompt.
|
||||||
|
// - In the UI, the user can only see the AI's responses, not the hidden user prompts.
|
||||||
|
// - Now, the user removes one AI response
|
||||||
|
// - The hidden user prompt is still there, but the user can't see it.
|
||||||
|
// - Since the user prompt is hidden, neither is it possible to remove nor edit it.
|
||||||
|
// - This method solves this issue by removing the hidden user prompt when the AI response is removed.
|
||||||
|
//
|
||||||
|
if (block.Role is ChatRole.AI && !removeForRegenerate)
|
||||||
|
{
|
||||||
|
var sortedBlocks = this.Blocks.OrderBy(x => x.Time).ToList();
|
||||||
|
var index = sortedBlocks.IndexOf(block);
|
||||||
|
if (index > 0)
|
||||||
|
{
|
||||||
|
var previousBlock = sortedBlocks[index - 1];
|
||||||
|
if (previousBlock.Role is ChatRole.USER && previousBlock.HideFromUser)
|
||||||
|
this.Blocks.Remove(previousBlock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the block from the chat thread:
|
||||||
this.Blocks.Remove(block);
|
this.Blocks.Remove(block);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,6 +12,12 @@
|
|||||||
<MudText Typo="Typo.body1">@this.Role.ToName() (@this.Time)</MudText>
|
<MudText Typo="Typo.body1">@this.Role.ToName() (@this.Time)</MudText>
|
||||||
</CardHeaderContent>
|
</CardHeaderContent>
|
||||||
<CardHeaderActions>
|
<CardHeaderActions>
|
||||||
|
@if (this.IsLastContentBlock && this.Role is ChatRole.AI && this.RegenerateFunc is not null)
|
||||||
|
{
|
||||||
|
<MudTooltip Text="Regenerate" Placement="Placement.Bottom">
|
||||||
|
<MudIconButton Icon="@Icons.Material.Filled.Recycling" Color="Color.Tertiary" OnClick="@this.RegenerateBlock"/>
|
||||||
|
</MudTooltip>
|
||||||
|
}
|
||||||
@if (this.RemoveBlockFunc is not null)
|
@if (this.RemoveBlockFunc is not null)
|
||||||
{
|
{
|
||||||
<MudTooltip Text="Removes this block" Placement="Placement.Bottom">
|
<MudTooltip Text="Removes this block" Placement="Placement.Bottom">
|
||||||
|
@ -41,9 +41,18 @@ public partial class ContentBlockComponent : ComponentBase
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public string Class { get; set; } = string.Empty;
|
public string Class { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public bool IsLastContentBlock { get; set; } = false;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public Func<IContent, Task>? RemoveBlockFunc { get; set; }
|
public Func<IContent, Task>? RemoveBlockFunc { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public Func<IContent, Task>? RegenerateFunc { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public Func<bool> RegenerateEnabled { get; set; } = () => false;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
private RustService RustService { get; init; } = null!;
|
private RustService RustService { get; init; } = null!;
|
||||||
|
|
||||||
@ -143,4 +152,22 @@ public partial class ContentBlockComponent : ComponentBase
|
|||||||
if (remove.HasValue && remove.Value)
|
if (remove.HasValue && remove.Value)
|
||||||
await this.RemoveBlockFunc(this.Content);
|
await this.RemoveBlockFunc(this.Content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task RegenerateBlock()
|
||||||
|
{
|
||||||
|
if (this.RegenerateFunc is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(this.Role is not ChatRole.AI)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var regenerate = await this.DialogService.ShowMessageBox(
|
||||||
|
"Regenerate Message",
|
||||||
|
"Do you really want to regenerate this message?",
|
||||||
|
"Yes, regenerate it",
|
||||||
|
"No, keep it");
|
||||||
|
|
||||||
|
if (regenerate.HasValue && regenerate.Value)
|
||||||
|
await this.RegenerateFunc(this.Content);
|
||||||
|
}
|
||||||
}
|
}
|
@ -7,11 +7,14 @@
|
|||||||
<ChildContent>
|
<ChildContent>
|
||||||
@if (this.ChatThread is not null)
|
@if (this.ChatThread is not null)
|
||||||
{
|
{
|
||||||
@foreach (var block in this.ChatThread.Blocks.OrderBy(n => n.Time))
|
var blocks = this.ChatThread.Blocks.OrderBy(n => n.Time).ToList();
|
||||||
|
for (var i = 0; i < blocks.Count; i++)
|
||||||
{
|
{
|
||||||
|
var block = blocks[i];
|
||||||
|
var isLastBlock = i == blocks.Count - 1;
|
||||||
@if (!block.HideFromUser)
|
@if (!block.HideFromUser)
|
||||||
{
|
{
|
||||||
<ContentBlockComponent Role="@block.Role" Type="@block.ContentType" Time="@block.Time" Content="@block.Content" RemoveBlockFunc="@this.RemoveBlock"/>
|
<ContentBlockComponent Role="@block.Role" Type="@block.ContentType" Time="@block.Time" Content="@block.Content" RemoveBlockFunc="@this.RemoveBlock" IsLastContentBlock="@isLastBlock" RegenerateFunc="@this.RegenerateBlock" RegenerateEnabled="@(() => this.IsProviderSelected)"/>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -242,7 +242,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SendMessage()
|
private async Task SendMessage(bool reuseLastUserPrompt = false)
|
||||||
{
|
{
|
||||||
if (!this.IsProviderSelected)
|
if (!this.IsProviderSelected)
|
||||||
return;
|
return;
|
||||||
@ -252,8 +252,6 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
|||||||
await this.inputField.BlurAsync();
|
await this.inputField.BlurAsync();
|
||||||
|
|
||||||
// Create a new chat thread if necessary:
|
// Create a new chat thread if necessary:
|
||||||
var threadName = this.ExtractThreadName(this.userInput);
|
|
||||||
|
|
||||||
if (this.ChatThread is null)
|
if (this.ChatThread is null)
|
||||||
{
|
{
|
||||||
this.ChatThread = new()
|
this.ChatThread = new()
|
||||||
@ -263,7 +261,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
|||||||
SystemPrompt = SystemPrompts.DEFAULT,
|
SystemPrompt = SystemPrompts.DEFAULT,
|
||||||
WorkspaceId = this.currentWorkspaceId,
|
WorkspaceId = this.currentWorkspaceId,
|
||||||
ChatId = Guid.NewGuid(),
|
ChatId = Guid.NewGuid(),
|
||||||
Name = threadName,
|
Name = this.ExtractThreadName(this.userInput),
|
||||||
Seed = this.RNG.Next(),
|
Seed = this.RNG.Next(),
|
||||||
Blocks = [],
|
Blocks = [],
|
||||||
};
|
};
|
||||||
@ -274,17 +272,19 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
|||||||
{
|
{
|
||||||
// Set the thread name if it is empty:
|
// Set the thread name if it is empty:
|
||||||
if (string.IsNullOrWhiteSpace(this.ChatThread.Name))
|
if (string.IsNullOrWhiteSpace(this.ChatThread.Name))
|
||||||
this.ChatThread.Name = threadName;
|
this.ChatThread.Name = this.ExtractThreadName(this.userInput);
|
||||||
|
|
||||||
// Update provider and profile:
|
// Update provider and profile:
|
||||||
this.ChatThread.SelectedProvider = this.Provider.Id;
|
this.ChatThread.SelectedProvider = this.Provider.Id;
|
||||||
this.ChatThread.SelectedProfile = this.currentProfile.Id;
|
this.ChatThread.SelectedProfile = this.currentProfile.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var time = DateTimeOffset.Now;
|
||||||
|
if (!reuseLastUserPrompt)
|
||||||
|
{
|
||||||
//
|
//
|
||||||
// Add the user message to the thread:
|
// Add the user message to the thread:
|
||||||
//
|
//
|
||||||
var time = DateTimeOffset.Now;
|
|
||||||
this.ChatThread?.Blocks.Add(new ContentBlock
|
this.ChatThread?.Blocks.Add(new ContentBlock
|
||||||
{
|
{
|
||||||
Time = time,
|
Time = time,
|
||||||
@ -303,6 +303,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
|||||||
this.hasUnsavedChanges = false;
|
this.hasUnsavedChanges = false;
|
||||||
this.StateHasChanged();
|
this.StateHasChanged();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Add the AI response to the thread:
|
// Add the AI response to the thread:
|
||||||
@ -582,6 +583,18 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
|||||||
this.StateHasChanged();
|
this.StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task RegenerateBlock(IContent aiBlock)
|
||||||
|
{
|
||||||
|
if(this.ChatThread is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.ChatThread.Remove(aiBlock, removeForRegenerate: true);
|
||||||
|
this.hasUnsavedChanges = true;
|
||||||
|
this.StateHasChanged();
|
||||||
|
|
||||||
|
await this.SendMessage(reuseLastUserPrompt: true);
|
||||||
|
}
|
||||||
|
|
||||||
#region Overrides of MSGComponentBase
|
#region Overrides of MSGComponentBase
|
||||||
|
|
||||||
public override async Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
|
public override async Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
# v0.9.24, build 199 (2025-01-xx xx:xx UTC)
|
# v0.9.24, build 199 (2025-01-xx xx:xx UTC)
|
||||||
- Added a button to remove a message from the chat thread.
|
- Added a button to remove a message from the chat thread.
|
||||||
|
- Added a button to regenerate the last AI response.
|
Loading…
Reference in New Issue
Block a user