mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-16 05:33:48 +00:00
Added the visual briefing assistant (#893)
Build and Release / Determine run mode (push) Has been cancelled
Build and Release / Read metadata (push) Has been cancelled
Build and Release / Sync Flatpak repo (push) Has been cancelled
Build and Release / Collect Flatpak artifacts (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Has been cancelled
Build and Release / Prepare & create release (push) Has been cancelled
Build and Release / Publish release (push) Has been cancelled
Build and Release / Determine run mode (push) Has been cancelled
Build and Release / Read metadata (push) Has been cancelled
Build and Release / Sync Flatpak repo (push) Has been cancelled
Build and Release / Collect Flatpak artifacts (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Has been cancelled
Build and Release / Prepare & create release (push) Has been cancelled
Build and Release / Publish release (push) Has been cancelled
This commit is contained in:
1 parent
df4663fff4
commit
58cc811a58
214 files changed
+18943
-353
No files matched your search
@@ -103,11 +103,29 @@ public partial class AssistantBlock<TSettings> : MSGComponentBase where TSetting
|
||||
|
||||
private MediaImportOwner CurrentMediaImportOwner => MediaImportOwner.ForAssistant(new AssistantSessionKey(this.Component, this.AssistantSessionInstanceId));
|
||||
|
||||
private MediaImportSnapshot? MediaImportSnapshot => string.IsNullOrWhiteSpace(this.AssistantSessionInstanceId)
|
||||
? this.MediaTranscriptionService.GetSnapshots().FirstOrDefault(snapshot =>
|
||||
snapshot.Owner.Kind is MediaImportOwnerKind.ASSISTANT
|
||||
&& snapshot.Owner.Id.StartsWith($"{this.Component}:", StringComparison.Ordinal))
|
||||
: this.MediaTranscriptionService.GetSnapshot(this.CurrentMediaImportOwner);
|
||||
private MediaImportSnapshot? MediaImportSnapshot => this.MediaTranscriptionService.GetSnapshots()
|
||||
.FirstOrDefault(snapshot => this.OwnedByThisBlock(snapshot.Owner));
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether a media-import owner belongs to the assistant represented by this block.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Owners that persist their own sources are keyed by the stored document rather than by an
|
||||
/// assistant session, so this block aggregates all of them for its component. Without a session
|
||||
/// instance we aggregate every owner of the component, otherwise we match the exact owner.
|
||||
/// </remarks>
|
||||
/// <param name="owner">The media-import owner to test.</param>
|
||||
/// <returns><c>true</c> when this block represents the owner.</returns>
|
||||
private bool OwnedByThisBlock(MediaImportOwner owner)
|
||||
{
|
||||
if (owner.Kind.PersistsOwnSources())
|
||||
return owner.Kind == this.Component.MediaOwnerKind();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(this.AssistantSessionInstanceId))
|
||||
return owner.Kind is MediaImportOwnerKind.ASSISTANT && owner.Id.StartsWith($"{this.Component}:", StringComparison.Ordinal);
|
||||
|
||||
return owner == this.CurrentMediaImportOwner;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the assistant session indicator shown on top of the assistant icon.
|
||||
@@ -140,11 +158,7 @@ public partial class AssistantBlock<TSettings> : MSGComponentBase where TSetting
|
||||
|
||||
private void OnMediaImportStateChanged(MediaImportOwner owner)
|
||||
{
|
||||
var matches = string.IsNullOrWhiteSpace(this.AssistantSessionInstanceId)
|
||||
? owner.Kind is MediaImportOwnerKind.ASSISTANT && owner.Id.StartsWith($"{this.Component}:", StringComparison.Ordinal)
|
||||
: owner == this.CurrentMediaImportOwner;
|
||||
|
||||
if (matches)
|
||||
if (this.OwnedByThisBlock(owner))
|
||||
_ = this.InvokeAsync(this.StateHasChanged);
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,12 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
[Parameter]
|
||||
public AIStudio.Settings.Provider? Provider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the optional picker and drop filter applied before standard attachment validation.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public FileTypeFilter[]? AllowedFileTypes { get; set; }
|
||||
|
||||
/// <summary>Optional persisted chat that can own transcript files immediately.</summary>
|
||||
[Parameter]
|
||||
public ChatThread? OwnerChat { get; set; }
|
||||
@@ -178,7 +184,11 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
private async Task SyncCompletedMediaAttachmentsAsync()
|
||||
{
|
||||
var delivery = this.MediaTranscriptionService.GetPendingDelivery(this.EffectiveMediaImportTarget);
|
||||
var completed = delivery?.Attachments ?? [];
|
||||
// Owners that persist their own sources have already taken the media over when the batch
|
||||
// started, so re-adding the delivered transcripts here would duplicate them.
|
||||
var completed = this.EffectiveImportOwner.Kind.PersistsOwnSources()
|
||||
? Array.Empty<FileAttachment>()
|
||||
: delivery?.Attachments ?? [];
|
||||
var pending = this.OwnerChat?.PendingMediaTranscripts ?? [];
|
||||
var changed = false;
|
||||
var ownerPendingChanged = false;
|
||||
@@ -314,7 +324,7 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
this.isFileDialogOpen = true;
|
||||
try
|
||||
{
|
||||
var selectFiles = await this.RustService.SelectFiles(T("Select files to attach"));
|
||||
var selectFiles = await this.RustService.SelectFiles(T("Select files to attach"), this.AllowedFileTypes);
|
||||
if (selectFiles.UserCancelled)
|
||||
return;
|
||||
|
||||
@@ -407,6 +417,14 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
private async Task AddFileBatchAsync(IEnumerable<string> paths)
|
||||
{
|
||||
var pathList = paths.ToList();
|
||||
if (this.AllowedFileTypes is { Length: > 0 })
|
||||
{
|
||||
var rejectedPaths = pathList.Where(path => !FileTypes.IsAllowedPath(path, this.AllowedFileTypes)).ToArray();
|
||||
pathList.RemoveAll(path => rejectedPaths.Contains(path, StringComparer.Ordinal));
|
||||
if (rejectedPaths.Length > 0)
|
||||
await this.MessageBus.SendWarning(new(Icons.Material.Filled.Warning, this.T("Some files do not use an allowed format and were not attached.")));
|
||||
}
|
||||
|
||||
var inaccessiblePaths = pathList.Where(path => !File.Exists(path)).ToList();
|
||||
if (inaccessiblePaths.Count > 0)
|
||||
{
|
||||
@@ -434,12 +452,9 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
if (!canAddRegularFiles)
|
||||
break;
|
||||
|
||||
if (!await FileExtensionValidation.IsExtensionValidWithNotifyAsync(
|
||||
FileExtensionValidation.UseCase.ATTACHING_CONTENT,
|
||||
path,
|
||||
this.ValidateMediaFileTypes,
|
||||
this.Provider))
|
||||
if (!await FileExtensionValidation.IsExtensionValidWithNotifyAsync(FileExtensionValidation.UseCase.ATTACHING_CONTENT, path, this.ValidateMediaFileTypes, this.Provider))
|
||||
continue;
|
||||
|
||||
this.DocumentPaths.Add(FileAttachment.FromPath(path));
|
||||
}
|
||||
|
||||
@@ -480,6 +495,17 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
if (this.OwnerChat is null)
|
||||
this.OwnerChat = await this.EnsureOwnerChatAsync(mediaPaths[0]);
|
||||
|
||||
// Owners that persist their own sources show the file right away and keep it next to the
|
||||
// stored document, instead of waiting for the transcription to be delivered back.
|
||||
if (this.EffectiveImportOwner.Kind.PersistsOwnSources())
|
||||
{
|
||||
foreach (var mediaPath in mediaPaths)
|
||||
this.DocumentPaths.Add(FileAttachment.FromPath(mediaPath));
|
||||
|
||||
await this.DocumentPathsChanged.InvokeAsync(this.DocumentPaths);
|
||||
await this.OnChange(this.DocumentPaths);
|
||||
}
|
||||
|
||||
this.MediaTranscriptionService.TryStartAttachmentBatch(mediaPaths, this.EffectiveMediaImportTarget, this.OwnerChat);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,10 +38,7 @@ public partial class MudCopyClipboardButton : ComponentBase
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Size Size { get; set; } = Size.Small;
|
||||
|
||||
[Inject]
|
||||
private ISnackbar Snackbar { get; init; } = null!;
|
||||
|
||||
|
||||
[Inject]
|
||||
private RustService RustService { get; init; } = null!;
|
||||
|
||||
@@ -58,7 +55,7 @@ public partial class MudCopyClipboardButton : ComponentBase
|
||||
/// </summary>
|
||||
private async Task CopyToClipboard(string textContent)
|
||||
{
|
||||
await this.RustService.CopyText2Clipboard(this.Snackbar, textContent);
|
||||
await this.RustService.CopyText2Clipboard(textContent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -73,16 +70,13 @@ public partial class MudCopyClipboardButton : ComponentBase
|
||||
{
|
||||
case ContentType.TEXT:
|
||||
var textContent = (ContentText) contentToCopy;
|
||||
await this.RustService.CopyText2Clipboard(this.Snackbar, textContent.Text);
|
||||
await this.RustService.CopyText2Clipboard(textContent.Text);
|
||||
break;
|
||||
|
||||
default:
|
||||
this.Snackbar.Add(TB("Cannot copy this content type to clipboard."), Severity.Error, config =>
|
||||
{
|
||||
config.Icon = Icons.Material.Filled.ContentCopy;
|
||||
config.IconSize = Size.Large;
|
||||
config.IconColor = Color.Error;
|
||||
});
|
||||
// This component is no MSGComponentBase, so it uses the shared bus instance the same
|
||||
// way FileExtensionValidation does:
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.ContentCopy, TB("Cannot copy this content type to clipboard.")));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<MudStepper ActiveIndex="@this.ActiveIndex"
|
||||
ActiveIndexChanged="@this.ActiveIndexChanged"
|
||||
CompletedStepColor="Color.Primary"
|
||||
CurrentStepColor="Color.Primary"
|
||||
ErrorStepColor="Color.Error"
|
||||
NonLinear="@false"
|
||||
ShowResetButton="@false"
|
||||
OnPreviewInteraction="@this.PreviewInteractionAsync"
|
||||
Class="@this.Classname">
|
||||
<ChildContent>
|
||||
@this.ChildContent
|
||||
</ChildContent>
|
||||
@* Empty on purpose: this is what keeps MudBlazor from rendering its Previous, Next, Skip, and
|
||||
Complete buttons. The surrounding action bar still renders and is hidden through app.css. *@
|
||||
<ActionContent Context="_">
|
||||
</ActionContent>
|
||||
</MudStepper>
|
||||
@@ -0,0 +1,70 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components;
|
||||
|
||||
/// <summary>
|
||||
/// A stepper that leaves the step navigation to the application instead of the user.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// MudBlazor renders Previous, Next, Skip, and Complete buttons by default. AI Studio drives its
|
||||
/// steppers from application state — a running build, or an install flow that advances when each
|
||||
/// step succeeds — so those buttons have nothing to do and would only look broken when clicked.
|
||||
/// This component removes them once instead of once per assistant, and carries the shared step
|
||||
/// colors so the steppers stay visually consistent.
|
||||
/// </remarks>
|
||||
public partial class MudStepperWithoutActions : ComponentBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the step the stepper points at.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public int ActiveIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the callback raised when the active step changed.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public EventCallback<int> ActiveIndexChanged { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the user must not change the active step.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Set this when the displayed process runs on its own. The step headers stay visible, but
|
||||
/// clicking them no longer moves the stepper away from the step the application selected.
|
||||
/// </remarks>
|
||||
[Parameter]
|
||||
public bool ReadOnly { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets additional CSS classes for the stepper.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Class { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the steps to render.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public RenderFragment? ChildContent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The marker class that lets app.css hide the action bar MudBlazor renders around the actions.
|
||||
/// </summary>
|
||||
private const string MARKER_CLASS = "mud-stepper-without-actions";
|
||||
|
||||
private string Classname => string.IsNullOrWhiteSpace(this.Class) ? MARKER_CLASS : $"{MARKER_CLASS} {this.Class}";
|
||||
|
||||
/// <summary>
|
||||
/// Blocks step changes that the user triggered while the stepper is read-only.
|
||||
/// </summary>
|
||||
/// <param name="args">The interaction to inspect.</param>
|
||||
/// <returns>A completed task.</returns>
|
||||
private Task PreviewInteractionAsync(StepperInteractionEventArgs args)
|
||||
{
|
||||
if (this.ReadOnly)
|
||||
args.Cancel = true;
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -74,7 +74,7 @@ public partial class SettingsPanelApp : SettingsPanelBase
|
||||
private async Task GenerateEncryptionSecret()
|
||||
{
|
||||
var secret = EnterpriseEncryption.GenerateSecret();
|
||||
await this.RustService.CopyText2Clipboard(this.Snackbar, secret);
|
||||
await this.RustService.CopyText2Clipboard(secret);
|
||||
}
|
||||
|
||||
private string GetStartPageHelpText()
|
||||
|
||||
@@ -16,6 +16,4 @@ public abstract class SettingsPanelBase : MSGComponentBase
|
||||
[Inject]
|
||||
protected RustService RustService { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected ISnackbar Snackbar { get; init; } = null!;
|
||||
}
|
||||
@@ -47,7 +47,7 @@ public abstract class SettingsPanelProviderBase : SettingsPanelBase
|
||||
else
|
||||
{
|
||||
// No encryption secret available - inform the user:
|
||||
this.Snackbar.Add(TB("Cannot export the encrypted API key: No enterprise encryption secret is configured."), Severity.Warning);
|
||||
await this.MessageBus.SendWarning(new(Icons.Material.Filled.Key, TB("Cannot export the encrypted API key: No enterprise encryption secret is configured.")));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,6 @@ public abstract class SettingsPanelProviderBase : SettingsPanelBase
|
||||
if (string.IsNullOrWhiteSpace(luaCode))
|
||||
return;
|
||||
|
||||
await this.RustService.CopyText2Clipboard(this.Snackbar, luaCode);
|
||||
await this.RustService.CopyText2Clipboard(luaCode);
|
||||
}
|
||||
}
|
||||
@@ -23,9 +23,6 @@ public partial class TextInfoLine : MSGComponentBase
|
||||
|
||||
[Inject]
|
||||
private RustService RustService { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private ISnackbar Snackbar { get; init; } = null!;
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
@@ -43,5 +40,5 @@ public partial class TextInfoLine : MSGComponentBase
|
||||
|
||||
private string ClipboardTooltip => string.Format(T("Copy {0} to the clipboard"), this.ClipboardTooltipSubject);
|
||||
|
||||
private async Task CopyToClipboard(string content) => await this.RustService.CopyText2Clipboard(this.Snackbar, content);
|
||||
private async Task CopyToClipboard(string content) => await this.RustService.CopyText2Clipboard(content);
|
||||
}
|
||||
@@ -26,9 +26,6 @@ public partial class TextInfoLines : MSGComponentBase
|
||||
|
||||
[Inject]
|
||||
private RustService RustService { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private ISnackbar Snackbar { get; init; } = null!;
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
@@ -46,7 +43,7 @@ public partial class TextInfoLines : MSGComponentBase
|
||||
|
||||
private string ClipboardTooltip => string.Format(T("Copy {0} to the clipboard"), this.ClipboardTooltipSubject);
|
||||
|
||||
private async Task CopyToClipboard(string content) => await this.RustService.CopyText2Clipboard(this.Snackbar, content);
|
||||
private async Task CopyToClipboard(string content) => await this.RustService.CopyText2Clipboard(content);
|
||||
|
||||
private string GetColor()
|
||||
{
|
||||
|
||||
@@ -25,9 +25,6 @@ public partial class VoiceRecorder : MSGComponentBase
|
||||
[Inject]
|
||||
private GlobalShortcutService GlobalShortcutService { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private ISnackbar Snackbar { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private VoiceRecordingAvailabilityService VoiceRecordingAvailabilityService { get; init; } = null!;
|
||||
|
||||
@@ -448,7 +445,7 @@ public partial class VoiceRecorder : MSGComponentBase
|
||||
}
|
||||
|
||||
// Copy the transcribed text to the clipboard:
|
||||
await this.RustService.CopyText2Clipboard(this.Snackbar, transcribedText);
|
||||
await this.RustService.CopyText2Clipboard(transcribedText);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
Reference in new issue
Block a user