diff --git a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor index e93ee20a3..5639c5886 100644 --- a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor +++ b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor @@ -9,17 +9,6 @@ - - - - @T("Restore default patterns") - - - - - @T("Supported audio and video files are transcribed automatically without an additional dialog. Each transcript is stored next to its media file as '.transcript.md' and reused when an interrupted run is continued.") - - @if (this.includeSubdirectories) @@ -29,6 +18,32 @@ } + + + + + @T("Supported audio and video files are transcribed automatically without an additional dialog. Each transcript is stored next to its media file as '.transcript.md' and reused when an interrupted run is continued.") + + + + + @(this.showExpertSettings ? T("Hide Expert Settings") : T("Show Expert Settings")) + + + + + + @T("Instructions") @@ -269,4 +284,11 @@ else } + + @if (this.numTooLargeFiles > 0) + { + + @string.Format(T("{0} matching files were left out because they are larger than {1}."), this.numTooLargeFiles, FolderFileSelection.MegabytesToBytes(this.maxFileSizeMegabytes).FileSize()) + + } } diff --git a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Session.cs b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Session.cs index 19d945ac6..29e5bb712 100644 --- a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Session.cs +++ b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Session.cs @@ -8,7 +8,10 @@ public partial class AssistantBatchProcessing private static readonly AssistantSessionStateKey INPUT_DIRECTORY_STATE_KEY = new(nameof(inputDirectory)); private static readonly AssistantSessionStateKey OUTPUT_DIRECTORY_STATE_KEY = new(nameof(outputDirectory)); private static readonly AssistantSessionStateKey FILE_PATTERNS_STATE_KEY = new(nameof(filePatterns)); + private static readonly AssistantSessionStateKey EXCLUDE_PATTERNS_STATE_KEY = new(nameof(excludePatterns)); + private static readonly AssistantSessionStateKey MAX_FILE_SIZE_MEGABYTES_STATE_KEY = new(nameof(maxFileSizeMegabytes)); private static readonly AssistantSessionStateKey INCLUDE_SUBDIRECTORIES_STATE_KEY = new(nameof(includeSubdirectories)); + private static readonly AssistantSessionStateKey INCLUDE_HIDDEN_FILES_AND_FOLDERS_STATE_KEY = new(nameof(includeHiddenFilesAndFolders)); private static readonly AssistantSessionStateKey PROMPT_SOURCE_STATE_KEY = new(nameof(promptSource)); private static readonly AssistantSessionStateKey FREE_PROMPT_STATE_KEY = new(nameof(freePrompt)); private static readonly AssistantSessionStateKey IMPORTED_PROMPT_STATE_KEY = new(nameof(importedPrompt)); @@ -28,6 +31,7 @@ public partial class AssistantBatchProcessing private static readonly AssistantSessionStateKey IS_PROCESSING_BATCH_STATE_KEY = new(nameof(isProcessingBatch)); private static readonly AssistantSessionStateKey HAS_REPORTED_WRITE_FAILURE_STATE_KEY = new(nameof(hasReportedWriteFailure)); private static readonly AssistantSessionStateKey NUM_PROCESSED_FILES_STATE_KEY = new(nameof(numProcessedFiles)); + private static readonly AssistantSessionStateKey NUM_TOO_LARGE_FILES_STATE_KEY = new(nameof(numTooLargeFiles)); private static readonly AssistantSessionStateKey PAUSE_BEFORE_NEXT_FILE_SECONDS_STATE_KEY = new(nameof(pauseBeforeNextFileSeconds)); /// @@ -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); } diff --git a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Validation.cs b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Validation.cs index bae6eb5e7..905c4f19c 100644 --- a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Validation.cs +++ b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.Validation.cs @@ -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 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(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 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; - } - /// /// 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; } diff --git a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.cs b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.cs index f3f0dddab..0f41497b4 100644 --- a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.cs +++ b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.cs @@ -82,6 +82,7 @@ public partial class AssistantBatchProcessing : AssistantBaseCore fileResults = []; private readonly HashSet usedResultFileNames = new(StringComparer.OrdinalIgnoreCase); + private bool showExpertSettings; private bool isProcessingBatch; private bool hasReportedWriteFailure; private int numProcessedFiles; private int pauseBeforeNextFileSeconds; + /// + /// How many matching files the last search left out for their size, cf. FindInputFiles. + /// + private int numTooLargeFiles; + /// /// The header of the column of the results table that holds the AI answer. /// @@ -159,6 +169,12 @@ public partial class AssistantBatchProcessing : AssistantBaseCore 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.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 '.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." diff --git a/app/MindWork AI Studio/Chat/FileAttachment.cs b/app/MindWork AI Studio/Chat/FileAttachment.cs index 9c68b5e37..a7c42f8cc 100644 --- a/app/MindWork AI Studio/Chat/FileAttachment.cs +++ b/app/MindWork AI Studio/Chat/FileAttachment.cs @@ -96,8 +96,8 @@ public record FileAttachment(FileAttachmentType Type, string FileName, [property } /// - /// Determines the file attachment type based on the file extension. - /// Uses centrally defined file type filters from . + /// 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. /// /// The file path to analyze. /// The corresponding FileAttachmentType. @@ -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; diff --git a/app/MindWork AI Studio/Components/ConfigurationNumber.razor b/app/MindWork AI Studio/Components/ConfigurationNumber.razor new file mode 100644 index 000000000..f3a33a18a --- /dev/null +++ b/app/MindWork AI Studio/Components/ConfigurationNumber.razor @@ -0,0 +1,4 @@ +@typeparam T +@inherits ConfigurationBaseCore + + \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/ConfigurationNumber.razor.cs b/app/MindWork AI Studio/Components/ConfigurationNumber.razor.cs new file mode 100644 index 000000000..0f93f5e51 --- /dev/null +++ b/app/MindWork AI Studio/Components/ConfigurationNumber.razor.cs @@ -0,0 +1,85 @@ +using System.Numerics; + +using Microsoft.AspNetCore.Components; + +namespace AIStudio.Components; + +/// +/// A number typed into a field, for a range too wide for a slider, e.g., a size limit in megabytes. +/// +public partial class ConfigurationNumber : ConfigurationBaseCore where T : struct, INumber, IMinMaxValue +{ + /// + /// The smallest allowed value. + /// + [Parameter] + public T Min { get; set; } = T.MinValue; + + /// + /// The largest allowed value. + /// + [Parameter] + public T Max { get; set; } = T.MaxValue; + + /// + /// The unit to display next to the value. + /// + [Parameter] + public string Unit { get; set; } = string.Empty; + + /// + /// The value used for the field. + /// + [Parameter] + public Func Value { get; set; } = () => T.Zero; + + /// + /// An action which is called when the option is changed. + /// + [Parameter] + public Action ValueUpdate { get; set; } = _ => { }; + + #region Overrides of ConfigurationBase + + /// + protected override bool Stretch => true; + + /// + 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); + } +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/ConfigurationText.razor b/app/MindWork AI Studio/Components/ConfigurationText.razor index feede5e29..8561639f9 100644 --- a/app/MindWork AI Studio/Components/ConfigurationText.razor +++ b/app/MindWork AI Studio/Components/ConfigurationText.razor @@ -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 { - + @* One element, since a locked option places it next to its lock icon: *@ +
- - @this.ResetButtonText - - + +
} \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/ConfigurationText.razor.cs b/app/MindWork AI Studio/Components/ConfigurationText.razor.cs index 3a1f88b18..c2648fb41 100644 --- a/app/MindWork AI Studio/Components/ConfigurationText.razor.cs +++ b/app/MindWork AI Studio/Components/ConfigurationText.razor.cs @@ -19,7 +19,7 @@ public partial class ConfigurationText : ConfigurationBaseCore public Action TextUpdate { get; set; } = _ => { }; /// - /// The icon to display next to the textfield. + /// The icon to display next to the textfield, when it has a single line. /// [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(); diff --git a/app/MindWork AI Studio/Components/DataSourceCloudEmbeddingWarning.razor.cs b/app/MindWork AI Studio/Components/DataSourceCloudEmbeddingWarning.razor.cs index 9f3ae4a2c..584d3dc9c 100644 --- a/app/MindWork AI Studio/Components/DataSourceCloudEmbeddingWarning.razor.cs +++ b/app/MindWork AI Studio/Components/DataSourceCloudEmbeddingWarning.razor.cs @@ -32,12 +32,17 @@ public partial class DataSourceCloudEmbeddingWarning : MSGComponentBase } } + /// + /// 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. + /// 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) diff --git a/app/MindWork AI Studio/Components/DataSourceManagement.razor b/app/MindWork AI Studio/Components/DataSourceManagement.razor index f31322e8c..57766f135 100644 --- a/app/MindWork AI Studio/Components/DataSourceManagement.razor +++ b/app/MindWork AI Studio/Components/DataSourceManagement.razor @@ -42,9 +42,18 @@ @{ var embeddingStatus = embeddingStatuses.GetValueOrDefault(context.Id); } @context.Num - @context.Name - @context.Type.GetDisplayName() - @this.GetEmbeddingName(context) + @* + 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. + *@ + +
@context.Name
+
+ @context.Type.GetDisplayName() + @this.GetEmbeddingName(context) @if (context is IIndexedDataSource) { diff --git a/app/MindWork AI Studio/Components/DataSourceManagement.razor.cs b/app/MindWork AI Studio/Components/DataSourceManagement.razor.cs index 131ce6613..be0ac62fb 100644 --- a/app/MindWork AI Studio/Components/DataSourceManagement.razor.cs +++ b/app/MindWork AI Studio/Components/DataSourceManagement.razor.cs @@ -83,17 +83,21 @@ public partial class DataSourceManagement : MSGComponentBase } /// - /// 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. /// 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, + }; } /// @@ -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) diff --git a/app/MindWork AI Studio/Components/RestoreDefaultButton.razor b/app/MindWork AI Studio/Components/RestoreDefaultButton.razor new file mode 100644 index 000000000..5c64c4dab --- /dev/null +++ b/app/MindWork AI Studio/Components/RestoreDefaultButton.razor @@ -0,0 +1,5 @@ + + + @this.Text + + \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/RestoreDefaultButton.razor.cs b/app/MindWork AI Studio/Components/RestoreDefaultButton.razor.cs new file mode 100644 index 000000000..21ba27ea9 --- /dev/null +++ b/app/MindWork AI Studio/Components/RestoreDefaultButton.razor.cs @@ -0,0 +1,35 @@ +using Microsoft.AspNetCore.Components; + +namespace AIStudio.Components; + +/// +/// A small button below a field, which puts the default value back into that field. +/// +/// +/// 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. +/// +public partial class RestoreDefaultButton : ComponentBase +{ + /// + /// The text on the button, e.g., "Restore default". + /// + [Parameter] + public string Text { get; set; } = string.Empty; + + /// + /// Puts the default value back into the field. + /// + [Parameter] + public EventCallback OnClick { get; set; } + + [Parameter] + public bool Disabled { get; set; } + + /// + /// The CSS classes of the row, e.g., for the space below it. + /// + [Parameter] + public string Class { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryDialog.razor b/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryDialog.razor index 64d99b57a..a228980b3 100644 --- a/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryDialog.razor +++ b/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryDialog.razor @@ -43,7 +43,7 @@ /> - @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.") @if (!this.CanChangeSource) { @@ -71,6 +71,33 @@ /> } + + + + @T("Select the file patterns this data source should index.") + + + + @T("In order for the AI to be able to determine the appropriate data at any time, you must choose an embedding provider.") @@ -121,6 +148,42 @@ +