mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-18 03:37:59 +00:00
Merge branch 'main' into chunk-data
This commit is contained in:
commit
9932b5870b
484 files changed
+45549
-2467
No files matched your search
@@ -1,6 +1,7 @@
|
||||
@attribute [Route(Routes.ASSISTANTS)]
|
||||
@using AIStudio.Dialogs.Settings
|
||||
@using AIStudio.Settings.DataModel
|
||||
@using AIStudio.Tools.PluginSystem
|
||||
@using AIStudio.Tools.PluginSystem.Assistants
|
||||
@inherits MSGComponentBase
|
||||
|
||||
@@ -17,7 +18,8 @@
|
||||
(Components.GRAMMAR_SPELLING_ASSISTANT, PreviewFeatures.NONE),
|
||||
(Components.REWRITE_ASSISTANT, PreviewFeatures.NONE),
|
||||
(Components.PROMPT_OPTIMIZER_ASSISTANT, PreviewFeatures.NONE),
|
||||
(Components.SYNONYMS_ASSISTANT, PreviewFeatures.NONE)
|
||||
(Components.SYNONYMS_ASSISTANT, PreviewFeatures.NONE),
|
||||
(Components.META_ASSISTANT, PreviewFeatures.PRE_META_ASSISTANT_V1)
|
||||
))
|
||||
{
|
||||
<MudText Typo="Typo.h4" Class="mb-2 mr-3">
|
||||
@@ -30,6 +32,7 @@
|
||||
<AssistantBlock TSettings="SettingsDialogRewrite" Component="Components.REWRITE_ASSISTANT" Name="@T("Rewrite & Improve")" Description="@T("Rewrite and improve a given text for a chosen style.")" Icon="@Icons.Material.Filled.Edit" Link="@Routes.ASSISTANT_REWRITE"/>
|
||||
<AssistantBlock TSettings="SettingsDialogPromptOptimizer" Component="Components.PROMPT_OPTIMIZER_ASSISTANT" Name="@T("Prompt Optimizer")" Description="@T("Optimize your prompt using a structured guideline.")" Icon="@Icons.Material.Filled.AutoFixHigh" Link="@Routes.ASSISTANT_PROMPT_OPTIMIZER"/>
|
||||
<AssistantBlock TSettings="SettingsDialogSynonyms" Component="Components.SYNONYMS_ASSISTANT" Name="@T("Synonyms")" Description="@T("Find synonyms for a given word or phrase.")" Icon="@Icons.Material.Filled.Spellcheck" Link="@Routes.ASSISTANT_SYNONYMS"/>
|
||||
<AssistantBlock TSettings="NoSettingsPanel" Component="Components.META_ASSISTANT" RequiredPreviewFeature="PreviewFeatures.PRE_META_ASSISTANT_V1" Name="@T("Assistant Builder")" Description="@T("Generate your own assistants.")" Icon="@Icons.Material.Filled.AutoMode" Link="@Routes.ASSISTANT_META_ASSISTANT"/>
|
||||
</MudStack>
|
||||
}
|
||||
|
||||
@@ -42,12 +45,22 @@
|
||||
@foreach (var assistantPlugin in this.AssistantPlugins)
|
||||
{
|
||||
var securityState = PluginAssistantSecurityResolver.Resolve(this.SettingsManager, assistantPlugin);
|
||||
var launchLink = assistantPlugin.StartsChatDirectly ? string.Empty : $"{Routes.ASSISTANT_DYNAMIC}?assistantId={assistantPlugin.Id}";
|
||||
var availablePlugin = PluginFactory.AvailablePlugins.OfType<IAvailablePlugin>().FirstOrDefault(plugin => plugin.Id == assistantPlugin.Id);
|
||||
<AssistantBlock TSettings="NoSettingsPanel"
|
||||
Name="@T(assistantPlugin.AssistantTitle)"
|
||||
Description="@T(assistantPlugin.Description)"
|
||||
Icon="@Icons.Material.Filled.FindInPage"
|
||||
Disabled="@(!securityState.CanStartAssistant)"
|
||||
Link="@($"{Routes.ASSISTANT_DYNAMIC}?assistantId={assistantPlugin.Id}")">
|
||||
AssistantSessionInstanceId="@assistantPlugin.Id.ToString()"
|
||||
Link="@launchLink"
|
||||
OnClick="@(() => this.StartAssistantPluginAsync(assistantPlugin))">
|
||||
<AdditionalActions>
|
||||
@if (availablePlugin is not null)
|
||||
{
|
||||
<AssistantPluginDeleteAction Plugin="@availablePlugin" />
|
||||
}
|
||||
</AdditionalActions>
|
||||
<SecurityBadge>
|
||||
<AssistantPluginSecurityCard Plugin="@assistantPlugin" Compact="@true" />
|
||||
</SecurityBadge>
|
||||
@@ -64,7 +77,8 @@
|
||||
(Components.JOB_POSTING_ASSISTANT, PreviewFeatures.NONE),
|
||||
(Components.LEGAL_CHECK_ASSISTANT, PreviewFeatures.NONE),
|
||||
(Components.ICON_FINDER_ASSISTANT, PreviewFeatures.NONE),
|
||||
(Components.SLIDE_BUILDER_ASSISTANT, PreviewFeatures.NONE)
|
||||
(Components.SLIDE_BUILDER_ASSISTANT, PreviewFeatures.NONE),
|
||||
(Components.VISUAL_BRIEFING_ASSISTANT, Components.VISUAL_BRIEFING_ASSISTANT.RequiredPreviewFeature())
|
||||
))
|
||||
{
|
||||
<MudText Typo="Typo.h4" Class="mb-2 mr-3 mt-6">
|
||||
@@ -79,6 +93,7 @@
|
||||
<AssistantBlock TSettings="SettingsDialogLegalCheck" Component="Components.LEGAL_CHECK_ASSISTANT" Name="@T("Legal Check")" Description="@T("Ask a question about a legal document.")" Icon="@Icons.Material.Filled.Gavel" Link="@Routes.ASSISTANT_LEGAL_CHECK"/>
|
||||
<AssistantBlock TSettings="SettingsDialogIconFinder" Component="Components.ICON_FINDER_ASSISTANT" Name="@T("Icon Finder")" Description="@T("Use an LLM to find an icon for a given context.")" Icon="@Icons.Material.Filled.FindInPage" Link="@Routes.ASSISTANT_ICON_FINDER"/>
|
||||
<AssistantBlock TSettings="SettingsDialogSlideBuilder" Component="Components.SLIDE_BUILDER_ASSISTANT" Name="@T("Slide Planner Assistant")" Description="@T("Develop slide content based on a given topic and content.")" Icon="@Icons.Material.Filled.Slideshow" Link="@Routes.ASSISTANT_SLIDE_BUILDER"/>
|
||||
<AssistantBlock TSettings="SettingsDialogVisualBriefing" Component="Components.VISUAL_BRIEFING_ASSISTANT" RequiredPreviewFeature="Components.VISUAL_BRIEFING_ASSISTANT.RequiredPreviewFeature()" Name="@T("Visual Briefing Assistant")" Description="@T("Turn documents, data, images, audio, and video into an audience-ready interactive briefing.")" Icon="@Icons.Material.Filled.DashboardCustomize" Link="@Routes.ASSISTANT_VISUAL_BRIEFING" />
|
||||
</MudStack>
|
||||
}
|
||||
|
||||
@@ -96,7 +111,8 @@
|
||||
|
||||
@if (this.SettingsManager.IsAnyCategoryAssistantVisible("Software Engineering",
|
||||
(Components.CODING_ASSISTANT, PreviewFeatures.NONE),
|
||||
(Components.ERI_ASSISTANT, PreviewFeatures.PRE_RAG_2024)
|
||||
(Components.ERI_ASSISTANT, PreviewFeatures.PRE_RAG_2024),
|
||||
(Components.LOG_VIEWER_ASSISTANT, PreviewFeatures.NONE)
|
||||
))
|
||||
{
|
||||
<MudText Typo="Typo.h4" Class="mb-2 mr-3 mt-6">
|
||||
@@ -117,8 +133,9 @@
|
||||
</MudText>
|
||||
<MudStack Row="@true" Wrap="@Wrap.Wrap" Class="mb-3">
|
||||
<AssistantBlock TSettings="SettingsDialogI18N" Component="Components.I18N_ASSISTANT" Name="@T("Localization")" Description="@T("Translate AI Studio text content into other languages")" Icon="@Icons.Material.Filled.Translate" Link="@Routes.ASSISTANT_AI_STUDIO_I18N"/>
|
||||
<AssistantBlock TSettings="NoSettingsPanel" Component="Components.LOG_VIEWER_ASSISTANT" Name="@T("Log Viewer")" Description="@T("View and filter AI Studio log files.")" Icon="@Icons.Material.Filled.Article" Link="@Routes.ASSISTANT_LOG_VIEWER"/>
|
||||
</MudStack>
|
||||
}
|
||||
|
||||
</InnerScrolling>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,3 +1,4 @@
|
||||
using AIStudio.Chat;
|
||||
using AIStudio.Components;
|
||||
using AIStudio.Agents.AssistantAudit;
|
||||
using AIStudio.Tools.PluginSystem;
|
||||
@@ -12,6 +13,12 @@ public partial class Assistants : MSGComponentBase
|
||||
|
||||
[Inject]
|
||||
private AssistantPluginAuditService AssistantPluginAuditService { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private NavigationManager NavigationManager { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private ILogger<Assistants> Logger { get; init; } = null!;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
@@ -81,6 +88,50 @@ public partial class Assistants : MSGComponentBase
|
||||
audits.Add(audit);
|
||||
}
|
||||
|
||||
private async Task StartAssistantPluginAsync(PluginAssistants assistantPlugin)
|
||||
{
|
||||
var securityState = PluginAssistantSecurityResolver.Resolve(this.SettingsManager, assistantPlugin);
|
||||
if (!securityState.CanStartAssistant)
|
||||
return;
|
||||
|
||||
if (!assistantPlugin.StartsChatDirectly)
|
||||
{
|
||||
this.NavigationManager.NavigateTo($"{Routes.ASSISTANT_DYNAMIC}?assistantId={assistantPlugin.Id}");
|
||||
return;
|
||||
}
|
||||
|
||||
var chatThread = await this.TryCreateDirectChatThreadAsync(assistantPlugin);
|
||||
if (chatThread is null)
|
||||
return;
|
||||
|
||||
MessageBus.INSTANCE.DeferMessage(this, Event.SEND_TO_CHAT, chatThread);
|
||||
this.NavigationManager.NavigateTo(Routes.CHAT);
|
||||
}
|
||||
|
||||
private async Task<ChatThread?> TryCreateDirectChatThreadAsync(PluginAssistants assistantPlugin)
|
||||
{
|
||||
var workspaceId = await WorkspaceBehaviour.ResolveOrCreateWorkspaceIdByNameAsync(assistantPlugin.LaunchWorkspaceName);
|
||||
if (workspaceId == Guid.Empty)
|
||||
{
|
||||
this.Logger.LogWarning("Assistant plugin '{PluginName}' could not resolve or create workspace '{WorkspaceName}'.", assistantPlugin.Name, assistantPlugin.LaunchWorkspaceName);
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ChatThread
|
||||
{
|
||||
IncludeDateTime = true,
|
||||
SelectedProvider = string.Empty,
|
||||
SelectedProfile = string.Empty,
|
||||
SelectedChatTemplate = string.Empty,
|
||||
SystemPrompt = SystemPrompts.DEFAULT,
|
||||
WorkspaceId = workspaceId,
|
||||
ChatId = Guid.NewGuid(),
|
||||
Name = assistantPlugin.AssistantTitle,
|
||||
DataSourceOptions = this.SettingsManager.ConfigurationData.Chat.PreselectedDataSourceOptions.CreateCopy(),
|
||||
Blocks = [],
|
||||
};
|
||||
}
|
||||
|
||||
protected override async Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
|
||||
{
|
||||
if (triggeredEvent is Event.PLUGINS_RELOADED)
|
||||
|
||||
@@ -8,52 +8,66 @@
|
||||
</MudText>
|
||||
|
||||
<InnerScrolling>
|
||||
<MudExpansionPanels @key="@this.expansionPanelsRenderKey" Class="mb-3" MultiExpansion="@false">
|
||||
@if (this.HasVisibleHomePanels)
|
||||
{
|
||||
<MudExpansionPanels @key="@this.expansionPanelsRenderKey" Class="mb-3" MultiExpansion="@false">
|
||||
|
||||
@if (this.SettingsManager.ConfigurationData.App.ShowIntroduction)
|
||||
{
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.MenuBook" HeaderText="@T("Introduction")" IsExpanded="@this.IsPanelExpanded(PANEL_ID_BUILT_IN_INTRODUCTION)" ExpandedChanged="@(isExpanded => this.SetPanelExpanded(PANEL_ID_BUILT_IN_INTRODUCTION, isExpanded))">
|
||||
<MudText Typo="Typo.h5" Class="mb-3">
|
||||
@T("Welcome to MindWork AI Studio!")
|
||||
</MudText>
|
||||
<MudText Typo="Typo.body1" Class="mb-3" Style="text-align: justify; hyphens: auto;">
|
||||
@T("Thank you for considering MindWork AI Studio for your AI needs. This app is designed to help you harness the power of Large Language Models (LLMs). Please note that this app doesn't come with an integrated LLM. Instead, you will need to bring an API key from a suitable provider.")
|
||||
</MudText>
|
||||
<MudText Typo="Typo.body1" Class="mb-3">
|
||||
@T("Here's what makes MindWork AI Studio stand out:")
|
||||
</MudText>
|
||||
<MudTextList Icon="@Icons.Material.Filled.CheckCircle" Clickable="@true" Items="@this.itemsAdvantages" Class="mb-3"/>
|
||||
<MudText Typo="Typo.body1" Class="mb-3">
|
||||
@T("We hope you enjoy using MindWork AI Studio to bring your AI projects to life!")
|
||||
</MudText>
|
||||
</ExpansionPanel>
|
||||
}
|
||||
@if (this.SettingsManager.ConfigurationData.App.ShowIntroduction)
|
||||
{
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.MenuBook" HeaderText="@T("Introduction")" IsExpanded="@this.IsPanelExpanded(PANEL_ID_BUILT_IN_INTRODUCTION)" ExpandedChanged="@(isExpanded => this.SetPanelExpanded(PANEL_ID_BUILT_IN_INTRODUCTION, isExpanded))">
|
||||
<MudText Typo="Typo.h5" Class="mb-3">
|
||||
@T("Welcome to MindWork AI Studio!")
|
||||
</MudText>
|
||||
<MudText Typo="Typo.body1" Class="mb-3" Style="text-align: justify; hyphens: auto;">
|
||||
@T("Thank you for considering MindWork AI Studio for your AI needs. This app is designed to help you harness the power of Large Language Models (LLMs). Please note that this app doesn't come with an integrated LLM. Instead, you will need to bring an API key from a suitable provider.")
|
||||
</MudText>
|
||||
<MudText Typo="Typo.body1" Class="mb-3">
|
||||
@T("Here's what makes MindWork AI Studio stand out:")
|
||||
</MudText>
|
||||
<MudTextList Icon="@Icons.Material.Filled.CheckCircle" Clickable="@true" Items="@this.itemsAdvantages" Class="mb-3"/>
|
||||
<MudText Typo="Typo.body1" Class="mb-3">
|
||||
@T("We hope you enjoy using MindWork AI Studio to bring your AI projects to life!")
|
||||
</MudText>
|
||||
</ExpansionPanel>
|
||||
}
|
||||
|
||||
@foreach (var introduction in this.introductions)
|
||||
{
|
||||
<ExpansionPanel @key="@introduction.Id" HeaderIcon="@Icons.Material.Filled.Info" HeaderText="@introduction.Title" IsExpanded="@this.IsPanelExpanded(IntroductionPanelId(introduction))" ExpandedChanged="@(isExpanded => this.SetPanelExpanded(IntroductionPanelId(introduction), isExpanded))">
|
||||
<MudText Typo="Typo.body2" Class="mb-3">
|
||||
@T("Version"): @introduction.VersionText
|
||||
</MudText>
|
||||
<MudJustifiedMarkdown Value="@introduction.Markdown" />
|
||||
</ExpansionPanel>
|
||||
}
|
||||
@foreach (var introduction in this.introductions)
|
||||
{
|
||||
<ExpansionPanel @key="@introduction.Id" HeaderIcon="@Icons.Material.Filled.Info" HeaderText="@introduction.Title" IsExpanded="@this.IsPanelExpanded(IntroductionPanelId(introduction))" ExpandedChanged="@(isExpanded => this.SetPanelExpanded(IntroductionPanelId(introduction), isExpanded))">
|
||||
<MudText Typo="Typo.body2" Class="mb-3">
|
||||
@T("Version"): @introduction.VersionText
|
||||
</MudText>
|
||||
<MudJustifiedMarkdown Value="@introduction.Markdown" />
|
||||
</ExpansionPanel>
|
||||
}
|
||||
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.EventNote" HeaderText="@T("Last Changelog")" IsExpanded="@this.IsPanelExpanded(PANEL_ID_LAST_CHANGELOG)" ExpandedChanged="@(isExpanded => this.SetPanelExpanded(PANEL_ID_LAST_CHANGELOG, isExpanded))">
|
||||
<MudMarkdown Value="@this.LastChangeContent" Props="Markdown.DefaultConfig" MarkdownPipeline="Markdown.SAFE_MARKDOWN_PIPELINE"/>
|
||||
</ExpansionPanel>
|
||||
@if (this.SettingsManager.ConfigurationData.App.ShowLastChangelog)
|
||||
{
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.EventNote" HeaderText="@T("Last Changelog")" IsExpanded="@this.IsPanelExpanded(PANEL_ID_LAST_CHANGELOG)" ExpandedChanged="@(isExpanded => this.SetPanelExpanded(PANEL_ID_LAST_CHANGELOG, isExpanded))">
|
||||
<MudMarkdown Value="@this.LastChangeContent" Props="Markdown.DefaultConfig" MarkdownPipeline="Markdown.SAFE_MARKDOWN_PIPELINE"/>
|
||||
</ExpansionPanel>
|
||||
}
|
||||
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.Lightbulb" HeaderText="@T("Vision")" IsExpanded="@this.IsPanelExpanded(PANEL_ID_VISION)" ExpandedChanged="@(isExpanded => this.SetPanelExpanded(PANEL_ID_VISION, isExpanded))">
|
||||
<Vision/>
|
||||
</ExpansionPanel>
|
||||
|
||||
@if (this.SettingsManager.ConfigurationData.App.ShowQuickStartGuide)
|
||||
{
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.RocketLaunch" HeaderText="@T("Quick Start Guide")" IsExpanded="@this.IsPanelExpanded(PANEL_ID_QUICK_START_GUIDE)" ExpandedChanged="@(isExpanded => this.SetPanelExpanded(PANEL_ID_QUICK_START_GUIDE, isExpanded))">
|
||||
<MudMarkdown Props="Markdown.DefaultConfig" Value="@QUICK_START_GUIDE" MarkdownPipeline="Markdown.SAFE_MARKDOWN_PIPELINE"/>
|
||||
</ExpansionPanel>
|
||||
}
|
||||
@if (this.SettingsManager.ConfigurationData.App.ShowVision)
|
||||
{
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.Lightbulb" HeaderText="@T("Vision")" IsExpanded="@this.IsPanelExpanded(PANEL_ID_VISION)" ExpandedChanged="@(isExpanded => this.SetPanelExpanded(PANEL_ID_VISION, isExpanded))">
|
||||
<Vision/>
|
||||
</ExpansionPanel>
|
||||
}
|
||||
|
||||
</MudExpansionPanels>
|
||||
@if (this.SettingsManager.ConfigurationData.App.ShowQuickStartGuide)
|
||||
{
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.RocketLaunch" HeaderText="@T("Quick Start Guide")" IsExpanded="@this.IsPanelExpanded(PANEL_ID_QUICK_START_GUIDE)" ExpandedChanged="@(isExpanded => this.SetPanelExpanded(PANEL_ID_QUICK_START_GUIDE, isExpanded))">
|
||||
<MudMarkdown Props="Markdown.DefaultConfig" Value="@QUICK_START_GUIDE" MarkdownPipeline="Markdown.SAFE_MARKDOWN_PIPELINE"/>
|
||||
</ExpansionPanel>
|
||||
}
|
||||
</MudExpansionPanels>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudText Typo="Typo.h5" Class="mb-3">
|
||||
@T("Welcome to MindWork AI Studio!")
|
||||
</MudText>
|
||||
}
|
||||
</InnerScrolling>
|
||||
</div>
|
||||
</div>
|
||||
@@ -29,6 +29,7 @@ public partial class Home : MSGComponentBase
|
||||
private const string PANEL_ID_LAST_CHANGELOG = "last-changelog";
|
||||
private const string PANEL_ID_VISION = "vision";
|
||||
private const string PANEL_ID_QUICK_START_GUIDE = "quick-start-guide";
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
@@ -102,15 +103,32 @@ public partial class Home : MSGComponentBase
|
||||
this.introductions = PluginFactory.GetIntroductions().ToList();
|
||||
}
|
||||
|
||||
private bool HasVisibleHomePanels =>
|
||||
this.SettingsManager.ConfigurationData.App.ShowIntroduction ||
|
||||
this.introductions.Count > 0 ||
|
||||
this.SettingsManager.ConfigurationData.App.ShowLastChangelog ||
|
||||
this.SettingsManager.ConfigurationData.App.ShowVision ||
|
||||
this.SettingsManager.ConfigurationData.App.ShowQuickStartGuide;
|
||||
|
||||
private string GetDefaultExpandedPanelId()
|
||||
{
|
||||
if (this.SettingsManager.ConfigurationData.App.ShowIntroduction)
|
||||
return PANEL_ID_BUILT_IN_INTRODUCTION;
|
||||
|
||||
var firstIntroduction = this.introductions.FirstOrDefault();
|
||||
return firstIntroduction is not null
|
||||
? IntroductionPanelId(firstIntroduction)
|
||||
: PANEL_ID_LAST_CHANGELOG;
|
||||
if (firstIntroduction is not null)
|
||||
return IntroductionPanelId(firstIntroduction);
|
||||
|
||||
if (this.SettingsManager.ConfigurationData.App.ShowLastChangelog)
|
||||
return PANEL_ID_LAST_CHANGELOG;
|
||||
|
||||
if (this.SettingsManager.ConfigurationData.App.ShowVision)
|
||||
return PANEL_ID_VISION;
|
||||
|
||||
if (this.SettingsManager.ConfigurationData.App.ShowQuickStartGuide)
|
||||
return PANEL_ID_QUICK_START_GUIDE;
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private void EnsureDefaultExpandedPanel()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@attribute [Route(Routes.ABOUT)]
|
||||
@using AIStudio.Tools.PluginSystem
|
||||
@using AIStudio.Tools.Services
|
||||
@inherits MSGComponentBase
|
||||
|
||||
<div class="inner-scrolling-context">
|
||||
@@ -53,7 +54,7 @@
|
||||
<MudText Typo="Typo.body1">
|
||||
@this.WorkingDirectory
|
||||
</MudText>
|
||||
<MudCopyClipboardButton TooltipMessage="@(T("Copies the working directory to the clipboard"))" StringContent="@this.runtimeInfo.WorkingDirectory"/>
|
||||
<MudCopyClipboardButton TooltipMessage="@(T("Copies the working directory to the clipboard"))" StringContent="@this.RuntimeInfo.WorkingDirectory"/>
|
||||
</div>
|
||||
</MudListItem>
|
||||
<MudListItem T="string" Icon="@Icons.Material.Filled.InsertDriveFile">
|
||||
@@ -61,7 +62,7 @@
|
||||
<MudText Typo="Typo.body1">
|
||||
@this.ExecutablePath
|
||||
</MudText>
|
||||
<MudCopyClipboardButton TooltipMessage="@(T("Copies the executable path to the clipboard"))" StringContent="@this.runtimeInfo.ExecutablePath"/>
|
||||
<MudCopyClipboardButton TooltipMessage="@(T("Copies the executable path to the clipboard"))" StringContent="@this.RuntimeInfo.ExecutablePath"/>
|
||||
</div>
|
||||
</MudListItem>
|
||||
@if (OperatingSystem.IsLinux())
|
||||
@@ -193,7 +194,7 @@
|
||||
</MudList>
|
||||
<MudStack Row="true">
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Info" StartIcon="@Icons.Material.Filled.Update" OnClick="@this.CheckForUpdate">
|
||||
@T("Check for updates")
|
||||
@(this.updatePolicyMode is UpdatePolicyMode.SELF_UPDATE ? T("Check for updates") : T("How to update"))
|
||||
</MudButton>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Default" StartIcon="@Icons.Material.Filled.Download" OnClick="@(async () => await this.ShowPandocDialog())">
|
||||
@this.PandocButtonText
|
||||
@@ -283,10 +284,13 @@
|
||||
<ThirdPartyComponent Name="CodeBeam.MudBlazor.Extensions" Developer="Mehmet Can Karagöz & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/CodeBeamOrg/CodeBeam.MudBlazor.Extensions/blob/dev/LICENSE" RepositoryUrl="https://github.com/CodeBeamOrg/CodeBeam.MudBlazor.Extensions" UseCase="@T("This library is used to extend the MudBlazor library. It provides additional components that are not part of the MudBlazor library.")"/>
|
||||
<ThirdPartyComponent Name="Rust" Developer="Graydon Hoare, Rust Foundation, Rust developers & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/rust-lang/rust/blob/master/LICENSE-MIT" RepositoryUrl="https://github.com/rust-lang/rust" UseCase="@T("The .NET backend cannot be started as a desktop app. Therefore, I use a second backend in Rust, which I call runtime. With Rust as the runtime, Tauri can be used to realize a typical desktop app. Thanks to Rust, this app can be offered for Windows, macOS, and Linux desktops. Rust is a great language for developing safe and high-performance software.")"/>
|
||||
<ThirdPartyComponent Name="Tauri" Developer="Daniel Thompson-Yvetot, Lucas Nogueira, Tensor, Boscop, Serge Zaitsev, George Burton & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/tauri-apps/tauri/blob/dev/LICENSE_MIT" RepositoryUrl="https://github.com/tauri-apps/tauri" UseCase="@T("Tauri is used to host the Blazor user interface. It is a great project that allows the creation of desktop applications using web technologies. I love Tauri!")"/>
|
||||
<ThirdPartyComponent Name="Apache ECharts" Developer="Yi Shen, 100pah, Ovilia, kener, Apache Software Foundation & Open Source Community" LicenseName="Apache-2.0" LicenseUrl="https://github.com/apache/echarts/blob/master/LICENSE" RepositoryUrl="https://github.com/apache/echarts" UseCase="@T("Apache ECharts is embedded only in exported visual briefings that use supported data-driven charts.")"/>
|
||||
<ThirdPartyComponent Name="image-rs" Developer="Aurelia Molzer, Jonathan Behrens, nwin, Sergey Davidoff, Michael Schmidt, Johannes Vollmer, Sven Nilsen, Sergio Gonzalez-Martin, Radzivon Bartoshyk, Philippe Solodov, ccgn, nabijaczleweli & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/image-rs/image/blob/main/LICENSE-MIT" RepositoryUrl="https://github.com/image-rs/image" UseCase="@T("The image crate decodes and optimizes PNG, JPEG, and WebP visual assets locally before they are analyzed and embedded in visual briefings.")"/>
|
||||
|
||||
@if (OperatingSystem.IsLinux())
|
||||
{
|
||||
<ThirdPartyComponent Name="GStreamer" Developer="GStreamer contributors & Open Source Community" LicenseName="LGPL-2.1" LicenseUrl="https://gstreamer.freedesktop.org/documentation/frequently-asked-questions/licensing.html" RepositoryUrl="https://gitlab.freedesktop.org/gstreamer/gstreamer" UseCase="@T("Linux AppImages bundle GStreamer components to support microphone access and WebM audio recording in the embedded WebKitGTK web view.")"/>
|
||||
<ThirdPartyComponent Name="ashpd" Developer="Bilal Elmoussaoui & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/bilelmoussaoui/ashpd/blob/main/LICENSE" RepositoryUrl="https://github.com/bilelmoussaoui/ashpd" UseCase="@T("On Linux, ashpd provides access to desktop portals, allowing AI Studio to open folders and files for the user.")"/>
|
||||
}
|
||||
|
||||
<ThirdPartyComponent Name="Qdrant Edge" Developer="Andrey Vasnetsov, Tim Visée, Arnaud Gourlay, Luis Cossío, Ivan Pleshkov, Roman Titov, xzfc, JojiiOfficial & Open Source Community" LicenseName="Apache-2.0" LicenseUrl="https://github.com/qdrant/qdrant/blob/master/LICENSE" RepositoryUrl="https://github.com/qdrant/qdrant" UseCase="@T("Qdrant Edge is an embedded vector database and vector similarity search engine. We use it to realize local RAG—retrieval-augmented generation—within AI Studio. Thanks for the effort and great work that has been and is being put into Qdrant.")"/>
|
||||
@@ -297,18 +301,24 @@
|
||||
<ThirdPartyComponent Name="serde" Developer="Erick Tryzelaar, David Tolnay & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/serde-rs/serde/blob/master/LICENSE-MIT" RepositoryUrl="https://github.com/serde-rs/serde" UseCase="@T("Now we have multiple systems, some developed in .NET and others in Rust. The data format JSON is responsible for translating data between both worlds (called data serialization and deserialization). Serde takes on this task in the Rust world. The counterpart in the .NET world is an integral part of .NET and is located in System.Text.Json.")"/>
|
||||
<ThirdPartyComponent Name="strum_macros" Developer="Peter Glotfelty & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/Peternator7/strum/blob/master/LICENSE" RepositoryUrl="https://github.com/Peternator7/strum" UseCase="@T("This crate provides derive macros for Rust enums, which we use to reduce boilerplate when implementing string conversions and metadata for runtime types. This is helpful for the communication between our Rust and .NET systems.")"/>
|
||||
<ThirdPartyComponent Name="keyring-core" Developer="Daniel Brotsky & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/open-source-cooperative/keyring-core/blob/main/LICENSE-MIT" RepositoryUrl="https://github.com/open-source-cooperative/keyring-core" UseCase="@T("AI Studio stores secrets like API keys in your operating system’s secure credential store. The keyring-core library handles this by connecting to macOS Keychain, Windows Credential Manager, and Linux Secret Service.")"/>
|
||||
<ThirdPartyComponent Name="dbus-secret-service" Developer="Daniel Brotsky, Walther Chen, ComplexSpaces, Rasmus Thomsen & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/open-source-cooperative/dbus-secret-service/blob/main/LICENSE-MIT" RepositoryUrl="https://github.com/open-source-cooperative/dbus-secret-service" UseCase="@T("On Linux, this library communicates with the FreeDesktop Secret Service. AI Studio uses its structured errors to provide helpful guidance when secure credential storage is unavailable or not configured correctly.")"/>
|
||||
<ThirdPartyComponent Name="arboard" Developer="Artur Kovacs, Avi Weinstock, 1Password & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/1Password/arboard/blob/master/LICENSE-MIT.txt" RepositoryUrl="https://github.com/1Password/arboard" UseCase="@T("To be able to use the responses of the LLM in other apps, we often use the clipboard of the respective operating system. Unfortunately, in .NET there is no solution that works with all operating systems. Therefore, I have opted for this library in Rust. This way, data transfer to other apps works on every system.")"/>
|
||||
<ThirdPartyComponent Name="tokio" Developer="Alex Crichton, Carl Lerche, Alice Ryhl, Taiki Endo, Ivan Petkov, Eliza Weisman, Lucio Franco & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/tokio-rs/tokio/blob/master/LICENSE" RepositoryUrl="https://github.com/tokio-rs/tokio" UseCase="@T("Code in the Rust language can be specified as synchronous or asynchronous. Unlike .NET and the C# language, Rust cannot execute asynchronous code by itself. Rust requires support in the form of an executor for this. Tokio is one such executor.")"/>
|
||||
<ThirdPartyComponent Name="futures" Developer="Alex Crichton, Taiki Endo, Taylor Cramer, Nemo157, Josef Brandl, Aaron Turon & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/rust-lang/futures-rs/blob/master/LICENSE-MIT" RepositoryUrl="https://github.com/rust-lang/futures-rs" UseCase="@T("This is a library providing the foundations for asynchronous programming in Rust. It includes key trait definitions like Stream, as well as utilities like join!, select!, and various futures combinator methods which enable expressive asynchronous control flow.")"/>
|
||||
<ThirdPartyComponent Name="async-stream" Developer="Carl Lerche, Taiki Endo & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/tokio-rs/async-stream/blob/master/LICENSE" RepositoryUrl="https://github.com/tokio-rs/async-stream" UseCase="@T("This library is used to create asynchronous streams in Rust. It allows us to work with streams of data that can be produced asynchronously, making it easier to handle events or data that arrive over time. We use this, e.g., to stream arbitrary data from the file system to the embedding system.")"/>
|
||||
<ThirdPartyComponent Name="flexi_logger" Developer="emabee & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/emabee/flexi_logger/blob/master/LICENSE-MIT" RepositoryUrl="https://github.com/emabee/flexi_logger" UseCase="@T("This Rust library is used to output the app's messages to the terminal. This is helpful during development and troubleshooting. This feature is initially invisible; when the app is started via the terminal, the messages become visible.")"/>
|
||||
<ThirdPartyComponent Name="dirs" Developer="soc, Wang Xuerui & Open Source Community" LicenseName="MIT" LicenseUrl="https://codeberg.org/dirs/dirs-rs/src/branch/main/LICENSE-MIT" RepositoryUrl="https://codeberg.org/dirs/dirs-rs" UseCase="@T("dirs determines the platform-specific local application data directory. AI Studio uses it so the Flatpak startup log is written to the same application data directory that Tauri uses.")"/>
|
||||
<ThirdPartyComponent Name="rand" Developer="Rust developers & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/rust-random/rand/blob/master/LICENSE-MIT" RepositoryUrl="https://github.com/rust-random/rand" UseCase="@T("We must generate random numbers, e.g., for securing the interprocess communication between the user interface and the runtime. The rand library is great for this purpose.")"/>
|
||||
<ThirdPartyComponent Name="pptx-to-md" Developer="Nils Kruthoff & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/nilskruthoff/pptx-parser/blob/master/LICENCE-MIT" RepositoryUrl="https://github.com/nilskruthoff/pptx-parser" UseCase="@T("We use this library to be able to read PowerPoint files. This allows us to insert content from slides into prompts and take PowerPoint files into account in RAG processes. We thank Nils Kruthoff for his work on this Rust crate.")"/>
|
||||
<ThirdPartyComponent Name="base64" Developer="Marshall Pierce, Alice Maz & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/marshallpierce/rust-base64/blob/master/LICENSE-MIT" RepositoryUrl="https://github.com/marshallpierce/rust-base64" UseCase="@T("For some data transfers, we need to encode the data in base64. This Rust library is great for this purpose.")"/>
|
||||
<ThirdPartyComponent Name="Rust Crypto" Developer="Artyom Pavlov, Tony Arcieri, Brian Warner, Arthur Gautier, Vlad Filippov, Friedel Ziegelmayer, Nicolas Stalder & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/RustCrypto/traits/blob/master/cipher/LICENSE-MIT" RepositoryUrl="https://github.com/RustCrypto" UseCase="@T("When transferring sensitive data between Rust runtime and .NET app, we encrypt the data. We use some libraries from the Rust Crypto project for this purpose: cipher, aes, cbc, pbkdf2, hmac, and sha2. We are thankful for the great work of the Rust Crypto project.")"/>
|
||||
<ThirdPartyComponent Name="rcgen" Developer="RustTLS developers, est31 & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/rustls/rcgen/blob/main/LICENSE" RepositoryUrl="https://github.com/rustls/rcgen" UseCase="@T("For the secure communication between the user interface and the runtime, we need to create certificates. This Rust library is great for this purpose.")"/>
|
||||
<ThirdPartyComponent Name="windows-registry" Developer="Microsoft, Kenny Kerr, Ryan Levick, Rafael Rivera, sivadeilra, Marijn Suijten & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/microsoft/windows-rs/blob/master/license-mit" RepositoryUrl="https://github.com/microsoft/windows-rs" UseCase="@T("This library is used to access the Windows registry. We use this for Windows enterprise environments to read the desired configuration.")"/>
|
||||
<ThirdPartyComponent Name="file-format" Developer="Mickaël Malécot & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/mmalecot/file-format/blob/main/LICENSE-MIT" RepositoryUrl="https://github.com/mmalecot/file-format" UseCase="@T("This library is used to determine the file type of a file. This is necessary, e.g., when we want to stream a file.")"/>
|
||||
<ThirdPartyComponent Name="file-format" Developer="Mickaël Malécot & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/mmalecot/file-format/blob/main/LICENSE-MIT" RepositoryUrl="https://github.com/mmalecot/file-format" UseCase="@T("This library identifies files by their content. It is used for document streaming and as the first safety and media classification step before local audio processing.")"/>
|
||||
<ThirdPartyComponent Name="Symphonia" Developer="Philip Deljanov & Open Source Community" LicenseName="MPL-2.0" LicenseUrl="https://github.com/pdeljanov/Symphonia/blob/v0.6.0/LICENSE" RepositoryUrl="https://github.com/pdeljanov/Symphonia" UseCase="@T("Symphonia is used for media container demuxing and audio decoding. The exact MPL-covered source is available from the repository linked and is identified in the offline notices bundled with AI Studio.")"/>
|
||||
<ThirdPartyComponent Name="Ropus" Developer="0x4D44, Xiph.Org, Skype Limited, Octasic, Jean-Marc Valin, Timothy B. Terriberry, CSIRO, Gregory Maxwell, Mark Borgerding, Erik de Castro Lopo, Mozilla, Amazon & Open Source Community" LicenseName="BSD-3-Clause" LicenseUrl="https://github.com/0x4D44/ropus/blob/main/LICENSE" RepositoryUrl="https://github.com/0x4d44/ropus" UseCase="@T("Ropus provides the Opus encoder and decoder used by the media pipeline.")"/>
|
||||
<ThirdPartyComponent Name="Rubato" Developer="Henrik Enquist & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/HEnquist/rubato/blob/master/LICENSE-MIT" RepositoryUrl="https://github.com/HEnquist/rubato" UseCase="@T("We use Rubato to resample the decoded audio to 48 kHz before the Opus encoding.")"/>
|
||||
<ThirdPartyComponent Name="webm-iterable" Developer="Austin Blake & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/austinleroy/webm-iterable/blob/main/LICENSE" RepositoryUrl="https://github.com/austinleroy/webm-iterable" UseCase="@T("webm-iterable provides the EBML and WebM writing path for normalized audio.")"/>
|
||||
<ThirdPartyComponent Name="calamine" Developer="Johann Tuffe, Joel Natividad, Eric Jolibois, Dmitriy & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/tafia/calamine/blob/master/LICENSE-MIT.md" RepositoryUrl="https://github.com/tafia/calamine" UseCase="@T("This library is used to read Excel and OpenDocument spreadsheet files. This is necessary, e.g., for using spreadsheets as a data source for a chat.")"/>
|
||||
<ThirdPartyComponent Name="PDFium" Developer="Lei Zhang, Tom Sepez, Dan Sinclair, and Foxit, Google, Chromium, Collabora, Ada, DocsCorp, Dropbox, Microsoft, and PSPDFKit Teams & Open Source Community" LicenseName="Apache-2.0" LicenseUrl="https://pdfium.googlesource.com/pdfium/+/refs/heads/main/LICENSE" RepositoryUrl="https://pdfium.googlesource.com/pdfium" UseCase="@T("This library is used to read PDF files. This is necessary, e.g., for using PDFs as a data source for a chat.")"/>
|
||||
<ThirdPartyComponent Name="pdfium-render" Developer="Alastair Carey, Dorian Rudolph & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/ajrcarey/pdfium-render/blob/master/LICENSE.md" RepositoryUrl="https://github.com/ajrcarey/pdfium-render" UseCase="@T("This library is used to read PDF files. This is necessary, e.g., for using PDFs as a data source for a chat.")"/>
|
||||
@@ -322,6 +332,7 @@
|
||||
<ThirdPartyComponent Name="HtmlAgilityPack" Developer="ZZZ Projects & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/zzzprojects/html-agility-pack/blob/master/LICENSE" RepositoryUrl="https://github.com/zzzprojects/html-agility-pack" UseCase="@T("We use the HtmlAgilityPack to extract content from the web. This is necessary, e.g., when you provide a URL as input for an assistant.")"/>
|
||||
<ThirdPartyComponent Name="ReverseMarkdown" Developer="Babu Annamalai & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/mysticmind/reversemarkdown-net/blob/master/LICENSE" RepositoryUrl="https://github.com/mysticmind/reversemarkdown-net" UseCase="@T("This library is used to convert HTML to Markdown. This is necessary, e.g., when you provide a URL as input for an assistant.")"/>
|
||||
<ThirdPartyComponent Name="wikEd diff" Developer="Cacycle & Open Source Community" LicenseName="None (public domain)" LicenseUrl="https://en.wikipedia.org/wiki/User:Cacycle/diff#License" RepositoryUrl="https://en.wikipedia.org/wiki/User:Cacycle/diff" UseCase="@T("This library is used to display the differences between two texts. This is necessary, e.g., for the grammar and spelling assistant.")"/>
|
||||
<ThirdPartyComponent Name="CodeJar" Developer="Anton Medvedev" LicenseName="MIT" LicenseUrl="https://github.com/antonmedv/codejar/blob/master/LICENSE" RepositoryUrl="https://github.com/antonmedv/codejar/" UseCase="@T("CodeJar is a lightweight embeddable code editor for the browser.")"/>
|
||||
</MudGrid>
|
||||
</ExpansionPanel>
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.Verified" HeaderText="License: FSL-1.1-MIT">
|
||||
|
||||
@@ -27,7 +27,10 @@ public partial class Information : MSGComponentBase
|
||||
private IDialogService DialogService { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private ISnackbar Snackbar { get; init; } = null!;
|
||||
private UpdatePolicy UpdatePolicy { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private RuntimeInfoResponse RuntimeInfo { get; init; }
|
||||
|
||||
[Inject]
|
||||
private DatabaseClientProvider DatabaseClientProvider { get; init; } = null!;
|
||||
@@ -42,7 +45,7 @@ public partial class Information : MSGComponentBase
|
||||
|
||||
private string osLanguage = string.Empty;
|
||||
private string osUserName = string.Empty;
|
||||
private RuntimeInfoResponse runtimeInfo;
|
||||
private UpdatePolicyMode updatePolicyMode;
|
||||
|
||||
private static string VersionApp => $"MindWork AI Studio: v{META_DATA.Version} (commit {META_DATA.AppCommitHash}, build {META_DATA.BuildNum}, {META_DATA_ARCH.Architecture.ToRID().ToUserFriendlyName()})";
|
||||
|
||||
@@ -54,13 +57,13 @@ public partial class Information : MSGComponentBase
|
||||
|
||||
private string OSUserName => $"{T("Username provided by the OS")}: '{this.osUserName}'";
|
||||
|
||||
private string WorkingDirectory => $"{T("Working directory")}: {this.runtimeInfo.WorkingDirectory}";
|
||||
private string WorkingDirectory => $"{T("Working directory")}: {this.RuntimeInfo.WorkingDirectory}";
|
||||
|
||||
private string ExecutablePath => $"{T("Executable path")}: {this.runtimeInfo.ExecutablePath}";
|
||||
private string ExecutablePath => $"{T("Executable path")}: {this.RuntimeInfo.ExecutablePath}";
|
||||
|
||||
private string LinuxPackageType => $"{T("Linux package")}: {this.LinuxPackageTypeDisplayName}";
|
||||
|
||||
private string LinuxPackageTypeDisplayName => this.runtimeInfo.LinuxPackageType switch
|
||||
private string LinuxPackageTypeDisplayName => this.RuntimeInfo.LinuxPackageType switch
|
||||
{
|
||||
"appimage" => "AppImage",
|
||||
"flatpak" => "Flatpak",
|
||||
@@ -162,7 +165,7 @@ public partial class Information : MSGComponentBase
|
||||
|
||||
this.osLanguage = await this.RustService.ReadUserLanguage();
|
||||
this.osUserName = await this.RustService.ReadUserName();
|
||||
this.runtimeInfo = await this.RustService.GetRuntimeInfo();
|
||||
this.updatePolicyMode = this.UpdatePolicy.CurrentMode;
|
||||
this.logPaths = await this.RustService.GetLogPaths();
|
||||
|
||||
await this.RefreshVectorStoreInfo(CancellationToken.None);
|
||||
@@ -185,6 +188,7 @@ public partial class Information : MSGComponentBase
|
||||
case Event.PLUGINS_RELOADED:
|
||||
case Event.ENTERPRISE_ENVIRONMENTS_CHANGED:
|
||||
case Event.CONFIGURATION_CHANGED:
|
||||
this.updatePolicyMode = this.UpdatePolicy.CurrentMode;
|
||||
this.RefreshEnterpriseConfigurationState();
|
||||
await this.InvokeAsync(this.StateHasChanged);
|
||||
break;
|
||||
@@ -481,12 +485,12 @@ public partial class Information : MSGComponentBase
|
||||
|
||||
private async Task CopyStartupLogPath()
|
||||
{
|
||||
await this.RustService.CopyText2Clipboard(this.Snackbar, this.logPaths.LogStartupPath);
|
||||
await this.RustService.CopyText2Clipboard(this.logPaths.LogStartupPath);
|
||||
}
|
||||
|
||||
private async Task CopyAppLogPath()
|
||||
{
|
||||
await this.RustService.CopyText2Clipboard(this.Snackbar, this.logPaths.LogAppPath);
|
||||
await this.RustService.CopyText2Clipboard(this.logPaths.LogAppPath);
|
||||
}
|
||||
|
||||
private const string LICENSE = """
|
||||
@@ -604,6 +608,26 @@ public partial class Information : MSGComponentBase
|
||||
|
||||
private async Task CheckForUpdate()
|
||||
{
|
||||
await this.MessageBus.SendMessage<bool>(this, Event.USER_SEARCH_FOR_UPDATE);
|
||||
this.updatePolicyMode = this.UpdatePolicy.CurrentMode;
|
||||
if (this.updatePolicyMode is UpdatePolicyMode.SELF_UPDATE)
|
||||
{
|
||||
await this.MessageBus.SendMessage<bool>(this, Event.USER_SEARCH_FOR_UPDATE);
|
||||
return;
|
||||
}
|
||||
|
||||
var parameters = new DialogParameters<UpdateInstructionsDialog>();
|
||||
if (this.updatePolicyMode is UpdatePolicyMode.ENTERPRISE_DISABLED)
|
||||
{
|
||||
parameters.Add(x => x.Message, T("Updates are managed by your organization. Contact your IT department if you have questions about updating AI Studio."));
|
||||
}
|
||||
else if (this.updatePolicyMode is UpdatePolicyMode.FLATPAK)
|
||||
{
|
||||
parameters.Add(x => x.Message, T("AI Studio cannot update itself when installed as a Flatpak. A Flathub listing is planned. Until then, you can find the latest release on GitHub."));
|
||||
parameters.Add(x => x.ReleaseUrl, "https://github.com/MindWorkAI/AI-Studio/releases/latest");
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
await this.DialogService.ShowAsync<UpdateInstructionsDialog>(T("How to update"), parameters, DialogOptions.FULLSCREEN);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
@using AIStudio.Tools.PluginSystem
|
||||
@using AIStudio.Tools.PluginSystem.Assistants
|
||||
@using AIStudio.Tools.Services
|
||||
@inherits MSGComponentBase
|
||||
@attribute [Route(Routes.PLUGINS)]
|
||||
|
||||
@@ -64,11 +65,11 @@
|
||||
</MudStack>
|
||||
</MudTd>
|
||||
<MudTd>
|
||||
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
|
||||
<MudStack Row="true" Spacing="0" AlignItems="AlignItems.Center">
|
||||
@if (context.Type is PluginType.ASSISTANT)
|
||||
{
|
||||
var assistantPlugin = PluginFactory.RunningPlugins.OfType<PluginAssistants>().FirstOrDefault(x => x.Id == context.Id);
|
||||
<AssistantPluginSecurityCard Plugin="@assistantPlugin" Compact="@true" />
|
||||
<AssistantPluginSecurityCard Plugin="@assistantPlugin" Compact="@true"/>
|
||||
}
|
||||
@if (context is { IsInternal: false, Type: not PluginType.CONFIGURATION })
|
||||
{
|
||||
@@ -79,23 +80,46 @@
|
||||
</MudTooltip>
|
||||
}
|
||||
|
||||
@if (context is { IsInternal: false } && !string.IsNullOrWhiteSpace(context.SourceURL))
|
||||
{
|
||||
var sourceUrl = context.SourceURL;
|
||||
var isSendingMail = IsSendingMail(sourceUrl);
|
||||
if (isSendingMail)
|
||||
<MudButtonGroup Class="ms-3">
|
||||
@if (context is { IsInternal: false } && !string.IsNullOrWhiteSpace(context.SourceURL))
|
||||
{
|
||||
<MudTooltip Text="@T("Send a mail")">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Email" Href="@sourceUrl" Target="_blank" Size="Size.Medium"/>
|
||||
var sourceUrl = context.SourceURL;
|
||||
var isSendingMail = IsSendingMail(sourceUrl);
|
||||
if (isSendingMail)
|
||||
{
|
||||
var isDefaultSupportContact = string.Equals(sourceUrl, AssistantPluginGenerationService.DEFAULT_SUPPORT_CONTACT, StringComparison.Ordinal);
|
||||
<MudTooltip Text="@(isDefaultSupportContact ? string.Empty : T("Send a mail"))">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Email" Href="@sourceUrl" Target="_blank" Size="Size.Medium" Disabled="@isDefaultSupportContact"/>
|
||||
</MudTooltip>
|
||||
}
|
||||
else
|
||||
{
|
||||
var isDefaultSourceUrl = string.Equals(sourceUrl, AssistantPluginGenerationService.DEFAULT_SOURCE_URL, StringComparison.Ordinal);
|
||||
<MudTooltip Text="@(isDefaultSourceUrl ? T("No source url available") : T("Open website"))">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.OpenInBrowser" Href="@sourceUrl" Target="_blank" Size="Size.Medium" Disabled="@isDefaultSourceUrl"/>
|
||||
</MudTooltip>
|
||||
}
|
||||
}
|
||||
|
||||
@if (context is IAvailablePlugin editablePlugin && CanEditAssistantPlugin(editablePlugin))
|
||||
{
|
||||
<MudTooltip Text="@T("Edit assistant plugin")">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Code" Size="Size.Medium" OnClick="@(() => this.OpenAssistantPluginEditorDialogAsync(editablePlugin))"/>
|
||||
</MudTooltip>
|
||||
}
|
||||
else
|
||||
|
||||
@if (context is IAvailablePlugin revisionPlugin && CanReviseAssistantPlugin(revisionPlugin))
|
||||
{
|
||||
<MudTooltip Text="@T("Open website")">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.OpenInBrowser" Href="@sourceUrl" Target="_blank" Size="Size.Medium"/>
|
||||
<MudTooltip Text="@T("Revise assistant plugin with AI")">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.AutoMode" Size="Size.Medium" OnClick="@(() => this.OpenAssistantPluginRevisionDialogAsync(revisionPlugin))"/>
|
||||
</MudTooltip>
|
||||
}
|
||||
}
|
||||
|
||||
@if (context is IAvailablePlugin availablePlugin)
|
||||
{
|
||||
<AssistantPluginDeleteAction Plugin="@availablePlugin" />
|
||||
}
|
||||
</MudButtonGroup>
|
||||
</MudStack>
|
||||
</MudTd>
|
||||
</RowTemplate>
|
||||
|
||||
@@ -27,6 +27,8 @@ public partial class Plugins : MSGComponentBase
|
||||
[Inject]
|
||||
private AssistantPluginAuditService AssistantPluginAuditService { get; init; } = null!;
|
||||
|
||||
private static readonly ILogger LOG = Program.LOGGER_FACTORY.CreateLogger(nameof(Plugins));
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
@@ -88,7 +90,7 @@ public partial class Plugins : MSGComponentBase
|
||||
return;
|
||||
}
|
||||
|
||||
if (securityState.IsBelowMinimum && securityState.IsBlocked)
|
||||
if (securityState is { IsBelowMinimum: true, IsBlocked: true })
|
||||
{
|
||||
var blockedAudit = securityState.Audit;
|
||||
if (blockedAudit is not null)
|
||||
@@ -96,7 +98,7 @@ public partial class Plugins : MSGComponentBase
|
||||
return;
|
||||
}
|
||||
|
||||
if (securityState.IsBelowMinimum && securityState.CanOverride &&
|
||||
if (securityState is { IsBelowMinimum: true, CanOverride: true } &&
|
||||
!await this.ConfirmActivationBelowMinimumAsync(pluginMeta.Name, securityState.Audit!.Level))
|
||||
{
|
||||
return;
|
||||
@@ -135,7 +137,7 @@ public partial class Plugins : MSGComponentBase
|
||||
{
|
||||
x => x.Message,
|
||||
string.Format(
|
||||
this.T("The assistant plugin \"{0}\" was audited with the level \"{1}\", which is below the required minimum level \"{2}\". Your current settings allow activation anyway, but this may be potentially dangerous. Do you really want to enable this plugin?"),
|
||||
this.T("The assistant plugin '{0}' was audited with the level '{1}', which is below the required minimum level \"{2}\". Your current settings allow activation anyway, but this may be potentially dangerous. Do you really want to enable this plugin?"),
|
||||
pluginName,
|
||||
actualLevel.GetName(),
|
||||
this.AssistantPluginAuditSettings.MinimumLevel.GetName())
|
||||
@@ -158,7 +160,7 @@ public partial class Plugins : MSGComponentBase
|
||||
return false;
|
||||
|
||||
var securityState = PluginAssistantSecurityResolver.Resolve(this.SettingsManager, assistantPlugin);
|
||||
return securityState.IsBlocked && !securityState.RequiresAudit;
|
||||
return securityState is { IsBlocked: true, RequiresAudit: false };
|
||||
}
|
||||
|
||||
private string GetActivationTooltip(IPluginMetadata pluginMeta, bool isEnabled)
|
||||
@@ -182,6 +184,55 @@ public partial class Plugins : MSGComponentBase
|
||||
: this.T("Enable plugin");
|
||||
}
|
||||
|
||||
private static bool CanEditAssistantPlugin(IAvailablePlugin plugin) => plugin is { IsInternal: false, Type: PluginType.ASSISTANT } && !string.IsNullOrWhiteSpace(plugin.LocalPath);
|
||||
|
||||
private static bool CanReviseAssistantPlugin(IAvailablePlugin plugin)
|
||||
{
|
||||
var assistantPlugin = PluginFactory.RunningPlugins.OfType<PluginAssistants>().FirstOrDefault(x => x.Id == plugin.Id);
|
||||
return plugin is { IsInternal: false, IsManagedByConfigServer: false, Type: PluginType.ASSISTANT } &&
|
||||
!string.IsNullOrWhiteSpace(plugin.LocalPath) &&
|
||||
assistantPlugin?.IsManagedByConfigServer is false;
|
||||
}
|
||||
|
||||
private async Task OpenAssistantPluginEditorDialogAsync(IAvailablePlugin plugin)
|
||||
{
|
||||
var parameters = new DialogParameters<AssistantPluginEditorDialog>
|
||||
{
|
||||
{ x => x.PluginId, plugin.Id },
|
||||
{ x => x.PluginLocalPath, plugin.LocalPath },
|
||||
};
|
||||
|
||||
var dialogReference = await this.DialogService.ShowAsync<AssistantPluginEditorDialog>(this.T("Edit Assistant Plugin"), parameters, DialogOptions.BLOCKING_FULLSCREEN);
|
||||
var dialogResult = await dialogReference.Result;
|
||||
if (dialogResult is null || dialogResult.Canceled || dialogResult.Data is not AssistantPluginEditorDialogResult result)
|
||||
return;
|
||||
|
||||
await this.MessageBus.SendSuccess(new(Icons.Material.Filled.Save, string.Format(this.T("The assistant plugin '{0}' has been successfully saved."), result.PluginName)));
|
||||
LOG.LogInformation($"The assistant plugin '{result.PluginName}' ({result.PluginId}) has been successfully updated.");
|
||||
await this.MessageBus.SendMessage<bool>(this, Event.PLUGINS_RELOADED);
|
||||
await this.InvokeAsync(this.StateHasChanged);
|
||||
}
|
||||
|
||||
private async Task OpenAssistantPluginRevisionDialogAsync(IAvailablePlugin plugin)
|
||||
{
|
||||
var parameters = new DialogParameters<AssistantPluginRevisionDialog>
|
||||
{
|
||||
{ x => x.PluginId, plugin.Id },
|
||||
{ x => x.PluginLocalPath, plugin.LocalPath },
|
||||
};
|
||||
|
||||
var dialogReference = await this.DialogService.ShowAsync<AssistantPluginRevisionDialog>(this.T("Revise Assistant Plugin"), parameters, DialogOptions.BLOCKING_FULLSCREEN);
|
||||
var dialogResult = await dialogReference.Result;
|
||||
if (dialogResult is null || dialogResult.Canceled || dialogResult.Data is not AssistantPluginRevisionDialogResult result)
|
||||
return;
|
||||
|
||||
await this.MessageBus.SendSuccess(new(Icons.Material.Filled.AutoFixHigh, string.Format(this.T("The assistant plugin '{0}' has been successfully revised."), result.PluginName)));
|
||||
LOG.LogInformation($"The assistant plugin '{result.PluginName}' ({result.PluginId}) has been successfully revised.");
|
||||
await this.MessageBus.SendMessage<bool>(this, Event.PLUGINS_RELOADED);
|
||||
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||
await this.InvokeAsync(this.StateHasChanged);
|
||||
}
|
||||
|
||||
private static bool IsSendingMail(string sourceUrl) => sourceUrl.TrimStart().StartsWith("mailto:", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
private PluginAssistants? TryGetAssistantPlugin(Guid pluginId) => PluginFactory.RunningPlugins.OfType<PluginAssistants>().FirstOrDefault(x => x.Id == pluginId);
|
||||
|
||||
Reference in new issue
Block a user