mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-06-27 18:16:26 +00:00
Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc53278c60 | ||
|
|
2acb6f2a57 | ||
|
|
5af616f565 | ||
|
|
6d48252db3 | ||
|
|
64e91ff4ff | ||
|
|
dddb40096d | ||
|
|
e65110a142 | ||
|
|
5045da3a91 | ||
|
|
e04879fd7f | ||
|
|
fc7197ec93 | ||
|
|
c3bf2563cd | ||
|
|
24952e796e | ||
|
|
4c328c8e72 | ||
|
|
c0e6a9a644 | ||
|
|
71ae52753a | ||
|
|
e4fa1cd72a | ||
|
|
0ea63a16c0 | ||
|
|
5272895441 | ||
|
|
f017b87abd | ||
|
|
c07a5227dc | ||
|
|
1c2d243c1f | ||
|
|
e9da7d31df | ||
|
|
b9813fcbe7 | ||
|
|
0a4208d91d | ||
|
|
102b344557 | ||
|
|
0b41f5eb96 | ||
|
|
9fc7eaff99 | ||
|
|
25595a39a5 | ||
|
|
f47dd5fdc2 | ||
|
|
5b5b6e0b28 | ||
|
|
1000d7fbc4 | ||
|
|
bd9597c706 | ||
|
|
b4c3abd6b0 | ||
|
|
86700847e9 | ||
|
|
b37f70d7ff | ||
|
|
e27cd27dba | ||
|
|
def685d2c2 | ||
|
|
a15c47b56d |
139
.github/workflows/build-and-release.yml
vendored
139
.github/workflows/build-and-release.yml
vendored
@ -329,8 +329,8 @@ jobs:
|
||||
pdfium_version=$(sed -n '11p' metadata.txt)
|
||||
pdfium_version=$(echo $pdfium_version | cut -d'.' -f3)
|
||||
|
||||
# Next line is the Qdrant version:
|
||||
qdrant_version="v$(sed -n '12p' metadata.txt)"
|
||||
# Next line is the vector store version:
|
||||
vector_store_version="$(sed -n '12p' metadata.txt)"
|
||||
|
||||
# Write the metadata to the environment:
|
||||
echo "APP_VERSION=${app_version}" >> $GITHUB_ENV
|
||||
@ -344,7 +344,7 @@ jobs:
|
||||
echo "TAURI_VERSION=${tauri_version}" >> $GITHUB_ENV
|
||||
echo "ARCHITECTURE=${{ matrix.dotnet_runtime }}" >> $GITHUB_ENV
|
||||
echo "PDFIUM_VERSION=${pdfium_version}" >> $GITHUB_ENV
|
||||
echo "QDRANT_VERSION=${qdrant_version}" >> $GITHUB_ENV
|
||||
echo "VECTOR_STORE_VERSION=${vector_store_version}" >> $GITHUB_ENV
|
||||
|
||||
# Log the metadata:
|
||||
echo "App version: '${formatted_app_version}'"
|
||||
@ -357,7 +357,7 @@ jobs:
|
||||
echo "Tauri version: '${tauri_version}'"
|
||||
echo "Architecture: '${{ matrix.dotnet_runtime }}'"
|
||||
echo "PDFium version: '${pdfium_version}'"
|
||||
echo "Qdrant version: '${qdrant_version}'"
|
||||
echo "Vector store version: '${vector_store_version}'"
|
||||
|
||||
- name: Read and format metadata (Windows)
|
||||
if: matrix.platform == 'windows-latest'
|
||||
@ -402,8 +402,8 @@ jobs:
|
||||
$pdfium_version = $metadata[10]
|
||||
$pdfium_version = $pdfium_version.Split('.')[2]
|
||||
|
||||
# Next line is the necessary Qdrant version:
|
||||
$qdrant_version = "v$($metadata[11])"
|
||||
# Next line is the vector store version:
|
||||
$vector_store_version = $metadata[11]
|
||||
|
||||
# Write the metadata to the environment:
|
||||
Write-Output "APP_VERSION=${app_version}" >> $env:GITHUB_ENV
|
||||
@ -416,7 +416,7 @@ jobs:
|
||||
Write-Output "MUD_BLAZOR_VERSION=${mud_blazor_version}" >> $env:GITHUB_ENV
|
||||
Write-Output "ARCHITECTURE=${{ matrix.dotnet_runtime }}" >> $env:GITHUB_ENV
|
||||
Write-Output "PDFIUM_VERSION=${pdfium_version}" >> $env:GITHUB_ENV
|
||||
Write-Output "QDRANT_VERSION=${qdrant_version}" >> $env:GITHUB_ENV
|
||||
Write-Output "VECTOR_STORE_VERSION=${vector_store_version}" >> $env:GITHUB_ENV
|
||||
|
||||
# Log the metadata:
|
||||
Write-Output "App version: '${formatted_app_version}'"
|
||||
@ -429,7 +429,7 @@ jobs:
|
||||
Write-Output "Tauri version: '${tauri_version}'"
|
||||
Write-Output "Architecture: '${{ matrix.dotnet_runtime }}'"
|
||||
Write-Output "PDFium version: '${pdfium_version}'"
|
||||
Write-Output "Qdrant version: '${qdrant_version}'"
|
||||
Write-Output "Vector store version: '${vector_store_version}'"
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
@ -558,129 +558,6 @@ jobs:
|
||||
} catch {
|
||||
Write-Warning "Could not fully clean up temporary directory: $TMP. This is usually harmless as Windows will clean it up later. Error: $($_.Exception.Message)"
|
||||
}
|
||||
- name: Deploy Qdrant (Unix)
|
||||
if: matrix.platform != 'windows-latest'
|
||||
env:
|
||||
QDRANT_VERSION: ${{ env.QDRANT_VERSION }}
|
||||
DOTNET_RUNTIME: ${{ matrix.dotnet_runtime }}
|
||||
RUST_TARGET: ${{ matrix.rust_target }}
|
||||
run: |
|
||||
set -e
|
||||
|
||||
# Target directory:
|
||||
TDB_DIR="runtime/target/databases/qdrant"
|
||||
mkdir -p "$TDB_DIR"
|
||||
|
||||
case "${DOTNET_RUNTIME}" in
|
||||
linux-x64)
|
||||
QDRANT_FILE="x86_64-unknown-linux-gnu.tar.gz"
|
||||
DB_SOURCE="qdrant"
|
||||
DB_TARGET="qdrant-${RUST_TARGET}"
|
||||
;;
|
||||
linux-arm64)
|
||||
QDRANT_FILE="aarch64-unknown-linux-musl.tar.gz"
|
||||
DB_SOURCE="qdrant"
|
||||
DB_TARGET="qdrant-${RUST_TARGET}"
|
||||
;;
|
||||
osx-x64)
|
||||
QDRANT_FILE="x86_64-apple-darwin.tar.gz"
|
||||
DB_SOURCE="qdrant"
|
||||
DB_TARGET="qdrant-${RUST_TARGET}"
|
||||
;;
|
||||
osx-arm64)
|
||||
QDRANT_FILE="aarch64-apple-darwin.tar.gz"
|
||||
DB_SOURCE="qdrant"
|
||||
DB_TARGET="qdrant-${RUST_TARGET}"
|
||||
;;
|
||||
*)
|
||||
echo "Unknown platform: ${DOTNET_RUNTIME}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
QDRANT_URL="https://github.com/qdrant/qdrant/releases/download/${QDRANT_VERSION}/qdrant-${QDRANT_FILE}"
|
||||
|
||||
echo "Download Qdrant $QDRANT_URL ..."
|
||||
TMP=$(mktemp -d)
|
||||
ARCHIVE="${TMP}/qdrant.tgz"
|
||||
|
||||
curl -fsSL -o "$ARCHIVE" "$QDRANT_URL"
|
||||
|
||||
echo "Extracting Qdrant ..."
|
||||
tar xzf "$ARCHIVE" -C "$TMP"
|
||||
SRC="${TMP}/${DB_SOURCE}"
|
||||
|
||||
if [ ! -f "$SRC" ]; then
|
||||
echo "Was not able to find Qdrant source: $SRC"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Copy Qdrant from ${DB_TARGET} to ${TDB_DIR}/"
|
||||
cp -f "$SRC" "$TDB_DIR/$DB_TARGET"
|
||||
|
||||
echo "Cleaning up ..."
|
||||
rm -fr "$TMP"
|
||||
|
||||
- name: Deploy Qdrant (Windows)
|
||||
if: matrix.platform == 'windows-latest'
|
||||
env:
|
||||
QDRANT_VERSION: ${{ env.QDRANT_VERSION }}
|
||||
DOTNET_RUNTIME: ${{ matrix.dotnet_runtime }}
|
||||
RUST_TARGET: ${{ matrix.rust_target }}
|
||||
run: |
|
||||
$TDB_DIR = "runtime\target\databases\qdrant"
|
||||
New-Item -ItemType Directory -Force -Path $TDB_DIR | Out-Null
|
||||
|
||||
switch ($env:DOTNET_RUNTIME) {
|
||||
"win-x64" {
|
||||
$QDRANT_FILE = "x86_64-pc-windows-msvc.zip"
|
||||
$DB_SOURCE = "qdrant.exe"
|
||||
$DB_TARGET = "qdrant-$($env:RUST_TARGET).exe"
|
||||
}
|
||||
"win-arm64" {
|
||||
$QDRANT_FILE = "x86_64-pc-windows-msvc.zip"
|
||||
$DB_SOURCE = "qdrant.exe"
|
||||
$DB_TARGET = "qdrant-$($env:RUST_TARGET).exe"
|
||||
}
|
||||
default {
|
||||
Write-Error "Unknown platform: $($env:DOTNET_RUNTIME)"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
$QDRANT_URL = "https://github.com/qdrant/qdrant/releases/download/$($env:QDRANT_VERSION)/qdrant-$QDRANT_FILE"
|
||||
Write-Host "Download $QDRANT_URL ..."
|
||||
|
||||
# Create a unique temporary directory (not just a file)
|
||||
$TMP = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())
|
||||
New-Item -ItemType Directory -Path $TMP -Force | Out-Null
|
||||
$ARCHIVE = Join-Path $TMP "qdrant.tgz"
|
||||
|
||||
Invoke-WebRequest -Uri $QDRANT_URL -OutFile $ARCHIVE
|
||||
|
||||
Write-Host "Extracting Qdrant ..."
|
||||
tar -xzf $ARCHIVE -C $TMP
|
||||
|
||||
$SRC = Join-Path $TMP $DB_SOURCE
|
||||
if (!(Test-Path $SRC)) {
|
||||
Write-Error "Cannot find Qdrant source: $SRC"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$DEST = Join-Path $TDB_DIR $DB_TARGET
|
||||
Copy-Item -Path $SRC -Destination $DEST -Force
|
||||
|
||||
Write-Host "Cleaning up ..."
|
||||
Remove-Item $ARCHIVE -Force -ErrorAction SilentlyContinue
|
||||
|
||||
# Try to remove the temporary directory, but ignore errors if files are still in use
|
||||
try {
|
||||
Remove-Item $TMP -Recurse -Force -ErrorAction Stop
|
||||
Write-Host "Successfully cleaned up temporary directory: $TMP"
|
||||
} catch {
|
||||
Write-Warning "Could not fully clean up temporary directory: $TMP. This is usually harmless as Windows will clean it up later. Error: $($_.Exception.Message)"
|
||||
}
|
||||
|
||||
- name: Build .NET project
|
||||
run: |
|
||||
cd "app/MindWork AI Studio"
|
||||
|
||||
23
AGENTS.md
23
AGENTS.md
@ -7,7 +7,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
MindWork AI Studio is a cross-platform desktop application for interacting with Large Language Models (LLMs). The app uses a hybrid architecture combining a Rust Tauri runtime (for the native desktop shell) with a .NET Blazor Server web application (for the UI and business logic).
|
||||
|
||||
**Key Architecture Points:**
|
||||
- **Runtime:** Rust-based Tauri v1.8 application providing the native window, system integration, and IPC layer
|
||||
- **Runtime:** Rust-based Tauri v2 application providing the native window, system integration, and IPC layer
|
||||
- **App:** .NET 9 Blazor Server application providing the UI and core functionality
|
||||
- **Communication:** The Rust runtime and .NET app communicate via HTTPS with TLS certificates generated at startup
|
||||
- **Providers:** Multi-provider architecture supporting OpenAI, Anthropic, Google, Mistral, Perplexity, self-hosted models, and others
|
||||
@ -18,7 +18,7 @@ MindWork AI Studio is a cross-platform desktop application for interacting with
|
||||
### Prerequisites
|
||||
- .NET 9 SDK
|
||||
- Rust toolchain (stable)
|
||||
- Tauri v1.6.2 CLI: `cargo install --version 1.6.2 tauri-cli`
|
||||
- Tauri v2 CLI
|
||||
- Tauri prerequisites (platform-specific dependencies)
|
||||
- **Note:** Development on Linux is discouraged due to complex Tauri dependencies that vary by distribution
|
||||
|
||||
@ -112,12 +112,16 @@ Plugins can configure:
|
||||
- Chat templates
|
||||
- etc.
|
||||
|
||||
When adding configuration options, update:
|
||||
- `app/MindWork AI Studio/Tools/PluginSystem/PluginConfiguration.cs`: In method `TryProcessConfiguration` register new options.
|
||||
- `app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Loading.cs`: In method `LoadAll` check for leftover configuration.
|
||||
- The corresponding data class in `app/MindWork AI Studio/Settings/DataModel/` to call `ManagedConfiguration.Register(...)`, when adding config options (in contrast to complex config. objects)
|
||||
- `app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObject.cs` for parsing logic of complex configuration objects.
|
||||
- `app/MindWork AI Studio/Plugins/configuration/plugin.lua` to document the new configuration option.
|
||||
Configuration plugins provide three kinds of values:
|
||||
- **Managed settings:** simple values such as booleans, numbers, strings, enums, lists, or sets handled through `ManagedConfiguration`. These values may be locked or used as organization defaults.
|
||||
- **Managed configuration objects:** complex Lua tables that are persisted into `SettingsManager.ConfigurationData`, implement `IConfigurationObject`, and are cleaned up through `PluginConfigurationObject.CleanLeftOverConfigurationObjects(...)`. Examples include providers, profiles, chat templates, data sources, and document analysis policies.
|
||||
- **Live plugin content:** complex Lua tables that implement `ILivePluginContent` and are read live from running plugins instead of being persisted to `ConfigurationData`. Examples include `MANDATORY_INFOS` and `INTRODUCTIONS`. If live plugin content creates persistent side data, add a dedicated cleanup path for that side data, like mandatory-info acceptances.
|
||||
|
||||
When adding configuration plugin capabilities:
|
||||
- For managed settings, update the corresponding data class in `app/MindWork AI Studio/Settings/DataModel/` to call `ManagedConfiguration.Register(...)`, process the setting in `PluginConfiguration.TryProcessConfiguration`, and check for leftover managed configuration in `PluginFactory.Loading.LoadAll`.
|
||||
- For managed configuration objects, update `PluginConfigurationObject.cs` and `PluginConfigurationObjectType.cs`, persist them in the appropriate `ConfigurationData` collection, and add cleanup via `PluginConfigurationObject.CleanLeftOverConfigurationObjects(...)`.
|
||||
- For live plugin content, add a data type implementing `ILivePluginContent`, parse it in `PluginConfiguration`, expose it through `PluginFactory`, and add any required cleanup only for persistent side data.
|
||||
- Always document the new capability in `app/MindWork AI Studio/Plugins/configuration/plugin.lua`.
|
||||
|
||||
## RAG (Retrieval-Augmented Generation)
|
||||
|
||||
@ -151,7 +155,7 @@ Multi-level confidence scheme allows users to control which providers see which
|
||||
## Dependencies and Frameworks
|
||||
|
||||
**Rust:**
|
||||
- Tauri 1.8 - Desktop application framework
|
||||
- Tauri 2 - Desktop application framework
|
||||
- Axum - HTTPS API server
|
||||
- tokio - Async runtime
|
||||
- keyring - OS keyring integration
|
||||
@ -196,6 +200,7 @@ Multi-level confidence scheme allows users to control which providers see which
|
||||
- **Encryption** - Initialized before Rust service is marked ready
|
||||
- **Message Bus** - Singleton event bus for cross-component communication inside the .NET app
|
||||
- **Naming conventions** - Constants, enum members, and `static readonly` fields use `UPPER_SNAKE_CASE` such as `MY_CONSTANT`.
|
||||
- **Compatibility shims** - Temporary fallback or read-repair code must be documented in `documentation/compatibility-shims/` with an introduced date, remove-after date, code references, and removal checklist. Add a short code comment near the shim that references the document and remove-after date. Check this folder before adding similar fallback logic, and do not extend expired shims without explicit maintainer direction. Do not use this process for permanent settings schema migrations; those belong in `app/MindWork AI Studio/Settings/SettingsMigrations.cs`.
|
||||
- **Empty lines** - Avoid adding extra empty lines at the end of files.
|
||||
|
||||
## Changelogs
|
||||
|
||||
@ -78,6 +78,9 @@ Since March 2025: We have started developing the plugin system. There will be la
|
||||
</h3>
|
||||
</summary>
|
||||
|
||||
- v26.6.2: Expanded enterprise configuration options with chat defaults, custom introduction panels, trust settings for data security, and managed confidence levels; added auto-backups for app settings & the possibility to view managed profiles and chat templates.
|
||||
- v26.6.1: Increased enterprise configuration capacity for large organizations, broader Flatpak deployment support, startup and Linux package diagnostics, chat search across all workspaces, improved workspace workflows, better model discovery for self-hosted llama.cpp providers, and fixes for profile and chat template updates, workspace naming, and startup behavior.
|
||||
- v26.5.5: Released voice recording and transcription for all users; added support for multiple chats running at the same time, export options for profiles, chat templates, and ERI data sources, organization-managed ERI servers, and configurable request timeouts; upgraded the native runtime to Tauri v2.
|
||||
- v26.4.1: Added support for the latest AI models, assistant plugins, a slide planner assistant, a prompt optimization assistant, math rendering in chats, and a configurable start page; released the document analysis assistant and improved enterprise deployment, chat performance, file attachments, and reliability across voice recording, logging, and provider validation.
|
||||
- v26.2.2: Added Qdrant as a building block for our local RAG preview, added an embedding test option to validate embedding providers, and improved enterprise and configuration plugins with preselected providers, additive preview features, support for multiple configurations, and more reliable synchronization.
|
||||
- v26.1.1: Added the option to attach files, including images, to chat templates; added support for source code file attachments in chats and document analysis; added a preview feature for recording your own voice for transcription; fixed various bugs in provider dialogs and profile selection.
|
||||
@ -87,9 +90,6 @@ Since March 2025: We have started developing the plugin system. There will be la
|
||||
- v0.9.46: Released our plugin system, a German language plugin, early support for enterprise environments, and configuration plugins. Additionally, we added the Pandoc integration for future data processing and file generation.
|
||||
- v0.9.45: Added chat templates to AI Studio, allowing you to create and use a library of system prompts for your chats.
|
||||
- v0.9.44: Added PDF import to the text summarizer, translation, and legal check assistants, allowing you to import PDF files and use them as input for the assistants.
|
||||
- v0.9.40: Added support for the `o4` models from OpenAI. Also, we added Alibaba Cloud & Hugging Face as LLM providers.
|
||||
- v0.9.39: Added the plugin system as a preview feature.
|
||||
- v0.9.31: Added Helmholtz & GWDG as LLM providers. This is a huge improvement for many researchers out there who can use these providers for free. We added DeepSeek as a provider as well.
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
@ -53,6 +53,9 @@ public sealed partial class CollectI18NKeysCommand
|
||||
foreach (var filePath in allFiles)
|
||||
{
|
||||
counter++;
|
||||
if(!this.IsSupportedSourceFile(filePath))
|
||||
continue;
|
||||
|
||||
if(filePath.StartsWith(binPath, StringComparison.OrdinalIgnoreCase))
|
||||
continue;
|
||||
|
||||
@ -68,6 +71,9 @@ public sealed partial class CollectI18NKeysCommand
|
||||
continue;
|
||||
|
||||
var ns = this.DetermineNamespace(filePath);
|
||||
if(ns is null)
|
||||
throw new InvalidOperationException($"Could not determine the namespace for I18N source file '{filePath}'.");
|
||||
|
||||
var fileInfo = new FileInfo(filePath);
|
||||
|
||||
var name = this.DetermineTypeName(filePath)
|
||||
@ -204,6 +210,10 @@ public sealed partial class CollectI18NKeysCommand
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
private bool IsSupportedSourceFile(string filePath) =>
|
||||
filePath.EndsWith(".cs", StringComparison.OrdinalIgnoreCase) ||
|
||||
filePath.EndsWith(".razor", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
private string? DetermineNamespace(string filePath)
|
||||
{
|
||||
@ -302,10 +312,10 @@ public sealed partial class CollectI18NKeysCommand
|
||||
return match.Groups[1].Value;
|
||||
}
|
||||
|
||||
[GeneratedRegex("""@namespace\s+([a-zA-Z0-9_.]+)""")]
|
||||
[GeneratedRegex("""(?m)^\s*@namespace\s+([a-zA-Z0-9_.]+)""")]
|
||||
private static partial Regex BlazorNamespaceRegex();
|
||||
|
||||
[GeneratedRegex("""namespace\s+([a-zA-Z0-9_.]+)""")]
|
||||
[GeneratedRegex("""(?m)^\s*namespace\s+([a-zA-Z0-9_.]+)\s*[;{]""")]
|
||||
private static partial Regex CSharpNamespaceRegex();
|
||||
|
||||
[GeneratedRegex("""\bpartial\s+(?:class|struct|interface|record(?:\s+(?:class|struct))?)\s+([A-Za-z_][A-Za-z0-9_]*)""")]
|
||||
|
||||
@ -7,74 +7,95 @@ namespace Build.Commands;
|
||||
|
||||
public static class Pdfium
|
||||
{
|
||||
public static async Task InstallAsync(RID rid, string version)
|
||||
private static readonly HttpClient CLIENT = new()
|
||||
{
|
||||
Timeout = TimeSpan.FromMinutes(5)
|
||||
};
|
||||
|
||||
public static async Task InstallAsync(RID rid, string version, bool offline)
|
||||
{
|
||||
Console.Write($"- Installing Pdfium {version} for {rid.ToUserFriendlyName()} ...");
|
||||
|
||||
var cwd = Environment.GetRustRuntimeDirectory();
|
||||
var pdfiumTmpDownloadPath = Path.GetTempFileName();
|
||||
var pdfiumTmpExtractPath = Directory.CreateTempSubdirectory();
|
||||
var pdfiumUrl = GetPdfiumDownloadUrl(rid, version);
|
||||
var library = GetLibraryPath(rid);
|
||||
var pdfiumLibTargetPath = Path.Join(cwd, "resources", "libraries", library.Filename);
|
||||
|
||||
//
|
||||
// Download the file:
|
||||
//
|
||||
Console.Write(" downloading ...");
|
||||
using (var client = new HttpClient())
|
||||
if (offline)
|
||||
{
|
||||
var response = await client.GetAsync(pdfiumUrl);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
if (File.Exists(pdfiumLibTargetPath))
|
||||
{
|
||||
Console.WriteLine($" failed to download Pdfium {version} for {rid.ToUserFriendlyName()} from {pdfiumUrl}");
|
||||
Console.WriteLine(" offline mode enabled and library already exists, skipping download");
|
||||
return;
|
||||
}
|
||||
|
||||
await using var fileStream = File.Create(pdfiumTmpDownloadPath);
|
||||
await response.Content.CopyToAsync(fileStream);
|
||||
Console.WriteLine($" failed because offline mode is enabled and '{pdfiumLibTargetPath}' does not exist");
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Extract the downloaded file:
|
||||
//
|
||||
Console.Write(" extracting ...");
|
||||
await using(var tgzStream = File.Open(pdfiumTmpDownloadPath, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
await using var uncompressedStream = new GZipStream(tgzStream, CompressionMode.Decompress);
|
||||
await TarFile.ExtractToDirectoryAsync(uncompressedStream, pdfiumTmpExtractPath.FullName, true);
|
||||
}
|
||||
|
||||
//
|
||||
// Copy the library to the target directory:
|
||||
//
|
||||
Console.Write(" deploying ...");
|
||||
var library = GetLibraryPath(rid);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(library.Path))
|
||||
{
|
||||
Console.WriteLine($" failed to find the library path for {rid.ToUserFriendlyName()}");
|
||||
return;
|
||||
}
|
||||
|
||||
var pdfiumLibSourcePath = Path.Join(pdfiumTmpExtractPath.FullName, library.Path);
|
||||
var pdfiumLibTargetPath = Path.Join(cwd, "resources", "libraries", library.Filename);
|
||||
if (!File.Exists(pdfiumLibSourcePath))
|
||||
|
||||
var pdfiumLibTargetDirectory = Path.Join(cwd, "resources", "libraries");
|
||||
var pdfiumLibTmpTargetPath = Path.Join(pdfiumLibTargetDirectory, $"{library.Filename}.{Guid.NewGuid():N}.tmp");
|
||||
var pdfiumLibArchivePath = library.Path.Replace('\\', '/');
|
||||
|
||||
//
|
||||
// Download the file:
|
||||
//
|
||||
Console.Write(" downloading ...");
|
||||
using var response = await CLIENT.GetAsync(pdfiumUrl, HttpCompletionOption.ResponseHeadersRead);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
Console.WriteLine($" failed to find the library file '{pdfiumLibSourcePath}'");
|
||||
Console.WriteLine($" failed to download Pdfium {version} for {rid.ToUserFriendlyName()} from {pdfiumUrl}");
|
||||
return;
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(Path.Join(cwd, "resources", "libraries"));
|
||||
if (File.Exists(pdfiumLibTargetPath))
|
||||
File.Delete(pdfiumLibTargetPath);
|
||||
|
||||
File.Copy(pdfiumLibSourcePath, pdfiumLibTargetPath);
|
||||
|
||||
|
||||
//
|
||||
// Cleanup:
|
||||
// Extract the library from the downloaded file:
|
||||
//
|
||||
Console.Write(" cleaning up ...");
|
||||
File.Delete(pdfiumTmpDownloadPath);
|
||||
Directory.Delete(pdfiumTmpExtractPath.FullName, true);
|
||||
|
||||
Console.Write(" extracting ...");
|
||||
Directory.CreateDirectory(pdfiumLibTargetDirectory);
|
||||
|
||||
var foundLibrary = false;
|
||||
try
|
||||
{
|
||||
await using var downloadStream = await response.Content.ReadAsStreamAsync();
|
||||
await using var uncompressedStream = new GZipStream(downloadStream, CompressionMode.Decompress);
|
||||
await using var tarReader = new TarReader(uncompressedStream);
|
||||
|
||||
while (await tarReader.GetNextEntryAsync() is { } entry)
|
||||
{
|
||||
if (!string.Equals(entry.Name.Replace('\\', '/'), pdfiumLibArchivePath, StringComparison.Ordinal))
|
||||
continue;
|
||||
|
||||
if (entry.DataStream == null)
|
||||
break;
|
||||
|
||||
await using var fileStream = File.Create(pdfiumLibTmpTargetPath);
|
||||
await entry.DataStream.CopyToAsync(fileStream);
|
||||
foundLibrary = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!foundLibrary)
|
||||
{
|
||||
Console.WriteLine($" failed to find the library file '{pdfiumLibArchivePath}' in the Pdfium archive");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.Write(" deploying ...");
|
||||
File.Move(pdfiumLibTmpTargetPath, pdfiumLibTargetPath, true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (File.Exists(pdfiumLibTmpTargetPath))
|
||||
File.Delete(pdfiumLibTmpTargetPath);
|
||||
}
|
||||
|
||||
Console.WriteLine(" done.");
|
||||
}
|
||||
|
||||
|
||||
@ -1,120 +0,0 @@
|
||||
using System.Formats.Tar;
|
||||
using System.IO.Compression;
|
||||
|
||||
using SharedTools;
|
||||
|
||||
namespace Build.Commands;
|
||||
|
||||
public static class Qdrant
|
||||
{
|
||||
public static async Task InstallAsync(RID rid, string version)
|
||||
{
|
||||
Console.Write($"- Installing Qdrant {version} for {rid.ToUserFriendlyName()} ...");
|
||||
|
||||
var cwd = Environment.GetRustRuntimeDirectory();
|
||||
var qdrantTmpDownloadPath = Path.GetTempFileName();
|
||||
var qdrantTmpExtractPath = Directory.CreateTempSubdirectory();
|
||||
var qdrantUrl = GetQdrantDownloadUrl(rid, version);
|
||||
|
||||
//
|
||||
// Download the file:
|
||||
//
|
||||
Console.Write(" downloading ...");
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
var response = await client.GetAsync(qdrantUrl);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
Console.WriteLine($" failed to download Qdrant {version} for {rid.ToUserFriendlyName()} from {qdrantUrl}");
|
||||
return;
|
||||
}
|
||||
|
||||
await using var fileStream = File.Create(qdrantTmpDownloadPath);
|
||||
await response.Content.CopyToAsync(fileStream);
|
||||
}
|
||||
|
||||
//
|
||||
// Extract the downloaded file:
|
||||
//
|
||||
Console.Write(" extracting ...");
|
||||
await using(var zStream = File.Open(qdrantTmpDownloadPath, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
if (rid == RID.WIN_X64)
|
||||
{
|
||||
using var archive = new ZipArchive(zStream, ZipArchiveMode.Read);
|
||||
archive.ExtractToDirectory(qdrantTmpExtractPath.FullName, overwriteFiles: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
await using var uncompressedStream = new GZipStream(zStream, CompressionMode.Decompress);
|
||||
await TarFile.ExtractToDirectoryAsync(uncompressedStream, qdrantTmpExtractPath.FullName, true);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Copy the database to the target directory:
|
||||
//
|
||||
Console.Write(" deploying ...");
|
||||
var database = GetDatabasePath(rid);
|
||||
if (string.IsNullOrWhiteSpace(database.Path))
|
||||
{
|
||||
Console.WriteLine($" failed to find the database path for {rid.ToUserFriendlyName()}");
|
||||
return;
|
||||
}
|
||||
|
||||
var qdrantDbSourcePath = Path.Join(qdrantTmpExtractPath.FullName, database.Path);
|
||||
var qdrantDbTargetPath = Path.Join(cwd, "target", "databases", "qdrant",database.Filename);
|
||||
if (!File.Exists(qdrantDbSourcePath))
|
||||
{
|
||||
Console.WriteLine($" failed to find the database file '{qdrantDbSourcePath}'");
|
||||
return;
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(Path.Join(cwd, "target", "databases", "qdrant"));
|
||||
if (File.Exists(qdrantDbTargetPath))
|
||||
File.Delete(qdrantDbTargetPath);
|
||||
|
||||
File.Copy(qdrantDbSourcePath, qdrantDbTargetPath);
|
||||
|
||||
//
|
||||
// Cleanup:
|
||||
//
|
||||
Console.Write(" cleaning up ...");
|
||||
File.Delete(qdrantTmpDownloadPath);
|
||||
Directory.Delete(qdrantTmpExtractPath.FullName, true);
|
||||
|
||||
Console.WriteLine(" done.");
|
||||
}
|
||||
|
||||
private static Database GetDatabasePath(RID rid) => rid switch
|
||||
{
|
||||
RID.OSX_ARM64 => new("qdrant", "qdrant-aarch64-apple-darwin"),
|
||||
RID.OSX_X64 => new("qdrant", "qdrant-x86_64-apple-darwin"),
|
||||
|
||||
RID.LINUX_ARM64 => new("qdrant", "qdrant-aarch64-unknown-linux-gnu"),
|
||||
RID.LINUX_X64 => new("qdrant", "qdrant-x86_64-unknown-linux-gnu"),
|
||||
|
||||
RID.WIN_X64 => new("qdrant.exe", "qdrant-x86_64-pc-windows-msvc.exe"),
|
||||
RID.WIN_ARM64 => new("qdrant.exe", "qdrant-aarch64-pc-windows-msvc.exe"),
|
||||
|
||||
_ => new(string.Empty, string.Empty),
|
||||
};
|
||||
|
||||
private static string GetQdrantDownloadUrl(RID rid, string version)
|
||||
{
|
||||
var baseUrl = $"https://github.com/qdrant/qdrant/releases/download/v{version}/qdrant-";
|
||||
return rid switch
|
||||
{
|
||||
RID.LINUX_ARM64 => $"{baseUrl}aarch64-unknown-linux-musl.tar.gz",
|
||||
RID.LINUX_X64 => $"{baseUrl}x86_64-unknown-linux-gnu.tar.gz",
|
||||
|
||||
RID.OSX_ARM64 => $"{baseUrl}aarch64-apple-darwin.tar.gz",
|
||||
RID.OSX_X64 => $"{baseUrl}x86_64-apple-darwin.tar.gz",
|
||||
|
||||
RID.WIN_X64 => $"{baseUrl}x86_64-pc-windows-msvc.zip",
|
||||
RID.WIN_ARM64 => $"{baseUrl}x86_64-pc-windows-msvc.zip",
|
||||
|
||||
_ => string.Empty,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -15,7 +15,8 @@ public sealed partial class UpdateMetadataCommands
|
||||
[Command("release", Description = "Prepare & build the next release")]
|
||||
public async Task Release(
|
||||
[Option("action", ['a'], Description = "The release action: patch, minor, or major")] PrepareAction action = PrepareAction.NONE,
|
||||
[Option("version", ['v'], Description = "Set a specific version directly, e.g., 26.1.2")] string? version = null)
|
||||
[Option("version", ['v'], Description = "Set a specific version directly, e.g., 26.1.2")] string? version = null,
|
||||
[Option("offline", Description = "Skip downloads and use locally available build dependencies")] bool offline = false)
|
||||
{
|
||||
if(!Environment.IsWorkingDirectoryValid())
|
||||
return;
|
||||
@ -42,7 +43,7 @@ public sealed partial class UpdateMetadataCommands
|
||||
|
||||
// Build once to allow the Rust compiler to read the changed metadata
|
||||
// and to update all .NET artifacts:
|
||||
await this.Build();
|
||||
await this.Build(offline);
|
||||
|
||||
// Now, we update the web assets (which may were updated by the first build):
|
||||
new UpdateWebAssetsCommand().UpdateWebAssets();
|
||||
@ -53,7 +54,7 @@ public sealed partial class UpdateMetadataCommands
|
||||
|
||||
// Build the final release, where Rust knows the updated metadata, the .NET
|
||||
// artifacts are already in place, and .NET knows the updated web assets, etc.:
|
||||
await this.Build();
|
||||
await this.Build(offline);
|
||||
}
|
||||
|
||||
[Command("update-versions", Description = "The command will update the package versions in the metadata file")]
|
||||
@ -69,6 +70,7 @@ public sealed partial class UpdateMetadataCommands
|
||||
await this.UpdateRustVersion();
|
||||
await this.UpdateMudBlazorVersion();
|
||||
await this.UpdateTauriVersion();
|
||||
await this.UpdateVectorStoreVersion();
|
||||
}
|
||||
|
||||
[Command("prepare", Description = "Prepare the metadata for the next release")]
|
||||
@ -126,6 +128,7 @@ public sealed partial class UpdateMetadataCommands
|
||||
await this.UpdateRustVersion();
|
||||
await this.UpdateMudBlazorVersion();
|
||||
await this.UpdateTauriVersion();
|
||||
await this.UpdateVectorStoreVersion();
|
||||
await this.UpdateProjectCommitHash();
|
||||
await this.UpdateLicenceYear(Path.GetFullPath(Path.Combine(Environment.GetAIStudioDirectory(), "..", "..", "LICENSE.md")));
|
||||
await this.UpdateLicenceYear(Path.GetFullPath(Path.Combine(Environment.GetAIStudioDirectory(), "Pages", "Information.razor.cs")));
|
||||
@ -134,7 +137,8 @@ public sealed partial class UpdateMetadataCommands
|
||||
}
|
||||
|
||||
[Command("build", Description = "Build MindWork AI Studio")]
|
||||
public async Task Build()
|
||||
public async Task Build(
|
||||
[Option("offline", Description = "Skip downloads and use locally available build dependencies")] bool offline = false)
|
||||
{
|
||||
if(!Environment.IsWorkingDirectoryValid())
|
||||
return;
|
||||
@ -147,12 +151,11 @@ public sealed partial class UpdateMetadataCommands
|
||||
|
||||
Console.WriteLine("==============================");
|
||||
await this.UpdateArchitecture(rid);
|
||||
await this.UpdateTauriVersion();
|
||||
await this.UpdateVectorStoreVersion();
|
||||
|
||||
var pdfiumVersion = await this.ReadPdfiumVersion();
|
||||
await Pdfium.InstallAsync(rid, pdfiumVersion);
|
||||
|
||||
var qdrantVersion = await this.ReadQdrantVersion();
|
||||
await Qdrant.InstallAsync(rid, qdrantVersion);
|
||||
await Pdfium.InstallAsync(rid, pdfiumVersion, Environment.IsOfflineBuildRequested(offline));
|
||||
|
||||
Console.Write($"- Start .NET build for {rid.ToUserFriendlyName()} ...");
|
||||
await this.ReadCommandOutput(pathApp, "dotnet", $"clean --configuration release --runtime {rid.AsMicrosoftRid()}");
|
||||
@ -367,16 +370,6 @@ public sealed partial class UpdateMetadataCommands
|
||||
return shortVersion;
|
||||
}
|
||||
|
||||
private async Task<string> ReadQdrantVersion()
|
||||
{
|
||||
const int QDRANT_VERSION_INDEX = 11;
|
||||
var pathMetadata = Environment.GetMetadataPath();
|
||||
var lines = await File.ReadAllLinesAsync(pathMetadata, Encoding.UTF8);
|
||||
var currentQdrantVersion = lines[QDRANT_VERSION_INDEX].Trim();
|
||||
|
||||
return currentQdrantVersion;
|
||||
}
|
||||
|
||||
private async Task UpdateArchitecture(RID rid)
|
||||
{
|
||||
const int ARCHITECTURE_INDEX = 9;
|
||||
@ -529,7 +522,32 @@ public sealed partial class UpdateMetadataCommands
|
||||
|
||||
await File.WriteAllLinesAsync(pathMetadata, lines, Environment.UTF8_NO_BOM);
|
||||
}
|
||||
|
||||
|
||||
private async Task UpdateVectorStoreVersion()
|
||||
{
|
||||
const int VECTOR_STORE_VERSION_INDEX = 11;
|
||||
|
||||
var pathMetadata = Environment.GetMetadataPath();
|
||||
var lines = await File.ReadAllLinesAsync(pathMetadata, Encoding.UTF8);
|
||||
var currentVectorStoreVersion = lines[VECTOR_STORE_VERSION_INDEX].Trim();
|
||||
|
||||
var matches = await this.DetermineVersion("Qdrant Edge", Environment.GetRustRuntimeDirectory(), QdrantEdgeVersionRegex(), "cargo", "tree --depth 1");
|
||||
if (matches.Count == 0)
|
||||
return;
|
||||
|
||||
var updatedVectorStoreVersion = matches[0].Groups["version"].Value;
|
||||
if(currentVectorStoreVersion == updatedVectorStoreVersion)
|
||||
{
|
||||
Console.WriteLine("- The vector store version is already up to date.");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine($"- Updated vector store version from {currentVectorStoreVersion} to {updatedVectorStoreVersion}.");
|
||||
lines[VECTOR_STORE_VERSION_INDEX] = updatedVectorStoreVersion;
|
||||
|
||||
await File.WriteAllLinesAsync(pathMetadata, lines, Environment.UTF8_NO_BOM);
|
||||
}
|
||||
|
||||
private async Task UpdateMudBlazorVersion()
|
||||
{
|
||||
const int MUD_BLAZOR_VERSION_INDEX = 6;
|
||||
@ -720,6 +738,9 @@ public sealed partial class UpdateMetadataCommands
|
||||
[GeneratedRegex("""MudBlazor\s+(?<version>[0-9.]+)""")]
|
||||
private static partial Regex MudBlazorVersionRegex();
|
||||
|
||||
[GeneratedRegex("""qdrant-edge\s+v(?<version>[0-9.]+)""")]
|
||||
private static partial Regex QdrantEdgeVersionRegex();
|
||||
|
||||
[GeneratedRegex("""tauri\s+v(?<version>[0-9.]+)""")]
|
||||
private static partial Regex TauriVersionRegex();
|
||||
|
||||
@ -731,4 +752,4 @@ public sealed partial class UpdateMetadataCommands
|
||||
|
||||
[GeneratedRegex("""(?<major>[0-9]+)\.(?<minor>[0-9]+)\.(?<patch>[0-9]+)""")]
|
||||
private static partial Regex AppVersionRegex();
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ namespace Build.Tools;
|
||||
public static class Environment
|
||||
{
|
||||
public const string DOTNET_VERSION = "net9.0";
|
||||
public const string BUILD_OFFLINE_ENVIRONMENT_VARIABLE = "AI_STUDIO_BUILD_OFFLINE";
|
||||
public static readonly Encoding UTF8_NO_BOM = new UTF8Encoding(false);
|
||||
|
||||
private static readonly Dictionary<RID, string> ALL_RIDS = Enum.GetValues<RID>().Select(rid => new KeyValuePair<RID, string>(rid, rid.AsMicrosoftRid())).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||
@ -47,6 +48,19 @@ public static class Environment
|
||||
return Path.GetFullPath(directory);
|
||||
}
|
||||
|
||||
public static bool IsOfflineBuildRequested(bool offlineOption)
|
||||
{
|
||||
if (offlineOption)
|
||||
return true;
|
||||
|
||||
var environmentValue = global::System.Environment.GetEnvironmentVariable(BUILD_OFFLINE_ENVIRONMENT_VARIABLE);
|
||||
return environmentValue?.Trim().ToLowerInvariant() switch
|
||||
{
|
||||
"1" or "true" or "yes" or "on" => true,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
public static string? GetOS()
|
||||
{
|
||||
if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
|
||||
@ -153,7 +153,7 @@
|
||||
</MudButton>
|
||||
}
|
||||
|
||||
@if (this.SettingsManager.ConfigurationData.LLMProviders.ShowProviderConfidence)
|
||||
@if (this.SettingsManager.ConfigurationData.Confidence.ShowProviderConfidence)
|
||||
{
|
||||
<ConfidenceInfo Mode="PopoverTriggerMode.BUTTON" LLMProvider="@this.ProviderSettings.UsedLLMProvider"/>
|
||||
}
|
||||
|
||||
@ -174,7 +174,7 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
|
||||
|
||||
private string TB(string fallbackEN) => this.T(fallbackEN, typeof(AssistantBase<TSettings>).Namespace, nameof(AssistantBase<TSettings>));
|
||||
|
||||
private string SubmitButtonStyle => this.SettingsManager.ConfigurationData.LLMProviders.ShowProviderConfidence ? this.ProviderSettings.UsedLLMProvider.GetConfidence(this.SettingsManager).StyleBorder(this.SettingsManager) : string.Empty;
|
||||
private string SubmitButtonStyle => this.SettingsManager.ConfigurationData.Confidence.ShowProviderConfidence ? this.ProviderSettings.UsedLLMProvider.GetConfidence(this.SettingsManager).StyleBorder(this.SettingsManager) : string.Empty;
|
||||
|
||||
private IReadOnlyList<Tools.Components> VisibleSendToAssistants => Enum.GetValues<AIStudio.Tools.Components>()
|
||||
.Where(this.CanSendToAssistant)
|
||||
|
||||
@ -439,10 +439,10 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
|
||||
private ConfidenceLevel GetPolicyMinimumConfidenceLevel()
|
||||
{
|
||||
var minimumLevel = ConfidenceLevel.NONE;
|
||||
var llmSettings = this.SettingsManager.ConfigurationData.LLMProviders;
|
||||
var enforceGlobalMinimumConfidence = llmSettings is { EnforceGlobalMinimumConfidence: true, GlobalMinimumConfidence: not ConfidenceLevel.NONE and not ConfidenceLevel.UNKNOWN };
|
||||
var confidenceSettings = this.SettingsManager.ConfigurationData.Confidence;
|
||||
var enforceGlobalMinimumConfidence = confidenceSettings is { EnforceGlobalMinimumConfidence: true, GlobalMinimumConfidence: not ConfidenceLevel.NONE and not ConfidenceLevel.UNKNOWN };
|
||||
if (enforceGlobalMinimumConfidence)
|
||||
minimumLevel = llmSettings.GlobalMinimumConfidence;
|
||||
minimumLevel = confidenceSettings.GlobalMinimumConfidence;
|
||||
|
||||
if (this.selectedPolicy is not null && this.selectedPolicy.MinimumProviderConfidence > minimumLevel)
|
||||
minimumLevel = this.selectedPolicy.MinimumProviderConfidence;
|
||||
|
||||
@ -2167,6 +2167,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIDENCEINFO::T847071819"] = "Shows and
|
||||
-- This feature is managed by your organization and has therefore been disabled.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONBASE::T1416426626"] = "This feature is managed by your organization and has therefore been disabled."
|
||||
|
||||
-- Choose File
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONFILE::T4285779702"] = "Choose File"
|
||||
|
||||
-- Choose the minimum confidence level that all LLM providers must meet. This way, you can ensure that only trustworthy providers are used. You cannot use any provider that falls below this level.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONMINCONFIDENCESELECTION::T2526727283"] = "Choose the minimum confidence level that all LLM providers must meet. This way, you can ensure that only trustworthy providers are used. You cannot use any provider that falls below this level."
|
||||
|
||||
@ -2629,12 +2632,18 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1278320412"]
|
||||
-- How often should we check for app updates?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1364944735"] = "How often should we check for app updates?"
|
||||
|
||||
-- Additional root certificates are enabled
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1380446131"] = "Additional root certificates are enabled"
|
||||
|
||||
-- Select preview features
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1439783084"] = "Select preview features"
|
||||
|
||||
-- Your organization provided a default start page, but you can still change it.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1454730224"] = "Your organization provided a default start page, but you can still change it."
|
||||
|
||||
-- Root certificate bundle path
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1471315821"] = "Root certificate bundle path"
|
||||
|
||||
-- Select the desired behavior for the navigation bar.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1555038969"] = "Select the desired behavior for the navigation bar."
|
||||
|
||||
@ -2689,12 +2698,24 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2591866808"]
|
||||
-- Choose which page AI Studio should open first when you start the app. Changes take effect the next time you launch AI Studio.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2655930524"] = "Choose which page AI Studio should open first when you start the app. Changes take effect the next time you launch AI Studio."
|
||||
|
||||
-- Path to a PEM file containing one or more root CA certificates. For Flatpak deployments, this file must be placed in a location that is readable inside the sandbox.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2700836219"] = "Path to a PEM file containing one or more root CA certificates. For Flatpak deployments, this file must be placed in a location that is readable inside the sandbox."
|
||||
|
||||
-- Enter one host pattern per line. Exact hosts such as data.intra.example.org and one-label wildcards such as *.intra.example.org are supported. Cloud provider endpoints built into AI Studio, such as OpenAI, Google, etc., never use these additional root certificates.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2960110864"] = "Enter one host pattern per line. Exact hosts such as data.intra.example.org and one-label wildcards such as *.intra.example.org are supported. Cloud provider endpoints built into AI Studio, such as OpenAI, Google, etc., never use these additional root certificates."
|
||||
|
||||
-- Save energy?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3100928009"] = "Save energy?"
|
||||
|
||||
-- Spellchecking is enabled
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3165555978"] = "Spellchecking is enabled"
|
||||
|
||||
-- External HTTPS certificates
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T348936513"] = "External HTTPS certificates"
|
||||
|
||||
-- Allowed hosts for additional root certificates
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3562495752"] = "Allowed hosts for additional root certificates"
|
||||
|
||||
-- Request timeout
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3569531009"] = "Request timeout"
|
||||
|
||||
@ -2713,9 +2734,15 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3694781396"]
|
||||
-- Read the Enterprise IT documentation for details.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3705451321"] = "Read the Enterprise IT documentation for details."
|
||||
|
||||
-- When enabled, AI Studio can trust root certificates from a configured PEM bundle for external HTTPS requests, such as self-hosted AI providers, embeddings, transcription, ERI data sources, and enterprise configuration downloads. Normal hostname and certificate validity checks still apply. Integrated cloud providers, such as OpenAI, Google, and others, will never use these additional certificates. Please note that you usually do not need this setting on macOS or Windows. If you use Linux with the AppImage version of MindWork AI Studio, you also do not need this option. A valid use case is a Linux environment where AI Studio runs from a Flatpak.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3798070907"] = "When enabled, AI Studio can trust root certificates from a configured PEM bundle for external HTTPS requests, such as self-hosted AI providers, embeddings, transcription, ERI data sources, and enterprise configuration downloads. Normal hostname and certificate validity checks still apply. Integrated cloud providers, such as OpenAI, Google, and others, will never use these additional certificates. Please note that you usually do not need this setting on macOS or Windows. If you use Linux with the AppImage version of MindWork AI Studio, you also do not need this option. A valid use case is a Linux environment where AI Studio runs from a Flatpak."
|
||||
|
||||
-- Enable spellchecking?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3914529369"] = "Enable spellchecking?"
|
||||
|
||||
-- Additional root certificates are disabled
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3985928190"] = "Additional root certificates are disabled"
|
||||
|
||||
-- Preselect one of your profiles?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T4004501229"] = "Preselect one of your profiles?"
|
||||
|
||||
@ -2728,6 +2755,12 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T4174666315"]
|
||||
-- How long AI Studio waits for external HTTP requests, such as AI providers, embeddings, transcription, ERI data sources, and enterprise configuration downloads.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T4192032183"] = "How long AI Studio waits for external HTTP requests, such as AI providers, embeddings, transcription, ERI data sources, and enterprise configuration downloads."
|
||||
|
||||
-- Use additional root certificates for external HTTPS requests?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T4235562267"] = "Use additional root certificates for external HTTPS requests?"
|
||||
|
||||
-- Select a root certificate bundle
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T436881267"] = "Select a root certificate bundle"
|
||||
|
||||
-- Navigation bar behavior
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T602293588"] = "Navigation bar behavior"
|
||||
|
||||
@ -2758,6 +2791,54 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T922066419"]
|
||||
-- Administration settings are not visible
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T929143445"] = "Administration settings are not visible"
|
||||
|
||||
-- Show provider's confidence level?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T1052533048"] = "Show provider's confidence level?"
|
||||
|
||||
-- Choose the scheme that best suits you and your organization. Do you trust any western provider? Or only providers from the USA or exclusively European providers? Then choose the appropriate scheme. Alternatively, you can assign the confidence levels to each provider yourself.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T1081931329"] = "Choose the scheme that best suits you and your organization. Do you trust any western provider? Or only providers from the USA or exclusively European providers? Then choose the appropriate scheme. Alternatively, you can assign the confidence levels to each provider yourself."
|
||||
|
||||
-- Provider Confidence
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T1453422580"] = "Provider Confidence"
|
||||
|
||||
-- When enabled, you can enforce a minimum confidence level for all features in AI Studio. This way, you can make sure only trustworthy providers are used.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T1499004705"] = "When enabled, you can enforce a minimum confidence level for all features in AI Studio. This way, you can make sure only trustworthy providers are used."
|
||||
|
||||
-- When enabled, we show you the confidence level for the selected provider in the app. This helps you assess where you are sending your data at any time. Example: are you currently working with sensitive data? Then choose a particularly trustworthy provider, etc.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T1505516304"] = "When enabled, we show you the confidence level for the selected provider in the app. This helps you assess where you are sending your data at any time. Example: are you currently working with sensitive data? Then choose a particularly trustworthy provider, etc."
|
||||
|
||||
-- No, please hide the confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T1628475119"] = "No, please hide the confidence level"
|
||||
|
||||
-- Description
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T1725856265"] = "Description"
|
||||
|
||||
-- Confidence Level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T2492230131"] = "Confidence Level"
|
||||
|
||||
-- No, do not enforce a minimum confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T3642102079"] = "No, do not enforce a minimum confidence level"
|
||||
|
||||
-- Select a confidence scheme
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T4144206465"] = "Select a confidence scheme"
|
||||
|
||||
-- Do you want to enforce an global minimum confidence level?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T4211873175"] = "Do you want to enforce an global minimum confidence level?"
|
||||
|
||||
-- Yes, enforce a minimum confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T458854917"] = "Yes, enforce a minimum confidence level"
|
||||
|
||||
-- Not yet configured
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T48051324"] = "Not yet configured"
|
||||
|
||||
-- Do you want to always see how trustworthy your providers are? This way, you stay in control of which provider you send your data to. You can choose a common schema or configure the trust levels for each provider yourself.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T700839804"] = "Do you want to always see how trustworthy your providers are? This way, you stay in control of which provider you send your data to. You can choose a common schema or configure the trust levels for each provider yourself."
|
||||
|
||||
-- Yes, show me the confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T853225204"] = "Yes, show me the confidence level"
|
||||
|
||||
-- Provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T900237532"] = "Provider"
|
||||
|
||||
-- Embedding Result
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T1387042335"] = "Embedding Result"
|
||||
|
||||
@ -2812,6 +2893,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T32678
|
||||
-- Close
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T3448155331"] = "Close"
|
||||
|
||||
-- This embedding provider is trusted by your organization for data source security checks. Local data can be sent to it without security warnings.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T3459188215"] = "This embedding provider is trusted by your organization for data source security checks. Local data can be sent to it without security warnings."
|
||||
|
||||
-- Actions
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T3865031940"] = "Actions"
|
||||
|
||||
@ -2854,21 +2938,12 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERBASE::T336
|
||||
-- Export API Key?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERBASE::T4010580285"] = "Export API Key?"
|
||||
|
||||
-- Show provider's confidence level?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T1052533048"] = "Show provider's confidence level?"
|
||||
-- This provider is trusted by your organization for data source security checks.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T1298650849"] = "This provider is trusted by your organization for data source security checks."
|
||||
|
||||
-- Delete
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T1469573738"] = "Delete"
|
||||
|
||||
-- When enabled, we show you the confidence level for the selected provider in the app. This helps you assess where you are sending your data at any time. Example: are you currently working with sensitive data? Then choose a particularly trustworthy provider, etc.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T1505516304"] = "When enabled, we show you the confidence level for the selected provider in the app. This helps you assess where you are sending your data at any time. Example: are you currently working with sensitive data? Then choose a particularly trustworthy provider, etc."
|
||||
|
||||
-- No, please hide the confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T1628475119"] = "No, please hide the confidence level"
|
||||
|
||||
-- Description
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T1725856265"] = "Description"
|
||||
|
||||
-- Uses the provider-configured model
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T1760715963"] = "Uses the provider-configured model"
|
||||
|
||||
@ -2884,27 +2959,12 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T186876
|
||||
-- Are you sure you want to delete the provider '{0}'?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2031310917"] = "Are you sure you want to delete the provider '{0}'?"
|
||||
|
||||
-- Do you want to always be able to recognize how trustworthy your LLM providers are? This way, you keep control over which provider you send your data to. You have two options for this: Either you choose a common schema, or you configure the trust levels for each LLM provider yourself.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2082904277"] = "Do you want to always be able to recognize how trustworthy your LLM providers are? This way, you keep control over which provider you send your data to. You have two options for this: Either you choose a common schema, or you configure the trust levels for each LLM provider yourself."
|
||||
|
||||
-- Model
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2189814010"] = "Model"
|
||||
|
||||
-- Choose the scheme that best suits you and your life. Do you trust any western provider? Or only providers from the USA or exclusively European providers? Then choose the appropriate scheme. Alternatively, you can assign the confidence levels to each provider yourself.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2283885378"] = "Choose the scheme that best suits you and your life. Do you trust any western provider? Or only providers from the USA or exclusively European providers? Then choose the appropriate scheme. Alternatively, you can assign the confidence levels to each provider yourself."
|
||||
|
||||
-- LLM Provider Confidence
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2349972795"] = "LLM Provider Confidence"
|
||||
|
||||
-- What we call a provider is the combination of an LLM provider such as OpenAI and a model like GPT-4o. You can configure as many providers as you want. This way, you can use the appropriate model for each task. As an LLM provider, you can also choose local providers. However, to use this app, you must configure at least one provider.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2460361126"] = "What we call a provider is the combination of an LLM provider such as OpenAI and a model like GPT-4o. You can configure as many providers as you want. This way, you can use the appropriate model for each task. As an LLM provider, you can also choose local providers. However, to use this app, you must configure at least one provider."
|
||||
|
||||
-- Confidence Level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2492230131"] = "Confidence Level"
|
||||
|
||||
-- When enabled, you can enforce a minimum confidence level for all LLM providers. This way, you can ensure that only trustworthy providers are used.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T281063702"] = "When enabled, you can enforce a minimum confidence level for all LLM providers. This way, you can ensure that only trustworthy providers are used."
|
||||
|
||||
-- Instance Name
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2842060373"] = "Instance Name"
|
||||
|
||||
@ -2926,36 +2986,15 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T334643
|
||||
-- This provider is managed by your organization.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T3415927576"] = "This provider is managed by your organization."
|
||||
|
||||
-- LLM Provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T3612415205"] = "LLM Provider"
|
||||
|
||||
-- No, do not enforce a minimum confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T3642102079"] = "No, do not enforce a minimum confidence level"
|
||||
|
||||
-- Actions
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T3865031940"] = "Actions"
|
||||
|
||||
-- Select a confidence scheme
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T4144206465"] = "Select a confidence scheme"
|
||||
|
||||
-- Do you want to enforce an app-wide minimum confidence level?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T4258968041"] = "Do you want to enforce an app-wide minimum confidence level?"
|
||||
|
||||
-- Delete LLM Provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T4269256234"] = "Delete LLM Provider"
|
||||
|
||||
-- Yes, enforce a minimum confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T458854917"] = "Yes, enforce a minimum confidence level"
|
||||
|
||||
-- Not yet configured
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T48051324"] = "Not yet configured"
|
||||
|
||||
-- Open Dashboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T78223861"] = "Open Dashboard"
|
||||
|
||||
-- Yes, show me the confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T853225204"] = "Yes, show me the confidence level"
|
||||
|
||||
-- Provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T900237532"] = "Provider"
|
||||
|
||||
@ -3004,6 +3043,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T42
|
||||
-- With the support of transcription models, MindWork AI Studio can convert human speech into text. This is useful, for example, when you need to dictate text. You can choose from dedicated transcription models, but not multimodal LLMs (large language models) that can handle both speech and text. The configuration of multimodal models is done in the 'Configure providers' section.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T584860404"] = "With the support of transcription models, MindWork AI Studio can convert human speech into text. This is useful, for example, when you need to dictate text. You can choose from dedicated transcription models, but not multimodal LLMs (large language models) that can handle both speech and text. The configuration of multimodal models is done in the 'Configure providers' section."
|
||||
|
||||
-- This transcription provider is trusted by your organization for data source security checks.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T601264181"] = "This transcription provider is trusted by your organization for data source security checks."
|
||||
|
||||
-- This transcription provider is managed by your organization.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T756131076"] = "This transcription provider is managed by your organization."
|
||||
|
||||
@ -3163,15 +3205,27 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1469573738"] = "Delete"
|
||||
-- Rename Workspace
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1474303418"] = "Rename Workspace"
|
||||
|
||||
-- Clear search
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1511254342"] = "Clear search"
|
||||
|
||||
-- Rename Chat
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T156144855"] = "Rename Chat"
|
||||
|
||||
-- Add workspace
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1586005241"] = "Add workspace"
|
||||
|
||||
-- Search chats
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1615077202"] = "Search chats"
|
||||
|
||||
-- Start a new chat in workspace '{0}'
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1840064668"] = "Start a new chat in workspace '{0}'"
|
||||
|
||||
-- Add chat
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1874060138"] = "Add chat"
|
||||
|
||||
-- No chats found
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1886517101"] = "No chats found"
|
||||
|
||||
-- Create Chat
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1939006681"] = "Create Chat"
|
||||
|
||||
@ -3208,6 +3262,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3045856778"] = "Move Chat to
|
||||
-- Please enter a new or edit the name for your workspace '{0}':
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T323280982"] = "Please enter a new or edit the name for your workspace '{0}':"
|
||||
|
||||
-- There is already a workspace with this name. Please choose a different name.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3249036008"] = "There is already a workspace with this name. Please choose a different name."
|
||||
|
||||
-- Please enter a workspace name.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3288132732"] = "Please enter a workspace name."
|
||||
|
||||
@ -3217,6 +3274,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3355849203"] = "Rename"
|
||||
-- Please enter a new or edit the name for your chat '{0}':
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3419791373"] = "Please enter a new or edit the name for your chat '{0}':"
|
||||
|
||||
-- Search chat contents
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3436662033"] = "Search chat contents"
|
||||
|
||||
-- Load Chat
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3555709365"] = "Load Chat"
|
||||
|
||||
@ -3463,6 +3523,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3227981830"] = "Using s
|
||||
-- Add a message
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3372872324"] = "Add a message"
|
||||
|
||||
-- Close
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3448155331"] = "Close"
|
||||
|
||||
-- Unsupported content type
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3570316759"] = "Unsupported content type"
|
||||
|
||||
@ -4243,6 +4306,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T3243902394"] = "The profile
|
||||
-- Profile Name
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T3392578705"] = "Profile Name"
|
||||
|
||||
-- Close
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T3448155331"] = "Close"
|
||||
|
||||
-- Please enter what the LLM should know about you and/or what actions it should take.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T3708405102"] = "Please enter what the LLM should know about you and/or what actions it should take."
|
||||
|
||||
@ -4762,6 +4828,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T14695
|
||||
-- Add Chat Template
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T1548314416"] = "Add Chat Template"
|
||||
|
||||
-- View
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T1582017048"] = "View"
|
||||
|
||||
-- Note: This advanced feature is designed for users familiar with prompt engineering concepts. Furthermore, you have to make sure yourself that your chosen provider supports the use of assistant prompts.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T1909110760"] = "Note: This advanced feature is designed for users familiar with prompt engineering concepts. Furthermore, you have to make sure yourself that your chosen provider supports the use of assistant prompts."
|
||||
|
||||
@ -4801,6 +4870,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T38650
|
||||
-- Delete Chat Template
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T4025180906"] = "Delete Chat Template"
|
||||
|
||||
-- View Chat Template
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T4042112076"] = "View Chat Template"
|
||||
|
||||
-- Export Chat Template
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T491504763"] = "Export Chat Template"
|
||||
|
||||
@ -5209,6 +5281,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T143353473
|
||||
-- Delete
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T1469573738"] = "Delete"
|
||||
|
||||
-- View
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T1582017048"] = "View"
|
||||
|
||||
-- Your Profiles
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T2378610256"] = "Your Profiles"
|
||||
|
||||
@ -5233,6 +5308,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T405841465
|
||||
-- Store personal data about yourself in various profiles so that the AIs know your personal context. This saves you from having to explain your context each time, for example, in every chat. When you have different roles, you can create a profile for each role.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T4125557797"] = "Store personal data about yourself in various profiles so that the AIs know your personal context. This saves you from having to explain your context each time, for example, in every chat. When you have different roles, you can create a profile for each role."
|
||||
|
||||
-- View Profile
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T4219233997"] = "View Profile"
|
||||
|
||||
-- Add Profile
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T4248067241"] = "Add Profile"
|
||||
|
||||
@ -5746,15 +5824,39 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::UPDATEDIALOG::T25417398"] = "Update from v{0
|
||||
-- Install later
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::UPDATEDIALOG::T2936430090"] = "Install later"
|
||||
|
||||
-- Create new workspace
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::WORKSPACESELECTIONDIALOG::T1541251414"] = "Create new workspace"
|
||||
|
||||
-- Add workspace
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::WORKSPACESELECTIONDIALOG::T1586005241"] = "Add workspace"
|
||||
|
||||
-- Workspace name
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::WORKSPACESELECTIONDIALOG::T295876489"] = "Workspace name"
|
||||
|
||||
-- There is already a workspace with this name. Please choose a different name.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::WORKSPACESELECTIONDIALOG::T3249036008"] = "There is already a workspace with this name. Please choose a different name."
|
||||
|
||||
-- Please enter a workspace name.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::WORKSPACESELECTIONDIALOG::T3288132732"] = "Please enter a workspace name."
|
||||
|
||||
-- Cancel
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::WORKSPACESELECTIONDIALOG::T900713019"] = "Cancel"
|
||||
|
||||
-- Reason
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1093747001"] = "Reason"
|
||||
|
||||
-- Settings
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1258653480"] = "Settings"
|
||||
|
||||
-- Your settings file does not contain a settings-format version. Changes in this session will not be saved to avoid overwriting your settings. Please check for updates or contact support.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1378304679"] = "Your settings file does not contain a settings-format version. Changes in this session will not be saved to avoid overwriting your settings. Please check for updates or contact support."
|
||||
|
||||
-- Home
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1391791790"] = "Home"
|
||||
|
||||
-- AI Studio found the current settings format but could not load it safely. Changes in this session will not be saved. Please check for updates or contact support.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1497084127"] = "AI Studio found the current settings format but could not load it safely. Changes in this session will not be saved. Please check for updates or contact support."
|
||||
|
||||
-- Are you sure you want to leave the chat page? All unsaved changes will be lost.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1563130494"] = "Are you sure you want to leave the chat page? All unsaved changes will be lost."
|
||||
|
||||
@ -5764,12 +5866,21 @@ UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1614176092"] = "Assistants"
|
||||
-- Update
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1847791252"] = "Update"
|
||||
|
||||
-- Check for updates
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1890416390"] = "Check for updates"
|
||||
|
||||
-- Your settings were created by a newer AI Studio version. Changes in this session will not be saved. Please install or start the latest available update.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1988273622"] = "Your settings were created by a newer AI Studio version. Changes in this session will not be saved. Please install or start the latest available update."
|
||||
|
||||
-- Leave Chat Page
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2124749705"] = "Leave Chat Page"
|
||||
|
||||
-- Plugins
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2222816203"] = "Plugins"
|
||||
|
||||
-- AI Studio cannot safely save settings in this session. Please check for updates or contact support.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2382622618"] = "AI Studio cannot safely save settings in this session. Please check for updates or contact support."
|
||||
|
||||
-- An update to version {0} is available.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2800137365"] = "An update to version {0} is available."
|
||||
|
||||
@ -5779,6 +5890,9 @@ UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2864211629"] = "Please wait for
|
||||
-- Supporters
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2929332068"] = "Supporters"
|
||||
|
||||
-- AI Studio could not read your settings file. Changes in this session will not be saved to avoid overwriting recoverable settings. Please check for updates or contact support.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2936083926"] = "AI Studio could not read your settings file. Changes in this session will not be saved to avoid overwriting recoverable settings. Please check for updates or contact support."
|
||||
|
||||
-- Writer
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2979224202"] = "Writer"
|
||||
|
||||
@ -5791,6 +5905,9 @@ UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T4256323669"] = "Information"
|
||||
-- Chat
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T578410699"] = "Chat"
|
||||
|
||||
-- AI Studio does not recognize your settings-format version. Changes in this session will not be saved to avoid overwriting your settings. Please check for updates or contact support.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T915412625"] = "AI Studio does not recognize your settings-format version. Changes in this session will not be saved to avoid overwriting your settings. Please check for updates or contact support."
|
||||
|
||||
-- Get coding and debugging support from an LLM.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T1243850917"] = "Get coding and debugging support from an LLM."
|
||||
|
||||
@ -5923,6 +6040,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T878695986"] = "Learn about one co
|
||||
-- Localization
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T897888480"] = "Localization"
|
||||
|
||||
-- Hide search
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::CHAT::T1281128983"] = "Hide search"
|
||||
|
||||
-- Reload your workspaces
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::CHAT::T194629703"] = "Reload your workspaces"
|
||||
|
||||
@ -5935,6 +6055,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::CHAT::T2813205227"] = "Open Chat Options"
|
||||
-- Disappearing Chat
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::CHAT::T3046519404"] = "Disappearing Chat"
|
||||
|
||||
-- Search your workspaces
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::CHAT::T3059773282"] = "Search your workspaces"
|
||||
|
||||
-- Configure your workspaces
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::CHAT::T3586092784"] = "Configure your workspaces"
|
||||
|
||||
@ -5968,6 +6091,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T144565305"] = "The app requires minimal
|
||||
-- You only pay for what you use, which can be cheaper than monthly subscription services like ChatGPT Plus, especially if used infrequently. But beware, here be dragons: For extremely intensive usage, the API costs can be significantly higher. Unfortunately, providers currently do not offer a way to display current costs in the app. Therefore, check your account with the respective provider to see how your costs are developing. When available, use prepaid and set a cost limit.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T149711988"] = "You only pay for what you use, which can be cheaper than monthly subscription services like ChatGPT Plus, especially if used infrequently. But beware, here be dragons: For extremely intensive usage, the API costs can be significantly higher. Unfortunately, providers currently do not offer a way to display current costs in the app. Therefore, check your account with the respective provider to see how your costs are developing. When available, use prepaid and set a cost limit."
|
||||
|
||||
-- Version
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T1573770551"] = "Version"
|
||||
|
||||
-- Assistants
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T1614176092"] = "Assistants"
|
||||
|
||||
@ -6037,27 +6163,42 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T91074375"] = "The app is free to use, b
|
||||
-- Startup log file
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1019424746"] = "Startup log file"
|
||||
|
||||
-- The configured root certificates could not be used.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T103551060"] = "The configured root certificates could not be used."
|
||||
|
||||
-- Browse AI Studio's source code on GitHub — we welcome your contributions.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1107156991"] = "Browse AI Studio's source code on GitHub — we welcome your contributions."
|
||||
|
||||
-- Vector store version
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1124039623"] = "Vector store version"
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1126023000"] = "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."
|
||||
|
||||
-- ID mismatch: the plugin ID differs from the enterprise configuration ID.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1137744461"] = "ID mismatch: the plugin ID differs from the enterprise configuration ID."
|
||||
|
||||
-- This is a private AI Studio installation. It runs without an enterprise configuration.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1209549230"] = "This is a private AI Studio installation. It runs without an enterprise configuration."
|
||||
|
||||
-- Copies the configuration origin to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T125850635"] = "Copies the configuration origin to the clipboard"
|
||||
|
||||
-- Unknown configuration plugin
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1290340974"] = "Unknown configuration plugin"
|
||||
|
||||
-- Copies the configuration slot to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1347508205"] = "Copies the configuration slot to the clipboard"
|
||||
|
||||
-- This library is used to read PDF files. This is necessary, e.g., for using PDFs as a data source for a chat.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1388816916"] = "This library is used to read PDF files. This is necessary, e.g., for using PDFs as a data source for a chat."
|
||||
|
||||
-- Database version
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1420062548"] = "Database version"
|
||||
|
||||
-- This library is used to extend the MudBlazor library. It provides additional components that are not part of the MudBlazor library.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1421513382"] = "This library is used to extend the MudBlazor library. It provides additional components that are not part of the MudBlazor library."
|
||||
|
||||
-- Copies the allowed host pattern to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1513592659"] = "Copies the allowed host pattern to the clipboard"
|
||||
|
||||
-- Waiting for the configuration plugin...
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1533382393"] = "Waiting for the configuration plugin..."
|
||||
|
||||
@ -6067,9 +6208,6 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1560776885"] = "Encryption secre
|
||||
-- AI Studio runs with an enterprise configuration and configuration servers. The configuration plugins are active.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1596483935"] = "AI Studio runs with an enterprise configuration and configuration servers. The configuration plugins are active."
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1619832053"] = "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."
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T162898512"] = "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."
|
||||
|
||||
@ -6082,6 +6220,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1630237140"] = "AI Studio create
|
||||
-- Consent:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T171952677"] = "Consent:"
|
||||
|
||||
-- Copies the executable path to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1722690800"] = "Copies the executable path to the clipboard"
|
||||
|
||||
-- This library is used to display the differences between two texts. This is necessary, e.g., for the grammar and spelling assistant.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1772678682"] = "This library is used to display the differences between two texts. This is necessary, e.g., for the grammar and spelling assistant."
|
||||
|
||||
@ -6106,12 +6247,18 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1924365263"] = "This library is
|
||||
-- Encryption secret: is configured
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1931141322"] = "Encryption secret: is configured"
|
||||
|
||||
-- Copies the number of loaded root certificates to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2015329654"] = "Copies the number of loaded root certificates to the clipboard"
|
||||
|
||||
-- Copies the following to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2029659664"] = "Copies the following to the clipboard"
|
||||
|
||||
-- Copies the server URL to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2037899437"] = "Copies the server URL to the clipboard"
|
||||
|
||||
-- This library is used to create temporary folders in runtime tests and supporting filesystem operations.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2160280545"] = "This library is used to create temporary folders in runtime tests and supporting filesystem operations."
|
||||
|
||||
-- This library is used to determine the file type of a file. This is necessary, e.g., when we want to stream a file.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2173617769"] = "This library is used to determine the file type of a file. This is necessary, e.g., when we want to stream a file."
|
||||
|
||||
@ -6145,6 +6292,12 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2371107659"] = "installation pro
|
||||
-- Installed Pandoc version: Pandoc is not installed or not available.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2374031539"] = "Installed Pandoc version: Pandoc is not installed or not available."
|
||||
|
||||
-- Configuration origin:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2435772109"] = "Configuration origin:"
|
||||
|
||||
-- Configuration slot:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T254943559"] = "Configuration slot:"
|
||||
|
||||
-- This library is used to determine the language of the operating system. This is necessary to set the language of the user interface.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2557014401"] = "This library is used to determine the language of the operating system. This is necessary to set the language of the user interface."
|
||||
|
||||
@ -6154,8 +6307,8 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2557066213"] = "Used Open Source
|
||||
-- Build time
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T260228112"] = "Build time"
|
||||
|
||||
-- This library is used to create temporary folders for saving the certificate and private key for communication with Qdrant.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2619858133"] = "This library is used to create temporary folders for saving the certificate and private key for communication with Qdrant."
|
||||
-- unknown
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2608177081"] = "unknown"
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2635482790"] = "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."
|
||||
@ -6199,9 +6352,21 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2868174483"] = "The .NET backend
|
||||
-- AI Studio runs with an enterprise configuration and configuration servers. The configuration plugins are not yet available.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2924964415"] = "AI Studio runs with an enterprise configuration and configuration servers. The configuration plugins are not yet available."
|
||||
|
||||
-- Copies the configuration source to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2929232062"] = "Copies the configuration source to the clipboard"
|
||||
|
||||
-- Copies the root certificate fingerprint to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2989678330"] = "Copies the root certificate fingerprint to the clipboard"
|
||||
|
||||
-- Changelog
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3017574265"] = "Changelog"
|
||||
|
||||
-- External HTTPS custom root certificates are configured but not active.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3021325354"] = "External HTTPS custom root certificates are configured but not active."
|
||||
|
||||
-- Vector store
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3046399223"] = "Vector store"
|
||||
|
||||
-- Enterprise configuration ID:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3092349641"] = "Enterprise configuration ID:"
|
||||
|
||||
@ -6214,6 +6379,12 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3178730036"] = "Have feature ide
|
||||
-- Hide Details
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3183837919"] = "Hide Details"
|
||||
|
||||
-- Linux package
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3196139293"] = "Linux package"
|
||||
|
||||
-- External HTTPS custom root certificates are active.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3208455732"] = "External HTTPS custom root certificates are active."
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3208719461"] = "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."
|
||||
|
||||
@ -6226,9 +6397,15 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3249965383"] = "Update Pandoc"
|
||||
-- Discover MindWork AI's mission and vision on our official homepage.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3294830584"] = "Discover MindWork AI's mission and vision on our official homepage."
|
||||
|
||||
-- External HTTPS custom root certificates
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3315279770"] = "External HTTPS custom root certificates"
|
||||
|
||||
-- User-language provided by the OS
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3334355246"] = "User-language provided by the OS"
|
||||
|
||||
-- Status:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3396815215"] = "Status:"
|
||||
|
||||
-- The following list shows the versions of the MindWork AI Studio, the used compilers, build time, etc.:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3405978777"] = "The following list shows the versions of the MindWork AI Studio, the used compilers, build time, etc.:"
|
||||
|
||||
@ -6247,18 +6424,30 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3494984593"] = "Tauri is used to
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3527399572"] = "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."
|
||||
|
||||
-- Copies the certificate bundle path to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3550115021"] = "Copies the certificate bundle path to the clipboard"
|
||||
|
||||
-- Motivation
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3563271893"] = "Motivation"
|
||||
|
||||
-- not available
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3574465749"] = "not available"
|
||||
|
||||
-- active
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3648362799"] = "active"
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3722989559"] = "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."
|
||||
|
||||
-- Username provided by the OS
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3764549776"] = "Username provided by the OS"
|
||||
|
||||
-- Allowed host:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3774270763"] = "Allowed host:"
|
||||
|
||||
-- Configuration source:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3801531724"] = "Configuration source:"
|
||||
|
||||
-- this version does not met the requirements
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3813932670"] = "this version does not met the requirements"
|
||||
|
||||
@ -6268,6 +6457,12 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3874337003"] = "This library is
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3908558992"] = "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."
|
||||
|
||||
-- not applicable
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T396609403"] = "not applicable"
|
||||
|
||||
-- Copies the allowed host configuration to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3970230163"] = "Copies the allowed host configuration to the clipboard"
|
||||
|
||||
-- Installed Pandoc version
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3983971016"] = "Installed Pandoc version"
|
||||
|
||||
@ -6277,8 +6472,8 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3986423270"] = "Check Pandoc Ins
|
||||
-- Versions
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4010195468"] = "Versions"
|
||||
|
||||
-- Database
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4036243672"] = "Database"
|
||||
-- Allowed hosts: none configured
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4058524336"] = "Allowed hosts: none configured"
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4060906280"] = "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."
|
||||
@ -6289,12 +6484,24 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4079152443"] = "This library is
|
||||
-- Community & Code
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4158546761"] = "Community & Code"
|
||||
|
||||
-- Executable path
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4164953312"] = "Executable path"
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4184485147"] = "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."
|
||||
|
||||
-- Copies the working directory to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4194302113"] = "Copies the working directory to the clipboard"
|
||||
|
||||
-- Certificate bundle:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4197142390"] = "Certificate bundle:"
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4229014037"] = "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."
|
||||
|
||||
-- Copies the status to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4291960437"] = "Copies the status to the clipboard"
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T566998575"] = "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."
|
||||
|
||||
@ -6304,6 +6511,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T585329785"] = "Used .NET SDK"
|
||||
-- starting
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T594602073"] = "starting"
|
||||
|
||||
-- Root certificate fingerprint:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T615041128"] = "Root certificate fingerprint:"
|
||||
|
||||
-- This library is used to manage sidecar processes and to ensure that stale or zombie sidecars are detected and terminated.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T633932150"] = "This library is used to manage sidecar processes and to ensure that stale or zombie sidecars are detected and terminated."
|
||||
|
||||
@ -6313,6 +6523,15 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T639371534"] = "Did you find a bu
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T64689067"] = "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."
|
||||
|
||||
-- not active
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T70364248"] = "not active"
|
||||
|
||||
-- Loaded root certificates:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T709525418"] = "Loaded root certificates:"
|
||||
|
||||
-- Working directory
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T768480635"] = "Working directory"
|
||||
|
||||
-- Copies the config ID to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T788846912"] = "Copies the config ID to the clipboard"
|
||||
|
||||
@ -6595,6 +6814,12 @@ UI_TEXT_CONTENT["AISTUDIO::PROVIDER::OPENAI::PROVIDEROPENAI::T757371511"] = "It
|
||||
-- Model as configured by whisper.cpp
|
||||
UI_TEXT_CONTENT["AISTUDIO::PROVIDER::SELFHOSTED::PROVIDERSELFHOSTED::T3313940770"] = "Model as configured by whisper.cpp"
|
||||
|
||||
-- The llama.cpp provider '{0}' does not offer a usable text model. Please check your provider settings.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PROVIDER::SELFHOSTED::PROVIDERSELFHOSTED::T3839908321"] = "The llama.cpp provider '{0}' does not offer a usable text model. Please check your provider settings."
|
||||
|
||||
-- The llama.cpp provider '{0}' offers multiple models. Please open the provider settings and select the model to use.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PROVIDER::SELFHOSTED::PROVIDERSELFHOSTED::T4018006464"] = "The llama.cpp provider '{0}' offers multiple models. Please open the provider settings and select the model to use."
|
||||
|
||||
-- Cannot export this chat template because example message {0} is not a text message.
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CHATTEMPLATE::T1861800849"] = "Cannot export this chat template because example message {0} is not a text message."
|
||||
|
||||
@ -7003,20 +7228,32 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::NODATABASECLIENT::T3662391977"] = "
|
||||
-- Status
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::NODATABASECLIENT::T6222351"] = "Status"
|
||||
|
||||
-- Storage size
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::QDRANT::QDRANTCLIENTIMPLEMENTATION::T1230141403"] = "Storage size"
|
||||
-- Reason
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::NOVECTORSTORECLIENT::T1093747001"] = "Reason"
|
||||
|
||||
-- HTTP port
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::QDRANT::QDRANTCLIENTIMPLEMENTATION::T1717573768"] = "HTTP port"
|
||||
-- Starting
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::NOVECTORSTORECLIENT::T1233211769"] = "Starting"
|
||||
|
||||
-- Unavailable
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::NOVECTORSTORECLIENT::T3662391977"] = "Unavailable"
|
||||
|
||||
-- Status
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::NOVECTORSTORECLIENT::T6222351"] = "Status"
|
||||
|
||||
-- Storage size
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::QDRANTEDGECLIENTIMPLEMENTATION::T1230141403"] = "Storage size"
|
||||
|
||||
-- Number of vector stores
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::QDRANTEDGECLIENTIMPLEMENTATION::T2785004838"] = "Number of vector stores"
|
||||
|
||||
-- Reported version
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::QDRANT::QDRANTCLIENTIMPLEMENTATION::T3556099842"] = "Reported version"
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::QDRANTEDGECLIENTIMPLEMENTATION::T3556099842"] = "Reported version"
|
||||
|
||||
-- gRPC port
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::QDRANT::QDRANTCLIENTIMPLEMENTATION::T757840040"] = "gRPC port"
|
||||
-- Status
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::QDRANTEDGECLIENTIMPLEMENTATION::T6222351"] = "Status"
|
||||
|
||||
-- Number of collections
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::QDRANT::QDRANTCLIENTIMPLEMENTATION::T842647336"] = "Number of collections"
|
||||
-- Qdrant Edge is not available.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::QDRANTEDGECLIENTIMPLEMENTATION::T744445696"] = "Qdrant Edge is not available."
|
||||
|
||||
-- The related data is not allowed to be sent to any LLM provider. This means that this data source cannot be used at the moment.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ERICLIENT::DATAMODEL::PROVIDERTYPEEXTENSIONS::T1555790630"] = "The related data is not allowed to be sent to any LLM provider. This means that this data source cannot be used at the moment."
|
||||
@ -7129,6 +7366,27 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::ERICLIENT::ERICLIENTV1::T816853779"] = "Failed
|
||||
-- Failed to retrieve the authentication methods: the ERI server did not return a valid response.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ERICLIENT::ERICLIENTV1::T984407320"] = "Failed to retrieve the authentication methods: the ERI server did not return a valid response."
|
||||
|
||||
-- No certificate bundle path is configured.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T1033171304"] = "No certificate bundle path is configured."
|
||||
|
||||
-- app settings
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T1736441001"] = "app settings"
|
||||
|
||||
-- environment variables
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T317663851"] = "environment variables"
|
||||
|
||||
-- configuration plugin
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T3427095600"] = "configuration plugin"
|
||||
|
||||
-- The configured certificate bundle file does not exist.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T3928871850"] = "The configured certificate bundle file does not exist."
|
||||
|
||||
-- The configured certificate bundle does not contain usable root CA certificates.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T599774443"] = "The configured certificate bundle does not contain usable root CA certificates."
|
||||
|
||||
-- policy files
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T632340680"] = "policy files"
|
||||
|
||||
-- AI Studio couldn't install Pandoc because the archive was not found.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PANDOC::T1059477764"] = "AI Studio couldn't install Pandoc because the archive was not found."
|
||||
|
||||
@ -7648,6 +7906,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T2502277006"] = "Custom"
|
||||
-- Media
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T3507473059"] = "Media"
|
||||
|
||||
-- Certificate bundle
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T3543954504"] = "Certificate bundle"
|
||||
|
||||
-- Source like prefix
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T378481461"] = "Source like prefix"
|
||||
|
||||
@ -7663,6 +7924,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PANDOCAVAILABILITYSERVICE::T25964655
|
||||
-- Failed to store the secret data due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T1110203516"] = "Failed to store the secret data due to an API issue."
|
||||
|
||||
-- Failed to store the API key due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T1704298921"] = "Failed to store the API key due to an API issue."
|
||||
|
||||
-- Failed to delete the secret data due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T2303057928"] = "Failed to delete the secret data due to an API issue."
|
||||
|
||||
|
||||
@ -94,6 +94,8 @@ public sealed record ChatThread
|
||||
/// <returns>The prepared system prompt.</returns>
|
||||
public string PrepareSystemPrompt(SettingsManager settingsManager)
|
||||
{
|
||||
this.allowProfile = true;
|
||||
|
||||
//
|
||||
// Use the information from the chat template, if provided. Otherwise, use the default system prompt
|
||||
//
|
||||
@ -111,8 +113,8 @@ public sealed record ChatThread
|
||||
systemPromptTextWithChatTemplate = this.SystemPrompt;
|
||||
else
|
||||
{
|
||||
var chatTemplate = settingsManager.ConfigurationData.ChatTemplates.FirstOrDefault(x => x.Id == this.SelectedChatTemplate);
|
||||
if(chatTemplate == null)
|
||||
var chatTemplate = settingsManager.GetChatTemplateById(this.SelectedChatTemplate);
|
||||
if(chatTemplate == ChatTemplate.NO_CHAT_TEMPLATE)
|
||||
systemPromptTextWithChatTemplate = this.SystemPrompt;
|
||||
else
|
||||
{
|
||||
@ -168,8 +170,8 @@ public sealed record ChatThread
|
||||
systemPromptText = systemPromptWithAugmentedData;
|
||||
else
|
||||
{
|
||||
var profile = settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == this.SelectedProfile);
|
||||
if(profile is null)
|
||||
var profile = settingsManager.GetProfileById(this.SelectedProfile);
|
||||
if(profile == Profile.NO_PROFILE)
|
||||
systemPromptText = systemPromptWithAugmentedData;
|
||||
else
|
||||
{
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using AIStudio.Provider.SelfHosted;
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Settings.DataModel;
|
||||
|
||||
namespace AIStudio.Chat;
|
||||
@ -33,12 +34,13 @@ public static class ChatThreadExtensions
|
||||
return true;
|
||||
|
||||
//
|
||||
// Is the provider self-hosted?
|
||||
// Is the provider trusted for data-source security checks?
|
||||
//
|
||||
var isSelfHostedProvider = provider switch
|
||||
var settingsManager = Program.SERVICE_PROVIDER.GetRequiredService<SettingsManager>();
|
||||
var isTrustedProvider = provider switch
|
||||
{
|
||||
ProviderSelfHosted => true,
|
||||
AIStudio.Settings.Provider p => p.IsSelfHosted,
|
||||
IProvider p => p.IsTrustedForDataSourceSecurityChecks(settingsManager),
|
||||
AIStudio.Settings.Provider p => p.IsTrustedForDataSourceSecurityChecks(settingsManager),
|
||||
|
||||
_ => false,
|
||||
};
|
||||
@ -46,12 +48,12 @@ public static class ChatThreadExtensions
|
||||
//
|
||||
// Check the chat data security against the selected provider:
|
||||
//
|
||||
return isSelfHostedProvider switch
|
||||
return isTrustedProvider switch
|
||||
{
|
||||
// The provider is self-hosted -- we can use any data source:
|
||||
// The provider is trusted -- we can use any data source:
|
||||
true => true,
|
||||
|
||||
// The provider is not self-hosted -- it depends on the data security of the chat thread:
|
||||
// The provider is not trusted -- it depends on the data security of the chat thread:
|
||||
false => chatThread.DataSecurity is not DataSourceSecurity.SELF_HOSTED,
|
||||
};
|
||||
}
|
||||
|
||||
@ -89,7 +89,7 @@ public static class IImageSourceExtensions
|
||||
|
||||
case ContentImageSource.URL:
|
||||
{
|
||||
using var httpClient = ExternalHttpClientTimeout.CreateHttpClient();
|
||||
using var httpClient = ExternalHttpClientTimeout.CreateHttpClient(ExternalHttpTrustPolicy.ALLOW_CUSTOM_ROOTS_WHEN_HOST_WHITELISTED);
|
||||
using var timeoutTokenSource = ExternalHttpClientTimeout.CreateTimeoutTokenSource(token);
|
||||
var timeoutToken = timeoutTokenSource.Token;
|
||||
using var response = await httpClient.GetAsync(image.Source, HttpCompletionOption.ResponseHeadersRead, timeoutToken);
|
||||
|
||||
@ -52,29 +52,42 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" StretchItems="StretchItems.None" Wrap="Wrap.Wrap">
|
||||
<MudText Typo="Typo.body1" Inline="true">
|
||||
@T("Drag and drop files into the marked area or click here to attach documents: ")
|
||||
</MudText>
|
||||
<MudButton
|
||||
Variant="Variant.Filled"
|
||||
StartIcon="@Icons.Material.Filled.Add"
|
||||
Color="Color.Primary"
|
||||
OnClick="@(() => this.AddFilesManually())"
|
||||
Style="vertical-align: top; margin-top: -2px;"
|
||||
Size="Size.Small">
|
||||
@T("Add file")
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
@if (!this.Disabled)
|
||||
{
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" StretchItems="StretchItems.None" Wrap="Wrap.Wrap">
|
||||
<MudText Typo="Typo.body1" Inline="true">
|
||||
@T("Drag and drop files into the marked area or click here to attach documents: ")
|
||||
</MudText>
|
||||
<MudButton
|
||||
Variant="Variant.Filled"
|
||||
StartIcon="@Icons.Material.Filled.Add"
|
||||
Color="Color.Primary"
|
||||
OnClick="@(() => this.AddFilesManually())"
|
||||
Style="vertical-align: top; margin-top: -2px;"
|
||||
Size="Size.Small">
|
||||
@T("Add file")
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
}
|
||||
<div @onmouseenter="@this.OnMouseEnter" @onmouseleave="@this.OnMouseLeave">
|
||||
<MudPaper Height="20em" Outlined="true" Class="@this.dragClass" Style="overflow-y: auto;">
|
||||
@foreach (var fileAttachment in this.DocumentPaths)
|
||||
{
|
||||
<MudChip T="string" Color="Color.Dark" Text="@fileAttachment.FileName" tabindex="-1" Icon="@Icons.Material.Filled.Search" OnClick="@(() => this.InvestigateFile(fileAttachment))" OnClose="@(() => this.RemoveDocument(fileAttachment))"/>
|
||||
@if (this.Disabled)
|
||||
{
|
||||
<MudChip T="string" Color="Color.Dark" Text="@fileAttachment.FileName" tabindex="-1" Icon="@Icons.Material.Filled.Search" OnClick="@(() => this.InvestigateFile(fileAttachment))"/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudChip T="string" Color="Color.Dark" Text="@fileAttachment.FileName" tabindex="-1" Icon="@Icons.Material.Filled.Search" OnClick="@(() => this.InvestigateFile(fileAttachment))" OnClose="@(() => this.RemoveDocument(fileAttachment))"/>
|
||||
}
|
||||
}
|
||||
</MudPaper>
|
||||
</div>
|
||||
<MudButton OnClick="@(async () => await this.ClearAllFiles())" Variant="Variant.Filled" Color="Color.Info" Class="mt-2" StartIcon="@Icons.Material.Filled.Delete">
|
||||
@T("Clear file list")
|
||||
</MudButton>
|
||||
@if (!this.Disabled)
|
||||
{
|
||||
<MudButton OnClick="@(async () => await this.ClearAllFiles())" Variant="Variant.Filled" Color="Color.Info" Class="mt-2" StartIcon="@Icons.Material.Filled.Delete">
|
||||
@T("Clear file list")
|
||||
</MudButton>
|
||||
}
|
||||
}
|
||||
@ -14,16 +14,16 @@ using DialogOptions = Dialogs.DialogOptions;
|
||||
public partial class AttachDocuments : MSGComponentBase
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(AttachDocuments).Namespace, nameof(AttachDocuments));
|
||||
|
||||
|
||||
[Parameter]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// On which layer to register the drop area. Higher layers have priority over lower layers.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public int Layer { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// When true, pause catching dropped files. Default is false.
|
||||
/// </summary>
|
||||
@ -38,16 +38,19 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
|
||||
[Parameter]
|
||||
public Func<HashSet<FileAttachment>, Task> OnChange { get; set; } = _ => Task.CompletedTask;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Catch all documents that are hovered over the AI Studio window and not only over the drop zone.
|
||||
/// Catch all documents that are hovered over the AI Studio window and not only over the drop zone.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
[Parameter]
|
||||
public bool CatchAllDocuments { get; set; }
|
||||
|
||||
|
||||
[Parameter]
|
||||
public bool UseSmallForm { get; set; }
|
||||
|
||||
|
||||
[Parameter]
|
||||
public bool Disabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When true, validate media file types before attaching. Default is true. That means that
|
||||
/// the user cannot attach unsupported media file types when the provider or model does not
|
||||
@ -56,16 +59,16 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool ValidateMediaFileTypes { get; set; } = true;
|
||||
|
||||
|
||||
[Parameter]
|
||||
public AIStudio.Settings.Provider? Provider { get; set; }
|
||||
|
||||
|
||||
[Inject]
|
||||
private ILogger<AttachDocuments> Logger { get; set; } = null!;
|
||||
|
||||
|
||||
[Inject]
|
||||
private RustService RustService { get; init; } = null!;
|
||||
|
||||
|
||||
[Inject]
|
||||
private IDialogService DialogService { get; init; } = null!;
|
||||
|
||||
@ -74,17 +77,17 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
|
||||
private const Placement TOOLBAR_TOOLTIP_PLACEMENT = Placement.Top;
|
||||
private static readonly string DROP_FILES_HERE_TEXT = TB("Drop files here to attach them.");
|
||||
|
||||
|
||||
private uint numDropAreasAboveThis;
|
||||
private bool isComponentHovered;
|
||||
private bool isDraggingOver;
|
||||
|
||||
|
||||
#region Overrides of MSGComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
this.ApplyFilters([], [ Event.TAURI_EVENT_RECEIVED, Event.REGISTER_FILE_DROP_AREA, Event.UNREGISTER_FILE_DROP_AREA ]);
|
||||
|
||||
|
||||
// Register this drop area:
|
||||
await this.MessageBus.SendMessage(this, Event.REGISTER_FILE_DROP_AREA, this.Layer);
|
||||
await base.OnInitializedAsync();
|
||||
@ -92,6 +95,9 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
|
||||
protected override async Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
|
||||
{
|
||||
if (this.Disabled && triggeredEvent == Event.TAURI_EVENT_RECEIVED)
|
||||
return;
|
||||
|
||||
switch (triggeredEvent)
|
||||
{
|
||||
case Event.REGISTER_FILE_DROP_AREA when sendingComponent != this:
|
||||
@ -111,7 +117,7 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
{
|
||||
if(this.numDropAreasAboveThis > 0)
|
||||
this.numDropAreasAboveThis--;
|
||||
|
||||
|
||||
if(this.numDropAreasAboveThis is 0)
|
||||
this.PauseCatchingDrops = false;
|
||||
}
|
||||
@ -122,40 +128,40 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
case Event.TAURI_EVENT_RECEIVED when data is TauriEvent { EventType: TauriEventType.FILE_DROP_HOVERED }:
|
||||
if(this.PauseCatchingDrops)
|
||||
return;
|
||||
|
||||
|
||||
if(!this.isComponentHovered && !this.CatchAllDocuments)
|
||||
{
|
||||
this.Logger.LogDebug("Attach documents component '{Name}' is not hovered, ignoring file drop hovered event.", this.Name);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
this.isDraggingOver = true;
|
||||
this.SetDragClass();
|
||||
this.StateHasChanged();
|
||||
break;
|
||||
|
||||
|
||||
case Event.TAURI_EVENT_RECEIVED when data is TauriEvent { EventType: TauriEventType.FILE_DROP_CANCELED }:
|
||||
if(this.PauseCatchingDrops)
|
||||
return;
|
||||
|
||||
|
||||
this.isDraggingOver = false;
|
||||
this.StateHasChanged();
|
||||
break;
|
||||
|
||||
|
||||
case Event.TAURI_EVENT_RECEIVED when data is TauriEvent { EventType: TauriEventType.WINDOW_NOT_FOCUSED }:
|
||||
if(this.PauseCatchingDrops)
|
||||
return;
|
||||
|
||||
|
||||
this.isDraggingOver = false;
|
||||
this.isComponentHovered = false;
|
||||
this.ClearDragClass();
|
||||
this.StateHasChanged();
|
||||
break;
|
||||
|
||||
|
||||
case Event.TAURI_EVENT_RECEIVED when data is TauriEvent { EventType: TauriEventType.FILE_DROP_DROPPED, Payload: var paths }:
|
||||
if(this.PauseCatchingDrops)
|
||||
return;
|
||||
|
||||
|
||||
if(!this.isComponentHovered && !this.CatchAllDocuments)
|
||||
{
|
||||
this.Logger.LogDebug("Attach documents component '{Name}' is not hovered, ignoring file drop dropped event.", this.Name);
|
||||
@ -197,11 +203,14 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
#endregion
|
||||
|
||||
private const string DEFAULT_DRAG_CLASS = "relative rounded-lg border-2 border-dashed pa-4 mt-4 mud-width-full mud-height-full";
|
||||
|
||||
|
||||
private string dragClass = DEFAULT_DRAG_CLASS;
|
||||
|
||||
|
||||
private async Task AddFilesManually()
|
||||
{
|
||||
if (this.Disabled)
|
||||
return;
|
||||
|
||||
// Ensure that Pandoc is installed and ready:
|
||||
var pandocState = await this.PandocAvailabilityService.EnsureAvailabilityAsync(
|
||||
showSuccessMessage: false,
|
||||
@ -228,43 +237,49 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
|
||||
this.DocumentPaths.Add(FileAttachment.FromPath(selectedFilePath));
|
||||
}
|
||||
|
||||
|
||||
await this.DocumentPathsChanged.InvokeAsync(this.DocumentPaths);
|
||||
await this.OnChange(this.DocumentPaths);
|
||||
}
|
||||
|
||||
|
||||
private async Task OpenAttachmentsDialog()
|
||||
{
|
||||
if (this.Disabled)
|
||||
return;
|
||||
|
||||
this.DocumentPaths = await ReviewAttachmentsDialog.OpenDialogAsync(this.DialogService, this.DocumentPaths);
|
||||
}
|
||||
|
||||
private async Task ClearAllFiles()
|
||||
{
|
||||
if (this.Disabled)
|
||||
return;
|
||||
|
||||
this.DocumentPaths.Clear();
|
||||
await this.DocumentPathsChanged.InvokeAsync(this.DocumentPaths);
|
||||
await this.OnChange(this.DocumentPaths);
|
||||
}
|
||||
|
||||
private void SetDragClass() => this.dragClass = $"{DEFAULT_DRAG_CLASS} mud-border-primary border-4";
|
||||
|
||||
|
||||
private void ClearDragClass() => this.dragClass = DEFAULT_DRAG_CLASS;
|
||||
|
||||
|
||||
private void OnMouseEnter(EventArgs _)
|
||||
{
|
||||
if(this.PauseCatchingDrops)
|
||||
if(this.Disabled || this.PauseCatchingDrops)
|
||||
return;
|
||||
|
||||
|
||||
this.Logger.LogDebug("Attach documents component '{Name}' is hovered.", this.Name);
|
||||
this.isComponentHovered = true;
|
||||
this.SetDragClass();
|
||||
this.StateHasChanged();
|
||||
}
|
||||
|
||||
|
||||
private void OnMouseLeave(EventArgs _)
|
||||
{
|
||||
if(this.PauseCatchingDrops)
|
||||
if(this.Disabled || this.PauseCatchingDrops)
|
||||
return;
|
||||
|
||||
|
||||
this.Logger.LogDebug("Attach documents component '{Name}' is no longer hovered.", this.Name);
|
||||
this.isComponentHovered = false;
|
||||
this.ClearDragClass();
|
||||
@ -273,6 +288,9 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
|
||||
private async Task RemoveDocument(FileAttachment fileAttachment)
|
||||
{
|
||||
if (this.Disabled)
|
||||
return;
|
||||
|
||||
this.DocumentPaths.Remove(fileAttachment);
|
||||
|
||||
await this.DocumentPathsChanged.InvokeAsync(this.DocumentPaths);
|
||||
|
||||
@ -13,6 +13,8 @@ public partial class Changelog
|
||||
|
||||
public static readonly Log[] LOGS =
|
||||
[
|
||||
new (242, "v26.6.2, build 242 (2026-06-21 14:07 UTC)", "v26.6.2.md"),
|
||||
new (241, "v26.6.1, build 241 (2026-06-11 13:49 UTC)", "v26.6.1.md"),
|
||||
new (240, "v26.5.5, build 240 (2026-05-25 18:52 UTC)", "v26.5.5.md"),
|
||||
new (239, "v26.5.4, build 239 (2026-05-13 11:58 UTC)", "v26.5.4.md"),
|
||||
new (238, "v26.5.3, build 238 (2026-05-13 09:50 UTC)", "v26.5.3.md"),
|
||||
|
||||
@ -129,7 +129,7 @@
|
||||
<DataSourceSelection @ref="@this.dataSourceSelectionComponent" PopoverTriggerMode="PopoverTriggerMode.BUTTON" LLMProvider="@this.Provider" DataSourceOptions="@this.GetCurrentDataSourceOptions()" DataSourceOptionsChanged="@(async options => await this.SetCurrentDataSourceOptions(options))" DataSourcesAISelected="@this.GetAgentSelectedDataSources()"/>
|
||||
}
|
||||
|
||||
@if (this.SettingsManager.ConfigurationData.LLMProviders.ShowProviderConfidence)
|
||||
@if (this.SettingsManager.ConfigurationData.Confidence.ShowProviderConfidence)
|
||||
{
|
||||
<ConfidenceInfo Mode="PopoverTriggerMode.ICON" LLMProvider="@this.Provider.UsedLLMProvider"/>
|
||||
}
|
||||
|
||||
@ -69,6 +69,9 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
private bool mustLoadChat;
|
||||
private LoadChat loadChat;
|
||||
private bool autoSaveEnabled;
|
||||
private bool previousInputForbidden = true;
|
||||
private Guid lastSeenChatId = Guid.Empty;
|
||||
private AIStudio.Settings.Provider lastSeenProvider = AIStudio.Settings.Provider.NONE;
|
||||
private string currentWorkspaceName = string.Empty;
|
||||
private Guid currentWorkspaceId = Guid.Empty;
|
||||
private Guid currentChatThreadId = Guid.Empty;
|
||||
@ -101,7 +104,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
// Apply the filters for the message bus:
|
||||
this.ApplyFilters([], [ Event.HAS_CHAT_UNSAVED_CHANGES, Event.RESET_CHAT_STATE, Event.CHAT_STREAMING_DONE, Event.AI_JOB_CHANGED, Event.AI_JOB_FINISHED, Event.CHAT_GENERATION_CHANGED ]);
|
||||
this.ApplyFilters([], [ Event.HAS_CHAT_UNSAVED_CHANGES, Event.RESET_CHAT_STATE, Event.CHAT_STREAMING_DONE, Event.AI_JOB_CHANGED, Event.AI_JOB_FINISHED, Event.CHAT_GENERATION_CHANGED, Event.WORKSPACE_RENAMED, Event.CONFIGURATION_CHANGED ]);
|
||||
|
||||
// Configure the spellchecking for the user input:
|
||||
this.SettingsManager.InjectSpellchecking(USER_INPUT_ATTRIBUTES);
|
||||
@ -287,12 +290,25 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
this.StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var inputForbidden = this.IsInputForbidden();
|
||||
if (!inputForbidden && this.previousInputForbidden)
|
||||
await this.inputField.FocusAsync();
|
||||
|
||||
this.previousInputForbidden = inputForbidden;
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
var incomingChatId = this.ChatThread?.ChatId ?? Guid.Empty;
|
||||
if (incomingChatId != this.lastSeenChatId || this.Provider != this.lastSeenProvider)
|
||||
{
|
||||
this.lastSeenChatId = incomingChatId;
|
||||
this.lastSeenProvider = this.Provider;
|
||||
this.previousInputForbidden = true;
|
||||
}
|
||||
|
||||
await this.ApplyLoadedChatParameterAsync();
|
||||
await this.SyncForegroundChatAsync();
|
||||
await base.OnParametersSetAsync();
|
||||
@ -377,6 +393,29 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
this.WorkspaceName(this.currentWorkspaceName);
|
||||
}
|
||||
|
||||
private async Task RefreshRenamedWorkspaceHeaderAsync(Guid workspaceId)
|
||||
{
|
||||
var currentChatThread = this.ChatThread;
|
||||
if (currentChatThread is null || currentChatThread.WorkspaceId != workspaceId)
|
||||
return;
|
||||
|
||||
var syncVersion = Interlocked.Increment(ref this.workspaceHeaderSyncVersion);
|
||||
var chatThreadId = currentChatThread.ChatId;
|
||||
var loadedWorkspaceName = await WorkspaceBehaviour.LoadWorkspaceNameAsync(workspaceId);
|
||||
|
||||
if (syncVersion != this.workspaceHeaderSyncVersion)
|
||||
return;
|
||||
|
||||
if (this.ChatThread is null
|
||||
|| this.ChatThread.ChatId != chatThreadId
|
||||
|| this.ChatThread.WorkspaceId != workspaceId)
|
||||
return;
|
||||
|
||||
this.currentChatThreadId = chatThreadId;
|
||||
this.currentWorkspaceId = workspaceId;
|
||||
this.PublishWorkspaceNameIfChanged(loadedWorkspaceName);
|
||||
}
|
||||
|
||||
private async Task SyncForegroundChatAsync()
|
||||
{
|
||||
var nextForegroundChatId = this.ChatThread?.ChatId ?? Guid.Empty;
|
||||
@ -412,9 +451,9 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
|
||||
private string TooltipAddChatToWorkspace => string.Format(T("Start new chat in workspace '{0}'"), this.currentWorkspaceName);
|
||||
|
||||
private string UserInputStyle => this.SettingsManager.ConfigurationData.LLMProviders.ShowProviderConfidence ? this.Provider.UsedLLMProvider.GetConfidence(this.SettingsManager).SetColorStyle(this.SettingsManager) : string.Empty;
|
||||
|
||||
private string UserInputClass => this.SettingsManager.ConfigurationData.LLMProviders.ShowProviderConfidence ? "confidence-border" : string.Empty;
|
||||
private string UserInputStyle => this.SettingsManager.ConfigurationData.Confidence.ShowProviderConfidence ? this.Provider.UsedLLMProvider.GetConfidence(this.SettingsManager).SetColorStyle(this.SettingsManager) : string.Empty;
|
||||
|
||||
private string UserInputClass => this.SettingsManager.ConfigurationData.Confidence.ShowProviderConfidence ? "confidence-border" : string.Empty;
|
||||
|
||||
private void ApplyStandardDataSourceOptions()
|
||||
{
|
||||
@ -447,7 +486,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
|
||||
private async Task ProfileWasChanged(Profile profile)
|
||||
{
|
||||
this.currentProfile = profile;
|
||||
this.currentProfile = this.SettingsManager.GetProfileById(profile.Id);
|
||||
if(this.ChatThread is null)
|
||||
return;
|
||||
|
||||
@ -461,7 +500,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
|
||||
private async Task ChatTemplateWasChanged(ChatTemplate chatTemplate)
|
||||
{
|
||||
this.currentChatTemplate = chatTemplate;
|
||||
this.currentChatTemplate = this.SettingsManager.GetChatTemplateById(chatTemplate.Id);
|
||||
if(!string.IsNullOrWhiteSpace(this.currentChatTemplate.PredefinedUserPrompt))
|
||||
this.ComposerState.SetSystemInput(this.currentChatTemplate.PredefinedUserPrompt);
|
||||
|
||||
@ -474,6 +513,42 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
await this.StartNewChat(true);
|
||||
}
|
||||
|
||||
private void RefreshCurrentProfileAndChatTemplate()
|
||||
{
|
||||
this.currentProfile = this.SettingsManager.GetProfileById(this.currentProfile.Id);
|
||||
this.currentChatTemplate = this.SettingsManager.GetChatTemplateById(this.currentChatTemplate.Id);
|
||||
}
|
||||
|
||||
private async Task RefreshChatSelectionsAfterConfigurationChange()
|
||||
{
|
||||
var previousProvider = this.Provider;
|
||||
var previousChatTemplate = this.currentChatTemplate;
|
||||
var chatProviderId = this.ChatThread?.SelectedProvider;
|
||||
|
||||
this.Provider = this.SettingsManager.GetChatProviderForLoadedChat(chatProviderId);
|
||||
if (this.Provider != previousProvider)
|
||||
await this.ProviderChanged.InvokeAsync(this.Provider);
|
||||
|
||||
if (this.ChatThread is null)
|
||||
{
|
||||
this.currentProfile = this.SettingsManager.GetPreselectedProfile(Tools.Components.CHAT);
|
||||
this.currentChatTemplate = this.SettingsManager.GetPreselectedChatTemplate(Tools.Components.CHAT);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.currentProfile = string.IsNullOrWhiteSpace(this.ChatThread.SelectedProfile)
|
||||
? this.SettingsManager.GetProfileById(this.currentProfile.Id)
|
||||
: this.SettingsManager.GetProfileById(this.ChatThread.SelectedProfile);
|
||||
|
||||
this.currentChatTemplate = string.IsNullOrWhiteSpace(this.ChatThread.SelectedChatTemplate)
|
||||
? this.SettingsManager.GetChatTemplateById(this.currentChatTemplate.Id)
|
||||
: this.SettingsManager.GetChatTemplateById(this.ChatThread.SelectedChatTemplate);
|
||||
}
|
||||
|
||||
if (!this.ComposerState.HasUserDraft && previousChatTemplate != this.currentChatTemplate)
|
||||
this.ComposerState.ApplyTemplate(this.currentChatTemplate);
|
||||
}
|
||||
|
||||
private IReadOnlyList<DataSourceAgentSelected> GetAgentSelectedDataSources()
|
||||
{
|
||||
if (this.ChatThread is null)
|
||||
@ -578,7 +653,9 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
|
||||
if(!this.ChatThread.IsLLMProviderAllowed(this.Provider))
|
||||
return;
|
||||
|
||||
|
||||
this.RefreshCurrentProfileAndChatTemplate();
|
||||
|
||||
// Blur the focus away from the input field to be able to clear it:
|
||||
await this.inputField.BlurAsync();
|
||||
|
||||
@ -772,6 +849,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
//
|
||||
this.hasUnsavedChanges = false;
|
||||
this.ComposerState.Clear();
|
||||
this.RefreshCurrentProfileAndChatTemplate();
|
||||
|
||||
//
|
||||
// Reset the LLM provider considering the user's settings:
|
||||
@ -864,7 +942,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
{ x => x.ConfirmText, T("Move chat") },
|
||||
};
|
||||
|
||||
var dialogReference = await this.DialogService.ShowAsync<WorkspaceSelectionDialog>(T("Move Chat to Workspace"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||
var dialogReference = await this.DialogService.ShowAsync<WorkspaceSelectionDialog>(T("Move Chat to Workspace"), dialogParameters, DialogOptions.FULLSCREEN_MANUAL_ESCAPE);
|
||||
var dialogResult = await dialogReference.Result;
|
||||
if (dialogResult is null || dialogResult.Canceled)
|
||||
return;
|
||||
@ -944,14 +1022,11 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
|
||||
// Try to select the profile:
|
||||
if (!string.IsNullOrWhiteSpace(chatProfile))
|
||||
this.currentProfile = this.SettingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == chatProfile) ?? Profile.NO_PROFILE;
|
||||
this.currentProfile = this.SettingsManager.GetProfileById(chatProfile);
|
||||
|
||||
// Try to select the chat template:
|
||||
if (!string.IsNullOrWhiteSpace(chatChatTemplate))
|
||||
{
|
||||
var selectedTemplate = this.SettingsManager.ConfigurationData.ChatTemplates.FirstOrDefault(x => x.Id == chatChatTemplate);
|
||||
this.currentChatTemplate = selectedTemplate ?? ChatTemplate.NO_CHAT_TEMPLATE;
|
||||
}
|
||||
this.currentChatTemplate = this.SettingsManager.GetChatTemplateById(chatChatTemplate);
|
||||
}
|
||||
|
||||
private async Task ToggleWorkspaceOverlay()
|
||||
@ -1046,6 +1121,17 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
if(this.autoSaveEnabled)
|
||||
await this.SaveThread();
|
||||
break;
|
||||
|
||||
case Event.WORKSPACE_RENAMED:
|
||||
if (data is Guid workspaceId)
|
||||
await this.RefreshRenamedWorkspaceHeaderAsync(workspaceId);
|
||||
break;
|
||||
|
||||
case Event.CONFIGURATION_CHANGED:
|
||||
case Event.PLUGINS_RELOADED:
|
||||
await this.RefreshChatSelectionsAfterConfigurationChange();
|
||||
this.StateHasChanged();
|
||||
break;
|
||||
|
||||
case Event.AI_JOB_CHANGED:
|
||||
case Event.AI_JOB_FINISHED:
|
||||
@ -1054,7 +1140,10 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
{
|
||||
this.ChatThread = this.AIJobService.TryGetLiveChatThread(snapshot.SubjectId) ?? this.ChatThread;
|
||||
if (!snapshot.IsActive)
|
||||
{
|
||||
this.hasUnsavedChanges = false;
|
||||
this.previousInputForbidden = true;
|
||||
}
|
||||
|
||||
this.StateHasChanged();
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<ActivatorContent>
|
||||
@if (this.CurrentChatTemplate != ChatTemplate.NO_CHAT_TEMPLATE)
|
||||
{
|
||||
<MudButton IconSize="Size.Large" StartIcon="@Icons.Material.Filled.RateReview" IconColor="Color.Default">
|
||||
<MudButton IconSize="Size.Large" StartIcon="@this.ChatTemplateIcon(this.CurrentChatTemplate)" IconColor="Color.Default">
|
||||
@this.CurrentChatTemplate.GetSafeName()
|
||||
</MudButton>
|
||||
}
|
||||
@ -22,7 +22,7 @@
|
||||
<MudDivider/>
|
||||
@foreach (var chatTemplate in this.SettingsManager.ConfigurationData.ChatTemplates.GetAllChatTemplates())
|
||||
{
|
||||
<MudMenuItem Icon="@Icons.Material.Filled.RateReview" OnClick="@(async () => await this.SelectionChanged(chatTemplate))">
|
||||
<MudMenuItem Icon="@this.ChatTemplateIcon(chatTemplate)" OnClick="@(async () => await this.SelectionChanged(chatTemplate))">
|
||||
@chatTemplate.GetSafeName()
|
||||
</MudMenuItem>
|
||||
}
|
||||
|
||||
@ -11,13 +11,13 @@ public partial class ChatTemplateSelection : MSGComponentBase
|
||||
{
|
||||
[Parameter]
|
||||
public ChatTemplate CurrentChatTemplate { get; set; } = ChatTemplate.NO_CHAT_TEMPLATE;
|
||||
|
||||
|
||||
[Parameter]
|
||||
public bool CanChatThreadBeUsedForTemplate { get; set; }
|
||||
|
||||
|
||||
[Parameter]
|
||||
public ChatThread? CurrentChatThread { get; set; }
|
||||
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<ChatTemplate> CurrentChatTemplateChanged { get; set; }
|
||||
|
||||
@ -26,24 +26,42 @@ public partial class ChatTemplateSelection : MSGComponentBase
|
||||
|
||||
[Parameter]
|
||||
public string MarginRight { get; set; } = string.Empty;
|
||||
|
||||
|
||||
[Inject]
|
||||
private IDialogService DialogService { get; init; } = null!;
|
||||
|
||||
|
||||
private string MarginClass => $"{this.MarginLeft} {this.MarginRight}";
|
||||
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
this.ApplyFilters([], [ Event.CONFIGURATION_CHANGED ]);
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private string ChatTemplateIcon(ChatTemplate chatTemplate)
|
||||
{
|
||||
if (chatTemplate.IsEnterpriseConfiguration)
|
||||
return Icons.Material.Filled.Business;
|
||||
|
||||
return Icons.Material.Filled.RateReview;
|
||||
}
|
||||
|
||||
private async Task SelectionChanged(ChatTemplate chatTemplate)
|
||||
{
|
||||
this.CurrentChatTemplate = chatTemplate;
|
||||
await this.CurrentChatTemplateChanged.InvokeAsync(chatTemplate);
|
||||
}
|
||||
|
||||
|
||||
private async Task OpenSettingsDialog()
|
||||
{
|
||||
var dialogParameters = new DialogParameters();
|
||||
await this.DialogService.ShowAsync<SettingsDialogChatTemplate>(T("Open Chat Template Options"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||
}
|
||||
|
||||
|
||||
private async Task CreateNewChatTemplateFromChat()
|
||||
{
|
||||
var dialogParameters = new DialogParameters<SettingsDialogChatTemplate>
|
||||
@ -53,4 +71,16 @@ public partial class ChatTemplateSelection : MSGComponentBase
|
||||
};
|
||||
await this.DialogService.ShowAsync<SettingsDialogChatTemplate>(T("Open Chat Template Options"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||
}
|
||||
|
||||
#region Overrides of MSGComponentBase
|
||||
|
||||
protected override Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
|
||||
{
|
||||
if (triggeredEvent is Event.CONFIGURATION_CHANGED or Event.PLUGINS_RELOADED)
|
||||
this.StateHasChanged();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -56,10 +56,12 @@ public abstract partial class ConfigurationBase : MSGComponentBase
|
||||
|
||||
protected bool IsDisabled => this.Disabled() || this.IsLocked();
|
||||
|
||||
private string Classes => $"{this.GetClassForBase} {MARGIN_CLASS}";
|
||||
private string Classes => $"{this.GetClassForBase} {JUSTIFIED_HELP_CLASS} {MARGIN_CLASS}";
|
||||
|
||||
private protected virtual RenderFragment? Body => null;
|
||||
|
||||
private const string JUSTIFIED_HELP_CLASS = "configuration-help-justified";
|
||||
|
||||
private const string MARGIN_CLASS = "mb-6";
|
||||
|
||||
protected static readonly Dictionary<string, object?> SPELLCHECK_ATTRIBUTES = new();
|
||||
|
||||
27
app/MindWork AI Studio/Components/ConfigurationFile.razor
Normal file
27
app/MindWork AI Studio/Components/ConfigurationFile.razor
Normal file
@ -0,0 +1,27 @@
|
||||
@inherits ConfigurationBaseCore
|
||||
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
||||
<MudTextField
|
||||
T="string"
|
||||
Text="@this.Text()"
|
||||
TextChanged="@this.InternalUpdate"
|
||||
Disabled="@this.IsDisabled"
|
||||
Adornment="Adornment.Start"
|
||||
AdornmentIcon="@this.Icon"
|
||||
AdornmentColor="@this.IconColor"
|
||||
UserAttributes="@SPELLCHECK_ATTRIBUTES"
|
||||
Immediate="@true"
|
||||
Underline="false"
|
||||
Class="flex-grow-1"
|
||||
/>
|
||||
|
||||
<MudButton StartIcon="@Icons.Material.Filled.FolderOpen"
|
||||
Variant="Variant.Outlined"
|
||||
Color="Color.Primary"
|
||||
Size="Size.Small"
|
||||
Disabled="@this.IsDisabled"
|
||||
Class="mb-1"
|
||||
OnClick="@this.OpenFileDialog">
|
||||
@T("Choose File")
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
127
app/MindWork AI Studio/Components/ConfigurationFile.razor.cs
Normal file
127
app/MindWork AI Studio/Components/ConfigurationFile.razor.cs
Normal file
@ -0,0 +1,127 @@
|
||||
using AIStudio.Tools.Rust;
|
||||
using AIStudio.Tools.Services;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
using Timer = System.Timers.Timer;
|
||||
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public partial class ConfigurationFile : ConfigurationBaseCore
|
||||
{
|
||||
/// <summary>
|
||||
/// The text used for the textfield.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<string> Text { get; set; } = () => string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// An action which is called when the text was changed.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Action<string> TextUpdate { get; set; } = _ => { };
|
||||
|
||||
/// <summary>
|
||||
/// The icon to display next to the textfield.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Icon { get; set; } = Icons.Material.Filled.AttachFile;
|
||||
|
||||
/// <summary>
|
||||
/// The color of the icon to use.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Color IconColor { get; set; } = Color.Default;
|
||||
|
||||
/// <summary>
|
||||
/// The title of the file selection dialog.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string FileDialogTitle { get; set; } = "Select File";
|
||||
|
||||
/// <summary>
|
||||
/// The optional file type filter for the file selection dialog.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public FileTypeFilter[]? Filter { get; set; }
|
||||
|
||||
[Inject]
|
||||
private RustService RustService { get; init; } = null!;
|
||||
|
||||
private string internalText = string.Empty;
|
||||
private readonly Timer timer = new(TimeSpan.FromMilliseconds(500))
|
||||
{
|
||||
AutoReset = false
|
||||
};
|
||||
|
||||
#region Overrides of ConfigurationBase
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool Stretch => true;
|
||||
|
||||
protected override Variant Variant => Variant.Outlined;
|
||||
|
||||
protected override string Label => this.OptionDescription;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides of ConfigurationBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
this.timer.Elapsed += async (_, _) => await this.InvokeAsync(async () => await this.OptionChanged(this.internalText));
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
this.internalText = this.Text();
|
||||
await base.OnParametersSetAsync();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void InternalUpdate(string text)
|
||||
{
|
||||
this.timer.Stop();
|
||||
this.internalText = text;
|
||||
this.timer.Start();
|
||||
}
|
||||
|
||||
private async Task OpenFileDialog()
|
||||
{
|
||||
var response = await this.RustService.SelectFile(this.FileDialogTitle, this.Filter, string.IsNullOrWhiteSpace(this.internalText) ? null : this.internalText);
|
||||
if (response.UserCancelled)
|
||||
return;
|
||||
|
||||
this.timer.Stop();
|
||||
this.internalText = response.SelectedFilePath;
|
||||
await this.OptionChanged(response.SelectedFilePath);
|
||||
}
|
||||
|
||||
private async Task OptionChanged(string updatedText)
|
||||
{
|
||||
this.TextUpdate(updatedText);
|
||||
await this.SettingsManager.StoreSettings();
|
||||
await this.InformAboutChange();
|
||||
}
|
||||
|
||||
#region Overrides of MSGComponentBase
|
||||
|
||||
protected override void DisposeResources()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.timer.Stop();
|
||||
this.timer.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
base.DisposeResources();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -41,9 +41,9 @@ public partial class ConfigurationMinConfidenceSelection : MSGComponentBase
|
||||
if (this.SelectedValue() is ConfidenceLevel.NONE)
|
||||
return ConfidenceLevel.NONE;
|
||||
|
||||
if(this.RestrictToGlobalMinimumConfidence && this.SettingsManager.ConfigurationData.LLMProviders.EnforceGlobalMinimumConfidence)
|
||||
if(this.RestrictToGlobalMinimumConfidence && this.SettingsManager.ConfigurationData.Confidence.EnforceGlobalMinimumConfidence)
|
||||
{
|
||||
var minimumLevel = this.SettingsManager.ConfigurationData.LLMProviders.GlobalMinimumConfidence;
|
||||
var minimumLevel = this.SettingsManager.ConfigurationData.Confidence.GlobalMinimumConfidence;
|
||||
if(this.SelectedValue() < minimumLevel)
|
||||
return minimumLevel;
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
||||
<MudIcon Icon="@this.Icon" Color="@this.IconColor"/>
|
||||
<MudText Typo="Typo.body1" Class="flex-grow-1">
|
||||
@if (string.IsNullOrWhiteSpace(this.Shortcut()))
|
||||
@if (string.IsNullOrWhiteSpace(this.Data.Value()))
|
||||
{
|
||||
@T("No shortcut configured")
|
||||
}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using AIStudio.Dialogs;
|
||||
using AIStudio.Tools.Rust;
|
||||
using AIStudio.Tools.Services;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
@ -19,22 +18,10 @@ public partial class ConfigurationShortcut : ConfigurationBaseCore
|
||||
private RustService RustService { get; init; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The current shortcut value.
|
||||
/// The shortcut binding data.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<string> Shortcut { get; set; } = () => string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// An action which is called when the shortcut was changed.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Action<string> ShortcutUpdate { get; set; } = _ => { };
|
||||
|
||||
/// <summary>
|
||||
/// The name/identifier of the shortcut (used for conflict detection and registration).
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Shortcut ShortcutId { get; init; }
|
||||
public ConfigurationShortcutData Data { get; set; } = ConfigurationShortcutData.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The icon to display.
|
||||
@ -60,10 +47,18 @@ public partial class ConfigurationShortcut : ConfigurationBaseCore
|
||||
|
||||
private string GetDisplayShortcut()
|
||||
{
|
||||
var shortcut = this.Shortcut();
|
||||
var shortcut = this.Data.Value();
|
||||
if (string.IsNullOrWhiteSpace(shortcut))
|
||||
return string.Empty;
|
||||
|
||||
var shortcutDisplayName = this.Data.DisplayName();
|
||||
var shortcutDisplaySource = this.Data.DisplaySource();
|
||||
if (!string.IsNullOrWhiteSpace(shortcutDisplayName)
|
||||
&& string.Equals(shortcutDisplaySource, shortcut, StringComparison.Ordinal))
|
||||
{
|
||||
return shortcutDisplayName;
|
||||
}
|
||||
|
||||
// Convert internal format to display format:
|
||||
return shortcut
|
||||
.Replace("CmdOrControl", OperatingSystem.IsMacOS() ? "Cmd" : "Ctrl")
|
||||
@ -80,8 +75,8 @@ public partial class ConfigurationShortcut : ConfigurationBaseCore
|
||||
{
|
||||
var dialogParameters = new DialogParameters<ShortcutDialog>
|
||||
{
|
||||
{ x => x.InitialShortcut, this.Shortcut() },
|
||||
{ x => x.ShortcutId, this.ShortcutId },
|
||||
{ x => x.InitialShortcut, this.Data.Value() },
|
||||
{ x => x.ShortcutId, this.Data.Id },
|
||||
};
|
||||
|
||||
var dialogReference = await this.DialogService.ShowAsync<ShortcutDialog>(
|
||||
@ -93,9 +88,17 @@ public partial class ConfigurationShortcut : ConfigurationBaseCore
|
||||
if (dialogResult is null || dialogResult.Canceled)
|
||||
return;
|
||||
|
||||
if (dialogResult.Data is string newShortcut)
|
||||
if (dialogResult.Data is ShortcutDialogResult shortcutResult)
|
||||
{
|
||||
this.ShortcutUpdate(newShortcut);
|
||||
this.Data.ValueUpdate(shortcutResult.Shortcut);
|
||||
this.Data.DisplayUpdate(shortcutResult.DisplayName, shortcutResult.DisplaySource);
|
||||
await this.SettingsManager.StoreSettings();
|
||||
await this.InformAboutChange();
|
||||
}
|
||||
else if (dialogResult.Data is string newShortcut)
|
||||
{
|
||||
this.Data.ValueUpdate(newShortcut);
|
||||
this.Data.DisplayUpdate(string.Empty, string.Empty);
|
||||
await this.SettingsManager.StoreSettings();
|
||||
await this.InformAboutChange();
|
||||
}
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
using AIStudio.Tools.Rust;
|
||||
|
||||
namespace AIStudio.Components;
|
||||
|
||||
/// <summary>
|
||||
/// UI binding data for a configurable keyboard shortcut.
|
||||
/// </summary>
|
||||
public sealed class ConfigurationShortcutData
|
||||
{
|
||||
/// <summary>
|
||||
/// Empty shortcut binding.
|
||||
/// </summary>
|
||||
public static ConfigurationShortcutData Empty { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// The name/identifier of the shortcut, used for conflict detection and registration.
|
||||
/// </summary>
|
||||
public Shortcut Id { get; init; } = Shortcut.NONE;
|
||||
|
||||
/// <summary>
|
||||
/// The current shortcut value.
|
||||
/// </summary>
|
||||
public Func<string> Value { get; init; } = () => string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// An action that is called when the shortcut was changed.
|
||||
/// </summary>
|
||||
public Action<string> ValueUpdate { get; init; } = _ => { };
|
||||
|
||||
/// <summary>
|
||||
/// The optional user-facing shortcut label.
|
||||
/// </summary>
|
||||
public Func<string> DisplayName { get; init; } = () => string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The canonical shortcut value the optional user-facing label belongs to.
|
||||
/// </summary>
|
||||
public Func<string> DisplaySource { get; init; } = () => string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// An action that is called when the user-facing shortcut label was changed.
|
||||
/// </summary>
|
||||
public Action<string, string> DisplayUpdate { get; init; } = (_, _) => { };
|
||||
}
|
||||
@ -37,6 +37,16 @@ public partial class ProfileSelection : MSGComponentBase
|
||||
private string ToolTipText => this.Disabled ? this.DisabledText : this.defaultToolTipText;
|
||||
|
||||
private string MarginClass => $"{this.MarginLeft} {this.MarginRight}";
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
this.ApplyFilters([], [ Event.CONFIGURATION_CHANGED ]);
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private string ProfileIcon(Profile profile)
|
||||
{
|
||||
@ -57,4 +67,16 @@ public partial class ProfileSelection : MSGComponentBase
|
||||
var dialogParameters = new DialogParameters();
|
||||
await this.DialogService.ShowAsync<SettingsDialogProfiles>(T("Open Profile Options"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||
}
|
||||
|
||||
#region Overrides of MSGComponentBase
|
||||
|
||||
protected override Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
|
||||
{
|
||||
if (triggeredEvent is Event.CONFIGURATION_CHANGED or Event.PLUGINS_RELOADED)
|
||||
this.StateHasChanged();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -25,6 +25,16 @@ public partial class ProviderSelection : MSGComponentBase
|
||||
|
||||
[Inject]
|
||||
private ILogger<ProviderSelection> Logger { get; init; } = null!;
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
this.ApplyFilters([], [ Event.CONFIGURATION_CHANGED ]);
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private async Task SelectionChanged(AIStudio.Settings.Provider provider)
|
||||
{
|
||||
@ -62,4 +72,16 @@ public partial class ProviderSelection : MSGComponentBase
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#region Overrides of MSGComponentBase
|
||||
|
||||
protected override Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
|
||||
{
|
||||
if (triggeredEvent is Event.CONFIGURATION_CHANGED or Event.PLUGINS_RELOADED)
|
||||
this.StateHasChanged();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -3,9 +3,9 @@
|
||||
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.Policy" HeaderText="@T("Agent: Security Audit for external Assistants")">
|
||||
<MudPaper Class="pa-3 mb-8 border-dashed border rounded-lg">
|
||||
<MudText Typo="Typo.body1" Class="mb-3">
|
||||
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
|
||||
@T("This Agent audits newly installed or updated external Plugin-Assistant for security risks before they are activated and stores the latest audit card until the plugin manifest changes.")
|
||||
</MudText>
|
||||
</MudJustifiedText>
|
||||
<MudField Label="@T("Require a security audit before activating external Assistants?")" Variant="Variant.Outlined" Underline="false" Class="mb-6" InnerPadding="false">
|
||||
<MudSwitch T="bool" Value="@this.SettingsManager.ConfigurationData.AssistantPluginAudit.RequireAuditBeforeActivation" ValueChanged="@this.RequireAuditBeforeActivationChanged" Color="Color.Primary">
|
||||
@(this.SettingsManager.ConfigurationData.AssistantPluginAudit.RequireAuditBeforeActivation ? T("External Assistants must be audited before activation") : T("External Assistant can be activated without an audit"))
|
||||
|
||||
@ -2,9 +2,9 @@
|
||||
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.TextFields" HeaderText="@T("Agent: Text Content Cleaner Options")">
|
||||
<MudPaper Class="pa-3 mb-8 border-dashed border rounded-lg">
|
||||
<MudText Typo="Typo.body1" Class="mb-3">
|
||||
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
|
||||
@T("Use Case: this agent is used to clean up text content. It extracts the main content, removes advertisements and other irrelevant things, and attempts to convert relative links into absolute links so that they can be used.")
|
||||
</MudText>
|
||||
</MudJustifiedText>
|
||||
<ConfigurationOption OptionDescription="@T("Preselect text content cleaner options?")" LabelOn="@T("Options are preselected")" LabelOff="@T("No options are preselected")" State="@(() => this.SettingsManager.ConfigurationData.TextContentCleaner.PreselectAgentOptions)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.TextContentCleaner.PreselectAgentOptions = updatedState)" OptionHelp="@T("When enabled, you can preselect some agent options. This is might be useful when you prefer an LLM.")"/>
|
||||
<ConfigurationProviderSelection Data="@this.AvailableLLMProvidersFunc()" Disabled="@(() => !this.SettingsManager.ConfigurationData.TextContentCleaner.PreselectAgentOptions)" SelectedValue="@(() => this.SettingsManager.ConfigurationData.TextContentCleaner.PreselectedAgentProvider)" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.TextContentCleaner.PreselectedAgentProvider = selectedValue)"/>
|
||||
</MudPaper>
|
||||
|
||||
@ -2,9 +2,9 @@
|
||||
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.SelectAll" HeaderText="@T("Agent: Data Source Selection Options")">
|
||||
<MudPaper Class="pa-3 mb-8 border-dashed border rounded-lg">
|
||||
<MudText Typo="Typo.body1" Class="mb-3">
|
||||
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
|
||||
@T("Use Case: this agent is used to select the appropriate data sources for the current prompt.")
|
||||
</MudText>
|
||||
</MudJustifiedText>
|
||||
<ConfigurationOption OptionDescription="@T("Preselect data source selection options?")" LabelOn="@T("Options are preselected")" LabelOff="@T("No options are preselected")" State="@(() => this.SettingsManager.ConfigurationData.AgentDataSourceSelection.PreselectAgentOptions)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.AgentDataSourceSelection.PreselectAgentOptions = updatedState)" OptionHelp="@T("When enabled, you can preselect some agent options. This is might be useful when you prefer an LLM.")"/>
|
||||
<ConfigurationProviderSelection Data="@this.AvailableLLMProvidersFunc()" Disabled="@(() => !this.SettingsManager.ConfigurationData.AgentDataSourceSelection.PreselectAgentOptions)" SelectedValue="@(() => this.SettingsManager.ConfigurationData.AgentDataSourceSelection.PreselectedAgentProvider)" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.AgentDataSourceSelection.PreselectedAgentProvider = selectedValue)"/>
|
||||
</MudPaper>
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
@inherits SettingsPanelBase
|
||||
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.Assessment" HeaderText="@T("Agent: Retrieval Context Validation Options")">
|
||||
<MudText Typo="Typo.body1" Class="mb-3">
|
||||
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
|
||||
@T("Use Case: this agent is used to validate any retrieval context of any retrieval process. Perhaps there are many of these retrieval contexts and you want to validate them all. Therefore, you might want to use a cheap and fast LLM for this job. When using a local or self-hosted LLM, look for a small (e.g. 3B) and fast model.")
|
||||
</MudText>
|
||||
</MudJustifiedText>
|
||||
<ConfigurationOption OptionDescription="@T("Enable the retrieval context validation agent?")" LabelOn="@T("The validation agent is enabled")" LabelOff="@T("No validation is performed")" State="@(() => this.SettingsManager.ConfigurationData.AgentRetrievalContextValidation.EnableRetrievalContextValidation)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.AgentRetrievalContextValidation.EnableRetrievalContextValidation = updatedState)" OptionHelp="@T("When enabled, the retrieval context validation agent will check each retrieval context of any retrieval process, whether a context makes sense for the given prompt.")"/>
|
||||
@if (this.SettingsManager.ConfigurationData.AgentRetrievalContextValidation.EnableRetrievalContextValidation)
|
||||
{
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
@if (PreviewFeatures.PRE_SPEECH_TO_TEXT_2026.IsEnabled(this.SettingsManager))
|
||||
{
|
||||
<ConfigurationSelect OptionDescription="@T("Select a transcription provider")" SelectedValue="@(() => this.SettingsManager.ConfigurationData.App.UseTranscriptionProvider)" Data="@this.GetFilteredTranscriptionProviders()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.App.UseTranscriptionProvider = selectedValue)" OptionHelp="@T("Select a transcription provider for transcribing your voice. Without a selected provider, dictation and transcription features will be disabled.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.UseTranscriptionProvider, out var meta) && meta.IsLocked"/>
|
||||
<ConfigurationShortcut ShortcutId="Shortcut.VOICE_RECORDING_TOGGLE" OptionDescription="@T("Voice recording shortcut")" Shortcut="@(() => this.SettingsManager.ConfigurationData.App.ShortcutVoiceRecording)" ShortcutUpdate="@(shortcut => this.SettingsManager.ConfigurationData.App.ShortcutVoiceRecording = shortcut)" OptionHelp="@T("The global keyboard shortcut for toggling voice recording. This shortcut works system-wide, even when the app is not focused.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.ShortcutVoiceRecording, out var meta) && meta.IsLocked"/>
|
||||
<ConfigurationShortcut Data="@this.VoiceRecordingShortcut" OptionDescription="@T("Voice recording shortcut")" OptionHelp="@T("The global keyboard shortcut for toggling voice recording. This shortcut works system-wide, even when the app is not focused.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.ShortcutVoiceRecording, out var meta) && meta.IsLocked"/>
|
||||
}
|
||||
|
||||
@if (this.SettingsManager.ConfigurationData.App.ShowAdminSettings)
|
||||
@ -46,12 +46,12 @@
|
||||
@T("Enterprise Administration")
|
||||
</MudText>
|
||||
|
||||
<MudText Typo="Typo.body2" Class="mb-3">
|
||||
<MudJustifiedText Typo="Typo.body2" Class="mb-3">
|
||||
@T("Generate a 256-bit encryption secret for encrypting API keys in configuration plugins. Deploy this secret to client machines via Group Policy (Windows Registry) or environment variables. Providers can then be exported with encrypted API keys using the export buttons in the provider settings.")
|
||||
<MudLink Href="https://github.com/MindWorkAI/AI-Studio/blob/main/documentation/Enterprise%20IT.md" Target="_blank">
|
||||
@T("Read the Enterprise IT documentation for details.")
|
||||
</MudLink>
|
||||
</MudText>
|
||||
</MudJustifiedText>
|
||||
|
||||
<MudButton StartIcon="@Icons.Material.Filled.Key"
|
||||
Variant="Variant.Filled"
|
||||
@ -59,5 +59,13 @@
|
||||
OnClick="@this.GenerateEncryptionSecret">
|
||||
@T("Generate an encryption secret and copy it to the clipboard")
|
||||
</MudButton>
|
||||
|
||||
<MudText Typo="Typo.h6" Class="mt-6 mb-3">
|
||||
@T("External HTTPS certificates")
|
||||
</MudText>
|
||||
|
||||
<ConfigurationOption OptionDescription="@T("Use additional root certificates for external HTTPS requests?")" LabelOn="@T("Additional root certificates are enabled")" LabelOff="@T("Additional root certificates are disabled")" State="@(() => this.SettingsManager.ConfigurationData.App.ExternalHttpCustomRootCertificatesEnabled)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.App.ExternalHttpCustomRootCertificatesEnabled = updatedState)" OptionHelp="@T("When enabled, AI Studio can trust root certificates from a configured PEM bundle for external HTTPS requests, such as self-hosted AI providers, embeddings, transcription, ERI data sources, and enterprise configuration downloads. Normal hostname and certificate validity checks still apply. Integrated cloud providers, such as OpenAI, Google, and others, will never use these additional certificates. Please note that you usually do not need this setting on macOS or Windows. If you use Linux with the AppImage version of MindWork AI Studio, you also do not need this option. A valid use case is a Linux environment where AI Studio runs from a Flatpak.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.ExternalHttpCustomRootCertificatesEnabled, out var meta) && meta.IsLocked"/>
|
||||
<ConfigurationFile OptionDescription="@T("Root certificate bundle path")" Icon="@Icons.Material.Filled.Folder" Text="@(() => this.SettingsManager.ConfigurationData.App.ExternalHttpCustomRootCertificateBundlePath)" TextUpdate="@(updatedText => this.SettingsManager.ConfigurationData.App.ExternalHttpCustomRootCertificateBundlePath = updatedText)" FileDialogTitle="@T("Select a root certificate bundle")" Filter="@([FileTypes.CERTIFICATE_BUNDLE])" Disabled="@this.AreExternalHttpCustomRootCertificateDetailsDisabled" OptionHelp="@T("Path to a PEM file containing one or more root CA certificates. For Flatpak deployments, this file must be placed in a location that is readable inside the sandbox.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.ExternalHttpCustomRootCertificateBundlePath, out var meta) && meta.IsLocked"/>
|
||||
<ConfigurationText OptionDescription="@T("Allowed hosts for additional root certificates")" Icon="@Icons.Material.Filled.Dns" NumLines="3" Text="@this.GetExternalHttpCustomRootCertificateAllowedHostsText" TextUpdate="@this.UpdateExternalHttpCustomRootCertificateAllowedHosts" Disabled="@this.AreExternalHttpCustomRootCertificateDetailsDisabled" OptionHelp="@T("Enter one host pattern per line. Exact hosts such as data.intra.example.org and one-label wildcards such as *.intra.example.org are supported. Cloud provider endpoints built into AI Studio, such as OpenAI, Google, etc., never use these additional root certificates.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.ExternalHttpCustomRootCertificateAllowedHosts, out var meta) && meta.IsLocked"/>
|
||||
}
|
||||
</ExpansionPanel>
|
||||
|
||||
@ -1,11 +1,22 @@
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Settings.DataModel;
|
||||
using AIStudio.Tools.Rust;
|
||||
|
||||
namespace AIStudio.Components.Settings;
|
||||
|
||||
public partial class SettingsPanelApp : SettingsPanelBase
|
||||
{
|
||||
private ConfigurationShortcutData VoiceRecordingShortcut => new()
|
||||
{
|
||||
Id = Shortcut.VOICE_RECORDING_TOGGLE,
|
||||
Value = () => this.SettingsManager.ConfigurationData.App.ShortcutVoiceRecording,
|
||||
ValueUpdate = shortcut => this.SettingsManager.ConfigurationData.App.ShortcutVoiceRecording = shortcut,
|
||||
DisplayName = () => this.SettingsManager.ConfigurationData.App.ShortcutVoiceRecordingDisplayName,
|
||||
DisplaySource = () => this.SettingsManager.ConfigurationData.App.ShortcutVoiceRecordingDisplaySource,
|
||||
DisplayUpdate = this.UpdateShortcutVoiceRecordingDisplay,
|
||||
};
|
||||
|
||||
private async Task GenerateEncryptionSecret()
|
||||
{
|
||||
var secret = EnterpriseEncryption.GenerateSecret();
|
||||
@ -67,12 +78,38 @@ public partial class SettingsPanelApp : SettingsPanelBase
|
||||
return enabled;
|
||||
}
|
||||
|
||||
private string GetExternalHttpCustomRootCertificateAllowedHostsText()
|
||||
{
|
||||
return string.Join(Environment.NewLine, this.SettingsManager.ConfigurationData.App.ExternalHttpCustomRootCertificateAllowedHosts.Order(StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private bool AreExternalHttpCustomRootCertificateDetailsDisabled()
|
||||
{
|
||||
return !this.SettingsManager.ConfigurationData.App.ExternalHttpCustomRootCertificatesEnabled;
|
||||
}
|
||||
|
||||
private void UpdateExternalHttpCustomRootCertificateAllowedHosts(string updatedText)
|
||||
{
|
||||
var patterns = updatedText
|
||||
.Split(['\r', '\n', ';', ','], StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
||||
.Where(pattern => !string.IsNullOrWhiteSpace(pattern))
|
||||
.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
this.SettingsManager.ConfigurationData.App.ExternalHttpCustomRootCertificateAllowedHosts = patterns;
|
||||
}
|
||||
|
||||
private void UpdateEnabledPreviewFeatures(HashSet<PreviewFeatures> selectedFeatures)
|
||||
{
|
||||
selectedFeatures.UnionWith(this.GetPluginContributedPreviewFeatures());
|
||||
this.SettingsManager.ConfigurationData.App.EnabledPreviewFeatures = selectedFeatures;
|
||||
}
|
||||
|
||||
private void UpdateShortcutVoiceRecordingDisplay(string displayName, string displaySource)
|
||||
{
|
||||
this.SettingsManager.ConfigurationData.App.ShortcutVoiceRecordingDisplayName = displayName;
|
||||
this.SettingsManager.ConfigurationData.App.ShortcutVoiceRecordingDisplaySource = displaySource;
|
||||
}
|
||||
|
||||
private async Task UpdateLangBehaviour(LangBehavior behavior)
|
||||
{
|
||||
this.SettingsManager.ConfigurationData.App.LanguageBehavior = behavior;
|
||||
|
||||
@ -0,0 +1,60 @@
|
||||
@using AIStudio.Provider
|
||||
@using AIStudio.Settings
|
||||
@inherits SettingsPanelBase
|
||||
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.Security" HeaderText="@T("Provider Confidence")">
|
||||
<MudText Typo="Typo.h4" Class="mb-3">
|
||||
@T("Provider Confidence")
|
||||
</MudText>
|
||||
<MudJustifiedText Class="mb-3">
|
||||
@T("Do you want to always see how trustworthy your providers are? This way, you stay in control of which provider you send your data to. You can choose a common schema or configure the trust levels for each provider yourself.")
|
||||
</MudJustifiedText>
|
||||
|
||||
<ConfigurationOption OptionDescription="@T("Do you want to enforce an global minimum confidence level?")" LabelOn="@T("Yes, enforce a minimum confidence level")" LabelOff="@T("No, do not enforce a minimum confidence level")" State="@(() => this.SettingsManager.ConfigurationData.Confidence.EnforceGlobalMinimumConfidence)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.Confidence.EnforceGlobalMinimumConfidence = updatedState)" OptionHelp="@T("When enabled, you can enforce a minimum confidence level for all features in AI Studio. This way, you can make sure only trustworthy providers are used.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.Confidence, x => x.EnforceGlobalMinimumConfidence, out var meta) && meta.IsLocked"/>
|
||||
@if(this.SettingsManager.ConfigurationData.Confidence.EnforceGlobalMinimumConfidence)
|
||||
{
|
||||
<ConfigurationMinConfidenceSelection RestrictToGlobalMinimumConfidence="@false" SelectedValue="@(() => this.SettingsManager.ConfigurationData.Confidence.GlobalMinimumConfidence)" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.Confidence.GlobalMinimumConfidence = selectedValue)" IsLocked="() => ManagedConfiguration.TryGet(x => x.Confidence, x => x.GlobalMinimumConfidence, out var meta) && meta.IsLocked"/>
|
||||
}
|
||||
|
||||
<ConfigurationOption OptionDescription="@T("Show provider's confidence level?")" LabelOn="@T("Yes, show me the confidence level")" LabelOff="@T("No, please hide the confidence level")" State="@(() => this.SettingsManager.ConfigurationData.Confidence.ShowProviderConfidence)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.Confidence.ShowProviderConfidence = updatedState)" OptionHelp="@T("When enabled, we show you the confidence level for the selected provider in the app. This helps you assess where you are sending your data at any time. Example: are you currently working with sensitive data? Then choose a particularly trustworthy provider, etc.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.Confidence, x => x.ShowProviderConfidence, out var meta) && meta.IsLocked"/>
|
||||
@if (this.SettingsManager.ConfigurationData.Confidence.ShowProviderConfidence)
|
||||
{
|
||||
<ConfigurationSelect OptionDescription="@T("Select a confidence scheme")" SelectedValue="@(() => this.SettingsManager.ConfigurationData.Confidence.ConfidenceScheme)" Data="@ConfigurationSelectDataFactory.GetConfidenceSchemesData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.Confidence.ConfidenceScheme = selectedValue)" OptionHelp="@T("Choose the scheme that best suits you and your organization. Do you trust any western provider? Or only providers from the USA or exclusively European providers? Then choose the appropriate scheme. Alternatively, you can assign the confidence levels to each provider yourself.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.Confidence, x => x.ConfidenceScheme, out var meta) && meta.IsLocked"/>
|
||||
@if (this.SettingsManager.ConfigurationData.Confidence.ConfidenceScheme is ConfidenceSchemes.CUSTOM)
|
||||
{
|
||||
<MudTable Items="@(Enum.GetValues<LLMProviders>().Where(x => x is not LLMProviders.NONE))" Hover="@true" Class="border-dashed border rounded-lg">
|
||||
<ColGroup>
|
||||
<col style="width: 12em;"/>
|
||||
<col/>
|
||||
<col style="width: 22em;"/>
|
||||
</ColGroup>
|
||||
<HeaderContent>
|
||||
<MudTh>@T("Provider")</MudTh>
|
||||
<MudTh>@T("Description")</MudTh>
|
||||
<MudTh>@T("Confidence Level")</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd Style="vertical-align: top;">
|
||||
@context.ToName()
|
||||
</MudTd>
|
||||
<MudTd>
|
||||
<MudMarkdown Value="@context.GetConfidence(this.SettingsManager).Description" MarkdownPipeline="Markdown.SAFE_MARKDOWN_PIPELINE"/>
|
||||
</MudTd>
|
||||
<MudTd Style="vertical-align: top;">
|
||||
<MudMenu StartIcon="@Icons.Material.Filled.Security" EndIcon="@Icons.Material.Filled.KeyboardArrowDown" Label="@this.GetCurrentConfidenceLevelName(context)" Variant="Variant.Filled" Style="@this.SetCurrentConfidenceLevelColorStyle(context)" Disabled="@this.IsCustomConfidenceSchemeLocked()">
|
||||
@foreach (var confidenceLevel in Enum.GetValues<ConfidenceLevel>().OrderBy(n => n))
|
||||
{
|
||||
if(confidenceLevel is ConfidenceLevel.NONE or ConfidenceLevel.UNKNOWN)
|
||||
continue;
|
||||
|
||||
<MudMenuItem OnClick="@(async () => await this.ChangeCustomConfidenceLevel(context, confidenceLevel))">
|
||||
@confidenceLevel.GetName()
|
||||
</MudMenuItem>
|
||||
}
|
||||
</MudMenu>
|
||||
</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
}
|
||||
}
|
||||
</ExpansionPanel>
|
||||
@ -0,0 +1,38 @@
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Settings;
|
||||
|
||||
namespace AIStudio.Components.Settings;
|
||||
|
||||
public partial class SettingsPanelConfidence : SettingsPanelBase
|
||||
{
|
||||
private string GetCurrentConfidenceLevelName(LLMProviders llmProvider)
|
||||
{
|
||||
if (this.SettingsManager.ConfigurationData.Confidence.CustomConfidenceScheme.TryGetValue(llmProvider, out var level))
|
||||
return level.GetName();
|
||||
|
||||
return T("Not yet configured");
|
||||
}
|
||||
|
||||
private string SetCurrentConfidenceLevelColorStyle(LLMProviders llmProvider)
|
||||
{
|
||||
if (this.SettingsManager.ConfigurationData.Confidence.CustomConfidenceScheme.TryGetValue(llmProvider, out var level))
|
||||
return $"background-color: {level.GetColor(this.SettingsManager)};";
|
||||
|
||||
return $"background-color: {ConfidenceLevel.UNKNOWN.GetColor(this.SettingsManager)};";
|
||||
}
|
||||
|
||||
private bool IsCustomConfidenceSchemeLocked()
|
||||
{
|
||||
return ManagedConfiguration.TryGet(x => x.Confidence, x => x.CustomConfidenceScheme, out var meta) && meta.IsLocked;
|
||||
}
|
||||
|
||||
private async Task ChangeCustomConfidenceLevel(LLMProviders llmProvider, ConfidenceLevel level)
|
||||
{
|
||||
if (this.IsCustomConfidenceSchemeLocked())
|
||||
return;
|
||||
|
||||
this.SettingsManager.ConfigurationData.Confidence.CustomConfidenceScheme[llmProvider] = level;
|
||||
await this.SettingsManager.StoreSettings();
|
||||
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
@using AIStudio.Provider
|
||||
@using AIStudio.Settings
|
||||
@using AIStudio.Settings.DataModel
|
||||
@inherits SettingsPanelProviderBase
|
||||
|
||||
@ -39,6 +40,12 @@
|
||||
|
||||
<MudTd>
|
||||
<MudStack Row="true" Class="mb-2 mt-2" Spacing="1" Wrap="Wrap.Wrap">
|
||||
@if (context.IsTrustedByConfiguration(this.SettingsManager))
|
||||
{
|
||||
<MudTooltip Text="@T("This embedding provider is trusted by your organization for data source security checks. Local data can be sent to it without security warnings.")">
|
||||
<MudIconButton Color="Color.Success" Icon="@Icons.Material.Filled.VerifiedUser" Disabled="true"/>
|
||||
</MudTooltip>
|
||||
}
|
||||
@if (context.IsEnterpriseConfiguration)
|
||||
{
|
||||
<MudTooltip Text="@T("This embedding provider is managed by your organization.")">
|
||||
|
||||
@ -31,6 +31,12 @@
|
||||
<MudTd>@this.GetLLMProviderModelName(context)</MudTd>
|
||||
<MudTd>
|
||||
<MudStack Row="true" Class="mb-2 mt-2" Spacing="1" Wrap="Wrap.Wrap">
|
||||
@if (context.IsTrustedByConfiguration(this.SettingsManager))
|
||||
{
|
||||
<MudTooltip Text="@T("This provider is trusted by your organization for data source security checks.")">
|
||||
<MudIconButton Color="Color.Success" Icon="@Icons.Material.Filled.VerifiedUser" Disabled="true"/>
|
||||
</MudTooltip>
|
||||
}
|
||||
@if (context.IsEnterpriseConfiguration)
|
||||
{
|
||||
<MudTooltip Text="@T("This provider is managed by your organization.")">
|
||||
@ -68,59 +74,4 @@
|
||||
}
|
||||
|
||||
<LockableButton Text="@T("Add Provider")" IsLocked="@(() => !this.SettingsManager.ConfigurationData.App.AllowUserToAddProvider)" Icon="@Icons.Material.Filled.AddRoad" OnClickAsync="@this.AddLLMProvider" Class="mt-3" />
|
||||
|
||||
<MudText Typo="Typo.h4" Class="mb-3">
|
||||
@T("LLM Provider Confidence")
|
||||
</MudText>
|
||||
<MudJustifiedText Class="mb-3">
|
||||
@T("Do you want to always be able to recognize how trustworthy your LLM providers are? This way, you keep control over which provider you send your data to. You have two options for this: Either you choose a common schema, or you configure the trust levels for each LLM provider yourself.")
|
||||
</MudJustifiedText>
|
||||
|
||||
<ConfigurationOption OptionDescription="@T("Do you want to enforce an app-wide minimum confidence level?")" LabelOn="@T("Yes, enforce a minimum confidence level")" LabelOff="@T("No, do not enforce a minimum confidence level")" State="@(() => this.SettingsManager.ConfigurationData.LLMProviders.EnforceGlobalMinimumConfidence)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.LLMProviders.EnforceGlobalMinimumConfidence = updatedState)" OptionHelp="@T("When enabled, you can enforce a minimum confidence level for all LLM providers. This way, you can ensure that only trustworthy providers are used.")"/>
|
||||
@if(this.SettingsManager.ConfigurationData.LLMProviders.EnforceGlobalMinimumConfidence)
|
||||
{
|
||||
<ConfigurationMinConfidenceSelection RestrictToGlobalMinimumConfidence="@false" SelectedValue="@(() => this.SettingsManager.ConfigurationData.LLMProviders.GlobalMinimumConfidence)" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.LLMProviders.GlobalMinimumConfidence = selectedValue)"/>
|
||||
}
|
||||
|
||||
<ConfigurationOption OptionDescription="@T("Show provider's confidence level?")" LabelOn="@T("Yes, show me the confidence level")" LabelOff="@T("No, please hide the confidence level")" State="@(() => this.SettingsManager.ConfigurationData.LLMProviders.ShowProviderConfidence)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.LLMProviders.ShowProviderConfidence = updatedState)" OptionHelp="@T("When enabled, we show you the confidence level for the selected provider in the app. This helps you assess where you are sending your data at any time. Example: are you currently working with sensitive data? Then choose a particularly trustworthy provider, etc.")"/>
|
||||
@if (this.SettingsManager.ConfigurationData.LLMProviders.ShowProviderConfidence)
|
||||
{
|
||||
<ConfigurationSelect OptionDescription="@T("Select a confidence scheme")" SelectedValue="@(() => this.SettingsManager.ConfigurationData.LLMProviders.ConfidenceScheme)" Data="@ConfigurationSelectDataFactory.GetConfidenceSchemesData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.LLMProviders.ConfidenceScheme = selectedValue)" OptionHelp="@T("Choose the scheme that best suits you and your life. Do you trust any western provider? Or only providers from the USA or exclusively European providers? Then choose the appropriate scheme. Alternatively, you can assign the confidence levels to each provider yourself.")"/>
|
||||
@if (this.SettingsManager.ConfigurationData.LLMProviders.ConfidenceScheme is ConfidenceSchemes.CUSTOM)
|
||||
{
|
||||
<MudTable Items="@(Enum.GetValues<LLMProviders>().Where(x => x is not LLMProviders.NONE))" Hover="@true" Class="border-dashed border rounded-lg">
|
||||
<ColGroup>
|
||||
<col style="width: 12em;"/>
|
||||
<col/>
|
||||
<col style="width: 22em;"/>
|
||||
</ColGroup>
|
||||
<HeaderContent>
|
||||
<MudTh>@T("LLM Provider")</MudTh>
|
||||
<MudTh>@T("Description")</MudTh>
|
||||
<MudTh>@T("Confidence Level")</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd Style="vertical-align: top;">
|
||||
@context.ToName()
|
||||
</MudTd>
|
||||
<MudTd>
|
||||
<MudMarkdown Value="@context.GetConfidence(this.SettingsManager).Description" MarkdownPipeline="Markdown.SAFE_MARKDOWN_PIPELINE"/>
|
||||
</MudTd>
|
||||
<MudTd Style="vertical-align: top;">
|
||||
<MudMenu StartIcon="@Icons.Material.Filled.Security" EndIcon="@Icons.Material.Filled.KeyboardArrowDown" Label="@this.GetCurrentConfidenceLevelName(context)" Variant="Variant.Filled" Style="@this.SetCurrentConfidenceLevelColorStyle(context)">
|
||||
@foreach (var confidenceLevel in Enum.GetValues<ConfidenceLevel>().OrderBy(n => n))
|
||||
{
|
||||
if(confidenceLevel is ConfidenceLevel.NONE or ConfidenceLevel.UNKNOWN)
|
||||
continue;
|
||||
|
||||
<MudMenuItem OnClick="@(async () => await this.ChangeCustomConfidenceLevel(context, confidenceLevel))">
|
||||
@confidenceLevel.GetName()
|
||||
</MudMenuItem>
|
||||
}
|
||||
</MudMenu>
|
||||
</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
}
|
||||
}
|
||||
</ExpansionPanel>
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
using AIStudio.Dialogs;
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Settings;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
@ -166,25 +165,4 @@ public partial class SettingsPanelProviders : SettingsPanelProviderBase
|
||||
await this.AvailableLLMProvidersChanged.InvokeAsync(this.AvailableLLMProviders);
|
||||
}
|
||||
|
||||
private string GetCurrentConfidenceLevelName(LLMProviders llmProvider)
|
||||
{
|
||||
if (this.SettingsManager.ConfigurationData.LLMProviders.CustomConfidenceScheme.TryGetValue(llmProvider, out var level))
|
||||
return level.GetName();
|
||||
|
||||
return T("Not yet configured");
|
||||
}
|
||||
|
||||
private string SetCurrentConfidenceLevelColorStyle(LLMProviders llmProvider)
|
||||
{
|
||||
if (this.SettingsManager.ConfigurationData.LLMProviders.CustomConfidenceScheme.TryGetValue(llmProvider, out var level))
|
||||
return $"background-color: {level.GetColor(this.SettingsManager)};";
|
||||
|
||||
return $"background-color: {ConfidenceLevel.UNKNOWN.GetColor(this.SettingsManager)};";
|
||||
}
|
||||
|
||||
private async Task ChangeCustomConfidenceLevel(LLMProviders llmProvider, ConfidenceLevel level)
|
||||
{
|
||||
this.SettingsManager.ConfigurationData.LLMProviders.CustomConfidenceScheme[llmProvider] = level;
|
||||
await this.SettingsManager.StoreSettings();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
@using AIStudio.Provider
|
||||
@using AIStudio.Settings
|
||||
@using AIStudio.Settings.DataModel
|
||||
@inherits SettingsPanelProviderBase
|
||||
|
||||
@ -35,6 +36,12 @@
|
||||
|
||||
<MudTd>
|
||||
<MudStack Row="true" Class="mb-2 mt-2" Spacing="1" Wrap="Wrap.Wrap">
|
||||
@if (context.IsTrustedByConfiguration(this.SettingsManager))
|
||||
{
|
||||
<MudTooltip Text="@T("This transcription provider is trusted by your organization for data source security checks.")">
|
||||
<MudIconButton Color="Color.Success" Icon="@Icons.Material.Filled.VerifiedUser" Disabled="true"/>
|
||||
</MudTooltip>
|
||||
}
|
||||
@if (context.IsEnterpriseConfiguration)
|
||||
{
|
||||
<MudTooltip Text="@T("This transcription provider is managed by your organization.")">
|
||||
|
||||
@ -11,6 +11,36 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
@if (this.SearchVisible)
|
||||
{
|
||||
<MudStack Class="mx-3 mt-2 mb-1" Spacing="1" Style="position: sticky; top: 0; z-index: 2; background-color: var(--mud-palette-background);">
|
||||
<MudStack Row="@true" AlignItems="AlignItems.Center" Wrap="Wrap.NoWrap" Spacing="1">
|
||||
<MudTextField T="string"
|
||||
Text="@this.searchText"
|
||||
TextChanged="@this.OnSearchTextChanged"
|
||||
Placeholder="@T("Search chats")"
|
||||
Variant="Variant.Outlined"
|
||||
Margin="Margin.Dense"
|
||||
Immediate="@true"
|
||||
Adornment="Adornment.Start"
|
||||
AdornmentIcon="@Icons.Material.Filled.Search"/>
|
||||
<MudTooltip Text="@T("Clear search")" Placement="@WORKSPACE_ITEM_TOOLTIP_PLACEMENT">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Clear" Size="Size.Medium" Color="Color.Inherit" Disabled="@(string.IsNullOrWhiteSpace(this.searchText))" OnClick="@this.ClearSearchAsync"/>
|
||||
</MudTooltip>
|
||||
</MudStack>
|
||||
|
||||
<MudStack Row="@true" AlignItems="AlignItems.Center" Wrap="Wrap.NoWrap" Spacing="1">
|
||||
<MudSwitch T="bool" Value="@this.includeThreadContents" ValueChanged="@this.IncludeThreadContentsChanged" Color="Color.Primary">
|
||||
@T("Search chat contents")
|
||||
</MudSwitch>
|
||||
@if (this.isSearchRunning)
|
||||
{
|
||||
<MudProgressCircular Size="Size.Small" Indeterminate="@true"/>
|
||||
}
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
}
|
||||
|
||||
<MudTreeView T="ITreeItem" Items="@this.treeItems" SelectionMode="SelectionMode.SingleSelection" Hover="@true" ExpandOnClick="@true" Class="ma-3">
|
||||
<ItemTemplate Context="item">
|
||||
@switch (item.Value)
|
||||
@ -35,7 +65,7 @@ else
|
||||
<MudTreeViewItem T="ITreeItem" Icon="@this.GetTreeItemIcon(treeItem)" Value="@item.Value" Expanded="@item.Expanded" CanExpand="@treeItem.Expandable" Items="@(treeItem.Children!)" OnClick="@(() => this.LoadChatAsync(treeItem.Path, true))">
|
||||
<BodyContent>
|
||||
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%">
|
||||
<MudText Style="justify-self: start;">
|
||||
<MudText Style="@this.GetChatTreeItemTextStyle(treeItem)">
|
||||
@if (string.IsNullOrWhiteSpace(treeItem.Text))
|
||||
{
|
||||
@T("Empty chat")
|
||||
@ -71,15 +101,22 @@ else
|
||||
<MudText Style="justify-self: start;">
|
||||
@treeItem.Text
|
||||
</MudText>
|
||||
<div style="justify-self: end;">
|
||||
<MudTooltip Text="@T("Rename")" Placement="@WORKSPACE_ITEM_TOOLTIP_PLACEMENT">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Edit" Size="Size.Medium" Color="Color.Inherit" OnClick="@(() => this.RenameWorkspaceAsync(treeItem.Path))"/>
|
||||
</MudTooltip>
|
||||
@if (!this.HasSearchQuery)
|
||||
{
|
||||
<div style="justify-self: end;">
|
||||
<MudTooltip Text="@this.GetAddChatToWorkspaceTooltip(treeItem.Text)" Placement="@WORKSPACE_ITEM_TOOLTIP_PLACEMENT">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.AddComment" Size="Size.Medium" Color="Color.Inherit" OnClick="@(() => this.AddChatAsync(treeItem.Path))"/>
|
||||
</MudTooltip>
|
||||
|
||||
<MudTooltip Text="@T("Delete")" Placement="@WORKSPACE_ITEM_TOOLTIP_PLACEMENT">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Delete" Size="Size.Medium" Color="Color.Error" OnClick="@(() => this.DeleteWorkspaceAsync(treeItem.Path))"/>
|
||||
</MudTooltip>
|
||||
</div>
|
||||
<MudTooltip Text="@T("Rename")" Placement="@WORKSPACE_ITEM_TOOLTIP_PLACEMENT">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Edit" Size="Size.Medium" Color="Color.Inherit" OnClick="@(() => this.RenameWorkspaceAsync(treeItem.Path))"/>
|
||||
</MudTooltip>
|
||||
|
||||
<MudTooltip Text="@T("Delete")" Placement="@WORKSPACE_ITEM_TOOLTIP_PLACEMENT">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Delete" Size="Size.Medium" Color="Color.Error" OnClick="@(() => this.DeleteWorkspaceAsync(treeItem.Path))"/>
|
||||
</MudTooltip>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</BodyContent>
|
||||
</MudTreeViewItem>
|
||||
|
||||
@ -3,7 +3,6 @@ using System.Text.Json;
|
||||
|
||||
using AIStudio.Chat;
|
||||
using AIStudio.Dialogs;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Tools.AIJobs;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
@ -32,21 +31,32 @@ public partial class Workspaces : MSGComponentBase
|
||||
[Parameter]
|
||||
public bool ExpandRootNodes { get; set; } = true;
|
||||
|
||||
[Parameter]
|
||||
public bool SearchVisible { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<bool> SearchVisibleChanged { get; set; }
|
||||
|
||||
private const Placement WORKSPACE_ITEM_TOOLTIP_PLACEMENT = Placement.Bottom;
|
||||
private readonly SemaphoreSlim treeLoadingSemaphore = new(1, 1);
|
||||
private readonly List<TreeItemData<ITreeItem>> treeItems = [];
|
||||
private readonly HashSet<Guid> loadingWorkspaceChatLists = [];
|
||||
|
||||
private CancellationTokenSource? prefetchCancellationTokenSource;
|
||||
private CancellationTokenSource? searchCancellationTokenSource;
|
||||
private bool isInitialLoading = true;
|
||||
private bool isDisposed;
|
||||
private bool includeThreadContents;
|
||||
private bool isSearchRunning;
|
||||
private string searchText = string.Empty;
|
||||
private long searchRevision;
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
this.ApplyFilters([], [ Event.AI_JOB_CHANGED, Event.AI_JOB_FINISHED, Event.CHAT_GENERATION_CHANGED ]);
|
||||
this.ApplyFilters([], [ Event.AI_JOB_CHANGED, Event.AI_JOB_FINISHED, Event.CHAT_GENERATION_CHANGED, Event.WORKSPACE_CREATED ]);
|
||||
_ = this.LoadTreeItemsAsync(startPrefetch: true);
|
||||
}
|
||||
|
||||
@ -54,6 +64,7 @@ public partial class Workspaces : MSGComponentBase
|
||||
|
||||
private async Task LoadTreeItemsAsync(bool startPrefetch = true, bool forceReload = false)
|
||||
{
|
||||
var shouldRunSearch = false;
|
||||
await this.treeLoadingSemaphore.WaitAsync();
|
||||
try
|
||||
{
|
||||
@ -64,7 +75,11 @@ public partial class Workspaces : MSGComponentBase
|
||||
await WorkspaceBehaviour.ForceReloadWorkspaceTreeAsync();
|
||||
|
||||
var snapshot = await WorkspaceBehaviour.GetOrLoadWorkspaceTreeShellAsync();
|
||||
this.BuildTreeItems(snapshot);
|
||||
if (this.HasSearchQuery)
|
||||
shouldRunSearch = true;
|
||||
else
|
||||
this.BuildTreeItems(snapshot);
|
||||
|
||||
this.isInitialLoading = false;
|
||||
}
|
||||
finally
|
||||
@ -72,12 +87,40 @@ public partial class Workspaces : MSGComponentBase
|
||||
this.treeLoadingSemaphore.Release();
|
||||
}
|
||||
|
||||
await this.SafeStateHasChanged();
|
||||
if (shouldRunSearch)
|
||||
await this.SearchWorkspaceItemsAsync();
|
||||
else
|
||||
await this.SafeStateHasChanged();
|
||||
|
||||
if (startPrefetch)
|
||||
await this.StartPrefetchAsync();
|
||||
}
|
||||
|
||||
private bool HasSearchQuery => this.SearchVisible && !string.IsNullOrWhiteSpace(this.searchText);
|
||||
|
||||
private string GetAddChatToWorkspaceTooltip(string workspaceName) => string.Format(T("Start a new chat in workspace '{0}'"), workspaceName);
|
||||
|
||||
private async Task<Func<string?, string?>> CreateWorkspaceNameValidationAsync(Guid excludedWorkspaceId = default, string? originalWorkspaceName = null)
|
||||
{
|
||||
var snapshot = await WorkspaceBehaviour.GetOrLoadWorkspaceTreeShellAsync();
|
||||
return workspaceName =>
|
||||
{
|
||||
var normalizedWorkspaceName = WorkspaceBehaviour.NormalizeWorkspaceName(workspaceName ?? string.Empty);
|
||||
if (string.IsNullOrWhiteSpace(normalizedWorkspaceName))
|
||||
return null;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(originalWorkspaceName) &&
|
||||
string.Equals(WorkspaceBehaviour.NormalizeWorkspaceName(originalWorkspaceName), normalizedWorkspaceName, StringComparison.OrdinalIgnoreCase))
|
||||
return null;
|
||||
|
||||
var nameExists = snapshot.Workspaces.Any(workspace =>
|
||||
workspace.WorkspaceId != excludedWorkspaceId &&
|
||||
string.Equals(WorkspaceBehaviour.NormalizeWorkspaceName(workspace.Name), normalizedWorkspaceName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
return nameExists ? T("There is already a workspace with this name. Please choose a different name.") : null;
|
||||
};
|
||||
}
|
||||
|
||||
private void BuildTreeItems(WorkspaceTreeCacheSnapshot snapshot)
|
||||
{
|
||||
this.treeItems.Clear();
|
||||
@ -219,6 +262,109 @@ public partial class Workspaces : MSGComponentBase
|
||||
};
|
||||
}
|
||||
|
||||
private void BuildSearchTreeItems(WorkspaceSearchSnapshot snapshot)
|
||||
{
|
||||
this.treeItems.Clear();
|
||||
|
||||
if (snapshot.Workspaces.Count == 0 && snapshot.TemporaryChats.Count == 0)
|
||||
{
|
||||
this.treeItems.Add(new TreeItemData<ITreeItem>
|
||||
{
|
||||
Expandable = false,
|
||||
Value = new TreeItemData
|
||||
{
|
||||
Depth = 0,
|
||||
Branch = WorkspaceBranch.NONE,
|
||||
Text = T("No chats found"),
|
||||
Icon = Icons.Material.Filled.Search,
|
||||
Expandable = false,
|
||||
Path = "search_empty",
|
||||
},
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (snapshot.Workspaces.Count > 0)
|
||||
{
|
||||
var workspaceChildren = new List<TreeItemData<ITreeItem>>();
|
||||
foreach (var workspace in snapshot.Workspaces)
|
||||
workspaceChildren.Add(this.CreateSearchWorkspaceTreeItem(workspace));
|
||||
|
||||
this.treeItems.Add(new TreeItemData<ITreeItem>
|
||||
{
|
||||
Expanded = true,
|
||||
Expandable = true,
|
||||
Value = new TreeItemData
|
||||
{
|
||||
Depth = 0,
|
||||
Branch = WorkspaceBranch.WORKSPACES,
|
||||
Text = T("Workspaces"),
|
||||
Icon = Icons.Material.Filled.Folder,
|
||||
Expandable = true,
|
||||
Path = "search_workspaces",
|
||||
Children = workspaceChildren,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (snapshot.Workspaces.Count > 0 && snapshot.TemporaryChats.Count > 0)
|
||||
{
|
||||
this.treeItems.Add(new TreeItemData<ITreeItem>
|
||||
{
|
||||
Expandable = false,
|
||||
Value = new TreeDivider(),
|
||||
});
|
||||
}
|
||||
|
||||
if (snapshot.TemporaryChats.Count > 0)
|
||||
{
|
||||
var temporaryChatsChildren = new List<TreeItemData<ITreeItem>>();
|
||||
foreach (var temporaryChat in snapshot.TemporaryChats)
|
||||
temporaryChatsChildren.Add(this.CreateChatTreeItem(temporaryChat.Chat, WorkspaceBranch.TEMPORARY_CHATS, depth: 1, icon: Icons.Material.Filled.Timer));
|
||||
|
||||
this.treeItems.Add(new TreeItemData<ITreeItem>
|
||||
{
|
||||
Expanded = true,
|
||||
Expandable = true,
|
||||
Value = new TreeItemData
|
||||
{
|
||||
Depth = 0,
|
||||
Branch = WorkspaceBranch.TEMPORARY_CHATS,
|
||||
Text = T("Disappearing Chats"),
|
||||
Icon = Icons.Material.Filled.Timer,
|
||||
Expandable = true,
|
||||
Path = "search_temp",
|
||||
Children = temporaryChatsChildren,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private TreeItemData<ITreeItem> CreateSearchWorkspaceTreeItem(WorkspaceSearchWorkspace workspace)
|
||||
{
|
||||
var children = new List<TreeItemData<ITreeItem>>();
|
||||
foreach (var chat in workspace.Chats)
|
||||
children.Add(this.CreateChatTreeItem(chat.Chat, WorkspaceBranch.WORKSPACES, depth: 2, icon: Icons.Material.Filled.Chat));
|
||||
|
||||
return new TreeItemData<ITreeItem>
|
||||
{
|
||||
Expanded = true,
|
||||
Expandable = true,
|
||||
Value = new TreeItemData
|
||||
{
|
||||
Type = TreeItemType.WORKSPACE,
|
||||
Depth = 1,
|
||||
Branch = WorkspaceBranch.WORKSPACES,
|
||||
Text = workspace.Name,
|
||||
Icon = Icons.Material.Filled.Description,
|
||||
Expandable = true,
|
||||
Path = workspace.WorkspacePath,
|
||||
Children = children,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private string GetTreeItemIcon(TreeItemData treeItem)
|
||||
{
|
||||
if (treeItem.Type is not TreeItemType.CHAT)
|
||||
@ -233,6 +379,19 @@ public partial class Workspaces : MSGComponentBase
|
||||
return treeItem.Type is TreeItemType.CHAT && this.AIJobService.IsChatGenerationActive(treeItem.ChatId);
|
||||
}
|
||||
|
||||
private string GetChatTreeItemTextStyle(TreeItemData treeItem)
|
||||
{
|
||||
return this.IsCurrentChatTreeItem(treeItem) ? "justify-self: start; font-weight: 700;" : "justify-self: start;";
|
||||
}
|
||||
|
||||
private bool IsCurrentChatTreeItem(TreeItemData treeItem)
|
||||
{
|
||||
return treeItem.Type is TreeItemType.CHAT
|
||||
&& this.CurrentChatThread is not null
|
||||
&& treeItem.ChatId == this.CurrentChatThread.ChatId
|
||||
&& treeItem.WorkspaceId == this.CurrentChatThread.WorkspaceId;
|
||||
}
|
||||
|
||||
private string GetChatTreeIcon(Guid chatId, string defaultIcon)
|
||||
{
|
||||
var snapshot = this.AIJobService.TryGetChatSnapshot(chatId);
|
||||
@ -289,6 +448,106 @@ public partial class Workspaces : MSGComponentBase
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ToggleSearchAsync()
|
||||
{
|
||||
var searchVisible = !this.SearchVisible;
|
||||
this.SearchVisible = searchVisible;
|
||||
await this.SearchVisibleChanged.InvokeAsync(searchVisible);
|
||||
|
||||
if (this.SearchVisible)
|
||||
{
|
||||
await this.SafeStateHasChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
await this.CancelSearchAsync();
|
||||
this.searchText = string.Empty;
|
||||
this.isSearchRunning = false;
|
||||
await this.LoadTreeItemsAsync(startPrefetch: false);
|
||||
}
|
||||
|
||||
private async Task CancelSearchAsync()
|
||||
{
|
||||
this.searchRevision++;
|
||||
if (this.searchCancellationTokenSource is not null)
|
||||
{
|
||||
await this.searchCancellationTokenSource.CancelAsync();
|
||||
this.searchCancellationTokenSource.Dispose();
|
||||
this.searchCancellationTokenSource = null;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnSearchTextChanged(string value)
|
||||
{
|
||||
this.searchText = value;
|
||||
if (string.IsNullOrWhiteSpace(this.searchText))
|
||||
{
|
||||
await this.CancelSearchAsync();
|
||||
this.isSearchRunning = false;
|
||||
await this.LoadTreeItemsAsync(startPrefetch: false);
|
||||
return;
|
||||
}
|
||||
|
||||
await this.SearchWorkspaceItemsAsync();
|
||||
}
|
||||
|
||||
private async Task IncludeThreadContentsChanged(bool value)
|
||||
{
|
||||
this.includeThreadContents = value;
|
||||
if (this.HasSearchQuery)
|
||||
await this.SearchWorkspaceItemsAsync();
|
||||
}
|
||||
|
||||
private async Task ClearSearchAsync()
|
||||
{
|
||||
this.searchText = string.Empty;
|
||||
await this.CancelSearchAsync();
|
||||
this.isSearchRunning = false;
|
||||
await this.LoadTreeItemsAsync(startPrefetch: false);
|
||||
}
|
||||
|
||||
private async Task SearchWorkspaceItemsAsync()
|
||||
{
|
||||
await this.CancelSearchAsync();
|
||||
|
||||
var text = this.searchText;
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
return;
|
||||
|
||||
this.searchCancellationTokenSource = new CancellationTokenSource();
|
||||
var token = this.searchCancellationTokenSource.Token;
|
||||
var revision = ++this.searchRevision;
|
||||
|
||||
this.isSearchRunning = true;
|
||||
await this.SafeStateHasChanged();
|
||||
|
||||
try
|
||||
{
|
||||
var snapshot = await WorkspaceBehaviour.SearchWorkspaceChatsAsync(text, this.includeThreadContents, token);
|
||||
if (this.isDisposed || token.IsCancellationRequested || revision != this.searchRevision)
|
||||
return;
|
||||
|
||||
this.BuildSearchTreeItems(snapshot);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// Expected when the user keeps typing or hides the search row.
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogWarning(ex, "Failed while searching workspace chats.");
|
||||
this.BuildSearchTreeItems(new([], []));
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (revision == this.searchRevision)
|
||||
{
|
||||
this.isSearchRunning = false;
|
||||
await this.SafeStateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnWorkspaceClicked(TreeItemData treeItem)
|
||||
{
|
||||
if (treeItem.Type is not TreeItemType.WORKSPACE)
|
||||
@ -494,6 +753,7 @@ public partial class Workspaces : MSGComponentBase
|
||||
{ x => x.ConfirmColor, Color.Info },
|
||||
{ x => x.AllowEmptyInput, false },
|
||||
{ x => x.EmptyInputErrorMessage, T("Please enter a workspace name.") },
|
||||
{ x => x.AdditionalValidation, await this.CreateWorkspaceNameValidationAsync(workspaceId, workspaceName) },
|
||||
};
|
||||
|
||||
var dialogReference = await this.DialogService.ShowAsync<SingleInputDialog>(T("Rename Workspace"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||
@ -502,9 +762,10 @@ public partial class Workspaces : MSGComponentBase
|
||||
return;
|
||||
|
||||
var alteredWorkspaceName = (dialogResult.Data as string)!;
|
||||
var workspaceNamePath = Path.Join(workspacePath, "name");
|
||||
await File.WriteAllTextAsync(workspaceNamePath, alteredWorkspaceName, Encoding.UTF8);
|
||||
await WorkspaceBehaviour.UpdateWorkspaceNameInCacheAsync(workspaceId, alteredWorkspaceName);
|
||||
if (!await WorkspaceBehaviour.RenameWorkspaceAsync(workspaceId, alteredWorkspaceName))
|
||||
return;
|
||||
|
||||
await this.SendMessage(Event.WORKSPACE_RENAMED, workspaceId);
|
||||
await this.LoadTreeItemsAsync(startPrefetch: false);
|
||||
}
|
||||
|
||||
@ -519,6 +780,7 @@ public partial class Workspaces : MSGComponentBase
|
||||
{ x => x.ConfirmColor, Color.Info },
|
||||
{ x => x.AllowEmptyInput, false },
|
||||
{ x => x.EmptyInputErrorMessage, T("Please enter a workspace name.") },
|
||||
{ x => x.AdditionalValidation, await this.CreateWorkspaceNameValidationAsync() },
|
||||
};
|
||||
|
||||
var dialogReference = await this.DialogService.ShowAsync<SingleInputDialog>(T("Add Workspace"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||
@ -526,14 +788,10 @@ public partial class Workspaces : MSGComponentBase
|
||||
if (dialogResult is null || dialogResult.Canceled)
|
||||
return;
|
||||
|
||||
var workspaceId = Guid.NewGuid();
|
||||
var workspacePath = Path.Join(SettingsManager.DataDirectory, "workspaces", workspaceId.ToString());
|
||||
Directory.CreateDirectory(workspacePath);
|
||||
|
||||
var workspaceName = (dialogResult.Data as string)!;
|
||||
var workspaceNamePath = Path.Join(workspacePath, "name");
|
||||
await File.WriteAllTextAsync(workspaceNamePath, workspaceName, Encoding.UTF8);
|
||||
await WorkspaceBehaviour.AddWorkspaceToCacheAsync(workspaceId, workspacePath, workspaceName);
|
||||
var result = await WorkspaceBehaviour.TryCreateWorkspaceAsync(workspaceName);
|
||||
if (!result.Success)
|
||||
return;
|
||||
|
||||
await this.LoadTreeItemsAsync(startPrefetch: false);
|
||||
}
|
||||
@ -578,7 +836,7 @@ public partial class Workspaces : MSGComponentBase
|
||||
{ x => x.ConfirmText, T("Move chat") },
|
||||
};
|
||||
|
||||
var dialogReference = await this.DialogService.ShowAsync<WorkspaceSelectionDialog>(T("Move Chat to Workspace"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||
var dialogReference = await this.DialogService.ShowAsync<WorkspaceSelectionDialog>(T("Move Chat to Workspace"), dialogParameters, DialogOptions.FULLSCREEN_MANUAL_ESCAPE);
|
||||
var dialogResult = await dialogReference.Result;
|
||||
if (dialogResult is null || dialogResult.Canceled)
|
||||
return;
|
||||
@ -642,6 +900,10 @@ public partial class Workspaces : MSGComponentBase
|
||||
await this.ForceRefreshFromDiskAsync();
|
||||
break;
|
||||
|
||||
case Event.WORKSPACE_CREATED:
|
||||
await this.LoadTreeItemsAsync(startPrefetch: false);
|
||||
break;
|
||||
|
||||
case Event.AI_JOB_CHANGED:
|
||||
case Event.AI_JOB_FINISHED:
|
||||
case Event.CHAT_GENERATION_CHANGED:
|
||||
@ -656,9 +918,12 @@ public partial class Workspaces : MSGComponentBase
|
||||
this.prefetchCancellationTokenSource?.Cancel();
|
||||
this.prefetchCancellationTokenSource?.Dispose();
|
||||
this.prefetchCancellationTokenSource = null;
|
||||
this.searchCancellationTokenSource?.Cancel();
|
||||
this.searchCancellationTokenSource?.Dispose();
|
||||
this.searchCancellationTokenSource = null;
|
||||
|
||||
base.DisposeResources();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
<MudJustifiedText Class="mb-3" Typo="Typo.body1">
|
||||
@T("The name of the chat template is mandatory. Each chat template must have a unique name.")
|
||||
</MudJustifiedText>
|
||||
|
||||
|
||||
<MudForm @ref="@this.form" @bind-IsValid="@this.dataIsValid" @bind-Errors="@this.dataIssues">
|
||||
@* ReSharper disable once CSharpWarnings::CS8974 *@
|
||||
<MudTextField
|
||||
@ -26,9 +26,10 @@
|
||||
AdornmentColor="Color.Info"
|
||||
Validation="@this.ValidateName"
|
||||
Variant="Variant.Outlined"
|
||||
ReadOnly="@this.IsReadOnly"
|
||||
UserAttributes="@SPELLCHECK_ATTRIBUTES"
|
||||
/>
|
||||
|
||||
|
||||
<MudText Typo="Typo.h6" Class="mb-3 mt-3">
|
||||
@T("System Prompt")
|
||||
</MudText>
|
||||
@ -47,16 +48,17 @@
|
||||
Class="mb-3"
|
||||
UserAttributes="@SPELLCHECK_ATTRIBUTES"
|
||||
HelperText="@T("Tell the AI your system prompt.")"
|
||||
ReadOnly="@this.IsReadOnly"
|
||||
/>
|
||||
|
||||
|
||||
<MudJustifiedText Class="mb-3" Typo="Typo.body1">
|
||||
@T("Are you unsure which system prompt to use? You might start with the default system prompt that AI Studio uses for all chats.")
|
||||
</MudJustifiedText>
|
||||
<MudButton Class="mb-3" Color="Color.Default" OnClick="@this.UseDefaultSystemPrompt" StartIcon="@Icons.Material.Filled.ListAlt" Variant="Variant.Filled">
|
||||
<MudButton Class="mb-3" Color="Color.Default" OnClick="@this.UseDefaultSystemPrompt" StartIcon="@Icons.Material.Filled.ListAlt" Variant="Variant.Filled" Disabled="@this.IsReadOnly">
|
||||
@T("Use the default system prompt")
|
||||
</MudButton>
|
||||
<ReadFileContent Text="@T("Load system prompt from file")" @bind-FileContent="@this.DataSystemPrompt"/>
|
||||
|
||||
<ReadFileContent Text="@T("Load system prompt from file")" @bind-FileContent="@this.DataSystemPrompt" Disabled="@this.IsReadOnly"/>
|
||||
|
||||
<MudText Typo="Typo.h6" Class="mb-3 mt-6">
|
||||
@T("Predefined User Input")
|
||||
</MudText>
|
||||
@ -77,6 +79,7 @@
|
||||
Class="mb-3"
|
||||
UserAttributes="@SPELLCHECK_ATTRIBUTES"
|
||||
HelperText="@T("Tell the AI your predefined user input.")"
|
||||
ReadOnly="@this.IsReadOnly"
|
||||
/>
|
||||
|
||||
<MudText Typo="Typo.h6" Class="mb-3 mt-6">
|
||||
@ -92,6 +95,7 @@
|
||||
UseSmallForm="false"
|
||||
CatchAllDocuments="true"
|
||||
ValidateMediaFileTypes="false"
|
||||
Disabled="@this.IsReadOnly"
|
||||
/>
|
||||
|
||||
<MudText Typo="Typo.h6" Class="mb-3 mt-6">
|
||||
@ -100,8 +104,8 @@
|
||||
<MudJustifiedText Class="mb-3" Typo="Typo.body1">
|
||||
@T("Using some chat templates in tandem with profiles might cause issues. Therefore, you might prohibit the usage of profiles here.")
|
||||
</MudJustifiedText>
|
||||
<MudTextSwitch @bind-Value="@this.AllowProfileUsage" Color="Color.Primary" Label="@T("Allow the use of profiles together with this chat template?")" LabelOn="@T("Yes, allow profiles when using this template")" LabelOff="@T("No, prohibit profile use for this template")" />
|
||||
|
||||
<MudTextSwitch @bind-Value="@this.AllowProfileUsage" Color="Color.Primary" Label="@T("Allow the use of profiles together with this chat template?")" LabelOn="@T("Yes, allow profiles when using this template")" LabelOff="@T("No, prohibit profile use for this template")" Disabled="@this.IsReadOnly" />
|
||||
|
||||
<MudText Typo="Typo.h6" Class="mb-3 mt-6">
|
||||
@T("Example Conversation")
|
||||
</MudText>
|
||||
@ -129,18 +133,18 @@
|
||||
case ContentText textContent:
|
||||
<MudTextField AutoGrow="true" Value="@textContent.Text" Placeholder="@T("Enter a message")" ReadOnly="true" Variant="Variant.Text" Validation="@this.ValidateExampleTextMessage"/>
|
||||
break;
|
||||
|
||||
|
||||
case ContentImage { SourceType: ContentImageSource.URL or ContentImageSource.LOCAL_PATH } imageContent:
|
||||
<MudImage Src="@imageContent.Source" Alt="@T("Image content")" Fluid="true" />
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
@T("Unsupported content type")
|
||||
break;
|
||||
}
|
||||
</MudTd>
|
||||
<MudTd>
|
||||
@if (!this.isInlineEditOnGoing)
|
||||
@if (!this.isInlineEditOnGoing && !this.IsReadOnly)
|
||||
{
|
||||
<MudStack Row="true" Class="mb-2 mt-2" Wrap="Wrap.Wrap">
|
||||
<MudTooltip Text="@T("Add a new message below")">
|
||||
@ -153,22 +157,29 @@
|
||||
</RowTemplate>
|
||||
<RowEditingTemplate>
|
||||
<MudTd>
|
||||
<MudSelect Label="@T("Role")" @bind-Value="@context.Role" Required="true">
|
||||
@foreach (var role in ChatRoles.ChatTemplateRoles())
|
||||
{
|
||||
<MudSelectItem Value="@role">
|
||||
@role.ToChatTemplateName()
|
||||
</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
@if (this.IsReadOnly)
|
||||
{
|
||||
@context.Role.ToChatTemplateName()
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudSelect Label="@T("Role")" @bind-Value="@context.Role" Required="true">
|
||||
@foreach (var role in ChatRoles.ChatTemplateRoles())
|
||||
{
|
||||
<MudSelectItem Value="@role">
|
||||
@role.ToChatTemplateName()
|
||||
</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
}
|
||||
</MudTd>
|
||||
<MudTd>
|
||||
@switch(context.Content)
|
||||
{
|
||||
case ContentText textContent:
|
||||
<MudTextField AutoGrow="true" @bind-Value="@textContent.Text" Label="@T("The message")" Required="true" Immediate="true" Placeholder="@T("Enter a message")"/>
|
||||
<MudTextField AutoGrow="true" @bind-Value="@textContent.Text" Label="@T("The message")" Required="true" Immediate="true" Placeholder="@T("Enter a message")" ReadOnly="@this.IsReadOnly"/>
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
<MudText Typo="Typo.body2">
|
||||
@T("Only text content is supported in the editing mode yet.")
|
||||
@ -182,8 +193,8 @@
|
||||
</PagerContent>
|
||||
</MudTable>
|
||||
</MudForm>
|
||||
|
||||
@if (!this.isInlineEditOnGoing)
|
||||
|
||||
@if (!this.isInlineEditOnGoing && !this.IsReadOnly)
|
||||
{
|
||||
<MudButton Class="mb-6" Color="Color.Primary" OnClick="@this.AddMessageToEnd" StartIcon="@Icons.Material.Filled.Add" Variant="Variant.Filled">
|
||||
@T("Add a message")
|
||||
@ -193,22 +204,31 @@
|
||||
<Issues IssuesData="@this.dataIssues"/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<MudButton OnClick="@this.Cancel" Variant="Variant.Filled">
|
||||
@T("Cancel")
|
||||
</MudButton>
|
||||
|
||||
@if (!this.isInlineEditOnGoing)
|
||||
@if (this.IsReadOnly)
|
||||
{
|
||||
<MudButton OnClick="@this.Store" Variant="Variant.Filled" Color="Color.Primary">
|
||||
@if (this.IsEditing)
|
||||
{
|
||||
@T("Update")
|
||||
}
|
||||
else
|
||||
{
|
||||
@T("Add")
|
||||
}
|
||||
<MudButton OnClick="@this.Cancel" Variant="Variant.Filled">
|
||||
@T("Close")
|
||||
</MudButton>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudButton OnClick="@this.Cancel" Variant="Variant.Filled">
|
||||
@T("Cancel")
|
||||
</MudButton>
|
||||
|
||||
@if (!this.isInlineEditOnGoing)
|
||||
{
|
||||
<MudButton OnClick="@this.Store" Variant="Variant.Filled" Color="Color.Primary">
|
||||
@if (this.IsEditing)
|
||||
{
|
||||
@T("Update")
|
||||
}
|
||||
else
|
||||
{
|
||||
@T("Add")
|
||||
}
|
||||
</MudButton>
|
||||
}
|
||||
}
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
@ -16,37 +16,40 @@ public partial class ChatTemplateDialog : MSGComponentBase
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public uint DataNum { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The chat template's ID.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string DataId { get; set; } = Guid.NewGuid().ToString();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The chat template name chosen by the user.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string DataName { get; set; } = string.Empty;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// What is the system prompt?
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string DataSystemPrompt { get; set; } = string.Empty;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// What is the predefined user prompt?
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string PredefinedUserPrompt { get; set; } = string.Empty;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Should the dialog be in editing mode?
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool IsEditing { get; init; }
|
||||
|
||||
|
||||
[Parameter]
|
||||
public bool IsReadOnly { get; init; }
|
||||
|
||||
[Parameter]
|
||||
public IReadOnlyCollection<ContentBlock> ExampleConversation { get; init; } = [];
|
||||
|
||||
@ -55,23 +58,23 @@ public partial class ChatTemplateDialog : MSGComponentBase
|
||||
|
||||
[Parameter]
|
||||
public bool AllowProfileUsage { get; set; } = true;
|
||||
|
||||
[Parameter]
|
||||
|
||||
[Parameter]
|
||||
public bool CreateFromExistingChatThread { get; set; }
|
||||
|
||||
[Parameter]
|
||||
|
||||
[Parameter]
|
||||
public ChatThread? ExistingChatThread { get; set; }
|
||||
|
||||
|
||||
[Inject]
|
||||
private ILogger<ChatTemplateDialog> Logger { get; init; } = null!;
|
||||
|
||||
|
||||
private static readonly Dictionary<string, object?> SPELLCHECK_ATTRIBUTES = new();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of used chat template names. We need this to check for uniqueness.
|
||||
/// </summary>
|
||||
private List<string> UsedNames { get; set; } = [];
|
||||
|
||||
|
||||
private bool dataIsValid;
|
||||
private List<ContentBlock> dataExampleConversation = [];
|
||||
private HashSet<FileAttachment> fileAttachments = [];
|
||||
@ -80,20 +83,20 @@ public partial class ChatTemplateDialog : MSGComponentBase
|
||||
private bool isInlineEditOnGoing;
|
||||
|
||||
private ContentBlock? messageEntryBeforeEdit;
|
||||
|
||||
|
||||
// We get the form reference from Blazor code to validate it manually:
|
||||
private MudForm form = null!;
|
||||
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
// Configure the spellchecking for the instance name input:
|
||||
this.SettingsManager.InjectSpellchecking(SPELLCHECK_ATTRIBUTES);
|
||||
|
||||
|
||||
// Load the used instance names:
|
||||
this.UsedNames = this.SettingsManager.ConfigurationData.ChatTemplates.Select(x => x.Name.ToLowerInvariant()).ToList();
|
||||
|
||||
|
||||
// When editing, we need to load the data:
|
||||
if(this.IsEditing)
|
||||
{
|
||||
@ -108,7 +111,7 @@ public partial class ChatTemplateDialog : MSGComponentBase
|
||||
this.dataExampleConversation = this.ExistingChatThread.Blocks.Select(n => n.DeepClone(true)).ToList();
|
||||
this.DataName = this.ExistingChatThread.Name;
|
||||
}
|
||||
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
@ -118,7 +121,7 @@ public partial class ChatTemplateDialog : MSGComponentBase
|
||||
// We don't want to show validation errors when the user opens the dialog.
|
||||
if(!this.IsEditing && firstRender)
|
||||
this.form.ResetValidation();
|
||||
|
||||
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
|
||||
@ -128,28 +131,34 @@ public partial class ChatTemplateDialog : MSGComponentBase
|
||||
{
|
||||
Num = this.DataNum,
|
||||
Id = this.DataId,
|
||||
|
||||
|
||||
Name = this.DataName,
|
||||
SystemPrompt = this.DataSystemPrompt,
|
||||
PredefinedUserPrompt = this.PredefinedUserPrompt,
|
||||
ExampleConversation = this.dataExampleConversation,
|
||||
FileAttachments = this.fileAttachments.Select(attachment => attachment.Normalize()).ToList(),
|
||||
AllowProfileUsage = this.AllowProfileUsage,
|
||||
|
||||
|
||||
EnterpriseConfigurationPluginId = Guid.Empty,
|
||||
IsEnterpriseConfiguration = false,
|
||||
};
|
||||
|
||||
private void RemoveMessage(ContentBlock item)
|
||||
{
|
||||
if (this.IsReadOnly)
|
||||
return;
|
||||
|
||||
this.dataExampleConversation.Remove(item);
|
||||
}
|
||||
|
||||
private void AddMessageToEnd()
|
||||
{
|
||||
if (this.IsReadOnly)
|
||||
return;
|
||||
|
||||
var newEntry = new ContentBlock
|
||||
{
|
||||
Role = this.dataExampleConversation.Count is 0 ? ChatRole.USER : this.dataExampleConversation.Last().Role.SelectNextRoleForTemplate(),
|
||||
Role = this.dataExampleConversation.Count is 0 ? ChatRole.USER : this.dataExampleConversation.Last().Role.SelectNextRoleForTemplate(),
|
||||
Content = new ContentText(),
|
||||
ContentType = ContentType.TEXT,
|
||||
HideFromUser = true,
|
||||
@ -161,6 +170,9 @@ public partial class ChatTemplateDialog : MSGComponentBase
|
||||
|
||||
private void AddMessageBelow(ContentBlock currentItem)
|
||||
{
|
||||
if (this.IsReadOnly)
|
||||
return;
|
||||
|
||||
var insertedEntry = new ContentBlock
|
||||
{
|
||||
Role = this.dataExampleConversation.Count is 0 ? ChatRole.USER : this.dataExampleConversation.Last().Role.SelectNextRoleForTemplate(),
|
||||
@ -169,7 +181,7 @@ public partial class ChatTemplateDialog : MSGComponentBase
|
||||
HideFromUser = true,
|
||||
Time = DateTimeOffset.Now,
|
||||
};
|
||||
|
||||
|
||||
// The rest of the method remains the same:
|
||||
var index = this.dataExampleConversation.IndexOf(currentItem);
|
||||
if (index >= 0)
|
||||
@ -177,71 +189,83 @@ public partial class ChatTemplateDialog : MSGComponentBase
|
||||
else
|
||||
this.dataExampleConversation.Add(insertedEntry);
|
||||
}
|
||||
|
||||
|
||||
private void BackupItem(object? element)
|
||||
{
|
||||
if (this.IsReadOnly)
|
||||
return;
|
||||
|
||||
this.isInlineEditOnGoing = true;
|
||||
this.messageEntryBeforeEdit = element switch
|
||||
{
|
||||
ContentBlock block => block.DeepClone(),
|
||||
_ => null,
|
||||
};
|
||||
|
||||
|
||||
this.StateHasChanged();
|
||||
}
|
||||
|
||||
private void ResetItem(object? element)
|
||||
{
|
||||
if (this.IsReadOnly)
|
||||
return;
|
||||
|
||||
this.isInlineEditOnGoing = false;
|
||||
switch (element)
|
||||
{
|
||||
case ContentBlock block:
|
||||
if (this.messageEntryBeforeEdit is null)
|
||||
return; // No backup to restore from
|
||||
|
||||
|
||||
block.Content = this.messageEntryBeforeEdit.Content?.DeepClone();
|
||||
block.Role = this.messageEntryBeforeEdit.Role;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
this.StateHasChanged();
|
||||
}
|
||||
|
||||
private void CommitInlineEdit(object? element)
|
||||
{
|
||||
if (this.IsReadOnly)
|
||||
return;
|
||||
|
||||
this.isInlineEditOnGoing = false;
|
||||
this.StateHasChanged();
|
||||
}
|
||||
|
||||
|
||||
private async Task Store()
|
||||
{
|
||||
if (this.IsReadOnly)
|
||||
return;
|
||||
|
||||
await this.form.Validate();
|
||||
|
||||
|
||||
// When the data is not valid, we don't store it:
|
||||
if (!this.dataIsValid)
|
||||
return;
|
||||
|
||||
|
||||
// When an inline edit is ongoing, we cannot store the data:
|
||||
if (this.isInlineEditOnGoing)
|
||||
return;
|
||||
|
||||
|
||||
// Use the data model to store the chat template.
|
||||
// We just return this data to the parent component:
|
||||
var addedChatTemplateSettings = this.CreateChatTemplateSettings();
|
||||
|
||||
|
||||
if(this.IsEditing)
|
||||
this.Logger.LogInformation($"Edited chat template '{addedChatTemplateSettings.Name}'.");
|
||||
else
|
||||
this.Logger.LogInformation($"Created chat template '{addedChatTemplateSettings.Name}'.");
|
||||
|
||||
|
||||
this.MudDialog.Close(DialogResult.Ok(addedChatTemplateSettings));
|
||||
}
|
||||
|
||||
|
||||
private string? ValidateExampleTextMessage(string message)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(message))
|
||||
return T("Please enter a message for the example conversation.");
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -249,20 +273,23 @@ public partial class ChatTemplateDialog : MSGComponentBase
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
return T("Please enter a name for the chat template.");
|
||||
|
||||
|
||||
if (name.Length > 40)
|
||||
return T("The chat template name must not exceed 40 characters.");
|
||||
|
||||
|
||||
// The instance name must be unique:
|
||||
var lowerName = name.ToLowerInvariant();
|
||||
if (lowerName != this.dataEditingPreviousName && this.UsedNames.Contains(lowerName))
|
||||
return T("The chat template name must be unique; the chosen name is already in use.");
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void UseDefaultSystemPrompt()
|
||||
{
|
||||
if (this.IsReadOnly)
|
||||
return;
|
||||
|
||||
this.DataSystemPrompt = SystemPrompts.DEFAULT;
|
||||
}
|
||||
|
||||
|
||||
@ -96,7 +96,7 @@ public partial class DataSourceLocalDirectoryDialog : MSGComponentBase
|
||||
|
||||
#endregion
|
||||
|
||||
private bool SelectedCloudEmbedding => !this.SettingsManager.ConfigurationData.EmbeddingProviders.FirstOrDefault(x => x.Id == this.dataEmbeddingId)?.IsSelfHosted ?? false;
|
||||
private bool SelectedCloudEmbedding => !(this.SettingsManager.ConfigurationData.EmbeddingProviders.FirstOrDefault(x => x.Id == this.dataEmbeddingId)?.IsTrustedForDataSourceSecurityChecks(this.SettingsManager) ?? false);
|
||||
|
||||
private DataSourceLocalDirectory CreateDataSource() => new()
|
||||
{
|
||||
|
||||
@ -56,7 +56,7 @@ public partial class DataSourceLocalDirectoryInfoDialog : MSGComponentBase, IAsy
|
||||
|
||||
private bool IsOperationInProgress { get; set; } = true;
|
||||
|
||||
private bool IsCloudEmbedding => !this.embeddingProvider.IsSelfHosted;
|
||||
private bool IsCloudEmbedding => !this.embeddingProvider.IsTrustedForDataSourceSecurityChecks(this.SettingsManager);
|
||||
|
||||
private bool IsDirectoryAvailable => this.directoryInfo.Exists;
|
||||
|
||||
|
||||
@ -96,7 +96,7 @@ public partial class DataSourceLocalFileDialog : MSGComponentBase
|
||||
|
||||
#endregion
|
||||
|
||||
private bool SelectedCloudEmbedding => !this.SettingsManager.ConfigurationData.EmbeddingProviders.FirstOrDefault(x => x.Id == this.dataEmbeddingId)?.IsSelfHosted ?? false;
|
||||
private bool SelectedCloudEmbedding => !(this.SettingsManager.ConfigurationData.EmbeddingProviders.FirstOrDefault(x => x.Id == this.dataEmbeddingId)?.IsTrustedForDataSourceSecurityChecks(this.SettingsManager) ?? false);
|
||||
|
||||
private DataSourceLocalFile CreateDataSource() => new()
|
||||
{
|
||||
|
||||
@ -28,7 +28,7 @@ public partial class DataSourceLocalFileInfoDialog : MSGComponentBase
|
||||
private EmbeddingProvider embeddingProvider = EmbeddingProvider.NONE;
|
||||
private FileInfo fileInfo = null!;
|
||||
|
||||
private bool IsCloudEmbedding => !this.embeddingProvider.IsSelfHosted;
|
||||
private bool IsCloudEmbedding => !this.embeddingProvider.IsTrustedForDataSourceSecurityChecks(this.SettingsManager);
|
||||
|
||||
private bool IsFileAvailable => this.fileInfo.Exists;
|
||||
|
||||
|
||||
@ -7,6 +7,12 @@ public static class DialogOptions
|
||||
CloseOnEscapeKey = true,
|
||||
FullWidth = true, MaxWidth = MaxWidth.Medium,
|
||||
};
|
||||
|
||||
public static readonly MudBlazor.DialogOptions FULLSCREEN_MANUAL_ESCAPE = new()
|
||||
{
|
||||
CloseOnEscapeKey = false,
|
||||
FullWidth = true, MaxWidth = MaxWidth.Medium,
|
||||
};
|
||||
|
||||
public static readonly MudBlazor.DialogOptions FULLSCREEN_NO_HEADER = new()
|
||||
{
|
||||
|
||||
@ -203,7 +203,7 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
|
||||
|
||||
#region Implementation of ISecretId
|
||||
|
||||
public string SecretId => this.DataLLMProvider.ToName();
|
||||
public string SecretId => this.DataLLMProvider.ToSecretId();
|
||||
|
||||
public string SecretName => this.DataName;
|
||||
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
AdornmentColor="Color.Info"
|
||||
Validation="@this.ValidateName"
|
||||
Variant="Variant.Outlined"
|
||||
ReadOnly="@this.IsReadOnly"
|
||||
UserAttributes="@SPELLCHECK_ATTRIBUTES"
|
||||
/>
|
||||
|
||||
@ -44,8 +45,9 @@
|
||||
MaxLines="12"
|
||||
UserAttributes="@SPELLCHECK_ATTRIBUTES"
|
||||
HelperText="@T("Tell the AI something about yourself. What is your profession? How experienced are you in this profession? Which technologies do you like?")"
|
||||
ReadOnly="@this.IsReadOnly"
|
||||
/>
|
||||
<ReadFileContent @bind-FileContent="@this.DataNeedToKnow"/>
|
||||
<ReadFileContent @bind-FileContent="@this.DataNeedToKnow" Disabled="@this.IsReadOnly"/>
|
||||
|
||||
<MudTextField
|
||||
T="string"
|
||||
@ -62,8 +64,9 @@
|
||||
Class="mt-10"
|
||||
UserAttributes="@SPELLCHECK_ATTRIBUTES"
|
||||
HelperText="@T("Tell the AI what you want it to do for you. What are your goals or are you trying to achieve? Like having the AI address you informally.")"
|
||||
ReadOnly="@this.IsReadOnly"
|
||||
/>
|
||||
<ReadFileContent @bind-FileContent="@this.DataActions"/>
|
||||
<ReadFileContent @bind-FileContent="@this.DataActions" Disabled="@this.IsReadOnly"/>
|
||||
|
||||
<MudJustifiedText Typo="Typo.body2" Class="mb-3 mt-3">
|
||||
@T("Please be aware that your profile info becomes part of the system prompt. This means it uses up context space — the “memory” the LLM uses to understand and respond to your request. If your profile is extremely long, the LLM may struggle to focus on your actual task.")
|
||||
@ -73,18 +76,27 @@
|
||||
<Issues IssuesData="@this.dataIssues"/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<MudButton OnClick="@this.Cancel" Variant="Variant.Filled">
|
||||
@T("Cancel")
|
||||
</MudButton>
|
||||
<MudButton OnClick="@this.Store" Variant="Variant.Filled" Color="Color.Primary">
|
||||
@if(this.IsEditing)
|
||||
{
|
||||
@T("Update")
|
||||
}
|
||||
else
|
||||
{
|
||||
@T("Add")
|
||||
}
|
||||
</MudButton>
|
||||
@if (this.IsReadOnly)
|
||||
{
|
||||
<MudButton OnClick="@this.Cancel" Variant="Variant.Filled">
|
||||
@T("Close")
|
||||
</MudButton>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudButton OnClick="@this.Cancel" Variant="Variant.Filled">
|
||||
@T("Cancel")
|
||||
</MudButton>
|
||||
<MudButton OnClick="@this.Store" Variant="Variant.Filled" Color="Color.Primary">
|
||||
@if(this.IsEditing)
|
||||
{
|
||||
@T("Update")
|
||||
}
|
||||
else
|
||||
{
|
||||
@T("Add")
|
||||
}
|
||||
</MudButton>
|
||||
}
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
@ -15,19 +15,19 @@ public partial class ProfileDialog : MSGComponentBase
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public uint DataNum { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The profile's ID.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string DataId { get; set; } = Guid.NewGuid().ToString();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The profile name chosen by the user.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string DataName { get; set; } = string.Empty;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// What should the LLM know about you?
|
||||
/// </summary>
|
||||
@ -39,27 +39,30 @@ public partial class ProfileDialog : MSGComponentBase
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string DataActions { get; set; } = string.Empty;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Should the dialog be in editing mode?
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool IsEditing { get; init; }
|
||||
|
||||
|
||||
[Parameter]
|
||||
public bool IsReadOnly { get; init; }
|
||||
|
||||
[Inject]
|
||||
private ILogger<ProviderDialog> Logger { get; init; } = null!;
|
||||
|
||||
|
||||
private static readonly Dictionary<string, object?> SPELLCHECK_ATTRIBUTES = new();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of used profile names. We need this to check for uniqueness.
|
||||
/// </summary>
|
||||
private List<string> UsedNames { get; set; } = [];
|
||||
|
||||
|
||||
private bool dataIsValid;
|
||||
private string[] dataIssues = [];
|
||||
private string dataEditingPreviousName = string.Empty;
|
||||
|
||||
|
||||
// We get the form reference from Blazor code to validate it manually:
|
||||
private MudForm form = null!;
|
||||
|
||||
@ -70,7 +73,7 @@ public partial class ProfileDialog : MSGComponentBase
|
||||
Name = this.DataName,
|
||||
NeedToKnow = this.DataNeedToKnow,
|
||||
Actions = this.DataActions,
|
||||
|
||||
|
||||
EnterpriseConfigurationPluginId = Guid.Empty,
|
||||
IsEnterpriseConfiguration = false,
|
||||
};
|
||||
@ -81,16 +84,16 @@ public partial class ProfileDialog : MSGComponentBase
|
||||
{
|
||||
// Configure the spellchecking for the instance name input:
|
||||
this.SettingsManager.InjectSpellchecking(SPELLCHECK_ATTRIBUTES);
|
||||
|
||||
|
||||
// Load the used instance names:
|
||||
this.UsedNames = this.SettingsManager.ConfigurationData.Profiles.Select(x => x.Name.ToLowerInvariant()).ToList();
|
||||
|
||||
|
||||
// When editing, we need to load the data:
|
||||
if(this.IsEditing)
|
||||
{
|
||||
this.dataEditingPreviousName = this.DataName.ToLowerInvariant();
|
||||
}
|
||||
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
@ -100,37 +103,40 @@ public partial class ProfileDialog : MSGComponentBase
|
||||
// We don't want to show validation errors when the user opens the dialog.
|
||||
if(!this.IsEditing && firstRender)
|
||||
this.form.ResetValidation();
|
||||
|
||||
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
private async Task Store()
|
||||
{
|
||||
if (this.IsReadOnly)
|
||||
return;
|
||||
|
||||
await this.form.Validate();
|
||||
|
||||
|
||||
// When the data is not valid, we don't store it:
|
||||
if (!this.dataIsValid)
|
||||
return;
|
||||
|
||||
|
||||
// Use the data model to store the profile.
|
||||
// We just return this data to the parent component:
|
||||
var addedProfileSettings = this.CreateProfileSettings();
|
||||
|
||||
|
||||
if(this.IsEditing)
|
||||
this.Logger.LogInformation($"Edited profile '{addedProfileSettings.Name}'.");
|
||||
else
|
||||
this.Logger.LogInformation($"Created profile '{addedProfileSettings.Name}'.");
|
||||
|
||||
|
||||
this.MudDialog.Close(DialogResult.Ok(addedProfileSettings));
|
||||
}
|
||||
|
||||
|
||||
private string? ValidateNeedToKnow(string text)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(this.DataNeedToKnow) && string.IsNullOrWhiteSpace(this.DataActions))
|
||||
return T("Please enter what the LLM should know about you and/or what actions it should take.");
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -138,7 +144,7 @@ public partial class ProfileDialog : MSGComponentBase
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(this.DataNeedToKnow) && string.IsNullOrWhiteSpace(this.DataActions))
|
||||
return T("Please enter what the LLM should know about you and/or what actions it should take.");
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -146,15 +152,15 @@ public partial class ProfileDialog : MSGComponentBase
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
return T("Please enter a profile name.");
|
||||
|
||||
|
||||
if (name.Length > 40)
|
||||
return T("The profile name must not exceed 40 characters.");
|
||||
|
||||
|
||||
// The instance name must be unique:
|
||||
var lowerName = name.ToLowerInvariant();
|
||||
if (lowerName != this.dataEditingPreviousName && this.UsedNames.Contains(lowerName))
|
||||
return T("The profile name must be unique; the chosen name is already in use.");
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@ -71,7 +71,7 @@
|
||||
@* ReSharper restore Asp.Entity *@
|
||||
}
|
||||
|
||||
@if (!this.DataLLMProvider.IsLLMModelSelectionHidden(this.DataHost))
|
||||
@if (!this.IsLLMModelSelectionHidden)
|
||||
{
|
||||
<MudField FullWidth="true" Label="@T("Model selection")" Variant="Variant.Outlined" Class="mb-3">
|
||||
<MudStack Row="@true" AlignItems="AlignItems.Center" StretchItems="StretchItems.End">
|
||||
|
||||
@ -104,6 +104,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
|
||||
private string dataAPIKeyStorageIssue = string.Empty;
|
||||
private string dataEditingPreviousInstanceName = string.Empty;
|
||||
private string dataLoadingModelsIssue = string.Empty;
|
||||
private bool usesLegacySystemModelFallback;
|
||||
private bool showExpertSettings;
|
||||
|
||||
// We get the form reference from Blazor code to validate it manually:
|
||||
@ -123,6 +124,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
|
||||
GetUsedInstanceNames = () => this.UsedInstanceNames,
|
||||
GetHost = () => this.DataHost,
|
||||
IsModelProvidedManually = () => this.DataLLMProvider.IsLLMModelProvidedManually(),
|
||||
IsModelSelectionHidden = () => this.IsLLMModelSelectionHidden,
|
||||
};
|
||||
}
|
||||
|
||||
@ -132,9 +134,9 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
|
||||
|
||||
// Determine the model based on the provider and host configuration:
|
||||
Model model;
|
||||
if (this.DataLLMProvider.IsLLMModelSelectionHidden(this.DataHost))
|
||||
if (this.IsLLMModelSelectionHidden)
|
||||
{
|
||||
// Use system model placeholder for hosts that don't support model selection (e.g., llama.cpp):
|
||||
// Use system model placeholder for legacy hosts that don't support model selection:
|
||||
model = Model.SYSTEM_MODEL;
|
||||
}
|
||||
else if (this.DataLLMProvider is LLMProviders.FIREWORKS or LLMProviders.HUGGINGFACE)
|
||||
@ -229,7 +231,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
|
||||
|
||||
#region Implementation of ISecretId
|
||||
|
||||
public string SecretId => this.DataLLMProvider.ToName();
|
||||
public string SecretId => this.DataLLMProvider.ToSecretId();
|
||||
|
||||
public string SecretName => this.DataInstanceName;
|
||||
|
||||
@ -300,6 +302,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
|
||||
this.dataManuallyModel = string.Empty;
|
||||
this.availableModels.Clear();
|
||||
this.dataLoadingModelsIssue = string.Empty;
|
||||
this.usesLegacySystemModelFallback = false;
|
||||
}
|
||||
|
||||
private async Task ReloadModels()
|
||||
@ -321,6 +324,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
|
||||
|
||||
this.availableModels.Clear();
|
||||
this.availableModels.AddRange(orderedModels);
|
||||
this.UpdateModelSelectionAfterLoading();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -334,6 +338,34 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
|
||||
LLMProviders.SELF_HOSTED => T("(Optional) API Key"),
|
||||
_ => T("API Key"),
|
||||
};
|
||||
|
||||
private bool IsLLMModelSelectionHidden => this.DataLLMProvider.IsLLMModelSelectionHidden(this.DataHost) ||
|
||||
this.DataLLMProvider is LLMProviders.SELF_HOSTED &&
|
||||
this.DataHost is Host.LLAMA_CPP &&
|
||||
this.usesLegacySystemModelFallback;
|
||||
|
||||
private void UpdateModelSelectionAfterLoading()
|
||||
{
|
||||
if (this.DataLLMProvider is not LLMProviders.SELF_HOSTED || this.DataHost is not Host.LLAMA_CPP)
|
||||
return;
|
||||
|
||||
this.usesLegacySystemModelFallback = this.availableModels.Count is 1 && this.availableModels[0].IsSystemModel;
|
||||
if (this.usesLegacySystemModelFallback)
|
||||
{
|
||||
this.DataModel = Model.SYSTEM_MODEL;
|
||||
return;
|
||||
}
|
||||
|
||||
var availableModel = this.availableModels.FirstOrDefault(model =>
|
||||
string.Equals(model.Id, this.DataModel.Id, StringComparison.OrdinalIgnoreCase));
|
||||
if (availableModel != default)
|
||||
{
|
||||
this.DataModel = availableModel;
|
||||
return;
|
||||
}
|
||||
|
||||
this.DataModel = this.availableModels.Count is 1 ? this.availableModels[0] : default;
|
||||
}
|
||||
|
||||
private void ToggleExpertSettings() => this.showExpertSettings = !this.showExpertSettings;
|
||||
|
||||
|
||||
@ -65,6 +65,9 @@ public abstract class SettingsDialogBase : MSGComponentBase
|
||||
switch (triggeredEvent)
|
||||
{
|
||||
case Event.CONFIGURATION_CHANGED:
|
||||
case Event.PLUGINS_RELOADED:
|
||||
this.UpdateProviders();
|
||||
this.UpdateEmbeddingProviders();
|
||||
this.StateHasChanged();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -16,10 +16,10 @@
|
||||
<ConfigurationSelect OptionDescription="@T("Provider selection when loading a chat and sending assistant results to chat")" SelectedValue="@(() => this.SettingsManager.ConfigurationData.Chat.LoadingProviderBehavior)" Data="@ConfigurationSelectDataFactory.GetLoadingChatProviderBehavior()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.Chat.LoadingProviderBehavior = selectedValue)" OptionHelp="@T("Control how the LLM provider for loaded chats is selected and when assistant results are sent to chat.")"/>
|
||||
|
||||
<MudPaper Class="pa-3 mb-8 border-dashed border rounded-lg">
|
||||
<ConfigurationOption OptionDescription="@T("Preselect chat options?")" LabelOn="@T("Chat options are preselected")" LabelOff="@T("No chat options are preselected")" State="@(() => this.SettingsManager.ConfigurationData.Chat.PreselectOptions)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.Chat.PreselectOptions = updatedState)" OptionHelp="@T("When enabled, you can preselect chat options. This is might be useful when you prefer a specific provider.")"/>
|
||||
<ConfigurationProviderSelection Component="Components.CHAT" Data="@this.AvailableLLMProviders" Disabled="@(() => !this.SettingsManager.ConfigurationData.Chat.PreselectOptions)" SelectedValue="@(() => this.SettingsManager.ConfigurationData.Chat.PreselectedProvider)" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.Chat.PreselectedProvider = selectedValue)"/>
|
||||
<ConfigurationSelect OptionDescription="@T("Preselect a profile")" Disabled="@(() => !this.SettingsManager.ConfigurationData.Chat.PreselectOptions)" SelectedValue="@(() => ProfilePreselection.FromStoredValue(this.SettingsManager.ConfigurationData.Chat.PreselectedProfile))" Data="@ConfigurationSelectDataFactory.GetComponentProfilesData(this.SettingsManager.ConfigurationData.Profiles)" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.Chat.PreselectedProfile = selectedValue)" OptionHelp="@T("Choose whether chats should use the app default profile, no profile, or a specific profile.")"/>
|
||||
<ConfigurationSelect OptionDescription="@T("Preselect one of your chat templates?")" Disabled="@(() => !this.SettingsManager.ConfigurationData.Chat.PreselectOptions)" SelectedValue="@(() => this.SettingsManager.ConfigurationData.Chat.PreselectedChatTemplate)" Data="@ConfigurationSelectDataFactory.GetChatTemplatesData(this.SettingsManager.ConfigurationData.ChatTemplates)" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.Chat.PreselectedChatTemplate = selectedValue)" OptionHelp="@T("Would you like to set one of your chat templates as the default for chats?")"/>
|
||||
<ConfigurationOption OptionDescription="@T("Preselect chat options?")" LabelOn="@T("Chat options are preselected")" LabelOff="@T("No chat options are preselected")" State="@(() => this.SettingsManager.ConfigurationData.Chat.PreselectOptions)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.Chat.PreselectOptions = updatedState)" OptionHelp="@T("When enabled, you can preselect chat options. This is might be useful when you prefer a specific provider.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.Chat, x => x.PreselectOptions, out var meta) && meta.IsLocked"/>
|
||||
<ConfigurationProviderSelection Component="Components.CHAT" Data="@this.AvailableLLMProviders" Disabled="@(() => !this.SettingsManager.ConfigurationData.Chat.PreselectOptions)" SelectedValue="@(() => this.SettingsManager.ConfigurationData.Chat.PreselectedProvider)" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.Chat.PreselectedProvider = selectedValue)" IsLocked="() => ManagedConfiguration.TryGet(x => x.Chat, x => x.PreselectedProvider, out var meta) && meta.IsLocked"/>
|
||||
<ConfigurationSelect OptionDescription="@T("Preselect a profile")" Disabled="@(() => !this.SettingsManager.ConfigurationData.Chat.PreselectOptions)" SelectedValue="@(() => ProfilePreselection.FromStoredValue(this.SettingsManager.ConfigurationData.Chat.PreselectedProfile))" Data="@ConfigurationSelectDataFactory.GetComponentProfilesData(this.SettingsManager.ConfigurationData.Profiles)" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.Chat.PreselectedProfile = selectedValue)" OptionHelp="@T("Choose whether chats should use the app default profile, no profile, or a specific profile.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.Chat, x => x.PreselectedProfile, out var meta) && meta.IsLocked"/>
|
||||
<ConfigurationSelect OptionDescription="@T("Preselect one of your chat templates?")" Disabled="@(() => !this.SettingsManager.ConfigurationData.Chat.PreselectOptions)" SelectedValue="@(() => this.SettingsManager.ConfigurationData.Chat.PreselectedChatTemplate)" Data="@ConfigurationSelectDataFactory.GetChatTemplatesData(this.SettingsManager.ConfigurationData.ChatTemplates)" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.Chat.PreselectedChatTemplate = selectedValue)" OptionHelp="@T("Would you like to set one of your chat templates as the default for chats?")" IsLocked="() => ManagedConfiguration.TryGet(x => x.Chat, x => x.PreselectedChatTemplate, out var meta) && meta.IsLocked"/>
|
||||
</MudPaper>
|
||||
|
||||
@if (PreviewFeatures.PRE_RAG_2024.IsEnabled(this.SettingsManager))
|
||||
|
||||
@ -33,9 +33,14 @@
|
||||
<MudTd>
|
||||
@if (context.IsEnterpriseConfiguration)
|
||||
{
|
||||
<MudTooltip Text="@T("This template is managed by your organization.")">
|
||||
<MudIconButton Color="Color.Info" Icon="@Icons.Material.Filled.Business" Disabled="true"/>
|
||||
</MudTooltip>
|
||||
<MudStack Row="true" Class="mb-2 mt-2" Wrap="Wrap.Wrap">
|
||||
<MudTooltip Text="@T("This template is managed by your organization.")">
|
||||
<MudIconButton Color="Color.Info" Icon="@Icons.Material.Filled.Business" Disabled="true"/>
|
||||
</MudTooltip>
|
||||
<MudTooltip Text="@T("View")">
|
||||
<MudIconButton Color="Color.Info" Icon="@Icons.Material.Filled.Visibility" OnClick="@(() => this.ViewChatTemplate(context))"/>
|
||||
</MudTooltip>
|
||||
</MudStack>
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -6,24 +6,24 @@ namespace AIStudio.Dialogs.Settings;
|
||||
|
||||
public partial class SettingsDialogChatTemplate : SettingsDialogBase
|
||||
{
|
||||
[Parameter]
|
||||
[Parameter]
|
||||
public bool CreateTemplateFromExistingChatThread { get; set; }
|
||||
|
||||
|
||||
[Parameter]
|
||||
public ChatThread? ExistingChatThread { get; set; }
|
||||
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
if (this.CreateTemplateFromExistingChatThread)
|
||||
if (this.CreateTemplateFromExistingChatThread)
|
||||
await this.AddChatTemplate();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
private async Task AddChatTemplate()
|
||||
{
|
||||
var dialogParameters = new DialogParameters<ChatTemplateDialog>
|
||||
@ -41,21 +41,21 @@ public partial class SettingsDialogChatTemplate : SettingsDialogBase
|
||||
var dialogResult = await dialogReference.Result;
|
||||
if (dialogResult is null || dialogResult.Canceled)
|
||||
return;
|
||||
|
||||
|
||||
var addedChatTemplate = (ChatTemplate)dialogResult.Data!;
|
||||
addedChatTemplate = addedChatTemplate with { Num = this.SettingsManager.ConfigurationData.NextChatTemplateNum++ };
|
||||
|
||||
|
||||
this.SettingsManager.ConfigurationData.ChatTemplates.Add(addedChatTemplate);
|
||||
|
||||
|
||||
await this.SettingsManager.StoreSettings();
|
||||
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||
}
|
||||
|
||||
|
||||
private async Task EditChatTemplate(ChatTemplate chatTemplate)
|
||||
{
|
||||
if (chatTemplate == ChatTemplate.NO_CHAT_TEMPLATE || chatTemplate.IsEnterpriseConfiguration)
|
||||
return;
|
||||
|
||||
|
||||
var dialogParameters = new DialogParameters<ChatTemplateDialog>
|
||||
{
|
||||
{ x => x.DataNum, chatTemplate.Num },
|
||||
@ -68,34 +68,53 @@ public partial class SettingsDialogChatTemplate : SettingsDialogBase
|
||||
{ x => x.FileAttachments, chatTemplate.FileAttachments },
|
||||
{ x => x.AllowProfileUsage, chatTemplate.AllowProfileUsage },
|
||||
};
|
||||
|
||||
|
||||
var dialogReference = await this.DialogService.ShowAsync<ChatTemplateDialog>(T("Edit Chat Template"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||
var dialogResult = await dialogReference.Result;
|
||||
if (dialogResult is null || dialogResult.Canceled)
|
||||
return;
|
||||
|
||||
|
||||
var editedChatTemplate = (ChatTemplate)dialogResult.Data!;
|
||||
this.SettingsManager.ConfigurationData.ChatTemplates[this.SettingsManager.ConfigurationData.ChatTemplates.IndexOf(chatTemplate)] = editedChatTemplate;
|
||||
|
||||
|
||||
await this.SettingsManager.StoreSettings();
|
||||
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||
}
|
||||
|
||||
private async Task ViewChatTemplate(ChatTemplate chatTemplate)
|
||||
{
|
||||
var dialogParameters = new DialogParameters<ChatTemplateDialog>
|
||||
{
|
||||
{ x => x.DataNum, chatTemplate.Num },
|
||||
{ x => x.DataId, chatTemplate.Id },
|
||||
{ x => x.DataName, chatTemplate.Name },
|
||||
{ x => x.DataSystemPrompt, chatTemplate.SystemPrompt },
|
||||
{ x => x.PredefinedUserPrompt, chatTemplate.PredefinedUserPrompt },
|
||||
{ x => x.IsEditing, true },
|
||||
{ x => x.IsReadOnly, true },
|
||||
{ x => x.ExampleConversation, chatTemplate.ExampleConversation },
|
||||
{ x => x.FileAttachments, chatTemplate.FileAttachments },
|
||||
{ x => x.AllowProfileUsage, chatTemplate.AllowProfileUsage },
|
||||
};
|
||||
|
||||
await this.DialogService.ShowAsync<ChatTemplateDialog>(T("View Chat Template"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||
}
|
||||
|
||||
private async Task DeleteChatTemplate(ChatTemplate chatTemplate)
|
||||
{
|
||||
var dialogParameters = new DialogParameters<ConfirmDialog>
|
||||
{
|
||||
{ x => x.Message, string.Format(T("Are you sure you want to delete the chat template '{0}'?"), chatTemplate.Name) },
|
||||
};
|
||||
|
||||
|
||||
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>(T("Delete Chat Template"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||
var dialogResult = await dialogReference.Result;
|
||||
if (dialogResult is null || dialogResult.Canceled)
|
||||
return;
|
||||
|
||||
|
||||
this.SettingsManager.ConfigurationData.ChatTemplates.Remove(chatTemplate);
|
||||
await this.SettingsManager.StoreSettings();
|
||||
|
||||
|
||||
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||
}
|
||||
|
||||
|
||||
@ -32,9 +32,14 @@
|
||||
<MudTd>
|
||||
@if (context.IsEnterpriseConfiguration)
|
||||
{
|
||||
<MudTooltip Text="@T("This profile is managed by your organization.")">
|
||||
<MudIconButton Color="Color.Info" Icon="@Icons.Material.Filled.Business" Disabled="true"/>
|
||||
</MudTooltip>
|
||||
<MudStack Row="true" Class="mb-2 mt-2" Wrap="Wrap.Wrap">
|
||||
<MudTooltip Text="@T("This profile is managed by your organization.")">
|
||||
<MudIconButton Color="Color.Info" Icon="@Icons.Material.Filled.Business" Disabled="true"/>
|
||||
</MudTooltip>
|
||||
<MudTooltip Text="@T("View")">
|
||||
<MudIconButton Color="Color.Info" Icon="@Icons.Material.Filled.Visibility" OnClick="() => this.ViewProfile(context)"/>
|
||||
</MudTooltip>
|
||||
</MudStack>
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -10,21 +10,21 @@ public partial class SettingsDialogProfiles : SettingsDialogBase
|
||||
{
|
||||
{ x => x.IsEditing, false },
|
||||
};
|
||||
|
||||
|
||||
var dialogReference = await this.DialogService.ShowAsync<ProfileDialog>(T("Add Profile"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||
var dialogResult = await dialogReference.Result;
|
||||
if (dialogResult is null || dialogResult.Canceled)
|
||||
return;
|
||||
|
||||
|
||||
var addedProfile = (Profile)dialogResult.Data!;
|
||||
addedProfile = addedProfile with { Num = this.SettingsManager.ConfigurationData.NextProfileNum++ };
|
||||
|
||||
|
||||
this.SettingsManager.ConfigurationData.Profiles.Add(addedProfile);
|
||||
|
||||
|
||||
await this.SettingsManager.StoreSettings();
|
||||
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||
}
|
||||
|
||||
|
||||
private async Task EditProfile(Profile profile)
|
||||
{
|
||||
var dialogParameters = new DialogParameters<ProfileDialog>
|
||||
@ -36,19 +36,35 @@ public partial class SettingsDialogProfiles : SettingsDialogBase
|
||||
{ x => x.DataActions, profile.Actions },
|
||||
{ x => x.IsEditing, true },
|
||||
};
|
||||
|
||||
|
||||
var dialogReference = await this.DialogService.ShowAsync<ProfileDialog>(T("Edit Profile"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||
var dialogResult = await dialogReference.Result;
|
||||
if (dialogResult is null || dialogResult.Canceled)
|
||||
return;
|
||||
|
||||
|
||||
var editedProfile = (Profile)dialogResult.Data!;
|
||||
this.SettingsManager.ConfigurationData.Profiles[this.SettingsManager.ConfigurationData.Profiles.IndexOf(profile)] = editedProfile;
|
||||
|
||||
|
||||
await this.SettingsManager.StoreSettings();
|
||||
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||
}
|
||||
|
||||
private async Task ViewProfile(Profile profile)
|
||||
{
|
||||
var dialogParameters = new DialogParameters<ProfileDialog>
|
||||
{
|
||||
{ x => x.DataNum, profile.Num },
|
||||
{ x => x.DataId, profile.Id },
|
||||
{ x => x.DataName, profile.Name },
|
||||
{ x => x.DataNeedToKnow, profile.NeedToKnow },
|
||||
{ x => x.DataActions, profile.Actions },
|
||||
{ x => x.IsEditing, true },
|
||||
{ x => x.IsReadOnly, true },
|
||||
};
|
||||
|
||||
await this.DialogService.ShowAsync<ProfileDialog>(T("View Profile"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||
}
|
||||
|
||||
private async Task ExportProfile(Profile profile)
|
||||
{
|
||||
if (!this.SettingsManager.ConfigurationData.App.ShowAdminSettings)
|
||||
@ -68,15 +84,15 @@ public partial class SettingsDialogProfiles : SettingsDialogBase
|
||||
{
|
||||
{ x => x.Message, string.Format(T("Are you sure you want to delete the profile '{0}'?"), profile.Name) },
|
||||
};
|
||||
|
||||
|
||||
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>(T("Delete Profile"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||
var dialogResult = await dialogReference.Result;
|
||||
if (dialogResult is null || dialogResult.Canceled)
|
||||
return;
|
||||
|
||||
|
||||
this.SettingsManager.ConfigurationData.Profiles.Remove(profile);
|
||||
await this.SettingsManager.StoreSettings();
|
||||
|
||||
|
||||
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||
}
|
||||
}
|
||||
@ -34,6 +34,7 @@ public partial class ShortcutDialog : MSGComponentBase
|
||||
|
||||
private string currentShortcut = string.Empty;
|
||||
private string originalShortcut = string.Empty;
|
||||
private string currentDisplayName = string.Empty;
|
||||
private string validationMessage = string.Empty;
|
||||
private Severity validationSeverity = Severity.Info;
|
||||
private bool hasValidationError;
|
||||
@ -115,6 +116,7 @@ public partial class ShortcutDialog : MSGComponentBase
|
||||
{
|
||||
this.UpdateModifiers(e);
|
||||
this.currentKey = null;
|
||||
this.currentDisplayName = string.Empty;
|
||||
this.UpdateShortcutString();
|
||||
return;
|
||||
}
|
||||
@ -123,10 +125,12 @@ public partial class ShortcutDialog : MSGComponentBase
|
||||
|
||||
// Get the key:
|
||||
this.currentKey = TranslateKeyCode(e.Code);
|
||||
this.currentDisplayName = this.BuildDisplayShortcut(e.Key);
|
||||
|
||||
// Validate: must have at least one modifier + a key
|
||||
if (!this.hasCtrl && !this.hasShift && !this.hasAlt && !this.hasMeta)
|
||||
{
|
||||
this.currentDisplayName = string.Empty;
|
||||
this.validationMessage = T("Please include at least one modifier key (Ctrl, Shift, Alt, or Cmd).");
|
||||
this.validationSeverity = Severity.Warning;
|
||||
this.hasValidationError = true;
|
||||
@ -216,6 +220,9 @@ public partial class ShortcutDialog : MSGComponentBase
|
||||
|
||||
private string GetDisplayShortcut()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(this.currentDisplayName))
|
||||
return this.currentDisplayName;
|
||||
|
||||
// Convert internal format to display format:
|
||||
return this.currentShortcut
|
||||
.Replace("CmdOrControl", OperatingSystem.IsMacOS() ? "Cmd" : "Ctrl")
|
||||
@ -225,6 +232,7 @@ public partial class ShortcutDialog : MSGComponentBase
|
||||
private void ClearShortcut()
|
||||
{
|
||||
this.currentShortcut = string.Empty;
|
||||
this.currentDisplayName = string.Empty;
|
||||
this.currentKey = null;
|
||||
this.hasCtrl = false;
|
||||
this.hasShift = false;
|
||||
@ -237,7 +245,17 @@ public partial class ShortcutDialog : MSGComponentBase
|
||||
|
||||
private void Cancel() => this.MudDialog.Cancel();
|
||||
|
||||
private void Confirm() => this.MudDialog.Close(DialogResult.Ok(this.currentShortcut));
|
||||
private void Confirm()
|
||||
{
|
||||
var displaySource = string.IsNullOrWhiteSpace(this.currentDisplayName)
|
||||
? string.Empty
|
||||
: this.currentShortcut;
|
||||
|
||||
this.MudDialog.Close(DialogResult.Ok(new ShortcutDialogResult(
|
||||
this.currentShortcut,
|
||||
this.currentDisplayName,
|
||||
displaySource)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the key code represents a modifier key.
|
||||
@ -377,6 +395,36 @@ public partial class ShortcutDialog : MSGComponentBase
|
||||
_ => code,
|
||||
};
|
||||
|
||||
private string BuildDisplayShortcut(string? key)
|
||||
{
|
||||
var displayKey = GetDisplayKey(key);
|
||||
if (string.IsNullOrWhiteSpace(displayKey))
|
||||
return string.Empty;
|
||||
|
||||
var parts = new List<string>();
|
||||
|
||||
if (this.hasCtrl)
|
||||
parts.Add(OperatingSystem.IsMacOS() ? "Cmd" : "Ctrl");
|
||||
|
||||
if (this.hasShift)
|
||||
parts.Add("Shift");
|
||||
|
||||
if (this.hasAlt)
|
||||
parts.Add("Alt");
|
||||
|
||||
parts.Add(displayKey);
|
||||
return string.Join("+", parts);
|
||||
}
|
||||
|
||||
private static string GetDisplayKey(string? key) => key switch
|
||||
{
|
||||
null or "" => string.Empty,
|
||||
" " => "Space",
|
||||
"Control" or "Shift" or "Alt" or "Meta" => string.Empty,
|
||||
_ when key.Length == 1 && key[0] >= 'a' && key[0] <= 'z' => key.ToUpperInvariant(),
|
||||
_ => key,
|
||||
};
|
||||
|
||||
private void HandleBlur()
|
||||
{
|
||||
// Re-focus the input field to keep capturing keys:
|
||||
|
||||
3
app/MindWork AI Studio/Dialogs/ShortcutDialogResult.cs
Normal file
3
app/MindWork AI Studio/Dialogs/ShortcutDialogResult.cs
Normal file
@ -0,0 +1,3 @@
|
||||
namespace AIStudio.Dialogs;
|
||||
|
||||
public readonly record struct ShortcutDialogResult(string Shortcut, string DisplayName, string DisplaySource);
|
||||
@ -31,6 +31,9 @@ public partial class SingleInputDialog : MSGComponentBase
|
||||
[Parameter]
|
||||
public string EmptyInputErrorMessage { get; set; } = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public Func<string?, string?>? AdditionalValidation { get; set; }
|
||||
|
||||
private static readonly Dictionary<string, object?> USER_INPUT_ATTRIBUTES = new();
|
||||
|
||||
private MudForm form = null!;
|
||||
@ -52,8 +55,8 @@ public partial class SingleInputDialog : MSGComponentBase
|
||||
{
|
||||
if (!this.AllowEmptyInput && string.IsNullOrWhiteSpace(value))
|
||||
return string.IsNullOrWhiteSpace(this.EmptyInputErrorMessage) ? T("Please enter a value.") : this.EmptyInputErrorMessage;
|
||||
|
||||
return null;
|
||||
|
||||
return this.AdditionalValidation?.Invoke(value);
|
||||
}
|
||||
|
||||
private void Cancel() => this.MudDialog.Cancel();
|
||||
|
||||
@ -218,7 +218,7 @@ public partial class TranscriptionProviderDialog : MSGComponentBase, ISecretId
|
||||
|
||||
#region Implementation of ISecretId
|
||||
|
||||
public string SecretId => this.DataLLMProvider.ToName();
|
||||
public string SecretId => this.DataLLMProvider.ToSecretId();
|
||||
|
||||
public string SecretName => this.DataName;
|
||||
|
||||
|
||||
@ -5,18 +5,57 @@
|
||||
@this.Message
|
||||
</MudText>
|
||||
<MudList T="Guid" @bind-SelectedValue="@this.selectedWorkspace">
|
||||
@foreach (var (workspaceName, workspaceId) in this.workspaces)
|
||||
@foreach (var workspace in this.workspaces)
|
||||
{
|
||||
<MudListItem Text="@workspaceName" Icon="@Icons.Material.Filled.Description" Value="@workspaceId" />
|
||||
<MudListItem Text="@workspace.Name" Icon="@Icons.Material.Filled.Description" Value="@workspace.WorkspaceId" />
|
||||
}
|
||||
</MudList>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<MudButton OnClick="@this.Cancel" Variant="Variant.Filled">
|
||||
@T("Cancel")
|
||||
</MudButton>
|
||||
<MudButton OnClick="@this.Confirm" Variant="Variant.Filled" Color="Color.Info">
|
||||
@this.ConfirmText
|
||||
</MudButton>
|
||||
<MudStack Style="width: 100%;" Spacing="2">
|
||||
<MudDivider/>
|
||||
|
||||
@if (this.showCreateWorkspaceForm)
|
||||
{
|
||||
<MudForm @ref="this.createWorkspaceForm">
|
||||
<MudTextField T="string"
|
||||
@ref="@this.newWorkspaceNameField"
|
||||
@bind-Text="@this.newWorkspaceName"
|
||||
Variant="Variant.Outlined"
|
||||
AutoGrow="@false"
|
||||
Lines="1"
|
||||
Label="@T("Workspace name")"
|
||||
AutoFocus="@true"
|
||||
Immediate="@true"
|
||||
Disabled="@this.isCreatingWorkspace"
|
||||
OnKeyDown="@this.HandleNewWorkspaceNameKeyDown"
|
||||
Validation="@this.ValidateNewWorkspaceName" />
|
||||
</MudForm>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudButton StartIcon="@Icons.Material.Filled.LibraryAdd" Variant="Variant.Filled" OnClick="@this.ShowCreateWorkspaceForm">
|
||||
@T("Create new workspace")
|
||||
</MudButton>
|
||||
}
|
||||
|
||||
<MudStack Row="@true" Justify="Justify.FlexEnd" AlignItems="AlignItems.Center" Wrap="Wrap.NoWrap" Spacing="2">
|
||||
<MudButton OnClick="@this.Cancel" Variant="Variant.Filled">
|
||||
@T("Cancel")
|
||||
</MudButton>
|
||||
@if (this.showCreateWorkspaceForm)
|
||||
{
|
||||
<MudButton OnClick="@this.CreateWorkspaceAsync" Variant="Variant.Filled" Color="Color.Info" Disabled="@this.isCreatingWorkspace">
|
||||
@T("Add workspace")
|
||||
</MudButton>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudButton OnClick="@this.Confirm" Variant="Variant.Filled" Color="Color.Info" Disabled="@(this.selectedWorkspace == Guid.Empty)">
|
||||
@this.ConfirmText
|
||||
</MudButton>
|
||||
}
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
@ -1,14 +1,20 @@
|
||||
using AIStudio.Components;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
|
||||
namespace AIStudio.Dialogs;
|
||||
|
||||
public partial class WorkspaceSelectionDialog : MSGComponentBase
|
||||
{
|
||||
private readonly record struct WorkspaceSelectionItem(Guid WorkspaceId, string Name);
|
||||
|
||||
[CascadingParameter]
|
||||
private IMudDialogInstance MudDialog { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
private IJSRuntime JsRuntime { get; init; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public string Message { get; set; } = string.Empty;
|
||||
|
||||
@ -18,8 +24,18 @@ public partial class WorkspaceSelectionDialog : MSGComponentBase
|
||||
[Parameter]
|
||||
public string ConfirmText { get; set; } = "OK";
|
||||
|
||||
private readonly Dictionary<string, Guid> workspaces = new();
|
||||
private readonly List<WorkspaceSelectionItem> workspaces = [];
|
||||
private readonly string escapeHandlerId = $"workspace-selection-dialog-{Guid.NewGuid():N}";
|
||||
private MudForm? createWorkspaceForm;
|
||||
private MudTextField<string>? newWorkspaceNameField;
|
||||
private DotNetObjectReference<WorkspaceSelectionDialog>? dotNetReference;
|
||||
private Guid selectedWorkspace;
|
||||
private string newWorkspaceName = string.Empty;
|
||||
private bool isCreatingWorkspace;
|
||||
private bool showCreateWorkspaceForm;
|
||||
private bool shouldFocusNewWorkspaceName;
|
||||
private string? createWorkspaceError;
|
||||
private string? createWorkspaceErrorName;
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
@ -29,15 +45,156 @@ public partial class WorkspaceSelectionDialog : MSGComponentBase
|
||||
|
||||
var snapshot = await WorkspaceBehaviour.GetOrLoadWorkspaceTreeShellAsync();
|
||||
foreach (var workspace in snapshot.Workspaces)
|
||||
this.workspaces[workspace.Name] = workspace.WorkspaceId;
|
||||
this.workspaces.Add(new(workspace.WorkspaceId, workspace.Name));
|
||||
|
||||
this.StateHasChanged();
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
this.dotNetReference = DotNetObjectReference.Create(this);
|
||||
await this.JsRuntime.InvokeVoidAsync("registerEscapeHandler", this.escapeHandlerId, this.dotNetReference);
|
||||
}
|
||||
|
||||
if (this.shouldFocusNewWorkspaceName && this.newWorkspaceNameField is not null)
|
||||
{
|
||||
this.shouldFocusNewWorkspaceName = false;
|
||||
await this.newWorkspaceNameField.FocusAsync();
|
||||
}
|
||||
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void Cancel() => this.MudDialog.Cancel();
|
||||
private string? ValidateNewWorkspaceName(string? workspaceName)
|
||||
{
|
||||
var normalizedWorkspaceName = WorkspaceBehaviour.NormalizeWorkspaceName(workspaceName ?? string.Empty);
|
||||
if (string.IsNullOrWhiteSpace(normalizedWorkspaceName))
|
||||
return T("Please enter a workspace name.");
|
||||
|
||||
if (this.IsWorkspaceNameExisting(normalizedWorkspaceName))
|
||||
return T("There is already a workspace with this name. Please choose a different name.");
|
||||
|
||||
if (this.createWorkspaceError is not null && string.Equals(this.createWorkspaceErrorName, normalizedWorkspaceName, StringComparison.OrdinalIgnoreCase))
|
||||
return this.createWorkspaceError;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool IsWorkspaceNameExisting(string normalizedWorkspaceName)
|
||||
{
|
||||
return this.workspaces.Any(workspace =>
|
||||
string.Equals(WorkspaceBehaviour.NormalizeWorkspaceName(workspace.Name), normalizedWorkspaceName, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private async Task HandleNewWorkspaceNameKeyDown(KeyboardEventArgs keyEvent)
|
||||
{
|
||||
var key = keyEvent.Key.ToLowerInvariant();
|
||||
var code = keyEvent.Code.ToLowerInvariant();
|
||||
if (key is not "enter" && code is not "enter" and not "numpadenter")
|
||||
return;
|
||||
|
||||
if (keyEvent is { AltKey: true } or { CtrlKey: true } or { MetaKey: true })
|
||||
return;
|
||||
|
||||
await this.CreateWorkspaceAsync();
|
||||
}
|
||||
|
||||
private void ShowCreateWorkspaceForm()
|
||||
{
|
||||
this.createWorkspaceError = null;
|
||||
this.createWorkspaceErrorName = null;
|
||||
this.newWorkspaceName = string.Empty;
|
||||
this.showCreateWorkspaceForm = true;
|
||||
this.shouldFocusNewWorkspaceName = true;
|
||||
}
|
||||
|
||||
private async Task CreateWorkspaceAsync()
|
||||
{
|
||||
if (this.createWorkspaceForm is null)
|
||||
return;
|
||||
|
||||
this.createWorkspaceError = null;
|
||||
this.createWorkspaceErrorName = null;
|
||||
await this.createWorkspaceForm.Validate();
|
||||
if (!this.createWorkspaceForm.IsValid)
|
||||
return;
|
||||
|
||||
this.isCreatingWorkspace = true;
|
||||
try
|
||||
{
|
||||
var result = await WorkspaceBehaviour.TryCreateWorkspaceAsync(this.newWorkspaceName);
|
||||
if (!result.Success)
|
||||
{
|
||||
this.createWorkspaceError = T("There is already a workspace with this name. Please choose a different name.");
|
||||
this.createWorkspaceErrorName = WorkspaceBehaviour.NormalizeWorkspaceName(this.newWorkspaceName);
|
||||
await this.createWorkspaceForm.Validate();
|
||||
return;
|
||||
}
|
||||
|
||||
this.workspaces.Add(new(result.Workspace.WorkspaceId, result.Workspace.Name));
|
||||
this.selectedWorkspace = result.Workspace.WorkspaceId;
|
||||
this.newWorkspaceName = string.Empty;
|
||||
this.createWorkspaceForm?.ResetValidation();
|
||||
this.showCreateWorkspaceForm = false;
|
||||
await this.SendMessage(Event.WORKSPACE_CREATED, result.Workspace.WorkspaceId);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.isCreatingWorkspace = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void Cancel()
|
||||
{
|
||||
if (!this.showCreateWorkspaceForm)
|
||||
{
|
||||
this.MudDialog.Cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
this.createWorkspaceError = null;
|
||||
this.createWorkspaceErrorName = null;
|
||||
this.newWorkspaceName = string.Empty;
|
||||
this.createWorkspaceForm?.ResetValidation();
|
||||
this.showCreateWorkspaceForm = false;
|
||||
this.shouldFocusNewWorkspaceName = false;
|
||||
}
|
||||
|
||||
[JSInvokable]
|
||||
public async Task HandleEscapeKeyAsync()
|
||||
{
|
||||
await this.InvokeAsync(() =>
|
||||
{
|
||||
this.Cancel();
|
||||
this.StateHasChanged();
|
||||
});
|
||||
}
|
||||
|
||||
private void Confirm() => this.MudDialog.Close(DialogResult.Ok(this.selectedWorkspace));
|
||||
|
||||
#region Overrides of MSGComponentBase
|
||||
|
||||
protected override void DisposeResources()
|
||||
{
|
||||
try
|
||||
{
|
||||
_ = this.JsRuntime.InvokeVoidAsync("unregisterEscapeHandler", this.escapeHandlerId).AsTask();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore JS cleanup errors while the dialog is being disposed.
|
||||
}
|
||||
|
||||
this.dotNetReference?.Dispose();
|
||||
this.dotNetReference = null;
|
||||
|
||||
base.DisposeResources();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -58,6 +58,7 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, ILan
|
||||
private MudThemeProvider themeProvider = null!;
|
||||
private bool useDarkMode;
|
||||
private bool startupCompleted;
|
||||
private bool settingsWriteProtectionWarningShown;
|
||||
private readonly SemaphoreSlim mandatoryInfoDialogSemaphore = new(1, 1);
|
||||
|
||||
private IReadOnlyCollection<NavBarItem> navItems = [];
|
||||
@ -127,6 +128,39 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, ILan
|
||||
|
||||
#endregion
|
||||
|
||||
private void ShowSettingsWriteProtectionWarning()
|
||||
{
|
||||
if(!this.SettingsManager.SettingsWriteBlocked || this.settingsWriteProtectionWarningShown)
|
||||
return;
|
||||
|
||||
this.settingsWriteProtectionWarningShown = true;
|
||||
var reason = this.SettingsManager.SettingsWriteBlockReason;
|
||||
var message = reason switch
|
||||
{
|
||||
SettingsWriteBlockReason.VERSION_NEWER_THAN_APP => T("Your settings were created by a newer AI Studio version. Changes in this session will not be saved. Please install or start the latest available update."),
|
||||
SettingsWriteBlockReason.VERSION_MISSING => T("Your settings file does not contain a settings-format version. Changes in this session will not be saved to avoid overwriting your settings. Please check for updates or contact support."),
|
||||
SettingsWriteBlockReason.VERSION_UNKNOWN => T("AI Studio does not recognize your settings-format version. Changes in this session will not be saved to avoid overwriting your settings. Please check for updates or contact support."),
|
||||
SettingsWriteBlockReason.FILE_UNREADABLE => T("AI Studio could not read your settings file. Changes in this session will not be saved to avoid overwriting recoverable settings. Please check for updates or contact support."),
|
||||
SettingsWriteBlockReason.CURRENT_VERSION_INVALID => T("AI Studio found the current settings format but could not load it safely. Changes in this session will not be saved. Please check for updates or contact support."),
|
||||
_ => T("AI Studio cannot safely save settings in this session. Please check for updates or contact support."),
|
||||
};
|
||||
message = $"{message} {T("Reason")}: {reason}";
|
||||
|
||||
this.Snackbar.Add(message, Severity.Warning, config =>
|
||||
{
|
||||
config.Icon = Icons.Material.Filled.WarningAmber;
|
||||
config.IconSize = Size.Large;
|
||||
config.VisibleStateDuration = 32_000;
|
||||
config.HideTransitionDuration = 600;
|
||||
config.Action = T("Check for updates");
|
||||
config.ActionVariant = Variant.Filled;
|
||||
config.OnClick = async _ =>
|
||||
{
|
||||
await this.MessageBus.SendMessage<bool>(this, Event.USER_SEARCH_FOR_UPDATE);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
#region Implementation of ILang
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -276,6 +310,7 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, ILan
|
||||
case Event.PLUGINS_RELOADED:
|
||||
this.Lang = await this.SettingsManager.GetActiveLanguagePlugin();
|
||||
I18N.Init(this.Lang);
|
||||
this.ShowSettingsWriteProtectionWarning();
|
||||
this.LoadNavItems();
|
||||
|
||||
await this.InvokeAsync(this.StateHasChanged);
|
||||
|
||||
@ -50,10 +50,9 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CodeBeam.MudBlazor.Extensions" Version="8.3.0" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.12.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="9.0.16" />
|
||||
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="9.0.17" />
|
||||
<PackageReference Include="MudBlazor" Version="8.15.0" />
|
||||
<PackageReference Include="MudBlazor.Markdown" Version="8.11.0" />
|
||||
<PackageReference Include="Qdrant.Client" Version="1.18.1" />
|
||||
<PackageReference Include="ReverseMarkdown" Version="5.0.0" />
|
||||
<PackageReference Include="LuaCSharp" Version="0.5.5" />
|
||||
</ItemGroup>
|
||||
@ -88,7 +87,7 @@
|
||||
<MetaAppCommitHash>$([System.String]::Copy( $(Metadata) ).Split( ';' )[ 8 ])</MetaAppCommitHash>
|
||||
<MetaArchitecture>$([System.String]::Copy( $(Metadata) ).Split( ';' )[ 9 ])</MetaArchitecture>
|
||||
<MetaPdfiumVersion>$([System.String]::Copy( $(Metadata) ).Split( ';' )[ 10 ])</MetaPdfiumVersion>
|
||||
<MetaQdrantVersion>$([System.String]::Copy( $(Metadata) ).Split( ';' )[ 11 ])</MetaQdrantVersion>
|
||||
<MetaVectorStoreVersion>$([System.String]::Copy( $(Metadata) ).Split( ';' )[ 11 ])</MetaVectorStoreVersion>
|
||||
|
||||
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
||||
|
||||
@ -116,8 +115,8 @@
|
||||
<AssemblyAttribute Include="AIStudio.Tools.Metadata.MetaDataLibraries">
|
||||
<_Parameter1>$(MetaPdfiumVersion)</_Parameter1>
|
||||
</AssemblyAttribute>
|
||||
<AssemblyAttribute Include="AIStudio.Tools.Metadata.MetaDataDatabases">
|
||||
<_Parameter1>$(MetaQdrantVersion)</_Parameter1>
|
||||
<AssemblyAttribute Include="AIStudio.Tools.Metadata.MetaDataVectorStore">
|
||||
<_Parameter1>$(MetaVectorStoreVersion)</_Parameter1>
|
||||
</AssemblyAttribute>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@ -51,13 +51,16 @@
|
||||
<MudTooltip Text="@T("Reload your workspaces")" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Refresh" Size="Size.Medium" OnClick="@this.RefreshWorkspaces"/>
|
||||
</MudTooltip>
|
||||
<MudTooltip Text="@this.WorkspaceSearchTooltip" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
|
||||
<MudIconButton Icon="@this.WorkspaceSearchIcon" Size="Size.Medium" OnClick="@this.ToggleWorkspaceSearch"/>
|
||||
</MudTooltip>
|
||||
<MudTooltip Text="@T("Hide your workspaces")" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
|
||||
<MudIconButton Size="Size.Medium" Icon="@this.WorkspaceSidebarToggleIcon" Class="me-1" OnClick="@(() => this.ToggleWorkspaceSidebar())"/>
|
||||
</MudTooltip>
|
||||
</MudStack>
|
||||
</HeaderContent>
|
||||
<ChildContent>
|
||||
<Workspaces @ref="this.workspaces" @bind-CurrentChatThread="@this.chatThread"/>
|
||||
<Workspaces @ref="this.workspaces" @bind-CurrentChatThread="@this.chatThread" @bind-SearchVisible="@this.workspaceSearchVisible"/>
|
||||
</ChildContent>
|
||||
</InnerScrolling>
|
||||
}
|
||||
@ -77,10 +80,13 @@
|
||||
<MudTooltip Text="@T("Reload your workspaces")" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Refresh" Size="Size.Medium" OnClick="@this.RefreshWorkspaces"/>
|
||||
</MudTooltip>
|
||||
<MudTooltip Text="@this.WorkspaceSearchTooltip" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
|
||||
<MudIconButton Icon="@this.WorkspaceSearchIcon" Size="Size.Medium" OnClick="@this.ToggleWorkspaceSearch"/>
|
||||
</MudTooltip>
|
||||
</MudStack>
|
||||
</HeaderContent>
|
||||
<ChildContent>
|
||||
<Workspaces @ref="this.workspaces" @bind-CurrentChatThread="@this.chatThread"/>
|
||||
<Workspaces @ref="this.workspaces" @bind-CurrentChatThread="@this.chatThread" @bind-SearchVisible="@this.workspaceSearchVisible"/>
|
||||
</ChildContent>
|
||||
</InnerScrolling>
|
||||
}
|
||||
@ -149,11 +155,14 @@
|
||||
<MudTooltip Text="@T("Reload your workspaces")" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Refresh" Size="Size.Medium" OnClick="@this.RefreshWorkspaces"/>
|
||||
</MudTooltip>
|
||||
<MudTooltip Text="@this.WorkspaceSearchTooltip" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
|
||||
<MudIconButton Icon="@this.WorkspaceSearchIcon" Size="Size.Medium" OnClick="@this.ToggleWorkspaceSearch"/>
|
||||
</MudTooltip>
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Close" Color="Color.Error" Size="Size.Medium" OnClick="@(() => this.ToggleWorkspacesOverlay())"/>
|
||||
</MudStack>
|
||||
</MudDrawerHeader>
|
||||
<MudDrawerContainer Class="ml-6">
|
||||
<Workspaces @ref="this.workspaces" @bind-CurrentChatThread="@this.chatThread"/>
|
||||
<Workspaces @ref="this.workspaces" @bind-CurrentChatThread="@this.chatThread" @bind-SearchVisible="@this.workspaceSearchVisible"/>
|
||||
</MudDrawerContainer>
|
||||
</MudDrawer>
|
||||
}
|
||||
|
||||
@ -23,6 +23,7 @@ public partial class Chat : MSGComponentBase
|
||||
private ChatThread? chatThread;
|
||||
private AIStudio.Settings.Provider providerSettings = AIStudio.Settings.Provider.NONE;
|
||||
private bool workspaceOverlayVisible;
|
||||
private bool workspaceSearchVisible;
|
||||
private string currentWorkspaceName = string.Empty;
|
||||
private Workspaces? workspaces;
|
||||
private double splitterPosition = 30;
|
||||
@ -51,6 +52,10 @@ public partial class Chat : MSGComponentBase
|
||||
|
||||
private string WorkspaceSidebarToggleIcon => this.SettingsManager.ConfigurationData.Workspace.IsSidebarVisible ? Icons.Material.Filled.ArrowCircleLeft : Icons.Material.Filled.ArrowCircleRight;
|
||||
|
||||
private string WorkspaceSearchIcon => this.workspaceSearchVisible ? Icons.Material.Filled.SearchOff : Icons.Material.Filled.Search;
|
||||
|
||||
private string WorkspaceSearchTooltip => this.workspaceSearchVisible ? T("Hide search") : T("Search your workspaces");
|
||||
|
||||
private bool AreWorkspacesVisible => this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is not WorkspaceStorageBehavior.DISABLE_WORKSPACES
|
||||
&& ((this.SettingsManager.ConfigurationData.Workspace.DisplayBehavior is WorkspaceDisplayBehavior.TOGGLE_SIDEBAR && this.SettingsManager.ConfigurationData.Workspace.IsSidebarVisible)
|
||||
|| this.SettingsManager.ConfigurationData.Workspace.DisplayBehavior is WorkspaceDisplayBehavior.SIDEBAR_ALWAYS_VISIBLE);
|
||||
@ -107,6 +112,14 @@ public partial class Chat : MSGComponentBase
|
||||
await this.workspaces.ForceRefreshFromDiskAsync();
|
||||
}
|
||||
|
||||
private async Task ToggleWorkspaceSearch()
|
||||
{
|
||||
if (this.workspaces is null)
|
||||
return;
|
||||
|
||||
await this.workspaces.ToggleSearchAsync();
|
||||
}
|
||||
|
||||
#region Overrides of MSGComponentBase
|
||||
|
||||
protected override void DisposeResources()
|
||||
|
||||
@ -8,36 +8,52 @@
|
||||
</MudText>
|
||||
|
||||
<InnerScrolling>
|
||||
<MudExpansionPanels Class="mb-3" MultiExpansion="@false">
|
||||
<MudExpansionPanels @key="@this.expansionPanelsRenderKey" Class="mb-3" MultiExpansion="@false">
|
||||
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.MenuBook" HeaderText="@T("Introduction")" IsExpanded="@true">
|
||||
<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>
|
||||
}
|
||||
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.EventNote" HeaderText="@T("Last Changelog")">
|
||||
@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>
|
||||
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.Lightbulb" HeaderText="@T("Vision")">
|
||||
<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>
|
||||
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.RocketLaunch" HeaderText="@T("Quick Start Guide")">
|
||||
<MudMarkdown Props="Markdown.DefaultConfig" Value="@QUICK_START_GUIDE" MarkdownPipeline="Markdown.SAFE_MARKDOWN_PIPELINE"/>
|
||||
</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>
|
||||
}
|
||||
|
||||
</MudExpansionPanels>
|
||||
</InnerScrolling>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using AIStudio.Components;
|
||||
using AIStudio.Settings.DataModel;
|
||||
using AIStudio.Tools.PluginSystem;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
@ -18,13 +19,25 @@ public partial class Home : MSGComponentBase
|
||||
private string LastChangeContent { get; set; } = string.Empty;
|
||||
|
||||
private TextItem[] itemsAdvantages = [];
|
||||
|
||||
private List<DataIntroduction> introductions = [];
|
||||
|
||||
private string expandedPanelId = string.Empty;
|
||||
private int expansionPanelsRenderKey;
|
||||
|
||||
private const string PANEL_ID_BUILT_IN_INTRODUCTION = "built-in-introduction";
|
||||
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()
|
||||
{
|
||||
this.ApplyFilters([], [ Event.CONFIGURATION_CHANGED ]);
|
||||
await base.OnInitializedAsync();
|
||||
this.InitializeAdvantagesItems();
|
||||
this.RefreshIntroductionPanels();
|
||||
this.EnsureDefaultExpandedPanel();
|
||||
|
||||
// Read the last change content asynchronously
|
||||
// without blocking the UI thread:
|
||||
@ -69,6 +82,14 @@ public partial class Home : MSGComponentBase
|
||||
{
|
||||
case Event.PLUGINS_RELOADED:
|
||||
this.InitializeAdvantagesItems();
|
||||
this.RefreshIntroductionPanels();
|
||||
this.EnsureDefaultExpandedPanel();
|
||||
await this.InvokeAsync(this.StateHasChanged);
|
||||
break;
|
||||
|
||||
case Event.CONFIGURATION_CHANGED:
|
||||
this.RefreshIntroductionPanels();
|
||||
this.EnsureDefaultExpandedPanel();
|
||||
await this.InvokeAsync(this.StateHasChanged);
|
||||
break;
|
||||
}
|
||||
@ -76,6 +97,42 @@ public partial class Home : MSGComponentBase
|
||||
|
||||
#endregion
|
||||
|
||||
private void RefreshIntroductionPanels()
|
||||
{
|
||||
this.introductions = PluginFactory.GetIntroductions().ToList();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private void EnsureDefaultExpandedPanel()
|
||||
{
|
||||
this.expandedPanelId = this.GetDefaultExpandedPanelId();
|
||||
this.expansionPanelsRenderKey++;
|
||||
}
|
||||
|
||||
private bool IsPanelExpanded(string panelId) => string.Equals(this.expandedPanelId, panelId, StringComparison.Ordinal);
|
||||
|
||||
private Task SetPanelExpanded(string panelId, bool isExpanded)
|
||||
{
|
||||
if (isExpanded)
|
||||
this.expandedPanelId = panelId;
|
||||
else if (this.IsPanelExpanded(panelId))
|
||||
this.expandedPanelId = string.Empty;
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private static string IntroductionPanelId(DataIntroduction introduction) => $"introduction:{introduction.Id}";
|
||||
|
||||
private async Task ReadLastChangeAsync()
|
||||
{
|
||||
var latest = Changelog.LOGS.MaxBy(n => n.Build);
|
||||
|
||||
@ -21,11 +21,11 @@
|
||||
<MudListItem T="string" Icon="@Icons.Material.Outlined.Build" Text="@this.VersionRust"/>
|
||||
<MudListItem T="string" Icon="@Icons.Material.Outlined.Storage">
|
||||
<MudText Typo="Typo.body1">
|
||||
@this.VersionDatabase
|
||||
@this.VersionVectorStore
|
||||
</MudText>
|
||||
<MudCollapse Expanded="@this.showDatabaseDetails">
|
||||
<MudCollapse Expanded="@this.showVectorStoreDetails">
|
||||
<MudText Typo="Typo.body1" Class="mt-2 mb-2">
|
||||
@foreach (var item in this.databaseDisplayInfo)
|
||||
@foreach (var item in this.vectorStoreDisplayInfo)
|
||||
{
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<MudIcon Icon="@Icons.Material.Filled.ArrowRightAlt"/>
|
||||
@ -35,11 +35,11 @@
|
||||
}
|
||||
</MudText>
|
||||
</MudCollapse>
|
||||
<MudButton StartIcon="@(this.showDatabaseDetails ? Icons.Material.Filled.ExpandLess : Icons.Material.Filled.ExpandMore)"
|
||||
<MudButton StartIcon="@(this.showVectorStoreDetails ? Icons.Material.Filled.ExpandLess : Icons.Material.Filled.ExpandMore)"
|
||||
Size="Size.Small"
|
||||
Variant="Variant.Text"
|
||||
OnClick="@this.ToggleDatabaseDetails">
|
||||
@(this.showDatabaseDetails ? T("Hide Details") : T("Show Details"))
|
||||
OnClick="@this.ToggleVectorStoreDetails">
|
||||
@(this.showVectorStoreDetails ? T("Hide Details") : T("Show Details"))
|
||||
</MudButton>
|
||||
</MudListItem>
|
||||
<MudListItem T="string" Icon="@Icons.Material.Outlined.DocumentScanner" Text="@this.VersionPdfium"/>
|
||||
@ -48,6 +48,26 @@
|
||||
<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.Folder">
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<MudText Typo="Typo.body1">
|
||||
@this.WorkingDirectory
|
||||
</MudText>
|
||||
<MudCopyClipboardButton TooltipMessage="@(T("Copies the working directory to the clipboard"))" StringContent="@this.runtimeInfo.WorkingDirectory"/>
|
||||
</div>
|
||||
</MudListItem>
|
||||
<MudListItem T="string" Icon="@Icons.Material.Filled.InsertDriveFile">
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<MudText Typo="Typo.body1">
|
||||
@this.ExecutablePath
|
||||
</MudText>
|
||||
<MudCopyClipboardButton TooltipMessage="@(T("Copies the executable path to the clipboard"))" StringContent="@this.runtimeInfo.ExecutablePath"/>
|
||||
</div>
|
||||
</MudListItem>
|
||||
@if (OperatingSystem.IsLinux())
|
||||
{
|
||||
<MudListItem T="string" Icon="@Icons.Material.Outlined.Storage" Text="@this.LinuxPackageType"/>
|
||||
}
|
||||
<MudListItem T="string" Icon="@Icons.Material.Outlined.Business">
|
||||
@switch (HasAnyActiveEnvironment)
|
||||
{
|
||||
@ -89,18 +109,7 @@
|
||||
{
|
||||
<ConfigPluginInfoCard HeaderIcon="@Icons.Material.Filled.HourglassBottom"
|
||||
HeaderText="@T("Waiting for the configuration plugin...")"
|
||||
Items="@([
|
||||
new ConfigInfoRowItem(Icons.Material.Filled.ArrowRightAlt,
|
||||
$"{T("Enterprise configuration ID:")} {env.ConfigurationId}",
|
||||
env.ConfigurationId.ToString(),
|
||||
T("Copies the config ID to the clipboard")),
|
||||
|
||||
new ConfigInfoRowItem(Icons.Material.Filled.ArrowRightAlt,
|
||||
$"{T("Configuration server:")} {env.ConfigurationServerUrl}",
|
||||
env.ConfigurationServerUrl,
|
||||
T("Copies the server URL to the clipboard"),
|
||||
"margin-top: 4px;")
|
||||
])"/>
|
||||
Items="@this.BuildEnterpriseConfigurationItems(env)"/>
|
||||
}
|
||||
|
||||
<EncryptionSecretInfo IsConfigured="@(PluginFactory.EnterpriseEncryption?.IsAvailable is true)"
|
||||
@ -130,41 +139,13 @@
|
||||
{
|
||||
<ConfigPluginInfoCard HeaderIcon="@Icons.Material.Filled.HourglassBottom"
|
||||
HeaderText="@T("Waiting for the configuration plugin...")"
|
||||
Items="@([
|
||||
new ConfigInfoRowItem(Icons.Material.Filled.ArrowRightAlt,
|
||||
$"{T("Enterprise configuration ID:")} {env.ConfigurationId}",
|
||||
env.ConfigurationId.ToString(),
|
||||
T("Copies the config ID to the clipboard")),
|
||||
|
||||
new ConfigInfoRowItem(Icons.Material.Filled.ArrowRightAlt,
|
||||
$"{T("Configuration server:")} {env.ConfigurationServerUrl}",
|
||||
env.ConfigurationServerUrl,
|
||||
T("Copies the server URL to the clipboard"),
|
||||
"margin-top: 4px;")
|
||||
])"/>
|
||||
Items="@this.BuildEnterpriseConfigurationItems(env)"/>
|
||||
continue;
|
||||
}
|
||||
|
||||
<ConfigPluginInfoCard HeaderIcon="@Icons.Material.Filled.Extension"
|
||||
HeaderText="@matchingPlugin.Name"
|
||||
Items="@([
|
||||
new ConfigInfoRowItem(Icons.Material.Filled.ArrowRightAlt,
|
||||
$"{T("Enterprise configuration ID:")} {env.ConfigurationId}",
|
||||
env.ConfigurationId.ToString(),
|
||||
T("Copies the config ID to the clipboard")),
|
||||
|
||||
new ConfigInfoRowItem(Icons.Material.Filled.ArrowRightAlt,
|
||||
$"{T("Configuration server:")} {env.ConfigurationServerUrl}",
|
||||
env.ConfigurationServerUrl,
|
||||
T("Copies the server URL to the clipboard"),
|
||||
"margin-top: 4px;"),
|
||||
|
||||
new ConfigInfoRowItem(Icons.Material.Filled.ArrowRightAlt,
|
||||
$"{T("Configuration plugin ID:")} {matchingPlugin.Id}",
|
||||
matchingPlugin.Id.ToString(),
|
||||
T("Copies the configuration plugin ID to the clipboard"),
|
||||
"margin-top: 4px;")
|
||||
])"
|
||||
Items="@this.BuildEnterpriseConfigurationItems(env, matchingPlugin)"
|
||||
ShowWarning="@this.IsManagedConfigurationIdMismatch(matchingPlugin, env.ConfigurationId)"
|
||||
WarningText="@T("ID mismatch: the plugin ID differs from the enterprise configuration ID.")"/>
|
||||
}
|
||||
@ -186,9 +167,32 @@
|
||||
</MudButton>
|
||||
}
|
||||
</MudListItem>
|
||||
@if (ExternalHttpClientTimeout.CustomRootCertificateState.IsEnabled)
|
||||
{
|
||||
<MudListItem T="string" Icon="@Icons.Material.Outlined.Security">
|
||||
<MudText Typo="Typo.body1">
|
||||
@(ExternalHttpClientTimeout.CustomRootCertificateState.IsUsable
|
||||
? T("External HTTPS custom root certificates are active.")
|
||||
: T("External HTTPS custom root certificates are configured but not active."))
|
||||
</MudText>
|
||||
<MudCollapse Expanded="@this.showExternalHttpCustomRootCertificateDetails">
|
||||
<ConfigPluginInfoCard HeaderIcon="@Icons.Material.Filled.Security"
|
||||
HeaderText="@T("External HTTPS custom root certificates")"
|
||||
Items="@this.BuildExternalHttpCustomRootCertificateItems()"
|
||||
ShowWarning="@(!ExternalHttpClientTimeout.CustomRootCertificateState.IsUsable)"
|
||||
WarningText="@this.ExternalHttpCustomRootCertificateWarningText"/>
|
||||
</MudCollapse>
|
||||
<MudButton StartIcon="@(this.showExternalHttpCustomRootCertificateDetails ? Icons.Material.Filled.ExpandLess : Icons.Material.Filled.ExpandMore)"
|
||||
Size="Size.Small"
|
||||
Variant="Variant.Text"
|
||||
OnClick="@this.ToggleExternalHttpCustomRootCertificateDetails">
|
||||
@(this.showExternalHttpCustomRootCertificateDetails ? T("Hide Details") : T("Show Details"))
|
||||
</MudButton>
|
||||
</MudListItem>
|
||||
}
|
||||
</MudList>
|
||||
<MudStack Row="true">
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Info" StartIcon="@Icons.Material.Filled.Update" OnClick="@(() => this.CheckForUpdate())">
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Info" StartIcon="@Icons.Material.Filled.Update" OnClick="@this.CheckForUpdate">
|
||||
@T("Check for updates")
|
||||
</MudButton>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Default" StartIcon="@Icons.Material.Filled.Download" OnClick="@(async () => await this.ShowPandocDialog())">
|
||||
@ -285,7 +289,7 @@
|
||||
<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="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.")"/>
|
||||
<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.")"/>
|
||||
@ -310,7 +314,7 @@
|
||||
<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="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 in runtime tests and supporting filesystem operations.")"/>
|
||||
<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.")" />
|
||||
<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.")"/>
|
||||
|
||||
@ -4,6 +4,7 @@ using AIStudio.Components;
|
||||
using AIStudio.Dialogs;
|
||||
using AIStudio.Settings.DataModel;
|
||||
using AIStudio.Tools.Databases;
|
||||
using AIStudio.Tools.Databases.VectorStore;
|
||||
using AIStudio.Tools.Metadata;
|
||||
using AIStudio.Tools.PluginSystem;
|
||||
using AIStudio.Tools.Rust;
|
||||
@ -35,12 +36,13 @@ public partial class Information : MSGComponentBase
|
||||
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 MetaDataVectorStoreAttribute META_DATA_VECTOR_STORE = ASSEMBLY.GetCustomAttribute<MetaDataVectorStoreAttribute>()!;
|
||||
|
||||
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 RuntimeInfoResponse runtimeInfo;
|
||||
|
||||
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()})";
|
||||
|
||||
@ -52,6 +54,20 @@ 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 ExecutablePath => $"{T("Executable path")}: {this.runtimeInfo.ExecutablePath}";
|
||||
|
||||
private string LinuxPackageType => $"{T("Linux package")}: {this.LinuxPackageTypeDisplayName}";
|
||||
|
||||
private string LinuxPackageTypeDisplayName => this.runtimeInfo.LinuxPackageType switch
|
||||
{
|
||||
"appimage" => "AppImage",
|
||||
"flatpak" => "Flatpak",
|
||||
"unknown" => T("unknown"),
|
||||
_ => T("not applicable")
|
||||
};
|
||||
|
||||
private string VersionRust => $"{T("Used Rust compiler")}: v{META_DATA.RustVersion}";
|
||||
|
||||
private string VersionDotnetRuntime => $"{T("Used .NET runtime")}: v{META_DATA.DotnetVersion}";
|
||||
@ -62,18 +78,18 @@ public partial class Information : MSGComponentBase
|
||||
|
||||
private string VersionPdfium => $"{T("Used PDFium version")}: v{META_DATA_LIBRARIES.PdfiumVersion}";
|
||||
|
||||
private string VersionDatabase
|
||||
private string VersionVectorStore
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.databaseClient is null)
|
||||
return $"{T("Database")}: {T("checking availability")}";
|
||||
if (this.vectorStore is null)
|
||||
return $"{T("Vector store")}: {T("checking availability")}";
|
||||
|
||||
return this.databaseClient.Status switch
|
||||
return this.vectorStore.Status switch
|
||||
{
|
||||
DatabaseClientStatus.AVAILABLE => $"{T("Database version")}: {this.databaseClient.Name} v{META_DATA_DATABASES.DatabaseVersion}",
|
||||
DatabaseClientStatus.STARTING => $"{T("Database")}: {this.databaseClient.Name} - {T("starting")}",
|
||||
_ => $"{T("Database")}: {this.databaseClient.Name} - {T("not available")}"
|
||||
DatabaseClientStatus.AVAILABLE => $"{T("Vector store version")}: {this.vectorStore.Name} v{META_DATA_VECTOR_STORE.VectorStoreVersion}",
|
||||
DatabaseClientStatus.STARTING => $"{T("Vector store")}: {this.vectorStore.Name} - {T("starting")}",
|
||||
_ => $"{T("Vector store")}: {this.vectorStore.Name} - {T("not available")}"
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -85,7 +101,8 @@ public partial class Information : MSGComponentBase
|
||||
|
||||
private bool showEnterpriseConfigDetails;
|
||||
|
||||
private bool showDatabaseDetails;
|
||||
private bool showVectorStoreDetails;
|
||||
private bool showExternalHttpCustomRootCertificateDetails;
|
||||
|
||||
private List<IAvailablePlugin> configPlugins = PluginFactory.AvailablePlugins
|
||||
.Where(x => x.Type is PluginType.CONFIGURATION)
|
||||
@ -95,14 +112,13 @@ public partial class Information : MSGComponentBase
|
||||
private List<EnterpriseEnvironment> enterpriseEnvironments = EnterpriseEnvironmentService.CURRENT_ENVIRONMENTS.ToList();
|
||||
|
||||
private List<MandatoryInfoPanelData> mandatoryInfoPanels = [];
|
||||
|
||||
private sealed record DatabaseDisplayInfo(string Label, string Value);
|
||||
|
||||
private sealed record MandatoryInfoPanelData(string HeaderText, string PluginName, DataMandatoryInfo Info, DataMandatoryInfoAcceptance? Acceptance);
|
||||
|
||||
private readonly List<DatabaseDisplayInfo> databaseDisplayInfo = new();
|
||||
private DatabaseClient? databaseClient;
|
||||
private CancellationTokenSource? databaseRefreshCancellationTokenSource;
|
||||
|
||||
private sealed record VectorStoreDisplayInfo(string Label, string Value);
|
||||
private readonly List<VectorStoreDisplayInfo> vectorStoreDisplayInfo = new();
|
||||
private DatabaseClient? vectorStore;
|
||||
private CancellationTokenSource? vectorStoreRefreshCancellationTokenSource;
|
||||
|
||||
private bool HasAnyActiveEnvironment => this.enterpriseEnvironments.Any(e => e.IsActive);
|
||||
|
||||
@ -146,11 +162,12 @@ public partial class Information : MSGComponentBase
|
||||
|
||||
this.osLanguage = await this.RustService.ReadUserLanguage();
|
||||
this.osUserName = await this.RustService.ReadUserName();
|
||||
this.runtimeInfo = await this.RustService.GetRuntimeInfo();
|
||||
this.logPaths = await this.RustService.GetLogPaths();
|
||||
|
||||
await this.RefreshDatabaseInfo(CancellationToken.None);
|
||||
if (this.databaseClient?.Status is DatabaseClientStatus.STARTING)
|
||||
this.StartShortDatabaseRefreshLoop();
|
||||
await this.RefreshVectorStoreInfo(CancellationToken.None);
|
||||
if (this.vectorStore?.Status is DatabaseClientStatus.STARTING)
|
||||
this.StartShortVectorStoreRefreshLoop();
|
||||
|
||||
// Determine the Pandoc version may take some time, so we start it here
|
||||
// without waiting for the result:
|
||||
@ -248,23 +265,28 @@ public partial class Information : MSGComponentBase
|
||||
{
|
||||
this.showEnterpriseConfigDetails = !this.showEnterpriseConfigDetails;
|
||||
}
|
||||
|
||||
private void ToggleDatabaseDetails()
|
||||
|
||||
private void ToggleExternalHttpCustomRootCertificateDetails()
|
||||
{
|
||||
this.showDatabaseDetails = !this.showDatabaseDetails;
|
||||
this.showExternalHttpCustomRootCertificateDetails = !this.showExternalHttpCustomRootCertificateDetails;
|
||||
}
|
||||
|
||||
private void ToggleVectorStoreDetails()
|
||||
{
|
||||
this.showVectorStoreDetails = !this.showVectorStoreDetails;
|
||||
}
|
||||
|
||||
private async Task RefreshDatabaseInfo(CancellationToken cancellationToken)
|
||||
private async Task RefreshVectorStoreInfo(CancellationToken cancellationToken)
|
||||
{
|
||||
var refreshedClient = await this.DatabaseClientProvider.RefreshClientAsync(DatabaseRole.VECTOR_STORE, cancellationToken);
|
||||
this.databaseClient = refreshedClient;
|
||||
this.databaseDisplayInfo.Clear();
|
||||
this.vectorStore = refreshedClient;
|
||||
this.vectorStoreDisplayInfo.Clear();
|
||||
|
||||
try
|
||||
{
|
||||
await foreach (var (label, value) in refreshedClient.GetDisplayInfo().WithCancellation(cancellationToken))
|
||||
{
|
||||
this.databaseDisplayInfo.Add(new DatabaseDisplayInfo(label, value));
|
||||
this.vectorStoreDisplayInfo.Add(new VectorStoreDisplayInfo(label, value));
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
@ -273,20 +295,20 @@ public partial class Information : MSGComponentBase
|
||||
}
|
||||
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.vectorStore = new NoVectorStoreClient(refreshedClient.Name, e.Message, DatabaseClientStatus.STARTING);
|
||||
await foreach (var (label, value) in this.vectorStore.GetDisplayInfo().WithCancellation(cancellationToken))
|
||||
{
|
||||
this.databaseDisplayInfo.Add(new DatabaseDisplayInfo(label, value));
|
||||
this.vectorStoreDisplayInfo.Add(new VectorStoreDisplayInfo(label, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void StartShortDatabaseRefreshLoop()
|
||||
private void StartShortVectorStoreRefreshLoop()
|
||||
{
|
||||
this.databaseRefreshCancellationTokenSource?.Cancel();
|
||||
this.databaseRefreshCancellationTokenSource?.Dispose();
|
||||
this.databaseRefreshCancellationTokenSource = new CancellationTokenSource();
|
||||
var cancellationToken = this.databaseRefreshCancellationTokenSource.Token;
|
||||
this.vectorStoreRefreshCancellationTokenSource?.Cancel();
|
||||
this.vectorStoreRefreshCancellationTokenSource?.Dispose();
|
||||
this.vectorStoreRefreshCancellationTokenSource = new CancellationTokenSource();
|
||||
var cancellationToken = this.vectorStoreRefreshCancellationTokenSource.Token;
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
@ -298,11 +320,11 @@ public partial class Information : MSGComponentBase
|
||||
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
|
||||
await this.InvokeAsync(async () =>
|
||||
{
|
||||
await this.RefreshDatabaseInfo(cancellationToken);
|
||||
await this.RefreshVectorStoreInfo(cancellationToken);
|
||||
this.StateHasChanged();
|
||||
});
|
||||
|
||||
if (this.databaseClient?.Status is not DatabaseClientStatus.STARTING)
|
||||
if (this.vectorStore?.Status is not DatabaseClientStatus.STARTING)
|
||||
return;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
@ -324,15 +346,136 @@ public partial class Information : MSGComponentBase
|
||||
?? this.configPlugins.FirstOrDefault(plugin => plugin.ManagedConfigurationId is null && plugin.Id == configurationId);
|
||||
}
|
||||
|
||||
private IReadOnlyList<ConfigInfoRowItem> BuildEnterpriseConfigurationItems(EnterpriseEnvironment environment, IAvailablePlugin? plugin = null)
|
||||
{
|
||||
var items = new List<ConfigInfoRowItem>
|
||||
{
|
||||
new(Icons.Material.Filled.ArrowRightAlt,
|
||||
$"{T("Enterprise configuration ID:")} {environment.ConfigurationId}",
|
||||
environment.ConfigurationId.ToString(),
|
||||
T("Copies the config ID to the clipboard")),
|
||||
|
||||
new(Icons.Material.Filled.ArrowRightAlt,
|
||||
$"{T("Configuration server:")} {environment.ConfigurationServerUrl}",
|
||||
environment.ConfigurationServerUrl,
|
||||
T("Copies the server URL to the clipboard"),
|
||||
"margin-top: 4px;"),
|
||||
|
||||
new(Icons.Material.Filled.ArrowRightAlt,
|
||||
$"{T("Configuration source:")} {environment.Source}",
|
||||
environment.Source,
|
||||
T("Copies the configuration source to the clipboard"),
|
||||
"margin-top: 4px;"),
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(environment.SourceDetail))
|
||||
{
|
||||
items.Add(new ConfigInfoRowItem(Icons.Material.Filled.ArrowRightAlt,
|
||||
$"{T("Configuration origin:")} {environment.SourceDetail}",
|
||||
environment.SourceDetail,
|
||||
T("Copies the configuration origin to the clipboard"),
|
||||
"margin-top: 4px;"));
|
||||
}
|
||||
|
||||
items.Add(new ConfigInfoRowItem(Icons.Material.Filled.ArrowRightAlt,
|
||||
$"{T("Configuration slot:")} {environment.Slot}",
|
||||
environment.Slot,
|
||||
T("Copies the configuration slot to the clipboard"),
|
||||
"margin-top: 4px;"));
|
||||
|
||||
if (plugin is not null)
|
||||
{
|
||||
items.Add(new ConfigInfoRowItem(Icons.Material.Filled.ArrowRightAlt,
|
||||
$"{T("Configuration plugin ID:")} {plugin.Id}",
|
||||
plugin.Id.ToString(),
|
||||
T("Copies the configuration plugin ID to the clipboard"),
|
||||
"margin-top: 4px;"));
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
private bool IsManagedConfigurationIdMismatch(IAvailablePlugin plugin, Guid configurationId)
|
||||
{
|
||||
return plugin.ManagedConfigurationId == configurationId && plugin.Id != configurationId;
|
||||
}
|
||||
|
||||
private string ExternalHttpCustomRootCertificateWarningText
|
||||
{
|
||||
get
|
||||
{
|
||||
var state = ExternalHttpClientTimeout.CustomRootCertificateState;
|
||||
return string.IsNullOrWhiteSpace(state.Issue)
|
||||
? T("The configured root certificates could not be used.")
|
||||
: state.Issue;
|
||||
}
|
||||
}
|
||||
|
||||
private IReadOnlyList<ConfigInfoRowItem> BuildExternalHttpCustomRootCertificateItems()
|
||||
{
|
||||
var state = ExternalHttpClientTimeout.CustomRootCertificateState;
|
||||
var items = new List<ConfigInfoRowItem>
|
||||
{
|
||||
new(Icons.Material.Filled.ArrowRightAlt,
|
||||
$"{T("Status:")} {(state.IsUsable ? T("active") : T("not active"))}",
|
||||
state.IsUsable ? T("active") : T("not active"),
|
||||
T("Copies the status to the clipboard")),
|
||||
|
||||
new(Icons.Material.Filled.ArrowRightAlt,
|
||||
$"{T("Configuration source:")} {state.Source}",
|
||||
state.Source,
|
||||
T("Copies the configuration source to the clipboard"),
|
||||
"margin-top: 4px;"),
|
||||
|
||||
new(Icons.Material.Filled.ArrowRightAlt,
|
||||
$"{T("Certificate bundle:")} {state.BundlePath}",
|
||||
state.BundlePath,
|
||||
T("Copies the certificate bundle path to the clipboard"),
|
||||
"margin-top: 4px;"),
|
||||
|
||||
new(Icons.Material.Filled.ArrowRightAlt,
|
||||
$"{T("Loaded root certificates:")} {state.CertificateCount}",
|
||||
state.CertificateCount.ToString(),
|
||||
T("Copies the number of loaded root certificates to the clipboard"),
|
||||
"margin-top: 4px;")
|
||||
};
|
||||
|
||||
if (state.AllowedHostPatterns.Count == 0)
|
||||
{
|
||||
items.Add(new ConfigInfoRowItem(Icons.Material.Filled.ArrowRightAlt,
|
||||
T("Allowed hosts: none configured"),
|
||||
string.Empty,
|
||||
T("Copies the allowed host configuration to the clipboard"),
|
||||
"margin-top: 4px;"));
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var allowedHostPattern in state.AllowedHostPatterns)
|
||||
{
|
||||
items.Add(new ConfigInfoRowItem(Icons.Material.Filled.Dns,
|
||||
$"{T("Allowed host:")} {allowedHostPattern}",
|
||||
allowedHostPattern,
|
||||
T("Copies the allowed host pattern to the clipboard"),
|
||||
"margin-top: 4px;"));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var fingerprint in state.CertificateFingerprints)
|
||||
{
|
||||
items.Add(new ConfigInfoRowItem(Icons.Material.Filled.Fingerprint,
|
||||
$"{T("Root certificate fingerprint:")} {fingerprint}",
|
||||
fingerprint,
|
||||
T("Copies the root certificate fingerprint to the clipboard"),
|
||||
"margin-top: 4px;"));
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
protected override void DisposeResources()
|
||||
{
|
||||
this.databaseRefreshCancellationTokenSource?.Cancel();
|
||||
this.databaseRefreshCancellationTokenSource?.Dispose();
|
||||
this.vectorStoreRefreshCancellationTokenSource?.Cancel();
|
||||
this.vectorStoreRefreshCancellationTokenSource?.Dispose();
|
||||
base.DisposeResources();
|
||||
}
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
<InnerScrolling>
|
||||
<MudExpansionPanels Class="mb-3" MultiExpansion="@false">
|
||||
<SettingsPanelConfidence/>
|
||||
<SettingsPanelProviders @bind-AvailableLLMProviders="@this.availableLLMProviders"/>
|
||||
|
||||
@if (PreviewFeatures.PRE_RAG_2024.IsEnabled(this.SettingsManager))
|
||||
|
||||
@ -204,12 +204,16 @@ CONFIG["SETTINGS"] = {}
|
||||
-- but users can still choose another start page in the app settings.
|
||||
-- CONFIG["SETTINGS"]["DataApp.StartPage.AllowUserOverride"] = true
|
||||
|
||||
-- Configure whether the quick start guide is shown on the welcome page.
|
||||
-- CONFIG["SETTINGS"]["DataApp.ShowQuickStartGuide"] = false
|
||||
|
||||
-- Configure whether the built-in introduction is shown on the welcome page.
|
||||
-- CONFIG["SETTINGS"]["DataApp.ShowIntroduction"] = false
|
||||
|
||||
-- Configure the user permission to add providers:
|
||||
-- Allowed values are: true, false
|
||||
-- CONFIG["SETTINGS"]["DataApp.AllowUserToAddProvider"] = false
|
||||
|
||||
-- Configure whether administration settings are visible in the UI:
|
||||
-- Allowed values are: true, false
|
||||
-- CONFIG["SETTINGS"]["DataApp.ShowAdminSettings"] = true
|
||||
|
||||
-- Configure the visibility of preview features:
|
||||
@ -234,6 +238,32 @@ CONFIG["SETTINGS"] = {}
|
||||
-- Please note: using an empty string ("") will lock the preselected profile selection, even though no valid preselected profile is found.
|
||||
-- CONFIG["SETTINGS"]["DataApp.PreselectedProfile"] = "00000000-0000-0000-0000-000000000000"
|
||||
|
||||
-- Configure chat-specific preselected options.
|
||||
-- This must be enabled for the chat-specific provider, profile, and chat template to take effect.
|
||||
-- CONFIG["SETTINGS"]["DataChat.PreselectOptions"] = true
|
||||
--
|
||||
-- Configure the preselected provider for chats.
|
||||
-- It must be one of the provider IDs defined in CONFIG["LLM_PROVIDERS"].
|
||||
-- CONFIG["SETTINGS"]["DataChat.PreselectedProvider"] = "00000000-0000-0000-0000-000000000000"
|
||||
--
|
||||
-- Configure the preselected profile for chats.
|
||||
-- It must be one of the profile IDs defined in CONFIG["PROFILES"].
|
||||
-- Please note: using an empty string ("") means chats will use the app default profile.
|
||||
-- Please note: using "00000000-0000-0000-0000-000000000000" means chats will use no profile.
|
||||
-- CONFIG["SETTINGS"]["DataChat.PreselectedProfile"] = "00000000-0000-0000-0000-000000000000"
|
||||
--
|
||||
-- Configure the preselected chat template for chats.
|
||||
-- It must be one of the chat template IDs defined in CONFIG["CHAT_TEMPLATES"].
|
||||
-- Please note: using an empty string ("") or "00000000-0000-0000-0000-000000000000" means chats will use no chat template.
|
||||
-- CONFIG["SETTINGS"]["DataChat.PreselectedChatTemplate"] = "00000000-0000-0000-0000-000000000000"
|
||||
--
|
||||
-- Allow users to change any configured chat default locally.
|
||||
-- Allowed values are: true, false
|
||||
-- CONFIG["SETTINGS"]["DataChat.PreselectOptions.AllowUserOverride"] = true
|
||||
-- CONFIG["SETTINGS"]["DataChat.PreselectedProvider.AllowUserOverride"] = true
|
||||
-- CONFIG["SETTINGS"]["DataChat.PreselectedProfile.AllowUserOverride"] = true
|
||||
-- CONFIG["SETTINGS"]["DataChat.PreselectedChatTemplate.AllowUserOverride"] = true
|
||||
|
||||
-- Configure the transcription provider for voice-to-text functionality.
|
||||
-- It must be one of the transcription provider IDs defined in CONFIG["TRANSCRIPTION_PROVIDERS"].
|
||||
-- Without a selected transcription provider, dictation and transcription features will be disabled.
|
||||
@ -264,6 +294,85 @@ CONFIG["SETTINGS"] = {}
|
||||
-- The default is 3600 (1 hour).
|
||||
-- CONFIG["SETTINGS"]["DataApp.HttpClientTimeoutSeconds"] = 3600
|
||||
|
||||
-- Configure additional root certificates for external HTTPS requests.
|
||||
--
|
||||
-- This is intended for managed Linux/Flatpak deployments where organization-internal
|
||||
-- HTTPS certificates chain to a private root CA that is not visible inside the sandbox.
|
||||
-- The file must be a PEM bundle with one or more root CA certificates and must be
|
||||
-- readable by AI Studio.
|
||||
--
|
||||
-- IMPORTANT: A configuration plugin cannot fix the very first download of that same
|
||||
-- configuration plugin. For bootstrapping enterprise configuration downloads, deploy
|
||||
-- the equivalent environment variables before AI Studio starts:
|
||||
--
|
||||
-- MINDWORK_AI_STUDIO_EXTERNAL_HTTP_CUSTOM_ROOT_CERTIFICATES_ENABLED=true
|
||||
-- MINDWORK_AI_STUDIO_EXTERNAL_HTTP_CUSTOM_ROOT_CERTIFICATE_BUNDLE_PATH=/path/in/sandbox/company-root-cas.pem
|
||||
-- MINDWORK_AI_STUDIO_EXTERNAL_HTTP_CUSTOM_ROOT_CERTIFICATE_ALLOWED_HOSTS=*.intra.example.org;data.example.org
|
||||
--
|
||||
-- CONFIG["SETTINGS"]["DataApp.ExternalHttpCustomRootCertificatesEnabled"] = true
|
||||
-- CONFIG["SETTINGS"]["DataApp.ExternalHttpCustomRootCertificateBundlePath"] = "/path/in/sandbox/company-root-cas.pem"
|
||||
-- CONFIG["SETTINGS"]["DataApp.ExternalHttpCustomRootCertificateAllowedHosts"] = { "*.intra.example.org", "eri.example.org" }
|
||||
|
||||
-- Configure provider confidence settings.
|
||||
-- These settings apply to LLM providers, embedding providers, and transcription providers.
|
||||
--
|
||||
-- Configure a predefined confidence scheme.
|
||||
-- Allowed values are: TRUST_ALL, TRUST_USA_EUROPE, TRUST_USA, TRUST_EUROPE, TRUST_ASIA, LOCAL_TRUST_ONLY, CUSTOM
|
||||
-- CONFIG["SETTINGS"]["DataConfidence.ConfidenceScheme"] = "TRUST_EUROPE"
|
||||
--
|
||||
-- Configure whether users can still change the confidence scheme locally.
|
||||
-- Allowed values are: true, false
|
||||
-- When set to true, the configured confidence scheme becomes the organization default,
|
||||
-- but users can still choose another scheme in the app settings.
|
||||
-- CONFIG["SETTINGS"]["DataConfidence.ConfidenceScheme.AllowUserOverride"] = true
|
||||
--
|
||||
-- Configure whether confidence levels are shown in the UI.
|
||||
-- CONFIG["SETTINGS"]["DataConfidence.ShowProviderConfidence"] = true
|
||||
--
|
||||
-- Configure an app-wide minimum confidence level.
|
||||
-- Allowed values are: NONE, VERY_LOW, LOW, MODERATE, MEDIUM, HIGH
|
||||
-- CONFIG["SETTINGS"]["DataConfidence.EnforceGlobalMinimumConfidence"] = true
|
||||
-- CONFIG["SETTINGS"]["DataConfidence.GlobalMinimumConfidence"] = "MEDIUM"
|
||||
--
|
||||
-- Configure whether users can change the app-wide minimum confidence level locally.
|
||||
-- CONFIG["SETTINGS"]["DataConfidence.EnforceGlobalMinimumConfidence.AllowUserOverride"] = false
|
||||
-- CONFIG["SETTINGS"]["DataConfidence.GlobalMinimumConfidence.AllowUserOverride"] = false
|
||||
--
|
||||
-- Configure a custom confidence scheme.
|
||||
-- This is used when DataConfidence.ConfidenceScheme is set to CUSTOM.
|
||||
-- Allowed provider keys are: OPEN_AI, ANTHROPIC, MISTRAL, GOOGLE, X, DEEP_SEEK, ALIBABA_CLOUD,
|
||||
-- PERPLEXITY, OPEN_ROUTER, FIREWORKS, GROQ, HUGGINGFACE, SELF_HOSTED, HELMHOLTZ, GWDG
|
||||
-- Allowed confidence values are: UNTRUSTED, VERY_LOW, LOW, MODERATE, MEDIUM, HIGH
|
||||
-- CONFIG["SETTINGS"]["DataConfidence.CustomConfidenceScheme"] = {
|
||||
-- ["OPEN_AI"] = "MODERATE",
|
||||
-- ["ANTHROPIC"] = "MODERATE",
|
||||
-- ["MISTRAL"] = "HIGH",
|
||||
-- ["GOOGLE"] = "LOW",
|
||||
-- ["X"] = "LOW",
|
||||
-- ["DEEP_SEEK"] = "LOW",
|
||||
-- ["ALIBABA_CLOUD"] = "LOW",
|
||||
-- ["PERPLEXITY"] = "MODERATE",
|
||||
-- ["OPEN_ROUTER"] = "MODERATE",
|
||||
-- ["FIREWORKS"] = "MODERATE",
|
||||
-- ["GROQ"] = "MODERATE",
|
||||
-- ["HUGGINGFACE"] = "MODERATE",
|
||||
-- ["SELF_HOSTED"] = "HIGH",
|
||||
-- ["HELMHOLTZ"] = "HIGH",
|
||||
-- ["GWDG"] = "HIGH",
|
||||
-- }
|
||||
--
|
||||
-- Configure whether users can change the custom confidence scheme locally.
|
||||
-- CONFIG["SETTINGS"]["DataConfidence.CustomConfidenceScheme.AllowUserOverride"] = false
|
||||
--
|
||||
-- Configure provider instances trusted by your organization for data-source security checks.
|
||||
-- These IDs may refer to LLM providers, embedding providers, or transcription providers
|
||||
-- defined in this configuration. Trusted providers are treated like self-hosted providers
|
||||
-- only for data-source security checks and related local data warnings.
|
||||
-- CONFIG["SETTINGS"]["DataSourceSecuritySettings.TrustedProviderIds"] = {
|
||||
-- "00000000-0000-0000-0000-000000000000",
|
||||
-- "00000000-0000-0000-0000-000000000001",
|
||||
-- }
|
||||
|
||||
-- Example chat templates for this configuration:
|
||||
CONFIG["CHAT_TEMPLATES"] = {}
|
||||
|
||||
@ -316,6 +425,26 @@ CONFIG["CHAT_TEMPLATES"] = {}
|
||||
-- }
|
||||
-- }
|
||||
|
||||
-- Introduction texts shown as expansion panels on the welcome page:
|
||||
CONFIG["INTRODUCTIONS"] = {}
|
||||
|
||||
-- An example introduction:
|
||||
-- CONFIG["INTRODUCTIONS"][#CONFIG["INTRODUCTIONS"]+1] = {
|
||||
-- ["Id"] = "00000000-0000-0000-0000-000000000000",
|
||||
-- ["Title"] = "Welcome to Your Organization's AI Studio",
|
||||
-- ["Version"] = "1",
|
||||
-- ["Index"] = 1,
|
||||
-- ["Markdown"] = [===[
|
||||
-- ## Getting Started
|
||||
--
|
||||
-- This AI Studio installation is managed by your organization.
|
||||
-- Please use the preconfigured providers and follow your internal
|
||||
-- AI usage guidelines.
|
||||
--
|
||||
-- Further information is available in the [internal wiki](https://example.org/wiki).
|
||||
-- ]===]
|
||||
-- }
|
||||
|
||||
-- Mandatory infos that users must explicitly accept before using AI Studio:
|
||||
-- AI Studio asks users again when Version, Title, or Markdown change.
|
||||
-- Changing Version additionally allows the UI to communicate that a new version is available.
|
||||
|
||||
@ -2169,6 +2169,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIDENCEINFO::T847071819"] = "Zeigt ode
|
||||
-- This feature is managed by your organization and has therefore been disabled.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONBASE::T1416426626"] = "Diese Funktion wird von Ihrer Organisation verwaltet und wurde daher deaktiviert."
|
||||
|
||||
-- Choose File
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONFILE::T4285779702"] = "Datei auswählen"
|
||||
|
||||
-- Choose the minimum confidence level that all LLM providers must meet. This way, you can ensure that only trustworthy providers are used. You cannot use any provider that falls below this level.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONMINCONFIDENCESELECTION::T2526727283"] = "Wählen Sie das minimale Vertrauensniveau, das alle LLM-Anbieter erfüllen müssen. So stellen Sie sicher, dass nur vertrauenswürdige Anbieter verwendet werden. Anbieter, die dieses Niveau unterschreiten, können nicht verwendet werden."
|
||||
|
||||
@ -2631,12 +2634,18 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1278320412"]
|
||||
-- How often should we check for app updates?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1364944735"] = "Wie oft sollen wir nach App-Updates suchen?"
|
||||
|
||||
-- Additional root certificates are enabled
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1380446131"] = "Zusätzliche Stammzertifikate sind aktiviert"
|
||||
|
||||
-- Select preview features
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1439783084"] = "Vorschaufunktionen auswählen"
|
||||
|
||||
-- Your organization provided a default start page, but you can still change it.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1454730224"] = "Ihre Organisation hat eine Standard-Startseite festgelegt, die Sie jedoch ändern können."
|
||||
|
||||
-- Root certificate bundle path
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1471315821"] = "Pfad zum Stammzertifikatsbundle"
|
||||
|
||||
-- Select the desired behavior for the navigation bar.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1555038969"] = "Wählen Sie das gewünschte Verhalten für die Navigationsleiste aus."
|
||||
|
||||
@ -2691,12 +2700,24 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2591866808"]
|
||||
-- Choose which page AI Studio should open first when you start the app. Changes take effect the next time you launch AI Studio.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2655930524"] = "Wählen Sie aus, welche Seite AI Studio beim Start der App zuerst öffnen soll. Änderungen werden beim nächsten Start von AI Studio wirksam."
|
||||
|
||||
-- Path to a PEM file containing one or more root CA certificates. For Flatpak deployments, this file must be placed in a location that is readable inside the sandbox.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2700836219"] = "Pfad zu einer PEM-Datei mit einem oder mehreren Root-CA-Zertifikaten. Bei Flatpak-Bereitstellungen muss diese Datei an einem Ort abgelegt werden, der innerhalb der Sandbox lesbar ist."
|
||||
|
||||
-- Enter one host pattern per line. Exact hosts such as data.intra.example.org and one-label wildcards such as *.intra.example.org are supported. Cloud provider endpoints built into AI Studio, such as OpenAI, Google, etc., never use these additional root certificates.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2960110864"] = "Geben Sie pro Zeile ein Hostmuster ein. Exakte Hosts wie data.intra.example.org sowie Wildcards mit einem Label wie *.intra.example.org werden unterstützt. In AI Studio integrierte Endpunkte von Cloud-Anbietern wie OpenAI, Google usw. verwenden diese zusätzlichen Stammzertifikate nicht."
|
||||
|
||||
-- Save energy?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3100928009"] = "Energie sparen?"
|
||||
|
||||
-- Spellchecking is enabled
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3165555978"] = "Rechtschreibprüfung ist aktiviert"
|
||||
|
||||
-- External HTTPS certificates
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T348936513"] = "Externe HTTPS-Zertifikate"
|
||||
|
||||
-- Allowed hosts for additional root certificates
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3562495752"] = "Zugelassene Hosts für zusätzliche Stammzertifikate"
|
||||
|
||||
-- Request timeout
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3569531009"] = "Zeitüberschreitung bei der Anfrage"
|
||||
|
||||
@ -2715,9 +2736,15 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3694781396"]
|
||||
-- Read the Enterprise IT documentation for details.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3705451321"] = "Lesen Sie die Enterprise-IT-Dokumentation für die Details."
|
||||
|
||||
-- When enabled, AI Studio can trust root certificates from a configured PEM bundle for external HTTPS requests, such as self-hosted AI providers, embeddings, transcription, ERI data sources, and enterprise configuration downloads. Normal hostname and certificate validity checks still apply. Integrated cloud providers, such as OpenAI, Google, and others, will never use these additional certificates. Please note that you usually do not need this setting on macOS or Windows. If you use Linux with the AppImage version of MindWork AI Studio, you also do not need this option. A valid use case is a Linux environment where AI Studio runs from a Flatpak.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3798070907"] = "Wenn diese Option aktiviert ist, kann AI Studio Stammzertifikate aus einem konfigurierten PEM-Bundle für externe HTTPS-Anfragen vertrauen, zum Beispiel für selbst gehostete KI-Anbieter, Embeddings, Transkription, ERI-Datenquellen und das Herunterladen von Unternehmenskonfigurationen. Die üblichen Prüfungen von Hostnamen und Zertifikatsgültigkeit gelten weiterhin. Integrierte Cloud-Anbieter wie OpenAI, Google und andere verwenden diese zusätzlichen Zertifikate niemals. Bitte beachten Sie, dass Sie diese Einstellung unter macOS oder Windows in der Regel nicht benötigen. Wenn Sie Linux mit der AppImage-Version von MindWork AI Studio verwenden, benötigen Sie diese Option ebenfalls nicht. Ein gültiger Anwendungsfall ist eine Linux-Umgebung, in der AI Studio aus einem Flatpak heraus ausgeführt wird."
|
||||
|
||||
-- Enable spellchecking?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3914529369"] = "Rechtschreibprüfung aktivieren?"
|
||||
|
||||
-- Additional root certificates are disabled
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3985928190"] = "Zusätzliche Stammzertifikate sind deaktiviert"
|
||||
|
||||
-- Preselect one of your profiles?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T4004501229"] = "Möchten Sie eines ihrer Profile vorauswählen?"
|
||||
|
||||
@ -2730,6 +2757,12 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T4174666315"]
|
||||
-- How long AI Studio waits for external HTTP requests, such as AI providers, embeddings, transcription, ERI data sources, and enterprise configuration downloads.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T4192032183"] = "Wie lange AI Studio auf externe HTTP-Anfragen wartet, z. B. an KI-Anbieter, Einbettungen, Transkription, ERI-Datenquellen und Downloads von Enterprise-Konfigurationen."
|
||||
|
||||
-- Use additional root certificates for external HTTPS requests?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T4235562267"] = "Zusätzliche Stammzertifikate für externe HTTPS-Anfragen verwenden?"
|
||||
|
||||
-- Select a root certificate bundle
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T436881267"] = "Wählen Sie ein Stammzertifikat-Bundle aus"
|
||||
|
||||
-- Navigation bar behavior
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T602293588"] = "Verhalten der Navigationsleiste"
|
||||
|
||||
@ -2760,6 +2793,54 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T922066419"]
|
||||
-- Administration settings are not visible
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T929143445"] = "Die Optionen für die Administration sind nicht sichtbar."
|
||||
|
||||
-- Show provider's confidence level?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T1052533048"] = "Anzeigen, wie sicher der Anbieter ist?"
|
||||
|
||||
-- Choose the scheme that best suits you and your organization. Do you trust any western provider? Or only providers from the USA or exclusively European providers? Then choose the appropriate scheme. Alternatively, you can assign the confidence levels to each provider yourself.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T1081931329"] = "Wählen Sie das Schema, das am besten zu Ihnen und Ihrer Organisation passt. Vertrauen Sie irgendeinem westlichen Anbieter? Oder nur Anbietern aus den USA oder ausschließlich europäischen Anbietern? Wählen Sie dann das passende Schema. Alternativ können Sie auch die Vertrauensstufen für jeden Anbieter eigenständig festlegen."
|
||||
|
||||
-- Provider Confidence
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T1453422580"] = "Vertrauen in die Anbieter"
|
||||
|
||||
-- When enabled, you can enforce a minimum confidence level for all features in AI Studio. This way, you can make sure only trustworthy providers are used.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T1499004705"] = "Wenn aktiviert, können Sie für alle Funktionen in AI Studio ein minimales Vertrauensniveau festlegen. So können Sie sicherstellen, dass nur vertrauenswürdige Anbieter verwendet werden."
|
||||
|
||||
-- When enabled, we show you the confidence level for the selected provider in the app. This helps you assess where you are sending your data at any time. Example: are you currently working with sensitive data? Then choose a particularly trustworthy provider, etc.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T1505516304"] = "Wenn aktiviert, zeigen wir Ihnen in der App das Vertrauensniveau für den ausgewählten Anbieter an. So können Sie jederzeit einschätzen, wohin Ihre Daten gesendet werden. Beispiel: Arbeiten Sie gerade mit sensiblen Daten? Dann wählen Sie einen besonders vertrauenswürdigen Anbieter usw."
|
||||
|
||||
-- No, please hide the confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T1628475119"] = "Nein, bitte das Vertrauensniveau ausblenden"
|
||||
|
||||
-- Description
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T1725856265"] = "Beschreibung"
|
||||
|
||||
-- Confidence Level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T2492230131"] = "Vertrauensniveau"
|
||||
|
||||
-- No, do not enforce a minimum confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T3642102079"] = "Nein, kein Mindestvertrauensniveau erzwingen"
|
||||
|
||||
-- Select a confidence scheme
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T4144206465"] = "Wählen Sie ein Vertrauensschema aus"
|
||||
|
||||
-- Do you want to enforce an global minimum confidence level?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T4211873175"] = "Möchten Sie ein globales Mindestvertrauensniveau festlegen?"
|
||||
|
||||
-- Yes, enforce a minimum confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T458854917"] = "Ja, ein Mindestvertrauensniveau erzwingen"
|
||||
|
||||
-- Not yet configured
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T48051324"] = "Noch nicht konfiguriert"
|
||||
|
||||
-- Do you want to always see how trustworthy your providers are? This way, you stay in control of which provider you send your data to. You can choose a common schema or configure the trust levels for each provider yourself.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T700839804"] = "Möchten Sie immer sehen, wie vertrauenswürdig Ihre Anbieter sind? So behalten Sie die Kontrolle darüber, an welchen Anbieter Sie Ihre Daten senden. Sie können ein gängiges Schema wählen oder die Vertrauensstufen für jeden Anbieter selbst festlegen."
|
||||
|
||||
-- Yes, show me the confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T853225204"] = "Ja, zeige mir das Vertrauensniveau"
|
||||
|
||||
-- Provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T900237532"] = "Anbieter"
|
||||
|
||||
-- Embedding Result
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T1387042335"] = "Einbettungsergebnis"
|
||||
|
||||
@ -2814,6 +2895,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T32678
|
||||
-- Close
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T3448155331"] = "Schließen"
|
||||
|
||||
-- This embedding provider is trusted by your organization for data source security checks. Local data can be sent to it without security warnings.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T3459188215"] = "Ihre Organisation vertraut diesem Anbieter von Einbettungen bei der Sicherheitsprüfung von Datenquellen. Lokale Daten können ohne Sicherheitswarnungen an diesen gesendet werden."
|
||||
|
||||
-- Actions
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T3865031940"] = "Aktionen"
|
||||
|
||||
@ -2856,21 +2940,12 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERBASE::T336
|
||||
-- Export API Key?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERBASE::T4010580285"] = "API-Schlüssel exportieren?"
|
||||
|
||||
-- Show provider's confidence level?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T1052533048"] = "Anzeigen, wie sicher sich der Anbieter ist?"
|
||||
-- This provider is trusted by your organization for data source security checks.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T1298650849"] = "Ihre Organisation vertraut diesem Anbieter bei der Sicherheitsprüfung von Datenquellen."
|
||||
|
||||
-- Delete
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T1469573738"] = "Löschen"
|
||||
|
||||
-- When enabled, we show you the confidence level for the selected provider in the app. This helps you assess where you are sending your data at any time. Example: are you currently working with sensitive data? Then choose a particularly trustworthy provider, etc.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T1505516304"] = "Wenn diese Option aktiviert ist, zeigen wir Ihnen das Vertrauensniveau des ausgewählten Anbieters in der App an. So können Sie jederzeit einschätzen, wohin ihre Daten gesendet werden. Beispiel: Arbeiten Sie gerade mit sensiblen Daten? Dann wählen Sie einen besonders vertrauenswürdigen Anbieter usw."
|
||||
|
||||
-- No, please hide the confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T1628475119"] = "Nein, bitte verbergen Sie das Vertrauensniveau."
|
||||
|
||||
-- Description
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T1725856265"] = "Beschreibung"
|
||||
|
||||
-- Uses the provider-configured model
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T1760715963"] = "Verwendet das vom Anbieter konfigurierte Modell"
|
||||
|
||||
@ -2886,27 +2961,12 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T186876
|
||||
-- Are you sure you want to delete the provider '{0}'?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2031310917"] = "Möchten Sie den Anbieter „{0}“ wirklich löschen?"
|
||||
|
||||
-- Do you want to always be able to recognize how trustworthy your LLM providers are? This way, you keep control over which provider you send your data to. You have two options for this: Either you choose a common schema, or you configure the trust levels for each LLM provider yourself.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2082904277"] = "Möchten Sie immer erkennen können, wie vertrauenswürdig ihre LLM-Anbieter sind? So behalten Sie die Kontrolle darüber, an welchen Anbieter Sie ihre Daten senden. Dafür haben Sie zwei Möglichkeiten: Entweder wählen Sie ein vorkonfiguriertes Schema, oder Sie konfigurieren die Vertrauensstufen für jeden LLM-Anbieter selbst."
|
||||
|
||||
-- Model
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2189814010"] = "Modell"
|
||||
|
||||
-- Choose the scheme that best suits you and your life. Do you trust any western provider? Or only providers from the USA or exclusively European providers? Then choose the appropriate scheme. Alternatively, you can assign the confidence levels to each provider yourself.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2283885378"] = "Wählen Sie das Schema, das am besten zu Ihnen und ihren Umständen passt. Vertrauen Sie einem westlichen Anbieter? Oder nur Anbietern aus den USA oder ausschließlich europäischen Anbietern? Dann wählen Sie das passende Schema aus. Alternativ können Sie auch die Vertrauensstufen für jeden Anbieter eigenständig festlegen."
|
||||
|
||||
-- LLM Provider Confidence
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2349972795"] = "Vertrauenswürdigkeit in LLM-Anbieter"
|
||||
|
||||
-- What we call a provider is the combination of an LLM provider such as OpenAI and a model like GPT-4o. You can configure as many providers as you want. This way, you can use the appropriate model for each task. As an LLM provider, you can also choose local providers. However, to use this app, you must configure at least one provider.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2460361126"] = "Was wir als „Anbieter“ bezeichnen, ist die Kombination aus einem LLM-Anbieter wie OpenAI und einem Modell wie GPT-4o. Sie können beliebig viele Anbieter einrichten. So können Sie für jede Aufgabe das passende Modell nutzen. Als LLM-Anbieter können Sie auch lokale Anbieter auswählen. Um diese App zu verwenden, müssen Sie jedoch mindestens einen Anbieter konfigurieren."
|
||||
|
||||
-- Confidence Level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2492230131"] = "Vertrauensniveau"
|
||||
|
||||
-- When enabled, you can enforce a minimum confidence level for all LLM providers. This way, you can ensure that only trustworthy providers are used.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T281063702"] = "Wenn aktiviert, können Sie ein minimales Vertrauensniveau für alle LLM-Anbieter festlegen. So stellen Sie sicher, dass nur vertrauenswürdige Anbieter verwendet werden."
|
||||
|
||||
-- Instance Name
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2842060373"] = "Instanzname"
|
||||
|
||||
@ -2928,36 +2988,15 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T334643
|
||||
-- This provider is managed by your organization.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T3415927576"] = "Dieser Anbieter wird von ihrer Organisation verwaltet."
|
||||
|
||||
-- LLM Provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T3612415205"] = "LLM-Anbieter"
|
||||
|
||||
-- No, do not enforce a minimum confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T3642102079"] = "Nein, kein Mindestvertrauensniveau erzwingen"
|
||||
|
||||
-- Actions
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T3865031940"] = "Aktionen"
|
||||
|
||||
-- Select a confidence scheme
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T4144206465"] = "Wählen Sie ein Vertrauensschema aus"
|
||||
|
||||
-- Do you want to enforce an app-wide minimum confidence level?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T4258968041"] = "Möchten Sie ein appweites Mindestvertrauensniveau festlegen?"
|
||||
|
||||
-- Delete LLM Provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T4269256234"] = "LLM-Anbieter löschen"
|
||||
|
||||
-- Yes, enforce a minimum confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T458854917"] = "Ja, ein Mindestvertrauensniveau erzwingen"
|
||||
|
||||
-- Not yet configured
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T48051324"] = "Noch nicht konfiguriert"
|
||||
|
||||
-- Open Dashboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T78223861"] = "Dashboard öffnen"
|
||||
|
||||
-- Yes, show me the confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T853225204"] = "Ja, zeige mir das Vertrauensniveau"
|
||||
|
||||
-- Provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T900237532"] = "Anbieter"
|
||||
|
||||
@ -3006,6 +3045,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T42
|
||||
-- With the support of transcription models, MindWork AI Studio can convert human speech into text. This is useful, for example, when you need to dictate text. You can choose from dedicated transcription models, but not multimodal LLMs (large language models) that can handle both speech and text. The configuration of multimodal models is done in the 'Configure LLM providers' section.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T584860404"] = "Mit Unterstützung von Modellen für Transkriptionen kann MindWork AI Studio menschliche Sprache in Text umwandeln. Das ist zum Beispiel hilfreich, wenn Sie Texte diktieren möchten. Sie können aus speziellen Modellen für Transkriptionen wählen, jedoch nicht aus multimodalen LLMs (Large Language Models), die sowohl Sprache als auch Text verarbeiten können. Die Einrichtung multimodaler Modelle erfolgt im Abschnitt „Anbieter für LLMs konfigurieren“."
|
||||
|
||||
-- This transcription provider is trusted by your organization for data source security checks.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T601264181"] = "Ihre Organisation vertraut diesem Anbieter für Transkriptionen bei der Sicherheitsprüfung von Datenquellen."
|
||||
|
||||
-- This transcription provider is managed by your organization.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T756131076"] = "Dieser Anbieter für Transkriptionen wird von Ihrer Organisation verwaltet."
|
||||
|
||||
@ -3165,15 +3207,27 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1469573738"] = "Löschen"
|
||||
-- Rename Workspace
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1474303418"] = "Arbeitsbereich umbenennen"
|
||||
|
||||
-- Clear search
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1511254342"] = "Suche zurücksetzen"
|
||||
|
||||
-- Rename Chat
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T156144855"] = "Chat umbenennen"
|
||||
|
||||
-- Add workspace
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1586005241"] = "Arbeitsbereich hinzufügen"
|
||||
|
||||
-- Search chats
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1615077202"] = "Chats durchsuchen"
|
||||
|
||||
-- Start a new chat in workspace '{0}'
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1840064668"] = "Neuen Chat im Arbeitsbereich „{0}“ starten"
|
||||
|
||||
-- Add chat
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1874060138"] = "Chat hinzufügen"
|
||||
|
||||
-- No chats found
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1886517101"] = "Keine Chats gefunden"
|
||||
|
||||
-- Create Chat
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1939006681"] = "Chat erstellen"
|
||||
|
||||
@ -3210,6 +3264,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3045856778"] = "Chat in den
|
||||
-- Please enter a new or edit the name for your workspace '{0}':
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T323280982"] = "Bitte geben Sie einen neuen Namen für ihren Arbeitsbereich „{0}“ ein oder bearbeiten Sie ihn:"
|
||||
|
||||
-- There is already a workspace with this name. Please choose a different name.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3249036008"] = "Es gibt bereits einen Arbeitsbereich mit diesem Namen. Bitte wählen Sie einen anderen Namen."
|
||||
|
||||
-- Please enter a workspace name.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3288132732"] = "Bitte geben Sie einen Namen für diesen Arbeitsbereich ein."
|
||||
|
||||
@ -3219,6 +3276,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3355849203"] = "Umbenennen"
|
||||
-- Please enter a new or edit the name for your chat '{0}':
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3419791373"] = "Bitte geben Sie einen neuen Namen für ihren Chat „{0}“ ein oder bearbeiten Sie ihn:"
|
||||
|
||||
-- Search chat contents
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3436662033"] = "Chat-Inhalte durchsuchen"
|
||||
|
||||
-- Load Chat
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3555709365"] = "Chat laden"
|
||||
|
||||
@ -3465,6 +3525,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3227981830"] = "Die gle
|
||||
-- Add a message
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3372872324"] = "Nachricht hinzufügen"
|
||||
|
||||
-- Close
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3448155331"] = "Schließen"
|
||||
|
||||
-- Unsupported content type
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3570316759"] = "Nicht unterstützter Inhaltstyp"
|
||||
|
||||
@ -4245,6 +4308,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T3243902394"] = "Der Profilna
|
||||
-- Profile Name
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T3392578705"] = "Profilname"
|
||||
|
||||
-- Close
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T3448155331"] = "Schließen"
|
||||
|
||||
-- Please enter what the LLM should know about you and/or what actions it should take.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T3708405102"] = "Bitte geben Sie ein, was das LLM über Sie wissen sollte und/oder welche Aktionen es ausführen soll."
|
||||
|
||||
@ -4764,6 +4830,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T14695
|
||||
-- Add Chat Template
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T1548314416"] = "Chat-Vorlage hinzufügen"
|
||||
|
||||
-- View
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T1582017048"] = "Anzeigen"
|
||||
|
||||
-- Note: This advanced feature is designed for users familiar with prompt engineering concepts. Furthermore, you have to make sure yourself that your chosen provider supports the use of assistant prompts.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T1909110760"] = "Hinweis: Diese fortgeschrittene Funktion richtet sich an Nutzer, die mit den Grundlagen des Prompt Engineerings vertraut sind. Außerdem müssen Sie selbst sicherstellen, dass Ihr gewählter Anbieter die Verwendung von Assistenten-Prompts unterstützt."
|
||||
|
||||
@ -4803,6 +4872,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T38650
|
||||
-- Delete Chat Template
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T4025180906"] = "Chat-Vorlage löschen"
|
||||
|
||||
-- View Chat Template
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T4042112076"] = "Chat-Vorlage anzeigen"
|
||||
|
||||
-- Export Chat Template
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T491504763"] = "Chat-Vorlage exportieren"
|
||||
|
||||
@ -5211,6 +5283,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T143353473
|
||||
-- Delete
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T1469573738"] = "Löschen"
|
||||
|
||||
-- View
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T1582017048"] = "Anzeigen"
|
||||
|
||||
-- Your Profiles
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T2378610256"] = "Ihre Profile"
|
||||
|
||||
@ -5235,6 +5310,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T405841465
|
||||
-- Store personal data about yourself in various profiles so that the AIs know your personal context. This saves you from having to explain your context each time, for example, in every chat. When you have different roles, you can create a profile for each role.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T4125557797"] = "Speichern Sie persönliche Daten über sich in verschiedenen Profilen, damit die KIs ihren persönlichen Kontext kennen. So müssen Sie den Kontext nicht jedes Mal erneut erklären, zum Beispiel in jedem Chat. Wenn Sie verschiedene Rollen haben, können Sie für jede Rolle ein eigenes Profil anlegen."
|
||||
|
||||
-- View Profile
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T4219233997"] = "Profil anzeigen"
|
||||
|
||||
-- Add Profile
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T4248067241"] = "Profil hinzufügen"
|
||||
|
||||
@ -5748,15 +5826,39 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::UPDATEDIALOG::T25417398"] = "Aktualisieren v
|
||||
-- Install later
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::UPDATEDIALOG::T2936430090"] = "Später installieren"
|
||||
|
||||
-- Create new workspace
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::WORKSPACESELECTIONDIALOG::T1541251414"] = "Neuen Arbeitsbereich erstellen"
|
||||
|
||||
-- Add workspace
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::WORKSPACESELECTIONDIALOG::T1586005241"] = "Arbeitsbereich hinzufügen"
|
||||
|
||||
-- Workspace name
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::WORKSPACESELECTIONDIALOG::T295876489"] = "Name des Arbeitsbereichs"
|
||||
|
||||
-- There is already a workspace with this name. Please choose a different name.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::WORKSPACESELECTIONDIALOG::T3249036008"] = "Es gibt bereits einen Arbeitsbereich mit diesem Namen. Bitte wählen Sie einen anderen Namen."
|
||||
|
||||
-- Please enter a workspace name.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::WORKSPACESELECTIONDIALOG::T3288132732"] = "Bitte geben Sie einen Namen für diesen Arbeitsbereich ein."
|
||||
|
||||
-- Cancel
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::WORKSPACESELECTIONDIALOG::T900713019"] = "Abbrechen"
|
||||
|
||||
-- Reason
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1093747001"] = "Begründung"
|
||||
|
||||
-- Settings
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1258653480"] = "Einstellungen"
|
||||
|
||||
-- Your settings file does not contain a settings-format version. Changes in this session will not be saved to avoid overwriting your settings. Please check for updates or contact support.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1378304679"] = "Ihre Einstellungsdatei enthält keine Versionsangabe des Einstellungsformats. Änderungen in dieser Sitzung werden nicht gespeichert, um ein Überschreiben Ihrer Einstellungen zu vermeiden. Bitte suchen Sie nach Updates oder wenden Sie sich an den Support."
|
||||
|
||||
-- Home
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1391791790"] = "Startseite"
|
||||
|
||||
-- AI Studio found the current settings format but could not load it safely. Changes in this session will not be saved. Please check for updates or contact support.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1497084127"] = "AI Studio hat das aktuelle Einstellungsformat gefunden, konnte es jedoch nicht sicher laden. Änderungen in dieser Sitzung werden nicht gespeichert. Bitte suchen Sie nach Updates oder wenden Sie sich an den Support."
|
||||
|
||||
-- Are you sure you want to leave the chat page? All unsaved changes will be lost.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1563130494"] = "Sind Sie sicher, dass Sie die Chat-Seite verlassen möchten? Alle nicht gespeicherten Änderungen gehen verloren."
|
||||
|
||||
@ -5766,12 +5868,21 @@ UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1614176092"] = "Assistenten"
|
||||
-- Update
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1847791252"] = "Aktualisieren"
|
||||
|
||||
-- Check for updates
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1890416390"] = "Nach Updates suchen"
|
||||
|
||||
-- Your settings were created by a newer AI Studio version. Changes in this session will not be saved. Please install or start the latest available update.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1988273622"] = "Ihre Einstellungen wurden mit einer neueren Version von AI Studio erstellt. Änderungen in dieser Sitzung werden nicht gespeichert. Bitte installieren oder starten Sie das neueste verfügbare Update."
|
||||
|
||||
-- Leave Chat Page
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2124749705"] = "Chat-Seite verlassen"
|
||||
|
||||
-- Plugins
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2222816203"] = "Plugins"
|
||||
|
||||
-- AI Studio cannot safely save settings in this session. Please check for updates or contact support.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2382622618"] = "AI Studio kann die Einstellungen in dieser Sitzung nicht sicher speichern. Bitte suchen Sie nach Updates oder wenden Sie sich an den Support."
|
||||
|
||||
-- An update to version {0} is available.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2800137365"] = "Ein Update auf Version {0} ist verfügbar."
|
||||
|
||||
@ -5781,6 +5892,9 @@ UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2864211629"] = "Bitte warten Sie
|
||||
-- Supporters
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2929332068"] = "Unterstützer"
|
||||
|
||||
-- AI Studio could not read your settings file. Changes in this session will not be saved to avoid overwriting recoverable settings. Please check for updates or contact support.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2936083926"] = "AI Studio konnte Ihre Einstellungsdatei nicht lesen. Änderungen in dieser Sitzung werden nicht gespeichert, um ein Überschreiben wiederherstellbarer Einstellungen zu vermeiden. Bitte suchen Sie nach Updates oder wenden Sie sich an den Support."
|
||||
|
||||
-- Writing
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2979224202"] = "Schreiben"
|
||||
|
||||
@ -5793,6 +5907,9 @@ UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T4256323669"] = "Information"
|
||||
-- Chat
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T578410699"] = "Chat"
|
||||
|
||||
-- AI Studio does not recognize your settings-format version. Changes in this session will not be saved to avoid overwriting your settings. Please check for updates or contact support.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T915412625"] = "AI Studio erkennt die Version Ihres Einstellungsformats nicht. Änderungen in dieser Sitzung werden nicht gespeichert, um zu verhindern, dass Ihre Einstellungen überschrieben werden. Bitte suchen Sie nach Updates oder wenden Sie sich an den Support."
|
||||
|
||||
-- Get coding and debugging support from an LLM.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T1243850917"] = "Erhalten Sie Unterstützung beim Programmieren und Debuggen durch ein KI-Modell."
|
||||
|
||||
@ -5925,6 +6042,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T878695986"] = "Lerne jeden Tag ei
|
||||
-- Localization
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T897888480"] = "Lokalisierung"
|
||||
|
||||
-- Hide search
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::CHAT::T1281128983"] = "Suche ausblenden"
|
||||
|
||||
-- Reload your workspaces
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::CHAT::T194629703"] = "Arbeitsbereiche neu laden"
|
||||
|
||||
@ -5937,6 +6057,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::CHAT::T2813205227"] = "Chat-Optionen öffnen"
|
||||
-- Disappearing Chat
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::CHAT::T3046519404"] = "Selbstlöschender Chat"
|
||||
|
||||
-- Search your workspaces
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::CHAT::T3059773282"] = "Arbeitsbereiche durchsuchen"
|
||||
|
||||
-- Configure your workspaces
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::CHAT::T3586092784"] = "Konfigurieren Sie ihre Arbeitsbereiche"
|
||||
|
||||
@ -5970,6 +6093,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T144565305"] = "Die App benötigt nur we
|
||||
-- You only pay for what you use, which can be cheaper than monthly subscription services like ChatGPT Plus, especially if used infrequently. But beware, here be dragons: For extremely intensive usage, the API costs can be significantly higher. Unfortunately, providers currently do not offer a way to display current costs in the app. Therefore, check your account with the respective provider to see how your costs are developing. When available, use prepaid and set a cost limit.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T149711988"] = "Sie zahlen nur für das, was Sie tatsächlich nutzen – das kann günstiger sein als monatliche Abos wie ChatGPT Plus, vor allem bei gelegentlicher Nutzung. Aber Vorsicht: Bei sehr intensiver Nutzung können die API-Kosten deutlich höher ausfallen. Leider bieten die Anbieter derzeit keine Möglichkeit, die aktuellen Kosten direkt in der App anzuzeigen. Prüfen Sie deshalb regelmäßig Ihr Konto beim jeweiligen Anbieter, um ihre Ausgaben im Blick zu behalten. Nutzen Sie, wenn möglich, Prepaid-Optionen und legen Sie ein Ausgabenlimit fest."
|
||||
|
||||
-- Version
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T1573770551"] = "Version"
|
||||
|
||||
-- Assistants
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T1614176092"] = "Assistenten"
|
||||
|
||||
@ -6039,27 +6165,42 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T91074375"] = "Die App ist sowohl für p
|
||||
-- Startup log file
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1019424746"] = "Startprotokolldatei"
|
||||
|
||||
-- The configured root certificates could not be used.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T103551060"] = "Die konfigurierten Root-Zertifikate konnten nicht verwendet werden."
|
||||
|
||||
-- Browse AI Studio's source code on GitHub — we welcome your contributions.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1107156991"] = "Sehen Sie sich den Quellcode von AI Studio auf GitHub an – wir freuen uns über ihre Beiträge."
|
||||
|
||||
-- Vector store version
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1124039623"] = "Vektordatenbankversion"
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1126023000"] = "Qdrant Edge ist eine eingebettete Vektordatenbank und ein Vektoraehnlichkeitssuchmaschine. Wir nutzen sie, um lokal RAG – retrieval-augmented generation – innerhalb von AI Studio zu realisieren. Vielen Dank für die Anstrengungen und die großartige Arbeit, die in Qdrant investiert wurde und weiterhin investiert wird."
|
||||
|
||||
-- ID mismatch: the plugin ID differs from the enterprise configuration ID.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1137744461"] = "ID-Konflikt: Die Plugin-ID stimmt nicht mit der ID der Unternehmenskonfiguration überein."
|
||||
|
||||
-- This is a private AI Studio installation. It runs without an enterprise configuration.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1209549230"] = "Dies ist eine private AI Studio-Installation. Sie läuft ohne Unternehmenskonfiguration."
|
||||
|
||||
-- Copies the configuration origin to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T125850635"] = "Kopiert den Ursprung der Konfiguration in die Zwischenablage"
|
||||
|
||||
-- Unknown configuration plugin
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1290340974"] = "Unbekanntes Konfigurations-Plugin"
|
||||
|
||||
-- Copies the configuration slot to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1347508205"] = "Kopiert den Slot der Konfiguration in die Zwischenablage"
|
||||
|
||||
-- This library is used to read PDF files. This is necessary, e.g., for using PDFs as a data source for a chat.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1388816916"] = "Diese Bibliothek wird verwendet, um PDF-Dateien zu lesen. Das ist zum Beispiel notwendig, um PDFs als Datenquelle für einen Chat zu nutzen."
|
||||
|
||||
-- Database version
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1420062548"] = "Datenbankversion"
|
||||
|
||||
-- This library is used to extend the MudBlazor library. It provides additional components that are not part of the MudBlazor library.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1421513382"] = "Diese Bibliothek wird verwendet, um die MudBlazor-Bibliothek zu erweitern. Sie stellt zusätzliche Komponenten bereit, die nicht Teil der MudBlazor-Bibliothek sind."
|
||||
|
||||
-- Copies the allowed host pattern to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1513592659"] = "Kopiert das zulässige Hostmuster in die Zwischenablage"
|
||||
|
||||
-- Waiting for the configuration plugin...
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1533382393"] = "Warten auf das Konfigurations-Plugin …"
|
||||
|
||||
@ -6069,9 +6210,6 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1560776885"] = "Geheimnis für d
|
||||
-- AI Studio runs with an enterprise configuration and configuration servers. The configuration plugins are active.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1596483935"] = "AI Studio wird mit Unternehmenskonfigurationen und Konfigurationsservern betrieben. Die Konfigurations-Plugins sind aktiv."
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1619832053"] = "Qdrant ist eine Vektordatenbank und Suchmaschine für Vektoren. Wir nutzen Qdrant, um lokales RAG (Retrieval-Augmented Generation) innerhalb von AI Studio zu realisieren. Vielen Dank für den Einsatz und die großartige Arbeit, die in Qdrant gesteckt wurde und weiterhin gesteckt wird."
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T162898512"] = "Wir verwenden Lua als Sprache für Plugins. Lua-CSharp ermöglicht die Kommunikation zwischen Lua-Skripten und AI Studio in beide Richtungen. Vielen Dank an Yusuke Nakada für diese großartige Bibliothek."
|
||||
|
||||
@ -6084,6 +6222,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1630237140"] = "AI Studio erstel
|
||||
-- Consent:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T171952677"] = "Zustimmung:"
|
||||
|
||||
-- Copies the executable path to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1722690800"] = "Kopiert den Pfad der ausführbaren Datei in die Zwischenablage"
|
||||
|
||||
-- This library is used to display the differences between two texts. This is necessary, e.g., for the grammar and spelling assistant.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1772678682"] = "Diese Bibliothek wird verwendet, um die Unterschiede zwischen zwei Texten anzuzeigen. Das ist zum Beispiel für den Grammatik- und Rechtschreibassistenten notwendig."
|
||||
|
||||
@ -6108,12 +6249,18 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1924365263"] = "Diese Bibliothek
|
||||
-- Encryption secret: is configured
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1931141322"] = "Geheimnis für die Verschlüsselung: ist konfiguriert"
|
||||
|
||||
-- Copies the number of loaded root certificates to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2015329654"] = "Kopiert die Anzahl der geladenen Stammzertifikate in die Zwischenablage"
|
||||
|
||||
-- Copies the following to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2029659664"] = "Kopiert Folgendes in die Zwischenablage"
|
||||
|
||||
-- Copies the server URL to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2037899437"] = "Kopiert die Server-URL in die Zwischenablage"
|
||||
|
||||
-- This library is used to create temporary folders in runtime tests and supporting filesystem operations.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2160280545"] = "Diese Bibliothek wird verwendet, um temporäre Ordner bei Laufzeittests zu erstellen und Dateisystemoperationen zu unterstützen."
|
||||
|
||||
-- This library is used to determine the file type of a file. This is necessary, e.g., when we want to stream a file.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2173617769"] = "Diese Bibliothek wird verwendet, um den Dateityp einer Datei zu bestimmen. Das ist zum Beispiel notwendig, wenn wir eine Datei streamen möchten."
|
||||
|
||||
@ -6147,6 +6294,12 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2371107659"] = "Installation vom
|
||||
-- Installed Pandoc version: Pandoc is not installed or not available.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2374031539"] = "Installierte Pandoc-Version: Pandoc ist nicht installiert oder nicht verfügbar."
|
||||
|
||||
-- Configuration origin:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2435772109"] = "Ursprung der Konfiguration:"
|
||||
|
||||
-- Configuration slot:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T254943559"] = "Slot der Konfiguration:"
|
||||
|
||||
-- This library is used to determine the language of the operating system. This is necessary to set the language of the user interface.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2557014401"] = "Diese Bibliothek wird verwendet, um die Sprache des Betriebssystems zu erkennen. Dies ist notwendig, um die Sprache der Benutzeroberfläche einzustellen."
|
||||
|
||||
@ -6156,8 +6309,8 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2557066213"] = "Verwendete Open-
|
||||
-- Build time
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T260228112"] = "Build-Zeit"
|
||||
|
||||
-- This library is used to create temporary folders for saving the certificate and private key for communication with Qdrant.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2619858133"] = "Diese Bibliothek wird verwendet, um temporäre Ordner zu erstellen, in denen das Zertifikat und der private Schlüssel für die Kommunikation mit Qdrant gespeichert werden."
|
||||
-- unknown
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2608177081"] = "unbekannt"
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2635482790"] = "Dieses Crate stellt Derive-Makros für Rust-Enums bereit, die wir verwenden, um Boilerplate zu reduzieren, wenn wir String-Konvertierungen und Metadaten für Laufzeittypen implementieren. Das ist hilfreich für die Kommunikation zwischen unseren Rust- und .NET-Systemen."
|
||||
@ -6201,9 +6354,21 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2868174483"] = "Das .NET-Backend
|
||||
-- AI Studio runs with an enterprise configuration and configuration servers. The configuration plugins are not yet available.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2924964415"] = "AI Studio wird mit Unternehmenskonfigurationen und Konfigurationsservern betrieben. Die Konfigurations-Plugins sind noch nicht verfügbar."
|
||||
|
||||
-- Copies the configuration source to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2929232062"] = "Kopiert die Quelle der Konfiguration in die Zwischenablage"
|
||||
|
||||
-- Copies the root certificate fingerprint to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2989678330"] = "Kopiert den Fingerabdruck des Stammzertifikats in die Zwischenablage"
|
||||
|
||||
-- Changelog
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3017574265"] = "Änderungsprotokoll"
|
||||
|
||||
-- External HTTPS custom root certificates are configured but not active.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3021325354"] = "Externe benutzerdefinierte Stammzertifikate sind konfiguriert, aber nicht aktiv."
|
||||
|
||||
-- Vector store
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3046399223"] = "Vektordatenbank"
|
||||
|
||||
-- Enterprise configuration ID:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3092349641"] = "Unternehmenskonfigurations-ID:"
|
||||
|
||||
@ -6216,6 +6381,12 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3178730036"] = "Haben Sie Ideen
|
||||
-- Hide Details
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3183837919"] = "Details ausblenden"
|
||||
|
||||
-- Linux package
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3196139293"] = "Linux-Paket"
|
||||
|
||||
-- External HTTPS custom root certificates are active.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3208455732"] = "Externe Stammzertifikate sind aktiv."
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3208719461"] = "Der Axum-Server führt den internen Axum-Dienst über eine sichere lokale Verbindung aus. Dadurch kann AI Studio die Kommunikation zwischen der Rust-Laufzeitumgebung und der Benutzeroberfläche schützen."
|
||||
|
||||
@ -6228,9 +6399,15 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3249965383"] = "Pandoc aktualisi
|
||||
-- Discover MindWork AI's mission and vision on our official homepage.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3294830584"] = "Entdecken Sie die Mission und Vision von MindWork AI auf unserer offiziellen Homepage."
|
||||
|
||||
-- External HTTPS custom root certificates
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3315279770"] = "Externe HTTPS-Stammzertifikate für benutzerdefinierte Zertifizierungsstellen"
|
||||
|
||||
-- User-language provided by the OS
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3334355246"] = "Vom Betriebssystem bereitgestellte Sprache"
|
||||
|
||||
-- Status:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3396815215"] = "Status:"
|
||||
|
||||
-- The following list shows the versions of the MindWork AI Studio, the used compilers, build time, etc.:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3405978777"] = "Die folgende Liste zeigt die Versionen von MindWork AI Studio und des verwendeten Compilers, den Build-Zeitpunkt und weitere Informationen:"
|
||||
|
||||
@ -6249,18 +6426,30 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3494984593"] = "Tauri wird verwe
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3527399572"] = "AI Studio speichert vertrauliche Daten wie API-Schlüssel im sicheren Speicher Ihres Betriebssystems. Die Bibliothek keyring-core übernimmt dies, indem sie eine Verbindung zum macOS-Schlüsselbund, zur Windows-Anmeldeinformationsverwaltung und zum Linux Secret Service herstellt."
|
||||
|
||||
-- Copies the certificate bundle path to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3550115021"] = "Kopiert den Pfad des Zertifikat-Bundles in die Zwischenablage"
|
||||
|
||||
-- Motivation
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3563271893"] = "Motivation"
|
||||
|
||||
-- not available
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3574465749"] = "nicht verfügbar"
|
||||
|
||||
-- active
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3648362799"] = "aktiv"
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3722989559"] = "Diese Bibliothek wird verwendet, um Excel- und OpenDocument-Tabellendateien zu lesen. Dies ist zum Beispiel notwendig, wenn Tabellen als Datenquelle für einen Chat verwendet werden sollen."
|
||||
|
||||
-- Username provided by the OS
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3764549776"] = "Vom Betriebssystem bereitgestellter Benutzername"
|
||||
|
||||
-- Allowed host:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3774270763"] = "Zulässiger Host:"
|
||||
|
||||
-- Configuration source:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3801531724"] = "Quelle der Konfiguration:"
|
||||
|
||||
-- this version does not met the requirements
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3813932670"] = "diese Version erfüllt die Anforderungen nicht"
|
||||
|
||||
@ -6270,6 +6459,12 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3874337003"] = "Diese Bibliothek
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3908558992"] = "Jetzt haben wir mehrere Systeme, einige entwickelt in .NET und andere in Rust. Das Datenformat JSON ist dafür zuständig, Daten zwischen beiden Welten zu übersetzen (dies nennt man Serialisierung und Deserialisierung von Daten). In der Rust-Welt übernimmt Serde diese Aufgabe. Das Pendant in der .NET-Welt ist ein fester Bestandteil von .NET und findet sich in System.Text.Json."
|
||||
|
||||
-- not applicable
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T396609403"] = "nicht zutreffend"
|
||||
|
||||
-- Copies the allowed host configuration to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3970230163"] = "Kopiert die zulässige Host-Konfiguration in die Zwischenablage"
|
||||
|
||||
-- Installed Pandoc version
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3983971016"] = "Installierte Pandoc-Version"
|
||||
|
||||
@ -6279,8 +6474,8 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3986423270"] = "Pandoc-Installat
|
||||
-- Versions
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4010195468"] = "Versionen"
|
||||
|
||||
-- Database
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4036243672"] = "Datenbank"
|
||||
-- Allowed hosts: none configured
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4058524336"] = "Zulässige Hosts: keine konfiguriert"
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4060906280"] = "Diese Bibliothek wird von der Rust-Laufzeitumgebung verwendet, um den Benutzernamen des aktuellen Benutzers auszulesen, z. B. wenn ein von einer Organisation verwalteter ERI-Server den OS-Benutzernamen für die Authentifizierung verwendet."
|
||||
@ -6291,12 +6486,24 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4079152443"] = "Diese Bibliothek
|
||||
-- Community & Code
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4158546761"] = "Community & Code"
|
||||
|
||||
-- Executable path
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4164953312"] = "Pfad der ausführbaren Datei"
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4184485147"] = "Wir verwenden das HtmlAgilityPack, um Inhalte aus dem Internet zu extrahieren. Das ist zum Beispiel notwendig, wenn Sie eine URL als Eingabe für einen Assistenten angeben."
|
||||
|
||||
-- Copies the working directory to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4194302113"] = "Kopiert das Arbeitsverzeichnis in die Zwischenablage"
|
||||
|
||||
-- Certificate bundle:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4197142390"] = "Zertifikatsbündel:"
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4229014037"] = "Beim Übertragen sensibler Daten zwischen der Rust-Laufzeitumgebung und der .NET-Anwendung verschlüsseln wir die Daten. Dafür verwenden wir einige Bibliotheken aus dem Rust Crypto-Projekt: cipher, aes, cbc, pbkdf2, hmac und sha2. Wir sind dankbar für die großartige Arbeit des Rust Crypto-Projekts."
|
||||
|
||||
-- Copies the status to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4291960437"] = "Kopiert den Status in die Zwischenablage"
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T566998575"] = "Dies ist eine Bibliothek, die die Grundlagen für asynchrones Programmieren in Rust bereitstellt. Sie enthält zentrale Trait-Definitionen wie Stream sowie Hilfsfunktionen wie join!, select! und verschiedene Methoden zur Kombination von Futures, die einen ausdrucksstarken asynchronen Kontrollfluss ermöglichen."
|
||||
|
||||
@ -6306,6 +6513,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T585329785"] = "Verwendetes .NET
|
||||
-- starting
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T594602073"] = "wird gestartet"
|
||||
|
||||
-- Root certificate fingerprint:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T615041128"] = "Fingerabdruck des Stammzertifikats:"
|
||||
|
||||
-- This library is used to manage sidecar processes and to ensure that stale or zombie sidecars are detected and terminated.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T633932150"] = "Diese Bibliothek wird verwendet, um Sidecar-Prozesse zu verwalten und sicherzustellen, dass veraltete oder Zombie-Sidecars erkannt und beendet werden."
|
||||
|
||||
@ -6315,6 +6525,15 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T639371534"] = "Haben Sie einen F
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T64689067"] = "Diese Rust-Bibliothek wird verwendet, um die Nachrichten der App im Terminal auszugeben. Das ist während der Entwicklung und Fehlersuche hilfreich. Diese Funktion ist zunächst unsichtbar; werden App über das Terminal gestartet, werden die Nachrichten sichtbar."
|
||||
|
||||
-- not active
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T70364248"] = "nicht aktiv"
|
||||
|
||||
-- Loaded root certificates:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T709525418"] = "Geladene Stammzertifikate:"
|
||||
|
||||
-- Working directory
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T768480635"] = "Arbeitsverzeichnis"
|
||||
|
||||
-- Copies the config ID to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T788846912"] = "Kopiert die Konfigurations-ID in die Zwischenablage"
|
||||
|
||||
@ -6597,6 +6816,12 @@ UI_TEXT_CONTENT["AISTUDIO::PROVIDER::OPENAI::PROVIDEROPENAI::T757371511"] = "Ans
|
||||
-- Model as configured by whisper.cpp
|
||||
UI_TEXT_CONTENT["AISTUDIO::PROVIDER::SELFHOSTED::PROVIDERSELFHOSTED::T3313940770"] = "Modell wie in whisper.cpp konfiguriert"
|
||||
|
||||
-- The llama.cpp provider '{0}' does not offer a usable text model. Please check your provider settings.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PROVIDER::SELFHOSTED::PROVIDERSELFHOSTED::T3839908321"] = "Der llama.cpp-Anbieter „{0}“ bietet kein verwendbares Textmodell an. Bitte überprüfen Sie Ihre Anbieter-Einstellungen."
|
||||
|
||||
-- The llama.cpp provider '{0}' offers multiple models. Please open the provider settings and select the model to use.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PROVIDER::SELFHOSTED::PROVIDERSELFHOSTED::T4018006464"] = "Der llama.cpp-Anbieter „{0}“ bietet mehrere Modelle an. Bitte öffnen Sie die Anbietereinstellungen und wählen Sie das zu verwendende Modell aus."
|
||||
|
||||
-- Cannot export this chat template because example message {0} is not a text message.
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CHATTEMPLATE::T1861800849"] = "Diese Chatvorlage kann nicht exportiert werden, da die Beispielnachricht {0} keine Textnachricht ist."
|
||||
|
||||
@ -7005,20 +7230,32 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::NODATABASECLIENT::T3662391977"] = "
|
||||
-- Status
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::NODATABASECLIENT::T6222351"] = "Status"
|
||||
|
||||
-- Storage size
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::QDRANT::QDRANTCLIENTIMPLEMENTATION::T1230141403"] = "Speichergröße"
|
||||
-- Reason
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::NOVECTORSTORECLIENT::T1093747001"] = "Grund"
|
||||
|
||||
-- HTTP port
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::QDRANT::QDRANTCLIENTIMPLEMENTATION::T1717573768"] = "HTTP-Port"
|
||||
-- Starting
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::NOVECTORSTORECLIENT::T1233211769"] = "Starten"
|
||||
|
||||
-- Unavailable
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::NOVECTORSTORECLIENT::T3662391977"] = "Nicht verfügbar"
|
||||
|
||||
-- Status
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::NOVECTORSTORECLIENT::T6222351"] = "Status"
|
||||
|
||||
-- Storage size
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::QDRANTEDGECLIENTIMPLEMENTATION::T1230141403"] = "Speichergröße"
|
||||
|
||||
-- Number of vector stores
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::QDRANTEDGECLIENTIMPLEMENTATION::T2785004838"] = "Anzahl der Vektordatenbanken"
|
||||
|
||||
-- Reported version
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::QDRANT::QDRANTCLIENTIMPLEMENTATION::T3556099842"] = "Gemeldete Version"
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::QDRANTEDGECLIENTIMPLEMENTATION::T3556099842"] = "Gemeldete Version"
|
||||
|
||||
-- gRPC port
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::QDRANT::QDRANTCLIENTIMPLEMENTATION::T757840040"] = "gRPC-Port"
|
||||
-- Status
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::QDRANTEDGECLIENTIMPLEMENTATION::T6222351"] = "Status"
|
||||
|
||||
-- Number of collections
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::QDRANT::QDRANTCLIENTIMPLEMENTATION::T842647336"] = "Anzahl der Collections"
|
||||
-- Qdrant Edge is not available.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::QDRANTEDGECLIENTIMPLEMENTATION::T744445696"] = "Qdrant Edge ist nicht verfügbar."
|
||||
|
||||
-- The related data is not allowed to be sent to any LLM provider. This means that this data source cannot be used at the moment.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ERICLIENT::DATAMODEL::PROVIDERTYPEEXTENSIONS::T1555790630"] = "Die zugehörigen Daten dürfen an keinen LLM-Anbieter gesendet werden. Das bedeutet, dass diese Datenquelle momentan nicht verwendet werden kann."
|
||||
@ -7131,6 +7368,27 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::ERICLIENT::ERICLIENTV1::T816853779"] = "Fehler
|
||||
-- Failed to retrieve the authentication methods: the ERI server did not return a valid response.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ERICLIENT::ERICLIENTV1::T984407320"] = "Fehler beim Abrufen der Authentifizierungsmethoden: Der ERI-Server hat keine gültige Antwort zurückgegeben."
|
||||
|
||||
-- No certificate bundle path is configured.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T1033171304"] = "Es ist kein Pfad für das Zertifikats-Bundle konfiguriert."
|
||||
|
||||
-- app settings
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T1736441001"] = "App-Einstellungen"
|
||||
|
||||
-- environment variables
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T317663851"] = "Umgebungsvariablen"
|
||||
|
||||
-- configuration plugin
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T3427095600"] = "Konfigurations-Plugin"
|
||||
|
||||
-- The configured certificate bundle file does not exist.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T3928871850"] = "Die konfigurierte Zertifikats-Bundle-Datei existiert nicht."
|
||||
|
||||
-- The configured certificate bundle does not contain usable root CA certificates.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T599774443"] = "Das konfigurierte Zertifikats-Bundle enthält keine verwendbaren Root-CA-Zertifikate."
|
||||
|
||||
-- policy files
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T632340680"] = "Richtliniendateien"
|
||||
|
||||
-- AI Studio couldn't install Pandoc because the archive was not found.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PANDOC::T1059477764"] = "AI Studio konnte Pandoc nicht installieren, da das Archiv nicht gefunden wurde."
|
||||
|
||||
@ -7650,6 +7908,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T2502277006"] = "Benutzerdefi
|
||||
-- Media
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T3507473059"] = "Medien"
|
||||
|
||||
-- Certificate bundle
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T3543954504"] = "Zertifikatsbündel"
|
||||
|
||||
-- Source like prefix
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T378481461"] = "Source Code ähnlicher Prefix"
|
||||
|
||||
@ -7665,6 +7926,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PANDOCAVAILABILITYSERVICE::T25964655
|
||||
-- Failed to store the secret data due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T1110203516"] = "Fehler beim Speichern der geheimen Daten aufgrund eines API-Problems."
|
||||
|
||||
-- Failed to store the API key due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T1704298921"] = "Fehler beim Speichern des API-Schlüssels aufgrund eines API-Problems."
|
||||
|
||||
-- Failed to delete the secret data due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T2303057928"] = "Das Löschen der geheimen Daten ist aufgrund eines API-Problems fehlgeschlagen."
|
||||
|
||||
|
||||
@ -2169,6 +2169,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIDENCEINFO::T847071819"] = "Shows and
|
||||
-- This feature is managed by your organization and has therefore been disabled.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONBASE::T1416426626"] = "This feature is managed by your organization and has therefore been disabled."
|
||||
|
||||
-- Choose File
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONFILE::T4285779702"] = "Choose File"
|
||||
|
||||
-- Choose the minimum confidence level that all LLM providers must meet. This way, you can ensure that only trustworthy providers are used. You cannot use any provider that falls below this level.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONMINCONFIDENCESELECTION::T2526727283"] = "Choose the minimum confidence level that all LLM providers must meet. This way, you can ensure that only trustworthy providers are used. You cannot use any provider that falls below this level."
|
||||
|
||||
@ -2631,12 +2634,18 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1278320412"]
|
||||
-- How often should we check for app updates?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1364944735"] = "How often should we check for app updates?"
|
||||
|
||||
-- Additional root certificates are enabled
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1380446131"] = "Additional root certificates are enabled"
|
||||
|
||||
-- Select preview features
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1439783084"] = "Select preview features"
|
||||
|
||||
-- Your organization provided a default start page, but you can still change it.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1454730224"] = "Your organization provided a default start page, but you can still change it."
|
||||
|
||||
-- Root certificate bundle path
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1471315821"] = "Root certificate bundle path"
|
||||
|
||||
-- Select the desired behavior for the navigation bar.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T1555038969"] = "Select the desired behavior for the navigation bar."
|
||||
|
||||
@ -2691,12 +2700,24 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2591866808"]
|
||||
-- Choose which page AI Studio should open first when you start the app. Changes take effect the next time you launch AI Studio.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2655930524"] = "Choose which page AI Studio should open first when you start the app. Changes take effect the next time you launch AI Studio."
|
||||
|
||||
-- Path to a PEM file containing one or more root CA certificates. For Flatpak deployments, this file must be placed in a location that is readable inside the sandbox.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2700836219"] = "Path to a PEM file containing one or more root CA certificates. For Flatpak deployments, this file must be placed in a location that is readable inside the sandbox."
|
||||
|
||||
-- Enter one host pattern per line. Exact hosts such as data.intra.example.org and one-label wildcards such as *.intra.example.org are supported. Cloud provider endpoints built into AI Studio, such as OpenAI, Google, etc., never use these additional root certificates.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T2960110864"] = "Enter one host pattern per line. Exact hosts such as data.intra.example.org and one-label wildcards such as *.intra.example.org are supported. Cloud provider endpoints built into AI Studio, such as OpenAI, Google, etc., never use these additional root certificates."
|
||||
|
||||
-- Save energy?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3100928009"] = "Save energy?"
|
||||
|
||||
-- Spellchecking is enabled
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3165555978"] = "Spellchecking is enabled"
|
||||
|
||||
-- External HTTPS certificates
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T348936513"] = "External HTTPS certificates"
|
||||
|
||||
-- Allowed hosts for additional root certificates
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3562495752"] = "Allowed hosts for additional root certificates"
|
||||
|
||||
-- Request timeout
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3569531009"] = "Request timeout"
|
||||
|
||||
@ -2715,9 +2736,15 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3694781396"]
|
||||
-- Read the Enterprise IT documentation for details.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3705451321"] = "Read the Enterprise IT documentation for details."
|
||||
|
||||
-- When enabled, AI Studio can trust root certificates from a configured PEM bundle for external HTTPS requests, such as self-hosted AI providers, embeddings, transcription, ERI data sources, and enterprise configuration downloads. Normal hostname and certificate validity checks still apply. Integrated cloud providers, such as OpenAI, Google, and others, will never use these additional certificates. Please note that you usually do not need this setting on macOS or Windows. If you use Linux with the AppImage version of MindWork AI Studio, you also do not need this option. A valid use case is a Linux environment where AI Studio runs from a Flatpak.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3798070907"] = "When enabled, AI Studio can trust root certificates from a configured PEM bundle for external HTTPS requests, such as self-hosted AI providers, embeddings, transcription, ERI data sources, and enterprise configuration downloads. Normal hostname and certificate validity checks still apply. Integrated cloud providers, such as OpenAI, Google, and others, will never use these additional certificates. Please note that you usually do not need this setting on macOS or Windows. If you use Linux with the AppImage version of MindWork AI Studio, you also do not need this option. A valid use case is a Linux environment where AI Studio runs from a Flatpak."
|
||||
|
||||
-- Enable spellchecking?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3914529369"] = "Enable spellchecking?"
|
||||
|
||||
-- Additional root certificates are disabled
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T3985928190"] = "Additional root certificates are disabled"
|
||||
|
||||
-- Preselect one of your profiles?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T4004501229"] = "Preselect one of your profiles?"
|
||||
|
||||
@ -2730,6 +2757,12 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T4174666315"]
|
||||
-- How long AI Studio waits for external HTTP requests, such as AI providers, embeddings, transcription, ERI data sources, and enterprise configuration downloads.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T4192032183"] = "How long AI Studio waits for external HTTP requests, such as AI providers, embeddings, transcription, ERI data sources, and enterprise configuration downloads."
|
||||
|
||||
-- Use additional root certificates for external HTTPS requests?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T4235562267"] = "Use additional root certificates for external HTTPS requests?"
|
||||
|
||||
-- Select a root certificate bundle
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T436881267"] = "Select a root certificate bundle"
|
||||
|
||||
-- Navigation bar behavior
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T602293588"] = "Navigation bar behavior"
|
||||
|
||||
@ -2760,6 +2793,54 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T922066419"]
|
||||
-- Administration settings are not visible
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAPP::T929143445"] = "Administration settings are not visible"
|
||||
|
||||
-- Show provider's confidence level?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T1052533048"] = "Show provider's confidence level?"
|
||||
|
||||
-- Choose the scheme that best suits you and your organization. Do you trust any western provider? Or only providers from the USA or exclusively European providers? Then choose the appropriate scheme. Alternatively, you can assign the confidence levels to each provider yourself.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T1081931329"] = "Choose the scheme that best suits you and your organization. Do you trust any western provider? Or only providers from the USA or exclusively European providers? Then choose the appropriate scheme. Alternatively, you can assign the confidence levels to each provider yourself."
|
||||
|
||||
-- Provider Confidence
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T1453422580"] = "Provider Confidence"
|
||||
|
||||
-- When enabled, you can enforce a minimum confidence level for all features in AI Studio. This way, you can make sure only trustworthy providers are used.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T1499004705"] = "When enabled, you can enforce a minimum confidence level for all features in AI Studio. This way, you can make sure only trustworthy providers are used."
|
||||
|
||||
-- When enabled, we show you the confidence level for the selected provider in the app. This helps you assess where you are sending your data at any time. Example: are you currently working with sensitive data? Then choose a particularly trustworthy provider, etc.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T1505516304"] = "When enabled, we show you the confidence level for the selected provider in the app. This helps you assess where you are sending your data at any time. Example: are you currently working with sensitive data? Then choose a particularly trustworthy provider, etc."
|
||||
|
||||
-- No, please hide the confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T1628475119"] = "No, please hide the confidence level"
|
||||
|
||||
-- Description
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T1725856265"] = "Description"
|
||||
|
||||
-- Confidence Level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T2492230131"] = "Confidence Level"
|
||||
|
||||
-- No, do not enforce a minimum confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T3642102079"] = "No, do not enforce a minimum confidence level"
|
||||
|
||||
-- Select a confidence scheme
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T4144206465"] = "Select a confidence scheme"
|
||||
|
||||
-- Do you want to enforce an global minimum confidence level?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T4211873175"] = "Do you want to enforce an global minimum confidence level?"
|
||||
|
||||
-- Yes, enforce a minimum confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T458854917"] = "Yes, enforce a minimum confidence level"
|
||||
|
||||
-- Not yet configured
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T48051324"] = "Not yet configured"
|
||||
|
||||
-- Do you want to always see how trustworthy your providers are? This way, you stay in control of which provider you send your data to. You can choose a common schema or configure the trust levels for each provider yourself.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T700839804"] = "Do you want to always see how trustworthy your providers are? This way, you stay in control of which provider you send your data to. You can choose a common schema or configure the trust levels for each provider yourself."
|
||||
|
||||
-- Yes, show me the confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T853225204"] = "Yes, show me the confidence level"
|
||||
|
||||
-- Provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T900237532"] = "Provider"
|
||||
|
||||
-- Embedding Result
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T1387042335"] = "Embedding Result"
|
||||
|
||||
@ -2814,6 +2895,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T32678
|
||||
-- Close
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T3448155331"] = "Close"
|
||||
|
||||
-- This embedding provider is trusted by your organization for data source security checks. Local data can be sent to it without security warnings.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T3459188215"] = "This embedding provider is trusted by your organization for data source security checks. Local data can be sent to it without security warnings."
|
||||
|
||||
-- Actions
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T3865031940"] = "Actions"
|
||||
|
||||
@ -2856,21 +2940,12 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERBASE::T336
|
||||
-- Export API Key?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERBASE::T4010580285"] = "Export API Key?"
|
||||
|
||||
-- Show provider's confidence level?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T1052533048"] = "Show provider's confidence level?"
|
||||
-- This provider is trusted by your organization for data source security checks.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T1298650849"] = "This provider is trusted by your organization for data source security checks."
|
||||
|
||||
-- Delete
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T1469573738"] = "Delete"
|
||||
|
||||
-- When enabled, we show you the confidence level for the selected provider in the app. This helps you assess where you are sending your data at any time. Example: are you currently working with sensitive data? Then choose a particularly trustworthy provider, etc.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T1505516304"] = "When enabled, we show you the confidence level for the selected provider in the app. This helps you assess where you are sending your data at any time. Example: are you currently working with sensitive data? Then choose a particularly trustworthy provider, etc."
|
||||
|
||||
-- No, please hide the confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T1628475119"] = "No, please hide the confidence level"
|
||||
|
||||
-- Description
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T1725856265"] = "Description"
|
||||
|
||||
-- Uses the provider-configured model
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T1760715963"] = "Uses the provider-configured model"
|
||||
|
||||
@ -2886,27 +2961,12 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T186876
|
||||
-- Are you sure you want to delete the provider '{0}'?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2031310917"] = "Are you sure you want to delete the provider '{0}'?"
|
||||
|
||||
-- Do you want to always be able to recognize how trustworthy your LLM providers are? This way, you keep control over which provider you send your data to. You have two options for this: Either you choose a common schema, or you configure the trust levels for each LLM provider yourself.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2082904277"] = "Do you want to always be able to recognize how trustworthy your LLM providers are? This way, you keep control over which provider you send your data to. You have two options for this: Either you choose a common schema, or you configure the trust levels for each LLM provider yourself."
|
||||
|
||||
-- Model
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2189814010"] = "Model"
|
||||
|
||||
-- Choose the scheme that best suits you and your life. Do you trust any western provider? Or only providers from the USA or exclusively European providers? Then choose the appropriate scheme. Alternatively, you can assign the confidence levels to each provider yourself.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2283885378"] = "Choose the scheme that best suits you and your life. Do you trust any western provider? Or only providers from the USA or exclusively European providers? Then choose the appropriate scheme. Alternatively, you can assign the confidence levels to each provider yourself."
|
||||
|
||||
-- LLM Provider Confidence
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2349972795"] = "LLM Provider Confidence"
|
||||
|
||||
-- What we call a provider is the combination of an LLM provider such as OpenAI and a model like GPT-4o. You can configure as many providers as you want. This way, you can use the appropriate model for each task. As an LLM provider, you can also choose local providers. However, to use this app, you must configure at least one provider.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2460361126"] = "What we call a provider is the combination of an LLM provider such as OpenAI and a model like GPT-4o. You can configure as many providers as you want. This way, you can use the appropriate model for each task. As an LLM provider, you can also choose local providers. However, to use this app, you must configure at least one provider."
|
||||
|
||||
-- Confidence Level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2492230131"] = "Confidence Level"
|
||||
|
||||
-- When enabled, you can enforce a minimum confidence level for all LLM providers. This way, you can ensure that only trustworthy providers are used.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T281063702"] = "When enabled, you can enforce a minimum confidence level for all LLM providers. This way, you can ensure that only trustworthy providers are used."
|
||||
|
||||
-- Instance Name
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T2842060373"] = "Instance Name"
|
||||
|
||||
@ -2928,36 +2988,15 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T334643
|
||||
-- This provider is managed by your organization.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T3415927576"] = "This provider is managed by your organization."
|
||||
|
||||
-- LLM Provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T3612415205"] = "LLM Provider"
|
||||
|
||||
-- No, do not enforce a minimum confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T3642102079"] = "No, do not enforce a minimum confidence level"
|
||||
|
||||
-- Actions
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T3865031940"] = "Actions"
|
||||
|
||||
-- Select a confidence scheme
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T4144206465"] = "Select a confidence scheme"
|
||||
|
||||
-- Do you want to enforce an app-wide minimum confidence level?
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T4258968041"] = "Do you want to enforce an app-wide minimum confidence level?"
|
||||
|
||||
-- Delete LLM Provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T4269256234"] = "Delete LLM Provider"
|
||||
|
||||
-- Yes, enforce a minimum confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T458854917"] = "Yes, enforce a minimum confidence level"
|
||||
|
||||
-- Not yet configured
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T48051324"] = "Not yet configured"
|
||||
|
||||
-- Open Dashboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T78223861"] = "Open Dashboard"
|
||||
|
||||
-- Yes, show me the confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T853225204"] = "Yes, show me the confidence level"
|
||||
|
||||
-- Provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T900237532"] = "Provider"
|
||||
|
||||
@ -3006,6 +3045,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T42
|
||||
-- With the support of transcription models, MindWork AI Studio can convert human speech into text. This is useful, for example, when you need to dictate text. You can choose from dedicated transcription models, but not multimodal LLMs (large language models) that can handle both speech and text. The configuration of multimodal models is done in the 'Configure LLM providers' section.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T584860404"] = "With the support of transcription models, MindWork AI Studio can convert human speech into text. This is useful, for example, when you need to dictate text. You can choose from dedicated transcription models, but not multimodal LLMs (large language models) that can handle both speech and text. The configuration of multimodal models is done in the 'Configure LLM providers' section."
|
||||
|
||||
-- This transcription provider is trusted by your organization for data source security checks.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T601264181"] = "This transcription provider is trusted by your organization for data source security checks."
|
||||
|
||||
-- This transcription provider is managed by your organization.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T756131076"] = "This transcription provider is managed by your organization."
|
||||
|
||||
@ -3165,15 +3207,27 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1469573738"] = "Delete"
|
||||
-- Rename Workspace
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1474303418"] = "Rename Workspace"
|
||||
|
||||
-- Clear search
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1511254342"] = "Clear search"
|
||||
|
||||
-- Rename Chat
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T156144855"] = "Rename Chat"
|
||||
|
||||
-- Add workspace
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1586005241"] = "Add workspace"
|
||||
|
||||
-- Search chats
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1615077202"] = "Search chats"
|
||||
|
||||
-- Start a new chat in workspace '{0}'
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1840064668"] = "Start a new chat in workspace '{0}'"
|
||||
|
||||
-- Add chat
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1874060138"] = "Add chat"
|
||||
|
||||
-- No chats found
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1886517101"] = "No chats found"
|
||||
|
||||
-- Create Chat
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T1939006681"] = "Create Chat"
|
||||
|
||||
@ -3210,6 +3264,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3045856778"] = "Move Chat to
|
||||
-- Please enter a new or edit the name for your workspace '{0}':
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T323280982"] = "Please enter a new or edit the name for your workspace '{0}':"
|
||||
|
||||
-- There is already a workspace with this name. Please choose a different name.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3249036008"] = "There is already a workspace with this name. Please choose a different name."
|
||||
|
||||
-- Please enter a workspace name.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3288132732"] = "Please enter a workspace name."
|
||||
|
||||
@ -3219,6 +3276,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3355849203"] = "Rename"
|
||||
-- Please enter a new or edit the name for your chat '{0}':
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3419791373"] = "Please enter a new or edit the name for your chat '{0}':"
|
||||
|
||||
-- Search chat contents
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3436662033"] = "Search chat contents"
|
||||
|
||||
-- Load Chat
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3555709365"] = "Load Chat"
|
||||
|
||||
@ -3465,6 +3525,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3227981830"] = "Using s
|
||||
-- Add a message
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3372872324"] = "Add a message"
|
||||
|
||||
-- Close
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3448155331"] = "Close"
|
||||
|
||||
-- Unsupported content type
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3570316759"] = "Unsupported content type"
|
||||
|
||||
@ -4245,6 +4308,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T3243902394"] = "The profile
|
||||
-- Profile Name
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T3392578705"] = "Profile Name"
|
||||
|
||||
-- Close
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T3448155331"] = "Close"
|
||||
|
||||
-- Please enter what the LLM should know about you and/or what actions it should take.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROFILEDIALOG::T3708405102"] = "Please enter what the LLM should know about you and/or what actions it should take."
|
||||
|
||||
@ -4764,6 +4830,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T14695
|
||||
-- Add Chat Template
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T1548314416"] = "Add Chat Template"
|
||||
|
||||
-- View
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T1582017048"] = "View"
|
||||
|
||||
-- Note: This advanced feature is designed for users familiar with prompt engineering concepts. Furthermore, you have to make sure yourself that your chosen provider supports the use of assistant prompts.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T1909110760"] = "Note: This advanced feature is designed for users familiar with prompt engineering concepts. Furthermore, you have to make sure yourself that your chosen provider supports the use of assistant prompts."
|
||||
|
||||
@ -4803,6 +4872,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T38650
|
||||
-- Delete Chat Template
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T4025180906"] = "Delete Chat Template"
|
||||
|
||||
-- View Chat Template
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T4042112076"] = "View Chat Template"
|
||||
|
||||
-- Export Chat Template
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T491504763"] = "Export Chat Template"
|
||||
|
||||
@ -5211,6 +5283,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T143353473
|
||||
-- Delete
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T1469573738"] = "Delete"
|
||||
|
||||
-- View
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T1582017048"] = "View"
|
||||
|
||||
-- Your Profiles
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T2378610256"] = "Your Profiles"
|
||||
|
||||
@ -5235,6 +5310,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T405841465
|
||||
-- Store personal data about yourself in various profiles so that the AIs know your personal context. This saves you from having to explain your context each time, for example, in every chat. When you have different roles, you can create a profile for each role.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T4125557797"] = "Store personal data about yourself in various profiles so that the AIs know your personal context. This saves you from having to explain your context each time, for example, in every chat. When you have different roles, you can create a profile for each role."
|
||||
|
||||
-- View Profile
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T4219233997"] = "View Profile"
|
||||
|
||||
-- Add Profile
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGPROFILES::T4248067241"] = "Add Profile"
|
||||
|
||||
@ -5748,15 +5826,39 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::UPDATEDIALOG::T25417398"] = "Update from v{0
|
||||
-- Install later
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::UPDATEDIALOG::T2936430090"] = "Install later"
|
||||
|
||||
-- Create new workspace
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::WORKSPACESELECTIONDIALOG::T1541251414"] = "Create new workspace"
|
||||
|
||||
-- Add workspace
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::WORKSPACESELECTIONDIALOG::T1586005241"] = "Add workspace"
|
||||
|
||||
-- Workspace name
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::WORKSPACESELECTIONDIALOG::T295876489"] = "Workspace name"
|
||||
|
||||
-- There is already a workspace with this name. Please choose a different name.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::WORKSPACESELECTIONDIALOG::T3249036008"] = "There is already a workspace with this name. Please choose a different name."
|
||||
|
||||
-- Please enter a workspace name.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::WORKSPACESELECTIONDIALOG::T3288132732"] = "Please enter a workspace name."
|
||||
|
||||
-- Cancel
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::WORKSPACESELECTIONDIALOG::T900713019"] = "Cancel"
|
||||
|
||||
-- Reason
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1093747001"] = "Reason"
|
||||
|
||||
-- Settings
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1258653480"] = "Settings"
|
||||
|
||||
-- Your settings file does not contain a settings-format version. Changes in this session will not be saved to avoid overwriting your settings. Please check for updates or contact support.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1378304679"] = "Your settings file does not contain a settings-format version. Changes in this session will not be saved to avoid overwriting your settings. Please check for updates or contact support."
|
||||
|
||||
-- Home
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1391791790"] = "Home"
|
||||
|
||||
-- AI Studio found the current settings format but could not load it safely. Changes in this session will not be saved. Please check for updates or contact support.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1497084127"] = "AI Studio found the current settings format but could not load it safely. Changes in this session will not be saved. Please check for updates or contact support."
|
||||
|
||||
-- Are you sure you want to leave the chat page? All unsaved changes will be lost.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1563130494"] = "Are you sure you want to leave the chat page? All unsaved changes will be lost."
|
||||
|
||||
@ -5766,12 +5868,21 @@ UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1614176092"] = "Assistants"
|
||||
-- Update
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1847791252"] = "Update"
|
||||
|
||||
-- Check for updates
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1890416390"] = "Check for updates"
|
||||
|
||||
-- Your settings were created by a newer AI Studio version. Changes in this session will not be saved. Please install or start the latest available update.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T1988273622"] = "Your settings were created by a newer AI Studio version. Changes in this session will not be saved. Please install or start the latest available update."
|
||||
|
||||
-- Leave Chat Page
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2124749705"] = "Leave Chat Page"
|
||||
|
||||
-- Plugins
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2222816203"] = "Plugins"
|
||||
|
||||
-- AI Studio cannot safely save settings in this session. Please check for updates or contact support.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2382622618"] = "AI Studio cannot safely save settings in this session. Please check for updates or contact support."
|
||||
|
||||
-- An update to version {0} is available.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2800137365"] = "An update to version {0} is available."
|
||||
|
||||
@ -5781,6 +5892,9 @@ UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2864211629"] = "Please wait for
|
||||
-- Supporters
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2929332068"] = "Supporters"
|
||||
|
||||
-- AI Studio could not read your settings file. Changes in this session will not be saved to avoid overwriting recoverable settings. Please check for updates or contact support.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2936083926"] = "AI Studio could not read your settings file. Changes in this session will not be saved to avoid overwriting recoverable settings. Please check for updates or contact support."
|
||||
|
||||
-- Writing
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2979224202"] = "Writing"
|
||||
|
||||
@ -5793,6 +5907,9 @@ UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T4256323669"] = "Information"
|
||||
-- Chat
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T578410699"] = "Chat"
|
||||
|
||||
-- AI Studio does not recognize your settings-format version. Changes in this session will not be saved to avoid overwriting your settings. Please check for updates or contact support.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T915412625"] = "AI Studio does not recognize your settings-format version. Changes in this session will not be saved to avoid overwriting your settings. Please check for updates or contact support."
|
||||
|
||||
-- Get coding and debugging support from an LLM.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T1243850917"] = "Get coding and debugging support from an LLM."
|
||||
|
||||
@ -5925,6 +6042,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T878695986"] = "Learn about one co
|
||||
-- Localization
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::ASSISTANTS::T897888480"] = "Localization"
|
||||
|
||||
-- Hide search
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::CHAT::T1281128983"] = "Hide search"
|
||||
|
||||
-- Reload your workspaces
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::CHAT::T194629703"] = "Reload your workspaces"
|
||||
|
||||
@ -5937,6 +6057,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::CHAT::T2813205227"] = "Open Chat Options"
|
||||
-- Disappearing Chat
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::CHAT::T3046519404"] = "Disappearing Chat"
|
||||
|
||||
-- Search your workspaces
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::CHAT::T3059773282"] = "Search your workspaces"
|
||||
|
||||
-- Configure your workspaces
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::CHAT::T3586092784"] = "Configure your workspaces"
|
||||
|
||||
@ -5970,6 +6093,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T144565305"] = "The app requires minimal
|
||||
-- You only pay for what you use, which can be cheaper than monthly subscription services like ChatGPT Plus, especially if used infrequently. But beware, here be dragons: For extremely intensive usage, the API costs can be significantly higher. Unfortunately, providers currently do not offer a way to display current costs in the app. Therefore, check your account with the respective provider to see how your costs are developing. When available, use prepaid and set a cost limit.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T149711988"] = "You only pay for what you use, which can be cheaper than monthly subscription services like ChatGPT Plus, especially if used infrequently. But beware, here be dragons: For extremely intensive usage, the API costs can be significantly higher. Unfortunately, providers currently do not offer a way to display current costs in the app. Therefore, check your account with the respective provider to see how your costs are developing. When available, use prepaid and set a cost limit."
|
||||
|
||||
-- Version
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T1573770551"] = "Version"
|
||||
|
||||
-- Assistants
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T1614176092"] = "Assistants"
|
||||
|
||||
@ -6039,27 +6165,42 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T91074375"] = "The app is free to use, b
|
||||
-- Startup log file
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1019424746"] = "Startup log file"
|
||||
|
||||
-- The configured root certificates could not be used.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T103551060"] = "The configured root certificates could not be used."
|
||||
|
||||
-- Browse AI Studio's source code on GitHub — we welcome your contributions.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1107156991"] = "Browse AI Studio's source code on GitHub — we welcome your contributions."
|
||||
|
||||
-- Vector store version
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1124039623"] = "Vector store version"
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1126023000"] = "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."
|
||||
|
||||
-- ID mismatch: the plugin ID differs from the enterprise configuration ID.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1137744461"] = "ID mismatch: the plugin ID differs from the enterprise configuration ID."
|
||||
|
||||
-- This is a private AI Studio installation. It runs without an enterprise configuration.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1209549230"] = "This is a private AI Studio installation. It runs without an enterprise configuration."
|
||||
|
||||
-- Copies the configuration origin to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T125850635"] = "Copies the configuration origin to the clipboard"
|
||||
|
||||
-- Unknown configuration plugin
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1290340974"] = "Unknown configuration plugin"
|
||||
|
||||
-- Copies the configuration slot to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1347508205"] = "Copies the configuration slot to the clipboard"
|
||||
|
||||
-- This library is used to read PDF files. This is necessary, e.g., for using PDFs as a data source for a chat.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1388816916"] = "This library is used to read PDF files. This is necessary, e.g., for using PDFs as a data source for a chat."
|
||||
|
||||
-- Database version
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1420062548"] = "Database version"
|
||||
|
||||
-- This library is used to extend the MudBlazor library. It provides additional components that are not part of the MudBlazor library.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1421513382"] = "This library is used to extend the MudBlazor library. It provides additional components that are not part of the MudBlazor library."
|
||||
|
||||
-- Copies the allowed host pattern to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1513592659"] = "Copies the allowed host pattern to the clipboard"
|
||||
|
||||
-- Waiting for the configuration plugin...
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1533382393"] = "Waiting for the configuration plugin..."
|
||||
|
||||
@ -6069,9 +6210,6 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1560776885"] = "Encryption secre
|
||||
-- AI Studio runs with an enterprise configuration and configuration servers. The configuration plugins are active.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1596483935"] = "AI Studio runs with an enterprise configuration and configuration servers. The configuration plugins are active."
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1619832053"] = "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."
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T162898512"] = "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."
|
||||
|
||||
@ -6084,6 +6222,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1630237140"] = "AI Studio create
|
||||
-- Consent:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T171952677"] = "Consent:"
|
||||
|
||||
-- Copies the executable path to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1722690800"] = "Copies the executable path to the clipboard"
|
||||
|
||||
-- This library is used to display the differences between two texts. This is necessary, e.g., for the grammar and spelling assistant.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1772678682"] = "This library is used to display the differences between two texts. This is necessary, e.g., for the grammar and spelling assistant."
|
||||
|
||||
@ -6108,12 +6249,18 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1924365263"] = "This library is
|
||||
-- Encryption secret: is configured
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T1931141322"] = "Encryption secret: is configured"
|
||||
|
||||
-- Copies the number of loaded root certificates to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2015329654"] = "Copies the number of loaded root certificates to the clipboard"
|
||||
|
||||
-- Copies the following to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2029659664"] = "Copies the following to the clipboard"
|
||||
|
||||
-- Copies the server URL to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2037899437"] = "Copies the server URL to the clipboard"
|
||||
|
||||
-- This library is used to create temporary folders in runtime tests and supporting filesystem operations.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2160280545"] = "This library is used to create temporary folders in runtime tests and supporting filesystem operations."
|
||||
|
||||
-- This library is used to determine the file type of a file. This is necessary, e.g., when we want to stream a file.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2173617769"] = "This library is used to determine the file type of a file. This is necessary, e.g., when we want to stream a file."
|
||||
|
||||
@ -6147,6 +6294,12 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2371107659"] = "installation pro
|
||||
-- Installed Pandoc version: Pandoc is not installed or not available.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2374031539"] = "Installed Pandoc version: Pandoc is not installed or not available."
|
||||
|
||||
-- Configuration origin:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2435772109"] = "Configuration origin:"
|
||||
|
||||
-- Configuration slot:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T254943559"] = "Configuration slot:"
|
||||
|
||||
-- This library is used to determine the language of the operating system. This is necessary to set the language of the user interface.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2557014401"] = "This library is used to determine the language of the operating system. This is necessary to set the language of the user interface."
|
||||
|
||||
@ -6156,8 +6309,8 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2557066213"] = "Used Open Source
|
||||
-- Build time
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T260228112"] = "Build time"
|
||||
|
||||
-- This library is used to create temporary folders for saving the certificate and private key for communication with Qdrant.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2619858133"] = "This library is used to create temporary folders for saving the certificate and private key for communication with Qdrant."
|
||||
-- unknown
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2608177081"] = "unknown"
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2635482790"] = "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."
|
||||
@ -6201,9 +6354,21 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2868174483"] = "The .NET backend
|
||||
-- AI Studio runs with an enterprise configuration and configuration servers. The configuration plugins are not yet available.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2924964415"] = "AI Studio runs with an enterprise configuration and configuration servers. The configuration plugins are not yet available."
|
||||
|
||||
-- Copies the configuration source to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2929232062"] = "Copies the configuration source to the clipboard"
|
||||
|
||||
-- Copies the root certificate fingerprint to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T2989678330"] = "Copies the root certificate fingerprint to the clipboard"
|
||||
|
||||
-- Changelog
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3017574265"] = "Changelog"
|
||||
|
||||
-- External HTTPS custom root certificates are configured but not active.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3021325354"] = "External HTTPS custom root certificates are configured but not active."
|
||||
|
||||
-- Vector store
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3046399223"] = "Vector store"
|
||||
|
||||
-- Enterprise configuration ID:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3092349641"] = "Enterprise configuration ID:"
|
||||
|
||||
@ -6216,6 +6381,12 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3178730036"] = "Have feature ide
|
||||
-- Hide Details
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3183837919"] = "Hide Details"
|
||||
|
||||
-- Linux package
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3196139293"] = "Linux package"
|
||||
|
||||
-- External HTTPS custom root certificates are active.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3208455732"] = "External HTTPS custom root certificates are active."
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3208719461"] = "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."
|
||||
|
||||
@ -6228,9 +6399,15 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3249965383"] = "Update Pandoc"
|
||||
-- Discover MindWork AI's mission and vision on our official homepage.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3294830584"] = "Discover MindWork AI's mission and vision on our official homepage."
|
||||
|
||||
-- External HTTPS custom root certificates
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3315279770"] = "External HTTPS custom root certificates"
|
||||
|
||||
-- User-language provided by the OS
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3334355246"] = "User-language provided by the OS"
|
||||
|
||||
-- Status:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3396815215"] = "Status:"
|
||||
|
||||
-- The following list shows the versions of the MindWork AI Studio, the used compilers, build time, etc.:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3405978777"] = "The following list shows the versions of the MindWork AI Studio, the used compilers, build time, etc.:"
|
||||
|
||||
@ -6249,18 +6426,30 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3494984593"] = "Tauri is used to
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3527399572"] = "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."
|
||||
|
||||
-- Copies the certificate bundle path to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3550115021"] = "Copies the certificate bundle path to the clipboard"
|
||||
|
||||
-- Motivation
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3563271893"] = "Motivation"
|
||||
|
||||
-- not available
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3574465749"] = "not available"
|
||||
|
||||
-- active
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3648362799"] = "active"
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3722989559"] = "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."
|
||||
|
||||
-- Username provided by the OS
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3764549776"] = "Username provided by the OS"
|
||||
|
||||
-- Allowed host:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3774270763"] = "Allowed host:"
|
||||
|
||||
-- Configuration source:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3801531724"] = "Configuration source:"
|
||||
|
||||
-- this version does not met the requirements
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3813932670"] = "this version does not met the requirements"
|
||||
|
||||
@ -6270,6 +6459,12 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3874337003"] = "This library is
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3908558992"] = "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."
|
||||
|
||||
-- not applicable
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T396609403"] = "not applicable"
|
||||
|
||||
-- Copies the allowed host configuration to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3970230163"] = "Copies the allowed host configuration to the clipboard"
|
||||
|
||||
-- Installed Pandoc version
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3983971016"] = "Installed Pandoc version"
|
||||
|
||||
@ -6279,8 +6474,8 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T3986423270"] = "Check Pandoc Ins
|
||||
-- Versions
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4010195468"] = "Versions"
|
||||
|
||||
-- Database
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4036243672"] = "Database"
|
||||
-- Allowed hosts: none configured
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4058524336"] = "Allowed hosts: none configured"
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4060906280"] = "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."
|
||||
@ -6291,12 +6486,24 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4079152443"] = "This library is
|
||||
-- Community & Code
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4158546761"] = "Community & Code"
|
||||
|
||||
-- Executable path
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4164953312"] = "Executable path"
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4184485147"] = "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."
|
||||
|
||||
-- Copies the working directory to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4194302113"] = "Copies the working directory to the clipboard"
|
||||
|
||||
-- Certificate bundle:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4197142390"] = "Certificate bundle:"
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4229014037"] = "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."
|
||||
|
||||
-- Copies the status to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T4291960437"] = "Copies the status to the clipboard"
|
||||
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T566998575"] = "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."
|
||||
|
||||
@ -6306,6 +6513,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T585329785"] = "Used .NET SDK"
|
||||
-- starting
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T594602073"] = "starting"
|
||||
|
||||
-- Root certificate fingerprint:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T615041128"] = "Root certificate fingerprint:"
|
||||
|
||||
-- This library is used to manage sidecar processes and to ensure that stale or zombie sidecars are detected and terminated.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T633932150"] = "This library is used to manage sidecar processes and to ensure that stale or zombie sidecars are detected and terminated."
|
||||
|
||||
@ -6315,6 +6525,15 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T639371534"] = "Did you find a bu
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T64689067"] = "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."
|
||||
|
||||
-- not active
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T70364248"] = "not active"
|
||||
|
||||
-- Loaded root certificates:
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T709525418"] = "Loaded root certificates:"
|
||||
|
||||
-- Working directory
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T768480635"] = "Working directory"
|
||||
|
||||
-- Copies the config ID to the clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::INFORMATION::T788846912"] = "Copies the config ID to the clipboard"
|
||||
|
||||
@ -6597,6 +6816,12 @@ UI_TEXT_CONTENT["AISTUDIO::PROVIDER::OPENAI::PROVIDEROPENAI::T757371511"] = "It
|
||||
-- Model as configured by whisper.cpp
|
||||
UI_TEXT_CONTENT["AISTUDIO::PROVIDER::SELFHOSTED::PROVIDERSELFHOSTED::T3313940770"] = "Model as configured by whisper.cpp"
|
||||
|
||||
-- The llama.cpp provider '{0}' does not offer a usable text model. Please check your provider settings.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PROVIDER::SELFHOSTED::PROVIDERSELFHOSTED::T3839908321"] = "The llama.cpp provider '{0}' does not offer a usable text model. Please check your provider settings."
|
||||
|
||||
-- The llama.cpp provider '{0}' offers multiple models. Please open the provider settings and select the model to use.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PROVIDER::SELFHOSTED::PROVIDERSELFHOSTED::T4018006464"] = "The llama.cpp provider '{0}' offers multiple models. Please open the provider settings and select the model to use."
|
||||
|
||||
-- Cannot export this chat template because example message {0} is not a text message.
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CHATTEMPLATE::T1861800849"] = "Cannot export this chat template because example message {0} is not a text message."
|
||||
|
||||
@ -7005,20 +7230,32 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::NODATABASECLIENT::T3662391977"] = "
|
||||
-- Status
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::NODATABASECLIENT::T6222351"] = "Status"
|
||||
|
||||
-- Storage size
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::QDRANT::QDRANTCLIENTIMPLEMENTATION::T1230141403"] = "Storage size"
|
||||
-- Reason
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::NOVECTORSTORECLIENT::T1093747001"] = "Reason"
|
||||
|
||||
-- HTTP port
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::QDRANT::QDRANTCLIENTIMPLEMENTATION::T1717573768"] = "HTTP port"
|
||||
-- Starting
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::NOVECTORSTORECLIENT::T1233211769"] = "Starting"
|
||||
|
||||
-- Unavailable
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::NOVECTORSTORECLIENT::T3662391977"] = "Unavailable"
|
||||
|
||||
-- Status
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::NOVECTORSTORECLIENT::T6222351"] = "Status"
|
||||
|
||||
-- Storage size
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::QDRANTEDGECLIENTIMPLEMENTATION::T1230141403"] = "Storage size"
|
||||
|
||||
-- Number of vector stores
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::QDRANTEDGECLIENTIMPLEMENTATION::T2785004838"] = "Number of vector stores"
|
||||
|
||||
-- Reported version
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::QDRANT::QDRANTCLIENTIMPLEMENTATION::T3556099842"] = "Reported version"
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::QDRANTEDGECLIENTIMPLEMENTATION::T3556099842"] = "Reported version"
|
||||
|
||||
-- gRPC port
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::QDRANT::QDRANTCLIENTIMPLEMENTATION::T757840040"] = "gRPC port"
|
||||
-- Status
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::QDRANTEDGECLIENTIMPLEMENTATION::T6222351"] = "Status"
|
||||
|
||||
-- Number of collections
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::QDRANT::QDRANTCLIENTIMPLEMENTATION::T842647336"] = "Number of collections"
|
||||
-- Qdrant Edge is not available.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::DATABASES::VECTORSTORE::QDRANTEDGECLIENTIMPLEMENTATION::T744445696"] = "Qdrant Edge is not available."
|
||||
|
||||
-- The related data is not allowed to be sent to any LLM provider. This means that this data source cannot be used at the moment.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ERICLIENT::DATAMODEL::PROVIDERTYPEEXTENSIONS::T1555790630"] = "The related data is not allowed to be sent to any LLM provider. This means that this data source cannot be used at the moment."
|
||||
@ -7131,6 +7368,27 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::ERICLIENT::ERICLIENTV1::T816853779"] = "Failed
|
||||
-- Failed to retrieve the authentication methods: the ERI server did not return a valid response.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ERICLIENT::ERICLIENTV1::T984407320"] = "Failed to retrieve the authentication methods: the ERI server did not return a valid response."
|
||||
|
||||
-- No certificate bundle path is configured.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T1033171304"] = "No certificate bundle path is configured."
|
||||
|
||||
-- app settings
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T1736441001"] = "app settings"
|
||||
|
||||
-- environment variables
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T317663851"] = "environment variables"
|
||||
|
||||
-- configuration plugin
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T3427095600"] = "configuration plugin"
|
||||
|
||||
-- The configured certificate bundle file does not exist.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T3928871850"] = "The configured certificate bundle file does not exist."
|
||||
|
||||
-- The configured certificate bundle does not contain usable root CA certificates.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T599774443"] = "The configured certificate bundle does not contain usable root CA certificates."
|
||||
|
||||
-- policy files
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T632340680"] = "policy files"
|
||||
|
||||
-- AI Studio couldn't install Pandoc because the archive was not found.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::PANDOC::T1059477764"] = "AI Studio couldn't install Pandoc because the archive was not found."
|
||||
|
||||
@ -7650,6 +7908,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T2502277006"] = "Custom"
|
||||
-- Media
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T3507473059"] = "Media"
|
||||
|
||||
-- Certificate bundle
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T3543954504"] = "Certificate bundle"
|
||||
|
||||
-- Source like prefix
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T378481461"] = "Source like prefix"
|
||||
|
||||
@ -7665,6 +7926,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PANDOCAVAILABILITYSERVICE::T25964655
|
||||
-- Failed to store the secret data due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T1110203516"] = "Failed to store the secret data due to an API issue."
|
||||
|
||||
-- Failed to store the API key due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T1704298921"] = "Failed to store the API key due to an API issue."
|
||||
|
||||
-- Failed to delete the secret data due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T2303057928"] = "Failed to delete the secret data due to an API issue."
|
||||
|
||||
|
||||
@ -6,14 +6,14 @@ using AIStudio.Settings;
|
||||
|
||||
namespace AIStudio.Provider.AlibabaCloud;
|
||||
|
||||
public sealed class ProviderAlibabaCloud() : BaseProvider(LLMProviders.ALIBABA_CLOUD, "https://dashscope-intl.aliyuncs.com/compatible-mode/v1/", LOGGER)
|
||||
public sealed class ProviderAlibabaCloud() : BaseProvider(LLMProviders.ALIBABA_CLOUD, new Uri("https://dashscope-intl.aliyuncs.com/compatible-mode/v1/"), ExternalHttpTrustPolicy.SYSTEM_TRUST_ONLY, LOGGER)
|
||||
{
|
||||
private static readonly ILogger<ProviderAlibabaCloud> LOGGER = Program.LOGGER_FACTORY.CreateLogger<ProviderAlibabaCloud>();
|
||||
|
||||
#region Implementation of IProvider
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Id => LLMProviders.ALIBABA_CLOUD.ToName();
|
||||
public override string Id => LLMProviders.ALIBABA_CLOUD.ToSecretId();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string InstanceName { get; set; } = "AlibabaCloud";
|
||||
@ -68,7 +68,7 @@ public sealed class ProviderAlibabaCloud() : BaseProvider(LLMProviders.ALIBABA_C
|
||||
/// <inhertidoc />
|
||||
public override async Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
||||
{
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
return await this.PerformStandardTextEmbeddingRequest(requestedSecret, embeddingModel, token: token, texts: texts);
|
||||
}
|
||||
|
||||
|
||||
@ -8,14 +8,14 @@ using AIStudio.Settings;
|
||||
|
||||
namespace AIStudio.Provider.Anthropic;
|
||||
|
||||
public sealed class ProviderAnthropic() : BaseProvider(LLMProviders.ANTHROPIC, "https://api.anthropic.com/v1/", LOGGER)
|
||||
public sealed class ProviderAnthropic() : BaseProvider(LLMProviders.ANTHROPIC, new Uri("https://api.anthropic.com/v1/"), ExternalHttpTrustPolicy.SYSTEM_TRUST_ONLY, LOGGER)
|
||||
{
|
||||
private static readonly ILogger<ProviderAnthropic> LOGGER = Program.LOGGER_FACTORY.CreateLogger<ProviderAnthropic>();
|
||||
|
||||
#region Implementation of IProvider
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Id => LLMProviders.ANTHROPIC.ToName();
|
||||
public override string Id => LLMProviders.ANTHROPIC.ToSecretId();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string InstanceName { get; set; } = "Anthropic";
|
||||
@ -27,7 +27,7 @@ public sealed class ProviderAnthropic() : BaseProvider(LLMProviders.ANTHROPIC, "
|
||||
public override async IAsyncEnumerable<ContentStreamChunk> StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
|
||||
{
|
||||
// Get the API key:
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER);
|
||||
if(!requestedSecret.Success)
|
||||
yield break;
|
||||
|
||||
@ -93,7 +93,7 @@ public sealed class ProviderAnthropic() : BaseProvider(LLMProviders.ANTHROPIC, "
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, "messages");
|
||||
|
||||
// Set the authorization header:
|
||||
request.Headers.Add("x-api-key", await requestedSecret.Secret.Decrypt(ENCRYPTION));
|
||||
request.Headers.Add("x-api-key", await requestedSecret.Secret.Decrypt(Program.ENCRYPTION));
|
||||
|
||||
// Set the Anthropic version:
|
||||
request.Headers.Add("anthropic-version", "2023-06-01");
|
||||
|
||||
@ -13,7 +13,6 @@ using AIStudio.Settings;
|
||||
using AIStudio.Tools.MIME;
|
||||
using AIStudio.Tools.PluginSystem;
|
||||
using AIStudio.Tools.Rust;
|
||||
using AIStudio.Tools.Services;
|
||||
|
||||
using Host = AIStudio.Provider.SelfHosted.Host;
|
||||
|
||||
@ -29,23 +28,13 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
/// <summary>
|
||||
/// The HTTP client to use it for all requests.
|
||||
/// </summary>
|
||||
protected readonly HttpClient HttpClient = ExternalHttpClientTimeout.CreateHttpClient();
|
||||
protected readonly HttpClient HttpClient;
|
||||
|
||||
/// <summary>
|
||||
/// The logger to use.
|
||||
/// </summary>
|
||||
private readonly ILogger logger;
|
||||
|
||||
static BaseProvider()
|
||||
{
|
||||
RUST_SERVICE = Program.RUST_SERVICE;
|
||||
ENCRYPTION = Program.ENCRYPTION;
|
||||
}
|
||||
|
||||
protected static readonly RustService RUST_SERVICE;
|
||||
|
||||
protected static readonly Encryption ENCRYPTION;
|
||||
|
||||
protected static readonly JsonSerializerOptions JSON_SERIALIZER_OPTIONS = new()
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
||||
@ -65,24 +54,32 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
/// Constructor for the base provider.
|
||||
/// </summary>
|
||||
/// <param name="provider">The provider enum value.</param>
|
||||
/// <param name="url">The base URL for the provider.</param>
|
||||
/// <param name="baseUri">The base URI for the provider.</param>
|
||||
/// <param name="trustPolicy">The trust policy for external HTTPS requests to this provider.</param>
|
||||
/// <param name="logger">The logger to use.</param>
|
||||
protected BaseProvider(LLMProviders provider, string url, ILogger logger)
|
||||
protected BaseProvider(LLMProviders provider, Uri baseUri, ExternalHttpTrustPolicy trustPolicy, ILogger logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.Provider = provider;
|
||||
|
||||
// Set the base URL:
|
||||
this.HttpClient.BaseAddress = new(url);
|
||||
this.BaseUri = baseUri;
|
||||
this.HttpClient = ExternalHttpClientTimeout.CreateHttpClient(baseUri, trustPolicy);
|
||||
}
|
||||
|
||||
#region Handling of IProvider, which all providers must implement
|
||||
|
||||
/// <inheritdoc />
|
||||
public LLMProviders Provider { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The base URI for all relative provider requests.
|
||||
/// </summary>
|
||||
public Uri BaseUri { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract string Id { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ConfiguredProviderId { get; init; } = string.Empty;
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract string InstanceName { get; set; }
|
||||
@ -156,9 +153,9 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
protected async Task<string?> GetModelLoadingSecretKey(SecretStoreType storeType, string? apiKeyProvisional = null, bool isTryingSecret = false) => apiKeyProvisional switch
|
||||
{
|
||||
not null => apiKeyProvisional,
|
||||
_ => await RUST_SERVICE.GetAPIKey(this, storeType, isTrying: isTryingSecret) switch
|
||||
_ => await Program.RUST_SERVICE.GetAPIKey(this, storeType, isTrying: isTryingSecret) switch
|
||||
{
|
||||
{ Success: true } result => await result.Secret.Decrypt(ENCRYPTION),
|
||||
{ Success: true } result => await result.Secret.Decrypt(Program.ENCRYPTION),
|
||||
_ => null,
|
||||
}
|
||||
};
|
||||
@ -976,7 +973,7 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
where TAnnotation : IAnnotationStreamLine
|
||||
{
|
||||
// Get the API key:
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, storeType, isTrying: isTryingSecret);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, storeType, isTrying: isTryingSecret);
|
||||
if(!requestedSecret.Success && !isTryingSecret)
|
||||
yield break;
|
||||
|
||||
@ -1000,7 +997,7 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
|
||||
// Set the authorization header:
|
||||
if (requestedSecret.Success)
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(ENCRYPTION));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(Program.ENCRYPTION));
|
||||
|
||||
// Set provider-specific headers:
|
||||
headersAction?.Invoke(request.Headers);
|
||||
@ -1048,7 +1045,7 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
{
|
||||
case LLMProviders.SELF_HOSTED:
|
||||
if(requestedSecret.Success)
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(ENCRYPTION));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(Program.ENCRYPTION));
|
||||
|
||||
break;
|
||||
|
||||
@ -1059,7 +1056,7 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
return TranscriptionResult.Failure();
|
||||
}
|
||||
|
||||
request.Headers.Add("Authorization", await requestedSecret.Secret.Decrypt(ENCRYPTION));
|
||||
request.Headers.Add("Authorization", await requestedSecret.Secret.Decrypt(Program.ENCRYPTION));
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1069,7 +1066,7 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
return TranscriptionResult.Failure();
|
||||
}
|
||||
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(ENCRYPTION));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(Program.ENCRYPTION));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1130,7 +1127,7 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
{
|
||||
case LLMProviders.SELF_HOSTED:
|
||||
if(requestedSecret.Success)
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(ENCRYPTION));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(Program.ENCRYPTION));
|
||||
|
||||
break;
|
||||
|
||||
@ -1141,7 +1138,7 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
return [];
|
||||
}
|
||||
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(ENCRYPTION));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(Program.ENCRYPTION));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -6,14 +6,14 @@ using AIStudio.Settings;
|
||||
|
||||
namespace AIStudio.Provider.DeepSeek;
|
||||
|
||||
public sealed class ProviderDeepSeek() : BaseProvider(LLMProviders.DEEP_SEEK, "https://api.deepseek.com/", LOGGER)
|
||||
public sealed class ProviderDeepSeek() : BaseProvider(LLMProviders.DEEP_SEEK, new Uri("https://api.deepseek.com/"), ExternalHttpTrustPolicy.SYSTEM_TRUST_ONLY, LOGGER)
|
||||
{
|
||||
private static readonly ILogger<ProviderDeepSeek> LOGGER = Program.LOGGER_FACTORY.CreateLogger<ProviderDeepSeek>();
|
||||
|
||||
#region Implementation of IProvider
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Id => LLMProviders.DEEP_SEEK.ToName();
|
||||
public override string Id => LLMProviders.DEEP_SEEK.ToSecretId();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string InstanceName { get; set; } = "DeepSeek";
|
||||
|
||||
@ -6,14 +6,14 @@ using AIStudio.Settings;
|
||||
|
||||
namespace AIStudio.Provider.Fireworks;
|
||||
|
||||
public class ProviderFireworks() : BaseProvider(LLMProviders.FIREWORKS, "https://api.fireworks.ai/inference/v1/", LOGGER)
|
||||
public class ProviderFireworks() : BaseProvider(LLMProviders.FIREWORKS, new Uri("https://api.fireworks.ai/inference/v1/"), ExternalHttpTrustPolicy.SYSTEM_TRUST_ONLY, LOGGER)
|
||||
{
|
||||
private static readonly ILogger<ProviderFireworks> LOGGER = Program.LOGGER_FACTORY.CreateLogger<ProviderFireworks>();
|
||||
|
||||
#region Implementation of IProvider
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Id => LLMProviders.FIREWORKS.ToName();
|
||||
public override string Id => LLMProviders.FIREWORKS.ToSecretId();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string InstanceName { get; set; } = "Fireworks.ai";
|
||||
@ -63,7 +63,7 @@ public class ProviderFireworks() : BaseProvider(LLMProviders.FIREWORKS, "https:/
|
||||
/// <inheritdoc />
|
||||
public override async Task<TranscriptionResult> TranscribeAudioAsync(Model transcriptionModel, string audioFilePath, SettingsManager settingsManager, CancellationToken token = default)
|
||||
{
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER);
|
||||
return await this.PerformStandardTranscriptionRequest(requestedSecret, transcriptionModel, audioFilePath, token: token);
|
||||
}
|
||||
|
||||
|
||||
@ -6,14 +6,14 @@ using AIStudio.Settings;
|
||||
|
||||
namespace AIStudio.Provider.GWDG;
|
||||
|
||||
public sealed class ProviderGWDG() : BaseProvider(LLMProviders.GWDG, "https://chat-ai.academiccloud.de/v1/", LOGGER)
|
||||
public sealed class ProviderGWDG() : BaseProvider(LLMProviders.GWDG, new Uri("https://chat-ai.academiccloud.de/v1/"), ExternalHttpTrustPolicy.SYSTEM_TRUST_ONLY, LOGGER)
|
||||
{
|
||||
private static readonly ILogger<ProviderGWDG> LOGGER = Program.LOGGER_FACTORY.CreateLogger<ProviderGWDG>();
|
||||
|
||||
#region Implementation of IProvider
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Id => LLMProviders.GWDG.ToName();
|
||||
public override string Id => LLMProviders.GWDG.ToSecretId();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string InstanceName { get; set; } = "GWDG SAIA";
|
||||
@ -62,7 +62,7 @@ public sealed class ProviderGWDG() : BaseProvider(LLMProviders.GWDG, "https://ch
|
||||
/// <inheritdoc />
|
||||
public override async Task<TranscriptionResult> TranscribeAudioAsync(Model transcriptionModel, string audioFilePath, SettingsManager settingsManager, CancellationToken token = default)
|
||||
{
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER);
|
||||
return await this.PerformStandardTranscriptionRequest(requestedSecret, transcriptionModel, audioFilePath, token: token);
|
||||
}
|
||||
|
||||
|
||||
@ -8,14 +8,14 @@ using AIStudio.Settings;
|
||||
|
||||
namespace AIStudio.Provider.Google;
|
||||
|
||||
public class ProviderGoogle() : BaseProvider(LLMProviders.GOOGLE, "https://generativelanguage.googleapis.com/v1beta/openai/", LOGGER)
|
||||
public class ProviderGoogle() : BaseProvider(LLMProviders.GOOGLE, new Uri("https://generativelanguage.googleapis.com/v1beta/openai/"), ExternalHttpTrustPolicy.SYSTEM_TRUST_ONLY, LOGGER)
|
||||
{
|
||||
private static readonly ILogger<ProviderGoogle> LOGGER = Program.LOGGER_FACTORY.CreateLogger<ProviderGoogle>();
|
||||
|
||||
#region Implementation of IProvider
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Id => LLMProviders.GOOGLE.ToName();
|
||||
public override string Id => LLMProviders.GOOGLE.ToSecretId();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string InstanceName { get; set; } = "Google Gemini";
|
||||
@ -71,7 +71,7 @@ public class ProviderGoogle() : BaseProvider(LLMProviders.GOOGLE, "https://gener
|
||||
/// <inhertidoc />
|
||||
public override async Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
||||
{
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
try
|
||||
{
|
||||
var modelName = embeddingModel.Id;
|
||||
@ -104,7 +104,7 @@ public class ProviderGoogle() : BaseProvider(LLMProviders.GOOGLE, "https://gener
|
||||
var embeddingRequest = JsonSerializer.Serialize(payload, JSON_SERIALIZER_OPTIONS);
|
||||
var embedUrl = $"https://generativelanguage.googleapis.com/v1beta/models/{modelName}:embedContent";
|
||||
using var request = new HttpRequestMessage(HttpMethod.Post, embedUrl);
|
||||
request.Headers.Add("x-goog-api-key", await requestedSecret.Secret.Decrypt(ENCRYPTION));
|
||||
request.Headers.Add("x-goog-api-key", await requestedSecret.Secret.Decrypt(Program.ENCRYPTION));
|
||||
|
||||
// Set the content:
|
||||
request.Content = new StringContent(embeddingRequest, Encoding.UTF8, "application/json");
|
||||
|
||||
@ -6,14 +6,14 @@ using AIStudio.Settings;
|
||||
|
||||
namespace AIStudio.Provider.Groq;
|
||||
|
||||
public class ProviderGroq() : BaseProvider(LLMProviders.GROQ, "https://api.groq.com/openai/v1/", LOGGER)
|
||||
public class ProviderGroq() : BaseProvider(LLMProviders.GROQ, new Uri("https://api.groq.com/openai/v1/"), ExternalHttpTrustPolicy.SYSTEM_TRUST_ONLY, LOGGER)
|
||||
{
|
||||
private static readonly ILogger<ProviderGroq> LOGGER = Program.LOGGER_FACTORY.CreateLogger<ProviderGroq>();
|
||||
|
||||
#region Implementation of IProvider
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Id => LLMProviders.GROQ.ToName();
|
||||
public override string Id => LLMProviders.GROQ.ToSecretId();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string InstanceName { get; set; } = "Groq";
|
||||
|
||||
@ -8,14 +8,14 @@ using AIStudio.Settings;
|
||||
|
||||
namespace AIStudio.Provider.Helmholtz;
|
||||
|
||||
public sealed class ProviderHelmholtz() : BaseProvider(LLMProviders.HELMHOLTZ, "https://api.helmholtz-blablador.fz-juelich.de/v1/", LOGGER)
|
||||
public sealed class ProviderHelmholtz() : BaseProvider(LLMProviders.HELMHOLTZ, new Uri("https://api.helmholtz-blablador.fz-juelich.de/v1/"), ExternalHttpTrustPolicy.SYSTEM_TRUST_ONLY, LOGGER)
|
||||
{
|
||||
private static readonly ILogger<ProviderHelmholtz> LOGGER = Program.LOGGER_FACTORY.CreateLogger<ProviderHelmholtz>();
|
||||
|
||||
#region Implementation of IProvider
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Id => LLMProviders.HELMHOLTZ.ToName();
|
||||
public override string Id => LLMProviders.HELMHOLTZ.ToSecretId();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string InstanceName { get; set; } = "Helmholtz Blablador";
|
||||
@ -70,7 +70,7 @@ public sealed class ProviderHelmholtz() : BaseProvider(LLMProviders.HELMHOLTZ, "
|
||||
/// <inhertidoc />
|
||||
public override async Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
||||
{
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
return await this.PerformStandardTextEmbeddingRequest(requestedSecret, embeddingModel, token: token, texts: texts);
|
||||
}
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ public sealed class ProviderHuggingFace : BaseProvider
|
||||
{
|
||||
private static readonly ILogger<ProviderHuggingFace> LOGGER = Program.LOGGER_FACTORY.CreateLogger<ProviderHuggingFace>();
|
||||
|
||||
public ProviderHuggingFace(HFInferenceProvider hfProvider, Model model) : base(LLMProviders.HUGGINGFACE, $"https://router.huggingface.co/{hfProvider.Endpoints(model)}", LOGGER)
|
||||
public ProviderHuggingFace(HFInferenceProvider hfProvider, Model model) : base(LLMProviders.HUGGINGFACE, new Uri($"https://router.huggingface.co/{hfProvider.Endpoints(model)}"), ExternalHttpTrustPolicy.SYSTEM_TRUST_ONLY, LOGGER)
|
||||
{
|
||||
LOGGER.LogInformation($"We use the inference provider '{hfProvider}'. Thus we use the base URL 'https://router.huggingface.co/{hfProvider.Endpoints(model)}'.");
|
||||
}
|
||||
@ -18,7 +18,7 @@ public sealed class ProviderHuggingFace : BaseProvider
|
||||
#region Implementation of IProvider
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Id => LLMProviders.HUGGINGFACE.ToName();
|
||||
public override string Id => LLMProviders.HUGGINGFACE.ToSecretId();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string InstanceName { get; set; } = "HuggingFace";
|
||||
|
||||
@ -18,6 +18,11 @@ public interface IProvider
|
||||
/// </summary>
|
||||
public string Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the configured provider instance.
|
||||
/// </summary>
|
||||
public string ConfiguredProviderId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The provider's instance name. Useful for multiple instances of the same provider,
|
||||
/// e.g., to distinguish between different OpenAI API keys.
|
||||
|
||||
@ -29,6 +29,10 @@ public static class LLMProvidersExtensions
|
||||
/// <summary>
|
||||
/// Returns the human-readable name of the provider.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is UI text and may be localized. Do not use it for persisted IDs, secret namespaces,
|
||||
/// or other stable identifiers.
|
||||
/// </remarks>
|
||||
/// <param name="llmProvider">The provider.</param>
|
||||
/// <returns>The human-readable name of the provider.</returns>
|
||||
public static string ToName(this LLMProviders llmProvider) => llmProvider switch
|
||||
@ -56,6 +60,41 @@ public static class LLMProvidersExtensions
|
||||
|
||||
_ => TB("Unknown"),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Returns the stable secret namespace for the provider.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// These values are used for OS keyring namespaces. They must never be localized or changed without
|
||||
/// an explicit migration for existing API keys.
|
||||
/// </remarks>
|
||||
/// <param name="llmProvider">The provider.</param>
|
||||
/// <returns>The stable secret namespace for the provider.</returns>
|
||||
public static string ToSecretId(this LLMProviders llmProvider) => llmProvider switch
|
||||
{
|
||||
LLMProviders.NONE => "No provider selected",
|
||||
|
||||
LLMProviders.OPEN_AI => "OpenAI",
|
||||
LLMProviders.ANTHROPIC => "Anthropic",
|
||||
LLMProviders.MISTRAL => "Mistral",
|
||||
LLMProviders.GOOGLE => "Google",
|
||||
LLMProviders.X => "xAI",
|
||||
LLMProviders.DEEP_SEEK => "DeepSeek",
|
||||
LLMProviders.ALIBABA_CLOUD => "Alibaba Cloud",
|
||||
LLMProviders.PERPLEXITY => "Perplexity",
|
||||
LLMProviders.OPEN_ROUTER => "OpenRouter",
|
||||
|
||||
LLMProviders.GROQ => "Groq",
|
||||
LLMProviders.FIREWORKS => "Fireworks.ai",
|
||||
LLMProviders.HUGGINGFACE => "Hugging Face",
|
||||
|
||||
LLMProviders.SELF_HOSTED => "Self-hosted",
|
||||
|
||||
LLMProviders.HELMHOLTZ => "Helmholtz Blablador",
|
||||
LLMProviders.GWDG => "GWDG SAIA",
|
||||
|
||||
_ => "Unknown",
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Get a provider's confidence.
|
||||
@ -186,7 +225,7 @@ public static class LLMProvidersExtensions
|
||||
/// <returns>The provider instance.</returns>
|
||||
public static IProvider CreateProvider(this AIStudio.Settings.Provider providerSettings)
|
||||
{
|
||||
return providerSettings.UsedLLMProvider.CreateProvider(providerSettings.InstanceName, providerSettings.Host, providerSettings.Hostname, providerSettings.Model, providerSettings.HFInferenceProvider, providerSettings.AdditionalJsonApiParameters, providerSettings.IsEnterpriseConfiguration);
|
||||
return providerSettings.UsedLLMProvider.CreateProvider(providerSettings.InstanceName, providerSettings.Host, providerSettings.Hostname, providerSettings.Model, providerSettings.HFInferenceProvider, providerSettings.Id, providerSettings.AdditionalJsonApiParameters, providerSettings.IsEnterpriseConfiguration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -196,7 +235,7 @@ public static class LLMProvidersExtensions
|
||||
/// <returns>The provider instance.</returns>
|
||||
public static IProvider CreateProvider(this EmbeddingProvider embeddingProviderSettings)
|
||||
{
|
||||
return embeddingProviderSettings.UsedLLMProvider.CreateProvider(embeddingProviderSettings.Name, embeddingProviderSettings.Host, embeddingProviderSettings.Hostname, embeddingProviderSettings.Model, HFInferenceProvider.NONE, isEnterpriseConfiguration: embeddingProviderSettings.IsEnterpriseConfiguration);
|
||||
return embeddingProviderSettings.UsedLLMProvider.CreateProvider(embeddingProviderSettings.Name, embeddingProviderSettings.Host, embeddingProviderSettings.Hostname, embeddingProviderSettings.Model, HFInferenceProvider.NONE, configuredProviderId: embeddingProviderSettings.Id, isEnterpriseConfiguration: embeddingProviderSettings.IsEnterpriseConfiguration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -206,33 +245,33 @@ public static class LLMProvidersExtensions
|
||||
/// <returns>The provider instance.</returns>
|
||||
public static IProvider CreateProvider(this TranscriptionProvider transcriptionProviderSettings)
|
||||
{
|
||||
return transcriptionProviderSettings.UsedLLMProvider.CreateProvider(transcriptionProviderSettings.Name, transcriptionProviderSettings.Host, transcriptionProviderSettings.Hostname, transcriptionProviderSettings.Model, HFInferenceProvider.NONE, isEnterpriseConfiguration: transcriptionProviderSettings.IsEnterpriseConfiguration);
|
||||
return transcriptionProviderSettings.UsedLLMProvider.CreateProvider(transcriptionProviderSettings.Name, transcriptionProviderSettings.Host, transcriptionProviderSettings.Hostname, transcriptionProviderSettings.Model, HFInferenceProvider.NONE, configuredProviderId: transcriptionProviderSettings.Id, isEnterpriseConfiguration: transcriptionProviderSettings.IsEnterpriseConfiguration);
|
||||
}
|
||||
|
||||
private static IProvider CreateProvider(this LLMProviders provider, string instanceName, Host host, string hostname, Model model, HFInferenceProvider inferenceProvider, string expertProviderApiParameter = "", bool isEnterpriseConfiguration = false)
|
||||
private static IProvider CreateProvider(this LLMProviders provider, string instanceName, Host host, string hostname, Model model, HFInferenceProvider inferenceProvider, string configuredProviderId = "", string expertProviderApiParameter = "", bool isEnterpriseConfiguration = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
return provider switch
|
||||
{
|
||||
LLMProviders.OPEN_AI => new ProviderOpenAI { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.ANTHROPIC => new ProviderAnthropic { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.MISTRAL => new ProviderMistral { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.GOOGLE => new ProviderGoogle { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.X => new ProviderX { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.DEEP_SEEK => new ProviderDeepSeek { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.ALIBABA_CLOUD => new ProviderAlibabaCloud { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.PERPLEXITY => new ProviderPerplexity { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.OPEN_ROUTER => new ProviderOpenRouter { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.OPEN_AI => new ProviderOpenAI { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.ANTHROPIC => new ProviderAnthropic { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.MISTRAL => new ProviderMistral { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.GOOGLE => new ProviderGoogle { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.X => new ProviderX { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.DEEP_SEEK => new ProviderDeepSeek { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.ALIBABA_CLOUD => new ProviderAlibabaCloud { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.PERPLEXITY => new ProviderPerplexity { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.OPEN_ROUTER => new ProviderOpenRouter { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
|
||||
LLMProviders.GROQ => new ProviderGroq { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.FIREWORKS => new ProviderFireworks { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.HUGGINGFACE => new ProviderHuggingFace(inferenceProvider, model) { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.GROQ => new ProviderGroq { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.FIREWORKS => new ProviderFireworks { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.HUGGINGFACE => new ProviderHuggingFace(inferenceProvider, model) { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
|
||||
LLMProviders.SELF_HOSTED => new ProviderSelfHosted(host, hostname) { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.SELF_HOSTED => new ProviderSelfHosted(host, hostname) { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
|
||||
LLMProviders.HELMHOLTZ => new ProviderHelmholtz { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.GWDG => new ProviderGWDG { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.HELMHOLTZ => new ProviderHelmholtz { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.GWDG => new ProviderGWDG { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
|
||||
_ => new NoProvider(),
|
||||
};
|
||||
@ -329,14 +368,13 @@ public static class LLMProvidersExtensions
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the model selection should be completely hidden for LLM providers.
|
||||
/// This is the case when the host does not support model selection (e.g., llama.cpp).
|
||||
/// This is the case when the host does not support model selection.
|
||||
/// </summary>
|
||||
/// <param name="provider">The provider.</param>
|
||||
/// <param name="host">The host for self-hosted providers.</param>
|
||||
/// <returns>True if model selection should be hidden; otherwise, false.</returns>
|
||||
public static bool IsLLMModelSelectionHidden(this LLMProviders provider, Host host) => provider switch
|
||||
{
|
||||
LLMProviders.SELF_HOSTED => host is Host.LLAMA_CPP,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
@ -416,11 +454,11 @@ public static class LLMProvidersExtensions
|
||||
switch (host)
|
||||
{
|
||||
case Host.NONE:
|
||||
case Host.LLAMA_CPP:
|
||||
case Host.WHISPER_CPP:
|
||||
default:
|
||||
return false;
|
||||
|
||||
case Host.LLAMA_CPP:
|
||||
case Host.OLLAMA:
|
||||
case Host.LM_STUDIO:
|
||||
case Host.VLLM:
|
||||
|
||||
@ -6,14 +6,14 @@ using AIStudio.Settings;
|
||||
|
||||
namespace AIStudio.Provider.Mistral;
|
||||
|
||||
public sealed class ProviderMistral() : BaseProvider(LLMProviders.MISTRAL, "https://api.mistral.ai/v1/", LOGGER)
|
||||
public sealed class ProviderMistral() : BaseProvider(LLMProviders.MISTRAL, new Uri("https://api.mistral.ai/v1/"), ExternalHttpTrustPolicy.SYSTEM_TRUST_ONLY, LOGGER)
|
||||
{
|
||||
private static readonly ILogger<ProviderMistral> LOGGER = Program.LOGGER_FACTORY.CreateLogger<ProviderMistral>();
|
||||
|
||||
#region Implementation of IProvider
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Id => LLMProviders.MISTRAL.ToName();
|
||||
public override string Id => LLMProviders.MISTRAL.ToSecretId();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string InstanceName { get; set; } = "Mistral";
|
||||
@ -69,14 +69,14 @@ public sealed class ProviderMistral() : BaseProvider(LLMProviders.MISTRAL, "http
|
||||
/// <inheritdoc />
|
||||
public override async Task<TranscriptionResult> TranscribeAudioAsync(Provider.Model transcriptionModel, string audioFilePath, SettingsManager settingsManager, CancellationToken token = default)
|
||||
{
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER);
|
||||
return await this.PerformStandardTranscriptionRequest(requestedSecret, transcriptionModel, audioFilePath, token: token);
|
||||
}
|
||||
|
||||
/// <inhertidoc />
|
||||
public override async Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Provider.Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
||||
{
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
return await this.PerformStandardTextEmbeddingRequest(requestedSecret, embeddingModel, token: token, texts: texts);
|
||||
}
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@ public readonly record struct Model(string Id, string? DisplayName)
|
||||
/// <summary>
|
||||
/// Checks if this model is the system-configured placeholder.
|
||||
/// </summary>
|
||||
public bool IsSystemModel => this == SYSTEM_MODEL;
|
||||
public bool IsSystemModel => string.Equals(this.Id, SYSTEM_MODEL_ID, StringComparison.Ordinal);
|
||||
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(Model).Namespace, nameof(Model));
|
||||
|
||||
|
||||
@ -13,6 +13,8 @@ public class NoProvider : IProvider
|
||||
|
||||
public string Id => "none";
|
||||
|
||||
public string ConfiguredProviderId => string.Empty;
|
||||
|
||||
public string InstanceName { get; set; } = "None";
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@ -13,7 +13,7 @@ namespace AIStudio.Provider.OpenAI;
|
||||
/// <summary>
|
||||
/// The OpenAI provider.
|
||||
/// </summary>
|
||||
public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, "https://api.openai.com/v1/", LOGGER)
|
||||
public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, new Uri("https://api.openai.com/v1/"), ExternalHttpTrustPolicy.SYSTEM_TRUST_ONLY, LOGGER)
|
||||
{
|
||||
private static readonly ILogger<ProviderOpenAI> LOGGER = Program.LOGGER_FACTORY.CreateLogger<ProviderOpenAI>();
|
||||
|
||||
@ -22,7 +22,7 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, "https
|
||||
#region Implementation of IProvider
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Id => LLMProviders.OPEN_AI.ToName();
|
||||
public override string Id => LLMProviders.OPEN_AI.ToSecretId();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string InstanceName { get; set; } = "OpenAI";
|
||||
@ -56,7 +56,7 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, "https
|
||||
public override async IAsyncEnumerable<ContentStreamChunk> StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
|
||||
{
|
||||
// Get the API key:
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER);
|
||||
if(!requestedSecret.Success)
|
||||
yield break;
|
||||
|
||||
@ -221,7 +221,7 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, "https
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, requestPath);
|
||||
|
||||
// Set the authorization header:
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(ENCRYPTION));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(Program.ENCRYPTION));
|
||||
|
||||
// Set the content:
|
||||
request.Content = new StringContent(openAIChatRequest, Encoding.UTF8, "application/json");
|
||||
@ -250,14 +250,14 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, "https
|
||||
/// <inheritdoc />
|
||||
public override async Task<TranscriptionResult> TranscribeAudioAsync(Model transcriptionModel, string audioFilePath, SettingsManager settingsManager, CancellationToken token = default)
|
||||
{
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER);
|
||||
return await this.PerformStandardTranscriptionRequest(requestedSecret, transcriptionModel, audioFilePath, token: token);
|
||||
}
|
||||
|
||||
/// <inhertidoc />
|
||||
public override async Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
||||
{
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
return await this.PerformStandardTextEmbeddingRequest(requestedSecret, embeddingModel, token: token, texts: texts);
|
||||
}
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ using AIStudio.Settings;
|
||||
|
||||
namespace AIStudio.Provider.OpenRouter;
|
||||
|
||||
public sealed class ProviderOpenRouter() : BaseProvider(LLMProviders.OPEN_ROUTER, "https://openrouter.ai/api/v1/", LOGGER)
|
||||
public sealed class ProviderOpenRouter() : BaseProvider(LLMProviders.OPEN_ROUTER, new Uri("https://openrouter.ai/api/v1/"), ExternalHttpTrustPolicy.SYSTEM_TRUST_ONLY, LOGGER)
|
||||
{
|
||||
private const string PROJECT_WEBSITE = "https://github.com/MindWorkAI/AI-Studio";
|
||||
private const string PROJECT_NAME = "MindWork AI Studio";
|
||||
@ -17,7 +17,7 @@ public sealed class ProviderOpenRouter() : BaseProvider(LLMProviders.OPEN_ROUTER
|
||||
#region Implementation of IProvider
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Id => LLMProviders.OPEN_ROUTER.ToName();
|
||||
public override string Id => LLMProviders.OPEN_ROUTER.ToSecretId();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string InstanceName { get; set; } = "OpenRouter";
|
||||
@ -79,7 +79,7 @@ public sealed class ProviderOpenRouter() : BaseProvider(LLMProviders.OPEN_ROUTER
|
||||
/// <inhertidoc />
|
||||
public override async Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
||||
{
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
return await this.PerformStandardTextEmbeddingRequest(requestedSecret, embeddingModel, token: token, texts: texts);
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ using AIStudio.Settings;
|
||||
|
||||
namespace AIStudio.Provider.Perplexity;
|
||||
|
||||
public sealed class ProviderPerplexity() : BaseProvider(LLMProviders.PERPLEXITY, "https://api.perplexity.ai/", LOGGER)
|
||||
public sealed class ProviderPerplexity() : BaseProvider(LLMProviders.PERPLEXITY, new Uri("https://api.perplexity.ai/"), ExternalHttpTrustPolicy.SYSTEM_TRUST_ONLY, LOGGER)
|
||||
{
|
||||
private static readonly ILogger<ProviderPerplexity> LOGGER = Program.LOGGER_FACTORY.CreateLogger<ProviderPerplexity>();
|
||||
|
||||
@ -22,7 +22,7 @@ public sealed class ProviderPerplexity() : BaseProvider(LLMProviders.PERPLEXITY,
|
||||
#region Implementation of IProvider
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Id => LLMProviders.PERPLEXITY.ToName();
|
||||
public override string Id => LLMProviders.PERPLEXITY.ToSecretId();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string InstanceName { get; set; } = "Perplexity";
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
namespace AIStudio.Provider.SelfHosted;
|
||||
|
||||
public readonly record struct ModelsResponse(string Object, Model[] Data);
|
||||
public readonly record struct ModelsResponse(string? Object, Model[]? Data);
|
||||
|
||||
public readonly record struct Model(string Id, string Object, string OwnedBy);
|
||||
public readonly record struct Model(string Id, string? Object, string? OwnedBy, ModelArchitecture? Architecture);
|
||||
|
||||
public readonly record struct ModelArchitecture(string[]? InputModalities, string[]? OutputModalities);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user