mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-18 14:58:00 +00:00
Added file patterns and exclusions to folder data sources (#1057)
Co-authored-by: Thorsten Sommer <SommerEngineering@users.noreply.github.com>
This commit is contained in:
1 parent
249fc778a2
commit
031874cebf
75 files changed
+4808
-589
No files matched your search
@@ -9,17 +9,6 @@
|
||||
|
||||
<SelectDirectory Label="@T("Folder containing your documents")" DirectoryDialogTitle="@T("Select the folder containing your documents")" @bind-Directory="@this.inputDirectory" Validation="@this.ValidateInputDirectory" EnableDragDrop="true" Disabled="@this.isProcessingBatch"/>
|
||||
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2" Class="mb-1">
|
||||
<MudTextField T="string" @bind-Text="@this.filePatterns" Validation="@this.ValidateFilePatterns" Immediate="@true" Disabled="@this.isProcessingBatch" Label="@T("File patterns")" HelperText="@T("Which files should be processed? Separate multiple patterns with a semicolon, e.g., *.pdf;*.docx")" AdornmentIcon="@Icons.Material.Filled.FilterAlt" Adornment="Adornment.Start" Variant="Variant.Outlined" Margin="Margin.Normal" Class="flex-grow-1" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
|
||||
<MudButton Variant="Variant.Outlined" StartIcon="@Icons.Material.Filled.Restore" Disabled="@this.isProcessingBatch" OnClick="@this.RestoreDefaultFilePatterns">
|
||||
@T("Restore default patterns")
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
|
||||
<MudJustifiedText Typo="Typo.body2" Class="mb-3">
|
||||
@T("Supported audio and video files are transcribed automatically without an additional dialog. Each transcript is stored next to its media file as '<media-file>.transcript.md' and reused when an interrupted run is continued.")
|
||||
</MudJustifiedText>
|
||||
|
||||
<MudTextSwitch Label="@T("Include subfolders?")" Disabled="@this.isProcessingBatch" Value="@this.includeSubdirectories" ValueChanged="@(v => this.includeSubdirectories = v)" LabelOn="@T("Yes, process files in subfolders as well")" LabelOff="@T("No, only process files in the selected folder")"/>
|
||||
|
||||
@if (this.includeSubdirectories)
|
||||
@@ -29,6 +18,32 @@
|
||||
</MudJustifiedText>
|
||||
}
|
||||
|
||||
<MudTextField T="string" @bind-Text="@this.filePatterns" Validation="@this.ValidateFilePatterns" Immediate="@true" Disabled="@this.isProcessingBatch" Label="@T("File patterns")" HelperText="@T("Which files should be processed? Separate multiple patterns with a semicolon, e.g., *.pdf;*.docx. Use :documents: for every document and readable text file, :text: for readable text files only, or * for every file.")" AdornmentIcon="@Icons.Material.Filled.FilterAlt" Adornment="Adornment.Start" Variant="Variant.Outlined" Margin="Margin.Normal" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
|
||||
<RestoreDefaultButton Text="@T("Restore default patterns")" Disabled="@this.isProcessingBatch" OnClick="@this.RestoreDefaultFilePatterns" Class="mb-1"/>
|
||||
|
||||
<MudJustifiedText Typo="Typo.body2" Class="mb-3">
|
||||
@T("Supported audio and video files are transcribed automatically without an additional dialog. Each transcript is stored next to its media file as '<media-file>.transcript.md' and reused when an interrupted run is continued.")
|
||||
</MudJustifiedText>
|
||||
|
||||
<MudStack Class="mb-3">
|
||||
<MudButton OnClick="@this.ToggleExpertSettings" Variant="Variant.Text" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Tune">
|
||||
@(this.showExpertSettings ? T("Hide Expert Settings") : T("Show Expert Settings"))
|
||||
</MudButton>
|
||||
<MudDivider/>
|
||||
<MudCollapse Expanded="@this.showExpertSettings" Class="@this.GetExpertStyles">
|
||||
<MudTextSwitch Label="@T("Include hidden files and folders?")" Disabled="@this.isProcessingBatch" Value="@this.includeHiddenFilesAndFolders" ValueChanged="@(v => this.includeHiddenFilesAndFolders = v)" LabelOn="@T("Yes, process hidden files and folders as well")" LabelOff="@T("No, ignore hidden files and folders")"/>
|
||||
<MudJustifiedText Typo="Typo.body2" Class="mb-3">
|
||||
@T("Hidden are files and folders whose names start with a dot, such as .git or .env, and those hidden by the operating system. A file pattern which starts with a dot, such as .gitignore, selects such files anyway.")
|
||||
</MudJustifiedText>
|
||||
|
||||
@* Without an icon: in a field of several lines, it floats in the middle of the text. *@
|
||||
<MudTextField T="string" @bind-Text="@this.excludePatterns" Validation="@this.ValidateExcludePatterns" Immediate="@true" Disabled="@this.isProcessingBatch" Label="@T("Excluded files and folders")" Lines="@FileExclusions.DEFAULT_LINE_COUNT" AutoGrow="@true" MaxLines="@FileExclusions.MAX_LINE_COUNT" HelperText="@T("These files and folders are left out, even when a file pattern selects them. Separate entries with a semicolon or a line break. End an entry with a slash to exclude every folder of that name, e.g., node_modules/. Other entries name files, e.g., *.min.js.")" Variant="Variant.Outlined" Margin="Margin.Normal" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
|
||||
<RestoreDefaultButton Text="@T("Restore default")" Disabled="@this.isProcessingBatch" OnClick="@this.RestoreDefaultExcludePatterns" Class="mb-1"/>
|
||||
|
||||
<MudNumericField T="int" @bind-Value="@this.maxFileSizeMegabytes" Min="@FolderFileSelection.SMALLEST_MAX_FILE_SIZE_MEGABYTES" Immediate="@true" Disabled="@this.isProcessingBatch" Label="@T("Ignore files larger than")" HelperText="@T("Matching files above this size are left out, e.g., images of virtual machines.")" Adornment="Adornment.End" AdornmentText="MB" Variant="Variant.Outlined" Margin="Margin.Normal"/>
|
||||
</MudCollapse>
|
||||
</MudStack>
|
||||
|
||||
<MudText Typo="Typo.h5" Class="mb-3 mt-6">
|
||||
@T("Instructions")
|
||||
</MudText>
|
||||
@@ -269,4 +284,11 @@ else
|
||||
}
|
||||
</tbody>
|
||||
</MudSimpleTable>
|
||||
|
||||
@if (this.numTooLargeFiles > 0)
|
||||
{
|
||||
<MudJustifiedText Typo="Typo.body2" Class="mb-3">
|
||||
@string.Format(T("{0} matching files were left out because they are larger than {1}."), this.numTooLargeFiles, FolderFileSelection.MegabytesToBytes(this.maxFileSizeMegabytes).FileSize())
|
||||
</MudJustifiedText>
|
||||
}
|
||||
}
|
||||
+12
@@ -8,7 +8,10 @@ public partial class AssistantBatchProcessing
|
||||
private static readonly AssistantSessionStateKey<string> INPUT_DIRECTORY_STATE_KEY = new(nameof(inputDirectory));
|
||||
private static readonly AssistantSessionStateKey<string> OUTPUT_DIRECTORY_STATE_KEY = new(nameof(outputDirectory));
|
||||
private static readonly AssistantSessionStateKey<string> FILE_PATTERNS_STATE_KEY = new(nameof(filePatterns));
|
||||
private static readonly AssistantSessionStateKey<string> EXCLUDE_PATTERNS_STATE_KEY = new(nameof(excludePatterns));
|
||||
private static readonly AssistantSessionStateKey<int> MAX_FILE_SIZE_MEGABYTES_STATE_KEY = new(nameof(maxFileSizeMegabytes));
|
||||
private static readonly AssistantSessionStateKey<bool> INCLUDE_SUBDIRECTORIES_STATE_KEY = new(nameof(includeSubdirectories));
|
||||
private static readonly AssistantSessionStateKey<bool> INCLUDE_HIDDEN_FILES_AND_FOLDERS_STATE_KEY = new(nameof(includeHiddenFilesAndFolders));
|
||||
private static readonly AssistantSessionStateKey<BatchProcessingPromptSource> PROMPT_SOURCE_STATE_KEY = new(nameof(promptSource));
|
||||
private static readonly AssistantSessionStateKey<string> FREE_PROMPT_STATE_KEY = new(nameof(freePrompt));
|
||||
private static readonly AssistantSessionStateKey<string> IMPORTED_PROMPT_STATE_KEY = new(nameof(importedPrompt));
|
||||
@@ -28,6 +31,7 @@ public partial class AssistantBatchProcessing
|
||||
private static readonly AssistantSessionStateKey<bool> IS_PROCESSING_BATCH_STATE_KEY = new(nameof(isProcessingBatch));
|
||||
private static readonly AssistantSessionStateKey<bool> HAS_REPORTED_WRITE_FAILURE_STATE_KEY = new(nameof(hasReportedWriteFailure));
|
||||
private static readonly AssistantSessionStateKey<int> NUM_PROCESSED_FILES_STATE_KEY = new(nameof(numProcessedFiles));
|
||||
private static readonly AssistantSessionStateKey<int> NUM_TOO_LARGE_FILES_STATE_KEY = new(nameof(numTooLargeFiles));
|
||||
private static readonly AssistantSessionStateKey<int> PAUSE_BEFORE_NEXT_FILE_SECONDS_STATE_KEY = new(nameof(pauseBeforeNextFileSeconds));
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -36,7 +40,10 @@ public partial class AssistantBatchProcessing
|
||||
state.Set(INPUT_DIRECTORY_STATE_KEY, this.inputDirectory);
|
||||
state.Set(OUTPUT_DIRECTORY_STATE_KEY, this.outputDirectory);
|
||||
state.Set(FILE_PATTERNS_STATE_KEY, this.filePatterns);
|
||||
state.Set(EXCLUDE_PATTERNS_STATE_KEY, this.excludePatterns);
|
||||
state.Set(MAX_FILE_SIZE_MEGABYTES_STATE_KEY, this.maxFileSizeMegabytes);
|
||||
state.Set(INCLUDE_SUBDIRECTORIES_STATE_KEY, this.includeSubdirectories);
|
||||
state.Set(INCLUDE_HIDDEN_FILES_AND_FOLDERS_STATE_KEY, this.includeHiddenFilesAndFolders);
|
||||
state.Set(PROMPT_SOURCE_STATE_KEY, this.promptSource);
|
||||
state.Set(FREE_PROMPT_STATE_KEY, this.freePrompt);
|
||||
state.Set(IMPORTED_PROMPT_STATE_KEY, this.importedPrompt);
|
||||
@@ -56,6 +63,7 @@ public partial class AssistantBatchProcessing
|
||||
state.Set(IS_PROCESSING_BATCH_STATE_KEY, this.isProcessingBatch);
|
||||
state.Set(HAS_REPORTED_WRITE_FAILURE_STATE_KEY, this.hasReportedWriteFailure);
|
||||
state.Set(NUM_PROCESSED_FILES_STATE_KEY, this.numProcessedFiles);
|
||||
state.Set(NUM_TOO_LARGE_FILES_STATE_KEY, this.numTooLargeFiles);
|
||||
state.Set(PAUSE_BEFORE_NEXT_FILE_SECONDS_STATE_KEY, this.pauseBeforeNextFileSeconds);
|
||||
}
|
||||
|
||||
@@ -65,7 +73,10 @@ public partial class AssistantBatchProcessing
|
||||
state.Restore(INPUT_DIRECTORY_STATE_KEY, value => this.inputDirectory = value);
|
||||
state.Restore(OUTPUT_DIRECTORY_STATE_KEY, value => this.outputDirectory = value);
|
||||
state.Restore(FILE_PATTERNS_STATE_KEY, value => this.filePatterns = value);
|
||||
state.Restore(EXCLUDE_PATTERNS_STATE_KEY, value => this.excludePatterns = value);
|
||||
state.Restore(MAX_FILE_SIZE_MEGABYTES_STATE_KEY, value => this.maxFileSizeMegabytes = value);
|
||||
state.Restore(INCLUDE_SUBDIRECTORIES_STATE_KEY, value => this.includeSubdirectories = value);
|
||||
state.Restore(INCLUDE_HIDDEN_FILES_AND_FOLDERS_STATE_KEY, value => this.includeHiddenFilesAndFolders = value);
|
||||
state.Restore(PROMPT_SOURCE_STATE_KEY, value => this.promptSource = value);
|
||||
state.Restore(FREE_PROMPT_STATE_KEY, value => this.freePrompt = value);
|
||||
state.Restore(IMPORTED_PROMPT_STATE_KEY, value => this.importedPrompt = value);
|
||||
@@ -89,6 +100,7 @@ public partial class AssistantBatchProcessing
|
||||
state.Restore(IS_PROCESSING_BATCH_STATE_KEY, value => this.isProcessingBatch = value);
|
||||
state.Restore(HAS_REPORTED_WRITE_FAILURE_STATE_KEY, value => this.hasReportedWriteFailure = value);
|
||||
state.Restore(NUM_PROCESSED_FILES_STATE_KEY, value => this.numProcessedFiles = value);
|
||||
state.Restore(NUM_TOO_LARGE_FILES_STATE_KEY, value => this.numTooLargeFiles = value);
|
||||
state.Restore(PAUSE_BEFORE_NEXT_FILE_SECONDS_STATE_KEY, value => this.pauseBeforeNextFileSeconds = value);
|
||||
}
|
||||
|
||||
|
||||
+43
-73
@@ -1,4 +1,3 @@
|
||||
using System.IO.Enumeration;
|
||||
|
||||
namespace AIStudio.Assistants.BatchProcessing;
|
||||
|
||||
@@ -15,35 +14,9 @@ public partial class AssistantBatchProcessing
|
||||
return null;
|
||||
}
|
||||
|
||||
private string? ValidateFilePatterns(string patterns)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(patterns))
|
||||
return T("Please provide at least one file pattern, e.g., *.pdf. Separate multiple patterns with a semicolon.");
|
||||
private string? ValidateFilePatterns(string patterns) => FileNamePatterns.Validate(patterns);
|
||||
|
||||
var individualPatterns = patterns.Split(';');
|
||||
if (individualPatterns.Any(string.IsNullOrWhiteSpace))
|
||||
return T("Please remove empty file patterns. Separate valid patterns with a single semicolon.");
|
||||
|
||||
foreach (var patternEntry in individualPatterns)
|
||||
{
|
||||
var pattern = patternEntry.Trim();
|
||||
if (pattern.Contains("**", StringComparison.Ordinal))
|
||||
return T("Please use only single asterisks as wildcards, e.g., *.pdf or report-*.docx.");
|
||||
|
||||
if (pattern is "." or ".."
|
||||
|| pattern.EndsWith("..", StringComparison.Ordinal)
|
||||
|| pattern.IndexOfAny([Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar, '/', '\\']) >= 0)
|
||||
return T("Please use file name patterns without folder paths, e.g., *.pdf or report-*.docx.");
|
||||
|
||||
var invalidCharacters = Path.GetInvalidFileNameChars()
|
||||
.Where(character => character is not '*' and not '?')
|
||||
.ToArray();
|
||||
if (pattern.IndexOfAny(invalidCharacters) >= 0)
|
||||
return T("One of the file patterns contains an invalid character.");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
private string? ValidateExcludePatterns(string patterns) => FileExclusions.Validate(patterns);
|
||||
|
||||
private string? ValidateCsvFileName(string fileName)
|
||||
{
|
||||
@@ -107,12 +80,9 @@ public partial class AssistantBatchProcessing
|
||||
|
||||
private IReadOnlyList<string> FindInputFiles(string resolvedOutputDirectory)
|
||||
{
|
||||
var patterns = this.filePatterns
|
||||
.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
||||
.ToList();
|
||||
|
||||
var searchOption = this.includeSubdirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
|
||||
var selection = new FolderFileSelection(FileNamePatterns.Parse(this.filePatterns), FileExclusions.Parse(this.excludePatterns), this.includeSubdirectories, this.includeHiddenFilesAndFolders, this.maxFileSizeMegabytes);
|
||||
var files = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
this.numTooLargeFiles = 0;
|
||||
|
||||
var normalizedInputDirectory = TrimDirectorySeparator(Path.GetFullPath(this.inputDirectory));
|
||||
var normalizedOutputDirectory = TrimDirectorySeparator(Path.GetFullPath(resolvedOutputDirectory));
|
||||
@@ -127,55 +97,46 @@ public partial class AssistantBatchProcessing
|
||||
// would also exclude a document named 'output-notes.md':
|
||||
var outputDirectoryPrefix = normalizedOutputDirectory + Path.DirectorySeparatorChar;
|
||||
|
||||
foreach (var pattern in patterns)
|
||||
foreach (var file in selection.EnumerateCandidates(
|
||||
this.inputDirectory,
|
||||
includeDirectory: directory => !isOutputSeparateFolder
|
||||
|| !string.Equals(TrimDirectorySeparator(Path.GetFullPath(directory)), normalizedOutputDirectory, StringComparison.OrdinalIgnoreCase),
|
||||
reportInaccessibleDirectory: (directory, exception) =>
|
||||
throw new IOException($"Could not access directory '{directory}'.", exception)))
|
||||
{
|
||||
foreach (var file in Directory.EnumerateFiles(this.inputDirectory, pattern, searchOption))
|
||||
var normalizedFile = Path.GetFullPath(file);
|
||||
if (!selection.Selects(normalizedFile) || IsTranscriptArtifact(normalizedFile))
|
||||
continue;
|
||||
|
||||
if (isOutputSeparateFolder)
|
||||
{
|
||||
var normalizedFile = Path.GetFullPath(file);
|
||||
if (IsTranscriptArtifact(normalizedFile))
|
||||
if (normalizedFile.StartsWith(outputDirectoryPrefix, StringComparison.OrdinalIgnoreCase))
|
||||
continue;
|
||||
|
||||
if (isOutputSeparateFolder)
|
||||
{
|
||||
if (normalizedFile.StartsWith(outputDirectoryPrefix, StringComparison.OrdinalIgnoreCase))
|
||||
continue;
|
||||
}
|
||||
else if (this.IsOwnOutputArtifact(normalizedFile))
|
||||
continue;
|
||||
|
||||
// On Windows, a pattern with a three-character extension also
|
||||
// matches longer extensions: '*.pdf' also returns 'report.pdfx'.
|
||||
// We therefore check the pattern ourselves:
|
||||
if (!MatchesAnyPattern(normalizedFile, patterns))
|
||||
continue;
|
||||
|
||||
files.Add(normalizedFile);
|
||||
}
|
||||
else if (this.IsOwnOutputArtifact(normalizedFile))
|
||||
continue;
|
||||
|
||||
//
|
||||
// Left out without a status of its own: the file never becomes part of the run. The
|
||||
// line below the file list tells the user, and the log names the limit:
|
||||
//
|
||||
if (selection.IsTooLarge(new FileInfo(normalizedFile)))
|
||||
{
|
||||
this.numTooLargeFiles++;
|
||||
continue;
|
||||
}
|
||||
|
||||
files.Add(normalizedFile);
|
||||
}
|
||||
|
||||
if (this.numTooLargeFiles > 0)
|
||||
this.Logger.LogInformation("Left out {NumTooLargeFiles} matching file(s) in '{InputDirectory}' from the batch run because they are larger than {MaxFileSize}.", this.numTooLargeFiles, this.inputDirectory, selection.MaxFileSizeBytes.FileSize());
|
||||
|
||||
return [.. files];
|
||||
}
|
||||
|
||||
private static string TrimDirectorySeparator(string path) => path.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||
|
||||
private static bool MatchesAnyPattern(string filePath, IReadOnlyList<string> patterns)
|
||||
{
|
||||
var fileName = Path.GetFileName(filePath);
|
||||
foreach (var pattern in patterns)
|
||||
{
|
||||
// A pattern may contain a folder part, which does not take part in
|
||||
// matching the file name:
|
||||
var namePattern = Path.GetFileName(pattern);
|
||||
if (string.IsNullOrWhiteSpace(namePattern))
|
||||
continue;
|
||||
|
||||
if (FileSystemName.MatchesSimpleExpression(namePattern, fileName))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a file is an output artifact of this assistant. We need
|
||||
/// this when the output folder is the input folder: without it, the results
|
||||
@@ -211,6 +172,13 @@ public partial class AssistantBatchProcessing
|
||||
{
|
||||
await this.Form!.Validate();
|
||||
|
||||
//
|
||||
// The exclusion list sits in the expert settings, which are folded away by default. Unfold
|
||||
// them, so the user sees the message next to the list:
|
||||
//
|
||||
if (this.ValidateExcludePatterns(this.excludePatterns) is not null)
|
||||
this.showExpertSettings = true;
|
||||
|
||||
var instructionIssue = this.ValidateInstructionSource();
|
||||
if (instructionIssue is not null)
|
||||
{
|
||||
@@ -236,7 +204,9 @@ public partial class AssistantBatchProcessing
|
||||
|
||||
if (files.Count == 0)
|
||||
{
|
||||
this.AddInputIssue(T("No matching files were found in the selected folder."));
|
||||
this.AddInputIssue(this.numTooLargeFiles > 0
|
||||
? string.Format(T("Every matching file in the selected folder is larger than {0}. Raise the size limit to process them."), FolderFileSelection.MegabytesToBytes(this.maxFileSizeMegabytes).FileSize())
|
||||
: T("No matching files were found in the selected folder."));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+24
-2
@@ -82,6 +82,7 @@ public partial class AssistantBatchProcessing : AssistantBaseCore<SettingsDialog
|
||||
this.hasReportedWriteFailure = false;
|
||||
this.numProcessedFiles = 0;
|
||||
this.pauseBeforeNextFileSeconds = 0;
|
||||
this.numTooLargeFiles = 0;
|
||||
}
|
||||
|
||||
protected override bool MightPreselectValues()
|
||||
@@ -102,7 +103,10 @@ public partial class AssistantBatchProcessing : AssistantBaseCore<SettingsDialog
|
||||
private string inputDirectory = string.Empty;
|
||||
private string outputDirectory = string.Empty;
|
||||
private string filePatterns = DataBatchProcessing.DEFAULT_FILE_PATTERNS;
|
||||
private bool includeSubdirectories;
|
||||
private string excludePatterns = FileExclusions.DEFAULT_PATTERNS;
|
||||
private int maxFileSizeMegabytes = FolderFileSelection.DEFAULT_MAX_FILE_SIZE_MEGABYTES;
|
||||
private bool includeSubdirectories = DataBatchProcessing.DEFAULT_INCLUDE_SUBDIRECTORIES;
|
||||
private bool includeHiddenFilesAndFolders = DataBatchProcessing.DEFAULT_INCLUDE_HIDDEN_FILES_AND_FOLDERS;
|
||||
private BatchProcessingPromptSource promptSource = BatchProcessingPromptSource.FREE_PROMPT;
|
||||
private string freePrompt = string.Empty;
|
||||
private string importedPrompt = string.Empty;
|
||||
@@ -120,11 +124,17 @@ public partial class AssistantBatchProcessing : AssistantBaseCore<SettingsDialog
|
||||
|
||||
private readonly List<BatchProcessingFileResult> fileResults = [];
|
||||
private readonly HashSet<string> usedResultFileNames = new(StringComparer.OrdinalIgnoreCase);
|
||||
private bool showExpertSettings;
|
||||
private bool isProcessingBatch;
|
||||
private bool hasReportedWriteFailure;
|
||||
private int numProcessedFiles;
|
||||
private int pauseBeforeNextFileSeconds;
|
||||
|
||||
/// <summary>
|
||||
/// How many matching files the last search left out for their size, cf. FindInputFiles.
|
||||
/// </summary>
|
||||
private int numTooLargeFiles;
|
||||
|
||||
/// <summary>
|
||||
/// The header of the column of the results table that holds the AI answer.
|
||||
/// </summary>
|
||||
@@ -159,6 +169,12 @@ public partial class AssistantBatchProcessing : AssistantBaseCore<SettingsDialog
|
||||
|
||||
private void RestoreDefaultFilePatterns() => this.filePatterns = DataBatchProcessing.DEFAULT_FILE_PATTERNS;
|
||||
|
||||
private void RestoreDefaultExcludePatterns() => this.excludePatterns = FileExclusions.DEFAULT_PATTERNS;
|
||||
|
||||
private void ToggleExpertSettings() => this.showExpertSettings = !this.showExpertSettings;
|
||||
|
||||
private string GetExpertStyles => this.showExpertSettings ? "border-2 border-dashed rounded pa-2" : string.Empty;
|
||||
|
||||
private ConfidenceLevel GetMinimumConfidenceLevel()
|
||||
{
|
||||
var minimumLevel = this.SettingsManager.GetMinimumConfidenceLevel(this.Component);
|
||||
@@ -178,7 +194,10 @@ public partial class AssistantBatchProcessing : AssistantBaseCore<SettingsDialog
|
||||
this.inputDirectory = string.Empty;
|
||||
this.outputDirectory = string.Empty;
|
||||
this.filePatterns = DataBatchProcessing.DEFAULT_FILE_PATTERNS;
|
||||
this.includeSubdirectories = false;
|
||||
this.excludePatterns = FileExclusions.DEFAULT_PATTERNS;
|
||||
this.maxFileSizeMegabytes = FolderFileSelection.DEFAULT_MAX_FILE_SIZE_MEGABYTES;
|
||||
this.includeSubdirectories = DataBatchProcessing.DEFAULT_INCLUDE_SUBDIRECTORIES;
|
||||
this.includeHiddenFilesAndFolders = DataBatchProcessing.DEFAULT_INCLUDE_HIDDEN_FILES_AND_FOLDERS;
|
||||
this.promptSource = BatchProcessingPromptSource.FREE_PROMPT;
|
||||
this.freePrompt = string.Empty;
|
||||
this.promptFilePath = string.Empty;
|
||||
@@ -197,7 +216,10 @@ public partial class AssistantBatchProcessing : AssistantBaseCore<SettingsDialog
|
||||
this.inputDirectory = settings.InputDirectory;
|
||||
this.outputDirectory = settings.OutputDirectory;
|
||||
this.filePatterns = settings.FilePatterns;
|
||||
this.excludePatterns = settings.ExcludePatterns;
|
||||
this.maxFileSizeMegabytes = Math.Max(settings.MaxFileSizeMegabytes, FolderFileSelection.SMALLEST_MAX_FILE_SIZE_MEGABYTES);
|
||||
this.includeSubdirectories = settings.IncludeSubdirectories;
|
||||
this.includeHiddenFilesAndFolders = settings.IncludeHiddenFilesAndFolders;
|
||||
this.promptSource = settings.PromptSource;
|
||||
this.freePrompt = settings.FreePrompt;
|
||||
this.promptFilePath = settings.PromptFilePath;
|
||||
|
||||
@@ -346,6 +346,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::ASSISTANTBASE::T83711157"] = "Copy result
|
||||
-- The transcription provider returned an empty transcript.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1080540822"] = "The transcription provider returned an empty transcript."
|
||||
|
||||
-- Hide Expert Settings
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1108876344"] = "Hide Expert Settings"
|
||||
|
||||
-- We always write a semicolon-separated log named log.csv, which lists every document with its processing time, the model, the status, and the details of any error. When you start another run on the same output folder, we ask you whether to continue that run: documents which failed or are missing in the log are then processed again. When no output folder is selected, everything is written to the subfolder 'ai-results' within the input folder.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1124333059"] = "We always write a semicolon-separated log named log.csv, which lists every document with its processing time, the model, the status, and the details of any error. When you start another run on the same output folder, we ask you whether to continue that run: documents which failed or are missing in the log are then processed again. When no output folder is selected, everything is written to the subfolder 'ai-results' within the input folder."
|
||||
|
||||
@@ -361,12 +364,6 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- The results table contains one row per document, starting with the file name. Here you can name the column that holds the AI answer, e.g., Summary. When left empty, we use 'Result'.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1164512104"] = "The results table contains one row per document, starting with the file name. Here you can name the column that holds the AI answer, e.g., Summary. When left empty, we use 'Result'."
|
||||
|
||||
-- One of the file patterns contains an invalid character.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1182642380"] = "One of the file patterns contains an invalid character."
|
||||
|
||||
-- Please use only single asterisks as wildcards, e.g., *.pdf or report-*.docx.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1187528282"] = "Please use only single asterisks as wildcards, e.g., *.pdf or report-*.docx."
|
||||
|
||||
-- Supported audio and video files are transcribed automatically without an additional dialog. Each transcript is stored next to its media file as '<media-file>.transcript.md' and reused when an interrupted run is continued.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T120341322"] = "Supported audio and video files are transcribed automatically without an additional dialog. Each transcript is stored next to its media file as '<media-file>.transcript.md' and reused when an interrupted run is continued."
|
||||
|
||||
@@ -379,6 +376,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Batch Processing Assistant
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T132410578"] = "Batch Processing Assistant"
|
||||
|
||||
-- Every matching file in the selected folder is larger than {0}. Raise the size limit to process them.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1335222997"] = "Every matching file in the selected folder is larger than {0}. Raise the size limit to process them."
|
||||
|
||||
-- These instructions are applied to every single document of the batch run.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1339979506"] = "These instructions are applied to every single document of the batch run."
|
||||
|
||||
@@ -400,9 +400,6 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Please select the file which contains your instructions.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1462027716"] = "Please select the file which contains your instructions."
|
||||
|
||||
-- Which files should be processed? Separate multiple patterns with a semicolon, e.g., *.pdf;*.docx
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1482642245"] = "Which files should be processed? Separate multiple patterns with a semicolon, e.g., *.pdf;*.docx"
|
||||
|
||||
-- blocked
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1516072627"] = "blocked"
|
||||
|
||||
@@ -415,6 +412,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Select the output folder
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1598970341"] = "Select the output folder"
|
||||
|
||||
-- Hidden are files and folders whose names start with a dot, such as .git or .env, and those hidden by the operating system. A file pattern which starts with a dot, such as .gitignore, selects such files anyway.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1624717965"] = "Hidden are files and folders whose names start with a dot, such as .git or .env, and those hidden by the operating system. A file pattern which starts with a dot, such as .gitignore, selects such files anyway."
|
||||
|
||||
-- The configured default policy no longer exists. Please select another document analysis policy.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T169666151"] = "The configured default policy no longer exists. Please select another document analysis policy."
|
||||
|
||||
@@ -448,9 +448,6 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- The configured instructions file is empty.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T216725576"] = "The configured instructions file is empty."
|
||||
|
||||
-- Please provide at least one file pattern, e.g., *.pdf. Separate multiple patterns with a semicolon.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2179775338"] = "Please provide at least one file pattern, e.g., *.pdf. Separate multiple patterns with a semicolon."
|
||||
|
||||
-- Model
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2189814010"] = "Model"
|
||||
|
||||
@@ -469,6 +466,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Was not able to create the output folder: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2290092642"] = "Was not able to create the output folder: {0}"
|
||||
|
||||
-- Yes, process hidden files and folders as well
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2295617720"] = "Yes, process hidden files and folders as well"
|
||||
|
||||
-- The AI answer was empty.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T230354366"] = "The AI answer was empty."
|
||||
|
||||
@@ -523,6 +523,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Before the next file starts, AI Studio waits for a random number of whole seconds from this interval. The minimum is always 6 seconds and the maximum is 300 seconds (5 minutes). Restored files and the end of a run do not add another pause.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2742154256"] = "Before the next file starts, AI Studio waits for a random number of whole seconds from this interval. The minimum is always 6 seconds and the maximum is 300 seconds (5 minutes). Restored files and the end of a run do not add another pause."
|
||||
|
||||
-- Excluded files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T286958948"] = "Excluded files and folders"
|
||||
|
||||
-- Please enter exactly one punctuation or symbol character. Letters, numbers, spaces, quotation marks, and line breaks cannot be used as CSV separators.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2908365499"] = "Please enter exactly one punctuation or symbol character. Letters, numbers, spaces, quotation marks, and line breaks cannot be used as CSV separators."
|
||||
|
||||
@@ -547,24 +550,36 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- The content of the selected file is used as the instructions for every single document of the batch run.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T332380551"] = "The content of the selected file is used as the instructions for every single document of the batch run."
|
||||
|
||||
-- Ignore files larger than
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3353866230"] = "Ignore files larger than"
|
||||
|
||||
-- Show Expert Settings
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3361153305"] = "Show Expert Settings"
|
||||
|
||||
-- Header of the result column (optional)
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T340994102"] = "Header of the result column (optional)"
|
||||
|
||||
-- Processing pace
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3428873429"] = "Processing pace"
|
||||
|
||||
-- Which files should be processed? Separate multiple patterns with a semicolon, e.g., *.pdf;*.docx. Use :documents: for every document and readable text file, :text: for readable text files only, or * for every file.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3436936162"] = "Which files should be processed? Separate multiple patterns with a semicolon, e.g., *.pdf;*.docx. Use :documents: for every document and readable text file, :text: for readable text files only, or * for every file."
|
||||
|
||||
-- The file name of the CSV results table. We add the ending .csv when it is missing. When left empty, we use 'batch-results.csv'.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3439247329"] = "The file name of the CSV results table. We add the ending .csv when it is missing. When left empty, we use 'batch-results.csv'."
|
||||
|
||||
-- Document analysis policy
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3510564924"] = "Document analysis policy"
|
||||
|
||||
-- Matching files above this size are left out, e.g., images of virtual machines.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3579292542"] = "Matching files above this size are left out, e.g., images of virtual machines."
|
||||
|
||||
-- No, ignore hidden files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3584816527"] = "No, ignore hidden files and folders"
|
||||
|
||||
-- {0} of {1} files processed
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3648144402"] = "{0} of {1} files processed"
|
||||
|
||||
-- Please remove empty file patterns. Separate valid patterns with a single semicolon.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T368919579"] = "Please remove empty file patterns. Separate valid patterns with a single semicolon."
|
||||
|
||||
-- Was not able to store the transcript next to the media file: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3691287653"] = "Was not able to store the transcript next to the media file: {0}"
|
||||
|
||||
@@ -586,6 +601,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Was not able to write '{0}'. Please make sure that the file is not opened in another application. The results of this run are incomplete on disk. The message is: '{1}'
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3899869356"] = "Was not able to write '{0}'. Please make sure that the file is not opened in another application. The results of this run are incomplete on disk. The message is: '{1}'"
|
||||
|
||||
-- These files and folders are left out, even when a file pattern selects them. Separate entries with a semicolon or a line break. End an entry with a slash to exclude every folder of that name, e.g., node_modules/. Other entries name files, e.g., *.min.js.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3934601817"] = "These files and folders are left out, even when a file pattern selects them. Separate entries with a semicolon or a line break. End an entry with a slash to exclude every folder of that name, e.g., node_modules/. Other entries name files, e.g., *.min.js."
|
||||
|
||||
-- Select the file with your instructions
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3943995624"] = "Select the file with your instructions"
|
||||
|
||||
@@ -610,6 +628,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Was not able to extract any text from this file.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T4175885324"] = "Was not able to extract any text from this file."
|
||||
|
||||
-- {0} matching files were left out because they are larger than {1}.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T4184365620"] = "{0} matching files were left out because they are larger than {1}."
|
||||
|
||||
-- Column separator
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T423947932"] = "Column separator"
|
||||
|
||||
@@ -634,9 +655,6 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Start batch processing
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T50133258"] = "Start batch processing"
|
||||
|
||||
-- Please use file name patterns without folder paths, e.g., *.pdf or report-*.docx.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T515934256"] = "Please use file name patterns without folder paths, e.g., *.pdf or report-*.docx."
|
||||
|
||||
-- Was not able to read the results table of the previous run. Its completed documents cannot be restored and will be processed again.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T544244392"] = "Was not able to read the results table of the previous run. Its completed documents cannot be restored and will be processed again."
|
||||
|
||||
@@ -658,6 +676,12 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- A separate output folder is excluded from document discovery. This includes the default 'ai-results' folder, so results from an earlier run are not processed again. If the input folder itself is used for output, known batch result files are excluded instead.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T822136905"] = "A separate output folder is excluded from document discovery. This includes the default 'ai-results' folder, so results from an earlier run are not processed again. If the input folder itself is used for output, known batch result files are excluded instead."
|
||||
|
||||
-- Include hidden files and folders?
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T85084423"] = "Include hidden files and folders?"
|
||||
|
||||
-- Restore default
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T913168756"] = "Restore default"
|
||||
|
||||
-- The AI may use these tools while working on each document. Every tool has to meet the confidence requirements of the selected provider, so a tool may stay unavailable even when it is selected here.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T967206794"] = "The AI may use these tools while working on each document. Every tool has to meet the confidence requirements of the selected provider, so a tool may stay unavailable even when it is selected here."
|
||||
|
||||
@@ -4024,9 +4048,15 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T2594880
|
||||
-- The file '{0}'
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T2794508936"] = "The file '{0}'"
|
||||
|
||||
-- Every file this data source selects from this folder
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T3414038542"] = "Every file this data source selects from this folder"
|
||||
|
||||
-- Warning: The selected embedding provider is not self-hosted. Creating embeddings can cost money and may need to run multiple times, for example after errors or file changes. {0} will be sent to an external third party. MindWork AI Studio has no control over what that third party does with the data after it is sent.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T3457494593"] = "Warning: The selected embedding provider is not self-hosted. Creating embeddings can cost money and may need to run multiple times, for example after errors or file changes. {0} will be sent to an external third party. MindWork AI Studio has no control over what that third party does with the data after it is sent."
|
||||
|
||||
-- Every file this data source selects from the folder '{0}'
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T3515150437"] = "Every file this data source selects from the folder '{0}'"
|
||||
|
||||
-- I confirm that I have read and understood the above
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T3683380716"] = "I confirm that I have read and understood the above"
|
||||
|
||||
@@ -4036,12 +4066,6 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T3793916
|
||||
-- The selected file
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T3999057817"] = "The selected file"
|
||||
|
||||
-- All files in the folder '{0}' and its subfolders
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T661754597"] = "All files in the folder '{0}' and its subfolders"
|
||||
|
||||
-- All files in this folder and its subfolders
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T916879200"] = "All files in this folder and its subfolders"
|
||||
|
||||
-- AI Studio is backing up or restoring the indexes of your data sources right now. Please try again once that is done.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1006756723"] = "AI Studio is backing up or restoring the indexes of your data sources right now. Please try again once that is done."
|
||||
|
||||
@@ -4078,9 +4102,6 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1652430727"] = "Ex
|
||||
-- Local File
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1687345358"] = "Local File"
|
||||
|
||||
-- {0} files were skipped because they contain no readable text. AI Studio reads them again once they change.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T169247705"] = "{0} files were skipped because they contain no readable text. AI Studio reads them again once they change."
|
||||
|
||||
-- Delete Data Source
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1849107431"] = "Delete Data Source"
|
||||
|
||||
@@ -4117,6 +4138,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2771708618"] = "Re
|
||||
-- Embedding
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2838542994"] = "Embedding"
|
||||
|
||||
-- Skipped files: {0}. Open Background embeddings to see why and what you can do.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2887502801"] = "Skipped files: {0}. Open Background embeddings to see why and what you can do."
|
||||
|
||||
-- Indexed
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2906901514"] = "Indexed"
|
||||
|
||||
@@ -6673,8 +6697,8 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1136409150"
|
||||
-- Default tokenizer
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1220918127"] = "Default tokenizer"
|
||||
|
||||
-- Select a root directory for this data source. All data in this directory and all its subdirectories will be processed for this data source.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1265737624"] = "Select a root directory for this data source. All data in this directory and all its subdirectories will be processed for this data source."
|
||||
-- Selected files above this size are not indexed, e.g., images of virtual machines. The embedding page lists them, so you can raise the limit when needed.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1311820297"] = "Selected files above this size are not indexed, e.g., images of virtual machines. The embedding page lists them, so you can raise the limit when needed."
|
||||
|
||||
-- Selected base directory for this data source
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1312296210"] = "Selected base directory for this data source"
|
||||
@@ -6682,9 +6706,18 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1312296210"
|
||||
-- No embedding selected
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1359179968"] = "No embedding selected"
|
||||
|
||||
-- Select a root directory for this data source.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1400580807"] = "Select a root directory for this data source."
|
||||
|
||||
-- No, only index files in the selected folder
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1490813458"] = "No, only index files in the selected folder"
|
||||
|
||||
-- Number of tokens repeated at the start of the next chunk. The default overlap is {0} tokens.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1588814044"] = "Number of tokens repeated at the start of the next chunk. The default overlap is {0} tokens."
|
||||
|
||||
-- Hidden are files and folders whose names start with a dot, such as .git or .env, and those hidden by the operating system. A file pattern which starts with a dot, such as .gitignore, selects such files anyway.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1624717965"] = "Hidden are files and folders whose names start with a dot, such as .git or .env, and those hidden by the operating system. A file pattern which starts with a dot, such as .gitignore, selects such files anyway."
|
||||
|
||||
-- Tokenizer
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1696723386"] = "Tokenizer"
|
||||
|
||||
@@ -6700,15 +6733,24 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1827669611"
|
||||
-- Update
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1847791252"] = "Update"
|
||||
|
||||
-- Include subfolders?
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2086334687"] = "Include subfolders?"
|
||||
|
||||
-- The overlap must be smaller than the effective token limit.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2101951526"] = "The overlap must be smaller than the effective token limit."
|
||||
|
||||
-- Select the file patterns this data source should index.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2244471011"] = "Select the file patterns this data source should index."
|
||||
|
||||
-- Required provider confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T236253137"] = "Required provider confidence level"
|
||||
|
||||
-- Please enter a token limit of at least 1.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2406580478"] = "Please enter a token limit of at least 1."
|
||||
|
||||
-- File patterns
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2460883298"] = "File patterns"
|
||||
|
||||
-- Add
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2646845972"] = "Add"
|
||||
|
||||
@@ -6721,41 +6763,83 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2814869210"
|
||||
-- Embedding
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2838542994"] = "Embedding"
|
||||
|
||||
-- Excluded files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T286958948"] = "Excluded files and folders"
|
||||
|
||||
-- Token limit
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2961294165"] = "Token limit"
|
||||
|
||||
-- Please enter 0 or a positive overlap length.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3242265813"] = "Please enter 0 or a positive overlap length."
|
||||
|
||||
-- Ignore files larger than
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3353866230"] = "Ignore files larger than"
|
||||
|
||||
-- For some data types, such as Office files, MindWork AI Studio requires the open-source application Pandoc.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3359366900"] = "For some data types, such as Office files, MindWork AI Studio requires the open-source application Pandoc."
|
||||
|
||||
-- Show Expert Settings
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3361153305"] = "Show Expert Settings"
|
||||
|
||||
-- No, ignore hidden files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3584816527"] = "No, ignore hidden files and folders"
|
||||
|
||||
-- These files and folders are left out, even when a file pattern selects them. Separate entries with a semicolon or a line break. End an entry with a slash to exclude every folder of that name, e.g., node_modules/. Other entries name files, e.g., *.min.js.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3934601817"] = "These files and folders are left out, even when a file pattern selects them. Separate entries with a semicolon or a line break. End an entry with a slash to exclude every folder of that name, e.g., node_modules/. Other entries name files, e.g., *.min.js."
|
||||
|
||||
-- In order for the AI to be able to determine the appropriate data at any time, you must choose an embedding provider.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T529871858"] = "In order for the AI to be able to determine the appropriate data at any time, you must choose an embedding provider."
|
||||
|
||||
-- Select the base directory
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T562479068"] = "Select the base directory"
|
||||
|
||||
-- Yes, index hidden files and folders as well
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T607153623"] = "Yes, index hidden files and folders as well"
|
||||
|
||||
-- Which files should be indexed? Separate multiple patterns with a semicolon, e.g., *.txt;*.pdf;*.docx;.gitignore. Use :documents: for every document and readable text file, :text: for readable text files only, or * for every file.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T761052435"] = "Which files should be indexed? Separate multiple patterns with a semicolon, e.g., *.txt;*.pdf;*.docx;.gitignore. Use :documents: for every document and readable text file, :text: for readable text files only, or * for every file."
|
||||
|
||||
-- The data source token limit must not be larger than the embedding provider token limit ({0}).
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T787118522"] = "The data source token limit must not be larger than the embedding provider token limit ({0})."
|
||||
|
||||
-- Data Source Name
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T813773421"] = "Data Source Name"
|
||||
|
||||
-- Include hidden files and folders?
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T85084423"] = "Include hidden files and folders?"
|
||||
|
||||
-- Cancel
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T900713019"] = "Cancel"
|
||||
|
||||
-- Restore default
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T913168756"] = "Restore default"
|
||||
|
||||
-- Yes, index files in subfolders as well
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T918760813"] = "Yes, index files in subfolders as well"
|
||||
|
||||
-- Token overlap
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T981382809"] = "Token overlap"
|
||||
|
||||
-- the total directory size
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1082241458"] = "the total directory size"
|
||||
-- the number of matching files in the directory
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1087340457"] = "the number of matching files in the directory"
|
||||
|
||||
-- Total directory size
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1101400963"] = "Total directory size"
|
||||
-- Total size of matching files
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1109307573"] = "Total size of matching files"
|
||||
|
||||
-- Number of matching files
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1397096827"] = "Number of matching files"
|
||||
|
||||
-- For performance reasons, only the first 100 matching files are shown. The configured patterns match {0} files in total.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1430424205"] = "For performance reasons, only the first 100 matching files are shown. The configured patterns match {0} files in total."
|
||||
|
||||
-- whether hidden files and folders are included
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1447415145"] = "whether hidden files and folders are included"
|
||||
|
||||
-- No
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1642511898"] = "No"
|
||||
|
||||
-- Include subfolders
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1710166842"] = "Include subfolders"
|
||||
|
||||
-- Data source name
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T171124909"] = "Data source name"
|
||||
@@ -6763,27 +6847,39 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1711249
|
||||
-- Description
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1725856265"] = "Description"
|
||||
|
||||
-- the number of files in the directory
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1795263412"] = "the number of files in the directory"
|
||||
|
||||
-- The embedding runs locally or in your organization. Your data is not sent to the cloud.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1950544032"] = "The embedding runs locally or in your organization. Your data is not sent to the cloud."
|
||||
|
||||
-- the files list
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2072700997"] = "the files list"
|
||||
-- the file patterns
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2013714981"] = "the file patterns"
|
||||
|
||||
-- The embedding runs in the cloud. Every file this data source selects from the folder '{0}' will be sent to the cloud.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2139422620"] = "The embedding runs in the cloud. Every file this data source selects from the folder '{0}' will be sent to the cloud."
|
||||
|
||||
-- whether subfolders are included
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2333573949"] = "whether subfolders are included"
|
||||
|
||||
-- Required provider confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T236253137"] = "Required provider confidence level"
|
||||
|
||||
-- File patterns
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2460883298"] = "File patterns"
|
||||
|
||||
-- the maximum number of matches per query
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2479753122"] = "the maximum number of matches per query"
|
||||
|
||||
-- the total size of matching files
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2515807708"] = "the total size of matching files"
|
||||
|
||||
-- the description
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2658359966"] = "the description"
|
||||
|
||||
-- the data source name
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2717738728"] = "the data source name"
|
||||
|
||||
-- Excluded files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T286958948"] = "Excluded files and folders"
|
||||
|
||||
-- The directory chosen for the data source does not exist anymore. Please edit the data source and correct the path.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2875614207"] = "The directory chosen for the data source does not exist anymore. Please edit the data source and correct the path."
|
||||
|
||||
@@ -6796,26 +6892,35 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2937209
|
||||
-- this path
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2944855252"] = "this path"
|
||||
|
||||
-- Yes
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3013883440"] = "Yes"
|
||||
|
||||
-- the size limit for files
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3081730094"] = "the size limit for files"
|
||||
|
||||
-- Embedding name
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3153201045"] = "Embedding name"
|
||||
|
||||
-- Files list
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3238813368"] = "Files list"
|
||||
-- Ignore files larger than
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3353866230"] = "Ignore files larger than"
|
||||
|
||||
-- Close
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3448155331"] = "Close"
|
||||
|
||||
-- For performance reasons, only the first 100 files are shown. The directory contains {0} files in total.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T360238400"] = "For performance reasons, only the first 100 files are shown. The directory contains {0} files in total."
|
||||
-- Matching files
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3650746465"] = "Matching files"
|
||||
|
||||
-- Include hidden files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3770422018"] = "Include hidden files and folders"
|
||||
|
||||
-- the matching files list
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3818527556"] = "the matching files list"
|
||||
|
||||
-- Path
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3949388886"] = "Path"
|
||||
|
||||
-- Number of files
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T417749210"] = "Number of files"
|
||||
|
||||
-- The embedding runs in the cloud. All your data from the folder '{0}' and all its subdirectories will be sent to the cloud.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T443873444"] = "The embedding runs in the cloud. All your data from the folder '{0}' and all its subdirectories will be sent to the cloud."
|
||||
-- the excluded files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T4001527349"] = "the excluded files and folders"
|
||||
|
||||
-- The directory chosen for the data source exists.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T445858624"] = "The directory chosen for the data source exists."
|
||||
@@ -8416,9 +8521,18 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T10
|
||||
-- Instructions
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T1221801316"] = "Instructions"
|
||||
|
||||
-- Include hidden files and folders by default?
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T1450016875"] = "Include hidden files and folders by default?"
|
||||
|
||||
-- Matching files above this size are left out of a batch run, e.g., images of virtual machines.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T1504546559"] = "Matching files above this size are left out of a batch run, e.g., images of virtual machines."
|
||||
|
||||
-- Leave empty to use the ai-results subfolder of the input folder.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T1550632323"] = "Leave empty to use the ai-results subfolder of the input folder."
|
||||
|
||||
-- Hidden are files and folders whose names start with a dot, such as .git or .env, and those hidden by the operating system. A file pattern which starts with a dot, such as .gitignore, selects such files anyway.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T1624717965"] = "Hidden are files and folders whose names start with a dot, such as .git or .env, and those hidden by the operating system. A file pattern which starts with a dot, such as .gitignore, selects such files anyway."
|
||||
|
||||
-- seconds
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T1723256298"] = "seconds"
|
||||
|
||||
@@ -8443,12 +8557,18 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T21
|
||||
-- Default output folder
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T223484721"] = "Default output folder"
|
||||
|
||||
-- Hidden files and folders are included
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T2288334048"] = "Hidden files and folders are included"
|
||||
|
||||
-- The lower end of the random pause interval. AI Studio never allows less than 6 seconds.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T237774509"] = "The lower end of the random pause interval. AI Studio never allows less than 6 seconds."
|
||||
|
||||
-- A policy brings its own tools, so there is nothing to preselect here. You configure them with the policy in the Document Analysis Assistant.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T2391906382"] = "A policy brings its own tools, so there is nothing to preselect here. You configure them with the policy in the Document Analysis Assistant."
|
||||
|
||||
-- Default excluded files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T2460020307"] = "Default excluded files and folders"
|
||||
|
||||
-- When enabled, new batch runs start with the defaults configured below.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T2592677194"] = "When enabled, new batch runs start with the defaults configured below."
|
||||
|
||||
@@ -8494,6 +8614,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T31
|
||||
-- These instructions are applied to every document of a new batch run.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T3195548336"] = "These instructions are applied to every document of a new batch run."
|
||||
|
||||
-- Ignore files larger than
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T3353866230"] = "Ignore files larger than"
|
||||
|
||||
-- No batch processing options are preselected
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T3421035581"] = "No batch processing options are preselected"
|
||||
|
||||
@@ -8521,6 +8644,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T37
|
||||
-- Default results table name
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T3816237687"] = "Default results table name"
|
||||
|
||||
-- These files and folders are left out, even when a file pattern selects them. Separate entries with a semicolon or a line break. End an entry with a slash to exclude every folder of that name, e.g., node_modules/. Other entries name files, e.g., *.min.js.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T3934601817"] = "These files and folders are left out, even when a file pattern selects them. Separate entries with a semicolon or a line break. End an entry with a slash to exclude every folder of that name, e.g., node_modules/. Other entries name files, e.g., *.min.js."
|
||||
|
||||
-- Default Markdown instructions file
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T3967465682"] = "Default Markdown instructions file"
|
||||
|
||||
@@ -8563,6 +8689,12 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T74
|
||||
-- Leave empty when an input folder should be selected for every batch run.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T762890100"] = "Leave empty when an input folder should be selected for every batch run."
|
||||
|
||||
-- Hidden files and folders are ignored
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T826400562"] = "Hidden files and folders are ignored"
|
||||
|
||||
-- Restore default
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T913168756"] = "Restore default"
|
||||
|
||||
-- Preselect one of your chat templates?
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHAT::T1402022556"] = "Preselect one of your chat templates?"
|
||||
|
||||
@@ -9754,6 +9886,9 @@ UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2148829171"] = "Embeddings are r
|
||||
-- Plugins
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2222816203"] = "Plugins"
|
||||
|
||||
-- One data source needs attention.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2349740877"] = "One data source needs attention."
|
||||
|
||||
-- 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."
|
||||
|
||||
@@ -9778,6 +9913,9 @@ UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2979224202"] = "Writer"
|
||||
-- Embeddings are waiting to be processed.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T3439916590"] = "Embeddings are waiting to be processed."
|
||||
|
||||
-- {0} data sources need attention.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T344098457"] = "{0} data sources need attention."
|
||||
|
||||
-- Show details
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T3692372066"] = "Show details"
|
||||
|
||||
@@ -10015,18 +10153,30 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1297391911"] = "Mailboxes are syn
|
||||
-- File {0} of {1} is being indexed: block {2}, page {3}.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1298290372"] = "File {0} of {1} is being indexed: block {2}, page {3}."
|
||||
|
||||
-- These image, audio, or video files match the data source patterns, but they cannot currently be added to the index.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1302021733"] = "These image, audio, or video files match the data source patterns, but they cannot currently be added to the index."
|
||||
|
||||
-- Mail
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1399880782"] = "Mail"
|
||||
|
||||
-- Could not open the file location: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1455637941"] = "Could not open the file location: {0}"
|
||||
|
||||
-- These files match the data source patterns, but they are larger than its limit of {0}. You can raise the limit in the expert settings of the data source.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1485378199"] = "These files match the data source patterns, but they are larger than its limit of {0}. You can raise the limit in the expert settings of the data source."
|
||||
|
||||
-- Outside the selection
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1512669069"] = "Outside the selection"
|
||||
|
||||
-- Failed: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1531389696"] = "Failed: {0}"
|
||||
|
||||
-- AI Studio indexes large data sources in steps of a few minutes, so that your other data sources get their turn in between.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1545941101"] = "AI Studio indexes large data sources in steps of a few minutes, so that your other data sources get their turn in between."
|
||||
|
||||
-- Too large
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T156180350"] = "Too large"
|
||||
|
||||
-- Open the settings
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1582896271"] = "Open the settings"
|
||||
|
||||
@@ -10048,9 +10198,6 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T2149927097"] = "Manage your data
|
||||
-- Noticed
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T2367007983"] = "Noticed"
|
||||
|
||||
-- Skipped files: {0}. AI Studio reads them again once they change.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T2382275084"] = "Skipped files: {0}. AI Studio reads them again once they change."
|
||||
|
||||
-- AI Studio indexes local RAG data sources in the background. Finished files stay recorded so unchanged files can be skipped after a restart, while added or deleted files are detected during the next run. The same applies to documents without readable text, such as scanned pages: AI Studio remembers them and reads them again only once they change.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T2398894096"] = "AI Studio indexes local RAG data sources in the background. Finished files stay recorded so unchanged files can be skipped after a restart, while added or deleted files are detected during the next run. The same applies to documents without readable text, such as scanned pages: AI Studio remembers them and reads them again only once they change."
|
||||
|
||||
@@ -10078,6 +10225,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T2945218010"] = "Data source: {0}"
|
||||
-- Embedding provider: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T300213237"] = "Embedding provider: {0}"
|
||||
|
||||
-- Not added to the index
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3013971506"] = "Not added to the index"
|
||||
|
||||
-- Failed files: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T309404893"] = "Failed files: {0}"
|
||||
|
||||
@@ -10099,15 +10249,27 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3483179115"] = "Mail {0} of {1} i
|
||||
-- Skipped mails: {0}.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3488200549"] = "Skipped mails: {0}."
|
||||
|
||||
-- Manage the data sources
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T357393405"] = "Manage the data sources"
|
||||
|
||||
-- {0} files ({1})
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3628102488"] = "{0} files ({1})"
|
||||
|
||||
-- No local data source has been queued for embedding yet.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3774205531"] = "No local data source has been queued for embedding yet."
|
||||
|
||||
-- Change the settings of the mailbox
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3788376715"] = "Change the settings of the mailbox"
|
||||
|
||||
-- Files without an extension ({0})
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3799572475"] = "Files without an extension ({0})"
|
||||
|
||||
-- Actions
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3865031940"] = "Actions"
|
||||
|
||||
-- These file types and folders were found in the folder of the data source, but its file patterns or its list of excluded files and folders leave them out. They are intentionally excluded and do not affect the indexing status. Excluded folders are not searched at all.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T4007318423"] = "These file types and folders were found in the folder of the data source, but its file patterns or its list of excluded files and folders leave them out. They are intentionally excluded and do not affect the indexing status. Excluded folders are not searched at all."
|
||||
|
||||
-- Remove them from the index
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T419343388"] = "Remove them from the index"
|
||||
|
||||
@@ -10117,6 +10279,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T4205079539"] = "Not synced comple
|
||||
-- Current mail: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T4242653147"] = "Current mail: {0}"
|
||||
|
||||
-- Skipped files: {0}. Open a group below to see why and what you can do.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T4287145754"] = "Skipped files: {0}. Open a group below to see why and what you can do."
|
||||
|
||||
-- Skipped until the file changes
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T542386347"] = "Skipped until the file changes"
|
||||
|
||||
@@ -12112,6 +12277,18 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T599774443"] = "The
|
||||
-- policy files
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T632340680"] = "policy files"
|
||||
|
||||
-- Selectors such as :text: cannot be excluded. Please use file name patterns such as *.min.js or folder names such as bin/.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXCLUSIONS::T405437626"] = "Selectors such as :text: cannot be excluded. Please use file name patterns such as *.min.js or folder names such as bin/."
|
||||
|
||||
-- One of the excluded files or folders contains an invalid character.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXCLUSIONS::T594151138"] = "One of the excluded files or folders contains an invalid character."
|
||||
|
||||
-- Please write excluded folders as a name without a path, ending with a slash, e.g., node_modules/ or bin/. Such an entry excludes every folder of that name.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXCLUSIONS::T81428473"] = "Please write excluded folders as a name without a path, ending with a slash, e.g., node_modules/ or bin/. Such an entry excludes every folder of that name."
|
||||
|
||||
-- Please use only single asterisks as wildcards, e.g., *.min.js or cmake-build-*/.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXCLUSIONS::T930019122"] = "Please use only single asterisks as wildcards, e.g., *.min.js or cmake-build-*/."
|
||||
|
||||
-- OpenDocument Text (.odt), e.g. LibreOffice
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXPORTFORMATEXTENSIONS::T1612025407"] = "OpenDocument Text (.odt), e.g. LibreOffice"
|
||||
|
||||
@@ -12307,6 +12484,24 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXTRACTIONRESULTEXTENSIONS::T594894810"] =
|
||||
-- The file '{0}' is not a readable document and was not sent. It might be damaged or transferred incompletely.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXTRACTIONRESULTEXTENSIONS::T985448614"] = "The file '{0}' is not a readable document and was not sent. It might be damaged or transferred incompletely."
|
||||
|
||||
-- One of the file patterns contains an invalid character.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILENAMEPATTERNS::T1182642380"] = "One of the file patterns contains an invalid character."
|
||||
|
||||
-- Please use file name patterns without folder paths, e.g., *.txt or report-*.md.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILENAMEPATTERNS::T1476818839"] = "Please use file name patterns without folder paths, e.g., *.txt or report-*.md."
|
||||
|
||||
-- One of the file patterns is an unknown selector. Please use :documents: or :text:, or a file name pattern such as *.txt.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILENAMEPATTERNS::T2207479763"] = "One of the file patterns is an unknown selector. Please use :documents: or :text:, or a file name pattern such as *.txt."
|
||||
|
||||
-- Please provide at least one file pattern, e.g., :documents: or *.txt. Separate multiple patterns with a semicolon.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILENAMEPATTERNS::T3371062811"] = "Please provide at least one file pattern, e.g., :documents: or *.txt. Separate multiple patterns with a semicolon."
|
||||
|
||||
-- Please remove empty file patterns. Separate valid patterns with a single semicolon.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILENAMEPATTERNS::T368919579"] = "Please remove empty file patterns. Separate valid patterns with a single semicolon."
|
||||
|
||||
-- Please use only single asterisks as wildcards, e.g., *.txt or report-*.md.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILENAMEPATTERNS::T495100949"] = "Please use only single asterisks as wildcards, e.g., *.txt or report-*.md."
|
||||
|
||||
-- The server could not be reached. Please check the host and the port, and whether you need a VPN connection.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::MAIL::MAILBOXCONNECTIONFAILUREEXTENSIONS::T1314233926"] = "The server could not be reached. Please check the host and the port, and whether you need a VPN connection."
|
||||
|
||||
@@ -13063,6 +13258,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T2505088878"] = "Visual brief
|
||||
-- Shortcut
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T2547828883"] = "Shortcut"
|
||||
|
||||
-- Readable text
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T2618627384"] = "Readable text"
|
||||
|
||||
-- Media
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T3507473059"] = "Media"
|
||||
|
||||
@@ -13435,9 +13633,6 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::INDEXING::FILESOURCEINDEXER::T139364
|
||||
-- The file '{0}' changed while it was being indexed. What was indexed of it is discarded, and the file is tried again during the next run.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::INDEXING::FILESOURCEINDEXER::T1935191670"] = "The file '{0}' changed while it was being indexed. What was indexed of it is discarded, and the file is tried again during the next run."
|
||||
|
||||
-- The file '{0}' has a type AI Studio cannot index.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::INDEXING::FILESOURCEINDEXER::T2424608026"] = "The file '{0}' has a type AI Studio cannot index."
|
||||
|
||||
-- The folder '{0}' could not be opened. Please check whether you are allowed to read it.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::INDEXING::FILESOURCEINDEXER::T3230000698"] = "The folder '{0}' could not be opened. Please check whether you are allowed to read it."
|
||||
|
||||
@@ -14236,6 +14431,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T2222598306"
|
||||
-- Please select your security policy.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T2250909198"] = "Please select your security policy."
|
||||
|
||||
-- The selected file is not a supported document or readable text file.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T2728355006"] = "The selected file is not a supported document or readable text file."
|
||||
|
||||
-- Please test the connection before saving.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T285470497"] = "Please test the connection before saving."
|
||||
|
||||
|
||||
@@ -96,8 +96,8 @@ public record FileAttachment(FileAttachmentType Type, string FileName, [property
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the file attachment type based on the file extension.
|
||||
/// Uses centrally defined file type filters from <see cref="FileTypes"/>.
|
||||
/// Determines the file attachment type based on the file extension or, for readable text, on
|
||||
/// the content. Uses the centrally defined file type filters from FileTypes.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The file path to analyze.</param>
|
||||
/// <returns>The corresponding FileAttachmentType.</returns>
|
||||
@@ -115,7 +115,11 @@ public record FileAttachment(FileAttachmentType Type, string FileName, [property
|
||||
if (FileTypes.IsAllowedPath(filePath, FileTypes.AUDIO))
|
||||
return FileAttachmentType.AUDIO;
|
||||
|
||||
// Check if it's an allowed document file (PDF, Text, LaTeX, or Office):
|
||||
//
|
||||
// Check if it's an allowed document file (PDF, Text, LaTeX, or Office). Text includes
|
||||
// READABLE_TEXT, so any readable text file is accepted, whatever its name, e.g., main.tf.
|
||||
// For a file of an unknown type, this reads up to the first 8 KB:
|
||||
//
|
||||
if (FileTypes.IsAllowedPath(filePath, FileTypes.DOCUMENT))
|
||||
return FileAttachmentType.DOCUMENT;
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
@typeparam T
|
||||
@inherits ConfigurationBaseCore
|
||||
|
||||
<MudNumericField T="@T" Value="@this.Value()" ValueChanged="@this.OptionChanged" Min="@this.Min" Max="@this.Max" Adornment="Adornment.End" AdornmentText="@this.Unit" Disabled="@this.IsDisabled" Variant="Variant.Text" Margin="Margin.Dense" Class="mb-1"/>
|
||||
@@ -0,0 +1,85 @@
|
||||
using System.Numerics;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components;
|
||||
|
||||
/// <summary>
|
||||
/// A number typed into a field, for a range too wide for a slider, e.g., a size limit in megabytes.
|
||||
/// </summary>
|
||||
public partial class ConfigurationNumber<T> : ConfigurationBaseCore where T : struct, INumber<T>, IMinMaxValue<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// The smallest allowed value.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public T Min { get; set; } = T.MinValue;
|
||||
|
||||
/// <summary>
|
||||
/// The largest allowed value.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public T Max { get; set; } = T.MaxValue;
|
||||
|
||||
/// <summary>
|
||||
/// The unit to display next to the value.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Unit { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The value used for the field.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<T> Value { get; set; } = () => T.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// An action which is called when the option is changed.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Action<T> ValueUpdate { get; set; } = _ => { };
|
||||
|
||||
#region Overrides of ConfigurationBase
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool Stretch => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Variant Variant => Variant.Outlined;
|
||||
|
||||
protected override string Label => this.OptionDescription;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await this.EnsureMinMax();
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
await this.EnsureMinMax();
|
||||
await base.OnParametersSetAsync();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private async Task OptionChanged(T updatedValue)
|
||||
{
|
||||
this.ValueUpdate(updatedValue);
|
||||
await this.SettingsManager.StoreSettings();
|
||||
await this.InformAboutChange();
|
||||
}
|
||||
|
||||
private async Task EnsureMinMax()
|
||||
{
|
||||
if (this.Value() < this.Min)
|
||||
await this.OptionChanged(this.Min);
|
||||
|
||||
else if (this.Value() > this.Max)
|
||||
await this.OptionChanged(this.Max);
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
Text="@this.Text()"
|
||||
TextChanged="@this.InternalUpdate"
|
||||
Disabled="@this.IsDisabled"
|
||||
Adornment="Adornment.Start"
|
||||
Adornment="@this.IconAdornment"
|
||||
AdornmentIcon="@this.Icon"
|
||||
AdornmentColor="@this.IconColor"
|
||||
UserAttributes="@SPELLCHECK_ATTRIBUTES"
|
||||
@@ -21,13 +21,14 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
||||
@* One element, since a locked option places it next to its lock icon: *@
|
||||
<div>
|
||||
<MudTextField
|
||||
T="string"
|
||||
Text="@this.Text()"
|
||||
TextChanged="@this.InternalUpdate"
|
||||
Disabled="@this.IsDisabled"
|
||||
Adornment="Adornment.Start"
|
||||
Adornment="@this.IconAdornment"
|
||||
AdornmentIcon="@this.Icon"
|
||||
AdornmentColor="@this.IconColor"
|
||||
UserAttributes="@SPELLCHECK_ATTRIBUTES"
|
||||
@@ -37,10 +38,7 @@ else
|
||||
Immediate="@true"
|
||||
Validation="@this.Validation"
|
||||
Underline="false"
|
||||
Class="flex-grow-1"
|
||||
/>
|
||||
<MudButton Variant="Variant.Outlined" StartIcon="@Icons.Material.Filled.Restore" Disabled="@this.IsDisabled" OnClick="@this.ResetTextAsync" Class="mb-1">
|
||||
@this.ResetButtonText
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
<RestoreDefaultButton Text="@this.ResetButtonText" Disabled="@this.IsDisabled" OnClick="@this.ResetTextAsync"/>
|
||||
</div>
|
||||
}
|
||||
@@ -19,7 +19,7 @@ public partial class ConfigurationText : ConfigurationBaseCore
|
||||
public Action<string> TextUpdate { get; set; } = _ => { };
|
||||
|
||||
/// <summary>
|
||||
/// The icon to display next to the textfield.
|
||||
/// The icon to display next to the textfield, when it has a single line.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Icon { get; set; } = Icons.Material.Filled.Info;
|
||||
@@ -93,6 +93,12 @@ public partial class ConfigurationText : ConfigurationBaseCore
|
||||
|
||||
private int GetMaxLines => this.AutoGrow ? this.MaxLines : 1;
|
||||
|
||||
//
|
||||
// MudBlazor centers the icon vertically, so in a field of several lines it floats in the middle
|
||||
// of the text. Such a field goes without:
|
||||
//
|
||||
private Adornment IconAdornment => this.NumLines == 1 ? Adornment.Start : Adornment.None;
|
||||
|
||||
private void InternalUpdate(string text)
|
||||
{
|
||||
this.timer.Stop();
|
||||
|
||||
@@ -32,12 +32,17 @@ public partial class DataSourceCloudEmbeddingWarning : MSGComponentBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// Which files of a folder are sent depends on its file patterns and switches. The sentence does
|
||||
/// not repeat them: they are right next to it in the dialog, and a sentence per combination would
|
||||
/// have to change with every new setting.
|
||||
/// </remarks>
|
||||
private string GetSubjectText()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(this.SourcePath))
|
||||
return this.DataSourceType switch
|
||||
{
|
||||
DataSourceType.LOCAL_DIRECTORY => T("All files in this folder and its subfolders"),
|
||||
DataSourceType.LOCAL_DIRECTORY => T("Every file this data source selects from this folder"),
|
||||
DataSourceType.LOCAL_FILE => T("The selected file"),
|
||||
DataSourceType.MAILBOX => T("Every mail of this mailbox in the selected folder and period, together with the text of its attachments,"),
|
||||
_ => T("The selected data")
|
||||
@@ -45,7 +50,7 @@ public partial class DataSourceCloudEmbeddingWarning : MSGComponentBase
|
||||
|
||||
return this.DataSourceType switch
|
||||
{
|
||||
DataSourceType.LOCAL_DIRECTORY => string.Format(T("All files in the folder '{0}' and its subfolders"), this.SourcePath),
|
||||
DataSourceType.LOCAL_DIRECTORY => string.Format(T("Every file this data source selects from the folder '{0}'"), this.SourcePath),
|
||||
DataSourceType.LOCAL_FILE => string.Format(T("The file '{0}'"), this.SourcePath),
|
||||
DataSourceType.MAILBOX => string.Format(T("Every mail of the mailbox '{0}' in the selected folder and period, together with the text of its attachments,"), this.SourcePath),
|
||||
_ => string.Format(T("The data source '{0}'"), this.SourcePath)
|
||||
|
||||
@@ -42,9 +42,18 @@
|
||||
<RowTemplate>
|
||||
@{ var embeddingStatus = embeddingStatuses.GetValueOrDefault(context.Id); }
|
||||
<MudTd>@context.Num</MudTd>
|
||||
<MudTd Style="white-space: normal; overflow-wrap: anywhere;">@context.Name</MudTd>
|
||||
<MudTd Style="white-space: nowrap;">@context.Type.GetDisplayName()</MudTd>
|
||||
<MudTd Style="white-space: nowrap;">@this.GetEmbeddingName(context)</MudTd>
|
||||
@*
|
||||
The name gets the room the other columns leave, which in the dialog was next to nothing: it
|
||||
may break anywhere, so a single character was enough for the browser. The minimum width
|
||||
keeps it readable, and the type and the embedding wrap instead, so that the table still fits.
|
||||
The minimum sits on a div, since browsers differ in whether they honor it on a table cell.
|
||||
With "break-word" instead, a long name without spaces would push the table out of the dialog.
|
||||
*@
|
||||
<MudTd Style="white-space: normal; overflow-wrap: anywhere;">
|
||||
<div style="min-width: 10em;">@context.Name</div>
|
||||
</MudTd>
|
||||
<MudTd>@context.Type.GetDisplayName()</MudTd>
|
||||
<MudTd>@this.GetEmbeddingName(context)</MudTd>
|
||||
<MudTd>
|
||||
@if (context is IIndexedDataSource)
|
||||
{
|
||||
|
||||
@@ -83,17 +83,21 @@ public partial class DataSourceManagement : MSGComponentBase
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// Files which were skipped for good are none of the failed ones, so a data source made of
|
||||
/// scanned documents stays green: there is nothing here for the user to fix.
|
||||
/// Files which were skipped for good are none of the failed ones, so an otherwise usable data
|
||||
/// source stays green. The shared health policy warns when none of the selected documents could
|
||||
/// be indexed.
|
||||
/// </remarks>
|
||||
private static Color GetIndexingStatusColor(DataSourceEmbeddingStatus? status)
|
||||
{
|
||||
if (status is null || status.State is DataSourceEmbeddingState.IDLE or DataSourceEmbeddingState.QUEUED or DataSourceEmbeddingState.RUNNING)
|
||||
return Color.Warning;
|
||||
|
||||
return status.State is DataSourceEmbeddingState.FAILED || status.FailedDocuments > 0
|
||||
? Color.Error
|
||||
: Color.Success;
|
||||
return status.Health switch
|
||||
{
|
||||
DataSourceEmbeddingHealth.ERROR => Color.Error,
|
||||
DataSourceEmbeddingHealth.WARNING => Color.Warning,
|
||||
_ => Color.Success,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -109,11 +113,11 @@ public partial class DataSourceManagement : MSGComponentBase
|
||||
if (status is null)
|
||||
return T("Waiting for indexing status");
|
||||
|
||||
// Only files are skipped for want of readable text. A mail is read from the server, never from a file:
|
||||
if (status.PermanentlySkippedDocuments == 0 || status.DataSourceType is DataSourceType.MAILBOX)
|
||||
// Only files have enumeration exclusions. A mail is read from the server, never from a file:
|
||||
if (status.SkippedDocuments == 0 || status.DataSourceType is DataSourceType.MAILBOX)
|
||||
return status.StateLabel;
|
||||
|
||||
return $"{status.StateLabel} — {string.Format(T("{0} files were skipped because they contain no readable text. AI Studio reads them again once they change."), status.PermanentlySkippedDocuments)}";
|
||||
return $"{status.StateLabel} — {string.Format(T("Skipped files: {0}. Open Background embeddings to see why and what you can do."), status.SkippedDocuments)}";
|
||||
}
|
||||
|
||||
private string GetEmbeddingName(IDataSourceBase dataSource)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<MudStack Row="@true" Justify="Justify.FlexEnd" Class="@this.Class">
|
||||
<MudButton Variant="Variant.Text" Size="Size.Small" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Restore" Disabled="@this.Disabled" OnClick="@this.OnClick">
|
||||
@this.Text
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
@@ -0,0 +1,35 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components;
|
||||
|
||||
/// <summary>
|
||||
/// A small button below a field, which puts the default value back into that field.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The button takes a row of its own, aligned to the right. Next to the field, it took away the width
|
||||
/// the field needs, wrapped or got cut off with a longer text, and every field of a form ended at
|
||||
/// another place, depending on the length of its button.
|
||||
/// </remarks>
|
||||
public partial class RestoreDefaultButton : ComponentBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The text on the button, e.g., "Restore default".
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Text { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Puts the default value back into the field.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public EventCallback OnClick { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public bool Disabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The CSS classes of the row, e.g., for the space below it.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Class { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -43,7 +43,7 @@
|
||||
/>
|
||||
|
||||
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
|
||||
@T("Select a root directory for this data source. All data in this directory and all its subdirectories will be processed for this data source.")
|
||||
@T("Select a root directory for this data source.")
|
||||
</MudJustifiedText>
|
||||
@if (!this.CanChangeSource)
|
||||
{
|
||||
@@ -71,6 +71,33 @@
|
||||
/>
|
||||
}
|
||||
|
||||
<MudTextSwitch
|
||||
Label="@T("Include subfolders?")"
|
||||
Value="@this.dataIncludeSubdirectories"
|
||||
ValueChanged="@(value => this.dataIncludeSubdirectories = value)"
|
||||
LabelOn="@T("Yes, index files in subfolders as well")"
|
||||
LabelOff="@T("No, only index files in the selected folder")"
|
||||
/>
|
||||
|
||||
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
|
||||
@T("Select the file patterns this data source should index.")
|
||||
</MudJustifiedText>
|
||||
|
||||
<MudTextField
|
||||
T="string"
|
||||
@bind-Text="@this.dataFilePatterns"
|
||||
Label="@T("File patterns")"
|
||||
Class="mb-3"
|
||||
Immediate="@true"
|
||||
Validation="@this.dataSourceValidation.ValidateFilePatterns"
|
||||
HelperText="@T("Which files should be indexed? Separate multiple patterns with a semicolon, e.g., *.txt;*.pdf;*.docx;.gitignore. Use :documents: for every document and readable text file, :text: for readable text files only, or * for every file.")"
|
||||
Adornment="Adornment.Start"
|
||||
AdornmentIcon="@Icons.Material.Filled.FilterAlt"
|
||||
AdornmentColor="Color.Info"
|
||||
UserAttributes="@SPELLCHECK_ATTRIBUTES"
|
||||
Variant="Variant.Outlined"
|
||||
/>
|
||||
|
||||
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
|
||||
@T("In order for the AI to be able to determine the appropriate data at any time, you must choose an embedding provider.")
|
||||
</MudJustifiedText>
|
||||
@@ -121,6 +148,42 @@
|
||||
</MudButton>
|
||||
<MudDivider/>
|
||||
<MudCollapse Expanded="@this.showExpertSettings" Class="@this.GetExpertStyles">
|
||||
<MudTextSwitch
|
||||
Label="@T("Include hidden files and folders?")"
|
||||
Value="@this.dataIncludeHiddenFilesAndFolders"
|
||||
ValueChanged="@(value => this.dataIncludeHiddenFilesAndFolders = value)"
|
||||
LabelOn="@T("Yes, index hidden files and folders as well")"
|
||||
LabelOff="@T("No, ignore hidden files and folders")"
|
||||
/>
|
||||
<MudJustifiedText Typo="Typo.body2" Class="mb-3">
|
||||
@T("Hidden are files and folders whose names start with a dot, such as .git or .env, and those hidden by the operating system. A file pattern which starts with a dot, such as .gitignore, selects such files anyway.")
|
||||
</MudJustifiedText>
|
||||
@* Without an icon: in a field of several lines, it floats in the middle of the text. *@
|
||||
<MudTextField
|
||||
T="string"
|
||||
@bind-Text="@this.dataExcludePatterns"
|
||||
Label="@T("Excluded files and folders")"
|
||||
Lines="@FileExclusions.DEFAULT_LINE_COUNT"
|
||||
AutoGrow="@true"
|
||||
MaxLines="@FileExclusions.MAX_LINE_COUNT"
|
||||
Immediate="@true"
|
||||
Validation="@this.dataSourceValidation.ValidateExcludePatterns"
|
||||
HelperText="@T("These files and folders are left out, even when a file pattern selects them. Separate entries with a semicolon or a line break. End an entry with a slash to exclude every folder of that name, e.g., node_modules/. Other entries name files, e.g., *.min.js.")"
|
||||
UserAttributes="@SPELLCHECK_ATTRIBUTES"
|
||||
Variant="Variant.Outlined"
|
||||
/>
|
||||
<RestoreDefaultButton Text="@T("Restore default")" OnClick="@this.RestoreDefaultExcludePatterns" Class="mb-3"/>
|
||||
<MudNumericField
|
||||
T="int"
|
||||
@bind-Value="@this.dataMaxFileSizeMegabytes"
|
||||
Label="@T("Ignore files larger than")"
|
||||
Class="mb-3"
|
||||
Min="@FolderFileSelection.SMALLEST_MAX_FILE_SIZE_MEGABYTES"
|
||||
Immediate="@true"
|
||||
HelperText="@T("Selected files above this size are not indexed, e.g., images of virtual machines. The embedding page lists them, so you can raise the limit when needed.")"
|
||||
Variant="Variant.Outlined"
|
||||
Adornment="Adornment.End"
|
||||
AdornmentText="MB"/>
|
||||
@if (!string.IsNullOrWhiteSpace(this.dataEmbeddingId))
|
||||
{
|
||||
<MudTextField
|
||||
|
||||
@@ -62,6 +62,11 @@ public partial class DataSourceLocalDirectoryDialog : MSGComponentBase
|
||||
private bool dataUserAcknowledgedCloudEmbedding;
|
||||
private string dataEmbeddingId = string.Empty;
|
||||
private string dataPath = string.Empty;
|
||||
private string dataFilePatterns = DataSourceLocalDirectory.DEFAULT_FILE_PATTERNS;
|
||||
private string dataExcludePatterns = FileExclusions.DEFAULT_PATTERNS;
|
||||
private int dataMaxFileSizeMegabytes = FolderFileSelection.DEFAULT_MAX_FILE_SIZE_MEGABYTES;
|
||||
private bool dataIncludeSubdirectories = DataSourceLocalDirectory.DEFAULT_INCLUDE_SUBDIRECTORIES;
|
||||
private bool dataIncludeHiddenFilesAndFolders = DataSourceLocalDirectory.DEFAULT_INCLUDE_HIDDEN_FILES_AND_FOLDERS;
|
||||
private int dataMaxChunkTokenLength;
|
||||
private int dataChunkOverlapTokenLength = DataSourceEmbeddingService.DEFAULT_CHUNK_OVERLAP_TOKEN_LENGTH;
|
||||
private ushort dataMaxMatches = 10;
|
||||
@@ -113,6 +118,11 @@ public partial class DataSourceLocalDirectoryDialog : MSGComponentBase
|
||||
this.dataDescription = this.DataSource.Description;
|
||||
this.dataEmbeddingId = this.DataSource.EmbeddingId;
|
||||
this.dataPath = this.DataSource.Path;
|
||||
this.dataFilePatterns = this.DataSource.EffectiveFilePatterns;
|
||||
this.dataExcludePatterns = this.DataSource.EffectiveExcludePatterns;
|
||||
this.dataMaxFileSizeMegabytes = this.DataSource.EffectiveMaxFileSizeMegabytes;
|
||||
this.dataIncludeSubdirectories = this.DataSource.IncludeSubdirectories;
|
||||
this.dataIncludeHiddenFilesAndFolders = this.DataSource.IncludeHiddenFilesAndFolders;
|
||||
this.dataMaxChunkTokenLength = this.DataSource.MaxChunkTokenLength;
|
||||
this.dataChunkOverlapTokenLength = this.DataSource.ChunkOverlapTokenLength;
|
||||
this.dataConfidenceLevel = this.DataSource.ConfidenceLevel;
|
||||
@@ -184,6 +194,13 @@ public partial class DataSourceLocalDirectoryDialog : MSGComponentBase
|
||||
// Kept out of reach of the form while the source is locked, so a stale field cannot point an
|
||||
// indexed data source somewhere else:
|
||||
Path = this.CanChangeSource ? this.dataPath : this.DataSource.Path,
|
||||
FilePatterns = this.NormalizeFilePatterns(),
|
||||
|
||||
// Kept as typed, since the line breaks group the entries for the eye:
|
||||
ExcludePatterns = this.dataExcludePatterns,
|
||||
MaxFileSizeMegabytes = this.dataMaxFileSizeMegabytes,
|
||||
IncludeSubdirectories = this.dataIncludeSubdirectories,
|
||||
IncludeHiddenFilesAndFolders = this.dataIncludeHiddenFilesAndFolders,
|
||||
MaxChunkTokenLength = this.dataMaxChunkTokenLength,
|
||||
ChunkOverlapTokenLength = this.dataChunkOverlapTokenLength,
|
||||
ConfidenceLevel = this.dataConfidenceLevel,
|
||||
@@ -216,6 +233,10 @@ public partial class DataSourceLocalDirectoryDialog : MSGComponentBase
|
||||
|
||||
private void Cancel() => this.MudDialog.Cancel();
|
||||
|
||||
private string NormalizeFilePatterns() => FileNamePatterns.Normalize(this.dataFilePatterns);
|
||||
|
||||
private void RestoreDefaultExcludePatterns() => this.dataExcludePatterns = FileExclusions.DEFAULT_PATTERNS;
|
||||
|
||||
/// <summary>
|
||||
/// Gives the fields which are checked against each other a fresh verdict: the embedding provider
|
||||
/// and the required confidence level, and the token limits, which depend on the embedding provider.
|
||||
|
||||
@@ -10,6 +10,11 @@
|
||||
}
|
||||
|
||||
<TextInfoLine Icon="@Icons.Material.Filled.FolderOpen" Label="@T("Path")" Value="@this.DataSource.Path" ClipboardTooltipSubject="@T("this path")"/>
|
||||
<TextInfoLine Icon="@Icons.Material.Filled.AccountTree" Label="@T("Include subfolders")" Value="@(this.DataSource.IncludeSubdirectories ? T("Yes") : T("No"))" ClipboardTooltipSubject="@T("whether subfolders are included")"/>
|
||||
<TextInfoLine Icon="@Icons.Material.Filled.VisibilityOff" Label="@T("Include hidden files and folders")" Value="@(this.DataSource.IncludeHiddenFilesAndFolders ? T("Yes") : T("No"))" ClipboardTooltipSubject="@T("whether hidden files and folders are included")"/>
|
||||
<TextInfoLine Icon="@Icons.Material.Filled.FilterAlt" Label="@T("File patterns")" Value="@this.DataSource.EffectiveFilePatterns" ClipboardTooltipSubject="@T("the file patterns")"/>
|
||||
<TextInfoLines Label="@T("Excluded files and folders")" Value="@this.DataSource.EffectiveExcludePatterns" ClipboardTooltipSubject="@T("the excluded files and folders")"/>
|
||||
<TextInfoLine Icon="@Icons.Material.Filled.Straighten" Label="@T("Ignore files larger than")" Value="@FolderFileSelection.MegabytesToBytes(this.DataSource.EffectiveMaxFileSizeMegabytes).FileSize()" ClipboardTooltipSubject="@T("the size limit for files")"/>
|
||||
@if (!this.IsDirectoryAvailable)
|
||||
{
|
||||
<MudJustifiedText Typo="Typo.body1" Color="Color.Error" Class="mb-3">
|
||||
@@ -27,7 +32,7 @@
|
||||
@if (this.IsCloudEmbedding)
|
||||
{
|
||||
<MudJustifiedText Typo="Typo.body1" Color="Color.Error" Class="mb-3">
|
||||
@string.Format(T("The embedding runs in the cloud. All your data from the folder '{0}' and all its subdirectories will be sent to the cloud."), this.DataSource.Path)
|
||||
@string.Format(T("The embedding runs in the cloud. Every file this data source selects from the folder '{0}' will be sent to the cloud."), this.DataSource.Path)
|
||||
</MudJustifiedText>
|
||||
}
|
||||
else
|
||||
@@ -40,16 +45,16 @@
|
||||
<TextInfoLine Label="@T("Required provider confidence level")" Value="@this.DataSource.ConfidenceLevel.GetName()" ClipboardTooltipSubject="@T("the required provider confidence level")"/>
|
||||
<TextInfoLine Label="@T("Maximum matches per query")" Value="@this.DataSource.MaxMatches.ToString()" ClipboardTooltipSubject="@T("the maximum number of matches per query")"/>
|
||||
|
||||
<TextInfoLine Icon="@Icons.Material.Filled.SquareFoot" Label="@T("Number of files")" Value="@this.NumberFilesInDirectory" ClipboardTooltipSubject="@T("the number of files in the directory")"/>
|
||||
<TextInfoLines Label="@T("Files list")" MaxLines="14" Value="@this.directoryFilesText" ClipboardTooltipSubject="@T("the files list")"/>
|
||||
<TextInfoLine Icon="@Icons.Material.Filled.SquareFoot" Label="@T("Number of matching files")" Value="@this.NumberFilesInDirectory" ClipboardTooltipSubject="@T("the number of matching files in the directory")"/>
|
||||
<TextInfoLines Label="@T("Matching files")" MaxLines="14" Value="@this.directoryFilesText" ClipboardTooltipSubject="@T("the matching files list")"/>
|
||||
@if (this.directorySizeNumFiles > 100)
|
||||
{
|
||||
<MudJustifiedText Typo="Typo.body1" Color="Color.Warning" Class="mb-3">
|
||||
@string.Format(T("For performance reasons, only the first 100 files are shown. The directory contains {0} files in total."), this.NumberFilesInDirectory)
|
||||
@string.Format(T("For performance reasons, only the first 100 matching files are shown. The configured patterns match {0} files in total."), this.NumberFilesInDirectory)
|
||||
</MudJustifiedText>
|
||||
}
|
||||
|
||||
<TextInfoLine Icon="@Icons.Material.Filled.SquareFoot" Label="@T("Total directory size")" Value="@this.directorySizeBytes.FileSize()" ClipboardTooltipSubject="@T("the total directory size")"/>
|
||||
<TextInfoLine Icon="@Icons.Material.Filled.SquareFoot" Label="@T("Total size of matching files")" Value="@this.directorySizeBytes.FileSize()" ClipboardTooltipSubject="@T("the total size of matching files")"/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
@if (this.IsOperationInProgress)
|
||||
|
||||
@@ -32,7 +32,7 @@ public partial class DataSourceLocalDirectoryInfoDialog : MSGComponentBase
|
||||
|
||||
if (this.directoryInfo.Exists)
|
||||
{
|
||||
this.directorySizeTask = this.directoryInfo.DetermineContentSize(this.UpdateDirectorySize, this.UpdateDirectoryFiles, this.UpdateFileList, MAX_FILES_TO_SHOW, this.DirectoryOperationDone, this.cts.Token);
|
||||
this.directorySizeTask = this.directoryInfo.DetermineContentSize(this.UpdateDirectorySize, this.UpdateDirectoryFiles, this.UpdateFileList, MAX_FILES_TO_SHOW, this.DirectoryOperationDone, this.cts.Token, FolderFileSelection.Of(this.DataSource));
|
||||
this.refreshTimer.Elapsed += (_, _) => this.InvokeAsync(this.StateHasChanged);
|
||||
this.refreshTimer.Start();
|
||||
}
|
||||
|
||||
@@ -19,8 +19,11 @@
|
||||
|
||||
<MudText Typo="Typo.h6" Class="mb-3">@T("Input")</MudText>
|
||||
<ConfigurationDirectory OptionDescription="@T("Default input folder")" Disabled="@this.DefaultsDisabled" DirectoryDialogTitle="@T("Select the default input folder")" Text="@(() => this.SettingsManager.ConfigurationData.BatchProcessing.InputDirectory)" TextUpdate="@(value => this.SettingsManager.ConfigurationData.BatchProcessing.InputDirectory = value)" OptionHelp="@T("Leave empty when an input folder should be selected for every batch run.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.BatchProcessing, x => x.InputDirectory, out var meta) && meta.IsLocked"/>
|
||||
<ConfigurationText OptionDescription="@T("Default file patterns")" Disabled="@this.DefaultsDisabled" Icon="@Icons.Material.Filled.FilterAlt" Text="@(() => this.SettingsManager.ConfigurationData.BatchProcessing.FilePatterns)" TextUpdate="@(value => this.SettingsManager.ConfigurationData.BatchProcessing.FilePatterns = value)" ResetValue="@(() => DataBatchProcessing.DEFAULT_FILE_PATTERNS)" ResetButtonText="@T("Restore default patterns")" OptionHelp="@T("Separate multiple file patterns with a semicolon, e.g., *.pdf;*.docx. The standard patterns include all supported audio and video formats.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.BatchProcessing, x => x.FilePatterns, out var meta) && meta.IsLocked"/>
|
||||
<ConfigurationOption OptionDescription="@T("Include subfolders by default?")" Disabled="@this.DefaultsDisabled" LabelOn="@T("Subfolders are included")" LabelOff="@T("Only the selected folder is processed")" State="@(() => this.SettingsManager.ConfigurationData.BatchProcessing.IncludeSubdirectories)" StateUpdate="@(value => this.SettingsManager.ConfigurationData.BatchProcessing.IncludeSubdirectories = value)" IsLocked="() => ManagedConfiguration.TryGet(x => x.BatchProcessing, x => x.IncludeSubdirectories, out var meta) && meta.IsLocked"/>
|
||||
<ConfigurationOption OptionDescription="@T("Include hidden files and folders by default?")" Disabled="@this.DefaultsDisabled" LabelOn="@T("Hidden files and folders are included")" LabelOff="@T("Hidden files and folders are ignored")" State="@(() => this.SettingsManager.ConfigurationData.BatchProcessing.IncludeHiddenFilesAndFolders)" StateUpdate="@(value => this.SettingsManager.ConfigurationData.BatchProcessing.IncludeHiddenFilesAndFolders = value)" OptionHelp="@T("Hidden are files and folders whose names start with a dot, such as .git or .env, and those hidden by the operating system. A file pattern which starts with a dot, such as .gitignore, selects such files anyway.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.BatchProcessing, x => x.IncludeHiddenFilesAndFolders, out var meta) && meta.IsLocked"/>
|
||||
<ConfigurationText OptionDescription="@T("Default file patterns")" Disabled="@this.DefaultsDisabled" Icon="@Icons.Material.Filled.FilterAlt" Text="@(() => this.SettingsManager.ConfigurationData.BatchProcessing.FilePatterns)" TextUpdate="@(value => this.SettingsManager.ConfigurationData.BatchProcessing.FilePatterns = value)" ResetValue="@(() => DataBatchProcessing.DEFAULT_FILE_PATTERNS)" ResetButtonText="@T("Restore default patterns")" OptionHelp="@T("Separate multiple file patterns with a semicolon, e.g., *.pdf;*.docx. The standard patterns include all supported audio and video formats.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.BatchProcessing, x => x.FilePatterns, out var meta) && meta.IsLocked"/>
|
||||
<ConfigurationText OptionDescription="@T("Default excluded files and folders")" Disabled="@this.DefaultsDisabled" Icon="@Icons.Material.Filled.FilterAltOff" Text="@(() => this.SettingsManager.ConfigurationData.BatchProcessing.ExcludePatterns)" TextUpdate="@(value => this.SettingsManager.ConfigurationData.BatchProcessing.ExcludePatterns = value)" NumLines="@FileExclusions.DEFAULT_LINE_COUNT" MaxLines="@FileExclusions.MAX_LINE_COUNT" ResetValue="@(() => FileExclusions.DEFAULT_PATTERNS)" ResetButtonText="@T("Restore default")" OptionHelp="@T("These files and folders are left out, even when a file pattern selects them. Separate entries with a semicolon or a line break. End an entry with a slash to exclude every folder of that name, e.g., node_modules/. Other entries name files, e.g., *.min.js.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.BatchProcessing, x => x.ExcludePatterns, out var meta) && meta.IsLocked"/>
|
||||
<ConfigurationNumber T="int" OptionDescription="@T("Ignore files larger than")" Min="@FolderFileSelection.SMALLEST_MAX_FILE_SIZE_MEGABYTES" Unit="MB" Disabled="@this.DefaultsDisabled" Value="@(() => this.SettingsManager.ConfigurationData.BatchProcessing.MaxFileSizeMegabytes)" ValueUpdate="@(value => this.SettingsManager.ConfigurationData.BatchProcessing.MaxFileSizeMegabytes = value)" OptionHelp="@T("Matching files above this size are left out of a batch run, e.g., images of virtual machines.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.BatchProcessing, x => x.MaxFileSizeMegabytes, out var meta) && meta.IsLocked"/>
|
||||
|
||||
<MudText Typo="Typo.h6" Class="mb-3 mt-6">@T("Instructions")</MudText>
|
||||
<ConfigurationSelect OptionDescription="@T("Default source of the instructions")" Disabled="@this.DefaultsDisabled" SelectedValue="@(() => this.SettingsManager.ConfigurationData.BatchProcessing.PromptSource)" Data="@this.PromptSourceData" SelectionUpdate="@(value => this.SettingsManager.ConfigurationData.BatchProcessing.PromptSource = value)" IsLocked="() => ManagedConfiguration.TryGet(x => x.BatchProcessing, x => x.PromptSource, out var meta) && meta.IsLocked"/>
|
||||
|
||||
@@ -87,7 +87,7 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, ILan
|
||||
private readonly SemaphoreSlim promptInjectionDialogSemaphore = new(1, 1);
|
||||
private readonly SemaphoreSlim dataRestorePendingDialogSemaphore = new(1, 1);
|
||||
|
||||
private DataSourceEmbeddingOverview embeddingOverview = new(DataSourceEmbeddingState.COMPLETED, 0, 0, 0);
|
||||
private DataSourceEmbeddingOverview embeddingOverview = DataSourceEmbeddingOverview.Create([]);
|
||||
private IReadOnlyCollection<NavBarItem> navItems = [];
|
||||
private NavBarItem embeddingItem = new (string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, false);
|
||||
private bool showEmbeddingStatusIcon;
|
||||
@@ -505,9 +505,10 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, ILan
|
||||
var palette = this.ColorTheme.GetCurrentPalette(this.SettingsManager);
|
||||
(string icon, string lightcolor, string darkcolor) embeddingIcon = this.embeddingOverview.State switch
|
||||
{
|
||||
DataSourceEmbeddingState.FAILED => (Icons.Material.Filled.Warning, palette.Error.Value, "#d32f2f"),
|
||||
DataSourceEmbeddingState.QUEUED => (Icons.Material.Filled.Sync, palette.Info.Value, "#1976d2"),
|
||||
DataSourceEmbeddingState.RUNNING => (Icons.Material.Filled.Sync, palette.Warning.Value, "#d29f00"),
|
||||
_ when this.embeddingOverview.Health is DataSourceEmbeddingHealth.ERROR => (Icons.Material.Filled.Error, palette.Error.Value, "#d32f2f"),
|
||||
_ when this.embeddingOverview.Health is DataSourceEmbeddingHealth.WARNING => (Icons.Material.Filled.Warning, palette.Warning.Value, "#d29f00"),
|
||||
|
||||
// Nothing to do: the entry keeps the colors of its neighbors, so a permanently visible
|
||||
// icon does not draw attention while there is nothing to attend to:
|
||||
@@ -526,9 +527,13 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, ILan
|
||||
T("Embeddings are running: {0} of {1} are indexed."),
|
||||
this.embeddingOverview.IndexedDocuments.CompactCount(),
|
||||
this.embeddingOverview.TotalDocuments.CompactCount()),
|
||||
DataSourceEmbeddingState.FAILED => this.embeddingOverview.FailedDocuments > 0
|
||||
_ when this.embeddingOverview.Health is DataSourceEmbeddingHealth.ERROR => this.embeddingOverview.FailedDocuments > 0
|
||||
? string.Format(T("Some embeddings failed: {0} could not be indexed."), this.embeddingOverview.FailedDocuments.CompactCount())
|
||||
: T("Some embeddings failed and need attention."),
|
||||
_ when this.embeddingOverview.Health is DataSourceEmbeddingHealth.WARNING && this.embeddingOverview.AttentionDataSources == 1 =>
|
||||
T("One data source needs attention."),
|
||||
_ when this.embeddingOverview.Health is DataSourceEmbeddingHealth.WARNING =>
|
||||
string.Format(T("{0} data sources need attention."), this.embeddingOverview.AttentionDataSources.CompactCount()),
|
||||
|
||||
// The entry is always visible, so its resting state needs words as well. An empty tooltip
|
||||
// would leave the user guessing what the icon is there for:
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
</MudText>
|
||||
}
|
||||
|
||||
@if (status.PermanentlySkippedDocuments > 0)
|
||||
@if (status.SkippedDocuments > 0)
|
||||
{
|
||||
<MudText Typo="Typo.body2">
|
||||
@this.GetSkippedText(status)
|
||||
@@ -120,7 +120,7 @@
|
||||
hundred scanned documents were skipped otherwise buries the handful of
|
||||
files somebody has to look at.
|
||||
*@
|
||||
@if (status.Failures.Count > 0)
|
||||
@if (status.Failures.Count > 0 || status.IgnoredFiles.Count > 0)
|
||||
{
|
||||
<MudExpansionPanels MultiExpansion="@true" Class="mt-2">
|
||||
@foreach (var group in this.GetFailureGroups(status))
|
||||
@@ -189,9 +189,89 @@
|
||||
</MudStack>
|
||||
</ExpansionPanel>
|
||||
}
|
||||
@foreach (var group in this.GetIgnoredFileGroups(status))
|
||||
{
|
||||
<ExpansionPanel HeaderIcon="@group.Cause.Icon" IconColor="@group.Cause.Color" IconSize="Size.Small" HeaderTypo="Typo.subtitle1" HeaderClass="expansion-panel-header-compact" HeaderText="@GetIgnoredGroupHeader(group)">
|
||||
<MudStack Spacing="3">
|
||||
<MudText Typo="Typo.body2">@group.Cause.Description</MudText>
|
||||
<MudStack Row="@true" Wrap="Wrap.Wrap" Spacing="2" AlignItems="AlignItems.Center">
|
||||
<MudChip T="string" Size="Size.Small" Color="Color.Default" Variant="Variant.Outlined">
|
||||
@T("Not added to the index")
|
||||
</MudChip>
|
||||
@if (group.Cause.NeedsDataSourceSettings)
|
||||
{
|
||||
<MudSpacer/>
|
||||
<MudButton Variant="Variant.Text" Size="Size.Small" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Settings" OnClick="@this.OpenDataSourceSettings">
|
||||
@T("Manage the data sources")
|
||||
</MudButton>
|
||||
}
|
||||
</MudStack>
|
||||
<MudTable Items="@group.Files" Dense="@true" Hover="@true" Elevation="0" Breakpoint="Breakpoint.None" RowsPerPage="10" Class="border-dashed border rounded-lg">
|
||||
<ColGroup>
|
||||
<col/>
|
||||
<col style="width: 7em;"/>
|
||||
</ColGroup>
|
||||
<HeaderContent>
|
||||
<MudTh>@T("File")</MudTh>
|
||||
<MudTh>@T("Actions")</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd Style="white-space: normal; overflow-wrap: anywhere;">
|
||||
<MudText Typo="Typo.body2">@GetFileName(context.FilePath)</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary d-block">@context.FilePath</MudText>
|
||||
</MudTd>
|
||||
<MudTd>
|
||||
@if (CanShowInFileManager(status, context.FilePath))
|
||||
{
|
||||
<MudTooltip Text="@T("Show this file in the file browser of your system")">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.FolderOpen" Color="Color.Info" Size="Size.Small" OnClick="@(async () => await this.ShowInFileManager(context.FilePath))"/>
|
||||
</MudTooltip>
|
||||
}
|
||||
</MudTd>
|
||||
</RowTemplate>
|
||||
<PagerContent>
|
||||
<MudTablePager PageSizeOptions="@PAGE_SIZE_OPTIONS"/>
|
||||
</PagerContent>
|
||||
</MudTable>
|
||||
</MudStack>
|
||||
</ExpansionPanel>
|
||||
}
|
||||
</MudExpansionPanels>
|
||||
}
|
||||
|
||||
@if (status.FilePatternExclusions.Count > 0 || status.ExcludedFolders.Count > 0)
|
||||
{
|
||||
<MudPaper Class="pa-3 border-dashed border rounded-lg mt-2" Elevation="0">
|
||||
<MudStack Spacing="2">
|
||||
<MudStack Row="@true" AlignItems="AlignItems.Center" Spacing="2">
|
||||
<MudIcon Icon="@Icons.Material.Filled.FilterAlt" Color="Color.Default" Size="Size.Small"/>
|
||||
<MudText Typo="Typo.subtitle1">@T("Outside the selection")</MudText>
|
||||
<MudSpacer/>
|
||||
<MudButton Variant="Variant.Text" Size="Size.Small" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Settings" OnClick="@this.OpenDataSourceSettings">
|
||||
@T("Manage the data sources")
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
<MudText Typo="Typo.body2">
|
||||
@T("These file types and folders were found in the folder of the data source, but its file patterns or its list of excluded files and folders leave them out. They are intentionally excluded and do not affect the indexing status. Excluded folders are not searched at all.")
|
||||
</MudText>
|
||||
<MudStack Row="@true" Wrap="Wrap.Wrap" Spacing="1">
|
||||
@foreach (var group in status.ExcludedFolders)
|
||||
{
|
||||
<MudChip T="string" Size="Size.Small" Color="Color.Default" Variant="Variant.Outlined" Icon="@Icons.Material.Filled.FolderOff">
|
||||
@this.GetExcludedFolderGroupText(group)
|
||||
</MudChip>
|
||||
}
|
||||
@foreach (var group in status.FilePatternExclusions)
|
||||
{
|
||||
<MudChip T="string" Size="Size.Small" Color="Color.Default" Variant="Variant.Outlined">
|
||||
@this.GetFilePatternExclusionGroupText(group)
|
||||
</MudChip>
|
||||
}
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
}
|
||||
|
||||
@*
|
||||
Shown next to the list, not instead of it: the list says which files failed,
|
||||
while this is the one sentence about the data source as a whole. Hiding it
|
||||
|
||||
@@ -50,7 +50,7 @@ public partial class Embeddings : MSGComponentBase
|
||||
/// </remarks>
|
||||
private int TotalIndexedDocuments => this.Statuses.Sum(status => status.IndexedDocuments);
|
||||
|
||||
private int TotalPendingDocuments => this.Statuses.Sum(status => Math.Max(0, status.TotalDocuments - status.IndexedDocuments - status.FailedDocuments - status.PermanentlySkippedDocuments));
|
||||
private int TotalPendingDocuments => this.Statuses.Sum(status => Math.Max(0, status.TotalDocuments - status.IndexedDocuments - status.FailedDocuments - status.SkippedDocuments));
|
||||
|
||||
private int TotalFailedDocuments => this.Statuses.Sum(status => status.FailedDocuments);
|
||||
|
||||
@@ -147,7 +147,8 @@ public partial class Embeddings : MSGComponentBase
|
||||
/// data source at once.
|
||||
/// </remarks>
|
||||
private static bool IsWorthOpening(DataSourceEmbeddingStatus status) =>
|
||||
status.State is DataSourceEmbeddingState.RUNNING or DataSourceEmbeddingState.QUEUED or DataSourceEmbeddingState.FAILED || status.FailedDocuments > 0;
|
||||
status.State is DataSourceEmbeddingState.RUNNING or DataSourceEmbeddingState.QUEUED or DataSourceEmbeddingState.FAILED
|
||||
|| status.Health is not DataSourceEmbeddingHealth.HEALTHY;
|
||||
|
||||
/// <remarks>
|
||||
/// MudBlazor keeps track of which panel is open on its own, so this only records the decision.
|
||||
@@ -210,7 +211,7 @@ public partial class Embeddings : MSGComponentBase
|
||||
// that: they are behind us in the folder, and leaving them out would let the number fall
|
||||
// behind the file whose name is shown right next to it.
|
||||
//
|
||||
var currentNumber = this.FormatNumber(Math.Min(status.TotalDocuments, status.IndexedDocuments + status.PermanentlySkippedDocuments + status.FailedDocuments + 1));
|
||||
var currentNumber = this.FormatNumber(Math.Min(status.TotalDocuments, status.IndexedDocuments + status.SkippedDocuments + status.FailedDocuments + 1));
|
||||
var total = this.FormatNumber(status.TotalDocuments);
|
||||
if (isMailbox)
|
||||
{
|
||||
@@ -229,7 +230,7 @@ public partial class Embeddings : MSGComponentBase
|
||||
|
||||
private string GetSkippedText(DataSourceEmbeddingStatus status) => IsMailbox(status)
|
||||
? string.Format(T("Skipped mails: {0}."), this.FormatNumber(status.PermanentlySkippedDocuments))
|
||||
: string.Format(T("Skipped files: {0}. AI Studio reads them again once they change."), this.FormatNumber(status.PermanentlySkippedDocuments));
|
||||
: string.Format(T("Skipped files: {0}. Open a group below to see why and what you can do."), this.FormatNumber(status.SkippedDocuments));
|
||||
|
||||
private string GetFailedText(DataSourceEmbeddingStatus status) => IsMailbox(status)
|
||||
? string.Format(T("Failed mails: {0}"), this.FormatNumber(status.FailedDocuments))
|
||||
@@ -255,10 +256,13 @@ public partial class Embeddings : MSGComponentBase
|
||||
{
|
||||
DataSourceEmbeddingState.RUNNING => Color.Warning,
|
||||
DataSourceEmbeddingState.QUEUED => Color.Info,
|
||||
DataSourceEmbeddingState.FAILED => Color.Error,
|
||||
DataSourceEmbeddingState.COMPLETED when status.FailedDocuments > 0 => Color.Warning,
|
||||
DataSourceEmbeddingState.COMPLETED => Color.Success,
|
||||
_ => Color.Default,
|
||||
_ => status.Health switch
|
||||
{
|
||||
DataSourceEmbeddingHealth.ERROR => Color.Error,
|
||||
DataSourceEmbeddingHealth.WARNING => Color.Warning,
|
||||
DataSourceEmbeddingHealth.HEALTHY => Color.Success,
|
||||
_ => Color.Default,
|
||||
},
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -272,6 +276,10 @@ public partial class Embeddings : MSGComponentBase
|
||||
|
||||
private sealed record FailureGroup(FailureCause Cause, string EmbeddingProviderName, IReadOnlyList<DataSourceEmbeddingFailure> Failures);
|
||||
|
||||
private sealed record IgnoredFileCause(int Priority, string Title, string Description, string Icon, Color Color, bool NeedsDataSourceSettings);
|
||||
|
||||
private sealed record IgnoredFileGroup(IgnoredFileCause Cause, IReadOnlyList<DataSourceEmbeddingIgnoredFile> Files);
|
||||
|
||||
/// <summary>
|
||||
/// Puts the failures of a data source into one group per cause, the most pressing one first.
|
||||
/// </summary>
|
||||
@@ -318,6 +326,60 @@ public partial class Embeddings : MSGComponentBase
|
||||
|
||||
private static string GetGroupHeader(FailureGroup group) => $"{group.Cause.Title} ({group.Failures.Count})";
|
||||
|
||||
private IReadOnlyList<IgnoredFileGroup> GetIgnoredFileGroups(DataSourceEmbeddingStatus status) => status.IgnoredFiles
|
||||
.GroupBy(file => this.GetIgnoredFileCause(status, file))
|
||||
.Select(group => new IgnoredFileGroup(group.Key, group.OrderBy(file => file.FilePath, StringComparer.OrdinalIgnoreCase).ToList()))
|
||||
.OrderBy(group => group.Cause.Priority)
|
||||
.ThenByDescending(group => group.Files.Count)
|
||||
.ThenBy(group => group.Cause.Title, StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
private IgnoredFileCause GetIgnoredFileCause(DataSourceEmbeddingStatus status, DataSourceEmbeddingIgnoredFile file) => file.Reason switch
|
||||
{
|
||||
DataSourceEmbeddingIgnoreReason.TOO_LARGE => new IgnoredFileCause(
|
||||
0,
|
||||
T("Too large"),
|
||||
string.Format(T("These files match the data source patterns, but they are larger than its limit of {0}. You can raise the limit in the expert settings of the data source."), this.GetMaxFileSizeText(status)),
|
||||
Icons.Material.Filled.Straighten,
|
||||
Color.Warning,
|
||||
true),
|
||||
DataSourceEmbeddingIgnoreReason.MEDIA_NOT_SUPPORTED => new IgnoredFileCause(
|
||||
1,
|
||||
FileTypes.MEDIA.FilterName,
|
||||
T("These image, audio, or video files match the data source patterns, but they cannot currently be added to the index."),
|
||||
Icons.Material.Filled.PermMedia,
|
||||
Color.Default,
|
||||
false),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(file.Reason), file.Reason, null),
|
||||
};
|
||||
|
||||
/// <remarks>
|
||||
/// Read from the settings rather than carried by the status: the user who raised the limit
|
||||
/// right away reads the new one, and the next run, which the change starts, settles the list.
|
||||
/// </remarks>
|
||||
private string GetMaxFileSizeText(DataSourceEmbeddingStatus status)
|
||||
{
|
||||
var maxFileSizeMegabytes = this.SettingsManager.ConfigurationData.DataSources
|
||||
.OfType<DataSourceLocalDirectory>()
|
||||
.Where(dataSource => dataSource.Id == status.DataSourceId)
|
||||
.Select(dataSource => dataSource.EffectiveMaxFileSizeMegabytes)
|
||||
.DefaultIfEmpty(FolderFileSelection.DEFAULT_MAX_FILE_SIZE_MEGABYTES)
|
||||
.First();
|
||||
|
||||
return FolderFileSelection.MegabytesToBytes(maxFileSizeMegabytes).FileSize();
|
||||
}
|
||||
|
||||
private static string GetIgnoredGroupHeader(IgnoredFileGroup group) => $"{group.Cause.Title} ({group.Files.Count})";
|
||||
|
||||
private string GetFilePatternExclusionGroupText(DataSourceEmbeddingFilePatternGroup group) => string.IsNullOrWhiteSpace(group.FileType)
|
||||
? string.Format(T("Files without an extension ({0})"), this.FormatNumber(group.FileCount))
|
||||
: string.Format(T("{0} files ({1})"), group.FileType, this.FormatNumber(group.FileCount));
|
||||
|
||||
/// <remarks>
|
||||
/// Written the way the exclusion list names folders, so the entry which caught a folder is easy to find.
|
||||
/// </remarks>
|
||||
private string GetExcludedFolderGroupText(DataSourceEmbeddingExcludedFolderGroup group) => $"{group.FolderName}{FileExclusions.FOLDER_SUFFIX} ({this.FormatNumber(group.FolderCount)})";
|
||||
|
||||
private static string GetFileName(string filePath)
|
||||
{
|
||||
var fileName = Path.GetFileName(filePath);
|
||||
@@ -333,6 +395,8 @@ public partial class Embeddings : MSGComponentBase
|
||||
/// </remarks>
|
||||
private static bool CanShowInFileManager(DataSourceEmbeddingStatus status, DataSourceEmbeddingFailure failure) => !IsMailbox(status) && !string.IsNullOrWhiteSpace(failure.DocumentKey) && Path.IsPathRooted(failure.DocumentKey);
|
||||
|
||||
private static bool CanShowInFileManager(DataSourceEmbeddingStatus status, string filePath) => !IsMailbox(status) && !string.IsNullOrWhiteSpace(filePath) && Path.IsPathRooted(filePath);
|
||||
|
||||
/// <summary>
|
||||
/// How a failed mail is called in the list: by its subject, which is all the user knows it by.
|
||||
/// </summary>
|
||||
@@ -350,12 +414,14 @@ public partial class Embeddings : MSGComponentBase
|
||||
/// file has to be opened, replaced, or run through an OCR. This is the same way out the log
|
||||
/// viewer offers for the log files.
|
||||
/// </remarks>
|
||||
private async Task ShowInFileManager(DataSourceEmbeddingFailure failure)
|
||||
private Task ShowInFileManager(DataSourceEmbeddingFailure failure) => this.ShowInFileManager(failure.DocumentKey);
|
||||
|
||||
private async Task ShowInFileManager(string filePath)
|
||||
{
|
||||
OpenPathResponse response;
|
||||
try
|
||||
{
|
||||
response = await this.RustService.TryOpenPathInRuntimeFileManager(failure.DocumentKey);
|
||||
response = await this.RustService.TryOpenPathInRuntimeFileManager(filePath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -608,10 +608,21 @@ CONFIG["SETTINGS"] = {}
|
||||
-- CONFIG["SETTINGS"]["DataBatchProcessing.InputDirectory"] = ""
|
||||
-- CONFIG["SETTINGS"]["DataBatchProcessing.OutputDirectory"] = ""
|
||||
--
|
||||
-- Configure the default file patterns and whether subfolders are included.
|
||||
-- Configure the default file patterns and whether subfolders as well as hidden files and folders are included.
|
||||
-- Separate multiple patterns with semicolons.
|
||||
-- CONFIG["SETTINGS"]["DataBatchProcessing.FilePatterns"] = "*.pdf;*.docx;*.pptx;*.xlsx;*.md;*.txt;*.mp3;*.wav;*.wave;*.aac;*.flac;*.ogg;*.opus;*.m4a;*.m4b;*.wma;*.alac;*.aif;*.aiff;*.caf;*.mp4;*.m4v;*.avi;*.mkv;*.mov;*.wmv;*.flv;*.webm"
|
||||
-- CONFIG["SETTINGS"]["DataBatchProcessing.IncludeSubdirectories"] = false
|
||||
-- CONFIG["SETTINGS"]["DataBatchProcessing.IncludeHiddenFilesAndFolders"] = false
|
||||
--
|
||||
-- Configure the files and folders which are left out, even when a file pattern selects them.
|
||||
-- Separate entries with semicolons or line breaks. An entry which ends with a slash excludes every
|
||||
-- folder of that name; every other entry is a file name pattern. An empty string excludes nothing
|
||||
-- beyond the metadata of operating systems, which is always left out. The default is:
|
||||
-- CONFIG["SETTINGS"]["DataBatchProcessing.ExcludePatterns"] = "node_modules/; bower_components/; Pods/; venv/; env/; __pycache__/; bin/; obj/; Debug/; Release/; target/; build/; dist/; DerivedData/; cmake-build-*/; TestResults/; htmlcov/; *.vmwarevm/; *.pvm/; *.utm/; package-lock.json; yarn.lock; pnpm-lock.yaml; packages.lock.json; Cargo.lock; poetry.lock; Pipfile.lock; composer.lock; Gemfile.lock; go.sum; *.min.js; *.min.css; *.js.map; *.css.map; *tokenizer.json; *.exe; *.dll; *.so; *.dylib; *.pdb; *.db; *.db3; *.db-*; *.sqlite; *.sqlite3; *.sqlite-*; *.vmdk; *.vdi; *.vhd; *.vhdx; *.qcow2; *.hdd; *.hds; *.iso; *.dmg; *.img"
|
||||
--
|
||||
-- Configure the size limit in megabytes. Larger files are left out of a batch run. The value must
|
||||
-- be at least 1; the default is 1024, i.e., 1 GB.
|
||||
-- CONFIG["SETTINGS"]["DataBatchProcessing.MaxFileSizeMegabytes"] = 1024
|
||||
--
|
||||
-- Configure the default instruction source.
|
||||
-- Allowed values are: FREE_PROMPT, FILE_IMPORT, POLICY
|
||||
@@ -657,6 +668,9 @@ CONFIG["SETTINGS"] = {}
|
||||
-- CONFIG["SETTINGS"]["DataBatchProcessing.OutputDirectory.AllowUserOverride"] = true
|
||||
-- CONFIG["SETTINGS"]["DataBatchProcessing.FilePatterns.AllowUserOverride"] = true
|
||||
-- CONFIG["SETTINGS"]["DataBatchProcessing.IncludeSubdirectories.AllowUserOverride"] = true
|
||||
-- CONFIG["SETTINGS"]["DataBatchProcessing.IncludeHiddenFilesAndFolders.AllowUserOverride"] = true
|
||||
-- CONFIG["SETTINGS"]["DataBatchProcessing.ExcludePatterns.AllowUserOverride"] = true
|
||||
-- CONFIG["SETTINGS"]["DataBatchProcessing.MaxFileSizeMegabytes.AllowUserOverride"] = true
|
||||
-- CONFIG["SETTINGS"]["DataBatchProcessing.PromptSource.AllowUserOverride"] = true
|
||||
-- CONFIG["SETTINGS"]["DataBatchProcessing.FreePrompt.AllowUserOverride"] = true
|
||||
-- CONFIG["SETTINGS"]["DataBatchProcessing.PromptFilePath.AllowUserOverride"] = true
|
||||
|
||||
+284
-86
@@ -348,6 +348,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::ASSISTANTBASE::T83711157"] = "Ergebnis ko
|
||||
-- The transcription provider returned an empty transcript.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1080540822"] = "Der Anbieter für Transkriptionen hat eine leere Transkription zurückgegeben."
|
||||
|
||||
-- Hide Expert Settings
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1108876344"] = "Experten-Einstellungen ausblenden"
|
||||
|
||||
-- We always write a semicolon-separated log named log.csv, which lists every document with its processing time, the model, the status, and the details of any error. When you start another run on the same output folder, we ask you whether to continue that run: documents which failed or are missing in the log are then processed again. When no output folder is selected, everything is written to the subfolder 'ai-results' within the input folder.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1124333059"] = "Wir schreiben stets ein durch Semikolons getrenntes Protokoll namens „log.csv“. Es enthält jedes Dokument mit seiner Verarbeitungszeit, dem Modell, dem Status und den Details zu möglichen Fehlern. Wenn Sie einen weiteren Durchlauf mit demselben Ausgabeordner starten, fragen wir Sie, ob Sie diesen Durchlauf fortsetzen möchten: Dokumente, deren Verarbeitung fehlgeschlagen ist oder die im Protokoll fehlen, werden dann erneut verarbeitet. Wenn kein Ausgabeordner ausgewählt ist, wird alles im Unterordner „ai-results“ innerhalb des Eingabeordners gespeichert."
|
||||
|
||||
@@ -363,12 +366,6 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- The results table contains one row per document, starting with the file name. Here you can name the column that holds the AI answer, e.g., Summary. When left empty, we use 'Result'.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1164512104"] = "Die Ergebnistabelle enthält eine Zeile pro Dokument, beginnend mit dem Dateinamen. Hier können Sie die Spalte benennen, welche die Antwort der KI enthält, z. B. Zusammenfassung. Wenn Sie das Feld leer lassen, verwenden wir 'Ergebnis'."
|
||||
|
||||
-- One of the file patterns contains an invalid character.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1182642380"] = "Eines der Dateimuster enthält ein ungültiges Zeichen."
|
||||
|
||||
-- Please use only single asterisks as wildcards, e.g., *.pdf or report-*.docx.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1187528282"] = "Bitte verwenden Sie nur einzelne Sternchen als Platzhalter, z. B. *.pdf oder report-*.docx."
|
||||
|
||||
-- Supported audio and video files are transcribed automatically without an additional dialog. Each transcript is stored next to its media file as '<media-file>.transcript.md' and reused when an interrupted run is continued.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T120341322"] = "Unterstützte Audio- und Videodateien werden ohne zusätzlichen Dialog automatisch transkribiert. Jedes Transkript wird neben der zugehörigen Mediendatei als „<Mediendatei>.transcript.md“ gespeichert und bei der Fortsetzung eines unterbrochenen Durchlaufs wiederverwendet."
|
||||
|
||||
@@ -381,6 +378,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Batch Processing Assistant
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T132410578"] = "Assistent für die Stapelverarbeitung"
|
||||
|
||||
-- Every matching file in the selected folder is larger than {0}. Raise the size limit to process them.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1335222997"] = "Alle passenden Dateien im ausgewählten Ordner sind größer als {0}. Erhöhen Sie das Größenlimit, um sie zu verarbeiten."
|
||||
|
||||
-- These instructions are applied to every single document of the batch run.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1339979506"] = "Diese Anweisungen werden auf jedes einzelne Dokument des Stapellaufs angewendet."
|
||||
|
||||
@@ -402,9 +402,6 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Please select the file which contains your instructions.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1462027716"] = "Bitte wählen Sie die Datei aus, die Ihre Anweisungen enthält."
|
||||
|
||||
-- Which files should be processed? Separate multiple patterns with a semicolon, e.g., *.pdf;*.docx
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1482642245"] = "Welche Dateien sollen verarbeitet werden? Trennen Sie mehrere Dateiendungen mit einem Semikolon, z. B. *.pdf;*.docx"
|
||||
|
||||
-- blocked
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1516072627"] = "blockiert"
|
||||
|
||||
@@ -417,6 +414,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Select the output folder
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1598970341"] = "Wählen Sie den Ausgabeordner aus"
|
||||
|
||||
-- Hidden are files and folders whose names start with a dot, such as .git or .env, and those hidden by the operating system. A file pattern which starts with a dot, such as .gitignore, selects such files anyway.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1624717965"] = "Als versteckt gelten Dateien und Ordner, deren Namen mit einem Punkt beginnen, z. B. .git oder .env, sowie solche, die das Betriebssystem als versteckt kennzeichnet. Ein Dateimuster, das mit einem Punkt beginnt, z. B. .gitignore, wählt solche Dateien trotzdem aus."
|
||||
|
||||
-- The configured default policy no longer exists. Please select another document analysis policy.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T169666151"] = "Das konfigurierte Standardregelwerk existiert nicht mehr. Bitte wählen Sie ein anderes Regelwerk für die Dokumentenanalyse aus."
|
||||
|
||||
@@ -450,9 +450,6 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- The configured instructions file is empty.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T216725576"] = "Die konfigurierte Anweisungsdatei ist leer."
|
||||
|
||||
-- Please provide at least one file pattern, e.g., *.pdf. Separate multiple patterns with a semicolon.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2179775338"] = "Bitte geben Sie mindestens eine Dateiendung an, z. B. *.pdf. Trennen Sie mehrere Dateiendungen mit einem Semikolon."
|
||||
|
||||
-- Model
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2189814010"] = "Modell"
|
||||
|
||||
@@ -471,6 +468,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Was not able to create the output folder: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2290092642"] = "Der Ausgabeordner konnte nicht erstellt werden: {0}"
|
||||
|
||||
-- Yes, process hidden files and folders as well
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2295617720"] = "Ja, auch versteckte Dateien und Ordner verarbeiten"
|
||||
|
||||
-- The AI answer was empty.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T230354366"] = "Die Antwort der KI war leer."
|
||||
|
||||
@@ -525,6 +525,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Before the next file starts, AI Studio waits for a random number of whole seconds from this interval. The minimum is always 6 seconds and the maximum is 300 seconds (5 minutes). Restored files and the end of a run do not add another pause.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2742154256"] = "Bevor die nächste Datei gestartet wird, wartet AI Studio eine zufällige Anzahl ganzer Sekunden aus diesem Intervall. Das Minimum beträgt immer 6 Sekunden, das Maximum 300 Sekunden (5 Minuten). Wiederhergestellte Dateien und das Ende eines Durchlaufs führen nicht zu einer weiteren Pause."
|
||||
|
||||
-- Excluded files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T286958948"] = "Ausgeschlossene Dateien und Ordner"
|
||||
|
||||
-- Please enter exactly one punctuation or symbol character. Letters, numbers, spaces, quotation marks, and line breaks cannot be used as CSV separators.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2908365499"] = "Bitte geben Sie genau ein Satz- oder Sonderzeichen ein. Buchstaben, Zahlen, Leerzeichen, Anführungszeichen und Zeilenumbrüche können nicht als CSV-Trennzeichen verwendet werden."
|
||||
|
||||
@@ -549,24 +552,36 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- The content of the selected file is used as the instructions for every single document of the batch run.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T332380551"] = "Der Inhalt der ausgewählten Datei wird als Anweisung für jedes einzelne Dokument des Stapellaufs verwendet."
|
||||
|
||||
-- Ignore files larger than
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3353866230"] = "Dateien ignorieren, die größer sind als"
|
||||
|
||||
-- Show Expert Settings
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3361153305"] = "Experten-Einstellungen anzeigen"
|
||||
|
||||
-- Header of the result column (optional)
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T340994102"] = "Überschrift der Ergebnisspalte (optional)"
|
||||
|
||||
-- Processing pace
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3428873429"] = "Verarbeitungsgeschwindigkeit"
|
||||
|
||||
-- Which files should be processed? Separate multiple patterns with a semicolon, e.g., *.pdf;*.docx. Use :documents: for every document and readable text file, :text: for readable text files only, or * for every file.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3436936162"] = "Welche Dateien sollen verarbeitet werden? Trennen Sie mehrere Muster durch ein Semikolon, z. B. *.pdf;*.docx. Verwenden Sie :documents: für alle Dokumente und lesbaren Textdateien, :text: nur für lesbare Textdateien oder * für alle Dateien."
|
||||
|
||||
-- The file name of the CSV results table. We add the ending .csv when it is missing. When left empty, we use 'batch-results.csv'.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3439247329"] = "Der Dateiname der CSV-Ergebnistabelle. Die Endung .csv wird ergänzt, falls sie fehlt. Wenn Sie das Feld leer lassen, wird 'batch-results.csv' verwendet."
|
||||
|
||||
-- Document analysis policy
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3510564924"] = "Regelwerk für die Dokumentenanalyse"
|
||||
|
||||
-- Matching files above this size are left out, e.g., images of virtual machines.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3579292542"] = "Passende Dateien über dieser Größe werden ausgelassen, z. B. Abbilder virtueller Maschinen."
|
||||
|
||||
-- No, ignore hidden files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3584816527"] = "Nein, versteckte Dateien und Ordner ignorieren"
|
||||
|
||||
-- {0} of {1} files processed
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3648144402"] = "{0} von {1} Dateien verarbeitet"
|
||||
|
||||
-- Please remove empty file patterns. Separate valid patterns with a single semicolon.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T368919579"] = "Bitte entfernen Sie leere Dateimuster. Trennen Sie gültige Muster durch ein einzelnes Semikolon."
|
||||
|
||||
-- Was not able to store the transcript next to the media file: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3691287653"] = "Das Transkript konnte nicht neben der Mediendatei gespeichert werden: {0}"
|
||||
|
||||
@@ -588,6 +603,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Was not able to write '{0}'. Please make sure that the file is not opened in another application. The results of this run are incomplete on disk. The message is: '{1}'
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3899869356"] = "'{0}' konnte nicht geschrieben werden. Bitte stellen Sie sicher, dass die Datei nicht in einem anderen Programm geöffnet ist. Die Ergebnisse dieses Laufs sind auf der Festplatte unvollständig. Die Meldung lautet: '{1}'"
|
||||
|
||||
-- These files and folders are left out, even when a file pattern selects them. Separate entries with a semicolon or a line break. End an entry with a slash to exclude every folder of that name, e.g., node_modules/. Other entries name files, e.g., *.min.js.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3934601817"] = "Diese Dateien und Ordner werden auch dann ausgeschlossen, wenn ein Dateimuster auf sie zutrifft. Trennen Sie die Einträge durch ein Semikolon oder einen Zeilenumbruch. Ein Eintrag mit einem Schrägstrich am Ende schließt alle Ordner mit diesem Namen aus, z. B. node_modules/. Alle anderen Einträge beziehen sich auf Dateien, z. B. *.min.js."
|
||||
|
||||
-- Select the file with your instructions
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3943995624"] = "Datei mit Ihren Anweisungen auswählen"
|
||||
|
||||
@@ -612,6 +630,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Was not able to extract any text from this file.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T4175885324"] = "Aus dieser Datei konnte kein Text extrahiert werden."
|
||||
|
||||
-- {0} matching files were left out because they are larger than {1}.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T4184365620"] = "{0} passende Dateien wurden ausgelassen, da sie größer als {1} sind."
|
||||
|
||||
-- Column separator
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T423947932"] = "Spaltentrennzeichen"
|
||||
|
||||
@@ -636,9 +657,6 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Start batch processing
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T50133258"] = "Stapelverarbeitung starten"
|
||||
|
||||
-- Please use file name patterns without folder paths, e.g., *.pdf or report-*.docx.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T515934256"] = "Bitte verwenden Sie Dateinamensmuster ohne Ordnerpfade, z. B. *.pdf oder bericht-*.docx."
|
||||
|
||||
-- Was not able to read the results table of the previous run. Its completed documents cannot be restored and will be processed again.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T544244392"] = "Die Ergebnistabelle des vorherigen Durchlaufs konnte nicht gelesen werden. Die bereits abgeschlossenen Dokumente können nicht wiederhergestellt werden und werden erneut verarbeitet."
|
||||
|
||||
@@ -660,6 +678,12 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- A separate output folder is excluded from document discovery. This includes the default 'ai-results' folder, so results from an earlier run are not processed again. If the input folder itself is used for output, known batch result files are excluded instead.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T822136905"] = "Ein separater Ausgabeordner wird bei der Dokumentensuche ausgeschlossen. Dazu gehört der Standardordner „ai-results“, damit Ergebnisse eines früheren Durchlaufs nicht erneut verarbeitet werden. Wenn der Eingabeordner selbst als Ausgabe verwendet wird, werden stattdessen bekannte Batch-Ergebnisdateien ausgeschlossen."
|
||||
|
||||
-- Include hidden files and folders?
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T85084423"] = "Versteckte Dateien und Ordner einbeziehen?"
|
||||
|
||||
-- Restore default
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T913168756"] = "Standard wiederherstellen"
|
||||
|
||||
-- The AI may use these tools while working on each document. Every tool has to meet the confidence requirements of the selected provider, so a tool may stay unavailable even when it is selected here.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T967206794"] = "Die KI kann diese Werkzeuge bei der Arbeit an jedem Dokument verwenden. Jedes Werkzeug muss die Vertrauensanforderungen des ausgewählten Anbieters erfüllen. Daher kann ein Werkzeug trotz Auswahl hier weiterhin nicht verfügbar sein."
|
||||
|
||||
@@ -723,7 +747,7 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BIASDAY::BIASOFTHEDAYASSISTANT::T34899469
|
||||
-- Custom target language
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BIASDAY::BIASOFTHEDAYASSISTANT::T3848935911"] = "Benutzerdefinierte Zielsprache"
|
||||
|
||||
-- Learn about a different cognitive bias every day. You can also ask the LLM your questions. The idea behind "Bias of the Day" is based on work by Buster Benson, John Manoogian III, and Brian Rene Morrissette. Buster Benson grouped the biases, and the original texts come from Wikipedia. Brian Rene Morrissette condensed them into a shorter version. Finally, John Manoogian III created the original poster based on Benson's work and Morrissette's texts. Thorsten Sommer compared all texts for integration into AI Studio with the current Wikipedia versions, updated them, and added source references. The idea of learning about one bias each day based on John's poster comes from Drew Nelson.
|
||||
-- Learn about a different cognitive bias every day. You can also ask the LLM your questions. The idea behind "Bias of the Day" is based on work by Buster Benson, John Manoogian III, and Brian Rene Morrissette. Buster Benson grouped the biases, and the original texts come from Wikipedia. Brian Rene Morrissette condensed them into a shorter version. Finally, John Manoogian III created the original poster based on Benson's work and Morrissette's texts. Thorsten Sommer compared all texts for integration into AI Studio with the current Wikipedia versions, updated them, and added source references. The idea of learning about one bias each day based on John's poster comes from Drew Nelson.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BIASDAY::BIASOFTHEDAYASSISTANT::T3882885376"] = "Lerne jeden Tag einen neuen kognitiven Bias kennen. Sie können dem LLM auch eigenen Fragen stellen. Die Idee hinter „Bias des Tages” basiert auf der Arbeit von Buster Benson, John Manoogian III und Brian Rene Morrissette. Buster Benson hat die Biases gruppiert, und die Originaltexte stammen aus der Wikipedia. Brian Rene Morrissette hat sie in einer kürzeren Version zusammengefasst. Schließlich hat John Manoogian III auf Grundlage von Bensons Arbeit und den Texten von Morrissette das Original-Poster erstellt. Thorsten Sommer hat alle Texte für die Integration in AI Studio mit den aktuellen Wikipedia-Versionen verglichen, sie aktualisiert und Quellenangaben hinzugefügt. Die Idee, jeden Tag einen Bias anhand von Johns Poster kennenzulernen, stammt von Drew Nelson."
|
||||
|
||||
-- Please provide a custom language.
|
||||
@@ -1500,7 +1524,7 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::ERI::ASSISTANTERI::T218617347"] = "Für I
|
||||
-- You can specify more than one embedding method. This can be useful when you want to use different embeddings for different queries or data types. For example, one embedding for texts, another for images, and a third for videos, etc.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::ERI::ASSISTANTERI::T2202387805"] = "Sie können mehr als eine Einbettungsmethode angeben. Das ist nützlich, wenn Sie unterschiedliche Einbettungen für verschiedene Abfragen oder Datentypen verwenden möchten. Zum Beispiel eine Einbettung für Texte, eine andere für Bilder und eine dritte für Videos usw."
|
||||
|
||||
-- Operating system on which your ERI server will run
|
||||
-- Operating system on which your ERI will run
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::ERI::ASSISTANTERI::T2205711729"] = "Betriebssystem, auf dem ihr ERI-Server ausgeführt wird"
|
||||
|
||||
-- You can integrate additional libraries. Perhaps you want to evaluate the prompts in advance using a machine learning method or analyze them with a text mining approach? Or maybe you want to preprocess images in the prompts? For such advanced scenarios, you can specify which libraries you want to use here. It's best to describe which library you want to integrate for which purpose. This way, the LLM that writes the ERI server for you can try to use these libraries effectively. This should result in less rework being necessary. If you don't know the necessary libraries, you can instead attempt to describe the intended use. The LLM can then attempt to choose suitable libraries. However, hallucinations can occur, and fictional libraries might be selected.
|
||||
@@ -2631,7 +2655,7 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::TEXTSUMMARIZER::ASSISTANTTEXTSUMMARIZER::
|
||||
-- Text Summarizer
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::TEXTSUMMARIZER::ASSISTANTTEXTSUMMARIZER::T1907192403"] = "Texte zusammenfassen"
|
||||
|
||||
-- Create a summary of my text.
|
||||
-- Create a summary of my text
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::TEXTSUMMARIZER::ASSISTANTTEXTSUMMARIZER::T2013275370"] = "Erstelle eine Zusammenfassung meines Textes."
|
||||
|
||||
-- Target language
|
||||
@@ -3675,13 +3699,13 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3662116565"] = "Profilän
|
||||
-- Data source changes are locked while a response is running. Your current selection is shown below and applies again from the next message once the run is finished.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3682097866"] = "Änderungen an den Datenquellen sind gesperrt, solange eine Antwort generiert wird. Ihre aktuelle Auswahl wird unten angezeigt und gilt ab der nächsten Nachricht wieder, sobald der Vorgang abgeschlossen ist."
|
||||
|
||||
-- Start new chat in workspace "{0}"
|
||||
-- Start new chat in workspace '{0}'
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3928697643"] = "Neuen Chat im Arbeitsbereich '{0}' starten"
|
||||
|
||||
-- {0} of {1} tokens
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3996190985"] = "{0} von {1} Token"
|
||||
|
||||
-- New disappearing chat
|
||||
-- Start temporary chat
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T4113970938"] = "Neuen selbstlöschenden Chat starten"
|
||||
|
||||
-- Heading
|
||||
@@ -4026,9 +4050,15 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T2594880
|
||||
-- The file '{0}'
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T2794508936"] = "Die Datei „{0}“"
|
||||
|
||||
-- Every file this data source selects from this folder
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T3414038542"] = "Jede Datei, die diese Datenquelle aus diesem Ordner auswählt"
|
||||
|
||||
-- Warning: The selected embedding provider is not self-hosted. Creating embeddings can cost money and may need to run multiple times, for example after errors or file changes. {0} will be sent to an external third party. MindWork AI Studio has no control over what that third party does with the data after it is sent.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T3457494593"] = "Warnung: Der ausgewählte Einbettungsanbieter ist nicht selbst gehostet. Das Erstellen von Einbettungen kann Geld kosten und muss möglicherweise mehrfach erfolgen, zum Beispiel nach Fehlern oder Dateiänderungen. {0} wird an einen externen Dritten gesendet. MindWork AI Studio hat keine Kontrolle darüber, was dieser Dritte mit den Daten nach dem Versand macht."
|
||||
|
||||
-- Every file this data source selects from the folder '{0}'
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T3515150437"] = "Jede Datei, die diese Datenquelle aus dem Ordner „{0}“ auswählt"
|
||||
|
||||
-- I confirm that I have read and understood the above
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T3683380716"] = "Ich bestätige, dass ich das oben Genannte gelesen und verstanden habe"
|
||||
|
||||
@@ -4038,12 +4068,6 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T3793916
|
||||
-- The selected file
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T3999057817"] = "Die ausgewählte Datei"
|
||||
|
||||
-- All files in the folder '{0}' and its subfolders
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T661754597"] = "Alle Dateien im Ordner „{0}“ und seinen Unterordnern"
|
||||
|
||||
-- All files in this folder and its subfolders
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T916879200"] = "Alle Dateien in diesem Ordner und seinen Unterordnern"
|
||||
|
||||
-- AI Studio is backing up or restoring the indexes of your data sources right now. Please try again once that is done.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1006756723"] = "AI Studio sichert gerade die Indexe Ihrer Datenquellen oder stellt sie wieder her. Bitte versuchen Sie es erneut, sobald der Vorgang abgeschlossen ist."
|
||||
|
||||
@@ -4080,9 +4104,6 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1652430727"] = "Ex
|
||||
-- Local File
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1687345358"] = "Lokale Datei"
|
||||
|
||||
-- {0} files were skipped because they contain no readable text. AI Studio reads them again once they change.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T169247705"] = "{0} Dateien wurden übersprungen, weil sie keinen lesbaren Text enthalten. AI Studio liest sie erneut ein, sobald sie sich ändern."
|
||||
|
||||
-- Delete Data Source
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1849107431"] = "Datenquelle löschen"
|
||||
|
||||
@@ -4119,6 +4140,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2771708618"] = "Di
|
||||
-- Embedding
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2838542994"] = "Einbettung"
|
||||
|
||||
-- Skipped files: {0}. Open Background embeddings to see why and what you can do.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2887502801"] = "Übersprungene Dateien: {0}. Öffnen Sie „Einbettungen im Hintergrund“, um zu sehen, warum und was Sie tun können."
|
||||
|
||||
-- Indexed
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2906901514"] = "Indexiert"
|
||||
|
||||
@@ -4497,7 +4521,7 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::MOTIVATION::T1986314327"] = "Demokratisie
|
||||
-- While exploring available solutions, I found a desktop application called Anything LLM. Unfortunately, it fell short of meeting my specific requirements and lacked the user interface design I envisioned. For macOS, there were several apps similar to what I had in mind, but they were all commercial solutions shrouded in uncertainty. The developers' identities and the origins of these apps were unclear, raising significant security concerns. Reports from users about stolen API keys and unwanted charges only amplified my reservations.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::MOTIVATION::T3552777197"] = "Während ich nach passenden Lösungen suchte, stieß ich auf eine Desktop-Anwendung namens Anything LLM. Leider konnte sie meine spezifischen Anforderungen nicht erfüllen und entsprach auch nicht dem Benutzeroberflächendesign, das ich mir vorgestellt hatte. Für macOS gab es zwar mehrere Apps, die meiner Vorstellung ähnelten, aber sie waren allesamt kostenpflichtige Lösungen mit unklarer Herkunft. Die Identität der Entwickler und die Ursprünge dieser Apps waren nicht ersichtlich, was erhebliche Sicherheitsbedenken hervorrief. Berichte von Nutzern über gestohlene API-Schlüssel und unerwünschte Abbuchungen verstärkten meine Bedenken zusätzlich."
|
||||
|
||||
-- We also want to contribute to the democratization of AI. MindWork AI Studio runs even on low-cost hardware, including computers around 100 € such as Raspberry Pi. This makes the app and its full feature set accessible to people and families with limited budgets. You can start with local LLMs for your first steps or use affordable cloud models. MindWork AI Studio itself is available free of charge.
|
||||
-- We also want to contribute to the democratization of AI. MindWork AI Studio runs even on low-cost hardware, including computers around 100 EUR such as Raspberry Pi. This makes the app and its full feature set accessible to people and families with limited budgets. You can start with local LLMs for your first steps or use affordable cloud models. MindWork AI Studio itself is available free of charge.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::MOTIVATION::T3672974243"] = "Wir möchten auch zur Demokratisierung von KI beitragen. MindWork AI Studio läuft selbst auf kostengünstiger Hardware, einschließlich Computern für rund 100 € wie dem Raspberry Pi. Dadurch sind die App und ihr voller Funktionsumfang auch für Menschen und Familien mit begrenztem Budget zugänglich. Für Ihre ersten Schritte können Sie mit lokalen LLMs beginnen oder günstige Cloud-Modelle nutzen. MindWork AI Studio selbst ist kostenlos erhältlich."
|
||||
|
||||
-- Relying on web services like ChatGPT was not a sustainable solution for me. I needed an AI that could also access files directly on my device, a functionality web services inherently lack due to security and privacy constraints. Although I could have scripted something in Python to meet my needs, this approach was too cumbersome for daily use. More importantly, I wanted to develop a solution that anyone could use without needing any programming knowledge.
|
||||
@@ -4842,7 +4866,7 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAGENTCONTENTCLEANE
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAGENTCONTENTCLEANER::T1299550589"] = "Anwendungsfall: Dieser Agent wird verwendet, um Textinhalte zu bereinigen. Er extrahiert den Hauptinhalt, entfernt Werbung und andere irrelevante Elemente und versucht, relative Links in absolute Links umzuwandeln, damit diese verwendet werden können."
|
||||
|
||||
-- Agent: Text Content Cleaner
|
||||
-- Agent: Text Content Cleaner Options
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAGENTCONTENTCLEANER::T3517268866"] = "Agent: Inhaltsbereinigung"
|
||||
|
||||
-- No options are preselected
|
||||
@@ -4860,7 +4884,7 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAGENTDATASOURCESEL
|
||||
-- Use Case: this agent is used to select the appropriate data sources for the current prompt.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAGENTDATASOURCESELECTION::T2208143316"] = "Anwendungsfall: Dieser Assistent wird verwendet, um die passenden Datenquellen für die aktuelle Eingabe auszuwählen."
|
||||
|
||||
-- Agent: Data Source Selection
|
||||
-- Agent: Data Source Selection Options
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAGENTDATASOURCESELECTION::T2258031949"] = "Agent: Wahl der Datenquellen"
|
||||
|
||||
-- No options are preselected
|
||||
@@ -4905,7 +4929,7 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAGENTRETRIEVALCONT
|
||||
-- Options are preselected
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAGENTRETRIEVALCONTEXTVALIDATION::T3875604319"] = "Optionen sind vorausgewählt"
|
||||
|
||||
-- Agent: Retrieval Context Validation
|
||||
-- Agent: Retrieval Context Validation Options
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAGENTRETRIEVALCONTEXTVALIDATION::T928989804"] = "Agent: Validierung der Abruf-Kontexte"
|
||||
|
||||
-- No validation is performed
|
||||
@@ -5463,7 +5487,7 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T40
|
||||
-- Configured Transcription Providers
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T4210863523"] = "Konfigurierte Anbieter für Transkriptionen"
|
||||
|
||||
-- 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.
|
||||
-- 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"] = "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.
|
||||
@@ -5622,7 +5646,7 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::VISION::T1986314327"] = "Demokratisierung
|
||||
-- Whatever your job or task is, MindWork AI Studio aims to meet your needs: whether you're a project manager, scientist, artist, author, software developer, or game developer.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::VISION::T2144737937"] = "Was auch immer Ihr Beruf oder Ihre Aufgabe ist, MindWork AI Studio möchte Ihre Bedürfnisse erfüllen: Egal, ob Sie Projektmanager, Wissenschaftler, Künstler, Autor, Softwareentwickler oder Spieleentwickler sind."
|
||||
|
||||
-- We want to contribute to the democratization of AI. MindWork AI Studio runs even on low-cost hardware, including computers around 100 € such as Raspberry Pi. This makes the app and its full feature set accessible to people and families with limited budgets. You can start with local LLMs or use affordable cloud models. MindWork AI Studio itself is available free of charge.
|
||||
-- We want to contribute to the democratization of AI. MindWork AI Studio runs even on low-cost hardware, including computers around 100 EUR such as Raspberry Pi. This makes the app and its full feature set accessible to people and families with limited budgets. You can start with local LLMs or use affordable cloud models. MindWork AI Studio itself is available free of charge.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::VISION::T2201645589"] = "Wir möchten zur Demokratisierung von KI beitragen. MindWork AI Studio läuft sogar auf kostengünstiger Hardware, einschließlich Computern für etwa 100 € wie dem Raspberry Pi. Dadurch werden die App und ihr voller Funktionsumfang auch für Menschen und Familien mit begrenztem Budget zugänglich. Sie können mit lokalen LLMs starten oder günstige Cloud-Modelle nutzen. MindWork AI Studio selbst ist kostenlos erhältlich."
|
||||
|
||||
-- You can connect your email inboxes with AI Studio. The AI will read your emails and notify you of important events. You'll also be able to access knowledge from your emails in your chats.
|
||||
@@ -6675,8 +6699,8 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1136409150"
|
||||
-- Default tokenizer
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1220918127"] = "Standard-Tokenizer"
|
||||
|
||||
-- Select a root directory for this data source. All data in this directory and all its subdirectories will be processed for this data source.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1265737624"] = "Wählen Sie ein Stammverzeichnis für diese Datenquelle aus. Alle Daten in diesem Verzeichnis und in allen Unterverzeichnissen werden für diese Datenquelle verarbeitet."
|
||||
-- Selected files above this size are not indexed, e.g., images of virtual machines. The embedding page lists them, so you can raise the limit when needed.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1311820297"] = "Ausgewählte Dateien über dieser Größe werden nicht indexiert, z. B. Abbilder virtueller Maschinen. Die Seite „Einbettungen im Hintergrund“ listet sie auf, sodass Sie das Größenlimit bei Bedarf erhöhen können."
|
||||
|
||||
-- Selected base directory for this data source
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1312296210"] = "Ausgewähltes Stammverzeichnis für diese Datenquelle"
|
||||
@@ -6684,9 +6708,18 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1312296210"
|
||||
-- No embedding selected
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1359179968"] = "Keine Einbettung ausgewählt"
|
||||
|
||||
-- Select a root directory for this data source.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1400580807"] = "Wählen Sie ein Stammverzeichnis für diese Datenquelle aus."
|
||||
|
||||
-- No, only index files in the selected folder
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1490813458"] = "Nein, nur Dateien im ausgewählten Ordner indexieren"
|
||||
|
||||
-- Number of tokens repeated at the start of the next chunk. The default overlap is {0} tokens.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1588814044"] = "Anzahl der Token, die am Anfang des nächsten Blocks wiederholt werden. Die Standardüberlappung beträgt {0} Token."
|
||||
|
||||
-- Hidden are files and folders whose names start with a dot, such as .git or .env, and those hidden by the operating system. A file pattern which starts with a dot, such as .gitignore, selects such files anyway.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1624717965"] = "Als versteckt gelten Dateien und Ordner, deren Namen mit einem Punkt beginnen, z. B. .git oder .env, sowie solche, die das Betriebssystem als versteckt kennzeichnet. Ein Dateimuster, das mit einem Punkt beginnt, z. B. .gitignore, wählt solche Dateien trotzdem aus."
|
||||
|
||||
-- Tokenizer
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1696723386"] = "Tokenizer"
|
||||
|
||||
@@ -6702,15 +6735,24 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1827669611"
|
||||
-- Update
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1847791252"] = "Aktualisieren"
|
||||
|
||||
-- Include subfolders?
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2086334687"] = "Unterordner einbeziehen?"
|
||||
|
||||
-- The overlap must be smaller than the effective token limit.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2101951526"] = "Die Überlappung muss kleiner sein als das effektive Token-Limit."
|
||||
|
||||
-- Select the file patterns this data source should index.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2244471011"] = "Legen Sie mit Dateimustern fest, welche Dateien diese Datenquelle indexiert."
|
||||
|
||||
-- Required provider confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T236253137"] = "Erforderliches Vertrauensniveau des Anbieters"
|
||||
|
||||
-- Please enter a token limit of at least 1.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2406580478"] = "Bitte geben Sie ein Token-Limit von mindestens 1 ein."
|
||||
|
||||
-- File patterns
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2460883298"] = "Dateimuster"
|
||||
|
||||
-- Add
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2646845972"] = "Hinzufügen"
|
||||
|
||||
@@ -6723,41 +6765,83 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2814869210"
|
||||
-- Embedding
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2838542994"] = "Einbettung"
|
||||
|
||||
-- Excluded files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T286958948"] = "Ausgeschlossene Dateien und Ordner"
|
||||
|
||||
-- Token limit
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2961294165"] = "Token-Limit"
|
||||
|
||||
-- Please enter 0 or a positive overlap length.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3242265813"] = "Bitte geben Sie 0 oder eine positive Überlappungslänge ein."
|
||||
|
||||
-- Ignore files larger than
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3353866230"] = "Dateien ignorieren, die größer sind als"
|
||||
|
||||
-- For some data types, such as Office files, MindWork AI Studio requires the open-source application Pandoc.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3359366900"] = "Für einige Dateitypen, wie zum Beispiel Office-Dateien, benötigt MindWork AI Studio die Open-Source-Anwendung Pandoc."
|
||||
|
||||
-- Show Expert Settings
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3361153305"] = "Experten-Einstellungen anzeigen"
|
||||
|
||||
-- No, ignore hidden files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3584816527"] = "Nein, versteckte Dateien und Ordner ignorieren"
|
||||
|
||||
-- These files and folders are left out, even when a file pattern selects them. Separate entries with a semicolon or a line break. End an entry with a slash to exclude every folder of that name, e.g., node_modules/. Other entries name files, e.g., *.min.js.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3934601817"] = "Diese Dateien und Ordner werden auch dann ausgeschlossen, wenn ein Dateimuster auf sie zutrifft. Trennen Sie die Einträge durch ein Semikolon oder einen Zeilenumbruch. Ein Eintrag mit einem Schrägstrich am Ende schließt alle Ordner mit diesem Namen aus, z. B. node_modules/. Alle anderen Einträge beziehen sich auf Dateien, z. B. *.min.js."
|
||||
|
||||
-- In order for the AI to be able to determine the appropriate data at any time, you must choose an embedding provider.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T529871858"] = "Damit die KI jederzeit die passenden Daten ermitteln kann, müssen Sie einen Einbettungsanbieter auswählen."
|
||||
|
||||
-- Select the base directory
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T562479068"] = "Wählen Sie das Stammverzeichnis aus"
|
||||
|
||||
-- Yes, index hidden files and folders as well
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T607153623"] = "Ja, auch versteckte Dateien und Ordner indexieren"
|
||||
|
||||
-- Which files should be indexed? Separate multiple patterns with a semicolon, e.g., *.txt;*.pdf;*.docx;.gitignore. Use :documents: for every document and readable text file, :text: for readable text files only, or * for every file.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T761052435"] = "Welche Dateien sollen indexiert werden? Trennen Sie mehrere Muster durch ein Semikolon, z. B. *.txt;*.pdf;*.docx;.gitignore. Verwenden Sie :documents: für alle Dokumente und lesbaren Textdateien, :text: nur für lesbare Textdateien oder * für alle Dateien."
|
||||
|
||||
-- The data source token limit must not be larger than the embedding provider token limit ({0}).
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T787118522"] = "Das Token-Limit der Datenquelle darf nicht größer sein als das Token-Limit des Einbettungsanbieters ({0})."
|
||||
|
||||
-- Data Source Name
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T813773421"] = "Name der Datenquelle"
|
||||
|
||||
-- Include hidden files and folders?
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T85084423"] = "Versteckte Dateien und Ordner einbeziehen?"
|
||||
|
||||
-- Cancel
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T900713019"] = "Abbrechen"
|
||||
|
||||
-- Restore default
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T913168756"] = "Standard wiederherstellen"
|
||||
|
||||
-- Yes, index files in subfolders as well
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T918760813"] = "Ja, auch Dateien in Unterordnern indexieren"
|
||||
|
||||
-- Token overlap
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T981382809"] = "Token-Überlappung"
|
||||
|
||||
-- the total directory size
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1082241458"] = "die Gesamtgröße des Verzeichnisses"
|
||||
-- the number of matching files in the directory
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1087340457"] = "die Anzahl der passenden Dateien im Verzeichnis"
|
||||
|
||||
-- Total directory size
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1101400963"] = "Gesamte Verzeichnisgröße"
|
||||
-- Total size of matching files
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1109307573"] = "Gesamtgröße der passenden Dateien"
|
||||
|
||||
-- Number of matching files
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1397096827"] = "Anzahl der passenden Dateien"
|
||||
|
||||
-- For performance reasons, only the first 100 matching files are shown. The configured patterns match {0} files in total.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1430424205"] = "Aus Leistungsgründen werden nur die ersten 100 passenden Dateien angezeigt. Die eingestellten Muster treffen insgesamt auf {0} Dateien zu."
|
||||
|
||||
-- whether hidden files and folders are included
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1447415145"] = "ob versteckte Dateien und Ordner einbezogen werden"
|
||||
|
||||
-- No
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1642511898"] = "Nein"
|
||||
|
||||
-- Include subfolders
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1710166842"] = "Unterordner einbeziehen"
|
||||
|
||||
-- Data source name
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T171124909"] = "Name der Datenquellen"
|
||||
@@ -6765,27 +6849,39 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1711249
|
||||
-- Description
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1725856265"] = "Beschreibung"
|
||||
|
||||
-- the number of files in the directory
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1795263412"] = "die Anzahl der Dateien im Verzeichnis"
|
||||
|
||||
-- The embedding runs locally or in your organization. Your data is not sent to the cloud.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1950544032"] = "Die Einbettung läuft lokal oder in ihrer Organisation. Ihre Daten werden nicht in die Cloud gesendet."
|
||||
|
||||
-- the files list
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2072700997"] = "Die Dateiliste"
|
||||
-- the file patterns
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2013714981"] = "die Dateimuster"
|
||||
|
||||
-- The embedding runs in the cloud. Every file this data source selects from the folder '{0}' will be sent to the cloud.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2139422620"] = "Das Einbetten erfolgt in der Cloud. Jede Datei, die diese Datenquelle aus dem Ordner „{0}“ auswählt, wird in die Cloud gesendet."
|
||||
|
||||
-- whether subfolders are included
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2333573949"] = "ob Unterordner einbezogen werden"
|
||||
|
||||
-- Required provider confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T236253137"] = "Erforderliches Vertrauensniveau des Anbieters"
|
||||
|
||||
-- File patterns
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2460883298"] = "Dateimuster"
|
||||
|
||||
-- the maximum number of matches per query
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2479753122"] = "die maximale Anzahl an Treffern pro Abfrage"
|
||||
|
||||
-- the total size of matching files
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2515807708"] = "die Gesamtgröße der passenden Dateien"
|
||||
|
||||
-- the description
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2658359966"] = "Die Beschreibung"
|
||||
|
||||
-- the data source name
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2717738728"] = "den Namen der Datenquelle"
|
||||
|
||||
-- Excluded files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T286958948"] = "Ausgeschlossene Dateien und Ordner"
|
||||
|
||||
-- The directory chosen for the data source does not exist anymore. Please edit the data source and correct the path.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2875614207"] = "Das für die Datenquelle gewählte Verzeichnis existiert nicht mehr. Bitte bearbeiten Sie die Datenquelle und korrigieren Sie den Pfad."
|
||||
|
||||
@@ -6798,26 +6894,35 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2937209
|
||||
-- this path
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2944855252"] = "diesen Pfad"
|
||||
|
||||
-- Yes
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3013883440"] = "Ja"
|
||||
|
||||
-- the size limit for files
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3081730094"] = "das Größenlimit für Dateien"
|
||||
|
||||
-- Embedding name
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3153201045"] = "Name der Einbettung"
|
||||
|
||||
-- Files list
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3238813368"] = "Dateiliste"
|
||||
-- Ignore files larger than
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3353866230"] = "Dateien ignorieren, die größer sind als"
|
||||
|
||||
-- Close
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3448155331"] = "Schließen"
|
||||
|
||||
-- For performance reasons, only the first 100 files are shown. The directory contains {0} files in total.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T360238400"] = "Aus Leistungsgründen werden nur die ersten 100 Dateien angezeigt. Das Verzeichnis enthält insgesamt {0} Dateien."
|
||||
-- Matching files
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3650746465"] = "Passende Dateien"
|
||||
|
||||
-- Include hidden files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3770422018"] = "Versteckte Dateien und Ordner einbeziehen"
|
||||
|
||||
-- the matching files list
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3818527556"] = "die Liste der passenden Dateien"
|
||||
|
||||
-- Path
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3949388886"] = "Pfad"
|
||||
|
||||
-- Number of files
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T417749210"] = "Anzahl der Dateien"
|
||||
|
||||
-- The embedding runs in the cloud. All your data from the folder '{0}' and all its subdirectories will be sent to the cloud.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T443873444"] = "Das Einbetten erfolgt in der Cloud. Alle ihre Daten aus dem Ordner '{0}' und allen seinen Unterordnern werden in die Cloud gesendet."
|
||||
-- the excluded files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T4001527349"] = "die ausgeschlossenen Dateien und Ordner"
|
||||
|
||||
-- The directory chosen for the data source exists.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T445858624"] = "Das ausgewählte Verzeichnis für die Datenquelle ist vorhanden."
|
||||
@@ -7566,7 +7671,7 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PANDOCDIALOG::T4152693089"] = "Pandoc neu in
|
||||
-- Accept the terms of the GPL license and download the latest installer with the download button below. Eventually, you need to allow the download of the installer in the download window.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PANDOCDIALOG::T504404155"] = "Akzeptieren Sie die Bedingungen der GPL-Lizenz und laden Sie mit dem untenstehenden Download-Button das neueste Installationsprogramm herunter. Gegebenenfalls müssen Sie den Download des Installationsprogramms im Downloadfenster erlauben."
|
||||
|
||||
-- Pandoc is distributed under the GNU General Public License v2 (GPL). By clicking "Accept the GPL and download the archive," you agree to the terms of the GPL license. Software under GPL is free of charge and free to use.
|
||||
-- Pandoc is distributed under the GNU General Public License v2 (GPL). By clicking "Accept GPL and archive," you agree to the terms of the GPL license. Software under GPL is free of charge and free to use.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PANDOCDIALOG::T523908375"] = "Pandoc wird unter der GNU General Public License v2 (GPL) vertrieben. Wenn Sie auf „GPL akzeptieren und Archiv herunterladen“ klicken, stimmen Sie den Bedingungen der GPL-Lizenz zu. Software unter der GPL ist kostenlos und frei nutzbar."
|
||||
|
||||
-- {0} profiles
|
||||
@@ -8208,7 +8313,7 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::REVIEWATTACHMENTSDIALOG::T1746160064"] = "Hi
|
||||
-- Attached {0}.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::REVIEWATTACHMENTSDIALOG::T1839536175"] = "Angehängt: {0}."
|
||||
|
||||
-- There aren't any file attachments right now.
|
||||
-- There aren't any file attachments available right now.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::REVIEWATTACHMENTSDIALOG::T2111340711"] = "Derzeit sind keine Dateianhänge vorhanden."
|
||||
|
||||
-- You can drag more files into this window to attach them right away.
|
||||
@@ -8418,9 +8523,18 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T10
|
||||
-- Instructions
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T1221801316"] = "Anweisungen"
|
||||
|
||||
-- Include hidden files and folders by default?
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T1450016875"] = "Versteckte Dateien und Ordner standardmäßig einbeziehen?"
|
||||
|
||||
-- Matching files above this size are left out of a batch run, e.g., images of virtual machines.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T1504546559"] = "Passende Dateien über dieser Größe werden bei einem Stapelverarbeitungsdurchlauf ausgelassen, z. B. Abbilder virtueller Maschinen."
|
||||
|
||||
-- Leave empty to use the ai-results subfolder of the input folder.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T1550632323"] = "Leer lassen, um den Unterordner „ai-results“ des Eingabeordners zu verwenden."
|
||||
|
||||
-- Hidden are files and folders whose names start with a dot, such as .git or .env, and those hidden by the operating system. A file pattern which starts with a dot, such as .gitignore, selects such files anyway.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T1624717965"] = "Als versteckt gelten Dateien und Ordner, deren Namen mit einem Punkt beginnen, z. B. .git oder .env, sowie solche, die das Betriebssystem als versteckt kennzeichnet. Ein Dateimuster, das mit einem Punkt beginnt, z. B. .gitignore, wählt solche Dateien trotzdem aus."
|
||||
|
||||
-- seconds
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T1723256298"] = "Sekunden"
|
||||
|
||||
@@ -8445,12 +8559,18 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T21
|
||||
-- Default output folder
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T223484721"] = "Standard-Ausgabeordner"
|
||||
|
||||
-- Hidden files and folders are included
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T2288334048"] = "Versteckte Dateien und Ordner werden einbezogen"
|
||||
|
||||
-- The lower end of the random pause interval. AI Studio never allows less than 6 seconds.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T237774509"] = "Das untere Ende des Intervalls für die zufällige Pause. AI Studio erlaubt niemals weniger als 6 Sekunden."
|
||||
|
||||
-- A policy brings its own tools, so there is nothing to preselect here. You configure them with the policy in the Document Analysis Assistant.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T2391906382"] = "Ein Regelwerk bringt seine eigenen Werkzeuge mit, daher gibt es hier nichts vorauszuwählen. Sie konfigurieren die Werkzeuge zusammen mit dem Regelwerk im Assistenten für die Dokumentenanalyse."
|
||||
|
||||
-- Default excluded files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T2460020307"] = "Standardmäßig ausgeschlossene Dateien und Ordner"
|
||||
|
||||
-- When enabled, new batch runs start with the defaults configured below.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T2592677194"] = "Wenn aktiviert, werden neue Stapel-Durchläufe mit den unten konfigurierten Standardwerten gestartet."
|
||||
|
||||
@@ -8496,6 +8616,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T31
|
||||
-- These instructions are applied to every document of a new batch run.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T3195548336"] = "Diese Anweisungen werden auf jedes Dokument eines neuen Stapelverarbeitungsdurchlaufs angewendet."
|
||||
|
||||
-- Ignore files larger than
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T3353866230"] = "Dateien ignorieren, die größer sind als"
|
||||
|
||||
-- No batch processing options are preselected
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T3421035581"] = "Keine Optionen für die Stapelverarbeitung sind vorausgewählt."
|
||||
|
||||
@@ -8523,6 +8646,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T37
|
||||
-- Default results table name
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T3816237687"] = "Standardname der Ergebnistabelle"
|
||||
|
||||
-- These files and folders are left out, even when a file pattern selects them. Separate entries with a semicolon or a line break. End an entry with a slash to exclude every folder of that name, e.g., node_modules/. Other entries name files, e.g., *.min.js.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T3934601817"] = "Diese Dateien und Ordner werden auch dann ausgeschlossen, wenn ein Dateimuster auf sie zutrifft. Trennen Sie die Einträge durch ein Semikolon oder einen Zeilenumbruch. Ein Eintrag mit einem Schrägstrich am Ende schließt alle Ordner mit diesem Namen aus, z. B. node_modules/. Alle anderen Einträge beziehen sich auf Dateien, z. B. *.min.js."
|
||||
|
||||
-- Default Markdown instructions file
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T3967465682"] = "Standarddatei für Markdown-Anweisungen"
|
||||
|
||||
@@ -8565,6 +8691,12 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T74
|
||||
-- Leave empty when an input folder should be selected for every batch run.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T762890100"] = "Leer lassen, wenn für jeden Stapelverarbeitungsdurchlauf ein Eingabeordner ausgewählt werden soll."
|
||||
|
||||
-- Hidden files and folders are ignored
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T826400562"] = "Versteckte Dateien und Ordner werden ignoriert"
|
||||
|
||||
-- Restore default
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T913168756"] = "Standard wiederherstellen"
|
||||
|
||||
-- Preselect one of your chat templates?
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHAT::T1402022556"] = "Eine ihrer Chat-Vorlagen vorab auswählen?"
|
||||
|
||||
@@ -8634,7 +8766,7 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHAT::T492357592"] =
|
||||
-- When enabled, the latest message is shown after loading a chat. When disabled, the first (oldest) message is shown.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHAT::T582516016"] = "Wenn diese Option aktiviert ist, wird nach dem Laden eines Chats die neueste Nachricht angezeigt. Wenn sie deaktiviert ist, wird die erste (älteste) Nachricht angezeigt."
|
||||
|
||||
-- Customize your AI experience with chat templates. Whether you want to experiment with prompt engineering, simply use a custom system prompt in the standard chat interface, or create a specialized assistant, chat templates give you full control. Similar to common AI companies' playgrounds, you can define your own system prompts and leverage assistant prompts for providers that support them.
|
||||
-- Customize your AI experience with chat templates. Whether you want to experiment with prompt engineering, simply use a custom system prompt in the standard chat interface, or create a specialized assistant, our templates give you full control. Similar to common AI companies' playgrounds, you can define your own system prompts and leverage assistant prompts for providers that support them.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T1172171653"] = "Passen Sie Ihre KI-Erfahrung mit Chat-Vorlagen an. Egal, ob Sie mit Prompt-Engineering experimentieren, einfach einen eigenen System-Prompt im normalen Chat verwenden oder einen spezialisierten Assistenten erstellen möchten – mit Chat-Vorlagen haben Sie die volle Kontrolle. Ähnlich wie in den Playgrounds gängiger KI-Anbieter können Sie eigene System-Prompts festlegen und bei unterstützenden Anbietern auch Assistenten-Prompts nutzen."
|
||||
|
||||
-- Copy attachments into plugin
|
||||
@@ -9396,7 +9528,7 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGVISUALBRIEFING::T956
|
||||
-- Default audience profile
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGVISUALBRIEFING::T963676741"] = "Standard-Zielgruppenprofil"
|
||||
|
||||
-- If and when should we delete your disappearing chats?
|
||||
-- If and when should we delete your temporary chats?
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGWORKSPACES::T1014418451"] = "Sollen ihre selbstlöschenden Chats gelöscht werden, und wenn ja, wann?"
|
||||
|
||||
-- Workspace display behavior
|
||||
@@ -9756,6 +9888,9 @@ UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2148829171"] = "Einbettungen wer
|
||||
-- Plugins
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2222816203"] = "Plugins"
|
||||
|
||||
-- One data source needs attention.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2349740877"] = "Eine Datenquelle benötigt Aufmerksamkeit."
|
||||
|
||||
-- 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."
|
||||
|
||||
@@ -9774,12 +9909,15 @@ 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
|
||||
-- Writer
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2979224202"] = "Schreiben"
|
||||
|
||||
-- Embeddings are waiting to be processed.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T3439916590"] = "Einbettungen warten auf die Verarbeitung."
|
||||
|
||||
-- {0} data sources need attention.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T344098457"] = "{0} Datenquellen benötigen Aufmerksamkeit."
|
||||
|
||||
-- Show details
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T3692372066"] = "Details anzeigen"
|
||||
|
||||
@@ -10017,18 +10155,30 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1297391911"] = "Postfächer werde
|
||||
-- File {0} of {1} is being indexed: block {2}, page {3}.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1298290372"] = "Datei {0} von {1} wird indexiert: Block {2}, Seite {3}."
|
||||
|
||||
-- These image, audio, or video files match the data source patterns, but they cannot currently be added to the index.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1302021733"] = "Diese Bild-, Audio- oder Videodateien entsprechen den Mustern der Datenquelle, können derzeit jedoch nicht zum Index hinzugefügt werden."
|
||||
|
||||
-- Mail
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1399880782"] = "E-Mail"
|
||||
|
||||
-- Could not open the file location: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1455637941"] = "Der Speicherort der Datei konnte nicht geöffnet werden: {0}"
|
||||
|
||||
-- These files match the data source patterns, but they are larger than its limit of {0}. You can raise the limit in the expert settings of the data source.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1485378199"] = "Diese Dateien entsprechen den Mustern der Datenquelle, überschreiten aber ihr Größenlimit von {0}. Sie können das Größenlimit in den Experten-Einstellungen der Datenquelle erhöhen."
|
||||
|
||||
-- Outside the selection
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1512669069"] = "Außerhalb der Auswahl"
|
||||
|
||||
-- Failed: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1531389696"] = "Fehlgeschlagen: {0}"
|
||||
|
||||
-- AI Studio indexes large data sources in steps of a few minutes, so that your other data sources get their turn in between.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1545941101"] = "AI Studio indexiert große Datenquellen in Etappen von wenigen Minuten, damit zwischendurch auch Ihre anderen Datenquellen an die Reihe kommen."
|
||||
|
||||
-- Too large
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T156180350"] = "Zu groß"
|
||||
|
||||
-- Open the settings
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1582896271"] = "Einstellungen öffnen"
|
||||
|
||||
@@ -10050,9 +10200,6 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T2149927097"] = "Ihre Datenquellen
|
||||
-- Noticed
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T2367007983"] = "Zur Kenntnis genommen"
|
||||
|
||||
-- Skipped files: {0}. AI Studio reads them again once they change.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T2382275084"] = "Übersprungene Dateien: {0}. AI Studio liest sie erneut ein, sobald sie sich ändern."
|
||||
|
||||
-- AI Studio indexes local RAG data sources in the background. Finished files stay recorded so unchanged files can be skipped after a restart, while added or deleted files are detected during the next run. The same applies to documents without readable text, such as scanned pages: AI Studio remembers them and reads them again only once they change.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T2398894096"] = "AI Studio indexiert lokale RAG-Datenquellen im Hintergrund. Fertig verarbeitete Dateien bleiben gespeichert, sodass unveränderte Dateien nach einem Neustart übersprungen werden können, während hinzugefügte oder gelöschte Dateien beim nächsten Durchlauf erkannt werden. Dasselbe gilt für Dokumente ohne lesbaren Text, etwa gescannte Seiten: AI Studio merkt sie sich und liest sie erst wieder ein, sobald sie sich ändern."
|
||||
|
||||
@@ -10080,6 +10227,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T2945218010"] = "Datenquelle: {0}"
|
||||
-- Embedding provider: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T300213237"] = "Einbettungsanbieter: {0}"
|
||||
|
||||
-- Not added to the index
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3013971506"] = "Nicht zum Index hinzugefügt"
|
||||
|
||||
-- Failed files: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T309404893"] = "Fehlerhafte Dateien: {0}"
|
||||
|
||||
@@ -10101,15 +10251,27 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3483179115"] = "E-Mail {0} von {1
|
||||
-- Skipped mails: {0}.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3488200549"] = "Übersprungene E-Mails: {0}."
|
||||
|
||||
-- Manage the data sources
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T357393405"] = "Datenquellen verwalten"
|
||||
|
||||
-- {0} files ({1})
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3628102488"] = "{0} Dateien ({1})"
|
||||
|
||||
-- No local data source has been queued for embedding yet.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3774205531"] = "Es wurde noch keine lokale Datenquelle für die Einbettung in die Warteschlange aufgenommen."
|
||||
|
||||
-- Change the settings of the mailbox
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3788376715"] = "Einstellungen des Postfachs ändern"
|
||||
|
||||
-- Files without an extension ({0})
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3799572475"] = "Dateien ohne Dateiendung ({0})"
|
||||
|
||||
-- Actions
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3865031940"] = "Aktionen"
|
||||
|
||||
-- These file types and folders were found in the folder of the data source, but its file patterns or its list of excluded files and folders leave them out. They are intentionally excluded and do not affect the indexing status. Excluded folders are not searched at all.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T4007318423"] = "Diese Dateitypen und Ordner wurden im Ordner der Datenquelle gefunden, aber ihre Dateimuster oder ihre Liste ausgeschlossener Dateien und Ordner lassen sie aus. Sie fehlen absichtlich und wirken sich nicht auf den Indexierungsstatus aus. Ausgeschlossene Ordner werden gar nicht durchsucht."
|
||||
|
||||
-- Remove them from the index
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T419343388"] = "Aus dem Index entfernen"
|
||||
|
||||
@@ -10119,6 +10281,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T4205079539"] = "Noch nicht vollst
|
||||
-- Current mail: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T4242653147"] = "Aktuelle E-Mail: {0}"
|
||||
|
||||
-- Skipped files: {0}. Open a group below to see why and what you can do.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T4287145754"] = "Übersprungene Dateien: {0}. Öffnen Sie unten eine Gruppe, um zu sehen, warum und was Sie tun können."
|
||||
|
||||
-- Skipped until the file changes
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T542386347"] = "Übersprungen, bis sich die Datei ändert"
|
||||
|
||||
@@ -10158,7 +10323,7 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T1573770551"] = "Version"
|
||||
-- Assistants
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T1614176092"] = "Assistenten"
|
||||
|
||||
-- We want to contribute to the democratization of AI. MindWork AI Studio runs even on low-cost hardware, including computers around 100 € such as Raspberry Pi. This makes the app and its full feature set accessible to people and families with limited budgets. You can start with local LLMs or use affordable cloud models.
|
||||
-- We want to contribute to the democratization of AI. MindWork AI Studio runs even on low-cost hardware, including computers around 100 EUR such as Raspberry Pi. This makes the app and its full feature set accessible to people and families with limited budgets. You can start with local LLMs or use affordable cloud models.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T1628689293"] = "Wir möchten zur Demokratisierung von KI beitragen. MindWork AI Studio läuft sogar auf kostengünstiger Hardware, einschließlich Computern für etwa 100 € wie dem Raspberry Pi. Dadurch werden die App und ihr vollständiger Funktionsumfang auch für Menschen und Familien mit begrenztem Budget zugänglich. Sie können mit lokalen LLMs starten oder günstige Cloud-Modelle nutzen."
|
||||
|
||||
-- Enterprise IT
|
||||
@@ -10872,7 +11037,7 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T3342440765"] = "Ihre Organisation ha
|
||||
-- Share plugin archive
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T3355474457"] = "Plugin-Archiv teilen"
|
||||
|
||||
-- Your organization has disabled sharing plugins
|
||||
-- Your organization has disabled sharing plugins.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T3379469503"] = "Ihre Organisation hat das Teilen von Plugins deaktiviert"
|
||||
|
||||
-- Close
|
||||
@@ -11307,10 +11472,10 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1245257804
|
||||
-- Settings
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1258653480"] = "Einstellungen"
|
||||
|
||||
-- No key is sending the input; you have to click the send button
|
||||
-- No key is sending the input
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1311973034"] = "Keine Taste sendet die Eingabe; Sie müssen auf die Schaltfläche klicken, um zu senden"
|
||||
|
||||
-- Navigation never expands, no tooltips; there are only icons
|
||||
-- Navigation never expands, no tooltips
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1402851833"] = "Navigationsleiste wird nie erweitert, keine Tooltips; es werden nur Icons angezeigt"
|
||||
|
||||
-- Welcome
|
||||
@@ -11352,7 +11517,7 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2301448762
|
||||
-- Check every week
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T238099712"] = "Jede Woche prüfen"
|
||||
|
||||
-- Disappearing chats: delete chats older than 1 year
|
||||
-- Delete disappearing chats older than 1 year
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2405705561"] = "Selbstlöschende Chats: lösche Chats die älter als 1 Jahr sind"
|
||||
|
||||
-- Store chats manually
|
||||
@@ -11373,7 +11538,7 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2929332068
|
||||
-- Do not specify the language
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2960082609"] = "Sprache nicht festlegen"
|
||||
|
||||
-- Disappearing chats: delete chats older than 7 days
|
||||
-- Delete disappearing chats older than 7 days
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2975140581"] = "Selbstlöschende Chats: lösche Chats die älter als 7 Tage sind"
|
||||
|
||||
-- Always use the default chat provider for new chats
|
||||
@@ -11385,7 +11550,7 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T3061414822
|
||||
-- Check every hour
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T3137986690"] = "Jede Stunde überprüfen"
|
||||
|
||||
-- Disappearing chats: delete chats older than 180 days
|
||||
-- Delete disappearing chats older than 180 days
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T3491430707"] = "Selbstlöschende Chats: lösche Chats die älter als 180 Tage sind"
|
||||
|
||||
-- Install updates automatically
|
||||
@@ -11397,7 +11562,7 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T3587225583
|
||||
-- Disable workspaces
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T3612390107"] = "Arbeitsbereiche deaktivieren"
|
||||
|
||||
-- Toggle the sidebar: show the workspaces on demand next to the chat
|
||||
-- Toggle the sidebar: show the workspaces next to the chat when desired
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T3711207137"] = "Seitenleiste umschalten: Arbeitsbereiche bei Bedarf neben dem Chat anzeigen"
|
||||
|
||||
-- Updates disabled by your organization
|
||||
@@ -11418,16 +11583,16 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T578410699"
|
||||
-- When possible, use the LLM provider which was used for each chat in the first place
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T75376144"] = "Wenn möglich, verwende den LLM-Anbieter, der ursprünglich für jeden Chat verwendet wurde."
|
||||
|
||||
-- Disappearing chats: no automatic maintenance; old chats will never be deleted
|
||||
-- No automatic maintenance for disappearing chats; old chats will never be deleted
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T803751240"] = "Selbstlöschende Chats: keine automatische Wartung; alte Chats werden nie gelöscht"
|
||||
|
||||
-- Disappearing chats: delete chats older than 90 days
|
||||
-- Delete disappearing chats older than 90 days
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T869922627"] = "Selbstlöschende Chats: lösche Chats die älter als 90 Tage sind"
|
||||
|
||||
-- Modifier key + enter is sending the input
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T870850829"] = "Mit gedrückter Modifikatortaste (z.B. Alt oder Strg) + Enter- bzw. Eingabe-Taste wird die Eingabe gesendet"
|
||||
|
||||
-- Disappearing chats: delete chats older than 30 days
|
||||
-- Delete disappearing chats older than 30 days
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T937754037"] = "Selbstlöschende Chats: lösche Chats die älter als 30 Tage sind"
|
||||
|
||||
-- This data source can be used with any LLM provider. Your data may be sent to a cloud-based provider.
|
||||
@@ -11454,7 +11619,7 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::DATASOURCETYPEEXTENSION::T298748
|
||||
-- External ERI Server (v1)
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::DATASOURCETYPEEXTENSION::T3020093889"] = "Externer ERI-Server (v1)"
|
||||
|
||||
-- No data source
|
||||
-- None
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::DATASOURCETYPEEXTENSION::T810547195"] = "Keine Datenquelle"
|
||||
|
||||
-- Local Directory
|
||||
@@ -11463,10 +11628,10 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::DATASOURCETYPEEXTENSION::T926703
|
||||
-- Unknown option
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::LANGBEHAVIOREXTENSIONS::T3964902774"] = "Unbekannte Option"
|
||||
|
||||
-- Choose the language manually
|
||||
-- Choose the language manually.
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::LANGBEHAVIOREXTENSIONS::T3988034966"] = "Sprache manuell auswählen"
|
||||
|
||||
-- Choose the language automatically, based on your system language
|
||||
-- Choose the language automatically, based on your system language.
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::LANGBEHAVIOREXTENSIONS::T485389934"] = "Sprache automatisch anhand ihrer Systemsprache auswählen"
|
||||
|
||||
-- The last 12 months
|
||||
@@ -11652,7 +11817,7 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::AUTHMETHODSV1EXTENSIONS::T2891154022"] = "Zuga
|
||||
-- Unknown authentication method
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::AUTHMETHODSV1EXTENSIONS::T3296465240"] = "Unbekannte Authentifizierungsmethode"
|
||||
|
||||
-- No authentication
|
||||
-- None
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::AUTHMETHODSV1EXTENSIONS::T810547195"] = "Keine Authentifizierung"
|
||||
|
||||
-- Username & Password
|
||||
@@ -11796,7 +11961,7 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::CONFIDENCESCHEMESEXTENSIONS::T3016210842"] = "
|
||||
-- Trust LLM providers from Europe
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::CONFIDENCESCHEMESEXTENSIONS::T357239630"] = "LLM-Anbietern aus Europa vertrauen"
|
||||
|
||||
-- Trust only self-hosted providers
|
||||
-- Trust only local LLM providers
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::CONFIDENCESCHEMESEXTENSIONS::T3893997203"] = "Nur selbst gehosteten LLM-Anbietern vertrauen"
|
||||
|
||||
-- Trust all LLM providers
|
||||
@@ -12114,6 +12279,18 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T599774443"] = "Das
|
||||
-- policy files
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T632340680"] = "Richtliniendateien"
|
||||
|
||||
-- Selectors such as :text: cannot be excluded. Please use file name patterns such as *.min.js or folder names such as bin/.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXCLUSIONS::T405437626"] = "Selektoren wie :text: können nicht ausgeschlossen werden. Bitte verwenden Sie Dateinamensmuster wie *.min.js oder Ordnernamen wie bin/."
|
||||
|
||||
-- One of the excluded files or folders contains an invalid character.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXCLUSIONS::T594151138"] = "Einer der Einträge für ausgeschlossene Dateien und Ordner enthält ein ungültiges Zeichen."
|
||||
|
||||
-- Please write excluded folders as a name without a path, ending with a slash, e.g., node_modules/ or bin/. Such an entry excludes every folder of that name.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXCLUSIONS::T81428473"] = "Bitte geben Sie ausgeschlossene Ordner als Namen ohne Pfad und mit einem Schrägstrich am Ende an, z. B. node_modules/ oder bin/. Ein solcher Eintrag schließt alle Ordner mit diesem Namen aus."
|
||||
|
||||
-- Please use only single asterisks as wildcards, e.g., *.min.js or cmake-build-*/.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXCLUSIONS::T930019122"] = "Bitte verwenden Sie als Platzhalter nur einzelne Sternchen, z. B. *.min.js oder cmake-build-*/."
|
||||
|
||||
-- OpenDocument Text (.odt), e.g. LibreOffice
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXPORTFORMATEXTENSIONS::T1612025407"] = "OpenDocument-Text (.odt), z. B. LibreOffice"
|
||||
|
||||
@@ -12309,6 +12486,24 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXTRACTIONRESULTEXTENSIONS::T594894810"] =
|
||||
-- The file '{0}' is not a readable document and was not sent. It might be damaged or transferred incompletely.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXTRACTIONRESULTEXTENSIONS::T985448614"] = "Die Datei „{0}“ ist kein lesbares Dokument und wurde nicht gesendet. Möglicherweise ist sie beschädigt oder unvollständig übertragen worden."
|
||||
|
||||
-- One of the file patterns contains an invalid character.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILENAMEPATTERNS::T1182642380"] = "Eines der Dateimuster enthält ein ungültiges Zeichen."
|
||||
|
||||
-- Please use file name patterns without folder paths, e.g., *.txt or report-*.md.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILENAMEPATTERNS::T1476818839"] = "Bitte verwenden Sie Dateinamensmuster ohne Ordnerpfade, z. B. *.txt oder report-*.md."
|
||||
|
||||
-- One of the file patterns is an unknown selector. Please use :documents: or :text:, or a file name pattern such as *.txt.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILENAMEPATTERNS::T2207479763"] = "Eines der Dateimuster ist ein unbekannter Selektor. Bitte verwenden Sie :documents:, :text: oder ein Dateinamensmuster wie *.txt."
|
||||
|
||||
-- Please provide at least one file pattern, e.g., :documents: or *.txt. Separate multiple patterns with a semicolon.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILENAMEPATTERNS::T3371062811"] = "Bitte geben Sie mindestens ein Dateimuster an, z. B. :documents: oder *.txt. Trennen Sie mehrere Muster durch ein Semikolon."
|
||||
|
||||
-- Please remove empty file patterns. Separate valid patterns with a single semicolon.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILENAMEPATTERNS::T368919579"] = "Bitte entfernen Sie leere Dateimuster. Trennen Sie gültige Muster durch ein einzelnes Semikolon."
|
||||
|
||||
-- Please use only single asterisks as wildcards, e.g., *.txt or report-*.md.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILENAMEPATTERNS::T495100949"] = "Bitte verwenden Sie als Platzhalter nur einzelne Sternchen, z. B. *.txt oder report-*.md."
|
||||
|
||||
-- The server could not be reached. Please check the host and the port, and whether you need a VPN connection.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::MAIL::MAILBOXCONNECTIONFAILUREEXTENSIONS::T1314233926"] = "Der Server konnte nicht erreicht werden. Bitte prüfen Sie Host und Port und ob Sie eine VPN-Verbindung benötigen."
|
||||
|
||||
@@ -13011,7 +13206,7 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::RAG::DATASOURCESELECTIONPROCESSES::AGENTICSRCS
|
||||
-- This RAG process filters data sources, automatically selects appropriate sources, optionally allows manual source selection, retrieves data, and automatically validates the retrieval context.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::RAG::RAGPROCESSES::AISRCSELWITHRETCTXVAL::T3047786484"] = "Dieser RAG-Prozess filtert Datenquellen, wählt automatisch passende Quellen aus, ermöglicht optional die manuelle Auswahl von Quellen, ruft Daten ab und überprüft den Abrufkontext automatisch."
|
||||
|
||||
-- AI-based data source selection with AI retrieval context validation
|
||||
-- AI source selection with AI retrieval context validation
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::RAG::RAGPROCESSES::AISRCSELWITHRETCTXVAL::T3775725978"] = "KI-basierte Datenquellen-Auswahl mit Validierung des Abrufkontexts"
|
||||
|
||||
-- Text
|
||||
@@ -13065,6 +13260,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T2505088878"] = "Visuelles Br
|
||||
-- Shortcut
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T2547828883"] = "Verknüpfung"
|
||||
|
||||
-- Readable text
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T2618627384"] = "Lesbarer Text"
|
||||
|
||||
-- Media
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T3507473059"] = "Medien"
|
||||
|
||||
@@ -13437,9 +13635,6 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::INDEXING::FILESOURCEINDEXER::T139364
|
||||
-- The file '{0}' changed while it was being indexed. What was indexed of it is discarded, and the file is tried again during the next run.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::INDEXING::FILESOURCEINDEXER::T1935191670"] = "Die Datei „{0}“ wurde während der Indexierung geändert. Die bereits indexierten Inhalte werden verworfen, und die Datei wird beim nächsten Durchlauf erneut verarbeitet."
|
||||
|
||||
-- The file '{0}' has a type AI Studio cannot index.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::INDEXING::FILESOURCEINDEXER::T2424608026"] = "Die Datei „{0}“ hat einen Dateityp, den AI Studio nicht indexieren kann."
|
||||
|
||||
-- The folder '{0}' could not be opened. Please check whether you are allowed to read it.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::INDEXING::FILESOURCEINDEXER::T3230000698"] = "Der Ordner „{0}“ konnte nicht geöffnet werden. Bitte prüfen Sie, ob Sie ihn lesen dürfen."
|
||||
|
||||
@@ -14238,6 +14433,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T2222598306"
|
||||
-- Please select your security policy.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T2250909198"] = "Bitte wählen Sie Ihre Sicherheitsrichtlinie aus."
|
||||
|
||||
-- The selected file is not a supported document or readable text file.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T2728355006"] = "Die ausgewählte Datei ist weder ein unterstütztes Dokument noch eine lesbare Textdatei."
|
||||
|
||||
-- Please test the connection before saving.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T285470497"] = "Bitte testen Sie die Verbindung, bevor Sie speichern."
|
||||
|
||||
|
||||
+284
-86
@@ -348,6 +348,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::ASSISTANTBASE::T83711157"] = "Copy result
|
||||
-- The transcription provider returned an empty transcript.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1080540822"] = "The transcription provider returned an empty transcript."
|
||||
|
||||
-- Hide Expert Settings
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1108876344"] = "Hide Expert Settings"
|
||||
|
||||
-- We always write a semicolon-separated log named log.csv, which lists every document with its processing time, the model, the status, and the details of any error. When you start another run on the same output folder, we ask you whether to continue that run: documents which failed or are missing in the log are then processed again. When no output folder is selected, everything is written to the subfolder 'ai-results' within the input folder.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1124333059"] = "We always write a semicolon-separated log named log.csv, which lists every document with its processing time, the model, the status, and the details of any error. When you start another run on the same output folder, we ask you whether to continue that run: documents which failed or are missing in the log are then processed again. When no output folder is selected, everything is written to the subfolder 'ai-results' within the input folder."
|
||||
|
||||
@@ -363,12 +366,6 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- The results table contains one row per document, starting with the file name. Here you can name the column that holds the AI answer, e.g., Summary. When left empty, we use 'Result'.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1164512104"] = "The results table contains one row per document, starting with the file name. Here you can name the column that holds the AI answer, e.g., Summary. When left empty, we use 'Result'."
|
||||
|
||||
-- One of the file patterns contains an invalid character.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1182642380"] = "One of the file patterns contains an invalid character."
|
||||
|
||||
-- Please use only single asterisks as wildcards, e.g., *.pdf or report-*.docx.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1187528282"] = "Please use only single asterisks as wildcards, e.g., *.pdf or report-*.docx."
|
||||
|
||||
-- Supported audio and video files are transcribed automatically without an additional dialog. Each transcript is stored next to its media file as '<media-file>.transcript.md' and reused when an interrupted run is continued.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T120341322"] = "Supported audio and video files are transcribed automatically without an additional dialog. Each transcript is stored next to its media file as '<media-file>.transcript.md' and reused when an interrupted run is continued."
|
||||
|
||||
@@ -381,6 +378,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Batch Processing Assistant
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T132410578"] = "Batch Processing Assistant"
|
||||
|
||||
-- Every matching file in the selected folder is larger than {0}. Raise the size limit to process them.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1335222997"] = "Every matching file in the selected folder is larger than {0}. Raise the size limit to process them."
|
||||
|
||||
-- These instructions are applied to every single document of the batch run.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1339979506"] = "These instructions are applied to every single document of the batch run."
|
||||
|
||||
@@ -402,9 +402,6 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Please select the file which contains your instructions.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1462027716"] = "Please select the file which contains your instructions."
|
||||
|
||||
-- Which files should be processed? Separate multiple patterns with a semicolon, e.g., *.pdf;*.docx
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1482642245"] = "Which files should be processed? Separate multiple patterns with a semicolon, e.g., *.pdf;*.docx"
|
||||
|
||||
-- blocked
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1516072627"] = "blocked"
|
||||
|
||||
@@ -417,6 +414,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Select the output folder
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1598970341"] = "Select the output folder"
|
||||
|
||||
-- Hidden are files and folders whose names start with a dot, such as .git or .env, and those hidden by the operating system. A file pattern which starts with a dot, such as .gitignore, selects such files anyway.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1624717965"] = "Hidden are files and folders whose names start with a dot, such as .git or .env, and those hidden by the operating system. A file pattern which starts with a dot, such as .gitignore, selects such files anyway."
|
||||
|
||||
-- The configured default policy no longer exists. Please select another document analysis policy.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T169666151"] = "The configured default policy no longer exists. Please select another document analysis policy."
|
||||
|
||||
@@ -450,9 +450,6 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- The configured instructions file is empty.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T216725576"] = "The configured instructions file is empty."
|
||||
|
||||
-- Please provide at least one file pattern, e.g., *.pdf. Separate multiple patterns with a semicolon.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2179775338"] = "Please provide at least one file pattern, e.g., *.pdf. Separate multiple patterns with a semicolon."
|
||||
|
||||
-- Model
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2189814010"] = "Model"
|
||||
|
||||
@@ -471,6 +468,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Was not able to create the output folder: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2290092642"] = "Was not able to create the output folder: {0}"
|
||||
|
||||
-- Yes, process hidden files and folders as well
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2295617720"] = "Yes, process hidden files and folders as well"
|
||||
|
||||
-- The AI answer was empty.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T230354366"] = "The AI answer was empty."
|
||||
|
||||
@@ -525,6 +525,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Before the next file starts, AI Studio waits for a random number of whole seconds from this interval. The minimum is always 6 seconds and the maximum is 300 seconds (5 minutes). Restored files and the end of a run do not add another pause.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2742154256"] = "Before the next file starts, AI Studio waits for a random number of whole seconds from this interval. The minimum is always 6 seconds and the maximum is 300 seconds (5 minutes). Restored files and the end of a run do not add another pause."
|
||||
|
||||
-- Excluded files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T286958948"] = "Excluded files and folders"
|
||||
|
||||
-- Please enter exactly one punctuation or symbol character. Letters, numbers, spaces, quotation marks, and line breaks cannot be used as CSV separators.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2908365499"] = "Please enter exactly one punctuation or symbol character. Letters, numbers, spaces, quotation marks, and line breaks cannot be used as CSV separators."
|
||||
|
||||
@@ -549,24 +552,36 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- The content of the selected file is used as the instructions for every single document of the batch run.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T332380551"] = "The content of the selected file is used as the instructions for every single document of the batch run."
|
||||
|
||||
-- Ignore files larger than
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3353866230"] = "Ignore files larger than"
|
||||
|
||||
-- Show Expert Settings
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3361153305"] = "Show Expert Settings"
|
||||
|
||||
-- Header of the result column (optional)
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T340994102"] = "Header of the result column (optional)"
|
||||
|
||||
-- Processing pace
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3428873429"] = "Processing pace"
|
||||
|
||||
-- Which files should be processed? Separate multiple patterns with a semicolon, e.g., *.pdf;*.docx. Use :documents: for every document and readable text file, :text: for readable text files only, or * for every file.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3436936162"] = "Which files should be processed? Separate multiple patterns with a semicolon, e.g., *.pdf;*.docx. Use :documents: for every document and readable text file, :text: for readable text files only, or * for every file."
|
||||
|
||||
-- The file name of the CSV results table. We add the ending .csv when it is missing. When left empty, we use 'batch-results.csv'.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3439247329"] = "The file name of the CSV results table. We add the ending .csv when it is missing. When left empty, we use 'batch-results.csv'."
|
||||
|
||||
-- Document analysis policy
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3510564924"] = "Document analysis policy"
|
||||
|
||||
-- Matching files above this size are left out, e.g., images of virtual machines.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3579292542"] = "Matching files above this size are left out, e.g., images of virtual machines."
|
||||
|
||||
-- No, ignore hidden files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3584816527"] = "No, ignore hidden files and folders"
|
||||
|
||||
-- {0} of {1} files processed
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3648144402"] = "{0} of {1} files processed"
|
||||
|
||||
-- Please remove empty file patterns. Separate valid patterns with a single semicolon.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T368919579"] = "Please remove empty file patterns. Separate valid patterns with a single semicolon."
|
||||
|
||||
-- Was not able to store the transcript next to the media file: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3691287653"] = "Was not able to store the transcript next to the media file: {0}"
|
||||
|
||||
@@ -588,6 +603,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Was not able to write '{0}'. Please make sure that the file is not opened in another application. The results of this run are incomplete on disk. The message is: '{1}'
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3899869356"] = "Was not able to write '{0}'. Please make sure that the file is not opened in another application. The results of this run are incomplete on disk. The message is: '{1}'"
|
||||
|
||||
-- These files and folders are left out, even when a file pattern selects them. Separate entries with a semicolon or a line break. End an entry with a slash to exclude every folder of that name, e.g., node_modules/. Other entries name files, e.g., *.min.js.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3934601817"] = "These files and folders are left out, even when a file pattern selects them. Separate entries with a semicolon or a line break. End an entry with a slash to exclude every folder of that name, e.g., node_modules/. Other entries name files, e.g., *.min.js."
|
||||
|
||||
-- Select the file with your instructions
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3943995624"] = "Select the file with your instructions"
|
||||
|
||||
@@ -612,6 +630,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Was not able to extract any text from this file.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T4175885324"] = "Was not able to extract any text from this file."
|
||||
|
||||
-- {0} matching files were left out because they are larger than {1}.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T4184365620"] = "{0} matching files were left out because they are larger than {1}."
|
||||
|
||||
-- Column separator
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T423947932"] = "Column separator"
|
||||
|
||||
@@ -636,9 +657,6 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- Start batch processing
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T50133258"] = "Start batch processing"
|
||||
|
||||
-- Please use file name patterns without folder paths, e.g., *.pdf or report-*.docx.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T515934256"] = "Please use file name patterns without folder paths, e.g., *.pdf or report-*.docx."
|
||||
|
||||
-- Was not able to read the results table of the previous run. Its completed documents cannot be restored and will be processed again.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T544244392"] = "Was not able to read the results table of the previous run. Its completed documents cannot be restored and will be processed again."
|
||||
|
||||
@@ -660,6 +678,12 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING
|
||||
-- A separate output folder is excluded from document discovery. This includes the default 'ai-results' folder, so results from an earlier run are not processed again. If the input folder itself is used for output, known batch result files are excluded instead.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T822136905"] = "A separate output folder is excluded from document discovery. This includes the default 'ai-results' folder, so results from an earlier run are not processed again. If the input folder itself is used for output, known batch result files are excluded instead."
|
||||
|
||||
-- Include hidden files and folders?
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T85084423"] = "Include hidden files and folders?"
|
||||
|
||||
-- Restore default
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T913168756"] = "Restore default"
|
||||
|
||||
-- The AI may use these tools while working on each document. Every tool has to meet the confidence requirements of the selected provider, so a tool may stay unavailable even when it is selected here.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T967206794"] = "The AI may use these tools while working on each document. Every tool has to meet the confidence requirements of the selected provider, so a tool may stay unavailable even when it is selected here."
|
||||
|
||||
@@ -723,7 +747,7 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BIASDAY::BIASOFTHEDAYASSISTANT::T34899469
|
||||
-- Custom target language
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BIASDAY::BIASOFTHEDAYASSISTANT::T3848935911"] = "Custom target language"
|
||||
|
||||
-- Learn about a different cognitive bias every day. You can also ask the LLM your questions. The idea behind "Bias of the Day" is based on work by Buster Benson, John Manoogian III, and Brian Rene Morrissette. Buster Benson grouped the biases, and the original texts come from Wikipedia. Brian Rene Morrissette condensed them into a shorter version. Finally, John Manoogian III created the original poster based on Benson's work and Morrissette's texts. Thorsten Sommer compared all texts for integration into AI Studio with the current Wikipedia versions, updated them, and added source references. The idea of learning about one bias each day based on John's poster comes from Drew Nelson.
|
||||
-- Learn about a different cognitive bias every day. You can also ask the LLM your questions. The idea behind "Bias of the Day" is based on work by Buster Benson, John Manoogian III, and Brian Rene Morrissette. Buster Benson grouped the biases, and the original texts come from Wikipedia. Brian Rene Morrissette condensed them into a shorter version. Finally, John Manoogian III created the original poster based on Benson's work and Morrissette's texts. Thorsten Sommer compared all texts for integration into AI Studio with the current Wikipedia versions, updated them, and added source references. The idea of learning about one bias each day based on John's poster comes from Drew Nelson.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BIASDAY::BIASOFTHEDAYASSISTANT::T3882885376"] = "Learn about a different cognitive bias every day. You can also ask the LLM your questions. The idea behind \"Bias of the Day\" is based on work by Buster Benson, John Manoogian III, and Brian Rene Morrissette. Buster Benson grouped the biases, and the original texts come from Wikipedia. Brian Rene Morrissette condensed them into a shorter version. Finally, John Manoogian III created the original poster based on Benson's work and Morrissette's texts. Thorsten Sommer compared all texts for integration into AI Studio with the current Wikipedia versions, updated them, and added source references. The idea of learning about one bias each day based on John's poster comes from Drew Nelson."
|
||||
|
||||
-- Please provide a custom language.
|
||||
@@ -1500,7 +1524,7 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::ERI::ASSISTANTERI::T218617347"] = "For yo
|
||||
-- You can specify more than one embedding method. This can be useful when you want to use different embeddings for different queries or data types. For example, one embedding for texts, another for images, and a third for videos, etc.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::ERI::ASSISTANTERI::T2202387805"] = "You can specify more than one embedding method. This can be useful when you want to use different embeddings for different queries or data types. For example, one embedding for texts, another for images, and a third for videos, etc."
|
||||
|
||||
-- Operating system on which your ERI server will run
|
||||
-- Operating system on which your ERI will run
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::ERI::ASSISTANTERI::T2205711729"] = "Operating system on which your ERI server will run"
|
||||
|
||||
-- You can integrate additional libraries. Perhaps you want to evaluate the prompts in advance using a machine learning method or analyze them with a text mining approach? Or maybe you want to preprocess images in the prompts? For such advanced scenarios, you can specify which libraries you want to use here. It's best to describe which library you want to integrate for which purpose. This way, the LLM that writes the ERI server for you can try to use these libraries effectively. This should result in less rework being necessary. If you don't know the necessary libraries, you can instead attempt to describe the intended use. The LLM can then attempt to choose suitable libraries. However, hallucinations can occur, and fictional libraries might be selected.
|
||||
@@ -2631,7 +2655,7 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::TEXTSUMMARIZER::ASSISTANTTEXTSUMMARIZER::
|
||||
-- Text Summarizer
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::TEXTSUMMARIZER::ASSISTANTTEXTSUMMARIZER::T1907192403"] = "Text Summarizer"
|
||||
|
||||
-- Create a summary of my text.
|
||||
-- Create a summary of my text
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::TEXTSUMMARIZER::ASSISTANTTEXTSUMMARIZER::T2013275370"] = "Create a summary of my text."
|
||||
|
||||
-- Target language
|
||||
@@ -3675,13 +3699,13 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3662116565"] = "Profile c
|
||||
-- Data source changes are locked while a response is running. Your current selection is shown below and applies again from the next message once the run is finished.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3682097866"] = "Data source changes are locked while a response is running. Your current selection is shown below and applies again from the next message once the run is finished."
|
||||
|
||||
-- Start new chat in workspace "{0}"
|
||||
-- Start new chat in workspace '{0}'
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3928697643"] = "Start new chat in workspace \"{0}\""
|
||||
|
||||
-- {0} of {1} tokens
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3996190985"] = "{0} of {1} tokens"
|
||||
|
||||
-- New disappearing chat
|
||||
-- Start temporary chat
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T4113970938"] = "New disappearing chat"
|
||||
|
||||
-- Heading
|
||||
@@ -4026,9 +4050,15 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T2594880
|
||||
-- The file '{0}'
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T2794508936"] = "The file '{0}'"
|
||||
|
||||
-- Every file this data source selects from this folder
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T3414038542"] = "Every file this data source selects from this folder"
|
||||
|
||||
-- Warning: The selected embedding provider is not self-hosted. Creating embeddings can cost money and may need to run multiple times, for example after errors or file changes. {0} will be sent to an external third party. MindWork AI Studio has no control over what that third party does with the data after it is sent.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T3457494593"] = "Warning: The selected embedding provider is not self-hosted. Creating embeddings can cost money and may need to run multiple times, for example after errors or file changes. {0} will be sent to an external third party. MindWork AI Studio has no control over what that third party does with the data after it is sent."
|
||||
|
||||
-- Every file this data source selects from the folder '{0}'
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T3515150437"] = "Every file this data source selects from the folder '{0}'"
|
||||
|
||||
-- I confirm that I have read and understood the above
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T3683380716"] = "I confirm that I have read and understood the above"
|
||||
|
||||
@@ -4038,12 +4068,6 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T3793916
|
||||
-- The selected file
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T3999057817"] = "The selected file"
|
||||
|
||||
-- All files in the folder '{0}' and its subfolders
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T661754597"] = "All files in the folder '{0}' and its subfolders"
|
||||
|
||||
-- All files in this folder and its subfolders
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T916879200"] = "All files in this folder and its subfolders"
|
||||
|
||||
-- AI Studio is backing up or restoring the indexes of your data sources right now. Please try again once that is done.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1006756723"] = "AI Studio is backing up or restoring the indexes of your data sources right now. Please try again once that is done."
|
||||
|
||||
@@ -4080,9 +4104,6 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1652430727"] = "Ex
|
||||
-- Local File
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1687345358"] = "Local File"
|
||||
|
||||
-- {0} files were skipped because they contain no readable text. AI Studio reads them again once they change.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T169247705"] = "{0} files were skipped because they contain no readable text. AI Studio reads them again once they change."
|
||||
|
||||
-- Delete Data Source
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1849107431"] = "Delete Data Source"
|
||||
|
||||
@@ -4119,6 +4140,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2771708618"] = "Re
|
||||
-- Embedding
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2838542994"] = "Embedding"
|
||||
|
||||
-- Skipped files: {0}. Open Background embeddings to see why and what you can do.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2887502801"] = "Skipped files: {0}. Open Background embeddings to see why and what you can do."
|
||||
|
||||
-- Indexed
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2906901514"] = "Indexed"
|
||||
|
||||
@@ -4497,7 +4521,7 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::MOTIVATION::T1986314327"] = "Democratizat
|
||||
-- While exploring available solutions, I found a desktop application called Anything LLM. Unfortunately, it fell short of meeting my specific requirements and lacked the user interface design I envisioned. For macOS, there were several apps similar to what I had in mind, but they were all commercial solutions shrouded in uncertainty. The developers' identities and the origins of these apps were unclear, raising significant security concerns. Reports from users about stolen API keys and unwanted charges only amplified my reservations.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::MOTIVATION::T3552777197"] = "While exploring available solutions, I found a desktop application called Anything LLM. Unfortunately, it fell short of meeting my specific requirements and lacked the user interface design I envisioned. For macOS, there were several apps similar to what I had in mind, but they were all commercial solutions shrouded in uncertainty. The developers' identities and the origins of these apps were unclear, raising significant security concerns. Reports from users about stolen API keys and unwanted charges only amplified my reservations."
|
||||
|
||||
-- We also want to contribute to the democratization of AI. MindWork AI Studio runs even on low-cost hardware, including computers around 100 € such as Raspberry Pi. This makes the app and its full feature set accessible to people and families with limited budgets. You can start with local LLMs for your first steps or use affordable cloud models. MindWork AI Studio itself is available free of charge.
|
||||
-- We also want to contribute to the democratization of AI. MindWork AI Studio runs even on low-cost hardware, including computers around 100 EUR such as Raspberry Pi. This makes the app and its full feature set accessible to people and families with limited budgets. You can start with local LLMs for your first steps or use affordable cloud models. MindWork AI Studio itself is available free of charge.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::MOTIVATION::T3672974243"] = "We also want to contribute to the democratization of AI. MindWork AI Studio runs even on low-cost hardware, including computers around 100 € such as Raspberry Pi. This makes the app and its full feature set accessible to people and families with limited budgets. You can start with local LLMs for your first steps or use affordable cloud models. MindWork AI Studio itself is available free of charge."
|
||||
|
||||
-- Relying on web services like ChatGPT was not a sustainable solution for me. I needed an AI that could also access files directly on my device, a functionality web services inherently lack due to security and privacy constraints. Although I could have scripted something in Python to meet my needs, this approach was too cumbersome for daily use. More importantly, I wanted to develop a solution that anyone could use without needing any programming knowledge.
|
||||
@@ -4842,7 +4866,7 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAGENTCONTENTCLEANE
|
||||
-- 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.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAGENTCONTENTCLEANER::T1299550589"] = "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."
|
||||
|
||||
-- Agent: Text Content Cleaner
|
||||
-- Agent: Text Content Cleaner Options
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAGENTCONTENTCLEANER::T3517268866"] = "Agent: Text Content Cleaner"
|
||||
|
||||
-- No options are preselected
|
||||
@@ -4860,7 +4884,7 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAGENTDATASOURCESEL
|
||||
-- Use Case: this agent is used to select the appropriate data sources for the current prompt.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAGENTDATASOURCESELECTION::T2208143316"] = "Use Case: this agent is used to select the appropriate data sources for the current prompt."
|
||||
|
||||
-- Agent: Data Source Selection
|
||||
-- Agent: Data Source Selection Options
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAGENTDATASOURCESELECTION::T2258031949"] = "Agent: Data Source Selection"
|
||||
|
||||
-- No options are preselected
|
||||
@@ -4905,7 +4929,7 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAGENTRETRIEVALCONT
|
||||
-- Options are preselected
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAGENTRETRIEVALCONTEXTVALIDATION::T3875604319"] = "Options are preselected"
|
||||
|
||||
-- Agent: Retrieval Context Validation
|
||||
-- Agent: Retrieval Context Validation Options
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELAGENTRETRIEVALCONTEXTVALIDATION::T928989804"] = "Agent: Retrieval Context Validation"
|
||||
|
||||
-- No validation is performed
|
||||
@@ -5463,7 +5487,7 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T40
|
||||
-- Configured Transcription Providers
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T4210863523"] = "Configured Transcription Providers"
|
||||
|
||||
-- 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.
|
||||
-- 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 LLM providers' section."
|
||||
|
||||
-- This transcription provider is trusted by your organization for data source security checks.
|
||||
@@ -5622,7 +5646,7 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::VISION::T1986314327"] = "Democratization
|
||||
-- Whatever your job or task is, MindWork AI Studio aims to meet your needs: whether you're a project manager, scientist, artist, author, software developer, or game developer.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::VISION::T2144737937"] = "Whatever your job or task is, MindWork AI Studio aims to meet your needs: whether you're a project manager, scientist, artist, author, software developer, or game developer."
|
||||
|
||||
-- We want to contribute to the democratization of AI. MindWork AI Studio runs even on low-cost hardware, including computers around 100 € such as Raspberry Pi. This makes the app and its full feature set accessible to people and families with limited budgets. You can start with local LLMs or use affordable cloud models. MindWork AI Studio itself is available free of charge.
|
||||
-- We want to contribute to the democratization of AI. MindWork AI Studio runs even on low-cost hardware, including computers around 100 EUR such as Raspberry Pi. This makes the app and its full feature set accessible to people and families with limited budgets. You can start with local LLMs or use affordable cloud models. MindWork AI Studio itself is available free of charge.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::VISION::T2201645589"] = "We want to contribute to the democratization of AI. MindWork AI Studio runs even on low-cost hardware, including computers around 100 € such as Raspberry Pi. This makes the app and its full feature set accessible to people and families with limited budgets. You can start with local LLMs or use affordable cloud models. MindWork AI Studio itself is available free of charge."
|
||||
|
||||
-- You can connect your email inboxes with AI Studio. The AI will read your emails and notify you of important events. You'll also be able to access knowledge from your emails in your chats.
|
||||
@@ -6675,8 +6699,8 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1136409150"
|
||||
-- Default tokenizer
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1220918127"] = "Default tokenizer"
|
||||
|
||||
-- Select a root directory for this data source. All data in this directory and all its subdirectories will be processed for this data source.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1265737624"] = "Select a root directory for this data source. All data in this directory and all its subdirectories will be processed for this data source."
|
||||
-- Selected files above this size are not indexed, e.g., images of virtual machines. The embedding page lists them, so you can raise the limit when needed.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1311820297"] = "Selected files above this size are not indexed, e.g., images of virtual machines. The embedding page lists them, so you can raise the limit when needed."
|
||||
|
||||
-- Selected base directory for this data source
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1312296210"] = "Selected base directory for this data source"
|
||||
@@ -6684,9 +6708,18 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1312296210"
|
||||
-- No embedding selected
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1359179968"] = "No embedding selected"
|
||||
|
||||
-- Select a root directory for this data source.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1400580807"] = "Select a root directory for this data source."
|
||||
|
||||
-- No, only index files in the selected folder
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1490813458"] = "No, only index files in the selected folder"
|
||||
|
||||
-- Number of tokens repeated at the start of the next chunk. The default overlap is {0} tokens.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1588814044"] = "Number of tokens repeated at the start of the next chunk. The default overlap is {0} tokens."
|
||||
|
||||
-- Hidden are files and folders whose names start with a dot, such as .git or .env, and those hidden by the operating system. A file pattern which starts with a dot, such as .gitignore, selects such files anyway.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1624717965"] = "Hidden are files and folders whose names start with a dot, such as .git or .env, and those hidden by the operating system. A file pattern which starts with a dot, such as .gitignore, selects such files anyway."
|
||||
|
||||
-- Tokenizer
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1696723386"] = "Tokenizer"
|
||||
|
||||
@@ -6702,15 +6735,24 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1827669611"
|
||||
-- Update
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1847791252"] = "Update"
|
||||
|
||||
-- Include subfolders?
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2086334687"] = "Include subfolders?"
|
||||
|
||||
-- The overlap must be smaller than the effective token limit.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2101951526"] = "The overlap must be smaller than the effective token limit."
|
||||
|
||||
-- Select the file patterns this data source should index.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2244471011"] = "Select the file patterns this data source should index."
|
||||
|
||||
-- Required provider confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T236253137"] = "Required provider confidence level"
|
||||
|
||||
-- Please enter a token limit of at least 1.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2406580478"] = "Please enter a token limit of at least 1."
|
||||
|
||||
-- File patterns
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2460883298"] = "File patterns"
|
||||
|
||||
-- Add
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2646845972"] = "Add"
|
||||
|
||||
@@ -6723,41 +6765,83 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2814869210"
|
||||
-- Embedding
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2838542994"] = "Embedding"
|
||||
|
||||
-- Excluded files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T286958948"] = "Excluded files and folders"
|
||||
|
||||
-- Token limit
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2961294165"] = "Token limit"
|
||||
|
||||
-- Please enter 0 or a positive overlap length.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3242265813"] = "Please enter 0 or a positive overlap length."
|
||||
|
||||
-- Ignore files larger than
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3353866230"] = "Ignore files larger than"
|
||||
|
||||
-- For some data types, such as Office files, MindWork AI Studio requires the open-source application Pandoc.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3359366900"] = "For some data types, such as Office files, MindWork AI Studio requires the open-source application Pandoc."
|
||||
|
||||
-- Show Expert Settings
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3361153305"] = "Show Expert Settings"
|
||||
|
||||
-- No, ignore hidden files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3584816527"] = "No, ignore hidden files and folders"
|
||||
|
||||
-- These files and folders are left out, even when a file pattern selects them. Separate entries with a semicolon or a line break. End an entry with a slash to exclude every folder of that name, e.g., node_modules/. Other entries name files, e.g., *.min.js.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3934601817"] = "These files and folders are left out, even when a file pattern selects them. Separate entries with a semicolon or a line break. End an entry with a slash to exclude every folder of that name, e.g., node_modules/. Other entries name files, e.g., *.min.js."
|
||||
|
||||
-- In order for the AI to be able to determine the appropriate data at any time, you must choose an embedding provider.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T529871858"] = "In order for the AI to be able to determine the appropriate data at any time, you must choose an embedding provider."
|
||||
|
||||
-- Select the base directory
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T562479068"] = "Select the base directory"
|
||||
|
||||
-- Yes, index hidden files and folders as well
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T607153623"] = "Yes, index hidden files and folders as well"
|
||||
|
||||
-- Which files should be indexed? Separate multiple patterns with a semicolon, e.g., *.txt;*.pdf;*.docx;.gitignore. Use :documents: for every document and readable text file, :text: for readable text files only, or * for every file.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T761052435"] = "Which files should be indexed? Separate multiple patterns with a semicolon, e.g., *.txt;*.pdf;*.docx;.gitignore. Use :documents: for every document and readable text file, :text: for readable text files only, or * for every file."
|
||||
|
||||
-- The data source token limit must not be larger than the embedding provider token limit ({0}).
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T787118522"] = "The data source token limit must not be larger than the embedding provider token limit ({0})."
|
||||
|
||||
-- Data Source Name
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T813773421"] = "Data Source Name"
|
||||
|
||||
-- Include hidden files and folders?
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T85084423"] = "Include hidden files and folders?"
|
||||
|
||||
-- Cancel
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T900713019"] = "Cancel"
|
||||
|
||||
-- Restore default
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T913168756"] = "Restore default"
|
||||
|
||||
-- Yes, index files in subfolders as well
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T918760813"] = "Yes, index files in subfolders as well"
|
||||
|
||||
-- Token overlap
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T981382809"] = "Token overlap"
|
||||
|
||||
-- the total directory size
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1082241458"] = "the total directory size"
|
||||
-- the number of matching files in the directory
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1087340457"] = "the number of matching files in the directory"
|
||||
|
||||
-- Total directory size
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1101400963"] = "Total directory size"
|
||||
-- Total size of matching files
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1109307573"] = "Total size of matching files"
|
||||
|
||||
-- Number of matching files
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1397096827"] = "Number of matching files"
|
||||
|
||||
-- For performance reasons, only the first 100 matching files are shown. The configured patterns match {0} files in total.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1430424205"] = "For performance reasons, only the first 100 matching files are shown. The configured patterns match {0} files in total."
|
||||
|
||||
-- whether hidden files and folders are included
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1447415145"] = "whether hidden files and folders are included"
|
||||
|
||||
-- No
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1642511898"] = "No"
|
||||
|
||||
-- Include subfolders
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1710166842"] = "Include subfolders"
|
||||
|
||||
-- Data source name
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T171124909"] = "Data source name"
|
||||
@@ -6765,27 +6849,39 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1711249
|
||||
-- Description
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1725856265"] = "Description"
|
||||
|
||||
-- the number of files in the directory
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1795263412"] = "the number of files in the directory"
|
||||
|
||||
-- The embedding runs locally or in your organization. Your data is not sent to the cloud.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1950544032"] = "The embedding runs locally or in your organization. Your data is not sent to the cloud."
|
||||
|
||||
-- the files list
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2072700997"] = "the files list"
|
||||
-- the file patterns
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2013714981"] = "the file patterns"
|
||||
|
||||
-- The embedding runs in the cloud. Every file this data source selects from the folder '{0}' will be sent to the cloud.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2139422620"] = "The embedding runs in the cloud. Every file this data source selects from the folder '{0}' will be sent to the cloud."
|
||||
|
||||
-- whether subfolders are included
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2333573949"] = "whether subfolders are included"
|
||||
|
||||
-- Required provider confidence level
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T236253137"] = "Required provider confidence level"
|
||||
|
||||
-- File patterns
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2460883298"] = "File patterns"
|
||||
|
||||
-- the maximum number of matches per query
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2479753122"] = "the maximum number of matches per query"
|
||||
|
||||
-- the total size of matching files
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2515807708"] = "the total size of matching files"
|
||||
|
||||
-- the description
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2658359966"] = "the description"
|
||||
|
||||
-- the data source name
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2717738728"] = "the data source name"
|
||||
|
||||
-- Excluded files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T286958948"] = "Excluded files and folders"
|
||||
|
||||
-- The directory chosen for the data source does not exist anymore. Please edit the data source and correct the path.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2875614207"] = "The directory chosen for the data source does not exist anymore. Please edit the data source and correct the path."
|
||||
|
||||
@@ -6798,26 +6894,35 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2937209
|
||||
-- this path
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2944855252"] = "this path"
|
||||
|
||||
-- Yes
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3013883440"] = "Yes"
|
||||
|
||||
-- the size limit for files
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3081730094"] = "the size limit for files"
|
||||
|
||||
-- Embedding name
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3153201045"] = "Embedding name"
|
||||
|
||||
-- Files list
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3238813368"] = "Files list"
|
||||
-- Ignore files larger than
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3353866230"] = "Ignore files larger than"
|
||||
|
||||
-- Close
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3448155331"] = "Close"
|
||||
|
||||
-- For performance reasons, only the first 100 files are shown. The directory contains {0} files in total.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T360238400"] = "For performance reasons, only the first 100 files are shown. The directory contains {0} files in total."
|
||||
-- Matching files
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3650746465"] = "Matching files"
|
||||
|
||||
-- Include hidden files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3770422018"] = "Include hidden files and folders"
|
||||
|
||||
-- the matching files list
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3818527556"] = "the matching files list"
|
||||
|
||||
-- Path
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3949388886"] = "Path"
|
||||
|
||||
-- Number of files
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T417749210"] = "Number of files"
|
||||
|
||||
-- The embedding runs in the cloud. All your data from the folder '{0}' and all its subdirectories will be sent to the cloud.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T443873444"] = "The embedding runs in the cloud. All your data from the folder '{0}' and all its subdirectories will be sent to the cloud."
|
||||
-- the excluded files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T4001527349"] = "the excluded files and folders"
|
||||
|
||||
-- The directory chosen for the data source exists.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T445858624"] = "The directory chosen for the data source exists."
|
||||
@@ -7566,7 +7671,7 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PANDOCDIALOG::T4152693089"] = "Re-install Pa
|
||||
-- Accept the terms of the GPL license and download the latest installer with the download button below. Eventually, you need to allow the download of the installer in the download window.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PANDOCDIALOG::T504404155"] = "Accept the terms of the GPL license and download the latest installer with the download button below. Eventually, you need to allow the download of the installer in the download window."
|
||||
|
||||
-- Pandoc is distributed under the GNU General Public License v2 (GPL). By clicking "Accept the GPL and download the archive," you agree to the terms of the GPL license. Software under GPL is free of charge and free to use.
|
||||
-- Pandoc is distributed under the GNU General Public License v2 (GPL). By clicking "Accept GPL and archive," you agree to the terms of the GPL license. Software under GPL is free of charge and free to use.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PANDOCDIALOG::T523908375"] = "Pandoc is distributed under the GNU General Public License v2 (GPL). By clicking \"Accept the GPL and download the archive,\" you agree to the terms of the GPL license. Software under GPL is free of charge and free to use."
|
||||
|
||||
-- {0} profiles
|
||||
@@ -8208,7 +8313,7 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::REVIEWATTACHMENTSDIALOG::T1746160064"] = "He
|
||||
-- Attached {0}.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::REVIEWATTACHMENTSDIALOG::T1839536175"] = "Attached {0}."
|
||||
|
||||
-- There aren't any file attachments right now.
|
||||
-- There aren't any file attachments available right now.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::REVIEWATTACHMENTSDIALOG::T2111340711"] = "There aren't any file attachments right now."
|
||||
|
||||
-- You can drag more files into this window to attach them right away.
|
||||
@@ -8418,9 +8523,18 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T10
|
||||
-- Instructions
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T1221801316"] = "Instructions"
|
||||
|
||||
-- Include hidden files and folders by default?
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T1450016875"] = "Include hidden files and folders by default?"
|
||||
|
||||
-- Matching files above this size are left out of a batch run, e.g., images of virtual machines.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T1504546559"] = "Matching files above this size are left out of a batch run, e.g., images of virtual machines."
|
||||
|
||||
-- Leave empty to use the ai-results subfolder of the input folder.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T1550632323"] = "Leave empty to use the ai-results subfolder of the input folder."
|
||||
|
||||
-- Hidden are files and folders whose names start with a dot, such as .git or .env, and those hidden by the operating system. A file pattern which starts with a dot, such as .gitignore, selects such files anyway.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T1624717965"] = "Hidden are files and folders whose names start with a dot, such as .git or .env, and those hidden by the operating system. A file pattern which starts with a dot, such as .gitignore, selects such files anyway."
|
||||
|
||||
-- seconds
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T1723256298"] = "seconds"
|
||||
|
||||
@@ -8445,12 +8559,18 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T21
|
||||
-- Default output folder
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T223484721"] = "Default output folder"
|
||||
|
||||
-- Hidden files and folders are included
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T2288334048"] = "Hidden files and folders are included"
|
||||
|
||||
-- The lower end of the random pause interval. AI Studio never allows less than 6 seconds.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T237774509"] = "The lower end of the random pause interval. AI Studio never allows less than 6 seconds."
|
||||
|
||||
-- A policy brings its own tools, so there is nothing to preselect here. You configure them with the policy in the Document Analysis Assistant.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T2391906382"] = "A policy brings its own tools, so there is nothing to preselect here. You configure them with the policy in the Document Analysis Assistant."
|
||||
|
||||
-- Default excluded files and folders
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T2460020307"] = "Default excluded files and folders"
|
||||
|
||||
-- When enabled, new batch runs start with the defaults configured below.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T2592677194"] = "When enabled, new batch runs start with the defaults configured below."
|
||||
|
||||
@@ -8496,6 +8616,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T31
|
||||
-- These instructions are applied to every document of a new batch run.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T3195548336"] = "These instructions are applied to every document of a new batch run."
|
||||
|
||||
-- Ignore files larger than
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T3353866230"] = "Ignore files larger than"
|
||||
|
||||
-- No batch processing options are preselected
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T3421035581"] = "No batch processing options are preselected"
|
||||
|
||||
@@ -8523,6 +8646,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T37
|
||||
-- Default results table name
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T3816237687"] = "Default results table name"
|
||||
|
||||
-- These files and folders are left out, even when a file pattern selects them. Separate entries with a semicolon or a line break. End an entry with a slash to exclude every folder of that name, e.g., node_modules/. Other entries name files, e.g., *.min.js.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T3934601817"] = "These files and folders are left out, even when a file pattern selects them. Separate entries with a semicolon or a line break. End an entry with a slash to exclude every folder of that name, e.g., node_modules/. Other entries name files, e.g., *.min.js."
|
||||
|
||||
-- Default Markdown instructions file
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T3967465682"] = "Default Markdown instructions file"
|
||||
|
||||
@@ -8565,6 +8691,12 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T74
|
||||
-- Leave empty when an input folder should be selected for every batch run.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T762890100"] = "Leave empty when an input folder should be selected for every batch run."
|
||||
|
||||
-- Hidden files and folders are ignored
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T826400562"] = "Hidden files and folders are ignored"
|
||||
|
||||
-- Restore default
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T913168756"] = "Restore default"
|
||||
|
||||
-- Preselect one of your chat templates?
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHAT::T1402022556"] = "Preselect one of your chat templates?"
|
||||
|
||||
@@ -8634,7 +8766,7 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHAT::T492357592"] =
|
||||
-- When enabled, the latest message is shown after loading a chat. When disabled, the first (oldest) message is shown.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHAT::T582516016"] = "When enabled, the latest message is shown after loading a chat. When disabled, the first (oldest) message is shown."
|
||||
|
||||
-- Customize your AI experience with chat templates. Whether you want to experiment with prompt engineering, simply use a custom system prompt in the standard chat interface, or create a specialized assistant, chat templates give you full control. Similar to common AI companies' playgrounds, you can define your own system prompts and leverage assistant prompts for providers that support them.
|
||||
-- Customize your AI experience with chat templates. Whether you want to experiment with prompt engineering, simply use a custom system prompt in the standard chat interface, or create a specialized assistant, our templates give you full control. Similar to common AI companies' playgrounds, you can define your own system prompts and leverage assistant prompts for providers that support them.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCHATTEMPLATE::T1172171653"] = "Customize your AI experience with chat templates. Whether you want to experiment with prompt engineering, simply use a custom system prompt in the standard chat interface, or create a specialized assistant, chat templates give you full control. Similar to common AI companies' playgrounds, you can define your own system prompts and leverage assistant prompts for providers that support them."
|
||||
|
||||
-- Copy attachments into plugin
|
||||
@@ -9396,7 +9528,7 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGVISUALBRIEFING::T956
|
||||
-- Default audience profile
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGVISUALBRIEFING::T963676741"] = "Default audience profile"
|
||||
|
||||
-- If and when should we delete your disappearing chats?
|
||||
-- If and when should we delete your temporary chats?
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGWORKSPACES::T1014418451"] = "If and when should we delete your disappearing chats?"
|
||||
|
||||
-- Workspace display behavior
|
||||
@@ -9756,6 +9888,9 @@ UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2148829171"] = "Embeddings are r
|
||||
-- Plugins
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2222816203"] = "Plugins"
|
||||
|
||||
-- One data source needs attention.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2349740877"] = "One data source needs attention."
|
||||
|
||||
-- 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."
|
||||
|
||||
@@ -9774,12 +9909,15 @@ 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
|
||||
-- Writer
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2979224202"] = "Writing"
|
||||
|
||||
-- Embeddings are waiting to be processed.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T3439916590"] = "Embeddings are waiting to be processed."
|
||||
|
||||
-- {0} data sources need attention.
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T344098457"] = "{0} data sources need attention."
|
||||
|
||||
-- Show details
|
||||
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T3692372066"] = "Show details"
|
||||
|
||||
@@ -10017,18 +10155,30 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1297391911"] = "Mailboxes are syn
|
||||
-- File {0} of {1} is being indexed: block {2}, page {3}.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1298290372"] = "File {0} of {1} is being indexed: block {2}, page {3}."
|
||||
|
||||
-- These image, audio, or video files match the data source patterns, but they cannot currently be added to the index.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1302021733"] = "These image, audio, or video files match the data source patterns, but they cannot currently be added to the index."
|
||||
|
||||
-- Mail
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1399880782"] = "Mail"
|
||||
|
||||
-- Could not open the file location: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1455637941"] = "Could not open the file location: {0}"
|
||||
|
||||
-- These files match the data source patterns, but they are larger than its limit of {0}. You can raise the limit in the expert settings of the data source.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1485378199"] = "These files match the data source patterns, but they are larger than its limit of {0}. You can raise the limit in the expert settings of the data source."
|
||||
|
||||
-- Outside the selection
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1512669069"] = "Outside the selection"
|
||||
|
||||
-- Failed: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1531389696"] = "Failed: {0}"
|
||||
|
||||
-- AI Studio indexes large data sources in steps of a few minutes, so that your other data sources get their turn in between.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1545941101"] = "AI Studio indexes large data sources in steps of a few minutes, so that your other data sources get their turn in between."
|
||||
|
||||
-- Too large
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T156180350"] = "Too large"
|
||||
|
||||
-- Open the settings
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T1582896271"] = "Open the settings"
|
||||
|
||||
@@ -10050,9 +10200,6 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T2149927097"] = "Manage your data
|
||||
-- Noticed
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T2367007983"] = "Noticed"
|
||||
|
||||
-- Skipped files: {0}. AI Studio reads them again once they change.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T2382275084"] = "Skipped files: {0}. AI Studio reads them again once they change."
|
||||
|
||||
-- AI Studio indexes local RAG data sources in the background. Finished files stay recorded so unchanged files can be skipped after a restart, while added or deleted files are detected during the next run. The same applies to documents without readable text, such as scanned pages: AI Studio remembers them and reads them again only once they change.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T2398894096"] = "AI Studio indexes local RAG data sources in the background. Finished files stay recorded so unchanged files can be skipped after a restart, while added or deleted files are detected during the next run. The same applies to documents without readable text, such as scanned pages: AI Studio remembers them and reads them again only once they change."
|
||||
|
||||
@@ -10080,6 +10227,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T2945218010"] = "Data source: {0}"
|
||||
-- Embedding provider: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T300213237"] = "Embedding provider: {0}"
|
||||
|
||||
-- Not added to the index
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3013971506"] = "Not added to the index"
|
||||
|
||||
-- Failed files: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T309404893"] = "Failed files: {0}"
|
||||
|
||||
@@ -10101,15 +10251,27 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3483179115"] = "Mail {0} of {1} i
|
||||
-- Skipped mails: {0}.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3488200549"] = "Skipped mails: {0}."
|
||||
|
||||
-- Manage the data sources
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T357393405"] = "Manage the data sources"
|
||||
|
||||
-- {0} files ({1})
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3628102488"] = "{0} files ({1})"
|
||||
|
||||
-- No local data source has been queued for embedding yet.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3774205531"] = "No local data source has been queued for embedding yet."
|
||||
|
||||
-- Change the settings of the mailbox
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3788376715"] = "Change the settings of the mailbox"
|
||||
|
||||
-- Files without an extension ({0})
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3799572475"] = "Files without an extension ({0})"
|
||||
|
||||
-- Actions
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T3865031940"] = "Actions"
|
||||
|
||||
-- These file types and folders were found in the folder of the data source, but its file patterns or its list of excluded files and folders leave them out. They are intentionally excluded and do not affect the indexing status. Excluded folders are not searched at all.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T4007318423"] = "These file types and folders were found in the folder of the data source, but its file patterns or its list of excluded files and folders leave them out. They are intentionally excluded and do not affect the indexing status. Excluded folders are not searched at all."
|
||||
|
||||
-- Remove them from the index
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T419343388"] = "Remove them from the index"
|
||||
|
||||
@@ -10119,6 +10281,9 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T4205079539"] = "Not synced comple
|
||||
-- Current mail: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T4242653147"] = "Current mail: {0}"
|
||||
|
||||
-- Skipped files: {0}. Open a group below to see why and what you can do.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T4287145754"] = "Skipped files: {0}. Open a group below to see why and what you can do."
|
||||
|
||||
-- Skipped until the file changes
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::EMBEDDINGS::T542386347"] = "Skipped until the file changes"
|
||||
|
||||
@@ -10158,7 +10323,7 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T1573770551"] = "Version"
|
||||
-- Assistants
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T1614176092"] = "Assistants"
|
||||
|
||||
-- We want to contribute to the democratization of AI. MindWork AI Studio runs even on low-cost hardware, including computers around 100 € such as Raspberry Pi. This makes the app and its full feature set accessible to people and families with limited budgets. You can start with local LLMs or use affordable cloud models.
|
||||
-- We want to contribute to the democratization of AI. MindWork AI Studio runs even on low-cost hardware, including computers around 100 EUR such as Raspberry Pi. This makes the app and its full feature set accessible to people and families with limited budgets. You can start with local LLMs or use affordable cloud models.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::HOME::T1628689293"] = "We want to contribute to the democratization of AI. MindWork AI Studio runs even on low-cost hardware, including computers around 100 € such as Raspberry Pi. This makes the app and its full feature set accessible to people and families with limited budgets. You can start with local LLMs or use affordable cloud models."
|
||||
|
||||
-- Enterprise IT
|
||||
@@ -10872,7 +11037,7 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T3342440765"] = "Your organization ha
|
||||
-- Share plugin archive
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T3355474457"] = "Share plugin archive"
|
||||
|
||||
-- Your organization has disabled sharing plugins
|
||||
-- Your organization has disabled sharing plugins.
|
||||
UI_TEXT_CONTENT["AISTUDIO::PAGES::PLUGINS::T3379469503"] = "Your organization has disabled sharing plugins"
|
||||
|
||||
-- Close
|
||||
@@ -11307,10 +11472,10 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1245257804
|
||||
-- Settings
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1258653480"] = "Settings"
|
||||
|
||||
-- No key is sending the input; you have to click the send button
|
||||
-- No key is sending the input
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1311973034"] = "No key is sending the input; you have to click the send button"
|
||||
|
||||
-- Navigation never expands, no tooltips; there are only icons
|
||||
-- Navigation never expands, no tooltips
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1402851833"] = "Navigation never expands, no tooltips; there are only icons"
|
||||
|
||||
-- Welcome
|
||||
@@ -11352,7 +11517,7 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2301448762
|
||||
-- Check every week
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T238099712"] = "Check every week"
|
||||
|
||||
-- Disappearing chats: delete chats older than 1 year
|
||||
-- Delete disappearing chats older than 1 year
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2405705561"] = "Disappearing chats: delete chats older than 1 year"
|
||||
|
||||
-- Store chats manually
|
||||
@@ -11373,7 +11538,7 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2929332068
|
||||
-- Do not specify the language
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2960082609"] = "Do not specify the language"
|
||||
|
||||
-- Disappearing chats: delete chats older than 7 days
|
||||
-- Delete disappearing chats older than 7 days
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T2975140581"] = "Disappearing chats: delete chats older than 7 days"
|
||||
|
||||
-- Always use the default chat provider for new chats
|
||||
@@ -11385,7 +11550,7 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T3061414822
|
||||
-- Check every hour
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T3137986690"] = "Check every hour"
|
||||
|
||||
-- Disappearing chats: delete chats older than 180 days
|
||||
-- Delete disappearing chats older than 180 days
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T3491430707"] = "Disappearing chats: delete chats older than 180 days"
|
||||
|
||||
-- Install updates automatically
|
||||
@@ -11397,7 +11562,7 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T3587225583
|
||||
-- Disable workspaces
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T3612390107"] = "Disable workspaces"
|
||||
|
||||
-- Toggle the sidebar: show the workspaces on demand next to the chat
|
||||
-- Toggle the sidebar: show the workspaces next to the chat when desired
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T3711207137"] = "Toggle the sidebar: show the workspaces on demand next to the chat"
|
||||
|
||||
-- Updates disabled by your organization
|
||||
@@ -11418,16 +11583,16 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T578410699"
|
||||
-- When possible, use the LLM provider which was used for each chat in the first place
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T75376144"] = "When possible, use the LLM provider which was used for each chat in the first place"
|
||||
|
||||
-- Disappearing chats: no automatic maintenance; old chats will never be deleted
|
||||
-- No automatic maintenance for disappearing chats; old chats will never be deleted
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T803751240"] = "Disappearing chats: no automatic maintenance; old chats will never be deleted"
|
||||
|
||||
-- Disappearing chats: delete chats older than 90 days
|
||||
-- Delete disappearing chats older than 90 days
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T869922627"] = "Disappearing chats: delete chats older than 90 days"
|
||||
|
||||
-- Modifier key + enter is sending the input
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T870850829"] = "Modifier key + enter is sending the input"
|
||||
|
||||
-- Disappearing chats: delete chats older than 30 days
|
||||
-- Delete disappearing chats older than 30 days
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T937754037"] = "Disappearing chats: delete chats older than 30 days"
|
||||
|
||||
-- This data source can be used with any LLM provider. Your data may be sent to a cloud-based provider.
|
||||
@@ -11454,7 +11619,7 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::DATASOURCETYPEEXTENSION::T298748
|
||||
-- External ERI Server (v1)
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::DATASOURCETYPEEXTENSION::T3020093889"] = "External ERI Server (v1)"
|
||||
|
||||
-- No data source
|
||||
-- None
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::DATASOURCETYPEEXTENSION::T810547195"] = "No data source"
|
||||
|
||||
-- Local Directory
|
||||
@@ -11463,10 +11628,10 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::DATASOURCETYPEEXTENSION::T926703
|
||||
-- Unknown option
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::LANGBEHAVIOREXTENSIONS::T3964902774"] = "Unknown option"
|
||||
|
||||
-- Choose the language manually
|
||||
-- Choose the language manually.
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::LANGBEHAVIOREXTENSIONS::T3988034966"] = "Choose the language manually"
|
||||
|
||||
-- Choose the language automatically, based on your system language
|
||||
-- Choose the language automatically, based on your system language.
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::LANGBEHAVIOREXTENSIONS::T485389934"] = "Choose the language automatically, based on your system language"
|
||||
|
||||
-- The last 12 months
|
||||
@@ -11652,7 +11817,7 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::AUTHMETHODSV1EXTENSIONS::T2891154022"] = "Acce
|
||||
-- Unknown authentication method
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::AUTHMETHODSV1EXTENSIONS::T3296465240"] = "Unknown authentication method"
|
||||
|
||||
-- No authentication
|
||||
-- None
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::AUTHMETHODSV1EXTENSIONS::T810547195"] = "No authentication"
|
||||
|
||||
-- Username & Password
|
||||
@@ -11796,7 +11961,7 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::CONFIDENCESCHEMESEXTENSIONS::T3016210842"] = "
|
||||
-- Trust LLM providers from Europe
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::CONFIDENCESCHEMESEXTENSIONS::T357239630"] = "Trust LLM providers from Europe"
|
||||
|
||||
-- Trust only self-hosted providers
|
||||
-- Trust only local LLM providers
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::CONFIDENCESCHEMESEXTENSIONS::T3893997203"] = "Trust only self-hosted providers"
|
||||
|
||||
-- Trust all LLM providers
|
||||
@@ -12114,6 +12279,18 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T599774443"] = "The
|
||||
-- policy files
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T632340680"] = "policy files"
|
||||
|
||||
-- Selectors such as :text: cannot be excluded. Please use file name patterns such as *.min.js or folder names such as bin/.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXCLUSIONS::T405437626"] = "Selectors such as :text: cannot be excluded. Please use file name patterns such as *.min.js or folder names such as bin/."
|
||||
|
||||
-- One of the excluded files or folders contains an invalid character.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXCLUSIONS::T594151138"] = "One of the excluded files or folders contains an invalid character."
|
||||
|
||||
-- Please write excluded folders as a name without a path, ending with a slash, e.g., node_modules/ or bin/. Such an entry excludes every folder of that name.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXCLUSIONS::T81428473"] = "Please write excluded folders as a name without a path, ending with a slash, e.g., node_modules/ or bin/. Such an entry excludes every folder of that name."
|
||||
|
||||
-- Please use only single asterisks as wildcards, e.g., *.min.js or cmake-build-*/.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXCLUSIONS::T930019122"] = "Please use only single asterisks as wildcards, e.g., *.min.js or cmake-build-*/."
|
||||
|
||||
-- OpenDocument Text (.odt), e.g. LibreOffice
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXPORTFORMATEXTENSIONS::T1612025407"] = "OpenDocument Text (.odt), e.g. LibreOffice"
|
||||
|
||||
@@ -12309,6 +12486,24 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXTRACTIONRESULTEXTENSIONS::T594894810"] =
|
||||
-- The file '{0}' is not a readable document and was not sent. It might be damaged or transferred incompletely.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXTRACTIONRESULTEXTENSIONS::T985448614"] = "The file '{0}' is not a readable document and was not sent. It might be damaged or transferred incompletely."
|
||||
|
||||
-- One of the file patterns contains an invalid character.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILENAMEPATTERNS::T1182642380"] = "One of the file patterns contains an invalid character."
|
||||
|
||||
-- Please use file name patterns without folder paths, e.g., *.txt or report-*.md.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILENAMEPATTERNS::T1476818839"] = "Please use file name patterns without folder paths, e.g., *.txt or report-*.md."
|
||||
|
||||
-- One of the file patterns is an unknown selector. Please use :documents: or :text:, or a file name pattern such as *.txt.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILENAMEPATTERNS::T2207479763"] = "One of the file patterns is an unknown selector. Please use :documents: or :text:, or a file name pattern such as *.txt."
|
||||
|
||||
-- Please provide at least one file pattern, e.g., :documents: or *.txt. Separate multiple patterns with a semicolon.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILENAMEPATTERNS::T3371062811"] = "Please provide at least one file pattern, e.g., :documents: or *.txt. Separate multiple patterns with a semicolon."
|
||||
|
||||
-- Please remove empty file patterns. Separate valid patterns with a single semicolon.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILENAMEPATTERNS::T368919579"] = "Please remove empty file patterns. Separate valid patterns with a single semicolon."
|
||||
|
||||
-- Please use only single asterisks as wildcards, e.g., *.txt or report-*.md.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILENAMEPATTERNS::T495100949"] = "Please use only single asterisks as wildcards, e.g., *.txt or report-*.md."
|
||||
|
||||
-- The server could not be reached. Please check the host and the port, and whether you need a VPN connection.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::MAIL::MAILBOXCONNECTIONFAILUREEXTENSIONS::T1314233926"] = "The server could not be reached. Please check the host and the port, and whether you need a VPN connection."
|
||||
|
||||
@@ -13011,7 +13206,7 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::RAG::DATASOURCESELECTIONPROCESSES::AGENTICSRCS
|
||||
-- This RAG process filters data sources, automatically selects appropriate sources, optionally allows manual source selection, retrieves data, and automatically validates the retrieval context.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::RAG::RAGPROCESSES::AISRCSELWITHRETCTXVAL::T3047786484"] = "This RAG process filters data sources, automatically selects appropriate sources, optionally allows manual source selection, retrieves data, and automatically validates the retrieval context."
|
||||
|
||||
-- AI-based data source selection with AI retrieval context validation
|
||||
-- AI source selection with AI retrieval context validation
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::RAG::RAGPROCESSES::AISRCSELWITHRETCTXVAL::T3775725978"] = "AI-based data source selection with AI retrieval context validation"
|
||||
|
||||
-- Text
|
||||
@@ -13065,6 +13260,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T2505088878"] = "Visual brief
|
||||
-- Shortcut
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T2547828883"] = "Shortcut"
|
||||
|
||||
-- Readable text
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T2618627384"] = "Readable text"
|
||||
|
||||
-- Media
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::RUST::FILETYPES::T3507473059"] = "Media"
|
||||
|
||||
@@ -13437,9 +13635,6 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::INDEXING::FILESOURCEINDEXER::T139364
|
||||
-- The file '{0}' changed while it was being indexed. What was indexed of it is discarded, and the file is tried again during the next run.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::INDEXING::FILESOURCEINDEXER::T1935191670"] = "The file '{0}' changed while it was being indexed. What was indexed of it is discarded, and the file is tried again during the next run."
|
||||
|
||||
-- The file '{0}' has a type AI Studio cannot index.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::INDEXING::FILESOURCEINDEXER::T2424608026"] = "The file '{0}' has a type AI Studio cannot index."
|
||||
|
||||
-- The folder '{0}' could not be opened. Please check whether you are allowed to read it.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::INDEXING::FILESOURCEINDEXER::T3230000698"] = "The folder '{0}' could not be opened. Please check whether you are allowed to read it."
|
||||
|
||||
@@ -14238,6 +14433,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T2222598306"
|
||||
-- Please select your security policy.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T2250909198"] = "Please select your security policy."
|
||||
|
||||
-- The selected file is not a supported document or readable text file.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T2728355006"] = "The selected file is not a supported document or readable text file."
|
||||
|
||||
-- Please test the connection before saving.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::VALIDATION::DATASOURCEVALIDATION::T285470497"] = "Please test the connection before saving."
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ public sealed class DataBatchProcessing(Expression<Func<Data, DataBatchProcessin
|
||||
public const int MAX_DELAY_SECONDS = 300;
|
||||
public const int DEFAULT_MIN_DELAY_SECONDS = 6;
|
||||
public const int DEFAULT_MAX_DELAY_SECONDS = 10;
|
||||
public const bool DEFAULT_INCLUDE_SUBDIRECTORIES = false;
|
||||
public const bool DEFAULT_INCLUDE_HIDDEN_FILES_AND_FOLDERS = false;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an unmanaged Batch Processing settings instance.
|
||||
@@ -32,7 +34,13 @@ public sealed class DataBatchProcessing(Expression<Func<Data, DataBatchProcessin
|
||||
|
||||
public string FilePatterns { get; set; } = ManagedConfiguration.Register(configSelection, value => value.FilePatterns, DEFAULT_FILE_PATTERNS);
|
||||
|
||||
public bool IncludeSubdirectories { get; set; } = ManagedConfiguration.Register(configSelection, value => value.IncludeSubdirectories, false);
|
||||
public bool IncludeSubdirectories { get; set; } = ManagedConfiguration.Register(configSelection, value => value.IncludeSubdirectories, DEFAULT_INCLUDE_SUBDIRECTORIES);
|
||||
|
||||
public bool IncludeHiddenFilesAndFolders { get; set; } = ManagedConfiguration.Register(configSelection, value => value.IncludeHiddenFilesAndFolders, DEFAULT_INCLUDE_HIDDEN_FILES_AND_FOLDERS);
|
||||
|
||||
public string ExcludePatterns { get; set; } = ManagedConfiguration.Register(configSelection, value => value.ExcludePatterns, FileExclusions.DEFAULT_PATTERNS);
|
||||
|
||||
public int MaxFileSizeMegabytes { get; set; } = ManagedConfiguration.Register(configSelection, value => value.MaxFileSizeMegabytes, FolderFileSelection.DEFAULT_MAX_FILE_SIZE_MEGABYTES);
|
||||
|
||||
public BatchProcessingPromptSource PromptSource { get; set; } = ManagedConfiguration.Register(configSelection, value => value.PromptSource, BatchProcessingPromptSource.FREE_PROMPT);
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using AIStudio.Chat;
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Tools.RAG;
|
||||
@@ -10,6 +12,16 @@ namespace AIStudio.Settings.DataModel;
|
||||
/// </summary>
|
||||
public readonly record struct DataSourceLocalDirectory : IInternalDataSource
|
||||
{
|
||||
// Selects what folder data sources indexed before they had file patterns, plus every other
|
||||
// file whose content is readable text, e.g., a Terraform file or a script without an extension.
|
||||
// Existing data sources get it as well, so an update neither adds images nor binaries to them:
|
||||
public const string DEFAULT_FILE_PATTERNS = FileNamePatterns.ALL_DOCUMENTS_PATTERN;
|
||||
|
||||
// Folder data sources were recursive before this option existed. Keeping true as the
|
||||
// deserialization default preserves every document of existing data sources.
|
||||
public const bool DEFAULT_INCLUDE_SUBDIRECTORIES = true;
|
||||
public const bool DEFAULT_INCLUDE_HIDDEN_FILES_AND_FOLDERS = false;
|
||||
|
||||
public DataSourceLocalDirectory()
|
||||
{
|
||||
}
|
||||
@@ -65,4 +77,67 @@ public readonly record struct DataSourceLocalDirectory : IInternalDataSource
|
||||
/// The path to the directory.
|
||||
/// </summary>
|
||||
public string Path { get; init; } = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Semicolon-separated file-name patterns which decide which files below the path
|
||||
/// are considered for indexing.
|
||||
/// </summary>
|
||||
public string FilePatterns { get; init; } = DEFAULT_FILE_PATTERNS;
|
||||
|
||||
/// <summary>
|
||||
/// The files and folders below the path which are left out, even when a file pattern selects
|
||||
/// them, cf. FileExclusions. Data sources from before this list existed get the default list,
|
||||
/// so their build outputs and dependencies leave the index during the next run.
|
||||
/// </summary>
|
||||
public string ExcludePatterns { get; init; } = FileExclusions.DEFAULT_PATTERNS;
|
||||
|
||||
/// <summary>
|
||||
/// The largest file below the path which is indexed, in megabytes. A larger file which the
|
||||
/// patterns select is not indexed, and the embedding page tells the user about it.
|
||||
/// </summary>
|
||||
public int MaxFileSizeMegabytes { get; init; } = FolderFileSelection.DEFAULT_MAX_FILE_SIZE_MEGABYTES;
|
||||
|
||||
/// <summary>
|
||||
/// Whether files in folders below the path are considered for indexing.
|
||||
/// </summary>
|
||||
public bool IncludeSubdirectories { get; init; } = DEFAULT_INCLUDE_SUBDIRECTORIES;
|
||||
|
||||
/// <summary>
|
||||
/// Whether hidden files and the files in hidden folders below the path are considered for
|
||||
/// indexing. Hidden are those whose names begin with a dot and those the operating system hides.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Even while this is off, a file pattern which begins with a dot, such as .gitignore, selects
|
||||
/// the hidden files it names, cf. FileNamePatterns.NamesHiddenFile. Hidden folders are entered
|
||||
/// only while this is on.
|
||||
/// </remarks>
|
||||
public bool IncludeHiddenFilesAndFolders { get; init; } = DEFAULT_INCLUDE_HIDDEN_FILES_AND_FOLDERS;
|
||||
|
||||
/// <summary>
|
||||
/// The patterns used at runtime. An invalid value can only come from malformed or hand-edited
|
||||
/// settings; falling back to the default, which selects what folder data sources indexed before
|
||||
/// they had file patterns, prevents an accidental removal of the index.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public string EffectiveFilePatterns => FileNamePatterns.IsValid(this.FilePatterns)
|
||||
? this.FilePatterns
|
||||
: DEFAULT_FILE_PATTERNS;
|
||||
|
||||
/// <summary>
|
||||
/// The exclusion list used at runtime. Like the patterns, an invalid value can only come from
|
||||
/// malformed or hand-edited settings, and the default list takes its place.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public string EffectiveExcludePatterns => FileExclusions.IsValid(this.ExcludePatterns)
|
||||
? this.ExcludePatterns
|
||||
: FileExclusions.DEFAULT_PATTERNS;
|
||||
|
||||
/// <summary>
|
||||
/// The size limit used at runtime. A limit below the smallest one can only come from malformed
|
||||
/// or hand-edited settings, and the default takes its place.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int EffectiveMaxFileSizeMegabytes => this.MaxFileSizeMegabytes >= FolderFileSelection.SMALLEST_MAX_FILE_SIZE_MEGABYTES
|
||||
? this.MaxFileSizeMegabytes
|
||||
: FolderFileSelection.DEFAULT_MAX_FILE_SIZE_MEGABYTES;
|
||||
}
|
||||
+12
-1
@@ -128,10 +128,21 @@ public sealed partial class SqliteIndexStoreClientImplementation(string name, st
|
||||
|
||||
var files = await context.EmbeddedFiles
|
||||
.AsNoTracking()
|
||||
.Where(file => file.DataSourceId == dataSourceId && file.ChunkCount > 0)
|
||||
.Where(file => file.DataSourceId == dataSourceId)
|
||||
.ToListAsync(token);
|
||||
foreach (var file in files)
|
||||
{
|
||||
//
|
||||
// A row is written without chunks before the first chunk arrives, and gets its real
|
||||
// count once the file is indexed. A row which still has none belongs to an indexing
|
||||
// which never came to an end:
|
||||
//
|
||||
if (file.ChunkCount <= 0)
|
||||
{
|
||||
manifest.UnfinishedFiles.Add(file.AbsolutePath);
|
||||
continue;
|
||||
}
|
||||
|
||||
manifest.Files[file.AbsolutePath] = new EmbeddedFileRecord(
|
||||
file.Fingerprint,
|
||||
file.FileSize,
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
namespace AIStudio.Tools;
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates files with the directory rules shared by folder-based features.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Hidden files and folders follow the convention of a shell: a file or folder is hidden when its
|
||||
/// name begins with a dot or when the operating system marks it as hidden. Unless they are asked
|
||||
/// for, hidden folders are not entered and hidden files are not returned, just as * in a shell
|
||||
/// does not match .env. A caller can still ask for single hidden files, e.g., because a file
|
||||
/// pattern begins with a dot itself, as .gitignore does.
|
||||
///
|
||||
/// The metadata of operating systems, such as Thumbs.db or __MACOSX, is never returned, cf.
|
||||
/// FileExclusions.
|
||||
/// </remarks>
|
||||
internal static class DirectoryFileTraversal
|
||||
{
|
||||
/// <summary>
|
||||
/// What the name of a hidden file or folder begins with on macOS and Linux.
|
||||
/// </summary>
|
||||
public const char HIDDEN_NAME_PREFIX = '.';
|
||||
|
||||
private const FileAttributes ALWAYS_SKIPPED_DIRECTORY_ATTRIBUTES =
|
||||
FileAttributes.ReparsePoint | FileAttributes.Offline | FileAttributes.System;
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates files below an explicitly selected root. The root itself is always read, even
|
||||
/// when it is hidden; the options apply to everything in it.
|
||||
/// </summary>
|
||||
/// <param name="rootPath">The selected folder.</param>
|
||||
/// <param name="includeSubdirectories">Whether files in subfolders are returned as well.</param>
|
||||
/// <param name="includeHiddenFilesAndFolders">Whether hidden files are returned and hidden folders are entered.</param>
|
||||
/// <param name="includeHiddenFile">Asked for each hidden file while hidden files and folders are left out: whether this one is wanted anyway.</param>
|
||||
/// <param name="includeDirectory">Whether a subfolder is entered at all.</param>
|
||||
/// <param name="reportInaccessibleDirectory">Told about every folder which could not be read.</param>
|
||||
/// <returns>The full paths of the files.</returns>
|
||||
public static IEnumerable<string> EnumerateFiles(
|
||||
string rootPath,
|
||||
bool includeSubdirectories,
|
||||
bool includeHiddenFilesAndFolders,
|
||||
Func<string, bool>? includeHiddenFile = null,
|
||||
Func<string, bool>? includeDirectory = null,
|
||||
Action<string, Exception>? reportInaccessibleDirectory = null)
|
||||
{
|
||||
var pendingDirectories = new Stack<string>();
|
||||
pendingDirectories.Push(rootPath);
|
||||
|
||||
while (pendingDirectories.Count > 0)
|
||||
{
|
||||
var currentPath = pendingDirectories.Pop();
|
||||
FileInfo[] files;
|
||||
DirectoryInfo[] subdirectories;
|
||||
try
|
||||
{
|
||||
//
|
||||
// Unlike plain paths, the entries carry the attributes the enumeration read anyway,
|
||||
// so telling hidden files apart costs no extra call per file on Windows:
|
||||
//
|
||||
var currentDirectory = new DirectoryInfo(currentPath);
|
||||
files = currentDirectory.GetFiles();
|
||||
subdirectories = includeSubdirectories ? currentDirectory.GetDirectories() : [];
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
reportInaccessibleDirectory?.Invoke(currentPath, exception);
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
if (FileExclusions.IsAlwaysExcludedFile(file.Name))
|
||||
continue;
|
||||
|
||||
if (!includeHiddenFilesAndFolders && IsHiddenFileLeftOut(file, includeHiddenFile))
|
||||
continue;
|
||||
|
||||
yield return file.FullName;
|
||||
}
|
||||
|
||||
foreach (var subdirectory in subdirectories)
|
||||
{
|
||||
if (FileExclusions.IsAlwaysExcludedFolder(subdirectory.Name))
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
if ((subdirectory.Attributes & ALWAYS_SKIPPED_DIRECTORY_ATTRIBUTES) != 0)
|
||||
continue;
|
||||
|
||||
if (!includeHiddenFilesAndFolders && IsHidden(subdirectory))
|
||||
continue;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
reportInaccessibleDirectory?.Invoke(subdirectory.FullName, exception);
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// Asked last, so that the caller hears only about folders which would have been
|
||||
// entered otherwise, e.g., to tell the user which folders a list left out:
|
||||
//
|
||||
if (includeDirectory is not null && !includeDirectory(subdirectory.FullName))
|
||||
continue;
|
||||
|
||||
pendingDirectories.Push(subdirectory.FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether a path, e.g., one a file system watcher reports, is a hidden file or folder.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Once a file or folder is gone, only its name can tell whether it was hidden.
|
||||
/// </remarks>
|
||||
public static bool IsHiddenPath(string path)
|
||||
{
|
||||
var name = Path.GetFileName(Path.TrimEndingDirectorySeparator(path));
|
||||
if (HasHiddenName(name))
|
||||
return true;
|
||||
|
||||
try
|
||||
{
|
||||
FileSystemInfo entry = Directory.Exists(path) ? new DirectoryInfo(path) : new FileInfo(path);
|
||||
return entry.Exists && entry.Attributes.HasFlag(FileAttributes.Hidden);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// The path vanished meanwhile, so its name is all there is to tell:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether a file or folder is hidden. The same rule applies to both.
|
||||
/// </summary>
|
||||
private static bool IsHidden(FileSystemInfo entry) => HasHiddenName(entry.Name) || entry.Attributes.HasFlag(FileAttributes.Hidden);
|
||||
|
||||
private static bool HasHiddenName(string name) => name.StartsWith(HIDDEN_NAME_PREFIX);
|
||||
|
||||
private static bool IsHiddenFileLeftOut(FileInfo file, Func<string, bool>? includeHiddenFile)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!IsHidden(file))
|
||||
return false;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// The file vanished meanwhile. Whoever reads it next finds out and says so:
|
||||
return false;
|
||||
}
|
||||
|
||||
return includeHiddenFile?.Invoke(file.FullName) is not true;
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,9 @@ namespace AIStudio.Tools;
|
||||
|
||||
public static class DirectoryInfoExtensions
|
||||
{
|
||||
private static readonly EnumerationOptions ENUMERATION_OPTIONS = new()
|
||||
{
|
||||
IgnoreInaccessible = true,
|
||||
RecurseSubdirectories = true,
|
||||
ReturnSpecialDirectories = false,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Determines the size of the directory and all its subdirectories, as well as the number of files. When desired,
|
||||
/// it can report the found files up to a certain limit.
|
||||
/// Determines the size and file count of the files a selection takes from a directory. When
|
||||
/// desired, it reports the found files up to a limit.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// You might set reportMaxFiles to a negative value to report all files. Any positive value will limit the number
|
||||
@@ -31,18 +24,27 @@ public static class DirectoryInfoExtensions
|
||||
/// <param name="reportMaxFiles">The maximum number of files to report. A negative value reports all files.</param>
|
||||
/// <param name="done">The callback to report that the operation is done.</param>
|
||||
/// <param name="cancellationToken">The cancellation token to stop the operation.</param>
|
||||
public static async Task DetermineContentSize(this DirectoryInfo directoryInfo, Action<long> reportCurrentTotalSize, Action<long> reportCurrentNumFiles, Action<string> reportNextFile, int reportMaxFiles = -1, Action? done = null, CancellationToken cancellationToken = default)
|
||||
/// <param name="selection">Which files count, e.g., those a data source indexes. Every file counts when it is missing.</param>
|
||||
internal static async Task DetermineContentSize(this DirectoryInfo directoryInfo, Action<long> reportCurrentTotalSize, Action<long> reportCurrentNumFiles, Action<string> reportNextFile, int reportMaxFiles = -1, Action? done = null, CancellationToken cancellationToken = default, FolderFileSelection? selection = null)
|
||||
{
|
||||
var rootDirectoryLen = directoryInfo.FullName.Length;
|
||||
var filesToCount = selection ?? FolderFileSelection.EVERY_FILE;
|
||||
long totalSize = 0;
|
||||
long numFiles = 0;
|
||||
|
||||
|
||||
await Task.Factory.StartNew(() => {
|
||||
foreach (var file in directoryInfo.EnumerateFiles("*", ENUMERATION_OPTIONS))
|
||||
foreach (var filePath in filesToCount.EnumerateCandidates(directoryInfo.FullName))
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
if (!filesToCount.Selects(filePath))
|
||||
continue;
|
||||
|
||||
var file = new FileInfo(filePath);
|
||||
if (filesToCount.IsTooLarge(file))
|
||||
continue;
|
||||
|
||||
totalSize += file.Length;
|
||||
numFiles++;
|
||||
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
using System.IO.Enumeration;
|
||||
|
||||
using AIStudio.Tools.PluginSystem;
|
||||
using AIStudio.Tools.Rust;
|
||||
|
||||
namespace AIStudio.Tools;
|
||||
|
||||
/// <summary>
|
||||
/// The files and folders which folder-based features leave out, whatever their file patterns
|
||||
/// select: the metadata of operating systems, which is built in, and a list the user can change.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// An entry which ends with a slash names folders, e.g., bin/, wherever they are below the selected
|
||||
/// folder. Unlike in .gitignore, an entry has no path, so /bin is no entry at all. Every other entry
|
||||
/// is a file name pattern, e.g., *.min.js. Both ignore case and accept the wildcards * and ?.
|
||||
/// Entries are separated by semicolons or line breaks.
|
||||
///
|
||||
/// Exclusion comes before selection: an excluded folder is not even entered, so node_modules costs
|
||||
/// no time, and an excluded file stays out even when a file pattern selects it.
|
||||
/// </remarks>
|
||||
internal static class FileExclusions
|
||||
{
|
||||
/// <summary>
|
||||
/// What an entry which names folders ends with.
|
||||
/// </summary>
|
||||
public const char FOLDER_SUFFIX = '/';
|
||||
|
||||
//
|
||||
// Folders of dependencies and build outputs which are not hidden. Hidden ones, such as .git,
|
||||
// .venv, or .gradle, are left out by the rule for hidden files and folders anyway. Names which
|
||||
// are common in office work stay out of the list on purpose: vendor (suppliers), out,
|
||||
// coverage (press, insurance), and packages.
|
||||
//
|
||||
private const string DEPENDENCY_AND_BUILD_FOLDERS = "node_modules/; bower_components/; Pods/; venv/; env/; __pycache__/; bin/; obj/; Debug/; Release/; target/; build/; dist/; DerivedData/; cmake-build-*/; TestResults/; htmlcov/";
|
||||
|
||||
//
|
||||
// Virtual machines are folders on macOS. Besides huge disk images, they hold text
|
||||
// configurations, e.g., .vmx or config.pvs, which the check for readable text would select:
|
||||
//
|
||||
private const string VIRTUAL_MACHINE_FOLDERS = "*.vmwarevm/; *.pvm/; *.utm/";
|
||||
|
||||
private const string LOCK_FILES = "package-lock.json; yarn.lock; pnpm-lock.yaml; packages.lock.json; Cargo.lock; poetry.lock; Pipfile.lock; composer.lock; Gemfile.lock; go.sum";
|
||||
|
||||
//
|
||||
// Only the source maps of scripts and styles: *.map alone would also hit the map files of
|
||||
// MapServer, which people write themselves:
|
||||
//
|
||||
private const string GENERATED_FILES = "*.min.js; *.min.css; *.js.map; *.css.map";
|
||||
|
||||
//
|
||||
// The tokenizers of language models are JSON files of several megabytes, which :documents:
|
||||
// would select as configuration files. The entry also covers names with a prefix, such as
|
||||
// chat_tokenizer.json, but not the small tokenizer_config.json:
|
||||
//
|
||||
private const string TOKENIZER_FILES = "*tokenizer.json";
|
||||
|
||||
//
|
||||
// Programs, databases, and disk images are binary, so :documents: never selects them. The list
|
||||
// names them anyway, so that * does not fill the embedding page with skipped files. SQLite
|
||||
// prescribes no extension, these are the common ones; -* covers its -wal, -shm, and -journal
|
||||
// companions:
|
||||
//
|
||||
private const string PROGRAM_FILES = "*.exe; *.dll; *.so; *.dylib; *.pdb";
|
||||
private const string DATABASE_FILES = "*.db; *.db3; *.db-*; *.sqlite; *.sqlite3; *.sqlite-*";
|
||||
private const string DISK_IMAGE_FILES = "*.vmdk; *.vdi; *.vhd; *.vhdx; *.qcow2; *.hdd; *.hds; *.iso; *.dmg; *.img";
|
||||
|
||||
/// <summary>
|
||||
/// The list a data source or the batch processing assistant starts with, one group per line.
|
||||
/// </summary>
|
||||
public const string DEFAULT_PATTERNS =
|
||||
DEPENDENCY_AND_BUILD_FOLDERS + "\n" +
|
||||
VIRTUAL_MACHINE_FOLDERS + "\n" +
|
||||
LOCK_FILES + "\n" +
|
||||
GENERATED_FILES + "\n" +
|
||||
TOKENIZER_FILES + "\n" +
|
||||
PROGRAM_FILES + "\n" +
|
||||
DATABASE_FILES + "\n" +
|
||||
DISK_IMAGE_FILES;
|
||||
|
||||
/// <summary>
|
||||
/// How many lines the default list has, so that a field shows all of it at once.
|
||||
/// </summary>
|
||||
public static readonly int DEFAULT_LINE_COUNT = DEFAULT_PATTERNS.Split('\n').Length;
|
||||
|
||||
/// <summary>
|
||||
/// How many lines a field for the list grows to before it scrolls: the default list, with room for
|
||||
/// a few entries of the user.
|
||||
/// </summary>
|
||||
public const int MAX_LINE_COUNT = 12;
|
||||
|
||||
private const string OFFICE_LOCK_FILE_PATTERN = "~$*";
|
||||
|
||||
/// <summary>
|
||||
/// Files nobody ever wanted as content: what operating systems leave in folders, and the lock
|
||||
/// files of Office. Windows marks some of them as system files, but a copy over a network
|
||||
/// drive, by a ZIP file, or onto a Mac loses that mark, and desktop.ini would then pass as a
|
||||
/// configuration file.
|
||||
/// </summary>
|
||||
private static readonly string[] ALWAYS_EXCLUDED_FILES = ["Thumbs.db", "ehthumbs.db", "ehthumbs_vista.db", "desktop.ini", ".DS_Store", "Icon\r", OFFICE_LOCK_FILE_PATTERN];
|
||||
|
||||
/// <summary>
|
||||
/// Folders nobody ever wanted as content: what operating systems and ZIP files on macOS leave behind.
|
||||
/// </summary>
|
||||
private static readonly string[] ALWAYS_EXCLUDED_FOLDERS = ["__MACOSX", "$RECYCLE.BIN", "System Volume Information"];
|
||||
|
||||
private static readonly char[] SEPARATORS = [';', '\r', '\n'];
|
||||
|
||||
private enum ValidationIssue
|
||||
{
|
||||
NONE,
|
||||
SELECTOR,
|
||||
PATH,
|
||||
RECURSIVE_WILDCARD,
|
||||
INVALID_CHARACTER,
|
||||
}
|
||||
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(FileExclusions).Namespace, nameof(FileExclusions));
|
||||
|
||||
/// <summary>
|
||||
/// Splits a list into its entries. Empty lines and empty entries are allowed and dropped.
|
||||
/// </summary>
|
||||
public static string[] Parse(string? patterns) => (patterns ?? string.Empty)
|
||||
.Split(SEPARATORS, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToArray();
|
||||
|
||||
public static bool IsValid(string? patterns) => GetValidationIssue(patterns) is ValidationIssue.NONE;
|
||||
|
||||
/// <summary>
|
||||
/// Validates a list of excluded files and folders. An empty list is valid: it excludes nothing
|
||||
/// beyond what is built in.
|
||||
/// </summary>
|
||||
public static string? Validate(string? patterns) => GetValidationIssue(patterns) switch
|
||||
{
|
||||
ValidationIssue.NONE => null,
|
||||
ValidationIssue.SELECTOR => TB("Selectors such as :text: cannot be excluded. Please use file name patterns such as *.min.js or folder names such as bin/."),
|
||||
ValidationIssue.PATH => TB("Please write excluded folders as a name without a path, ending with a slash, e.g., node_modules/ or bin/. Such an entry excludes every folder of that name."),
|
||||
ValidationIssue.RECURSIVE_WILDCARD => TB("Please use only single asterisks as wildcards, e.g., *.min.js or cmake-build-*/."),
|
||||
ValidationIssue.INVALID_CHARACTER => TB("One of the excluded files or folders contains an invalid character."),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(patterns)),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Whether a folder is left out, either by the built-in list or by one of the entries.
|
||||
/// </summary>
|
||||
public static bool ExcludesFolder(string folderPath, IReadOnlyList<string> exclusions)
|
||||
{
|
||||
var folderName = Path.GetFileName(Path.TrimEndingDirectorySeparator(folderPath));
|
||||
return IsAlwaysExcludedFolder(folderName)
|
||||
|| exclusions.Any(entry => IsFolderEntry(entry) && FileSystemName.MatchesSimpleExpression(entry.AsSpan()[..^1], folderName, ignoreCase: true));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether a file is left out, either by the built-in list or by one of the entries.
|
||||
/// </summary>
|
||||
public static bool ExcludesFile(string filePath, IReadOnlyList<string> exclusions)
|
||||
{
|
||||
var fileName = Path.GetFileName(filePath);
|
||||
return IsAlwaysExcludedFile(fileName)
|
||||
|| exclusions.Any(entry => !IsFolderEntry(entry) && FileSystemName.MatchesSimpleExpression(entry, fileName, ignoreCase: true));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether a file is one nobody ever wanted as content, whatever any list says.
|
||||
/// </summary>
|
||||
public static bool IsAlwaysExcludedFile(string fileName) =>
|
||||
FileTypes.IsAllowedPath(fileName, FileTypes.SHORTCUT)
|
||||
|| ALWAYS_EXCLUDED_FILES.Any(pattern => FileSystemName.MatchesSimpleExpression(pattern, fileName, ignoreCase: true));
|
||||
|
||||
/// <summary>
|
||||
/// Whether a folder is one nobody ever wanted as content, whatever any list says.
|
||||
/// </summary>
|
||||
public static bool IsAlwaysExcludedFolder(string folderName) => ALWAYS_EXCLUDED_FOLDERS.Contains(folderName, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private static bool IsFolderEntry(string entry) => entry.EndsWith(FOLDER_SUFFIX);
|
||||
|
||||
private static ValidationIssue GetValidationIssue(string? patterns)
|
||||
{
|
||||
foreach (var entry in Parse(patterns))
|
||||
{
|
||||
if (FileNamePatterns.LooksLikeSelector(entry))
|
||||
return ValidationIssue.SELECTOR;
|
||||
|
||||
var name = IsFolderEntry(entry) ? entry[..^1] : entry;
|
||||
if (string.IsNullOrWhiteSpace(name)
|
||||
|| name is "." or ".."
|
||||
|| name.EndsWith("..", StringComparison.Ordinal)
|
||||
|| name.IndexOfAny([Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar, '/', '\\']) >= 0)
|
||||
return ValidationIssue.PATH;
|
||||
|
||||
if (name.Contains("**", StringComparison.Ordinal))
|
||||
return ValidationIssue.RECURSIVE_WILDCARD;
|
||||
|
||||
if (name.IndexOfAny(FileNamePatterns.INVALID_PATTERN_CHARACTERS) >= 0)
|
||||
return ValidationIssue.INVALID_CHARACTER;
|
||||
}
|
||||
|
||||
return ValidationIssue.NONE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
using System.IO.Enumeration;
|
||||
|
||||
using AIStudio.Tools.PluginSystem;
|
||||
using AIStudio.Tools.Rust;
|
||||
|
||||
namespace AIStudio.Tools;
|
||||
|
||||
/// <summary>
|
||||
/// Parses and matches the semicolon-separated file-name patterns and semantic selectors used by
|
||||
/// folder-based features.
|
||||
/// </summary>
|
||||
internal static class FileNamePatterns
|
||||
{
|
||||
/// <summary>
|
||||
/// A semantic pattern for every document AI Studio can read: the known document types, such as
|
||||
/// PDF, Office files, and source code, plus every other file whose contents can be read as text.
|
||||
/// Unlike <c>*</c>, it does not select media or binary files.
|
||||
/// </summary>
|
||||
public const string ALL_DOCUMENTS_PATTERN = ":documents:";
|
||||
|
||||
/// <summary>
|
||||
/// A semantic pattern for every file whose contents can be read as text, including files
|
||||
/// without a known extension. Unlike <c>*</c>, it does not select media or binary documents.
|
||||
/// </summary>
|
||||
public const string ALL_TEXT_FILES_PATTERN = ":text:";
|
||||
|
||||
/// <summary>
|
||||
/// What every selector begins and ends with, so that a mistyped selector can be told apart from
|
||||
/// a file name pattern.
|
||||
/// </summary>
|
||||
private const char SELECTOR_DELIMITER = ':';
|
||||
|
||||
private enum ValidationIssue
|
||||
{
|
||||
NONE,
|
||||
MISSING,
|
||||
EMPTY_ENTRY,
|
||||
UNKNOWN_SELECTOR,
|
||||
RECURSIVE_WILDCARD,
|
||||
PATH,
|
||||
INVALID_CHARACTER,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// What a file name pattern must not contain: what no file name may contain, apart from the wildcards.
|
||||
/// </summary>
|
||||
internal static readonly char[] INVALID_PATTERN_CHARACTERS = Path.GetInvalidFileNameChars()
|
||||
.Where(character => character is not '*' and not '?')
|
||||
.ToArray();
|
||||
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(FileNamePatterns).Namespace, nameof(FileNamePatterns));
|
||||
|
||||
public static string[] Parse(string? patterns) => (patterns ?? string.Empty)
|
||||
.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToArray();
|
||||
|
||||
public static string Normalize(string? patterns) => string.Join(';', Parse(patterns));
|
||||
|
||||
public static bool Matches(string filePath, IReadOnlyList<string> patterns)
|
||||
{
|
||||
var fileName = Path.GetFileName(filePath);
|
||||
return !string.IsNullOrWhiteSpace(fileName)
|
||||
&& patterns.Any(pattern => MatchesPattern(filePath, fileName, pattern));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether one of the patterns asks for a hidden file by itself.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// As in a shell, only a pattern which begins with a dot, such as .gitignore or .*, selects a
|
||||
/// hidden file while hidden files are left out. Neither * nor a selector does, so .env does not
|
||||
/// end up in an index by accident, cf. DirectoryFileTraversal.
|
||||
/// </remarks>
|
||||
public static bool NamesHiddenFile(string filePath, IReadOnlyList<string> patterns)
|
||||
{
|
||||
var fileName = Path.GetFileName(filePath);
|
||||
return !string.IsNullOrWhiteSpace(fileName)
|
||||
&& patterns.Any(pattern => pattern.StartsWith(DirectoryFileTraversal.HIDDEN_NAME_PREFIX)
|
||||
&& FileSystemName.MatchesSimpleExpression(pattern, fileName, ignoreCase: true));
|
||||
}
|
||||
|
||||
public static bool AreEquivalent(IReadOnlyCollection<string>? left, IReadOnlyCollection<string>? right)
|
||||
{
|
||||
if (left is null || right is null)
|
||||
return left is null && right is null;
|
||||
|
||||
return left.ToHashSet(StringComparer.OrdinalIgnoreCase).SetEquals(right);
|
||||
}
|
||||
|
||||
public static bool IsValid(string? patterns) => GetValidationIssue(patterns) is ValidationIssue.NONE;
|
||||
|
||||
/// <summary>
|
||||
/// Validates a semicolon-separated list of simple file-name patterns and semantic selectors.
|
||||
/// </summary>
|
||||
public static string? Validate(string? patterns) => GetValidationIssue(patterns) switch
|
||||
{
|
||||
ValidationIssue.NONE => null,
|
||||
ValidationIssue.MISSING => TB("Please provide at least one file pattern, e.g., :documents: or *.txt. Separate multiple patterns with a semicolon."),
|
||||
ValidationIssue.EMPTY_ENTRY => TB("Please remove empty file patterns. Separate valid patterns with a single semicolon."),
|
||||
ValidationIssue.UNKNOWN_SELECTOR => TB("One of the file patterns is an unknown selector. Please use :documents: or :text:, or a file name pattern such as *.txt."),
|
||||
ValidationIssue.RECURSIVE_WILDCARD => TB("Please use only single asterisks as wildcards, e.g., *.txt or report-*.md."),
|
||||
ValidationIssue.PATH => TB("Please use file name patterns without folder paths, e.g., *.txt or report-*.md."),
|
||||
ValidationIssue.INVALID_CHARACTER => TB("One of the file patterns contains an invalid character."),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(patterns)),
|
||||
};
|
||||
|
||||
private static ValidationIssue GetValidationIssue(string? patterns)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(patterns))
|
||||
return ValidationIssue.MISSING;
|
||||
|
||||
var individualPatterns = patterns.Split(';');
|
||||
if (individualPatterns.Any(string.IsNullOrWhiteSpace))
|
||||
return ValidationIssue.EMPTY_ENTRY;
|
||||
|
||||
foreach (var patternEntry in individualPatterns)
|
||||
{
|
||||
var pattern = patternEntry.Trim();
|
||||
if (IsSelector(pattern))
|
||||
continue;
|
||||
|
||||
//
|
||||
// Colons are allowed in file names on macOS and Linux, so a mistyped selector such as
|
||||
// ':document:' would be a valid pattern which matches nothing. Every file would then
|
||||
// leave the index:
|
||||
//
|
||||
if (LooksLikeSelector(pattern))
|
||||
return ValidationIssue.UNKNOWN_SELECTOR;
|
||||
|
||||
if (pattern.Contains("**", StringComparison.Ordinal))
|
||||
return ValidationIssue.RECURSIVE_WILDCARD;
|
||||
|
||||
if (pattern is "." or ".."
|
||||
|| pattern.EndsWith("..", StringComparison.Ordinal)
|
||||
|| pattern.IndexOfAny([Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar, '/', '\\']) >= 0)
|
||||
return ValidationIssue.PATH;
|
||||
|
||||
if (pattern.IndexOfAny(INVALID_PATTERN_CHARACTERS) >= 0)
|
||||
return ValidationIssue.INVALID_CHARACTER;
|
||||
}
|
||||
|
||||
return ValidationIssue.NONE;
|
||||
}
|
||||
|
||||
private static bool MatchesPattern(string filePath, string fileName, string pattern)
|
||||
{
|
||||
//
|
||||
// Media never matches a selector: a data source cannot index it, and an SVG or a renamed
|
||||
// file would pass the check for readable text. The media check looks at the extension
|
||||
// only, so it comes first and saves reading the file:
|
||||
//
|
||||
if (IsSelector(pattern, ALL_DOCUMENTS_PATTERN))
|
||||
return !IsMediaFile(filePath) && FileTypes.IsAllowedPath(filePath, FileTypes.DOCUMENT);
|
||||
|
||||
if (IsSelector(pattern, ALL_TEXT_FILES_PATTERN))
|
||||
return !IsMediaFile(filePath) && FileTypes.IsAllowedPath(filePath, FileTypes.READABLE_TEXT);
|
||||
|
||||
return FileSystemName.MatchesSimpleExpression(pattern, fileName, ignoreCase: true);
|
||||
}
|
||||
|
||||
internal static bool IsSelector(string pattern) => IsSelector(pattern, ALL_DOCUMENTS_PATTERN) || IsSelector(pattern, ALL_TEXT_FILES_PATTERN);
|
||||
|
||||
private static bool IsSelector(string pattern, string selector) => string.Equals(pattern, selector, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
internal static bool LooksLikeSelector(string pattern) => pattern.StartsWith(SELECTOR_DELIMITER) && pattern.EndsWith(SELECTOR_DELIMITER);
|
||||
|
||||
internal static bool IsMediaFile(string filePath) => FileTypes.IsAllowedPath(filePath, FileTypes.MEDIA);
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
using System.Globalization;
|
||||
|
||||
using AIStudio.Settings.DataModel;
|
||||
|
||||
namespace AIStudio.Tools;
|
||||
|
||||
/// <summary>
|
||||
/// Which files below a folder a folder-based feature works with.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The file patterns select files, while the exclusion list and the rule for hidden files and
|
||||
/// folders leave some out again, cf. FileNamePatterns, FileExclusions, and DirectoryFileTraversal.
|
||||
/// Data sources, their information dialog, and the batch processing assistant all decide through
|
||||
/// this class, so the files the dialog counts are the files which get indexed.
|
||||
/// </remarks>
|
||||
/// <param name="filePatterns">The parsed file patterns.</param>
|
||||
/// <param name="exclusions">The parsed list of excluded files and folders.</param>
|
||||
/// <param name="includeSubdirectories">Whether files in subfolders are selected as well.</param>
|
||||
/// <param name="includeHiddenFilesAndFolders">Whether hidden files and the files in hidden folders are selected as well.</param>
|
||||
/// <param name="maxFileSizeMegabytes">The largest file the feature works with, in megabytes, cf. IsTooLarge.</param>
|
||||
internal sealed class FolderFileSelection(IReadOnlyList<string> filePatterns, IReadOnlyList<string> exclusions, bool includeSubdirectories, bool includeHiddenFilesAndFolders, int maxFileSizeMegabytes)
|
||||
{
|
||||
/// <summary>
|
||||
/// The size limit of files unless the user or the organization chooses another one.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A safety net, not a brake on costs: large scanned PDFs, often 100 to 500 MB, still pass. It
|
||||
/// catches the images of virtual machines, ISO files, database dumps, and huge logs, which end
|
||||
/// up in a selection by * or by an unknown extension. There is no value for "no limit"; the
|
||||
/// limit can be raised instead.
|
||||
/// </remarks>
|
||||
public const int DEFAULT_MAX_FILE_SIZE_MEGABYTES = 1024;
|
||||
|
||||
/// <summary>
|
||||
/// The smallest size limit which can be set.
|
||||
/// </summary>
|
||||
public const int SMALLEST_MAX_FILE_SIZE_MEGABYTES = 1;
|
||||
|
||||
private const long BYTES_PER_MEGABYTE = 1024 * 1024;
|
||||
|
||||
/// <summary>
|
||||
/// Every file below a folder, hidden ones included, whatever its size. Only what nobody ever
|
||||
/// wants is left out.
|
||||
/// </summary>
|
||||
public static readonly FolderFileSelection EVERY_FILE = new(["*"], [], true, true, int.MaxValue);
|
||||
|
||||
/// <summary>
|
||||
/// The files a local folder data source indexes.
|
||||
/// </summary>
|
||||
public static FolderFileSelection Of(DataSourceLocalDirectory dataSource) => new(
|
||||
FileNamePatterns.Parse(dataSource.EffectiveFilePatterns),
|
||||
FileExclusions.Parse(dataSource.EffectiveExcludePatterns),
|
||||
dataSource.IncludeSubdirectories,
|
||||
dataSource.IncludeHiddenFilesAndFolders,
|
||||
dataSource.EffectiveMaxFileSizeMegabytes);
|
||||
|
||||
/// <summary>
|
||||
/// The size limit in bytes.
|
||||
/// </summary>
|
||||
public long MaxFileSizeBytes => MegabytesToBytes(maxFileSizeMegabytes);
|
||||
|
||||
public static long MegabytesToBytes(int megabytes) => megabytes * BYTES_PER_MEGABYTE;
|
||||
|
||||
/// <summary>
|
||||
/// Describes the selection as text, which is the same for two selections exactly when they
|
||||
/// select the same files.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// File patterns and exclusions ignore case and order, so the description does as well. It names
|
||||
/// every argument of this class: whoever adds one adds it here, or changing it would not restart
|
||||
/// a run which still works with the old selection, cf. DataSourceEmbeddingService.BuildSelectionSignature.
|
||||
/// </remarks>
|
||||
public string Describe() => string.Create(
|
||||
CultureInfo.InvariantCulture,
|
||||
$"patterns:{Canonical(filePatterns)}|exclusions:{Canonical(exclusions)}|subfolders:{includeSubdirectories}|hidden:{includeHiddenFilesAndFolders}|max-mb:{maxFileSizeMegabytes}");
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates the files below a folder which are neither hidden nor in an excluded or a hidden
|
||||
/// folder. Whether one of them is selected tells Selects.
|
||||
/// </summary>
|
||||
/// <param name="rootPath">The folder.</param>
|
||||
/// <param name="reportExcludedFolder">Told about every folder the exclusion list leaves out.</param>
|
||||
/// <param name="includeDirectory">Whether the caller wants a folder entered, e.g., not the output folder of a batch run.</param>
|
||||
/// <param name="reportInaccessibleDirectory">Told about every folder which could not be read.</param>
|
||||
/// <returns>The full paths of the files.</returns>
|
||||
public IEnumerable<string> EnumerateCandidates(
|
||||
string rootPath,
|
||||
Action<string>? reportExcludedFolder = null,
|
||||
Func<string, bool>? includeDirectory = null,
|
||||
Action<string, Exception>? reportInaccessibleDirectory = null) => DirectoryFileTraversal.EnumerateFiles(
|
||||
rootPath,
|
||||
includeSubdirectories,
|
||||
includeHiddenFilesAndFolders,
|
||||
includeHiddenFile: filePath => FileNamePatterns.NamesHiddenFile(filePath, filePatterns),
|
||||
includeDirectory: directoryPath => this.IsNotExcluded(directoryPath, reportExcludedFolder) && includeDirectory?.Invoke(directoryPath) is not false,
|
||||
reportInaccessibleDirectory: reportInaccessibleDirectory);
|
||||
|
||||
/// <summary>
|
||||
/// Whether a file which EnumerateCandidates found is selected: the exclusion list does not name
|
||||
/// it, and one of the file patterns does. Exclusion comes first.
|
||||
/// </summary>
|
||||
public bool Selects(string filePath) => !FileExclusions.ExcludesFile(filePath, exclusions) && FileNamePatterns.Matches(filePath, filePatterns);
|
||||
|
||||
/// <summary>
|
||||
/// Whether a selected file is larger than the limit. A file of exactly the limit is not.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Kept apart from Selects on purpose: a file the user selected but which is too large is no
|
||||
/// intentional exclusion, so the caller tells the user about it.
|
||||
/// </remarks>
|
||||
public bool IsTooLarge(FileInfo file) => file.Length > this.MaxFileSizeBytes;
|
||||
|
||||
/// <summary>
|
||||
/// Whether a path below the folder lies where EnumerateCandidates never looks: in a hidden or
|
||||
/// an excluded folder, or as a hidden or an excluded file itself.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Meant for the file system watcher. It judges each folder between the root and the path by
|
||||
/// its name, so it also works for a path which is gone, e.g., after a rename. Whether the
|
||||
/// operating system hid something can be told only while it exists. A path which is gone can
|
||||
/// have been a file or a folder, so it is left out only when it would be either way.
|
||||
/// </remarks>
|
||||
/// <param name="rootPath">The folder.</param>
|
||||
/// <param name="path">The path below it.</param>
|
||||
public bool LeavesOut(string rootPath, string path)
|
||||
{
|
||||
var relativePath = Path.GetRelativePath(rootPath, path);
|
||||
//
|
||||
// The folder itself, or a path outside of it, is nothing this selection has a say about:
|
||||
//
|
||||
if (relativePath is "." or ".." || relativePath.StartsWith($"..{Path.DirectorySeparatorChar}", StringComparison.Ordinal) || Path.IsPathRooted(relativePath))
|
||||
return false;
|
||||
|
||||
var names = relativePath.Split([Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar], StringSplitOptions.RemoveEmptyEntries);
|
||||
if (!includeSubdirectories && names.Length > 1)
|
||||
return true;
|
||||
|
||||
var folderPath = rootPath;
|
||||
foreach (var folderName in names[..^1])
|
||||
{
|
||||
folderPath = Path.Combine(folderPath, folderName);
|
||||
if (this.LeavesOutFolder(folderPath))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Directory.Exists(path))
|
||||
return this.LeavesOutFolder(path);
|
||||
|
||||
if (File.Exists(path))
|
||||
return this.LeavesOutFile(path);
|
||||
|
||||
return this.LeavesOutFolder(path) && this.LeavesOutFile(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether a file which is gone now could have been selected.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A selector reads the content of a file, which is gone. So any file which a selector may
|
||||
/// have taken counts, i.e., every one but media, which never matches a selector.
|
||||
/// </remarks>
|
||||
public bool CouldHaveSelected(string filePath) => this.Selects(filePath)
|
||||
|| (filePatterns.Any(FileNamePatterns.IsSelector)
|
||||
&& !FileExclusions.ExcludesFile(filePath, exclusions)
|
||||
&& !FileNamePatterns.IsMediaFile(filePath));
|
||||
|
||||
private bool LeavesOutFolder(string folderPath) => FileExclusions.ExcludesFolder(folderPath, exclusions)
|
||||
|| (!includeHiddenFilesAndFolders && DirectoryFileTraversal.IsHiddenPath(folderPath));
|
||||
|
||||
private bool LeavesOutFile(string filePath) => FileExclusions.ExcludesFile(filePath, exclusions)
|
||||
|| (!includeHiddenFilesAndFolders && DirectoryFileTraversal.IsHiddenPath(filePath) && !FileNamePatterns.NamesHiddenFile(filePath, filePatterns));
|
||||
|
||||
private static string Canonical(IEnumerable<string> entries) => string.Join(';', entries
|
||||
.Select(entry => entry.ToLowerInvariant())
|
||||
.Distinct(StringComparer.Ordinal)
|
||||
.Order(StringComparer.Ordinal));
|
||||
|
||||
private bool IsNotExcluded(string directoryPath, Action<string>? reportExcludedFolder)
|
||||
{
|
||||
if (!FileExclusions.ExcludesFolder(directoryPath, exclusions))
|
||||
return true;
|
||||
|
||||
reportExcludedFolder?.Invoke(directoryPath);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -419,6 +419,13 @@ public sealed class PluginConfiguration(bool isInternal, LuaState state, PluginT
|
||||
ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.OutputDirectory, this.Id, settingsTable, dryRun);
|
||||
ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.FilePatterns, this.Id, settingsTable, dryRun);
|
||||
ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.IncludeSubdirectories, this.Id, settingsTable, dryRun);
|
||||
ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.IncludeHiddenFilesAndFolders, this.Id, settingsTable, dryRun);
|
||||
ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.ExcludePatterns, this.Id, settingsTable, dryRun);
|
||||
|
||||
var maxFileSizeIsValid = ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.MaxFileSizeMegabytes, this.Id, settingsTable, dryRun, validator: value => value >= FolderFileSelection.SMALLEST_MAX_FILE_SIZE_MEGABYTES);
|
||||
if (!maxFileSizeIsValid && settingsTable.TryGetValue("DataBatchProcessing.MaxFileSizeMegabytes", out _))
|
||||
LOG.LogWarning("The Batch Processing size limit configured by plugin {ConfigPluginId} must be at least {SmallestMaxFileSizeMegabytes} MB.", this.Id, FolderFileSelection.SMALLEST_MAX_FILE_SIZE_MEGABYTES);
|
||||
|
||||
ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.PromptSource, this.Id, settingsTable, dryRun);
|
||||
ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.FreePrompt, this.Id, settingsTable, dryRun);
|
||||
ManagedConfiguration.TryProcessConfiguration(x => x.BatchProcessing, x => x.PromptFilePath, this.Id, settingsTable, dryRun);
|
||||
|
||||
@@ -58,7 +58,19 @@ public static class FileTypes
|
||||
// Document hierarchy
|
||||
public static readonly FileTypeFilter PDF = FileTypeFilter.Leaf("PDF", "pdf");
|
||||
public static readonly FileTypeFilter MARKDOWN = FileTypeFilter.Leaf("Markdown", "md");
|
||||
public static readonly FileTypeFilter TEXT = FileTypeFilter.Leaf(TB("Text"), "txt", "md", "rtf");
|
||||
|
||||
/// <summary>
|
||||
/// Text whose file name or extension is not known in advance, such as LICENSE or main.tf.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It is recognized by its content, cf. ReadableTextDetection, and therefore names no extension:
|
||||
/// in a filter of the native file picker, only the extensions of the other types count. The
|
||||
/// runtime's text reader has the final say when it extracts the text.
|
||||
/// </remarks>
|
||||
public static readonly FileTypeFilter READABLE_TEXT = FileTypeFilter.Leaf(TB("Readable text"));
|
||||
|
||||
public static readonly FileTypeFilter TEXT = FileTypeFilter.Composite(TB("Text"), ["txt", "md", "rtf"], READABLE_TEXT);
|
||||
|
||||
public static readonly FileTypeFilter TABULAR = FileTypeFilter.Leaf(TB("Tabular text"), "csv", "tsv");
|
||||
public static readonly FileTypeFilter CSV = FileTypeFilter.Leaf("CSV", "csv");
|
||||
public static readonly FileTypeFilter TSV = FileTypeFilter.Leaf("TSV", "tsv");
|
||||
@@ -160,8 +172,13 @@ public static class FileTypes
|
||||
|
||||
/// <summary>
|
||||
/// Validates a file path against the provided filters.
|
||||
/// Supports extension-based matching and source-like file names (e.g. Dockerfile).
|
||||
/// Supports extension-based matching, source-like file names (e.g. Dockerfile), and readable
|
||||
/// text recognized directly from file contents.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When a filter holds READABLE_TEXT and neither the extension nor the file name matches, this
|
||||
/// reads up to the first 8 KB of the file, cf. ReadableTextDetection. TEXT and DOCUMENT hold it.
|
||||
/// </remarks>
|
||||
public static bool IsAllowedPath(string filePath, params FileTypeFilter[]? types)
|
||||
{
|
||||
if (types == null || types.Length == 0 || string.IsNullOrWhiteSpace(filePath))
|
||||
@@ -185,6 +202,9 @@ public static class FileTypes
|
||||
if (SOURCE_LIKE_FILE_NAME_PREFIXES.FilterExtensions.Any(prefix => fileName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (types.Any(type => type.ContainsType(READABLE_TEXT)) && ReadableTextDetection.IsReadableTextFile(filePath))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Tools.Rust;
|
||||
|
||||
/// <summary>
|
||||
/// Tells from the beginning of a file whether it holds text which the runtime's text reader can read.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// FileTypes asks it for READABLE_TEXT, i.e., for text whose file name or extension is not known in
|
||||
/// advance, such as LICENSE, .gitignore, or main.tf. That applies across the app: chat attachments,
|
||||
/// data sources, and the selectors of file patterns. Only the first PROBE_SIZE bytes are read, so a
|
||||
/// file whose text ends there passes as well. The runtime's text reader has the final say when it
|
||||
/// extracts the text.
|
||||
/// </remarks>
|
||||
internal static class ReadableTextDetection
|
||||
{
|
||||
/// <summary>
|
||||
/// How many bytes at the beginning of a file are read at most.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The same size as BINARY_PROBE_SIZE in runtime/src/file_data.rs, where the text reader looks
|
||||
/// for NUL bytes. Change both together, so that this check and the reader agree on what is binary.
|
||||
/// </remarks>
|
||||
public const int PROBE_SIZE = 8_192;
|
||||
|
||||
/// <summary>
|
||||
/// Text holds at most one control character in this many characters, e.g., an escape sequence
|
||||
/// in a log. Binary data holds far more.
|
||||
/// </summary>
|
||||
private const int MIN_CHARACTERS_PER_CONTROL_CHARACTER = 100;
|
||||
|
||||
private const byte DELETE_BYTE = 0x7F;
|
||||
|
||||
private static readonly byte[] UTF8_BOM = [0xEF, 0xBB, 0xBF];
|
||||
private static readonly byte[] UTF16_BE_BOM = [0xFE, 0xFF];
|
||||
private static readonly byte[] UTF16_LE_BOM = [0xFF, 0xFE];
|
||||
|
||||
/// <summary>
|
||||
/// Determines from the first PROBE_SIZE bytes whether a file uses a recognizable text encoding
|
||||
/// and does not resemble binary data.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The path of the file.</param>
|
||||
/// <returns>True, when the file looks like readable text. False, when it is empty, binary, or cannot be read.</returns>
|
||||
public static bool IsReadableTextFile(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var stream = new FileStream(
|
||||
filePath,
|
||||
FileMode.Open,
|
||||
FileAccess.Read,
|
||||
FileShare.ReadWrite | FileShare.Delete,
|
||||
PROBE_SIZE,
|
||||
FileOptions.SequentialScan);
|
||||
|
||||
var buffer = new byte[PROBE_SIZE];
|
||||
var length = 0;
|
||||
while (length < buffer.Length)
|
||||
{
|
||||
var read = stream.Read(buffer, length, buffer.Length - length);
|
||||
if (read == 0)
|
||||
break;
|
||||
|
||||
length += read;
|
||||
}
|
||||
|
||||
if (length == 0)
|
||||
return false;
|
||||
|
||||
return IsReadableText(buffer.AsSpan(0, length));
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (DecoderFallbackException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsReadableText(ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
if (bytes.StartsWith(UTF8_BOM))
|
||||
return IsReadableText(bytes[UTF8_BOM.Length..], new UTF8Encoding(true, true));
|
||||
|
||||
if (bytes.StartsWith(UTF16_BE_BOM))
|
||||
return IsReadableText(bytes[UTF16_BE_BOM.Length..], new UnicodeEncoding(true, true, true));
|
||||
|
||||
if (bytes.StartsWith(UTF16_LE_BOM))
|
||||
return IsReadableText(bytes[UTF16_LE_BOM.Length..], new UnicodeEncoding(false, true, true));
|
||||
|
||||
if (bytes.Contains((byte)0))
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
return IsReadableText(bytes, new UTF8Encoding(false, true));
|
||||
}
|
||||
catch (DecoderFallbackException)
|
||||
{
|
||||
// Legacy single-byte encodings can represent every byte. Control bytes are therefore
|
||||
// the useful distinction between an encoded text file and arbitrary binary content.
|
||||
return HasAcceptableControlByteRatio(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsReadableText(ReadOnlySpan<byte> bytes, Encoding encoding)
|
||||
{
|
||||
//
|
||||
// The probe may end in the middle of a character. Without flushing, the decoder keeps
|
||||
// such a rest to itself instead of rejecting it:
|
||||
//
|
||||
var characters = new char[encoding.GetMaxCharCount(bytes.Length)];
|
||||
var decoder = encoding.GetDecoder();
|
||||
decoder.Convert(bytes, characters, false, out _, out var charactersUsed, out _);
|
||||
|
||||
return charactersUsed > 0 && HasAcceptableControlCharacterRatio(characters.AsSpan(0, charactersUsed));
|
||||
}
|
||||
|
||||
private static bool HasAcceptableControlByteRatio(ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
var controls = 0;
|
||||
foreach (var value in bytes)
|
||||
{
|
||||
if ((value < (byte)' ' && value != (byte)'\t' && value != (byte)'\n' && value != (byte)'\r' && value != (byte)'\f') || value == DELETE_BYTE)
|
||||
controls++;
|
||||
}
|
||||
|
||||
return controls * MIN_CHARACTERS_PER_CONTROL_CHARACTER <= bytes.Length;
|
||||
}
|
||||
|
||||
private static bool HasAcceptableControlCharacterRatio(ReadOnlySpan<char> characters)
|
||||
{
|
||||
var controls = 0;
|
||||
foreach (var character in characters)
|
||||
{
|
||||
if (char.IsControl(character) && character != '\t' && character != '\n' && character != '\r' && character != '\f')
|
||||
controls++;
|
||||
}
|
||||
|
||||
return controls * MIN_CHARACTERS_PER_CONTROL_CHARACTER <= characters.Length;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace AIStudio.Tools.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Folders which the exclusion list of a local data source left out, summarized by name, e.g.,
|
||||
/// every folder named bin. The user sees whether the list caught a folder they wanted, such as
|
||||
/// a folder named Release which holds press releases.
|
||||
/// </summary>
|
||||
/// <param name="FolderName">The name of the folders.</param>
|
||||
/// <param name="FolderCount">How many folders of this name were left out.</param>
|
||||
public sealed record DataSourceEmbeddingExcludedFolderGroup(string FolderName, int FolderCount);
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace AIStudio.Tools.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Files outside the configured patterns, summarized by extension or by a known extensionless
|
||||
/// file type so a large folder does not put every deliberately excluded path into memory or the
|
||||
/// user interface.
|
||||
/// </summary>
|
||||
/// <param name="FileType">The normalized extension including its leading dot, a known extensionless filename, or an empty string for other files without an extension.</param>
|
||||
/// <param name="FileCount">How many files of this summarized type were found.</param>
|
||||
public sealed record DataSourceEmbeddingFilePatternGroup(string FileType, int FileCount);
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace AIStudio.Tools.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Whether a settled data source can be used as-is or needs the user's attention.
|
||||
/// </summary>
|
||||
public enum DataSourceEmbeddingHealth
|
||||
{
|
||||
HEALTHY,
|
||||
WARNING,
|
||||
ERROR,
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace AIStudio.Tools.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Why a file found while enumerating a local data source was deliberately left out of its index.
|
||||
/// </summary>
|
||||
public enum DataSourceEmbeddingIgnoreReason
|
||||
{
|
||||
MEDIA_NOT_SUPPORTED,
|
||||
TOO_LARGE,
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace AIStudio.Tools.Services;
|
||||
|
||||
/// <summary>
|
||||
/// A file which matches the configured part of a local data source, but was skipped before text
|
||||
/// extraction.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Files below folders the user chose not to scan never reach enumeration and therefore do not
|
||||
/// appear here. Temporary and system files are implementation details and stay hidden as well.
|
||||
/// </remarks>
|
||||
/// <param name="FilePath">The absolute path of the ignored file.</param>
|
||||
/// <param name="Reason">Why the file was ignored.</param>
|
||||
public sealed record DataSourceEmbeddingIgnoredFile(string FilePath, DataSourceEmbeddingIgnoreReason Reason);
|
||||
@@ -12,6 +12,17 @@ public sealed class DataSourceEmbeddingManifest
|
||||
|
||||
public Dictionary<string, EmbeddedFileRecord> Files { get; init; } = new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// The files whose indexing began but never came to an end, by their absolute path.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Their row in the index store has no chunks, and some of their vectors may have reached the
|
||||
/// collection: the run was canceled while it indexed the file, or the app was closed or crashed
|
||||
/// meanwhile. Indexing such a file again replaces both. A file which is gone, or which the data
|
||||
/// source no longer selects, is never indexed again, so the indexer has to remove them itself.
|
||||
/// </remarks>
|
||||
public HashSet<string> UnfinishedFiles { get; init; } = new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// The files whose indexing failed for a reason which lies in the file itself, keyed by their
|
||||
/// absolute path.
|
||||
|
||||
@@ -1,3 +1,45 @@
|
||||
namespace AIStudio.Tools.Services;
|
||||
|
||||
public sealed record DataSourceEmbeddingOverview(DataSourceEmbeddingState State, int IndexedDocuments, int TotalDocuments, int FailedDocuments);
|
||||
public sealed record DataSourceEmbeddingOverview(DataSourceEmbeddingState State, int IndexedDocuments, int TotalDocuments,
|
||||
int FailedDocuments, DataSourceEmbeddingHealth Health, int AttentionDataSources)
|
||||
{
|
||||
/// <summary>
|
||||
/// Reduces the individual statuses to the activity and health shown by the navigation entry.
|
||||
/// </summary>
|
||||
public static DataSourceEmbeddingOverview Create(IReadOnlyList<DataSourceEmbeddingStatus> statuses)
|
||||
{
|
||||
var activeStatus = statuses.FirstOrDefault(status => status.State is DataSourceEmbeddingState.RUNNING)
|
||||
?? statuses.FirstOrDefault(status => status.State is DataSourceEmbeddingState.QUEUED);
|
||||
var health = GetHealth(statuses);
|
||||
var attentionDataSources = statuses.Count(status => status.Health is not DataSourceEmbeddingHealth.HEALTHY);
|
||||
|
||||
if (activeStatus is not null)
|
||||
{
|
||||
return new(
|
||||
activeStatus.State,
|
||||
activeStatus.IndexedDocuments,
|
||||
Math.Max(activeStatus.TotalDocuments, 1),
|
||||
activeStatus.FailedDocuments,
|
||||
health,
|
||||
attentionDataSources);
|
||||
}
|
||||
|
||||
return new(
|
||||
health is DataSourceEmbeddingHealth.ERROR ? DataSourceEmbeddingState.FAILED : DataSourceEmbeddingState.COMPLETED,
|
||||
statuses.Sum(status => status.IndexedDocuments),
|
||||
statuses.Sum(status => status.TotalDocuments),
|
||||
statuses.Sum(status => status.FailedDocuments),
|
||||
health,
|
||||
attentionDataSources);
|
||||
}
|
||||
|
||||
private static DataSourceEmbeddingHealth GetHealth(IReadOnlyList<DataSourceEmbeddingStatus> statuses)
|
||||
{
|
||||
if (statuses.Any(status => status.Health is DataSourceEmbeddingHealth.ERROR))
|
||||
return DataSourceEmbeddingHealth.ERROR;
|
||||
|
||||
return statuses.Any(status => status.Health is DataSourceEmbeddingHealth.WARNING)
|
||||
? DataSourceEmbeddingHealth.WARNING
|
||||
: DataSourceEmbeddingHealth.HEALTHY;
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ public sealed partial class DataSourceEmbeddingService
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Stops every active run which works for embedding settings which no longer apply.
|
||||
/// Stops every active run which works for embedding settings or a selection of documents which no longer apply.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Reads no database, because it runs on every change of a setting anywhere in the app. A run
|
||||
@@ -110,6 +110,10 @@ public sealed partial class DataSourceEmbeddingService
|
||||
if (!indexStore.IsAvailable)
|
||||
return;
|
||||
|
||||
//
|
||||
// The embedding signature alone: another selection leaves the stored index valid, and
|
||||
// the next ordinary run adds and removes the documents.
|
||||
//
|
||||
var indexState = await indexStore.GetDataSourceStateAsync(dataSource.Id, CancellationToken.None);
|
||||
if (string.Equals(indexState?.EmbeddingSignature, currentRunSignature.EmbeddingSignature, StringComparison.Ordinal))
|
||||
continue;
|
||||
|
||||
@@ -95,6 +95,12 @@ public sealed partial class DataSourceEmbeddingService
|
||||
/// made that a different signature, so opening the expert settings of a data source — which
|
||||
/// fills an empty limit with the provider's — threw the whole index away for nothing.
|
||||
///
|
||||
/// The file patterns and the exclusion list of a directory, and whether it includes subfolders
|
||||
/// and hidden files and folders, are omitted as well. They change which documents belong to the
|
||||
/// source, not how retained documents are embedded; the file indexer adds and removes the
|
||||
/// affected document rows and vectors during its ordinary hash-check run. A run which still works
|
||||
/// with the old selection stops all the same, cf. BuildSelectionSignature.
|
||||
///
|
||||
/// The confidence level a data source asks of a provider is deliberately not among them. It
|
||||
/// changes no vector, and it is enforced live on every request anyway: DataSourceService checks
|
||||
/// it against the participating chat providers and against the embedding provider, and this
|
||||
@@ -142,14 +148,34 @@ public sealed partial class DataSourceEmbeddingService
|
||||
internal static string BuildEmbeddingSignature(IDataSourceBase dataSource, EmbeddingProvider embeddingProvider) =>
|
||||
BuildEmbeddingSignature(dataSource, embeddingProvider, GetChunkingOptions(dataSource, embeddingProvider));
|
||||
|
||||
/// <summary>
|
||||
/// Describes which documents of a data source an indexing run works with.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Kept out of the embedding signature on purpose, cf. BuildEmbeddingSignature: another selection
|
||||
/// adds and removes documents, while every vector stored so far stays valid. A run which started
|
||||
/// with another selection, however, goes on with it until it ends, perhaps after hours: it embeds
|
||||
/// files which no longer belong to the data source, and the ones which now do have to wait for
|
||||
/// the next run.
|
||||
///
|
||||
/// Only a local folder chooses its documents by file patterns, exclusions, switches, and a size
|
||||
/// limit. For every other kind of data source, this is empty.
|
||||
/// </remarks>
|
||||
/// <param name="dataSource">The data source to index.</param>
|
||||
/// <returns>The description of its selection, or an empty string.</returns>
|
||||
internal static string BuildSelectionSignature(IIndexedDataSource dataSource) => dataSource is DataSourceLocalDirectory directory
|
||||
? FolderFileSelection.Of(directory).Describe()
|
||||
: string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Describes the indexing run a data source would get with a given embedding provider.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The embedding signature, as long as the provider may read the data source at all. Comparing
|
||||
/// what a run started with against what it would start with now tells whether the run is
|
||||
/// outdated: either it embeds for an index the next run throws away, or it sends documents to a
|
||||
/// provider which may no longer read them.
|
||||
/// The embedding signature and the selection signature, as long as the provider may read the
|
||||
/// data source at all. Comparing what a run started with against what it would start with now
|
||||
/// tells whether the run is outdated: it embeds for an index the next run throws away, it works
|
||||
/// with documents the data source no longer selects, or it sends documents to a provider which
|
||||
/// may no longer read them.
|
||||
/// </remarks>
|
||||
/// <param name="dataSource">The data source to index.</param>
|
||||
/// <param name="embeddingProvider">The embedding provider the data source names.</param>
|
||||
@@ -157,11 +183,11 @@ public sealed partial class DataSourceEmbeddingService
|
||||
/// <returns>The signature of the run, or NONE when the provider may not read the data source and no run would start.</returns>
|
||||
internal static DataSourceRunSignature GetRunSignature(IIndexedDataSource dataSource, EmbeddingProvider embeddingProvider, ConfidenceLevel embeddingProviderConfidence) =>
|
||||
AllowsEmbedding(dataSource, embeddingProviderConfidence)
|
||||
? new(BuildEmbeddingSignature(dataSource, embeddingProvider))
|
||||
? new(BuildEmbeddingSignature(dataSource, embeddingProvider), BuildSelectionSignature(dataSource))
|
||||
: DataSourceRunSignature.NONE;
|
||||
|
||||
/// <summary>
|
||||
/// Whether an indexing run works for embedding settings which no longer apply.
|
||||
/// Whether an indexing run works for embedding settings or a selection of documents which no longer apply.
|
||||
/// </summary>
|
||||
/// <param name="runSignature">The signature the run started with, or null while the run has not resolved its embedding provider yet.</param>
|
||||
/// <param name="currentRunSignature">The signature a run would start with now, or NONE when no run would start anymore.</param>
|
||||
|
||||
@@ -81,7 +81,7 @@ public sealed partial class DataSourceEmbeddingService(SettingsManager settingsM
|
||||
private sealed record DataSourceRunControl(CancellationTokenSource TokenSource, TaskCompletionSource<object?> Completion, DataSourceEmbeddingRefreshMode RefreshMode)
|
||||
{
|
||||
/// <summary>
|
||||
/// The embedding settings the run works for, as GetRunSignature describes them.
|
||||
/// The embedding settings and the selection of documents the run works for, as GetRunSignature describes them.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Null until the run has resolved its embedding provider. Read and written under
|
||||
@@ -113,27 +113,7 @@ public sealed partial class DataSourceEmbeddingService(SettingsManager settingsM
|
||||
|
||||
public DataSourceEmbeddingOverview GetOverview()
|
||||
{
|
||||
var orderedStatuses = this.GetStatuses();
|
||||
var activeStatus = orderedStatuses
|
||||
.FirstOrDefault(status => status.State is DataSourceEmbeddingState.QUEUED or DataSourceEmbeddingState.RUNNING);
|
||||
|
||||
if (activeStatus is not null)
|
||||
{
|
||||
var total = Math.Max(activeStatus.TotalDocuments, 1);
|
||||
return new(
|
||||
activeStatus.State,
|
||||
activeStatus.IndexedDocuments,
|
||||
total,
|
||||
activeStatus.FailedDocuments);
|
||||
}
|
||||
|
||||
var failedStatus = orderedStatuses
|
||||
.FirstOrDefault(status => status.State is DataSourceEmbeddingState.FAILED || status.FailedDocuments > 0);
|
||||
|
||||
if (failedStatus is not null)
|
||||
return new(DataSourceEmbeddingState.FAILED, failedStatus.IndexedDocuments, failedStatus.TotalDocuments, failedStatus.FailedDocuments);
|
||||
|
||||
return new(DataSourceEmbeddingState.COMPLETED, 0, 0, 0);
|
||||
return DataSourceEmbeddingOverview.Create(this.GetStatuses());
|
||||
}
|
||||
|
||||
public Task QueueAllInternalDataSourcesAsync()
|
||||
@@ -830,11 +810,13 @@ public sealed partial class DataSourceEmbeddingService(SettingsManager settingsM
|
||||
dataSource.Id);
|
||||
|
||||
//
|
||||
// From here on, a change of the embedding settings stops this run, cf. CancelOutdatedDataSourceRun.
|
||||
// The provider passed the confidence check above, so this is the run signature as well.
|
||||
// From here on, a change of the embedding settings or of the documents the data source
|
||||
// selects stops this run, cf. CancelOutdatedDataSourceRun. The provider passed the
|
||||
// confidence check above, so this is the run signature as well. Both parts come from the
|
||||
// data source this run works with, not from the one stored now.
|
||||
//
|
||||
var embeddingSignature = BuildEmbeddingSignature(dataSource, embeddingProvider);
|
||||
var runSignature = new DataSourceRunSignature(embeddingSignature);
|
||||
var runSignature = new DataSourceRunSignature(embeddingSignature, BuildSelectionSignature(dataSource));
|
||||
lock (this.runSignatureLock)
|
||||
runControl.RunSignature = runSignature;
|
||||
|
||||
@@ -857,7 +839,7 @@ public sealed partial class DataSourceEmbeddingService(SettingsManager settingsM
|
||||
|
||||
//
|
||||
// Only now, with the run signature recorded and checked, and with whatever an outdated
|
||||
// manifest threw away: a pass belongs to the embedding settings it began with.
|
||||
// manifest threw away: a pass belongs to the embedding settings and the selection it began with.
|
||||
//
|
||||
var lastPass = this.passes.GetValueOrDefault(dataSource.Id);
|
||||
var pass = IndexingPass.ContinueOrBegin(lastPass, refreshMode, runSignature);
|
||||
@@ -1357,13 +1339,15 @@ public sealed partial class DataSourceEmbeddingService(SettingsManager settingsM
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the active run of a data source when it works for embedding settings which no longer apply.
|
||||
/// Stops the active run of a data source when it works for embedding settings or a selection of
|
||||
/// documents which no longer apply.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only what the run signature covers counts, cf. GetRunSignature: another embedding model, other
|
||||
/// chunk settings, a deleted embedding provider, or one which may no longer read the data source.
|
||||
/// A changed name or a changed document leaves the run alone. Whoever calls this has to make sure
|
||||
/// a run follows which starts over with the current settings.
|
||||
/// chunk settings, other file patterns, exclusions, switches, or size limit of a folder, a deleted
|
||||
/// embedding provider, or one which may no longer read the data source. A changed name or a
|
||||
/// changed document leaves the run alone. Whoever calls this has to make sure a run follows which
|
||||
/// starts over with the current settings.
|
||||
/// </remarks>
|
||||
/// <param name="dataSourceId">The id of the data source.</param>
|
||||
private void CancelOutdatedDataSourceRun(string dataSourceId)
|
||||
@@ -1380,17 +1364,22 @@ public sealed partial class DataSourceEmbeddingService(SettingsManager settingsM
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// The selection is a long text, of which a prefix tells nothing apart. Whether it changed is
|
||||
// what the log needs:
|
||||
//
|
||||
logger.LogInformation(
|
||||
"Canceling the active embedding run for data source '{DataSourceId}' because its embedding settings changed or its embedding provider may no longer read it. RunSignaturePrefix={RunSignaturePrefix}, CurrentSignaturePrefix={CurrentSignaturePrefix}.",
|
||||
"Canceling the active embedding run for data source '{DataSourceId}' because its embedding settings or the documents it selects changed, or its embedding provider may no longer read it. RunSignaturePrefix={RunSignaturePrefix}, CurrentSignaturePrefix={CurrentSignaturePrefix}, SelectionChanged={SelectionChanged}.",
|
||||
dataSourceId,
|
||||
ShortHash(runSignature?.EmbeddingSignature ?? string.Empty),
|
||||
currentRunSignature == DataSourceRunSignature.NONE ? "<no run would start>" : ShortHash(currentRunSignature.EmbeddingSignature));
|
||||
currentRunSignature == DataSourceRunSignature.NONE ? "<no run would start>" : ShortHash(currentRunSignature.EmbeddingSignature),
|
||||
currentRunSignature != DataSourceRunSignature.NONE && !string.Equals(runSignature?.SelectionSignature, currentRunSignature.SelectionSignature, StringComparison.Ordinal));
|
||||
|
||||
TryCancelRun(activeRun);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The embedding settings a run of a data source would start with now, as GetRunSignature describes them.
|
||||
/// The embedding settings and the selection of documents a run of a data source would start with now, as GetRunSignature describes them.
|
||||
/// </summary>
|
||||
/// <param name="dataSourceId">The id of the data source.</param>
|
||||
/// <returns>The run signature, or NONE when no run would start: the data source is gone, its embedding provider is, or that provider may not read it.</returns>
|
||||
|
||||
@@ -42,12 +42,60 @@ public sealed record DataSourceEmbeddingStatus(
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(DataSourceEmbeddingStatus).Namespace, nameof(DataSourceEmbeddingStatus));
|
||||
|
||||
/// <summary>
|
||||
/// Files which were found in the scanned part of a local data source but intentionally not
|
||||
/// indexed.
|
||||
/// </summary>
|
||||
public IReadOnlyList<DataSourceEmbeddingIgnoredFile> IgnoredFiles { get; init; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Files outside the configured file patterns or named by the exclusion list, summarized by file
|
||||
/// type. They are intentional exclusions rather than skipped documents and therefore do not
|
||||
/// affect progress or status.
|
||||
/// </summary>
|
||||
public IReadOnlyList<DataSourceEmbeddingFilePatternGroup> FilePatternExclusions { get; init; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Folders which the exclusion list left out, summarized by name. Like the files outside the
|
||||
/// patterns, they are intentional and do not affect progress or status.
|
||||
/// </summary>
|
||||
public IReadOnlyList<DataSourceEmbeddingExcludedFolderGroup> ExcludedFolders { get; init; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Every selected document the run skipped, whether it may become readable after changing or
|
||||
/// was excluded before extraction. Files outside the configured patterns are not selected and
|
||||
/// therefore do not count here.
|
||||
/// </summary>
|
||||
public int SkippedDocuments => this.PermanentlySkippedDocuments + this.IgnoredFiles.Count;
|
||||
|
||||
/// <summary>
|
||||
/// The settled health of this data source. Activity is represented by State
|
||||
/// instead, so queued and running sources can keep their activity indicator.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Documents which were skipped for good are done, even though nothing was indexed of them.
|
||||
/// Leaving them out would keep the bar short of the end for a data source which has nothing
|
||||
/// left to do.
|
||||
/// A few permanently unreadable files do not make an otherwise usable data source unhealthy.
|
||||
/// They become a warning only when none of the selected documents could be indexed. Files
|
||||
/// outside the configured patterns never take part in this decision.
|
||||
/// </remarks>
|
||||
public int ProgressPercent => this.TotalDocuments <= 0 ? 0 : Math.Clamp((int)Math.Round((this.IndexedDocuments + this.PermanentlySkippedDocuments) * 100d / this.TotalDocuments), 0, 100);
|
||||
public DataSourceEmbeddingHealth Health
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.State is DataSourceEmbeddingState.FAILED || this.FailedDocuments > 0)
|
||||
return DataSourceEmbeddingHealth.ERROR;
|
||||
|
||||
if (this.State is DataSourceEmbeddingState.COMPLETED && this.IndexedDocuments == 0 && this.SkippedDocuments > 0)
|
||||
return DataSourceEmbeddingHealth.WARNING;
|
||||
|
||||
return DataSourceEmbeddingHealth.HEALTHY;
|
||||
}
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// Skipped documents are done for this run, even though nothing was indexed of them. Leaving
|
||||
/// them out would keep the bar short of the end for a data source which has nothing left to do.
|
||||
/// </remarks>
|
||||
public int ProgressPercent => this.TotalDocuments <= 0 ? 0 : Math.Clamp((int)Math.Round((this.IndexedDocuments + this.SkippedDocuments) * 100d / this.TotalDocuments), 0, 100);
|
||||
|
||||
public string StateLabel => this.State switch
|
||||
{
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
namespace AIStudio.Tools.Services;
|
||||
|
||||
/// <summary>
|
||||
/// The embedding settings an indexing run of a data source works for.
|
||||
/// What an indexing run of a data source works for: its embedding settings and the documents it selects.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Deliberately nothing but the embedding signature, which decides when a stored index is thrown
|
||||
/// away. A run counts as outdated exactly when the next run would throw its work away, and a list of
|
||||
/// fields of its own would have to be kept in step with that signature by hand.
|
||||
/// A run counts as outdated when the next run would throw its work away, or when it works with
|
||||
/// documents which no longer belong to the data source, or misses the ones which now do. Both parts
|
||||
/// are descriptions which exist anyway, so no list of fields has to be kept in step with them by
|
||||
/// hand: the embedding signature decides when a stored index is thrown away, and the selection
|
||||
/// signature is what the selection of a folder tells about itself.
|
||||
/// </remarks>
|
||||
/// <param name="EmbeddingSignature">The embedding signature of the run, cf. DataSourceEmbeddingService.BuildEmbeddingSignature.</param>
|
||||
internal sealed record DataSourceRunSignature(string EmbeddingSignature)
|
||||
/// <param name="SelectionSignature">Which documents the run works with, cf. DataSourceEmbeddingService.BuildSelectionSignature.</param>
|
||||
internal sealed record DataSourceRunSignature(string EmbeddingSignature, string SelectionSignature)
|
||||
{
|
||||
/// <summary>
|
||||
/// No run would start: the data source or its embedding provider is gone, or that provider may not read it.
|
||||
/// </summary>
|
||||
public static readonly DataSourceRunSignature NONE = new(string.Empty);
|
||||
public static readonly DataSourceRunSignature NONE = new(string.Empty, string.Empty);
|
||||
}
|
||||
@@ -1,11 +1,33 @@
|
||||
using AIStudio.Tools.Rust;
|
||||
|
||||
namespace AIStudio.Tools.Services;
|
||||
|
||||
public sealed class FileEnumerationResult
|
||||
{
|
||||
private readonly Dictionary<string, int> filePatternExclusionCounts = new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private readonly Dictionary<string, int> excludedFolderCounts = new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public List<FileInfo> Files { get; } = [];
|
||||
|
||||
public List<DataSourceEmbeddingFailure> Failures { get; } = [];
|
||||
|
||||
public List<DataSourceEmbeddingIgnoredFile> IgnoredFiles { get; } = [];
|
||||
|
||||
public IReadOnlyList<DataSourceEmbeddingFilePatternGroup> FilePatternExclusions => this.filePatternExclusionCounts
|
||||
.Select(group => new DataSourceEmbeddingFilePatternGroup(group.Key, group.Value))
|
||||
.OrderBy(group => group.FileType, StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
public int FilePatternExclusionCount => this.filePatternExclusionCounts.Values.Sum();
|
||||
|
||||
public IReadOnlyList<DataSourceEmbeddingExcludedFolderGroup> ExcludedFolders => this.excludedFolderCounts
|
||||
.Select(group => new DataSourceEmbeddingExcludedFolderGroup(group.Key, group.Value))
|
||||
.OrderBy(group => group.FolderName, StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
public int ExcludedFolderCount => this.excludedFolderCounts.Values.Sum();
|
||||
|
||||
public int FailedFiles { get; set; }
|
||||
|
||||
public string LastError { get; set; } = string.Empty;
|
||||
@@ -32,4 +54,31 @@ public sealed class FileEnumerationResult
|
||||
this.UnreadableDirectories.Add(directoryPath);
|
||||
this.AddFailure(directoryPath, reason);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddIgnoredFile(string filePath, DataSourceEmbeddingIgnoreReason reason) =>
|
||||
this.IgnoredFiles.Add(new DataSourceEmbeddingIgnoredFile(filePath, reason));
|
||||
|
||||
public void AddFilePatternExclusion(string filePath)
|
||||
{
|
||||
var fileType = GetFilePatternExclusionType(filePath);
|
||||
this.filePatternExclusionCounts[fileType] = this.filePatternExclusionCounts.GetValueOrDefault(fileType) + 1;
|
||||
}
|
||||
|
||||
public void AddExcludedFolder(string directoryPath)
|
||||
{
|
||||
var folderName = Path.GetFileName(Path.TrimEndingDirectorySeparator(directoryPath));
|
||||
this.excludedFolderCounts[folderName] = this.excludedFolderCounts.GetValueOrDefault(folderName) + 1;
|
||||
}
|
||||
|
||||
private static string GetFilePatternExclusionType(string filePath)
|
||||
{
|
||||
var extension = Path.GetExtension(filePath).ToLowerInvariant();
|
||||
if (!string.IsNullOrWhiteSpace(extension))
|
||||
return extension;
|
||||
|
||||
var fileName = Path.GetFileName(filePath);
|
||||
return FileTypes.SOURCE_LIKE_FILE_NAMES.FilterExtensions
|
||||
.FirstOrDefault(knownFileName => string.Equals(knownFileName, fileName, StringComparison.OrdinalIgnoreCase))
|
||||
?? string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -75,5 +75,6 @@ Rules which are easy to break:
|
||||
`IsIndexingPaused` first and tells the user instead of waiting.
|
||||
- **A pass lives only while the last step left more to do.** The service drops the pass of a data source after
|
||||
every other outcome and every exception, and when the stored index is reset. A retry the user asks for, and a
|
||||
step with other embedding settings, begin a new pass (`IndexingPass.ContinueOrBegin`). A pass kept beyond that
|
||||
step with other embedding settings or another selection of documents, begin a new pass
|
||||
(`IndexingPass.ContinueOrBegin`). A pass kept beyond that
|
||||
leaves out documents which would work by now, for example once the embedding provider is reachable again.
|
||||
@@ -23,7 +23,10 @@ namespace AIStudio.Tools.Services.Indexing;
|
||||
/// <param name="lastInputError">Why the last of those could not be looked at, or an empty string.</param>
|
||||
/// <param name="inputFailures">The failures of those which could not be looked at.</param>
|
||||
/// <param name="logger">The logger of the embedding service, so the log reads the same whoever writes it.</param>
|
||||
internal sealed class DocumentRunProgress(IndexedRunContext context, int totalDocuments, int failedInputs, string lastInputError, IEnumerable<DataSourceEmbeddingFailure> inputFailures, ILogger logger)
|
||||
/// <param name="inputIgnoredFiles">Files found during enumeration but intentionally not selected for indexing.</param>
|
||||
/// <param name="filePatternExclusions">Files intentionally excluded by the configured patterns or the exclusion list, summarized by file type.</param>
|
||||
/// <param name="excludedFolders">Folders intentionally left out by the exclusion list, summarized by name.</param>
|
||||
internal sealed class DocumentRunProgress(IndexedRunContext context, int totalDocuments, int failedInputs, string lastInputError, IEnumerable<DataSourceEmbeddingFailure> inputFailures, ILogger logger, IEnumerable<DataSourceEmbeddingIgnoredFile>? inputIgnoredFiles = null, IEnumerable<DataSourceEmbeddingFilePatternGroup>? filePatternExclusions = null, IEnumerable<DataSourceEmbeddingExcludedFolderGroup>? excludedFolders = null)
|
||||
{
|
||||
/// <summary>
|
||||
/// How often the block progress within one document is reported to the user interface at most.
|
||||
@@ -32,6 +35,12 @@ internal sealed class DocumentRunProgress(IndexedRunContext context, int totalDo
|
||||
|
||||
private readonly List<DataSourceEmbeddingFailure> failures = inputFailures.ToList();
|
||||
|
||||
private readonly IReadOnlyList<DataSourceEmbeddingIgnoredFile> ignoredFiles = inputIgnoredFiles?.ToList() ?? [];
|
||||
|
||||
private readonly IReadOnlyList<DataSourceEmbeddingFilePatternGroup> filePatternExclusions = filePatternExclusions?.ToList() ?? [];
|
||||
|
||||
private readonly IReadOnlyList<DataSourceEmbeddingExcludedFolderGroup> excludedFolders = excludedFolders?.ToList() ?? [];
|
||||
|
||||
/// <summary>
|
||||
/// The documents this run read, whether indexing them worked or not, cf. HasDoneItsShare.
|
||||
/// </summary>
|
||||
@@ -545,5 +554,10 @@ internal sealed class DocumentRunProgress(IndexedRunContext context, int totalDo
|
||||
currentPage,
|
||||
Attention: attention,
|
||||
PendingRemovalCount: pendingRemovalCount,
|
||||
LastSyncUtc: this.LastSyncUtc);
|
||||
}
|
||||
LastSyncUtc: this.LastSyncUtc)
|
||||
{
|
||||
IgnoredFiles = this.ignoredFiles,
|
||||
FilePatternExclusions = this.filePatternExclusions,
|
||||
ExcludedFolders = this.excludedFolders,
|
||||
};
|
||||
}
|
||||
@@ -99,7 +99,9 @@ internal sealed partial class FileSourceIndexer
|
||||
{
|
||||
var watcher = new FileSystemWatcher(configuration.RootPath)
|
||||
{
|
||||
Filter = configuration.Filter,
|
||||
// Filtering in managed code keeps rename events reliable: a native filter for one
|
||||
// file may suppress the event when that file is renamed to a different name.
|
||||
Filter = "*",
|
||||
IncludeSubdirectories = configuration.IncludeSubdirectories,
|
||||
NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.LastWrite | NotifyFilters.CreationTime | NotifyFilters.Size,
|
||||
};
|
||||
@@ -227,7 +229,7 @@ internal sealed partial class FileSourceIndexer
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsRelevantWatcherEvent(DataSourceWatcherConfiguration configuration, FileSystemEventArgs args)
|
||||
internal static bool IsRelevantWatcherEvent(DataSourceWatcherConfiguration configuration, FileSystemEventArgs args)
|
||||
{
|
||||
if (args is RenamedEventArgs renamedArgs)
|
||||
{
|
||||
@@ -238,7 +240,7 @@ internal sealed partial class FileSourceIndexer
|
||||
return IsRelevantWatcherPath(configuration, args.FullPath, args.ChangeType);
|
||||
}
|
||||
|
||||
private static bool IsRelevantWatcherPath(DataSourceWatcherConfiguration configuration, string path, WatcherChangeTypes changeType)
|
||||
internal static bool IsRelevantWatcherPath(DataSourceWatcherConfiguration configuration, string path, WatcherChangeTypes changeType)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
return false;
|
||||
@@ -247,43 +249,85 @@ internal sealed partial class FileSourceIndexer
|
||||
if (string.IsNullOrWhiteSpace(fileName))
|
||||
return true;
|
||||
|
||||
if (!configuration.IncludeSubdirectories && !string.Equals(fileName, configuration.Filter, StringComparison.OrdinalIgnoreCase))
|
||||
if (configuration.TargetFileName is { } targetFileName)
|
||||
return string.Equals(fileName, targetFileName, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
//
|
||||
// Git renames .git/index.lock to .git/index with almost every command, and a build or
|
||||
// npm install writes thousands of files into bin, obj, or node_modules. None of them is
|
||||
// part of the data source, so none of them may start a run over the whole folder:
|
||||
//
|
||||
var selection = configuration.Selection;
|
||||
if (selection.LeavesOut(configuration.RootPath, path))
|
||||
return false;
|
||||
|
||||
//
|
||||
// A folder which appears may have been moved here with all its files, and the watcher
|
||||
// reports the folder only:
|
||||
//
|
||||
if (Directory.Exists(path))
|
||||
return true;
|
||||
|
||||
if (IsSkippedRagFileName(fileName))
|
||||
return false;
|
||||
|
||||
if (IsSupportedRagFilePath(path))
|
||||
if (selection.Selects(path))
|
||||
return true;
|
||||
|
||||
return changeType is WatcherChangeTypes.Deleted or WatcherChangeTypes.Renamed
|
||||
&& string.IsNullOrWhiteSpace(Path.GetExtension(path));
|
||||
//
|
||||
// A new or changed file outside the selection changes nothing in the index. The summary of
|
||||
// files outside the selection catches up with the next run, whatever starts it.
|
||||
//
|
||||
if (changeType is not WatcherChangeTypes.Deleted and not WatcherChangeTypes.Renamed)
|
||||
return false;
|
||||
|
||||
//
|
||||
// Once a path is gone, the watcher no longer tells whether it was a folder. A path
|
||||
// without an extension may have been one, with indexed files below it. A file whose
|
||||
// content a selector read may have been indexed as well:
|
||||
//
|
||||
return string.IsNullOrWhiteSpace(Path.GetExtension(path)) || selection.CouldHaveSelected(path);
|
||||
}
|
||||
|
||||
private static DataSourceWatcherConfiguration? GetWatchConfiguration(IDataSourceBase dataSource) => dataSource switch
|
||||
{
|
||||
DataSourceLocalDirectory localDirectory when Directory.Exists(localDirectory.Path) => new DataSourceWatcherConfiguration(
|
||||
localDirectory.Path,
|
||||
"*.*",
|
||||
true),
|
||||
localDirectory.IncludeSubdirectories,
|
||||
localDirectory.IncludeHiddenFilesAndFolders,
|
||||
FilePatterns: FileNamePatterns.Parse(localDirectory.EffectiveFilePatterns),
|
||||
ExcludePatterns: FileExclusions.Parse(localDirectory.EffectiveExcludePatterns)),
|
||||
DataSourceLocalFile localFile when File.Exists(localFile.FilePath) && !string.IsNullOrWhiteSpace(Path.GetDirectoryName(localFile.FilePath)) => new DataSourceWatcherConfiguration(
|
||||
Path.GetDirectoryName(localFile.FilePath)!,
|
||||
Path.GetFileName(localFile.FilePath),
|
||||
false),
|
||||
false,
|
||||
TargetFileName: Path.GetFileName(localFile.FilePath)),
|
||||
_ => null,
|
||||
};
|
||||
|
||||
private static bool IsSameWatchConfiguration(DataSourceWatcherConfiguration left, DataSourceWatcherConfiguration right)
|
||||
internal static bool IsSameWatchConfiguration(DataSourceWatcherConfiguration left, DataSourceWatcherConfiguration right)
|
||||
{
|
||||
return left.IncludeSubdirectories == right.IncludeSubdirectories
|
||||
&& left.IncludeHiddenFilesAndFolders == right.IncludeHiddenFilesAndFolders
|
||||
&& string.Equals(left.RootPath, right.RootPath, StringComparison.OrdinalIgnoreCase)
|
||||
&& string.Equals(left.Filter, right.Filter, StringComparison.OrdinalIgnoreCase);
|
||||
&& string.Equals(left.TargetFileName, right.TargetFileName, StringComparison.OrdinalIgnoreCase)
|
||||
&& FileNamePatterns.AreEquivalent(left.FilePatterns, right.FilePatterns)
|
||||
&& FileNamePatterns.AreEquivalent(left.ExcludePatterns, right.ExcludePatterns);
|
||||
}
|
||||
|
||||
private sealed record DataSourceWatcherConfiguration(string RootPath, string Filter, bool IncludeSubdirectories);
|
||||
internal sealed record DataSourceWatcherConfiguration(
|
||||
string RootPath,
|
||||
bool IncludeSubdirectories,
|
||||
bool IncludeHiddenFilesAndFolders = false,
|
||||
string? TargetFileName = null,
|
||||
IReadOnlyList<string>? FilePatterns = null,
|
||||
IReadOnlyList<string>? ExcludePatterns = null)
|
||||
{
|
||||
/// <summary>
|
||||
/// The files of a folder data source, judged the way its runs judge them, cf. FolderFileSelection.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Built on every call, so that a copy made with "with" judges by its own values. The size
|
||||
/// limit plays no part: a file which grew beyond it has to leave the index during a run.
|
||||
/// </remarks>
|
||||
public FolderFileSelection Selection => new(this.FilePatterns ?? [], this.ExcludePatterns ?? [], this.IncludeSubdirectories, this.IncludeHiddenFilesAndFolders, int.MaxValue);
|
||||
}
|
||||
|
||||
private sealed record DataSourceWatcherRegistration(FileSystemWatcher Watcher, DataSourceWatcherConfiguration Configuration);
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,6 @@ namespace AIStudio.Tools.Services.Indexing;
|
||||
/// <param name="logger">The logger of the embedding service, so the log reads the same whoever writes it.</param>
|
||||
internal sealed partial class FileSourceIndexer(SettingsManager settingsManager, RustService rustService, TextChunker textChunker, ILogger logger) : IIndexedSourceIndexer
|
||||
{
|
||||
private const string OFFICE_LOCK_FILE_PREFIX = "~$";
|
||||
private const bool IMAGE_EMBEDDING_ENABLED = false;
|
||||
private const int MAX_LOGGED_EXCLUDED_FILE_EXAMPLES = 3;
|
||||
|
||||
@@ -46,7 +45,8 @@ internal sealed partial class FileSourceIndexer(SettingsManager settingsManager,
|
||||
{
|
||||
INDEXABLE,
|
||||
EXCLUDED,
|
||||
UNSUPPORTED,
|
||||
MEDIA_NOT_SUPPORTED,
|
||||
TOO_LARGE,
|
||||
}
|
||||
|
||||
private sealed record DataSourceMetadataSnapshot(string SourceHash, IReadOnlyDictionary<string, string> FileHashes);
|
||||
@@ -72,7 +72,7 @@ internal sealed partial class FileSourceIndexer(SettingsManager settingsManager,
|
||||
return this.StopWithoutRoot(context, dataSource, unreachableRootReason);
|
||||
|
||||
var indexedFiles = inputFiles.Files;
|
||||
var totalFiles = indexedFiles.Count + inputFiles.FailedFiles;
|
||||
var totalFiles = indexedFiles.Count + inputFiles.FailedFiles + inputFiles.IgnoredFiles.Count;
|
||||
|
||||
foreach (var failure in inputFiles.Failures)
|
||||
{
|
||||
@@ -89,10 +89,13 @@ internal sealed partial class FileSourceIndexer(SettingsManager settingsManager,
|
||||
// hence the time it took:
|
||||
//
|
||||
logger.LogInformation(
|
||||
"Prepared data source '{DataSourceName}' ({DataSourceId}) for embedding. AccessibleFiles={AccessibleFiles}, FailedFiles={FailedFiles}, EnumerationMs={EnumerationMs:F0}, Collection='{CollectionName}'.",
|
||||
"Prepared data source '{DataSourceName}' ({DataSourceId}) for embedding. AccessibleFiles={AccessibleFiles}, SkippedBeforeExtraction={SkippedBeforeExtraction}, ExcludedByFilePattern={ExcludedByFilePattern}, ExcludedFolders={ExcludedFolders}, FailedFiles={FailedFiles}, EnumerationMs={EnumerationMs:F0}, Collection='{CollectionName}'.",
|
||||
dataSource.Name,
|
||||
dataSource.Id,
|
||||
indexedFiles.Count,
|
||||
inputFiles.IgnoredFiles.Count,
|
||||
inputFiles.FilePatternExclusionCount,
|
||||
inputFiles.ExcludedFolderCount,
|
||||
inputFiles.FailedFiles,
|
||||
enumerationDuration.TotalMilliseconds,
|
||||
context.CollectionName);
|
||||
@@ -111,7 +114,7 @@ internal sealed partial class FileSourceIndexer(SettingsManager settingsManager,
|
||||
indexedFiles.Count,
|
||||
removedMissingFiles);
|
||||
|
||||
var progress = new DocumentRunProgress(context, totalFiles, inputFiles.FailedFiles, inputFiles.LastError, inputFiles.Failures, logger);
|
||||
var progress = new DocumentRunProgress(context, totalFiles, inputFiles.FailedFiles, inputFiles.LastError, inputFiles.Failures, logger, inputFiles.IgnoredFiles, inputFiles.FilePatternExclusions, inputFiles.ExcludedFolders);
|
||||
if (CanSkipDataSourceByHash(manifest, metadataSnapshot, indexedFiles))
|
||||
{
|
||||
logger.LogInformation(
|
||||
@@ -352,27 +355,6 @@ internal sealed partial class FileSourceIndexer(SettingsManager settingsManager,
|
||||
return IndexedRunOutcome.DONE;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether a file name marks a file which is never indexed, whatever its type.
|
||||
/// </summary>
|
||||
/// <param name="fileName">The name of the file.</param>
|
||||
/// <returns>True for shortcuts and the lock files of office suites.</returns>
|
||||
private static bool IsSkippedRagFileName(string fileName)
|
||||
{
|
||||
return FileTypes.IsAllowedPath(fileName, FileTypes.SHORTCUT)
|
||||
|| fileName.StartsWith(OFFICE_LOCK_FILE_PREFIX, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether a file has a type whose text can be indexed.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The path of the file.</param>
|
||||
/// <returns>True for every document type the runtime can read.</returns>
|
||||
private static bool IsSupportedRagFilePath(string filePath)
|
||||
{
|
||||
return FileTypes.IsAllowedPath(filePath, FileTypes.DOCUMENT);
|
||||
}
|
||||
|
||||
private async Task<int> RemoveMissingFileEmbeddingsAsync(IndexedRunContext context, FileEnumerationResult inputFiles, CancellationToken token)
|
||||
{
|
||||
var manifest = context.Manifest;
|
||||
@@ -390,6 +372,23 @@ internal sealed partial class FileSourceIndexer(SettingsManager settingsManager,
|
||||
context.DataSource.Id);
|
||||
}
|
||||
|
||||
//
|
||||
// A file whose indexing never came to an end, e.g., since its run was canceled or the app
|
||||
// was closed meanwhile, left a row without chunks and perhaps some vectors. Indexing it again
|
||||
// would replace both, but a file which is gone or no longer selected is never indexed again:
|
||||
//
|
||||
foreach (var unfinishedFilePath in GetGoneFiles(manifest.UnfinishedFiles, inputFiles.Files, inputFiles.UnreadableDirectories))
|
||||
{
|
||||
await context.DeleteDocumentPointsAsync(unfinishedFilePath, token);
|
||||
await context.IndexStore.DeleteFileAsync(context.DataSource.Id, unfinishedFilePath, token);
|
||||
manifest.UnfinishedFiles.Remove(unfinishedFilePath);
|
||||
logger.LogInformation(
|
||||
"Removed what the unfinished indexing of file '{FilePath}' left behind in data source '{DataSourceName}' ({DataSourceId}), since the file is gone or no longer selected.",
|
||||
unfinishedFilePath,
|
||||
context.DataSource.Name,
|
||||
context.DataSource.Id);
|
||||
}
|
||||
|
||||
//
|
||||
// A file which is gone needs no mark keeping it out of the index. Without this, the table
|
||||
// would grow with every document the user ever deleted:
|
||||
@@ -498,7 +497,7 @@ internal sealed partial class FileSourceIndexer(SettingsManager settingsManager,
|
||||
yield return chunk;
|
||||
}
|
||||
|
||||
private FileEnumerationResult GetInputFiles(IDataSource dataSource)
|
||||
internal FileEnumerationResult GetInputFiles(IDataSource dataSource)
|
||||
{
|
||||
var result = new FileEnumerationResult();
|
||||
|
||||
@@ -506,25 +505,15 @@ internal sealed partial class FileSourceIndexer(SettingsManager settingsManager,
|
||||
{
|
||||
case DataSourceLocalFile localFile when File.Exists(localFile.FilePath):
|
||||
var file = new FileInfo(localFile.FilePath);
|
||||
switch (this.GetRagFileIndexingDecision(file))
|
||||
{
|
||||
case RagFileIndexingDecision.INDEXABLE:
|
||||
result.Files.Add(file);
|
||||
break;
|
||||
|
||||
case RagFileIndexingDecision.EXCLUDED:
|
||||
logger.LogDebug("Skipping excluded file '{FilePath}' while indexing.", file.FullName);
|
||||
break;
|
||||
|
||||
default:
|
||||
result.AddFailure(localFile.FilePath, string.Format(TB("The file '{0}' has a type AI Studio cannot index."), localFile.FilePath));
|
||||
break;
|
||||
}
|
||||
// No size limit: the user chose this very file, cf. FolderFileSelection.IsTooLarge.
|
||||
if (this.AddInputFile(file, null, result) is RagFileIndexingDecision.EXCLUDED)
|
||||
logger.LogDebug("Skipping excluded file '{FilePath}' while indexing.", file.FullName);
|
||||
|
||||
return result;
|
||||
|
||||
case DataSourceLocalDirectory localDirectory when Directory.Exists(localDirectory.Path):
|
||||
this.EnumerateAccessibleFiles(localDirectory.Path, result);
|
||||
this.EnumerateAccessibleFiles(localDirectory, result);
|
||||
if (result.UnreadableDirectories.Contains(localDirectory.Path))
|
||||
result.UnreachableRootReason = string.Format(TB("The folder '{0}' could not be opened. Please check whether you are allowed to read it. Nothing was removed from the index."), localDirectory.Path);
|
||||
|
||||
@@ -548,77 +537,86 @@ internal sealed partial class FileSourceIndexer(SettingsManager settingsManager,
|
||||
return result;
|
||||
}
|
||||
|
||||
private void EnumerateAccessibleFiles(string rootPath, FileEnumerationResult result)
|
||||
private void EnumerateAccessibleFiles(DataSourceLocalDirectory dataSource, FileEnumerationResult result)
|
||||
{
|
||||
var pendingDirectories = new Stack<string>();
|
||||
pendingDirectories.Push(rootPath);
|
||||
var selection = FolderFileSelection.Of(dataSource);
|
||||
|
||||
//
|
||||
// Every log line travels to the runtime as a request of its own. A folder full of icons
|
||||
// would flood the log with one line per file, so the excluded files get one line in total:
|
||||
// Every log line travels to the runtime as a request of its own. A folder holding many
|
||||
// temporary or system files gets one line in total rather than one per file:
|
||||
//
|
||||
var excludedFiles = 0;
|
||||
var excludedFileExamples = new List<string>(MAX_LOGGED_EXCLUDED_FILE_EXAMPLES);
|
||||
|
||||
while (pendingDirectories.Count > 0)
|
||||
foreach (var filePath in selection.EnumerateCandidates(
|
||||
dataSource.Path,
|
||||
reportExcludedFolder: result.AddExcludedFolder,
|
||||
reportInaccessibleDirectory: (directoryPath, exception) =>
|
||||
{
|
||||
logger.LogWarning(exception, "Cannot access directory '{DirectoryPath}' while indexing.", directoryPath);
|
||||
result.AddUnreadableDirectory(directoryPath, string.Format(TB("The folder '{0}' could not be opened. Please check whether you are allowed to read it."), directoryPath));
|
||||
}))
|
||||
{
|
||||
var currentPath = pendingDirectories.Pop();
|
||||
IEnumerable<string> subDirectories;
|
||||
IEnumerable<string> files;
|
||||
|
||||
try
|
||||
if (!selection.Selects(filePath))
|
||||
{
|
||||
subDirectories = Directory.EnumerateDirectories(currentPath);
|
||||
files = Directory.EnumerateFiles(currentPath);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
logger.LogWarning(exception, "Cannot access directory '{DirectoryPath}' while indexing.", currentPath);
|
||||
result.AddUnreadableDirectory(currentPath, string.Format(TB("The folder '{0}' could not be opened. Please check whether you are allowed to read it."), currentPath));
|
||||
// Everything in a folder the user chose to scan is useful transparency when a
|
||||
// pattern was mistyped or was narrower than intended, or when the exclusion list
|
||||
// caught a file somebody wanted:
|
||||
result.AddFilePatternExclusion(filePath);
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var filePath in files)
|
||||
FileInfo fileInfo;
|
||||
try
|
||||
{
|
||||
FileInfo fileInfo;
|
||||
try
|
||||
{
|
||||
fileInfo = new FileInfo(filePath);
|
||||
if (!fileInfo.Exists)
|
||||
continue;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
logger.LogWarning(exception, "Cannot inspect file '{FilePath}' while indexing.", filePath);
|
||||
result.AddFailure(filePath, string.Format(TB("The file '{0}' could not be read. Please check whether you are allowed to read it."), filePath));
|
||||
fileInfo = new FileInfo(filePath);
|
||||
if (!fileInfo.Exists)
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (this.GetRagFileIndexingDecision(fileInfo))
|
||||
{
|
||||
case RagFileIndexingDecision.INDEXABLE:
|
||||
result.Files.Add(fileInfo);
|
||||
break;
|
||||
|
||||
case RagFileIndexingDecision.EXCLUDED:
|
||||
excludedFiles++;
|
||||
if (excludedFileExamples.Count < MAX_LOGGED_EXCLUDED_FILE_EXAMPLES)
|
||||
excludedFileExamples.Add(Path.GetRelativePath(rootPath, fileInfo.FullName));
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
logger.LogWarning(exception, "Cannot inspect file '{FilePath}' while indexing.", filePath);
|
||||
result.AddFailure(filePath, string.Format(TB("The file '{0}' could not be read. Please check whether you are allowed to read it."), filePath));
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var subDirectory in subDirectories)
|
||||
{
|
||||
if (this.IsSkippedRagDirectory(subDirectory))
|
||||
continue;
|
||||
if (this.AddInputFile(fileInfo, selection, result) is not RagFileIndexingDecision.EXCLUDED)
|
||||
continue;
|
||||
|
||||
pendingDirectories.Push(subDirectory);
|
||||
}
|
||||
excludedFiles++;
|
||||
if (excludedFileExamples.Count < MAX_LOGGED_EXCLUDED_FILE_EXAMPLES)
|
||||
excludedFileExamples.Add(Path.GetRelativePath(dataSource.Path, fileInfo.FullName));
|
||||
}
|
||||
|
||||
if (excludedFiles > 0)
|
||||
logger.LogDebug("Skipped {ExcludedFiles} excluded file(s) in '{RootPath}' while indexing, for example: {ExampleFiles}.", excludedFiles, rootPath, string.Join(", ", excludedFileExamples.Select(path => $"'{path}'")));
|
||||
logger.LogDebug("Skipped {ExcludedFiles} excluded file(s) in '{RootPath}' while indexing, for example: {ExampleFiles}.", excludedFiles, dataSource.Path, string.Join(", ", excludedFileExamples.Select(path => $"'{path}'")));
|
||||
}
|
||||
|
||||
/// <param name="file">The file.</param>
|
||||
/// <param name="selection">The files of a folder data source, or null for a single file, which has no size limit.</param>
|
||||
/// <param name="result">Where the file goes, if anywhere.</param>
|
||||
private RagFileIndexingDecision AddInputFile(FileInfo file, FolderFileSelection? selection, FileEnumerationResult result)
|
||||
{
|
||||
var decision = this.GetRagFileIndexingDecision(file, selection);
|
||||
switch (decision)
|
||||
{
|
||||
case RagFileIndexingDecision.INDEXABLE:
|
||||
result.Files.Add(file);
|
||||
break;
|
||||
|
||||
case RagFileIndexingDecision.EXCLUDED:
|
||||
break;
|
||||
|
||||
case RagFileIndexingDecision.MEDIA_NOT_SUPPORTED:
|
||||
result.AddIgnoredFile(file.FullName, DataSourceEmbeddingIgnoreReason.MEDIA_NOT_SUPPORTED);
|
||||
break;
|
||||
|
||||
case RagFileIndexingDecision.TOO_LARGE:
|
||||
result.AddIgnoredFile(file.FullName, DataSourceEmbeddingIgnoreReason.TOO_LARGE);
|
||||
break;
|
||||
}
|
||||
|
||||
return decision;
|
||||
}
|
||||
|
||||
private string TryGetRelativePath(IDataSource dataSource, FileInfo file) => dataSource switch
|
||||
@@ -632,22 +630,34 @@ internal sealed partial class FileSourceIndexer(SettingsManager settingsManager,
|
||||
return FileTypes.IsAllowedPath(filePath, FileTypes.IMAGE);
|
||||
}
|
||||
|
||||
private RagFileIndexingDecision GetRagFileIndexingDecision(FileInfo file)
|
||||
private RagFileIndexingDecision GetRagFileIndexingDecision(FileInfo file, FolderFileSelection? selection)
|
||||
{
|
||||
if (this.IsSkippedRagFile(file))
|
||||
return RagFileIndexingDecision.EXCLUDED;
|
||||
|
||||
if (!IMAGE_EMBEDDING_ENABLED && this.IsImageFilePath(file.FullName))
|
||||
return RagFileIndexingDecision.EXCLUDED;
|
||||
return RagFileIndexingDecision.MEDIA_NOT_SUPPORTED;
|
||||
|
||||
return IsSupportedRagFilePath(file.FullName)
|
||||
? RagFileIndexingDecision.INDEXABLE
|
||||
: RagFileIndexingDecision.UNSUPPORTED;
|
||||
//
|
||||
// Audio and video hold no text until they are transcribed, and data sources do not
|
||||
// transcribe them yet:
|
||||
//
|
||||
if (FileTypes.IsAllowedPath(file.FullName, FileTypes.AUDIO, FileTypes.VIDEO))
|
||||
return RagFileIndexingDecision.MEDIA_NOT_SUPPORTED;
|
||||
|
||||
if (selection?.IsTooLarge(file) is true)
|
||||
return RagFileIndexingDecision.TOO_LARGE;
|
||||
|
||||
// A directory source reaches this point only after its user-configured pattern selected
|
||||
// the file. A single-file source was validated before it was stored. Extraction is the
|
||||
// authoritative capability check and records an unreadable selected file through the
|
||||
// ordinary per-document failure path instead of silently overriding the user's selection.
|
||||
return RagFileIndexingDecision.INDEXABLE;
|
||||
}
|
||||
|
||||
private bool IsSkippedRagFile(FileInfo file)
|
||||
{
|
||||
if (IsSkippedRagFileName(file.Name))
|
||||
if (FileExclusions.IsAlwaysExcludedFile(file.Name))
|
||||
return true;
|
||||
|
||||
try
|
||||
@@ -664,22 +674,6 @@ internal sealed partial class FileSourceIndexer(SettingsManager settingsManager,
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsSkippedRagDirectory(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
var directory = new DirectoryInfo(path);
|
||||
return directory.Attributes.HasFlag(FileAttributes.ReparsePoint)
|
||||
|| directory.Attributes.HasFlag(FileAttributes.Offline)
|
||||
|| directory.Attributes.HasFlag(FileAttributes.System);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
logger.LogWarning(exception, "Cannot inspect directory '{DirectoryPath}' while indexing.", path);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private DataSourceMetadataSnapshot BuildDataSourceMetadataSnapshot(IDataSource dataSource, IReadOnlyList<FileInfo> indexedFiles)
|
||||
{
|
||||
var fileHashes = indexedFiles
|
||||
@@ -810,4 +804,4 @@ internal sealed partial class FileSourceIndexer(SettingsManager settingsManager,
|
||||
var extension = file.Extension.TrimStart('.').ToLowerInvariant();
|
||||
return string.IsNullOrWhiteSpace(extension) ? "unknown" : extension;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,13 +15,13 @@ namespace AIStudio.Tools.Services.Indexing;
|
||||
///
|
||||
/// The embedding service keeps a pass only while the last step of its data source left more to do.
|
||||
/// Any other end of a run ends the pass, and so does a reset of the stored index. A manual retry
|
||||
/// begins a new pass, as does a run for other embedding settings.
|
||||
/// begins a new pass, as does a run for other embedding settings or another selection of documents.
|
||||
///
|
||||
/// Documents which failed for a reason of their own are none of its business: the index remembers
|
||||
/// them for good, cf. PermanentIndexingFailure. Only the steps of one data source use a pass, one
|
||||
/// after the other, so it needs no lock.
|
||||
/// </remarks>
|
||||
/// <param name="runSignature">The embedding settings the pass works for.</param>
|
||||
/// <param name="runSignature">The embedding settings and the selection of documents the pass works for.</param>
|
||||
internal sealed class IndexingPass(DataSourceRunSignature runSignature)
|
||||
{
|
||||
/// <summary>
|
||||
@@ -66,14 +66,15 @@ internal sealed class IndexingPass(DataSourceRunSignature runSignature)
|
||||
/// </summary>
|
||||
/// <param name="current">The pass the last step of the data source left, or null when there is none.</param>
|
||||
/// <param name="refreshMode">Why the run was asked for.</param>
|
||||
/// <param name="runSignature">The embedding settings the run works for.</param>
|
||||
/// <param name="runSignature">The embedding settings and the selection of documents the run works for.</param>
|
||||
/// <returns>The pass of the run.</returns>
|
||||
public static IndexingPass ContinueOrBegin(IndexingPass? current, DataSourceEmbeddingRefreshMode refreshMode, DataSourceRunSignature runSignature)
|
||||
{
|
||||
//
|
||||
// A manual retry is the user asking for every failed document to be tried again, so it
|
||||
// never carries on with what a pass knows. Neither does a run for other embedding settings:
|
||||
// what failed with the old ones may well work with the new.
|
||||
// what failed with the old ones may well work with the new. A run for another selection
|
||||
// goes through the data source anew as well, since it works with other documents:
|
||||
//
|
||||
if (current is not null && refreshMode is not DataSourceEmbeddingRefreshMode.MANUAL_RETRY && current.RunSignature == runSignature)
|
||||
return current;
|
||||
|
||||
@@ -3,6 +3,7 @@ using AIStudio.Settings;
|
||||
using AIStudio.Settings.DataModel;
|
||||
using AIStudio.Tools.ERIClient.DataModel;
|
||||
using AIStudio.Tools.PluginSystem;
|
||||
using AIStudio.Tools.Rust;
|
||||
|
||||
namespace AIStudio.Tools.Validation;
|
||||
|
||||
@@ -156,10 +157,17 @@ public sealed class DataSourceValidation
|
||||
|
||||
if(!File.Exists(filePath))
|
||||
return TB("The file does not exist. Please select a valid file.");
|
||||
|
||||
if(!FileTypes.IsAllowedPath(filePath, FileTypes.DOCUMENT))
|
||||
return TB("The selected file is not a supported document or readable text file.");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string? ValidateFilePatterns(string patterns) => FileNamePatterns.Validate(patterns);
|
||||
|
||||
public string? ValidateExcludePatterns(string patterns) => FileExclusions.Validate(patterns);
|
||||
|
||||
public string? ValidateEmbeddingId(string embeddingId)
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(embeddingId))
|
||||
|
||||
@@ -30,8 +30,16 @@
|
||||
- Improved how AI Studio indexes large local data sources. It now works through them in steps of a few minutes, so your other data sources, such as your mailboxes, stay up to date in between.
|
||||
- Improved the plugins page with the details of each plugin. The info button next to the name of a plugin shows, among other things, its version, its authors, and where to get support.
|
||||
- Improved the details of a plugin on the plugins page, which now show when the plugin was last changed, in your time zone. Plugin authors can state this time, and AI Studio fills it in by itself when it writes a plugin for you, for example, with the Assistant Builder.
|
||||
- Improved local data sources for folders. You can now choose which files AI Studio indexes, for example, only PDF files, and whether it includes subfolders as well as hidden files and folders. By default, AI Studio now also indexes text files it did not recognize before, such as program code of any kind or a LICENSE file, so a Git repository makes a useful data source. Thanks, Paul Koudelka (`PaulKoudelka`), for this contribution.
|
||||
- Improved local data sources for folders, which now leave out hidden files and folders as well as build output and downloaded dependencies, such as the folders `node_modules`, `bin`, and `obj`. You can change this in the expert settings of the data source. When an existing data source contains such files, AI Studio removes them from its index during the next update.
|
||||
- Improved the background embeddings page, which now lists the files of a local data source that AI Studio left out, for example, images or files that are too large. It also shows which file types and folders lie outside what the data source selects.
|
||||
- Improved the Batch Processing assistant, which now leaves out hidden files and folders as well as build output and downloaded dependencies, such as the folder `node_modules`. You can change both in the expert settings of the assistant.
|
||||
- Improved local data sources for folders and the Batch Processing assistant, which now leave out files larger than 1 GB, such as images of virtual machines. You can change this limit.
|
||||
- Improved the organization-wide management of the Batch Processing assistant. IT departments can now preset whether it includes hidden files and folders, which files and folders it leaves out, and how large a file may be, either fixed or as a default which users may change.
|
||||
- Improved attaching files to a chat. You can now attach any file that contains readable text, for example, program code or configuration files of a kind AI Studio did not know before.
|
||||
- Changed the banner on the start page to a fresh design that shows what AI Studio can do today.
|
||||
- Fixed a warning about the confidence level that stayed in the dialog for adding a local data source, even after you chose an embedding provider that meets it. The dialog now checks again whenever you change either of them, so a warning also appears when you switch to a provider that falls short.
|
||||
- Fixed the list of data sources squeezing their names into a very narrow column when you opened it from a chat or from the background embeddings page, so the names were hard to read.
|
||||
- Fixed two confidence levels sharing the same name in the German user interface. Moderate is called "Mäßig" again, and Medium stays "Mittel".
|
||||
- Fixed renaming an external data source (ERI server) leaving its secret behind under the old name in the keychain of your operating system.
|
||||
- Fixed the ERI server assistant deleting files in a folder you no longer used. When it updates a server, it deletes the files it created before, and after you chose another folder for the server, it also deleted them in the old one. It now only deletes files within the folder you chose.
|
||||
|
||||
Reference in new issue
Block a user