@attribute [Route(Routes.EMBEDDINGS)] @using AIStudio.Tools.Services @inherits MSGComponentBase @T("Background embeddings") @T("AI Studio indexes local RAG data sources in the background. Finished files stay recorded so unchanged files can be skipped after a restart, while added or deleted files are detected during the next run. The same applies to documents without readable text, such as scanned pages: AI Studio remembers them and reads them again only once they change.") @if (this.AreMailboxesEnabled) { @T("Mailboxes are synced every 16 minutes while the automatic refresh is on. Each mail is embedded only once: when it moves to another folder, AI Studio merely notes where it lies now.") } @string.Format(T("Indexed: {0}"), this.FormatNumber(this.TotalIndexedDocuments)) @string.Format(T("Pending: {0}"), this.FormatNumber(this.TotalPendingDocuments)) @string.Format(T("Skipped: {0}"), this.FormatNumber(this.TotalPermanentlySkippedDocuments)) @string.Format(T("Failed: {0}"), this.FormatNumber(this.TotalFailedDocuments)) @if (this.IsWorkingThroughDataSources) { @string.Format(T("Data source {0} of {1} is being worked on. The others are waiting their turn."), this.CurrentDataSourceNumber, this.Statuses.Count) } @if (this.Statuses.Count == 0) { @T("No local data source has been queued for embedding yet.") } else { @* One panel per data source, and only one of them open: a folder with thousands of files fills the page by itself. What a closed panel still has to say stays in its header, so nobody has to open every one of them to see how their data sources are doing. *@ @foreach (var status in this.Statuses) {
@string.Format(T("Data source: {0}"), status.DataSourceName) @status.StateLabel @if (CanRefresh(status)) { @* This opens or closes the panel along the way. The header is what toggles it, and neither stopping the event nor swallowing the click works in this project — see the end button of our own ExpansionPanel component, which behaves the same way. *@ } @if (this.CanRepair(status)) { }
@this.GetProgressText(status) @if (IsMailbox(status)) { @this.GetLastSyncText(status) } @if (status.PermanentlySkippedDocuments > 0) { @this.GetSkippedText(status) } @if (status.FailedDocuments > 0) { @this.GetFailedText(status) } @if (!string.IsNullOrWhiteSpace(status.CurrentDocument)) { @this.GetCurrentDocumentText(status) } @* One panel per cause, the most pressing one first. A folder in which nine hundred scanned documents were skipped otherwise buries the handful of files somebody has to look at. *@ @if (status.Failures.Count > 0) { @foreach (var group in this.GetFailureGroups(status)) { @(group.Cause.IsPermanent ? (IsMailbox(status) ? T("Skipped") : T("Skipped until the file changes")) : T("Tried again during the next run")) @if (!string.IsNullOrWhiteSpace(group.EmbeddingProviderName)) { @string.Format(T("Embedding provider: {0}"), group.EmbeddingProviderName) } @if (group.Cause.NeedsProviderSettings) { @T("Open the settings") } @(IsMailbox(status) ? T("Mail") : T("File")) @T("Noticed") @T("Actions") @* Captions render as spans, so each of them needs to be told to take its own line. *@ @if (IsMailbox(status)) { @GetMailName(context) } else { @GetFileName(context.DocumentKey) @context.DocumentKey } @if (group.Cause.ShowsMessagePerFile) { @context.Reason } @GetOccurrenceText(context) @if (CanShowInFileManager(status, context)) { } } } @* Shown next to the list, not instead of it: the list says which files failed, while this is the one sentence about the data source as a whole. Hiding it as soon as a single file failed is what made it invisible in practice. *@ @if (!string.IsNullOrWhiteSpace(status.LastError)) { @status.LastError } @* What the user has to decide comes with the buttons to decide it. The sentence above says what is at stake; reading it and then having to find the settings of the mailbox is where people give up. *@ @if (status.Attention is DataSourceAttention.AUTH_FAILED) { @T("Change the password") @T("Try to sign in again") } else if (status is { Attention: DataSourceAttention.MASS_REMOVAL_PENDING, PendingRemovalCount: not null }) { @T("Remove them from the index") @T("Change the settings of the mailbox") }
}
}