using AIStudio.Components; using AIStudio.Tools.PluginSystem; using AIStudio.Tools.RAG; using Microsoft.AspNetCore.Components; namespace AIStudio.Dialogs; /// /// Shows the passages the AI received from one file, so the user can check what an answer rests on. /// /// /// Opened from the list of sources below an answer, and meant for every other place which hands /// passages of data sources to the AI and wants to show them, such as an assistant. The file is /// named once, above everything else; its passages are numbered at the side when there are several, /// in the order of the document, and the one picked is shown in full.

/// Only the text of a passage scrolls: the dialog fits the window, see dialog-content-fit in app.css, /// so that it never has to scroll as well. ///
public partial class SourcePassagesDialog : MSGComponentBase { private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(SourcePassagesDialog).Namespace, nameof(SourcePassagesDialog)); [CascadingParameter] private IMudDialogInstance MudDialog { get; set; } = null!; /// /// The passages to show, in the order the AI received them; they are shown in the order of the document. /// [Parameter] public IReadOnlyList Passages { get; set; } = []; /// /// The file the passages are from, or null when it is no file this computer can open. /// [Parameter] public SourceDocumentLocation? Document { get; set; } /// /// The passages in the order of the document. A passage which does not say where it is comes /// last, in the order the AI received it. /// /// /// The order the AI received them in tells the user nothing: the AI gets no weight with them, /// and each one counts as much as every other. The order of the document is what lets the user /// read them alongside it. /// private List passagesInDocumentOrder = []; private SourcePassage selectedPassage = new(); private string fileName = string.Empty; private string path = string.Empty; #region Overrides of ComponentBase protected override async Task OnInitializedAsync() { this.passagesInDocumentOrder = [..this.Passages.OrderBy(passage => passage.GetLocationRange()?.First ?? int.MaxValue)]; this.selectedPassage = this.passagesInDocumentOrder.Count > 0 ? this.passagesInDocumentOrder[0] : new(); this.fileName = GetFileName(this.Passages); this.path = this.Document?.Path ?? this.selectedPassage.Path; await base.OnInitializedAsync(); } #endregion /// /// The name of the file the passages are from, without their pages: those are what the dialog lets the user pick. /// private static string GetFileName(IReadOnlyList passages) => passages is [{ DataSourceName.Length: > 0 } firstPassage, ..] ? firstPassage.DataSourceName : TB("Passages"); private void Close() => this.MudDialog.Cancel(); /// /// Shows the passages the AI received from a file. /// /// The dialog service. /// The passages to show, in any order: they are shown in the order of the document. /// The file the passages are from, or null when it is no file this computer can open. public static async Task OpenDialogAsync(IDialogService dialogService, IReadOnlyList passages, SourceDocumentLocation? document = null) { var dialogParameters = new DialogParameters { { x => x.Passages, passages }, { x => x.Document, document }, }; var dialogReference = await dialogService.ShowAsync(GetFileName(passages), dialogParameters, DialogOptions.FULLSCREEN); await dialogReference.Result; } }