diff --git a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor index 5639c5886..5639cfbd2 100644 --- a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor +++ b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor @@ -3,7 +3,7 @@ @using AIStudio.Settings.DataModel @using AIStudio.Tools.Rust - + @T("Input") @@ -18,8 +18,13 @@ } - - +
+ + + + + +
@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.") @@ -31,20 +36,22 @@ - - + @T("Instructions") @@ -130,7 +137,7 @@ else } } - + @T("Output") @@ -185,7 +192,7 @@ else @T("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.") - + @T("Processing pace") @@ -226,7 +233,7 @@ else @if (this.fileResults.Count > 0) { - + @T("Progress") diff --git a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.cs b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.cs index 5cedad6e2..5fa06afcd 100644 --- a/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.cs +++ b/app/MindWork AI Studio/Assistants/BatchProcessing/AssistantBatchProcessing.razor.cs @@ -168,8 +168,6 @@ 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; diff --git a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua index 17db92a21..f3d070dc6 100644 --- a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua +++ b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua @@ -409,9 +409,6 @@ 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." @@ -433,9 +430,15 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING -- Please provide a file name without a path, e.g., my-results.csv UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T189587595"] = "Please provide a file name without a path, e.g., my-results.csv" +-- Hidden files and folders +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1902969218"] = "Hidden files and folders" + -- Select the folder containing your documents UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T1926838679"] = "Select the folder containing your documents" +-- Files to include +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2000156297"] = "Files to include" + -- Include subfolders? UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2086334687"] = "Include subfolders?" @@ -481,9 +484,6 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING -- Was not able to read the existing transcript: {0} UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2397111152"] = "Was not able to read the existing transcript: {0}" --- File patterns -UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2460883298"] = "File patterns" - -- Load prompt from file UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T2474257795"] = "Load prompt from file" @@ -532,6 +532,12 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING -- The batch run finished, but one file could not be processed. See the progress table and log for details. UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3201532790"] = "The batch run finished, but one file could not be processed. See the progress table and log for details." +-- Files and folders are hidden if their names start with a dot or the operating system marks them as hidden. If you choose 'No', hidden items are skipped. To explicitly include a file such as .gitignore, enter its name under 'Files to include'. Using generic patterns such as *, :text: or :documents: still skips hidden files. Exclusion rules always take priority; you can change them in the fields below. +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3204694333"] = "Files and folders are hidden if their names start with a dot or the operating system marks them as hidden. If you choose 'No', hidden items are skipped. To explicitly include a file such as .gitignore, enter its name under 'Files to include'. Using generic patterns such as *, :text: or :documents: still skips hidden files. Exclusion rules always take priority; you can change them in the fields below." + +-- File size limit +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3225743883"] = "File size limit" + -- Maximum pause between files UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING::T3250003796"] = "Maximum pause between files" @@ -556,9 +562,6 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::BATCHPROCESSING::ASSISTANTBATCHPROCESSING -- 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'." @@ -592,9 +595,6 @@ 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" @@ -4438,6 +4438,78 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DIRECTCHATLAUNCHERSETTINGSACTION::T244391 -- Change what this tile opens UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DIRECTCHATLAUNCHERSETTINGSACTION::T4272203100"] = "Change what this tile opens" +-- Exclusion help and examples +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEEXCLUSIONEDITOR::T1309128010"] = "Exclusion help and examples" + +-- PDF files, regardless of letter case +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEEXCLUSIONEDITOR::T138823545"] = "PDF files, regardless of letter case" + +-- Folders +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEEXCLUSIONEDITOR::T1412427146"] = "Folders" + +-- the excluded folders +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEEXCLUSIONEDITOR::T1647237555"] = "the excluded folders" + +-- File names starting with draft- +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEEXCLUSIONEDITOR::T1676890987"] = "File names starting with draft-" + +-- Excluded files +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEEXCLUSIONEDITOR::T2590452128"] = "Excluded files" + +-- Folders ending in build, such as build or app-build +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEEXCLUSIONEDITOR::T27471988"] = "Folders ending in build, such as build or app-build" + +-- Excluded files and folders +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEEXCLUSIONEDITOR::T286958948"] = "Excluded files and folders" + +-- Excluded folders +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEEXCLUSIONEDITOR::T3345276250"] = "Excluded folders" + +-- Files +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEEXCLUSIONEDITOR::T3877444400"] = "Files" + +-- Separate patterns with semicolons. Folder patterns must end with /. Exclusions take priority. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEEXCLUSIONEDITOR::T3993888277"] = "Separate patterns with semicolons. Folder patterns must end with /. Exclusions take priority." + +-- the excluded files +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEEXCLUSIONEDITOR::T4083345389"] = "the excluded files" + +-- Exclusion examples +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEEXCLUSIONEDITOR::T727293714"] = "Exclusion examples" + +-- Restore default +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEEXCLUSIONEDITOR::T913168756"] = "Restore default" + +-- Exclude folders ending in build, such as build or app-build +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEPATTERNSELECTION::T1241240542"] = "Exclude folders ending in build, such as build or app-build" + +-- Pattern help and examples +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEPATTERNSELECTION::T1369669520"] = "Pattern help and examples" + +-- Include readable text files, including files without an extension +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEPATTERNSELECTION::T1634513321"] = "Include readable text files, including files without an extension" + +-- File names starting with draft- +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEPATTERNSELECTION::T1676890987"] = "File names starting with draft-" + +-- Pattern examples +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEPATTERNSELECTION::T2430822600"] = "Pattern examples" + +-- Separate patterns with semicolons. Exclusions take priority over included files. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEPATTERNSELECTION::T2728429336"] = "Separate patterns with semicolons. Exclusions take priority over included files." + +-- PDF and Word files +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEPATTERNSELECTION::T3467839719"] = "PDF and Word files" + +-- Patterns match file names regardless of letter case. Folder paths are not supported. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEPATTERNSELECTION::T3691425703"] = "Patterns match file names regardless of letter case. Folder paths are not supported." + +-- Include all files, including audio and video +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEPATTERNSELECTION::T827447634"] = "Include all files, including audio and video" + +-- Include all documents and readable text files +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::FILEPATTERNSELECTION::T967949655"] = "Include all documents and readable text files" + -- LLMs can make mistakes. Check important information. UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::HALLUZINATIONREMINDER::T3528806904"] = "LLMs can make mistakes. Check important information." @@ -6742,6 +6814,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCEERIV1USERNAMEPASSWORDEXPORTDIALOG: -- Cancel UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCEERIV1USERNAMEPASSWORDEXPORTDIALOG::T900713019"] = "Cancel" +-- Folder +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T104168189"] = "Folder" + -- Hide Expert Settings UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1108876344"] = "Hide Expert Settings" @@ -6760,21 +6835,24 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1311820297" -- Selected base directory for this data source UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1312296210"] = "Selected base directory for this data source" +-- MindWork AI Studio uses Pandoc to read HTML files. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T133018120"] = "MindWork AI Studio uses Pandoc to read HTML files." + -- 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." +-- Provider trust +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T148137342"] = "Provider trust" + -- 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" @@ -6790,6 +6868,15 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1827669611" -- Update UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1847791252"] = "Update" +-- Hidden files and folders +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T1902969218"] = "Hidden files and folders" + +-- Files to include +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2000156297"] = "Files to include" + +-- Data source +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2034620186"] = "Data source" + -- Include subfolders? UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2086334687"] = "Include subfolders?" @@ -6805,8 +6892,8 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T236253137"] -- 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" +-- Search results +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2499087427"] = "Search results" -- Add UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2646845972"] = "Add" @@ -6820,6 +6907,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2814869210" -- Embedding UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2838542994"] = "Embedding" +-- Choose an embedding provider to make this data source searchable. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2861534545"] = "Choose an embedding provider to make this data source searchable." + -- Excluded files and folders UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T286958948"] = "Excluded files and folders" @@ -6829,39 +6919,42 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T2961294165" -- Audio and video files which this data source selects are skipped, because your transcription provider does not meet the confidence level this data source requires. UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3017942214"] = "Audio and video files which this data source selects are skipped, because your transcription provider does not meet the confidence level this data source requires." +-- Text chunking +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3105524153"] = "Text chunking" + -- Audio and video files which this data source selects are skipped until you choose a transcription provider in the settings. UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3119708878"] = "Audio and video files which this data source selects are skipped until you choose a transcription provider in the settings." +-- Files and folders are hidden if their names start with a dot or the operating system marks them as hidden. If you choose 'No', hidden items are skipped. To explicitly include a file such as .gitignore, enter its name under 'Files to include'. Using generic patterns such as *, :text: or :documents: still skips hidden files. Exclusion rules always take priority; you can change them in the fields below. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3204694333"] = "Files and folders are hidden if their names start with a dot or the operating system marks them as hidden. If you choose 'No', hidden items are skipped. To explicitly include a file such as .gitignore, enter its name under 'Files to include'. Using generic patterns such as *, :text: or :documents: still skips hidden files. Exclusion rules always take priority; you can change them in the fields below." + +-- File size limit +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3225743883"] = "File size 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." +-- Only providers with this confidence level or higher may receive and process data from this data source. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T3755939304"] = "Only providers with this confidence level or higher may receive and process data from this data source." -- Select the base directory UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T562479068"] = "Select the base directory" --- 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. Audio and video files, e.g., *.mp3 or *.mp4, are transcribed by your transcription provider. -UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T599406584"] = "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. Audio and video files, e.g., *.mp3 or *.mp4, are transcribed by your transcription provider." - -- Yes, index hidden files and folders as well UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T607153623"] = "Yes, index hidden files and folders as well" +-- Restore default patterns +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYDIALOG::T7425959"] = "Restore default patterns" + -- 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})." @@ -6913,6 +7006,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T1725856 -- 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." +-- Files to include +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2000156297"] = "Files to include" + -- the file patterns UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2013714981"] = "the file patterns" @@ -6925,9 +7021,6 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2333573 -- 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" @@ -6940,9 +7033,6 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T2658359 -- 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." @@ -6982,9 +7072,6 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3818527 -- Path UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALDIRECTORYINFODIALOG::T3949388886"] = "Path" --- 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." @@ -7000,9 +7087,15 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T1133561850"] = " -- Default tokenizer UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T1220918127"] = "Default tokenizer" +-- MindWork AI Studio uses Pandoc to read HTML files. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T133018120"] = "MindWork AI Studio uses Pandoc to read HTML files." + -- No embedding selected UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T1359179968"] = "No embedding selected" +-- Provider trust +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T148137342"] = "Provider trust" + -- Number of tokens repeated at the start of the next chunk. The default overlap is {0} tokens. UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T1588814044"] = "Number of tokens repeated at the start of the next chunk. The default overlap is {0} tokens." @@ -7021,6 +7114,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T1827669611"] = " -- Update UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T1847791252"] = "Update" +-- Data source +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T2034620186"] = "Data source" + -- The overlap must be smaller than the effective token limit. UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T2101951526"] = "The overlap must be smaller than the effective token limit." @@ -7033,6 +7129,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T2406580478"] = " -- This audio or video file is skipped, because your transcription provider does not meet the confidence level this data source requires. UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T2468760910"] = "This audio or video file is skipped, because your transcription provider does not meet the confidence level this data source requires." +-- Search results +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T2499087427"] = "Search results" + -- Add UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T2646845972"] = "Add" @@ -7045,26 +7144,32 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T2838542994"] = " -- Describe what data this file contains to help the AI select it. UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T2859265837"] = "Describe what data this file contains to help the AI select it." +-- Choose an embedding provider to make this data source searchable. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T2861534545"] = "Choose an embedding provider to make this data source searchable." + -- Token limit UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T2961294165"] = "Token limit" +-- Text chunking +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T3105524153"] = "Text chunking" + -- Please enter 0 or a positive overlap length. UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T3242265813"] = "Please enter 0 or a positive overlap length." --- For some data types, such as Office files, MindWork AI Studio requires the open-source application Pandoc. -UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::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::DATASOURCELOCALFILEDIALOG::T3361153305"] = "Show Expert Settings" -- Select the file UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T3740148848"] = "Select the file" +-- Only providers with this confidence level or higher may receive and process data from this data source. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T3755939304"] = "Only providers with this confidence level or higher may receive and process data from this data source." + -- This audio or video file is skipped until you choose a transcription provider in the settings. UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T4026150982"] = "This audio or video file is skipped until you choose a transcription provider in the settings." --- 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::DATASOURCELOCALFILEDIALOG::T529871858"] = "In order for the AI to be able to determine the appropriate data at any time, you must choose an embedding provider." +-- File +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T723007075"] = "File" -- The data source token limit must not be larger than the embedding provider token limit ({0}). UI_TEXT_CONTENT["AISTUDIO::DIALOGS::DATASOURCELOCALFILEDIALOG::T787118522"] = "The data source token limit must not be larger than the embedding provider token limit ({0})." @@ -8599,9 +8704,6 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T15 -- 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" @@ -8614,9 +8716,15 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T17 -- Batch processing options are preselected UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T1893713430"] = "Batch processing options are preselected" +-- Hidden files and folders +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T1902969218"] = "Hidden files and folders" + -- Default custom column separator UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T19367494"] = "Default custom column separator" +-- Files to include +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T2000156297"] = "Files to include" + -- Default document analysis policy UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T2015391667"] = "Default document analysis policy" @@ -8641,9 +8749,6 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T24 -- 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." --- Separate multiple file patterns with a semicolon, e.g., *.pdf;*.docx. The standard patterns include all supported audio and video formats. -UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T2594325620"] = "Separate multiple file patterns with a semicolon, e.g., *.pdf;*.docx. The standard patterns include all supported audio and video formats." - -- Subfolders are included UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T2607092632"] = "Subfolders are included" @@ -8665,9 +8770,6 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T28 -- 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::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T2908365499"] = "Please enter exactly one punctuation or symbol character. Letters, numbers, spaces, quotation marks, and line breaks cannot be used as CSV separators." --- Default file patterns -UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T2909693903"] = "Default file patterns" - -- Only the selected folder is processed UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T2958253681"] = "Only the selected folder is processed" @@ -8683,6 +8785,12 @@ 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." +-- Files and folders are hidden if their names start with a dot or the operating system marks them as hidden. If you choose 'No', hidden items are skipped. To explicitly include a file such as .gitignore, enter its name under 'Files to include'. Using generic patterns such as *, :text: or :documents: still skips hidden files. Exclusion rules always take priority; you can change them in the fields below. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T3204694333"] = "Files and folders are hidden if their names start with a dot or the operating system marks them as hidden. If you choose 'No', hidden items are skipped. To explicitly include a file such as .gitignore, enter its name under 'Files to include'. Using generic patterns such as *, :text: or :documents: still skips hidden files. Exclusion rules always take priority; you can change them in the fields below." + +-- File size limit +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T3225743883"] = "File size limit" + -- Ignore files larger than UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGBATCHPROCESSING::T3353866230"] = "Ignore files larger than" @@ -8713,9 +8821,6 @@ 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" @@ -12382,6 +12487,12 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T599774443"] = "The -- policy files UI_TEXT_CONTENT["AISTUDIO::TOOLS::EXTERNALHTTPCLIENTTIMEOUT::T632340680"] = "policy files" +-- Enter folder patterns ending with / in 'Folders'. File patterns must not end with /. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXCLUSIONS::T2019378403"] = "Enter folder patterns ending with / in 'Folders'. File patterns must not end with /." + +-- Folder patterns must end with /, e.g., build/. Enter file patterns such as *.pdf in 'Files'. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILEEXCLUSIONS::T2695719308"] = "Folder patterns must end with /, e.g., build/. Enter file patterns such as *.pdf in '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/." @@ -12607,9 +12718,6 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::FILENAMEPATTERNS::T2207479763"] = "One of the -- 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." diff --git a/app/MindWork AI Studio/Components/ConfigurationFileExclusions.razor b/app/MindWork AI Studio/Components/ConfigurationFileExclusions.razor new file mode 100644 index 000000000..bbea9399c --- /dev/null +++ b/app/MindWork AI Studio/Components/ConfigurationFileExclusions.razor @@ -0,0 +1,3 @@ +@inherits ConfigurationText + + diff --git a/app/MindWork AI Studio/Components/ConfigurationFileExclusions.razor.cs b/app/MindWork AI Studio/Components/ConfigurationFileExclusions.razor.cs new file mode 100644 index 000000000..569439679 --- /dev/null +++ b/app/MindWork AI Studio/Components/ConfigurationFileExclusions.razor.cs @@ -0,0 +1,17 @@ +using Microsoft.AspNetCore.Components; + +namespace AIStudio.Components; + +/// +/// Reuses ConfigurationText's persistence, validation, reset, and organization locks with the +/// shared exclusion editor. The editor supplies its own outlined fields and heading. +/// +public partial class ConfigurationFileExclusions : ConfigurationText +{ + [Parameter] + public bool ShowHelp { get; set; } = true; + + protected override Variant Variant => Variant.Text; + + protected override string Label => string.Empty; +} diff --git a/app/MindWork AI Studio/Components/ConfigurationText.razor b/app/MindWork AI Studio/Components/ConfigurationText.razor index 8561639f9..6ea70c8f2 100644 --- a/app/MindWork AI Studio/Components/ConfigurationText.razor +++ b/app/MindWork AI Studio/Components/ConfigurationText.razor @@ -4,7 +4,7 @@ { - + @if (!this.ResetButtonIconOnly) + { + + } } \ 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 c2648fb41..70e954f6b 100644 --- a/app/MindWork AI Studio/Components/ConfigurationText.razor.cs +++ b/app/MindWork AI Studio/Components/ConfigurationText.razor.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Web; using Timer = System.Timers.Timer; @@ -24,6 +25,18 @@ public partial class ConfigurationText : ConfigurationBaseCore [Parameter] public string Icon { get; set; } = Icons.Material.Filled.Info; + /// + /// Removes the default bottom margin when the field is part of a compact group. + /// + [Parameter] + public bool Compact { get; set; } + + /// + /// Wraps and grows to show the full text, including while the field is not focused. + /// + [Parameter] + public bool ExpandToContent { get; set; } + /// /// The color of the icon to use. /// @@ -54,6 +67,12 @@ public partial class ConfigurationText : ConfigurationBaseCore [Parameter] public string ResetButtonText { get; set; } = string.Empty; + /// + /// Uses an accessible reset icon inside the field. + /// + [Parameter] + public bool ResetButtonIconOnly { get; set; } + /// /// Validates the configured text before it is stored. /// @@ -61,10 +80,14 @@ public partial class ConfigurationText : ConfigurationBaseCore public Func? Validation { get; set; } private string internalText = string.Empty; + private string? lastSourceText; + private readonly Timer timer = new(TimeSpan.FromMilliseconds(500)) { AutoReset = false }; + + protected string EditingText => this.internalText; #region Overrides of ConfigurationBase @@ -72,6 +95,8 @@ public partial class ConfigurationText : ConfigurationBaseCore protected override bool Stretch => true; protected override Variant Variant => Variant.Outlined; + + protected override string MarginClass => this.Compact ? "mb-0" : base.MarginClass; protected override string Label => this.OptionDescription; @@ -83,15 +108,24 @@ public partial class ConfigurationText : ConfigurationBaseCore protected override async Task OnParametersSetAsync() { - this.internalText = this.Text(); + var sourceText = this.Text(); + // Re-rendering the parent must not replace a draft which is waiting for its debounce. + // A genuinely changed setting, e.g. from a configuration plugin, still replaces it. + if (this.IsDisabled || !string.Equals(sourceText, this.lastSourceText, StringComparison.Ordinal)) + { + this.internalText = sourceText; + this.lastSourceText = sourceText; + } await base.OnParametersSetAsync(); } #endregion - private bool AutoGrow => this.NumLines > 1; + private bool AutoGrow => this.ExpandToContent || this.NumLines > 1; - private int GetMaxLines => this.AutoGrow ? this.MaxLines : 1; + private int GetMaxLines => this.ExpandToContent ? 0 : this.AutoGrow ? this.MaxLines : 1; + + private string InputClass => this.ExpandToContent ? "pattern-text-field" : string.Empty; // // MudBlazor centers the icon vertically, so in a field of several lines it floats in the middle @@ -99,29 +133,50 @@ public partial class ConfigurationText : ConfigurationBaseCore // private Adornment IconAdornment => this.NumLines == 1 ? Adornment.Start : Adornment.None; - private void InternalUpdate(string text) + protected void InternalUpdate(string text) { + if (this.IsDisabled) + return; + this.timer.Stop(); this.internalText = text; this.timer.Start(); } - private async Task ResetTextAsync() + private EventCallback ResetAdornmentClick => this.ResetButtonIconOnly + ? EventCallback.Factory.Create(this, this.ResetTextAsync) + : default; + + protected async Task ResetTextAsync() { if (this.ResetValue is null || this.IsDisabled) return; + await this.ApplyTextAsync(this.ResetValue()); + } + + /// + /// Applies an explicit value immediately, including a reset of part of a compound setting. + /// + protected async Task ApplyTextAsync(string text) + { + if (this.IsDisabled) + return; + this.timer.Stop(); - this.internalText = this.ResetValue(); + this.internalText = text; await this.OptionChanged(this.internalText); } - private async Task OptionChanged(string updatedText) + protected async Task OptionChanged(string updatedText) { - if (this.Validation?.Invoke(updatedText) is not null) + if (this.IsDisabled || this.Validation?.Invoke(updatedText) is not null) return; this.TextUpdate(updatedText); + // A save may finish after another keystroke. Remember the value it applied before + // awaiting storage, so its configuration-change notification cannot erase that keystroke. + this.lastSourceText = this.Text(); await this.SettingsManager.StoreSettings(); await this.InformAboutChange(); } diff --git a/app/MindWork AI Studio/Components/FileExclusionEditor.razor b/app/MindWork AI Studio/Components/FileExclusionEditor.razor new file mode 100644 index 000000000..8da883f40 --- /dev/null +++ b/app/MindWork AI Studio/Components/FileExclusionEditor.razor @@ -0,0 +1,46 @@ +@inherits MSGComponentBase + +
+ @if (this.ShowHeader || this.ShowHelp) + { + + @if (this.ShowHeader) + { + @this.EditorLabel + } + @if (this.ShowHelp) + { + + + + } + + } + + + @if (this.ReadOnly) + { + + + } + else + { + + + } + + + @if (!this.ReadOnly) + { + @T("Separate patterns with semicolons. Folder patterns must end with /. Exclusions take priority.") + } + + + + *.pdf@T("PDF files, regardless of letter case") + draft-*@T("File names starting with draft-") + *build/@T("Folders ending in build, such as build or app-build") + + + +
diff --git a/app/MindWork AI Studio/Components/FileExclusionEditor.razor.cs b/app/MindWork AI Studio/Components/FileExclusionEditor.razor.cs new file mode 100644 index 000000000..5f8ede4f7 --- /dev/null +++ b/app/MindWork AI Studio/Components/FileExclusionEditor.razor.cs @@ -0,0 +1,118 @@ +using Microsoft.AspNetCore.Components; + +namespace AIStudio.Components; + +/// +/// A compact, two-group editor for the exclusion string shared by folder-based features. +/// +public partial class FileExclusionEditor : MSGComponentBase +{ + private static readonly Dictionary INPUT_ATTRIBUTES = new() + { + ["spellcheck"] = false, + ["autocorrect"] = "off", + ["autocapitalize"] = "off", + }; + + [Parameter] + public string? Text { get; set; } = string.Empty; + + [Parameter] + public EventCallback TextChanged { get; set; } + + [Parameter] + public string Label { get; set; } = string.Empty; + + [Parameter] + public bool Disabled { get; set; } + + /// + /// Displays both groups with copy buttons instead of editing and reset controls. + /// + [Parameter] + public bool ReadOnly { get; set; } + + [Parameter] + public bool ShowReset { get; set; } = true; + + [Parameter] + public bool ShowHelp { get; set; } = true; + + [Parameter] + public bool ShowHeader { get; set; } = true; + + [Parameter] + public string ResetValue { get; set; } = FileExclusions.DEFAULT_PATTERNS; + + [Parameter] + public string ResetButtonText { get; set; } = string.Empty; + + /// + /// Immediately persists the combined value after restoring just one of its groups. + /// Ordinary edits continue through TextChanged. + /// + [Parameter] + public EventCallback ResetRequested { get; set; } + + private readonly FileExclusionEditorState state = new(); + private readonly string folderInputId = $"exclusion-folders-{Guid.NewGuid():N}"; + private readonly string fileInputId = $"exclusion-files-{Guid.NewGuid():N}"; + private bool showHelp; + + private string EditorLabel => string.IsNullOrWhiteSpace(this.Label) ? T("Excluded files and folders") : this.Label; + + private string RestoreLabel => string.IsNullOrWhiteSpace(this.ResetButtonText) ? T("Restore default") : this.ResetButtonText; + + private string FolderRestoreLabel => $"{this.RestoreLabel}: {T("Folders")}"; + + private string FileRestoreLabel => $"{this.RestoreLabel}: {T("Files")}"; + + protected override void OnParametersSet() + { + this.state.Receive(this.Text, discardDraft: this.Disabled || this.ReadOnly); + base.OnParametersSet(); + } + + protected Task ChangeFoldersAsync(string text) => this.ChangePatternsAsync(text, folders: true); + + protected Task ChangeFilesAsync(string text) => this.ChangePatternsAsync(text, folders: false); + + private async Task ChangePatternsAsync(string text, bool folders) + { + if (this.Disabled || this.ReadOnly) + return; + + var previousText = this.state.Text; + var wasValid = this.state.IsValid; + if (folders) + this.state.EditFolders(text); + else + this.state.EditFiles(text); + + // Moving a rule to the correct field can keep the combined text identical. It must still + // publish the now-valid draft, because the previous, invalid arrangement was not sent. + if (this.state.IsValid && (!wasValid || !string.Equals(previousText, this.state.Text, StringComparison.Ordinal))) + await this.TextChanged.InvokeAsync(this.state.Text); + } + + protected async Task RestoreDefaultsAsync(bool folders) + { + if (this.Disabled || this.ReadOnly || !this.ShowReset) + return; + + if (folders) + this.state.RestoreFolders(this.ResetValue); + else + this.state.RestoreFiles(this.ResetValue); + + if (!this.state.IsValid) + return; + + if (this.ResetRequested.HasDelegate) + await this.ResetRequested.InvokeAsync(this.state.Text); + else + await this.TextChanged.InvokeAsync(this.state.Text); + } + + private void ToggleHelp() => this.showHelp = !this.showHelp; +} diff --git a/app/MindWork AI Studio/Components/FileExclusionEditorState.cs b/app/MindWork AI Studio/Components/FileExclusionEditorState.cs new file mode 100644 index 000000000..b338200e3 --- /dev/null +++ b/app/MindWork AI Studio/Components/FileExclusionEditorState.cs @@ -0,0 +1,89 @@ +namespace AIStudio.Components; + +/// +/// Presents the existing exclusion string as two editable groups without losing the other group +/// or letting delayed parameter echoes overwrite newer edits. +/// +internal sealed class FileExclusionEditorState +{ + private const string PATTERN_SEPARATOR = "; "; + + private string? receivedText; + private readonly HashSet pendingValues = new(StringComparer.Ordinal); + + public string Text { get; private set; } = string.Empty; + + public string FolderText { get; private set; } = string.Empty; + + public string FileText { get; private set; } = string.Empty; + + public bool IsValid => FileExclusions.IsValidFolders(this.FolderText) && FileExclusions.IsValidFiles(this.FileText); + + public bool Receive(string? text, bool discardDraft = false) + { + text ??= string.Empty; + if (discardDraft) + { + var changed = !string.Equals(text, this.Text, StringComparison.Ordinal); + this.receivedText = text; + this.Reset(text); + return changed; + } + + if (string.Equals(text, this.receivedText, StringComparison.Ordinal)) + return false; + + this.receivedText = text; + if (string.Equals(text, this.Text, StringComparison.Ordinal)) + { + this.pendingValues.Clear(); + return false; + } + + if (this.pendingValues.Remove(text)) + return false; + + this.Reset(text); + return true; + } + + public void Reset(string text) + { + this.pendingValues.Clear(); + this.Text = text; + this.Regroup(); + } + + public void EditFolders(string? text) + { + this.FolderText = text ?? string.Empty; + this.UpdateText(); + } + + public void EditFiles(string? text) + { + this.FileText = text ?? string.Empty; + this.UpdateText(); + } + + public void RestoreFolders(string defaults) => this.EditFolders(string.Join(PATTERN_SEPARATOR, FileExclusions.Parse(defaults).Where(IsFolder))); + + public void RestoreFiles(string defaults) => this.EditFiles(string.Join(PATTERN_SEPARATOR, FileExclusions.Parse(defaults).Where(pattern => !IsFolder(pattern)))); + + private void Regroup() + { + var patterns = FileExclusions.Parse(this.Text); + this.FolderText = string.Join(PATTERN_SEPARATOR, patterns.Where(IsFolder)); + this.FileText = string.Join(PATTERN_SEPARATOR, patterns.Where(pattern => !IsFolder(pattern))); + } + + private static bool IsFolder(string pattern) => pattern.EndsWith(FileExclusions.FOLDER_SUFFIX); + + private void UpdateText() + { + this.Text = string.Join(PATTERN_SEPARATOR, FileExclusions.Parse(this.FolderText) + .Concat(FileExclusions.Parse(this.FileText)) + .Distinct(StringComparer.OrdinalIgnoreCase)); + this.pendingValues.Add(this.Text); + } +} diff --git a/app/MindWork AI Studio/Components/FilePatternSelection.razor b/app/MindWork AI Studio/Components/FilePatternSelection.razor new file mode 100644 index 000000000..3e483d8e1 --- /dev/null +++ b/app/MindWork AI Studio/Components/FilePatternSelection.razor @@ -0,0 +1,42 @@ +@inherits MSGComponentBase + + +
+
+ @this.AllowedContent +
+ + + +
+ @if (this.HasExclusions) + { +
+
+ @this.ExcludedContent +
+
+ } + +
+ + @T("Pattern examples") + @T("Separate patterns with semicolons. Exclusions take priority over included files.") + + + *.pdf;*.docx@T("PDF and Word files") + :documents:@T("Include all documents and readable text files") + *@T("Include all files, including audio and video") + :text:@T("Include readable text files, including files without an extension") + draft-*@T("File names starting with draft-") + @if (this.HasExclusions) + { + *build/@T("Exclude folders ending in build, such as build or app-build") + } + + + @T("Patterns match file names regardless of letter case. Folder paths are not supported.") + +
+
+
diff --git a/app/MindWork AI Studio/Components/FilePatternSelection.razor.cs b/app/MindWork AI Studio/Components/FilePatternSelection.razor.cs new file mode 100644 index 000000000..4c8735d79 --- /dev/null +++ b/app/MindWork AI Studio/Components/FilePatternSelection.razor.cs @@ -0,0 +1,28 @@ +using Microsoft.AspNetCore.Components; + +namespace AIStudio.Components; + +/// +/// A file-pattern field with shared, collapsible help and optional, always-visible exclusions. +/// Callers supply their existing fields, preserving validation and managed-configuration locks. +/// +public partial class FilePatternSelection : MSGComponentBase +{ + private const string PATTERN_ROW_STYLE = "display: grid; grid-template-columns: minmax(0, 1fr) 48px; column-gap: 8px; align-items: center;"; + + [Parameter, EditorRequired] + public RenderFragment AllowedContent { get; set; } = null!; + + /// + /// When supplied, shows the existing exclusion field below the inclusion field. + /// Both groups stay visible and use the same help control. + /// + [Parameter] + public RenderFragment? ExcludedContent { get; set; } + + internal bool HasExclusions => this.ExcludedContent is not null; + + private bool showHelp; + + private void ToggleHelp() => this.showHelp = !this.showHelp; +} diff --git a/app/MindWork AI Studio/Components/ManagePandocDependency.razor b/app/MindWork AI Studio/Components/ManagePandocDependency.razor index 7208b1c45..3a614bf11 100644 --- a/app/MindWork AI Studio/Components/ManagePandocDependency.razor +++ b/app/MindWork AI Studio/Components/ManagePandocDependency.razor @@ -1,10 +1,13 @@ @inherits MSGComponentBase - - - @this.DetermineIntroText() - - - @this.DetermineButtonText() - - \ No newline at end of file +@if (ShouldShowInstallationPrompt(this.pandocInstallation)) +{ + + + @this.DetermineIntroText() + + + @this.DetermineButtonText() + + +} diff --git a/app/MindWork AI Studio/Components/ManagePandocDependency.razor.cs b/app/MindWork AI Studio/Components/ManagePandocDependency.razor.cs index 886b1ff4d..d05c8e7d3 100644 --- a/app/MindWork AI Studio/Components/ManagePandocDependency.razor.cs +++ b/app/MindWork AI Studio/Components/ManagePandocDependency.razor.cs @@ -18,7 +18,10 @@ public partial class ManagePandocDependency : MSGComponentBase [Inject] private RustService RustService { get; init; } = null!; - private PandocInstallation pandocInstallation; + // Null means the silent availability check has not completed yet. + private PandocInstallation? pandocInstallation; + + internal static bool ShouldShowInstallationPrompt(PandocInstallation? installation) => installation is { IsAvailable: false }; #region Overrides of MSGComponentBase @@ -32,10 +35,10 @@ public partial class ManagePandocDependency : MSGComponentBase private Color DetermineButtonColor() { - if (this.pandocInstallation == default) + if (this.pandocInstallation is null) return Color.Default; - switch (this.pandocInstallation) + switch (this.pandocInstallation.Value) { case { CheckWasSuccessful: true, IsAvailable: true }: return Color.Default; @@ -50,10 +53,10 @@ public partial class ManagePandocDependency : MSGComponentBase private string DetermineButtonText() { - if(this.pandocInstallation == default) + if(this.pandocInstallation is null) return T("Please wait while we check the availability of Pandoc."); - switch (this.pandocInstallation) + switch (this.pandocInstallation.Value) { case { CheckWasSuccessful: true, IsAvailable: true }: return T("Check your Pandoc installation"); @@ -68,10 +71,10 @@ public partial class ManagePandocDependency : MSGComponentBase private string DetermineIntroText() { - if (this.pandocInstallation == default) + if (this.pandocInstallation is null) return $"{this.IntroText} {T("Please wait while we check the availability of Pandoc.")}"; - switch (this.pandocInstallation) + switch (this.pandocInstallation.Value) { case { CheckWasSuccessful: true, IsAvailable: true }: return $"{this.IntroText} {T("Your Pandoc installation meets the requirements.")}"; diff --git a/app/MindWork AI Studio/Components/TextInfoLines.razor b/app/MindWork AI Studio/Components/TextInfoLines.razor index a6a8e824c..b5ed3923f 100644 --- a/app/MindWork AI Studio/Components/TextInfoLines.razor +++ b/app/MindWork AI Studio/Components/TextInfoLines.razor @@ -7,9 +7,11 @@ Text="@this.Value" Variant="Variant.Outlined" Margin="Margin.Dense" - Lines="3" + Lines="@this.Lines" MaxLines="@this.MaxLines" AutoGrow="@true" + Adornment="@(string.IsNullOrEmpty(this.Icon) ? Adornment.None : Adornment.Start)" + AdornmentIcon="@this.Icon" Style="@this.GetColor()" UserAttributes="@USER_INPUT_ATTRIBUTES" /> diff --git a/app/MindWork AI Studio/Components/TextInfoLines.razor.cs b/app/MindWork AI Studio/Components/TextInfoLines.razor.cs index e33a78ee7..f143ddef5 100644 --- a/app/MindWork AI Studio/Components/TextInfoLines.razor.cs +++ b/app/MindWork AI Studio/Components/TextInfoLines.razor.cs @@ -9,6 +9,9 @@ public partial class TextInfoLines : MSGComponentBase [Parameter] public string Label { get; set; } = string.Empty; + [Parameter] + public string Icon { get; set; } = string.Empty; + [Parameter] public string Value { get; set; } = string.Empty; @@ -18,6 +21,9 @@ public partial class TextInfoLines : MSGComponentBase [Parameter] public int MaxLines { get; set; } = 30; + [Parameter] + public int Lines { get; set; } = 3; + [Parameter] public bool ShowingCopyButton { get; set; } = true; diff --git a/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryDialog.razor b/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryDialog.razor index d152c99e2..f5872dafa 100644 --- a/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryDialog.razor +++ b/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryDialog.razor @@ -10,12 +10,15 @@ + + @T("Data source") + @* ReSharper disable once CSharpWarnings::CS8974 *@ - + + @T("Folder") + + @T("Select a root directory for this data source.") @if (!this.CanChangeSource) @@ -81,28 +87,42 @@ LabelOff="@T("No, only index files in the selected folder")" /> - + + @T("Files to include") + + @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.") - + + @T("Embedding") + + + @T("Choose an embedding provider to make this data source searchable.") + @foreach (var provider in this.SettingsManager.GetAllEmbeddingProviders()) { @@ -118,14 +138,17 @@ } else if (!string.IsNullOrWhiteSpace(this.dataEmbeddingId)) { - + @T("The embedding you selected runs locally or in your organization. Your data is not sent to the cloud.") } - + - + + @T("Provider trust") + + @foreach (var level in this.ConfidenceLevels) { @@ -147,31 +170,21 @@ + @T("Hidden files and folders")