AI-Studio/app/MindWork AI Studio/Components/DataSourceSelection.razor
Thorsten Sommer 1eaca9b12f
Some checks are pending
Build and Release / Determine run mode (push) Waiting to run
Build and Release / Read metadata (push) Blocked by required conditions
Build and Release / Sync Flatpak repo (push) Blocked by required conditions
Build and Release / Collect Flatpak artifacts (push) Blocked by required conditions
Build and Release / Verify (push) Waiting to run
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
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) Blocked by required conditions
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) Blocked by required conditions
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) Blocked by required conditions
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) Blocked by required conditions
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) Blocked by required conditions
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Publish release (push) Blocked by required conditions
Added a semantic search tool (#1005)
2026-09-27 16:26:52 +02:00

245 lines
19 KiB
Plaintext

@using AIStudio.Settings
@using AIStudio.Provider
@inherits MSGComponentBase
@if (this.SelectionMode is DataSourceSelectionMode.SELECTION_MODE)
{
<div class="d-flex">
<MudTooltip Text="@T("Select the data you want to use here.")" Placement="Placement.Top">
@if (this.PopoverTriggerMode is PopoverTriggerMode.ICON)
{
<MudIconButton Icon="@AppIcons.DATABASE" Class="@this.PopoverButtonClasses" OnClick="@this.ToggleDataSourceSelection"/>
}
else
{
<MudButton Variant="Variant.Filled" StartIcon="@AppIcons.DATABASE" Class="@this.PopoverButtonClasses" OnClick="@this.ToggleDataSourceSelection">
@T("Select data")
</MudButton>
}
</MudTooltip>
<MudPopover Open="@this.showDataSourceSelection" AnchorOrigin="Origin.TopLeft" TransformOrigin="Origin.BottomLeft" DropShadow="@true" Class="border-solid border-4 rounded-lg">
<MudCard>
<MudCardHeader Class="pa-2 pb-0">
<CardHeaderContent>
<MudStack Row="true" AlignItems="AlignItems.Center">
<MudText Typo="Typo.h5">
@T("Data Source Selection")
</MudText>
<PreviewBeta ChipClass=""/>
<MudSpacer/>
<MudTooltip Text="@T("Manage your data sources")" Placement="Placement.Top">
<MudIconButton Icon="@Icons.Material.Filled.Settings" OnClick="@this.OpenSettingsDialog"/>
</MudTooltip>
</MudStack>
</CardHeaderContent>
</MudCardHeader>
<MudCardContent Class="pa-2" Style="min-width: 24em; max-height: 60vh; max-width: 45vw; overflow: auto;">
@if (this.waitingForDataSources)
{
<MudSkeleton Width="30%" Height="42px;"/>
<MudSkeleton Width="80%"/>
<MudSkeleton Width="100%"/>
}
else if (this.SettingsManager.ConfigurationData.DataSources.Count == 0)
{
<MudJustifiedText Typo="Typo.body2" Class="mb-2">
@T("You haven't configured any data sources. To grant the AI access to your data, you need to add such a source. However, if you wish to use data from your device, you first have to set up a so-called embedding. This embedding is necessary so the AI can effectively search your data, find and retrieve the correct information required for each task. In addition to local data, you can also incorporate your company's data. To do so, your company must provide the data through an ERI (External Retrieval Interface).")
</MudJustifiedText>
<MudStack StretchItems="StretchItems.None" AlignItems="AlignItems.Start">
<MudButton Variant="Variant.Filled" OnClick="this.OpenSettingsDialog" StartIcon="@Icons.Material.Filled.Settings">
@T("Manage Data Sources")
</MudButton>
<MudButton Variant="Variant.Filled" Href="https://mindworkai.org/#eri---external-retrieval-interface" Target="_blank" StartIcon="@Icons.Material.Filled.Settings">
@T("Read more about ERI")
</MudButton>
</MudStack>
}
else if (this.showDataSourceSelection)
{
<MudTextSwitch Label="@T("Are data sources enabled?")" Value="@this.areDataSourcesEnabled" LabelOn="@T("Yes, I want to use data sources.")" LabelOff="@T("No, I don't want to use data sources.")" ValueChanged="@this.EnabledChanged" Dense="@true"/>
@if (this.areDataSourcesEnabled)
{
@* Where Semantic Search cannot be used, there is no choice to make, only the reason to tell: *@
@if (this.IsSemanticSearchUnavailable)
{
<MudJustifiedText Typo="Typo.body2" Color="Color.Info" Class="mb-2">
@this.GetSemanticSearchUnavailableMessage()
</MudJustifiedText>
}
else
{
<MudTextSwitch Label="@T("Semantic Search")" Value="@this.IsSemanticSearchPreferred" LabelOn="@T("Yes, the AI searches your data sources itself, whenever a question calls for it (Semantic Search).")" LabelOff="@T("No, AI Studio searches your data sources with every message, before the AI answers (classic RAG).")" ValueChanged="@this.SemanticSearchChanged" Dense="@true"/>
}
<MudTextSwitch Label="@T("AI-based data source selection")" Value="@this.aiBasedSourceSelection" LabelOn="@T("Yes, let the AI decide which data sources are needed.")" LabelOff="@T("No, I manually decide which data source to use.")" ValueChanged="@this.AutoModeChanged" Dense="@true"/>
@* With Semantic Search, no agent takes part: nothing would validate the retrieved data. *@
@if (this.SettingsManager.ConfigurationData.AgentRetrievalContextValidation.EnableRetrievalContextValidation && !this.IsSemanticSearchEffective)
{
<MudTextSwitch Label="@T("AI-based data validation")" Value="@this.aiBasedValidation" LabelOn="@T("Yes, let the AI validate & filter the retrieved data.")" LabelOff="@T("No, use all data retrieved from the data sources.")" ValueChanged="@this.ValidationModeChanged" Dense="@true"/>
}
@switch (this.aiBasedSourceSelection)
{
case true when this.GetListedDataSources().Count == 0:
<MudText Typo="Typo.body2" Class="mb-2">
@T("Your data sources cannot be used with the selected providers due to data privacy or confidence-level requirements, or they are currently unavailable.")
</MudText>
break;
case false when this.GetListedDataSources().Count == 0:
<MudText Typo="Typo.body2" Class="mb-2">
@T("Your data sources cannot be used with the selected providers due to data privacy or confidence-level requirements, or they are currently unavailable.")
</MudText>
break;
case false:
<MudField Label="@T("Available Data Sources")" Variant="Variant.Outlined" Class="mb-2" Disabled="@this.aiBasedSourceSelection">
<MudList T="IDataSource" Dense="@true" Class="data-source-rows" SelectionMode="@this.GetListSelectionMode()" @bind-SelectedValues:get="@this.selectedDataSources" @bind-SelectedValues:set="@this.SelectionChanged" Style="max-height: 14em;">
@foreach (var source in this.GetListedDataSources())
{
<DataSourceSelectionRow DataSource="@source" BlockReason="@this.GetBlockReason(source)"/>
}
</MudList>
</MudField>
break;
case true:
@if (this.IsSemanticSearchEffective)
{
<MudText Typo="Typo.body2" Class="mb-2">
@T("Whenever a question calls for it, the AI picks the fitting ones among these data sources itself.")
</MudText>
}
else if (this.DataSourcesAISelected.Count == 0)
{
<MudText Typo="Typo.body2" Class="mb-2">
@T("The AI evaluates each of your inputs to determine whether and which data sources are necessary. Currently, the AI has not selected any source.")
</MudText>
}
<MudExpansionPanels MultiExpansion="@false" Class="mt-3" Style="max-height: 14em;">
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.TouchApp" IconSize="Size.Small" HeaderTypo="Typo.subtitle1" HeaderClass="expansion-panel-header-compact" HeaderText="@T("Available Data Sources")">
<MudList T="IDataSource" Dense="@true" Class="data-source-rows" SelectionMode="MudBlazor.SelectionMode.SingleSelection" SelectedValues="@this.selectedDataSources" Style="max-height: 14em;">
@foreach (var source in this.GetListedDataSources())
{
<DataSourceSelectionRow DataSource="@source" BlockReason="@this.GetBlockReason(source)"/>
}
</MudList>
</ExpansionPanel>
@*
With Semantic Search, no agent selects: the chat model picks with each search, and its
searches show in the answer. With classic RAG, there is something to show once the agent
picked for a message.
*@
@if (!this.IsSemanticSearchEffective && this.DataSourcesAISelected.Count > 0)
{
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.Filter" IconSize="Size.Small" HeaderTypo="Typo.subtitle1" HeaderClass="expansion-panel-header-compact" HeaderText="@T("AI-Selected Data Sources")">
<MudList T="DataSourceAgentSelected" Dense="@true" Class="data-source-rows" SelectionMode="MudBlazor.SelectionMode.MultiSelection" ReadOnly="@true" SelectedValues="@this.GetSelectedDataSourcesWithAI()" Style="max-height: 14em;">
@foreach (var source in this.DataSourcesAISelected)
{
<MudListItem Value="@source">
<ChildContent>
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1" Style="min-width: 0; width: 100%;">
<MudText Typo="Typo.body2" Style="min-width: 0; white-space: normal; overflow-wrap: anywhere;">
@source.DataSource.Name
</MudText>
@if (source.DataSource is IInternalDataSource internalSource)
{
<MudSpacer/>
<MudTooltip Text="@internalSource.ConfidenceLevel.GetName()">
<MudIcon Icon="@Icons.Material.Filled.Security" Size="Size.Small" Class="confidence-icon" Style="@this.GetConfidenceIconStyle(internalSource)"/>
</MudTooltip>
}
</MudStack>
<MudProgressLinear Color="Color.Info" Min="0" Max="1" Value="@source.AIDecision.Confidence"/>
<MudJustifiedText Typo="Typo.body2">
@(this.GetAIReasoning(source))
</MudJustifiedText>
</ChildContent>
</MudListItem>
}
</MudList>
</ExpansionPanel>
}
</MudExpansionPanels>
break;
}
@if (!this.aiBasedSourceSelection && this.GetUnavailablePreselectedDataSourcesToList().Count > 0)
{
<MudJustifiedText Typo="Typo.body2" Color="Color.Warning">
@T("These data sources are preselected, but cannot be used right now, either due to data privacy or confidence-level requirements, or because they are unavailable:")
</MudJustifiedText>
<ul class="unavailable-data-sources mb-3 mt-1">
@foreach (var source in this.GetUnavailablePreselectedDataSourcesToList())
{
<li>@source.Name</li>
}
</ul>
}
}
}
</MudCardContent>
<MudCardActions>
<MudButton Variant="Variant.Filled" OnClick="@this.HideDataSourceSelection">
@T("Close")
</MudButton>
</MudCardActions>
</MudCard>
</MudPopover>
</div>
}
else if (this.SelectionMode is DataSourceSelectionMode.CONFIGURATION_MODE)
{
<MudPaper Class="pa-3 mb-8 mt-3 border-dashed border rounded-lg">
<PreviewBeta/>
<MudText Typo="Typo.h5">
@T("Data Source Selection")
</MudText>
@if (!string.IsNullOrWhiteSpace(this.ConfigurationHeaderMessage))
{
<MudText Typo="Typo.body2">
@this.ConfigurationHeaderMessage
</MudText>
}
<MudTextSwitch Label="@T("Are data sources enabled?")" Value="@this.areDataSourcesEnabled" LabelOn="@T("Yes, I want to use data sources.")" LabelOff="@T("No, I don't want to use data sources.")" ValueChanged="@this.EnabledChanged" Disabled="@(this.ReadOnly || this.IsPreselectedDataSourcesDisabledLocked())"/>
@if (this.areDataSourcesEnabled)
{
<MudTextSwitch Label="@T("Semantic Search")" Value="@this.IsSemanticSearchPreferred" LabelOn="@T("Yes, the AI searches your data sources itself, whenever a question calls for it (Semantic Search).")" LabelOff="@T("No, AI Studio searches your data sources with every message, before the AI answers (classic RAG).")" ValueChanged="@this.SemanticSearchChanged" Disabled="@(this.ReadOnly || this.IsPreselectedDataSourcesRetrievalModeLocked())"/>
@* No provider is known here, so this says in general what the chat itself tells about its model: *@
@if (this.IsSemanticSearchPreferred)
{
<MudJustifiedText Typo="Typo.body2" Class="mb-3">
@T("When the model of a chat cannot use tools, AI Studio uses classic RAG instead and searches your data sources with every message.")
</MudJustifiedText>
}
<MudTextSwitch Label="@T("AI-based data source selection")" Value="@this.aiBasedSourceSelection" LabelOn="@T("Yes, let the AI decide which data sources are needed.")" LabelOff="@T("No, I manually decide which data source to use.")" ValueChanged="@this.AutoModeChanged" Disabled="@(this.ReadOnly || this.IsPreselectedDataSourcesAutomaticSelectionLocked())"/>
@* Semantic Search may fall back to searching with every message, so the validation is kept, marked as belonging to that way only: *@
<MudPaper Class="pa-3 mb-3 border-dashed border rounded-lg">
<MudJustifiedText Typo="Typo.body2" Class="mb-2">
@T("Only used with classic RAG, which searches your data sources with every message:")
</MudJustifiedText>
<MudTextSwitch Label="@T("AI-based data validation")" Value="@this.aiBasedValidation" LabelOn="@T("Yes, let the AI validate & filter the retrieved data.")" LabelOff="@T("No, use all data retrieved from the data sources.")" ValueChanged="@this.ValidationModeChanged" Disabled="@(this.ReadOnly || this.IsPreselectedDataSourcesAutomaticValidationLocked())"/>
</MudPaper>
<MudField Label="@T("Available Data Sources")" Variant="Variant.Outlined" Class="mb-3" Disabled="@(this.ReadOnly || this.aiBasedSourceSelection || this.IsPreselectedDataSourceIdsLocked())">
<MudList T="IDataSource" Dense="@true" Class="data-source-rows" SelectionMode="@this.GetListSelectionMode()" @bind-SelectedValues:get="@this.selectedDataSources" @bind-SelectedValues:set="@(x => this.SelectionChanged(x))" ReadOnly="@(this.ReadOnly || this.IsPreselectedDataSourceIdsLocked())">
@*
The configuration mode lists what was configured, without filtering it, so no
row here is ever waiting for an index.
*@
@foreach (var source in this.availableDataSources)
{
<DataSourceSelectionRow DataSource="@source"/>
}
</MudList>
</MudField>
}
</MudPaper>
}