mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-17 18:38:00 +00:00
Merge branch 'main' into chunk-data
This commit is contained in:
commit
00b6c98f3b
167 files changed
+8153
-3577
No files matched your search
@@ -89,6 +89,7 @@
|
||||
<ChatComponent
|
||||
@bind-ChatThread="@this.chatThread"
|
||||
@bind-Provider="@this.providerSettings"
|
||||
ComposerState="@this.composerState"
|
||||
Workspaces="@this.workspaces"
|
||||
WorkspaceName="name => this.UpdateWorkspaceName(name)"/>
|
||||
</EndContent>
|
||||
@@ -115,6 +116,7 @@
|
||||
<ChatComponent
|
||||
@bind-ChatThread="@this.chatThread"
|
||||
@bind-Provider="@this.providerSettings"
|
||||
ComposerState="@this.composerState"
|
||||
Workspaces="@this.workspaces"
|
||||
WorkspaceName="name => this.UpdateWorkspaceName(name)"/>
|
||||
</MudStack>
|
||||
@@ -125,6 +127,7 @@
|
||||
<ChatComponent
|
||||
@bind-ChatThread="@this.chatThread"
|
||||
@bind-Provider="@this.providerSettings"
|
||||
ComposerState="@this.composerState"
|
||||
Workspaces="@this.workspaces"
|
||||
WorkspaceName="name => this.UpdateWorkspaceName(name)"/>
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ public partial class Chat : MSGComponentBase
|
||||
private string currentWorkspaceName = string.Empty;
|
||||
private Workspaces? workspaces;
|
||||
private double splitterPosition = 30;
|
||||
private readonly ChatComposerState composerState = new();
|
||||
|
||||
private readonly Timer splitterSaveTimer = new(TimeSpan.FromSeconds(1.6));
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
<MudListItem T="string" Icon="@Icons.Material.Outlined.Widgets" Text="@MudBlazorVersion"/>
|
||||
<MudListItem T="string" Icon="@Icons.Material.Outlined.Memory" Text="@TauriVersion"/>
|
||||
<MudListItem T="string" Icon="@Icons.Material.Outlined.Translate" Text="@this.OSLanguage"/>
|
||||
<MudListItem T="string" Icon="@Icons.Material.Outlined.AccountCircle" Text="@this.OSUserName"/>
|
||||
<MudListItem T="string" Icon="@Icons.Material.Outlined.Business">
|
||||
@switch (HasAnyActiveEnvironment)
|
||||
{
|
||||
@@ -278,11 +279,19 @@
|
||||
<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!")"/>
|
||||
|
||||
@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="Qdrant" 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 is a 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.")"/>
|
||||
<ThirdPartyComponent Name="Rocket" Developer="Sergio Benitez & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/rwf2/Rocket/blob/master/LICENSE-MIT" RepositoryUrl="https://github.com/rwf2/Rocket" UseCase="@T("We use Rocket to implement the runtime API. This is necessary because the runtime must be able to communicate with the user interface (IPC). Rocket is a great framework for implementing web APIs in Rust.")"/>
|
||||
<ThirdPartyComponent Name="axum" Developer="David Pedersen, Jonas Platte, tottoto, David Mládek, Yann Simon, Tobias Bieniek, Open Source Community & Tokio Project" LicenseName="MIT" LicenseUrl="https://github.com/tokio-rs/axum/blob/main/LICENSE" RepositoryUrl="https://github.com/tokio-rs/axum" UseCase="@T("Axum is used to provide the small internal service that connects the Rust runtime with the app's user interface. This lets both parts of AI Studio exchange information while the app is running.")"/>
|
||||
<ThirdPartyComponent Name="axum-server" Developer="Eray Karatay, Adi Salimgereyev, daxpedda & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/programatik29/axum-server/blob/master/LICENSE" RepositoryUrl="https://github.com/programatik29/axum-server" UseCase="@T("Axum server runs the internal axum service over a secure local connection. This helps AI Studio protect the communication between the Rust runtime and the user interface.")"/>
|
||||
<ThirdPartyComponent Name="Rustls" Developer="Joe Birr-Pixton, Dirkjan Ochtman, Daniel McCarney, Brian Smith, Jacob Hoffman-Andrews, Jorge Aparicio & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/rustls/rustls/blob/main/LICENSE-MIT" RepositoryUrl="https://github.com/rustls/rustls" UseCase="@T("Rustls helps secure the internal connection between the app's user interface and the Rust runtime. This protects the local communication that AI Studio needs while it is running.")"/>
|
||||
<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" Developer="Walther Chen, Daniel Brotsky & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/hwchen/keyring-rs/blob/master/LICENSE-MIT" RepositoryUrl="https://github.com/hwchen/keyring-rs" UseCase="@T("In order to use any LLM, each user must store their so-called API key for each LLM provider. This key must be kept secure, similar to a password. The safest way to do this is offered by operating systems like macOS, Windows, and Linux: They have mechanisms to store such data, if available, on special security hardware. Since this is currently not possible in .NET, we use this Rust library.")"/>
|
||||
<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="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.")"/>
|
||||
@@ -299,6 +308,7 @@
|
||||
<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.")"/>
|
||||
<ThirdPartyComponent Name="sys-locale" Developer="1Password Team, ComplexSpaces & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/1Password/sys-locale/blob/main/LICENSE-MIT" RepositoryUrl="https://github.com/1Password/sys-locale" UseCase="@T("This library is used to determine the language of the operating system. This is necessary to set the language of the user interface.")"/>
|
||||
<ThirdPartyComponent Name="whoami" Developer="Ardaku Systems, Jeryn Aldaron Lau, Chase Johnson & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/ardaku/whoami/blob/stable/LICENSE_MIT" RepositoryUrl="https://github.com/ardaku/whoami" UseCase="@T("This library is used by the Rust runtime to read the current user's username, e.g. when an organization-managed ERI server uses the OS username for authentication.")"/>
|
||||
<ThirdPartyComponent Name="sysinfo" Developer="Guillaume Gomez & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/GuillaumeGomez/sysinfo/blob/main/LICENSE" RepositoryUrl="https://github.com/GuillaumeGomez/sysinfo" UseCase="@T("This library is used to manage sidecar processes and to ensure that stale or zombie sidecars are detected and terminated.")"/>
|
||||
<ThirdPartyComponent Name="tempfile" Developer="Steven Allen, Ashley Mannix & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/Stebalien/tempfile/blob/master/LICENSE-MIT" RepositoryUrl="https://github.com/Stebalien/tempfile" UseCase="@T("This library is used to create temporary folders for saving the certificate and private key for communication with Qdrant.")"/>
|
||||
<ThirdPartyComponent Name="Lua-CSharp" Developer="Yusuke Nakada & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/nuskey8/Lua-CSharp/blob/main/LICENSE" RepositoryUrl="https://github.com/nuskey8/Lua-CSharp" UseCase="@T("We use Lua as the language for plugins. Lua-CSharp lets Lua scripts communicate with AI Studio and vice versa. Thank you, Yusuke Nakada, for this great library.")" />
|
||||
@@ -314,4 +324,4 @@
|
||||
</ExpansionPanel>
|
||||
</MudExpansionPanels>
|
||||
</InnerScrolling>
|
||||
</div>
|
||||
</div>
|
||||
@@ -29,17 +29,18 @@ public partial class Information : MSGComponentBase
|
||||
private ISnackbar Snackbar { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private EmbeddingStore EmbeddingStore { get; init; } = null!;
|
||||
private DatabaseClient DatabaseClient { get; init; } = null!;
|
||||
|
||||
private static readonly Assembly ASSEMBLY = Assembly.GetExecutingAssembly();
|
||||
private static readonly MetaDataAttribute META_DATA = ASSEMBLY.GetCustomAttribute<MetaDataAttribute>()!;
|
||||
private static readonly MetaDataArchitectureAttribute META_DATA_ARCH = ASSEMBLY.GetCustomAttribute<MetaDataArchitectureAttribute>()!;
|
||||
private static readonly MetaDataLibrariesAttribute META_DATA_LIBRARIES = ASSEMBLY.GetCustomAttribute<MetaDataLibrariesAttribute>()!;
|
||||
private static readonly MetaDataDatabasesAttribute META_DATA_DATABASES = ASSEMBLY.GetCustomAttribute<MetaDataDatabasesAttribute>()!;
|
||||
private static readonly MetaDataEmbeddingStoreAttribute META_DATA_EMBEDDING_STORE = ASSEMBLY.GetCustomAttribute<MetaDataEmbeddingStoreAttribute>()!;
|
||||
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(Information).Namespace, nameof(Information));
|
||||
|
||||
private string osLanguage = string.Empty;
|
||||
private string osUserName = string.Empty;
|
||||
|
||||
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()})";
|
||||
|
||||
@@ -49,6 +50,8 @@ public partial class Information : MSGComponentBase
|
||||
|
||||
private string OSLanguage => $"{T("User-language provided by the OS")}: '{this.osLanguage}'";
|
||||
|
||||
private string OSUserName => $"{T("Username provided by the OS")}: '{this.osUserName}'";
|
||||
|
||||
private string VersionRust => $"{T("Used Rust compiler")}: v{META_DATA.RustVersion}";
|
||||
|
||||
private string VersionDotnetRuntime => $"{T("Used .NET runtime")}: v{META_DATA.DotnetVersion}";
|
||||
@@ -59,9 +62,21 @@ public partial class Information : MSGComponentBase
|
||||
|
||||
private string VersionPdfium => $"{T("Used PDFium version")}: v{META_DATA_LIBRARIES.PdfiumVersion}";
|
||||
|
||||
private string VersionDatabase => this.EmbeddingStore.IsAvailable
|
||||
? $"{T("Database version")}: {this.EmbeddingStore.Name} v{META_DATA_DATABASES.DatabaseVersion}"
|
||||
: $"{T("Database")}: {this.EmbeddingStore.Name} - {T("not available")}";
|
||||
private string VersionEmbeddingStore
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.embeddingStore is null)
|
||||
return $"{T("Embedding store")}: {T("checking availability")}";
|
||||
|
||||
return this.embeddingStore.Status switch
|
||||
{
|
||||
EmbeddingStoreStatus.AVAILABLE => $"{T("Embedding store version")}: {this.embeddingStore.Name} v{META_DATA_EMBEDDING_STORE.DatabaseVersion}",
|
||||
EmbeddingStoreStatus.STARTING => $"{T("Embedding store")}: {this.embeddingStore.Name} - {T("starting")}",
|
||||
_ => $"{T("Embedding store")}: {this.embeddingStore.Name} - {T("not available")}"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private string versionPandoc = TB("Determine Pandoc version, please wait...");
|
||||
private PandocInstallation pandocInstallation;
|
||||
@@ -70,7 +85,7 @@ public partial class Information : MSGComponentBase
|
||||
|
||||
private bool showEnterpriseConfigDetails;
|
||||
|
||||
private bool showDatabaseDetails;
|
||||
private bool showEmbeddingStoreDetails;
|
||||
|
||||
private List<IAvailablePlugin> configPlugins = PluginFactory.AvailablePlugins
|
||||
.Where(x => x.Type is PluginType.CONFIGURATION)
|
||||
@@ -81,11 +96,13 @@ public partial class Information : MSGComponentBase
|
||||
|
||||
private List<MandatoryInfoPanelData> mandatoryInfoPanels = [];
|
||||
|
||||
private sealed record DatabaseDisplayInfo(string Label, string Value);
|
||||
private sealed record EmbeddingStoreDisplayInfo(string Label, string Value);
|
||||
|
||||
private sealed record MandatoryInfoPanelData(string HeaderText, string PluginName, DataMandatoryInfo Info, DataMandatoryInfoAcceptance? Acceptance);
|
||||
|
||||
private readonly List<DatabaseDisplayInfo> databaseDisplayInfo = new();
|
||||
private readonly List<EmbeddingStoreDisplayInfo> embeddingStoreDisplayInfo = new();
|
||||
private DatabaseClient? embeddingStore;
|
||||
private CancellationTokenSource? databaseRefreshCancellationTokenSource;
|
||||
|
||||
private bool HasAnyActiveEnvironment => this.enterpriseEnvironments.Any(e => e.IsActive);
|
||||
|
||||
@@ -128,12 +145,12 @@ public partial class Information : MSGComponentBase
|
||||
this.RefreshEnterpriseConfigurationState();
|
||||
|
||||
this.osLanguage = await this.RustService.ReadUserLanguage();
|
||||
this.osUserName = await this.RustService.ReadUserName();
|
||||
this.logPaths = await this.RustService.GetLogPaths();
|
||||
|
||||
await foreach (var (label, value) in this.EmbeddingStore.GetDisplayInfo())
|
||||
{
|
||||
this.databaseDisplayInfo.Add(new DatabaseDisplayInfo(label, value));
|
||||
}
|
||||
await this.RefreshDatabaseInfo(CancellationToken.None);
|
||||
if (this.databaseClient?.Status is DatabaseClientStatus.STARTING)
|
||||
this.StartShortDatabaseRefreshLoop();
|
||||
|
||||
// Determine the Pandoc version may take some time, so we start it here
|
||||
// without waiting for the result:
|
||||
@@ -234,7 +251,70 @@ public partial class Information : MSGComponentBase
|
||||
|
||||
private void ToggleDatabaseDetails()
|
||||
{
|
||||
this.showDatabaseDetails = !this.showDatabaseDetails;
|
||||
this.showEmbeddingStoreDetails = !this.showEmbeddingStoreDetails;
|
||||
}
|
||||
|
||||
private async Task RefreshDatabaseInfo(CancellationToken cancellationToken)
|
||||
{
|
||||
var refreshedClient = await this.DatabaseClientProvider.RefreshClientAsync(DatabaseRole.VECTOR_STORE, cancellationToken);
|
||||
this.databaseClient = refreshedClient;
|
||||
this.embeddingStoreDisplayInfo.Clear();
|
||||
|
||||
try
|
||||
{
|
||||
await foreach (var (label, value) in refreshedClient.GetDisplayInfo().WithCancellation(cancellationToken))
|
||||
{
|
||||
this.embeddingStoreDisplayInfo.Add(new EmbeddingStoreDisplayInfo(label, value));
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.databaseClient = new NoDatabaseClient(refreshedClient.Name, e.Message, DatabaseClientStatus.STARTING);
|
||||
await foreach (var (label, value) in this.databaseClient.GetDisplayInfo().WithCancellation(cancellationToken))
|
||||
{
|
||||
this.embeddingStoreDisplayInfo.Add(new EmbeddingStoreDisplayInfo(label, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void StartShortDatabaseRefreshLoop()
|
||||
{
|
||||
this.databaseRefreshCancellationTokenSource?.Cancel();
|
||||
this.databaseRefreshCancellationTokenSource?.Dispose();
|
||||
this.databaseRefreshCancellationTokenSource = new CancellationTokenSource();
|
||||
var cancellationToken = this.databaseRefreshCancellationTokenSource.Token;
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
const int MAX_TRIES = 12;
|
||||
for (var attempt = 0; attempt < MAX_TRIES; attempt++)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
|
||||
await this.InvokeAsync(async () =>
|
||||
{
|
||||
await this.RefreshDatabaseInfo(cancellationToken);
|
||||
this.StateHasChanged();
|
||||
});
|
||||
|
||||
if (this.databaseClient?.Status is not DatabaseClientStatus.STARTING)
|
||||
return;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
private IAvailablePlugin? FindManagedConfigurationPlugin(Guid configurationId)
|
||||
@@ -249,6 +329,13 @@ public partial class Information : MSGComponentBase
|
||||
return plugin.ManagedConfigurationId == configurationId && plugin.Id != configurationId;
|
||||
}
|
||||
|
||||
protected override void DisposeResources()
|
||||
{
|
||||
this.databaseRefreshCancellationTokenSource?.Cancel();
|
||||
this.databaseRefreshCancellationTokenSource?.Dispose();
|
||||
base.DisposeResources();
|
||||
}
|
||||
|
||||
private async Task CopyStartupLogPath()
|
||||
{
|
||||
await this.RustService.CopyText2Clipboard(this.Snackbar, this.logPaths.LogStartupPath);
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace AIStudio.Pages;
|
||||
|
||||
public partial class Writer : MSGComponentBase
|
||||
{
|
||||
private static readonly ILogger<Writer> LOGGER = Program.LOGGER_FACTORY.CreateLogger<Writer>();
|
||||
private static readonly Dictionary<string, object?> USER_INPUT_ATTRIBUTES = new();
|
||||
private readonly Timer typeTimer = new(TimeSpan.FromMilliseconds(1_500));
|
||||
|
||||
@@ -106,22 +107,38 @@ public partial class Writer : MSGComponentBase
|
||||
InitialRemoteWait = true,
|
||||
};
|
||||
|
||||
this.chatThread?.Blocks.Add(new ContentBlock
|
||||
var aiBlock = new ContentBlock
|
||||
{
|
||||
Time = time,
|
||||
ContentType = ContentType.TEXT,
|
||||
Role = ChatRole.AI,
|
||||
Content = aiText,
|
||||
});
|
||||
};
|
||||
|
||||
this.chatThread?.Blocks.Add(aiBlock);
|
||||
|
||||
this.isStreaming = true;
|
||||
this.StateHasChanged();
|
||||
|
||||
this.chatThread = await aiText.CreateFromProviderAsync(this.providerSettings.CreateProvider(), this.providerSettings.Model, lastUserPrompt, this.chatThread);
|
||||
this.suggestion = aiText.Text;
|
||||
|
||||
this.isStreaming = false;
|
||||
this.StateHasChanged();
|
||||
|
||||
try
|
||||
{
|
||||
this.chatThread = await aiText.CreateFromProviderAsync(this.providerSettings.CreateProvider(), this.providerSettings.Model, lastUserPrompt, this.chatThread);
|
||||
this.suggestion = aiText.Text;
|
||||
}
|
||||
catch (ProviderRequestException e)
|
||||
{
|
||||
LOGGER.LogError(e, "The provider request failed for writer suggestions. Status={StatusCode}, Reason='{ReasonPhrase}', Body='{ResponseBody}'", e.StatusCode, e.ReasonPhrase, e.ResponseBody);
|
||||
await this.MessageBus.SendError(new(Icons.Material.Filled.CloudOff, e.UserMessage));
|
||||
this.suggestion = string.Empty;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(aiText.Text))
|
||||
this.chatThread?.Blocks.Remove(aiBlock);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.isStreaming = false;
|
||||
this.StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void AcceptEntireSuggestion()
|
||||
|
||||
Reference in new issue
Block a user