Added the choice between formal and informal address to the whole app (#1200)

This commit is contained in:
Thorsten Sommer authored and GitHub committed 2026-11-13 10:16:56 +01:00
1 parent 382db4b8d0
commit c9a376f742
342 files changed
+14378 -1893

No files matched your search

@@ -18,6 +18,8 @@ namespace AIStudio.Agents.AssistantAudit;
public sealed class AssistantAuditAgent(ILogger<AssistantAuditAgent> logger, ILogger<AgentBase> baseLogger, SettingsManager settingsManager, DataSourceService dataSourceService, ToolRegistry toolRegistry, ThreadSafeRandom rng) : AgentBase(baseLogger, settingsManager, dataSourceService, rng)
{
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(AssistantAuditAgent).Namespace, nameof(AssistantAuditAgent));
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(AssistantAuditAgent).Namespace, nameof(AssistantAuditAgent));
protected override Type Type => Type.SYSTEM;
@@ -167,7 +169,7 @@ public sealed class AssistantAuditAgent(ILogger<AssistantAuditAgent> logger, ILo
//
var wasFallbackRejected = fallbackProvider is { UsedLLMProvider: not LLMProviders.NONE };
var message = wasFallbackRejected
? TB("The selected provider is not trusted enough for security checks. Pick one which meets the confidence required here, or choose a dedicated provider for security checks in the app settings.")
? TA("The selected provider is not trusted enough for security checks. Pick one which meets the confidence required here, or choose a dedicated provider for security checks in the app settings.")
: TB("No provider is configured for the Security Audit Agent.");
await MessageBus.INSTANCE.SendError(new (AppIcons.AGENT, message));
@@ -270,7 +272,7 @@ public sealed class AssistantAuditAgent(ILogger<AssistantAuditAgent> logger, ILo
if (response.Content is not ContentText content || string.IsNullOrWhiteSpace(content.Text))
{
logger.LogWarning($"The assistant plugin audit agent did not return text: {response}");
await MessageBus.INSTANCE.SendWarning(new (AppIcons.AUDIT_INCOMPLETE, string.Format(TB("The security check could not be completed because the LLM's response was unusable. The audit level remains Unknown, so please try again later."))));
await MessageBus.INSTANCE.SendWarning(new (AppIcons.AUDIT_INCOMPLETE, string.Format(TA("The security check could not be completed because the LLM's response was unusable. The audit level remains Unknown, so please try again later."))));
return new AssistantAuditResult
{
@@ -1,10 +1,10 @@
@attribute [Route(Routes.ASSISTANT_AGENDA)]
@inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogAgenda>
<MudTextField T="string" @bind-Text="@this.inputName" Validation="@this.ValidateName" Label="@T("Meeting Name")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.NAME" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("Name the meeting, seminar, etc.")" Placeholder="@T("Weekly jour fixe")" Class="mb-3"/>
<MudTextField T="string" @bind-Text="@this.inputTopic" Validation="@this.ValidateTopic" Label="@T("Topic")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.MEETING_TOPIC" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("Describe the topic of the meeting, seminar, etc. Is it about quantum computing, software engineering, or is it a general business meeting?")" Placeholder="@T("Project meeting")" Class="mb-3"/>
<MudTextField T="string" @bind-Text="@this.inputName" Validation="@this.ValidateName" Label="@T("Meeting Name")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.NAME" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@TA("Name the meeting, seminar, etc.")" Placeholder="@T("Weekly jour fixe")" Class="mb-3"/>
<MudTextField T="string" @bind-Text="@this.inputTopic" Validation="@this.ValidateTopic" Label="@T("Topic")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.MEETING_TOPIC" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@TA("Describe the topic of the meeting, seminar, etc. Is it about quantum computing, software engineering, or is it a general business meeting?")" Placeholder="@T("Project meeting")" Class="mb-3"/>
<ReadFileContent Text="@T("Load the content list from file")" FileContent="@this.inputContent" FileContentChanged="@this.ContentLoadedFromFile" EnableDragDrop="true"/>
<DebouncedTextField @bind-Text="@this.inputContent" ValidationFunc="@this.ValidateContent" DebounceTime="TimeSpan.FromSeconds(1)" Label="@T("Content list")" Lines="6" Attributes="@USER_INPUT_ATTRIBUTES" HelpText="@T("Bullet list the content of the meeting, seminar, etc. roughly. Use dashes (-) to separate the items.")" Placeholder="@PLACEHOLDER_CONTENT" WhenTextCanged="@this.OnContentChanged" Icon="@AppIcons.LIST"/>
<DebouncedTextField @bind-Text="@this.inputContent" ValidationFunc="@this.ValidateContent" DebounceTime="TimeSpan.FromSeconds(1)" Label="@T("Content list")" Lines="6" Attributes="@USER_INPUT_ATTRIBUTES" HelpText="@TA("Bullet list the content of the meeting, seminar, etc. roughly. Use dashes (-) to separate the items.")" Placeholder="@PLACEHOLDER_CONTENT" WhenTextCanged="@this.OnContentChanged" Icon="@AppIcons.LIST"/>
<MudSelect T="string" Label="@T("(Optional) What topics should be the focus?")" MultiSelection="@true" @bind-SelectedValues="@this.selectedFoci" Variant="Variant.Outlined" Class="mb-3" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.LIST">
@foreach (var contentLine in this.contentLines)
{
@@ -29,11 +29,11 @@
}
</MudSelect>
<MudTextField T="string" @bind-Text="@this.inputObjective" Validation="@this.ValidateObjective" Label="@T("Objective")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.OBJECTIVE" Variant="Variant.Outlined" Lines="3" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("Describe the objective(s) of the meeting, seminar, etc. What should be achieved?")" Placeholder="@T("Discuss the current project status and plan the next steps.")" Class="mb-3"/>
<MudTextField T="string" @bind-Text="@this.inputObjective" Validation="@this.ValidateObjective" Label="@T("Objective")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.OBJECTIVE" Variant="Variant.Outlined" Lines="3" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@TA("Describe the objective(s) of the meeting, seminar, etc. What should be achieved?")" Placeholder="@TA("Discuss the current project status and plan the next steps.")" Class="mb-3"/>
<MudTextField T="string" @bind-Text="@this.inputModerator" Validation="@this.ValidateModerator" Label="@T("Moderator")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.MODERATOR" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("Who will moderate the meeting, seminar, etc.?")" Placeholder="Jane Doe" Class="mb-3" />
<MudTextField T="string" @bind-Text="@this.inputDuration" Validation="@this.ValidateDuration" Label="@T("Duration")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.TIME" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("How long will the meeting, seminar, etc. last? E.g., '2 hours', or '2 days (first day 8 hours, then 4 hours)', etc.")" Placeholder="@T("2 hours")" Class="mb-3"/>
<MudTextField T="string" @bind-Text="@this.inputStartTime" Validation="@this.ValidateStartTime" Label="Start time" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.TIME" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("When will the meeting, seminar, etc. start? E.g., '9:00 AM', or '9:00 AM (CET)', etc. When the meeting is a multi-day event, specify the start time for each day.")" Placeholder="@T("9:00 AM")" Class="mb-3"/>
<MudTextField T="string" @bind-Text="@this.inputWhoIsPresenting" Label="@T("(Optional) Who is presenting?")" Variant="Variant.Outlined" Lines="6" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("(Optional) List the persons who will present at the meeting, seminar, etc. Use dashes (-) to separate the items.")" Placeholder="@PLACEHOLDER_WHO_IS_PRESENTING" Class="mb-3"/>
<MudTextField T="string" @bind-Text="@this.inputStartTime" Validation="@this.ValidateStartTime" Label="@T("Start time")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.TIME" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@TA("When will the meeting, seminar, etc. start? E.g., '9:00 AM', or '9:00 AM (CET)', etc. When the meeting is a multi-day event, specify the start time for each day.")" Placeholder="@T("9:00 AM")" Class="mb-3"/>
<MudTextField T="string" @bind-Text="@this.inputWhoIsPresenting" Label="@T("(Optional) Who is presenting?")" Variant="Variant.Outlined" Lines="6" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@TA("(Optional) List the persons who will present at the meeting, seminar, etc. Use dashes (-) to separate the items.")" Placeholder="@PLACEHOLDER_WHO_IS_PRESENTING" Class="mb-3"/>
<MudTextSwitch Label="@T("Do the participants need to get to know each other first?")" @bind-Value="@this.introduceParticipants" LabelOn="@T("Yes, introduce participants")" LabelOff="@T("No, participants know each other")" />
<EnumSelection T="NumberParticipants" @bind-Value="@this.numberParticipants" NameFunc="@(participants => participants.Name)" Icon="@AppIcons.PARTICIPANTS" Label="@T("Number of participants")" ValidateSelection="@this.ValidateNumberParticipants"/>
<MudTextSwitch Label="@T("Should the participants be involved passively or actively?")" @bind-Value="@this.activeParticipation" LabelOn="@T("Active participation, like world café, discussions, etc.")" LabelOff="@T("Passive participation, like presentations, lectures, etc.")" />
@@ -12,7 +12,7 @@ public partial class AssistantAgenda : AssistantBaseCore<SettingsDialogAgenda>
protected override string Title => T("Agenda Planner");
protected override string Description => T("This agenda planner helps you create a structured agenda for your meeting or seminar. Just provide some basic information about the event, and the assistant will generate an agenda for you. You can also specify the duration, the start time, the location, the target language, and other details.");
protected override string Description => TA("This agenda planner helps you create a structured agenda for your meeting or seminar. Just provide some basic information about the event, and the assistant will generate an agenda for you. You can also specify the duration, the start time, the location, the target language, and other details.");
// The prompt of this assistant demands the agenda in a fixed format, so the chat gets a prompt of its own, which keeps the knowledge and the language:
protected override ChatSystemPromptChoice ChatSystemPrompt => ChatSystemPromptChoice.Custom(this.CreateChatSystemPrompt);
@@ -352,7 +352,7 @@ public partial class AssistantAgenda : AssistantBaseCore<SettingsDialogAgenda>
private string? ValidateLocation(string location)
{
if(!this.isMeetingVirtual && string.IsNullOrWhiteSpace(location))
return T("Please provide a location for the meeting or the seminar.");
return TA("Please provide a location for the meeting or the seminar.");
return null;
}
@@ -360,7 +360,7 @@ public partial class AssistantAgenda : AssistantBaseCore<SettingsDialogAgenda>
private string? ValidateNumberParticipants(NumberParticipants selectedSize)
{
if(selectedSize is NumberParticipants.NOT_SPECIFIED)
return T("Please select the number of participants.");
return TA("Please select the number of participants.");
return null;
}
@@ -368,7 +368,7 @@ public partial class AssistantAgenda : AssistantBaseCore<SettingsDialogAgenda>
private string? ValidateTargetLanguage(CommonLanguages language)
{
if(language is CommonLanguages.AS_IS)
return T("Please select a target language for the agenda.");
return TA("Please select a target language for the agenda.");
return null;
}
@@ -376,7 +376,7 @@ public partial class AssistantAgenda : AssistantBaseCore<SettingsDialogAgenda>
private string? ValidateDuration(string duration)
{
if(string.IsNullOrWhiteSpace(duration))
return T("Please provide a duration for the meeting or the seminar, e.g. '2 hours', or '2 days (8 hours and 4 hours)', etc.");
return TA("Please provide a duration for the meeting or the seminar, e.g. '2 hours', or '2 days (8 hours and 4 hours)', etc.");
return null;
}
@@ -384,7 +384,7 @@ public partial class AssistantAgenda : AssistantBaseCore<SettingsDialogAgenda>
private string? ValidateStartTime(string startTime)
{
if(string.IsNullOrWhiteSpace(startTime))
return T("Please provide a start time for the meeting or the seminar. When the meeting is a multi-day event, specify the start time for each day, e.g. '9:00 AM, 10:00 AM', etc.");
return TA("Please provide a start time for the meeting or the seminar. When the meeting is a multi-day event, specify the start time for each day, e.g. '9:00 AM, 10:00 AM', etc.");
return null;
}
@@ -392,7 +392,7 @@ public partial class AssistantAgenda : AssistantBaseCore<SettingsDialogAgenda>
private string? ValidateCustomLanguage(string language)
{
if(this.selectedTargetLanguage == CommonLanguages.OTHER && string.IsNullOrWhiteSpace(language))
return T("Please provide a custom language.");
return TA("Please provide a custom language.");
return null;
}
@@ -400,7 +400,7 @@ public partial class AssistantAgenda : AssistantBaseCore<SettingsDialogAgenda>
private string? ValidateTopic(string topic)
{
if(string.IsNullOrWhiteSpace(topic))
return T("Please provide a topic for the agenda. What is the meeting or the seminar about?");
return TA("Please provide a topic for the agenda. What is the meeting or the seminar about?");
return null;
}
@@ -408,7 +408,7 @@ public partial class AssistantAgenda : AssistantBaseCore<SettingsDialogAgenda>
private string? ValidateName(string name)
{
if(string.IsNullOrWhiteSpace(name))
return T("Please provide a name for the meeting or the seminar.");
return TA("Please provide a name for the meeting or the seminar.");
return null;
}
@@ -416,12 +416,12 @@ public partial class AssistantAgenda : AssistantBaseCore<SettingsDialogAgenda>
private string? ValidateContent(string content)
{
if(string.IsNullOrWhiteSpace(content))
return T("Please provide some content for the agenda. What are the main points of the meeting or the seminar?");
return TA("Please provide some content for the agenda. What are the main points of the meeting or the seminar?");
var lines = content.Split('\n', StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
if(!line.TrimStart().StartsWith('-'))
return T("Please start each line of your content list with a dash (-) to create a bullet point list.");
return TA("Please start each line of your content list with a dash (-) to create a bullet point list.");
return null;
}
@@ -429,7 +429,7 @@ public partial class AssistantAgenda : AssistantBaseCore<SettingsDialogAgenda>
private string? ValidateObjective(string objective)
{
if(string.IsNullOrWhiteSpace(objective))
return T("Please provide an objective for the meeting or the seminar. What do you want to achieve?");
return TA("Please provide an objective for the meeting or the seminar. What do you want to achieve?");
return null;
}
@@ -437,7 +437,7 @@ public partial class AssistantAgenda : AssistantBaseCore<SettingsDialogAgenda>
private string? ValidateModerator(string moderator)
{
if(string.IsNullOrWhiteSpace(moderator))
return T("Please provide a moderator for the meeting or the seminar. Who will lead the discussion?");
return TA("Please provide a moderator for the meeting or the seminar. Who will lead the discussion?");
return null;
}
@@ -3,12 +3,14 @@ namespace AIStudio.Assistants.Agenda;
public static class NumberParticipantsExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(NumberParticipantsExtensions).Namespace, nameof(NumberParticipantsExtensions));
private static string TA(string fallbackEN) => Tools.PluginSystem.I18N.I.TA(fallbackEN, typeof(NumberParticipantsExtensions).Namespace, nameof(NumberParticipantsExtensions));
extension(NumberParticipants numberParticipants)
{
public string Name => numberParticipants switch
{
NumberParticipants.NOT_SPECIFIED => TB("Please select how many participants are expected"),
NumberParticipants.NOT_SPECIFIED => TA("Please select how many participants are expected"),
NumberParticipants.PEER_TO_PEER => TB("2 (peer to peer)"),
@@ -354,6 +354,12 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
private string TB(string fallbackEN) => this.T(fallbackEN, typeof(AssistantBase<>).Namespace, nameof(AssistantBase<>));
/// <summary>
/// Gets a text of this base class which addresses the reader; the collector files it under AssistantBase, not
/// under the assistant which derives from it.
/// </summary>
private new string TA(string fallbackEN) => this.TA(fallbackEN, typeof(AssistantBase<>).Namespace, nameof(AssistantBase<>));
private string SubmitButtonStyle => this.SettingsManager.ConfigurationData.Confidence.ShowProviderConfidence ? this.ProviderSettings.UsedLLMProvider.GetConfidence(this.SettingsManager).StyleBorder(this.SettingsManager) : string.Empty;
private IReadOnlyList<Tools.Components> VisibleSendToAssistants => this.AssistantLaunchService.GetDestinationsFor(this.Component);
@@ -361,11 +367,11 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
protected string? ValidatingProvider(AIStudio.Settings.Provider provider)
{
if(provider.UsedLLMProvider == LLMProviders.NONE)
return this.TB("Please select a provider.");
return this.TA("Please select a provider.");
// A provider which nothing else rules out may still be kept from the text sent here, because of where it came from:
if (!this.transferredRestrictions.IsLLMProviderAllowed(provider) && ChatRestrictions.NONE.IsLLMProviderAllowed(provider))
return this.TB("This provider may not see the text sent to this assistant, because of where the text came from. Please select another provider.");
return this.TA("This provider may not see the text sent to this assistant, because of where the text came from. Please select another provider.");
return null;
}
@@ -7,7 +7,7 @@
@T("Input")
</MudText>
<SelectDirectory Label="@T("Folder containing your documents")" DirectoryDialogTitle="@T("Select the folder containing your documents")" @bind-Directory="@this.inputDirectory" Validation="@this.ValidateInputDirectory" EnableDragDrop="true" Disabled="@this.isProcessingBatch"/>
<SelectDirectory Label="@TA("Folder containing your documents")" DirectoryDialogTitle="@TA("Select the folder containing your documents")" @bind-Directory="@this.inputDirectory" Validation="@this.ValidateInputDirectory" EnableDragDrop="true" Disabled="@this.isProcessingBatch"/>
<MudTextSwitch Label="@T("Include subfolders?")" Disabled="@this.isProcessingBatch" Value="@this.includeSubdirectories" ValueChanged="@(v => this.includeSubdirectories = v)" LabelOn="@T("Yes, process files in subfolders as well")" LabelOff="@T("No, only process files in the selected folder")"/>
@@ -31,7 +31,7 @@
</MudJustifiedText>
<MudJustifiedText Typo="Typo.body2" Class="mb-3">
@T("Images in JPG, PNG, WebP, GIF, BMP, or TIFF format are given to the model as images, so you need a model that understands images. If the selected model cannot read images, remove the image patterns, such as *.jpg or *.png, before you start.")
@TA("Images in JPG, PNG, WebP, GIF, BMP, or TIFF format are given to the model as images, so you need a model that understands images. If the selected model cannot read images, remove the image patterns, such as *.jpg or *.png, before you start.")
</MudJustifiedText>
<MudStack Class="mb-3">
@@ -81,7 +81,7 @@
}
else if (this.promptSource is BatchProcessingPromptSource.FILE_IMPORT)
{
<ReadFileContent Text="@T("Select the file with your instructions")" @bind-FileContent="@this.ImportedPrompt" Filter="@([FileTypes.MARKDOWN])" ShowAttachedDocumentState="@true" EnableDragDrop="true" Disabled="@this.isProcessingBatch"/>
<ReadFileContent Text="@TA("Select the file with your instructions")" @bind-FileContent="@this.ImportedPrompt" Filter="@([FileTypes.MARKDOWN])" ShowAttachedDocumentState="@true" EnableDragDrop="true" Disabled="@this.isProcessingBatch"/>
@if (!string.IsNullOrWhiteSpace(this.promptFilePath))
{
@@ -103,13 +103,13 @@ else
{
@if (this.ConfiguredPolicyIsMissing)
{
<MudAlert Severity="Severity.Warning" Dense="true" Class="mb-3">@T("The configured default policy no longer exists. Please select another document analysis policy.")</MudAlert>
<MudAlert Severity="Severity.Warning" Dense="true" Class="mb-3">@TA("The configured default policy no longer exists. Please select another document analysis policy.")</MudAlert>
}
@if (this.SettingsManager.ConfigurationData.DocumentAnalysis.Policies.Count is 0)
{
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
@T("You have not yet created any document analysis policies. Please use the Document Analysis Assistant to create a policy first.")
@TA("You have not yet created any document analysis policies. Please use the Document Analysis Assistant to create a policy first.")
</MudJustifiedText>
<MudButton Href="@Routes.ASSISTANT_DOCUMENT_ANALYSIS" Variant="Variant.Filled" Color="Color.Primary" Class="mb-3">
@T("Open the Document Analysis Assistant")
@@ -156,7 +156,7 @@ else
@if (this.outputMode is BatchProcessingOutputMode.INDIVIDUAL_FILES)
{
<MudSelect T="FileExportFormat" @bind-Value="@this.resultFileFormat" Disabled="@this.isProcessingBatch" AdornmentIcon="@AppIcons.DOCUMENT" Adornment="Adornment.Start" Label="@T("File format")" HelperText="@T("Choose the format of the result files. Everything except Markdown is converted by Pandoc, which AI Studio offers to install when it is missing.")" Variant="Variant.Outlined" Margin="Margin.Dense" Class="mb-3">
<MudSelect T="FileExportFormat" @bind-Value="@this.resultFileFormat" Disabled="@this.isProcessingBatch" AdornmentIcon="@AppIcons.DOCUMENT" Adornment="Adornment.Start" Label="@T("File format")" HelperText="@TA("Choose the format of the result files. Everything except Markdown is converted by Pandoc, which AI Studio offers to install when it is missing.")" Variant="Variant.Outlined" Margin="Margin.Dense" Class="mb-3">
@foreach (var format in FileExportFormat.AnswerFormats)
{
<MudSelectItem Value="@format">
@@ -171,11 +171,11 @@ else
}
else
{
<MudTextField T="string" @bind-Text="@this.csvFileName" Validation="@this.ValidateCsvFileName" Immediate="@true" Disabled="@this.isProcessingBatch" Label="@T("Name of the results table (optional)")" HelperText="@T("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'.")" AdornmentIcon="@AppIcons.DOCUMENT" Adornment="Adornment.Start" Variant="Variant.Outlined" Margin="Margin.Normal" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudTextField T="string" @bind-Text="@this.csvFileName" Validation="@this.ValidateCsvFileName" Immediate="@true" Disabled="@this.isProcessingBatch" Label="@T("Name of the results table (optional)")" HelperText="@TA("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'.")" AdornmentIcon="@AppIcons.DOCUMENT" Adornment="Adornment.Start" Variant="Variant.Outlined" Margin="Margin.Normal" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudTextField T="string" @bind-Text="@this.resultColumnHeader" Disabled="@this.isProcessingBatch" Label="@T("Header of the result column (optional)")" HelperText="@T("The results table contains one row per document, starting with the file name. Here you can name the column that holds the AI answer, e.g., Summary. When left empty, we use 'Result'.")" AdornmentIcon="@AppIcons.RESULT_COLUMN" Adornment="Adornment.Start" Variant="Variant.Outlined" Margin="Margin.Normal" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudTextField T="string" @bind-Text="@this.resultColumnHeader" Disabled="@this.isProcessingBatch" Label="@T("Header of the result column (optional)")" HelperText="@TA("The results table contains one row per document, starting with the file name. Here you can name the column that holds the AI answer, e.g., Summary. When left empty, we use 'Result'.")" AdornmentIcon="@AppIcons.RESULT_COLUMN" Adornment="Adornment.Start" Variant="Variant.Outlined" Margin="Margin.Normal" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudSelect T="BatchProcessingCsvSeparator" @bind-Value="@this.csvSeparator" Disabled="@this.isProcessingBatch" AdornmentIcon="@AppIcons.CSV_SEPARATOR" Adornment="Adornment.Start" Label="@T("Column separator")" HelperText="@T("Choose which character separates the columns of the results table.")" Variant="Variant.Outlined" Margin="Margin.Dense" Class="mb-3">
<MudSelect T="BatchProcessingCsvSeparator" @bind-Value="@this.csvSeparator" Disabled="@this.isProcessingBatch" AdornmentIcon="@AppIcons.CSV_SEPARATOR" Adornment="Adornment.Start" Label="@T("Column separator")" HelperText="@TA("Choose which character separates the columns of the results table.")" Variant="Variant.Outlined" Margin="Margin.Dense" Class="mb-3">
@foreach (var separator in Enum.GetValues<BatchProcessingCsvSeparator>())
{
<MudSelectItem Value="@separator">
@@ -186,14 +186,14 @@ else
@if (this.csvSeparator is BatchProcessingCsvSeparator.CUSTOM)
{
<MudTextField T="string" @bind-Text="@this.customCsvSeparator" Validation="@this.ValidateCustomCsvSeparator" Immediate="@true" Disabled="@this.isProcessingBatch" Label="@T("Custom column separator")" HelperText="@T("Enter one punctuation or symbol character.")" AdornmentIcon="@AppIcons.CSV_SEPARATOR" Adornment="Adornment.Start" Variant="Variant.Outlined" Margin="Margin.Normal" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudTextField T="string" @bind-Text="@this.customCsvSeparator" Validation="@this.ValidateCustomCsvSeparator" Immediate="@true" Disabled="@this.isProcessingBatch" Label="@T("Custom column separator")" HelperText="@TA("Enter one punctuation or symbol character.")" AdornmentIcon="@AppIcons.CSV_SEPARATOR" Adornment="Adornment.Start" Variant="Variant.Outlined" Margin="Margin.Normal" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
}
}
<SelectDirectory Label="@T("Output folder (optional)")" DirectoryDialogTitle="@T("Select the output folder")" @bind-Directory="@this.outputDirectory" EnableDragDrop="true" Disabled="@this.isProcessingBatch"/>
<SelectDirectory Label="@T("Output folder (optional)")" DirectoryDialogTitle="@TA("Select the output folder")" @bind-Directory="@this.outputDirectory" EnableDragDrop="true" Disabled="@this.isProcessingBatch"/>
<MudJustifiedText Typo="Typo.body2" Class="mb-3">
@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.")
@TA("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.")
</MudJustifiedText>
<MudText Typo="Typo.h6" Class="mb-3 mt-6">
@@ -203,7 +203,7 @@ else
@if (MinimumDelayIsManaged)
{
<MudAlert Severity="Severity.Info" Dense="true" Class="mb-3">
@(string.Format(T("Your organization requires a pause of at least {0} seconds between files."), this.ManagedMinimumDelaySeconds))
@(string.Format(TA("Your organization requires a pause of at least {0} seconds between files."), this.ManagedMinimumDelaySeconds))
</MudAlert>
}
else
@@ -58,7 +58,7 @@ public partial class AssistantBatchProcessing
{
if (!this.ProviderSettings.SupportsImageInput())
{
this.FinishFileResult(fileResult, BatchProcessingFileStatus.FAILED, T("The selected model cannot read images. Select a model with image support to process this image."));
this.FinishFileResult(fileResult, BatchProcessingFileStatus.FAILED, TA("The selected model cannot read images. Select a model with image support to process this image."));
return null;
}
@@ -162,7 +162,7 @@ public partial class AssistantBatchProcessing
return;
this.hasReportedWriteFailure = true;
await this.MessageBus.SendError(new(AppIcons.SAVE_FAILED, string.Format(T("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}'"), Path.GetFileName(targetFilePath), e.Message)));
await this.MessageBus.SendError(new(AppIcons.SAVE_FAILED, string.Format(TA("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}'"), Path.GetFileName(targetFilePath), e.Message)));
}
}
@@ -196,8 +196,8 @@ public partial class AssistantBatchProcessing
if (failedFiles > 0)
{
var failureMessage = failedFiles == 1
? T("The batch run finished, but one file could not be processed. See the progress table and log for details.")
: string.Format(T("The batch run finished, but {0} files could not be processed. See the progress table and log for details."), failedFiles);
? TA("The batch run finished, but one file could not be processed. See the progress table and log for details.")
: string.Format(TA("The batch run finished, but {0} files could not be processed. See the progress table and log for details."), failedFiles);
await this.MessageBus.SendError(new(AppIcons.ERROR, failureMessage));
}
}
@@ -8,7 +8,7 @@ public partial class AssistantBatchProcessing
private string? ValidateInputDirectory(string directory)
{
if (string.IsNullOrWhiteSpace(directory))
return T("Please select the folder that contains the documents you want to process.");
return TA("Please select the folder that contains the documents you want to process.");
if (!Directory.Exists(directory))
return T("The selected folder does not exist.");
@@ -24,7 +24,7 @@ public partial class AssistantBatchProcessing
return null;
if (fileName.Trim().IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
return T("Please provide a file name without a path, e.g., my-results.csv");
return TA("Please provide a file name without a path, e.g., my-results.csv");
return null;
}
@@ -36,7 +36,7 @@ public partial class AssistantBatchProcessing
return null;
if (!BatchProcessingCsvSeparator.IsValidCustomSeparator(separator))
return T("Please enter exactly one punctuation or symbol character. Letters, numbers, spaces, quotation marks, and line breaks cannot be used as CSV separators.");
return TA("Please enter exactly one punctuation or symbol character. Letters, numbers, spaces, quotation marks, and line breaks cannot be used as CSV separators.");
return null;
}
@@ -44,7 +44,7 @@ public partial class AssistantBatchProcessing
private string? ValidateFreePrompt(string prompt)
{
if (this.promptSource is BatchProcessingPromptSource.FREE_PROMPT && string.IsNullOrWhiteSpace(prompt))
return T("Please describe what the AI should do with each document.");
return TA("Please describe what the AI should do with each document.");
return null;
}
@@ -54,10 +54,10 @@ public partial class AssistantBatchProcessing
/// </summary>
private string? ValidateInstructionSource() => this.promptSource switch
{
BatchProcessingPromptSource.POLICY when this.ConfiguredPolicyIsMissing => T("The configured default policy no longer exists. Please select another document analysis policy."),
BatchProcessingPromptSource.POLICY when this.selectedPolicy is null => T("Please select a document analysis policy."),
BatchProcessingPromptSource.POLICY when this.ConfiguredPolicyIsMissing => TA("The configured default policy no longer exists. Please select another document analysis policy."),
BatchProcessingPromptSource.POLICY when this.selectedPolicy is null => TA("Please select a document analysis policy."),
BatchProcessingPromptSource.FILE_IMPORT when !string.IsNullOrWhiteSpace(this.promptFileLoadIssue) => this.promptFileLoadIssue,
BatchProcessingPromptSource.FILE_IMPORT when string.IsNullOrWhiteSpace(this.importedPrompt) => T("Please select the file which contains your instructions."),
BatchProcessingPromptSource.FILE_IMPORT when string.IsNullOrWhiteSpace(this.importedPrompt) => TA("Please select the file which contains your instructions."),
_ => null,
};
@@ -165,7 +165,7 @@ public partial class AssistantBatchProcessing
if (files.Count == 0)
{
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())
? string.Format(TA("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;
}
@@ -173,7 +173,7 @@ public partial class AssistantBatchProcessing
var requiresTranscription = files.Any(file => IsTranscribableMedia(file) && !HasReusableTranscript(file));
if (requiresTranscription && !this.MediaTranscriptionService.HasUsableTranscriptionProvider)
{
this.AddInputIssue(T("The selected files include audio or video without an existing transcript, but no usable transcription provider is configured. Configure one in the transcription settings or remove the media patterns."));
this.AddInputIssue(TA("The selected files include audio or video without an existing transcript, but no usable transcription provider is configured. Configure one in the transcription settings or remove the media patterns."));
return null;
}
@@ -184,7 +184,7 @@ public partial class AssistantBatchProcessing
//
if (files.All(IsImage) && !this.ProviderSettings.SupportsImageInput())
{
this.AddInputIssue(T("All selected files are images, but the selected model cannot read images. Select a model with image support."));
this.AddInputIssue(TA("All selected files are images, but the selected model cannot read images. Select a model with image support."));
return null;
}
@@ -54,7 +54,7 @@ public partial class AssistantBatchProcessing : AssistantBaseCore<SettingsDialog
protected override string Title => T("Batch Processing Assistant");
protected override string Description => T("Process all documents and media files of a folder in one batch run: documents are converted to Markdown, while audio and video files are transcribed automatically, before their content is sent to the AI along with your instructions. You choose whether each answer is stored as its own Markdown file or whether all answers are collected in one CSV results table. A log records what happened to every file, so a run which was interrupted or produced errors can be continued later. A single failing file never stops the entire run.");
protected override string Description => TA("Process all documents and media files of a folder in one batch run: documents are converted to Markdown, while audio and video files are transcribed automatically, before their content is sent to the AI along with your instructions. You choose whether each answer is stored as its own Markdown file or whether all answers are collected in one CSV results table. A log records what happened to every file, so a run which was interrupted or produced errors can be continued later. A single failing file never stops the entire run.");
// The results of this assistant go into files, so no chat continues its conversations:
protected override ChatSystemPromptChoice ChatSystemPrompt => ChatSystemPromptChoice.AI_STUDIO_DEFAULT;
@@ -207,7 +207,7 @@ public partial class BeyondFactsLabAssistant
catch (Exception exception) when (exception is IOException or UnauthorizedAccessException or InvalidDataException or ArgumentException)
{
this.Logger.LogError(exception, "A change of the preparations of the BeyondFacts Lab failed.");
await this.MessageBus.SendError(new(AppIcons.ASSISTANT_BEYOND_FACTS_LAB, TA("AI Studio could not save the change of your preparations. Please try again.")));
await this.MessageBus.SendError(new(AppIcons.ASSISTANT_BEYOND_FACTS_LAB, TA("AI Studio could not save the change to your preparations. Please try again.")));
await this.ReloadAfterFailureAsync();
}
finally
@@ -13,7 +13,7 @@ public partial class BiasOfTheDayAssistant : AssistantBaseCore<SettingsDialogAss
protected override string Title => T("Bias of the Day");
protected override string Description => T("""Learn about a different cognitive bias every day. You can also ask the LLM your questions. The idea behind "Bias of the Day" is based on work by Buster Benson, John Manoogian III, and Brian Rene Morrissette. Buster Benson grouped the biases, and the original texts come from Wikipedia. Brian Rene Morrissette condensed them into a shorter version. Finally, John Manoogian III created the original poster based on Benson's work and Morrissette's texts. Thorsten Sommer compared all texts for integration into AI Studio with the current Wikipedia versions, updated them, and added source references. The idea of learning about one bias each day based on John's poster comes from Drew Nelson.""");
protected override string Description => TA("""Learn about a different cognitive bias every day. You can also ask the LLM your questions. The idea behind "Bias of the Day" is based on work by Buster Benson, John Manoogian III, and Brian Rene Morrissette. Buster Benson grouped the biases, and the original texts come from Wikipedia. Brian Rene Morrissette condensed them into a shorter version. Finally, John Manoogian III created the original poster based on Benson's work and Morrissette's texts. Thorsten Sommer compared all texts for integration into AI Studio with the current Wikipedia versions, updated them, and added source references. The idea of learning about one bias each day based on John's poster comes from Drew Nelson.""");
// The chat continues the talk about today's bias, which only this prompt describes, together with its sources and language:
protected override ChatSystemPromptChoice ChatSystemPrompt => ChatSystemPromptChoice.ASSISTANT;
@@ -93,7 +93,7 @@ public partial class BiasOfTheDayAssistant : AssistantBaseCore<SettingsDialogAss
private string? ValidateTargetLanguage(CommonLanguages language)
{
if(language is CommonLanguages.AS_IS)
return T("Please select a target language for the bias.");
return TA("Please select a target language for the bias.");
return null;
}
@@ -101,7 +101,7 @@ public partial class BiasOfTheDayAssistant : AssistantBaseCore<SettingsDialogAss
private string? ValidateCustomLanguage(string language)
{
if(this.selectedTargetLanguage == CommonLanguages.OTHER && string.IsNullOrWhiteSpace(language))
return T("Please provide a custom language.");
return TA("Please provide a custom language.");
return null;
}
@@ -8,7 +8,7 @@
@if (this.step is BuilderStep.DESCRIBE)
{
<ReadFileContent Text="@T("Load description from file")" @bind-FileContent="@this.assistantDescription" EnableDragDrop="true" CatchAllDocuments="true"/>
<MudTextField T="string" @bind-Text="@this.assistantDescription" Validation="@this.ValidateAssistantDescription" AdornmentIcon="@AppIcons.GENERATE" Adornment="Adornment.Start" Label="@T("Describe your assistant")" HelperText="@T("Describe the task, inputs, and desired output in your own words. The model will infer all the plugin details.")" Placeholder="@T("I need an assistant that turns meeting notes into clear tasks with owners and deadlines.")" Variant="Variant.Outlined" Lines="8" Sizing="InputSizing.Auto" MaxLines="18" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudTextField T="string" @bind-Text="@this.assistantDescription" Validation="@this.ValidateAssistantDescription" AdornmentIcon="@AppIcons.GENERATE" Adornment="Adornment.Start" Label="@TA("Describe your assistant")" HelperText="@TA("Describe the task, inputs, and desired output in your own words. The model will infer all the plugin details.")" Placeholder="@T("I need an assistant that turns meeting notes into clear tasks with owners and deadlines.")" Variant="Variant.Outlined" Lines="8" Sizing="InputSizing.Auto" MaxLines="18" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
@* This switch chooses between the two kinds of assistant the Builder can create, so it stays
outside the advanced options. Its fields are required, and a collapsed panel would hide
@@ -23,7 +23,7 @@
</MudField>
<MudJustifiedText Typo="Typo.body2" Class="mb-3">
@(this.createChatLauncher
? T("The direct chat launcher tile has no input form of its own. It opens a new chat right away, with the provider, profile, chat template, and data sources you select below. Name a workspace for that chat, or leave the workspace empty to open a disappearing chat.")
? TA("The direct chat launcher tile has no input form of its own. It opens a new chat right away, with the provider, profile, chat template, and data sources you select below. Name a workspace for that chat, or leave the workspace empty to open a disappearing chat.")
: T("The assistant asks users for input through a form and builds its own prompt from it."))
</MudJustifiedText>
@if (this.createChatLauncher)
@@ -95,7 +95,7 @@ else
</MudTooltip>
@if (this.step is BuilderStep.DONE)
{
<MudTooltip Text="@T("Discard the current plugin preview, edit the accepted draft, and generate the plugin again.")">
<MudTooltip Text="@TA("Discard the current plugin preview, edit the accepted draft, and generate the plugin again.")">
<MudButton Variant="Variant.Outlined" StartIcon="@AppIcons.EDIT" Size="Size.Small" IconSize="Size.Small" OnClick="@(async () => await this.EditDraftAndDiscardPluginPreview())">
@T("Edit draft")
</MudButton>
@@ -242,7 +242,7 @@ else
@if (this.RequiresActivationConfirmation)
{
<MudAlert Severity="Severity.Warning" Dense="@true" Icon="@AppIcons.WARNING">
@T("The security check is below your required level. Your settings allow activation after confirmation.")
@TA("The security check is below your required level. Your settings allow activation after confirmation.")
</MudAlert>
}
<MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@AppIcons.ENABLE" Disabled="@(!this.CanEnableAssistant)" OnClick="@(async () => await this.EnableInstalledAssistantAsync())">
@@ -262,7 +262,7 @@ else
}
else
{
<MudText Typo="Typo.body2">@T("Enable the assistant before opening it.")</MudText>
<MudText Typo="Typo.body2">@TA("Enable the assistant before opening it.")</MudText>
}
</MudStack>
</MudStep>
@@ -34,7 +34,7 @@ public partial class AssistantBuilder : AssistantBaseCore<SettingsDialogAssistan
protected override string Title => T("Assistant Builder");
protected override string Description => T("Describe the assistant you want to create. AI Studio will draft a readable assistant specification first and then generate an assistant plugin from it.");
protected override string Description => TA("Describe the assistant you want to create. AI Studio will draft a readable assistant specification first and then generate an assistant plugin from it.");
// This assistant generates a plugin and has no conversation for a chat to continue:
protected override ChatSystemPromptChoice ChatSystemPrompt => ChatSystemPromptChoice.AI_STUDIO_DEFAULT;
@@ -369,7 +369,7 @@ public partial class AssistantBuilder : AssistantBaseCore<SettingsDialogAssistan
private string? ValidateAssistantDescription(string description)
{
if (string.IsNullOrWhiteSpace(description))
return T("Please describe the assistant you want to create.");
return TA("Please describe the assistant you want to create.");
return null;
}
@@ -382,7 +382,7 @@ public partial class AssistantBuilder : AssistantBaseCore<SettingsDialogAssistan
private string? ValidateCustomCategory(string category)
{
if(this.selectedCategory is AssistantCategory.OTHER && string.IsNullOrWhiteSpace(category))
return T("Please provide a custom category.");
return TA("Please provide a custom category.");
return null;
}
@@ -390,7 +390,7 @@ public partial class AssistantBuilder : AssistantBaseCore<SettingsDialogAssistan
private string? ValidateCustomOutputLanguage(string language)
{
if(this.selectedOutputLanguage is CommonLanguages.OTHER && string.IsNullOrWhiteSpace(language))
return T("Please provide a custom output language.");
return TA("Please provide a custom output language.");
return null;
}
@@ -447,7 +447,7 @@ public partial class AssistantBuilder : AssistantBaseCore<SettingsDialogAssistan
if (string.IsNullOrWhiteSpace(this.generatedAssistantSpec))
{
this.AddInputIssue(T("Please create an assistant draft first."));
this.AddInputIssue(TA("Please create an assistant draft first."));
return;
}
@@ -609,7 +609,7 @@ public partial class AssistantBuilder : AssistantBaseCore<SettingsDialogAssistan
if (!this.createChatLauncher || !this.MaySuggestDescription())
return;
var suggestion = T("Create a tile that opens a preconfigured chat directly, without an input form of its own.");
var suggestion = TA("Create a tile that opens a preconfigured chat directly, without an input form of its own.");
suggestion = string.IsNullOrWhiteSpace(this.launcherWorkspaceName)
? $"{suggestion} {T("The chat opens as a disappearing chat, without a workspace.")}"
: $"{suggestion} {string.Format(T("Workspace: {0}"), this.launcherWorkspaceName.Trim())}";
@@ -740,8 +740,8 @@ public partial class AssistantBuilder : AssistantBaseCore<SettingsDialogAssistan
if (this.IsActivationBlockedBySettings)
{
this.stepperIndex = (int)BuilderInstallStep.ENABLE_ASSISTANT;
this.FailInstallStep(BuilderInstallStep.ENABLE_ASSISTANT, T("This assistant cannot be enabled because the security check is below your required level."));
await this.MessageBus.SendError(new(AppIcons.BLOCKED, T("The assistant cannot be enabled because it is below your required security level.")));
this.FailInstallStep(BuilderInstallStep.ENABLE_ASSISTANT, TA("This assistant cannot be enabled because the security check is below your required level."));
await this.MessageBus.SendError(new(AppIcons.BLOCKED, TA("The assistant cannot be enabled because it is below your required security level.")));
return;
}
@@ -791,7 +791,7 @@ public partial class AssistantBuilder : AssistantBaseCore<SettingsDialogAssistan
{
x => x.Message,
string.Format(
T("The assistant '{0}' was checked with the level '{1}', which is below your required level '{2}'. Your settings allow activation anyway, but this may be unsafe. Do you want to enable this assistant?"),
TA("The assistant '{0}' was checked with the level '{1}', which is below your required level '{2}'. Your settings allow activation anyway, but this may be unsafe. Do you want to enable this assistant?"),
this.pluginInstallResult?.PluginName ?? T("Unknown assistant"),
this.pluginAudit?.Level.Name ?? T("Unknown"),
this.SettingsManager.ConfigurationData.AssistantPluginAudit.MinimumLevel.Name)
@@ -3,19 +3,19 @@
<MudText Typo="Typo.h5" Class="mb-1 mt-3">@T("Context")</MudText>
<MudJustifiedText Typo="Typo.body1" Class="mb-2">
@T("You can attach source files as optional context for your coding question.")
@TA("You can attach source files as optional context for your coding question.")
</MudJustifiedText>
<div class="mb-3">
<AttachDocuments Name="Coding Source Files" @bind-DocumentPaths="@this.loadedDocumentPaths" CatchAllDocuments="true" UseSmallForm="false" Provider="@this.ProviderSettings"/>
</div>
<MudStack Row="@false" Class="mb-3">
<MudTextSwitch Label="@T("Do you want to provide compiler messages?")" @bind-Value="@this.provideCompilerMessages" LabelOn="@T("Yes, provide compiler messages")" LabelOff="@T("No, there are no compiler messages")" />
<MudTextSwitch Label="@TA("Do you want to provide compiler messages?")" @bind-Value="@this.provideCompilerMessages" LabelOn="@T("Yes, provide compiler messages")" LabelOff="@T("No, there are no compiler messages")" />
@if (this.provideCompilerMessages)
{
<MudTextField T="string" @bind-Text="@this.compilerMessages" Validation="@this.ValidatingCompilerMessages" AdornmentIcon="@AppIcons.COMPILER_MESSAGES" Adornment="Adornment.Start" Label="@T("Compiler messages")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
}
</MudStack>
<MudTextField T="string" @bind-Text="@this.questions" Validation="@this.ValidateQuestions" AdornmentIcon="@AppIcons.QUESTIONS" Adornment="Adornment.Start" Label="@T("Your question(s)")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudTextField T="string" @bind-Text="@this.questions" Validation="@this.ValidateQuestions" AdornmentIcon="@AppIcons.QUESTIONS" Adornment="Adornment.Start" Label="@TA("Your question(s)")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<ProviderSelection @bind-ProviderSettings="@this.ProviderSettings" ValidateProvider="@this.ValidatingProvider"/>
@@ -13,7 +13,7 @@ public partial class AssistantCoding : AssistantBaseCore<SettingsDialogCoding>
protected override string Title => T("Coding Assistant");
protected override string Description => T("This coding assistant supports you in writing code. Ask your coding question and optionally attach source files as context. When you have compiler messages, you can paste them into the input fields to get help with debugging as well.");
protected override string Description => TA("This coding assistant supports you in writing code. Ask your coding question and optionally attach source files as context. When you have compiler messages, you can paste them into the input fields to get help with debugging as well.");
// This prompt describes a developer for any coding question, which suits the follow-up questions of the chat:
protected override ChatSystemPromptChoice ChatSystemPrompt => ChatSystemPromptChoice.ASSISTANT;
@@ -149,7 +149,7 @@ public partial class AssistantCoding : AssistantBaseCore<SettingsDialogCoding>
return null;
if(string.IsNullOrWhiteSpace(checkCompilerMessages))
return T("Please provide the compiler messages.");
return TA("Please provide the compiler messages.");
return null;
}
@@ -157,7 +157,7 @@ public partial class AssistantCoding : AssistantBaseCore<SettingsDialogCoding>
private string? ValidateQuestions(string checkQuestions)
{
if(string.IsNullOrWhiteSpace(checkQuestions))
return T("Please provide your questions.");
return TA("Please provide your questions.");
return null;
}
@@ -11,13 +11,13 @@
</MudText>
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
@T("Here you have the option to save different policies for various document analysis assistants and switch between them.")
@TA("Here you have the option to save different policies for various document analysis assistants and switch between them.")
</MudJustifiedText>
@if(this.SettingsManager.ConfigurationData.DocumentAnalysis.Policies.Count is 0)
{
<MudText Typo="Typo.body1" Class="mb-3">
@T("You have not yet added any document analysis policies.")
@TA("You have not yet added any document analysis policies.")
</MudText>
}
else
@@ -29,7 +29,7 @@ else
{
<MudListItem T="DataDocumentAnalysisPolicy" Icon="@AppIcons.ANALYSIS_POLICY" Value="@policy">
@policy.PolicyName
<MudTooltip Text="@T("This policy is managed by your organization.")" Placement="Placement.Right">
<MudTooltip Text="@TA("This policy is managed by your organization.")" Placement="Placement.Right">
<MudIcon Icon="@AppIcons.ORGANIZATION" Size="Size.Small" Class="ml-2" Style="vertical-align: middle;" />
</MudTooltip>
</MudListItem>
@@ -87,7 +87,7 @@ else
@if (!this.policyDefinitionExpanded)
{
<MudJustifiedText Typo="Typo.body1" Class="mb-1">
@T("Expand this section to view and edit the policy definition.")
@TA("Expand this section to view and edit the policy definition.")
</MudJustifiedText>
}
else
@@ -96,14 +96,14 @@ else
@T("Common settings")
</MudText>
<MudTextField T="string" Disabled="@this.IsNoPolicySelectedOrProtected" @bind-Text="@this.policyName" Validation="@this.ValidatePolicyName" Immediate="@true" Label="@T("Policy name")" HelperText="@T("Please give your policy a name that provides information about the intended purpose. The name will be displayed to users in AI Studio.")" Counter="60" MaxLength="60" Variant="Variant.Outlined" Margin="Margin.Normal" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3" OnKeyUp="@(() => this.PolicyNameWasChanged())"/>
<MudTextField T="string" Disabled="@this.IsNoPolicySelectedOrProtected" @bind-Text="@this.policyName" Validation="@this.ValidatePolicyName" Immediate="@true" Label="@T("Policy name")" HelperText="@TA("Please give your policy a name that provides information about the intended purpose. The name will be displayed to users in AI Studio.")" Counter="60" MaxLength="60" Variant="Variant.Outlined" Margin="Margin.Normal" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3" OnKeyUp="@(() => this.PolicyNameWasChanged())"/>
<MudTextField T="string" Disabled="@this.IsNoPolicySelectedOrProtected" @bind-Text="@this.policyDescription" Validation="@this.ValidatePolicyDescription" Immediate="@true" Label="@T("Policy description")" HelperText="@T("Please provide a brief description of your policy. Describe or explain what your policy does. This description will be shown to users in AI Studio.")" Counter="512" MaxLength="512" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="3" Sizing="InputSizing.Auto" MaxLines="6" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<MudTextField T="string" Disabled="@this.IsNoPolicySelectedOrProtected" @bind-Text="@this.policyDescription" Validation="@this.ValidatePolicyDescription" Immediate="@true" Label="@T("Policy description")" HelperText="@TA("Please provide a brief description of your policy. Describe or explain what your policy does. This description will be shown to users in AI Studio.")" Counter="512" MaxLength="512" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="3" Sizing="InputSizing.Auto" MaxLines="6" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<MudTextSwitch Disabled="@this.IsNoPolicySelectedOrProtected" Label="@T("Hide the policy definition when distributed via configuration plugin?")" Value="@this.policyHidePolicyDefinition" ValueChanged="async state => await this.PolicyHidePolicyDefinitionWasChanged(state)" LabelOn="@T("Yes, hide the policy definition")" LabelOff="@T("No, show the policy definition")" />
<MudJustifiedText Typo="Typo.body2" Class="mt-2 mb-3">
@T("Note: This setting only takes effect when this policy is exported and distributed via a configuration plugin to other users. When enabled, users will only see the document selection interface and cannot view or modify the policy details. This setting does NOT affect your local view - you will always see the full policy definition for policies you create.")
@TA("Note: This setting only takes effect when this policy is exported and distributed via a configuration plugin to other users. When enabled, users will only see the document selection interface and cannot view or modify the policy details. This setting does NOT affect your local view - you will always see the full policy definition for policies you create.")
</MudJustifiedText>
<ConfigurationMinConfidenceSelection Disabled="@(() => this.IsNoPolicySelectedOrProtected)" RestrictToGlobalMinimumConfidence="true" SelectedValue="@(() => this.policyMinimumProviderConfidence)" SelectionUpdate="@this.PolicyMinimumConfidenceWasChanged" />
@@ -112,33 +112,33 @@ else
<ConfigurationProviderSelection Component="Components.DOCUMENT_ANALYSIS_ASSISTANT" Data="@this.availableLLMProviders" Disabled="@(() => this.IsNoPolicySelectedOrProtected)" SelectedValue="@(() => this.policyPreselectedProviderId)" SelectionUpdate="@this.PolicyPreselectedProviderWasChanged" ExplicitMinimumConfidence="@this.GetPolicyMinimumConfidenceLevel()"/>
<ConfigurationSelect OptionDescription="@T("Preselect a profile")" Disabled="@(() => this.IsNoPolicySelected)" SelectedValue="@(() => this.policyPreselectedProfile)" Data="@ConfigurationSelectDataFactory.GetComponentProfilesData(this.SettingsManager.ConfigurationData.Profiles)" SelectionUpdate="@this.PolicyPreselectedProfileWasChanged" OptionHelp="@T("Choose whether the policy should use the app default profile, no profile, or a specific profile.")"/>
<ConfigurationSelect OptionDescription="@T("Preselect a profile")" Disabled="@(() => this.IsNoPolicySelected)" SelectedValue="@(() => this.policyPreselectedProfile)" Data="@ConfigurationSelectDataFactory.GetComponentProfilesData(this.SettingsManager.ConfigurationData.Profiles)" SelectionUpdate="@this.PolicyPreselectedProfileWasChanged" OptionHelp="@TA("Choose whether the policy should use the app default profile, no profile, or a specific profile.")"/>
<MudTextSwitch Disabled="@(this.IsNoPolicySelected || (this.selectedPolicy?.IsEnterpriseConfiguration ?? true))" Label="@T("Would you like to protect this policy so that you cannot accidentally edit or delete it?")" Value="@this.policyIsProtected" ValueChanged="async state => await this.PolicyProtectionWasChanged(state)" LabelOn="@T("Yes, protect this policy")" LabelOff="@T("No, the policy can be edited")" />
<MudTextSwitch Disabled="@(this.IsNoPolicySelected || (this.selectedPolicy?.IsEnterpriseConfiguration ?? true))" Label="@TA("Would you like to protect this policy so that you cannot accidentally edit or delete it?")" Value="@this.policyIsProtected" ValueChanged="async state => await this.PolicyProtectionWasChanged(state)" LabelOn="@T("Yes, protect this policy")" LabelOff="@T("No, the policy can be edited")" />
<MudText Typo="Typo.h5" Class="mt-6 mb-1">
@T("Analysis and output rules")
</MudText>
<MudJustifiedText Typo="Typo.body1" Class="mt-3">
@T("Use the analysis and output rules to define how the AI evaluates your documents and formats the results.")
@TA("Use the analysis and output rules to define how the AI evaluates your documents and formats the results.")
</MudJustifiedText>
<MudJustifiedText Typo="Typo.body1" Class="mt-3">
@T("The analysis rules specify what the AI should pay particular attention to while reviewing the documents you provide, and which aspects it should highlight or save. For example, if you want to extract the potential of green hydrogen for agriculture from a variety of general publications, you can explicitly define this in the analysis rules.")
@TA("The analysis rules specify what the AI should pay particular attention to while reviewing the documents you provide, and which aspects it should highlight or save. For example, if you want to extract the potential of green hydrogen for agriculture from a variety of general publications, you can explicitly define this in the analysis rules.")
</MudJustifiedText>
<MudTextField T="string" Disabled="@this.IsNoPolicySelectedOrProtected" @bind-Text="@this.policyAnalysisRules" Validation="@this.ValidateAnalysisRules" Immediate="@true" Label="@T("Analysis rules")" HelperText="@T("Please provide a description of your analysis rules. This rules will be used to instruct the AI on how to analyze the documents.")" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="5" Sizing="InputSizing.Auto" MaxLines="26" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<MudTextField T="string" Disabled="@this.IsNoPolicySelectedOrProtected" @bind-Text="@this.policyAnalysisRules" Validation="@this.ValidateAnalysisRules" Immediate="@true" Label="@T("Analysis rules")" HelperText="@TA("Please provide a description of your analysis rules. These rules will be used to instruct the AI on how to analyze the documents.")" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="5" Sizing="InputSizing.Auto" MaxLines="26" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
@* No default target for the rule zones: while the policy definition is open, three
zones are in play, so each drop has to be aimed at the one it belongs to. *@
<ReadFileContent Text="@T("Load analysis rules from document")" @bind-FileContent="@this.policyAnalysisRules" EnableDragDrop="true" Disabled="@this.IsNoPolicySelectedOrProtected"/>
<MudJustifiedText Typo="Typo.body1" Class="mt-3">
@T("After the AI has processed all documents, it needs your instructions on how the result should be formatted. Would you like a structured list with keywords or a continuous text? Should the output include emojis or be written in formal business language? You can specify all these preferences in the output rules. There, you can also predefine a desired structure—for example, by using Markdown formatting to define headings, paragraphs, or bullet points.")
@TA("After the AI has processed all documents, it needs your instructions on how the result should be formatted. Would you like a structured list with keywords or a continuous text? Should the output include emojis or be written in formal business language? You can specify all these preferences in the output rules. There, you can also predefine a desired structure—for example, by using Markdown formatting to define headings, paragraphs, or bullet points.")
</MudJustifiedText>
<MudTextField T="string" Disabled="@this.IsNoPolicySelectedOrProtected" @bind-Text="@this.policyOutputRules" Validation="@this.ValidateOutputRules" Immediate="@true" Label="@T("Output rules")" HelperText="@T("Please provide a description of your output rules. This rules will be used to instruct the AI on how to format the output of the analysis.")" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="5" Sizing="InputSizing.Auto" MaxLines="26" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<MudTextField T="string" Disabled="@this.IsNoPolicySelectedOrProtected" @bind-Text="@this.policyOutputRules" Validation="@this.ValidateOutputRules" Immediate="@true" Label="@T("Output rules")" HelperText="@TA("Please provide a description of your output rules. These rules will be used to instruct the AI on how to format the output of the analysis.")" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="5" Sizing="InputSizing.Auto" MaxLines="26" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<ReadFileContent Text="@T("Load output rules from document")" @bind-FileContent="@this.policyOutputRules" EnableDragDrop="true" Disabled="@this.IsNoPolicySelectedOrProtected"/>
@@ -41,7 +41,7 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
/// </summary>
protected override string ExportFileName => string.IsNullOrWhiteSpace(this.analyzedPolicyName) ? this.Title : this.analyzedPolicyName;
protected override string Description => T("The document analysis assistant helps you to analyze and extract information from documents based on predefined policies. You can create, edit, and manage document analysis policies that define how documents should be processed and what information should be extracted. Some policies might be protected by your organization and cannot be modified or deleted.");
protected override string Description => TA("The document analysis assistant helps you to analyze and extract information from documents based on predefined policies. You can create, edit, and manage document analysis policies that define how documents should be processed and what information should be extracted. Some policies might be protected by your organization and cannot be modified or deleted.");
// The prompt of this assistant demands the output of the policy and nothing else, so the chat gets a prompt of its own, which keeps the policy:
protected override ChatSystemPromptChoice ChatSystemPrompt => ChatSystemPromptChoice.Custom(this.CreateChatSystemPrompt);
@@ -162,7 +162,7 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
protected override bool ShowSendTo => true;
protected override string SubmitText => T("Analyze the documents based on your chosen policy");
protected override string SubmitText => TA("Analyze the documents based on your chosen policy");
protected override Func<Task> SubmitAction => this.Analyze;
@@ -191,7 +191,7 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
ContentType = ContentType.TEXT,
Content = new ContentText
{
Text = this.T("The result of your previous document analysis session."),
Text = this.TA("The result of your previous document analysis session."),
FileAttachments = this.loadedDocumentPaths.ToList(),
}
},
@@ -572,7 +572,7 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
var dialogParameters = new DialogParameters<ConfirmDialog>
{
{ x => x.Message, string.Format(T("Are you sure you want to delete the document analysis policy '{0}'?"), this.selectedPolicy.PolicyName) },
{ x => x.Message, string.Format(TA("Are you sure you want to delete the document analysis policy '{0}'?"), this.selectedPolicy.PolicyName) },
};
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>(T("Delete document analysis policy"), dialogParameters, DialogOptions.FULLSCREEN);
@@ -830,13 +830,13 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
return null;
if(string.IsNullOrWhiteSpace(name))
return T("Please provide a name for your policy. This name will be used to identify the policy in AI Studio.");
return TA("Please provide a name for your policy. This name will be used to identify the policy in AI Studio.");
if(name.Length is > 60 or < 6)
return T("The name of your policy must be between 6 and 60 characters long.");
return TA("The name of your policy must be between 6 and 60 characters long.");
if(this.SettingsManager.ConfigurationData.DocumentAnalysis.Policies.Where(n => n != this.selectedPolicy).Any(n => n.PolicyName == name))
return T("A policy with this name already exists. Please choose a different name.");
return TA("A policy with this name already exists. Please choose a different name.");
return null;
}
@@ -847,10 +847,10 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
return null;
if(string.IsNullOrWhiteSpace(description))
return T("Please provide a description for your policy. This description will be used to inform users about the purpose of your document analysis policy.");
return TA("Please provide a description for your policy. This description will be used to inform users about the purpose of your document analysis policy.");
if(description.Length is < 32 or > 512)
return T("The description of your policy must be between 32 and 512 characters long.");
return TA("The description of your policy must be between 32 and 512 characters long.");
return null;
}
@@ -858,7 +858,7 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
private string? ValidateAnalysisRules(string analysisRules)
{
if(string.IsNullOrWhiteSpace(analysisRules))
return T("Please provide a description of your analysis rules. This rules will be used to instruct the AI on how to analyze the documents.");
return TA("Please provide a description of your analysis rules. These rules will be used to instruct the AI on how to analyze the documents.");
return null;
}
@@ -866,7 +866,7 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
private string? ValidateOutputRules(string outputRules)
{
if(string.IsNullOrWhiteSpace(outputRules))
return T("Please provide a description of your output rules. This rules will be used to instruct the AI on how to format the output of the analysis.");
return TA("Please provide a description of your output rules. These rules will be used to instruct the AI on how to format the output of the analysis.");
return null;
}
@@ -1011,7 +1011,7 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
{
if (this.IsNoPolicySelected)
{
await this.MessageBus.SendError(new (AppIcons.ANALYSIS_POLICY, this.T("No policy is selected. Please select a policy to export.")));
await this.MessageBus.SendError(new (AppIcons.ANALYSIS_POLICY, this.TA("No policy is selected. Please select a policy to export.")));
return;
}
@@ -1035,7 +1035,7 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
policyIssues.Count,
string.Join(" | ", policyIssues));
await this.MessageBus.SendError(new (AppIcons.ANALYSIS_POLICY, $"{this.T("The selected policy contains invalid data. Please fix the issues before exporting the policy.")} {string.Join(" ", policyIssues)}"));
await this.MessageBus.SendError(new (AppIcons.ANALYSIS_POLICY, $"{this.TA("The selected policy contains invalid data. Please fix the issues before exporting the policy.")} {string.Join(" ", policyIssues)}"));
return;
}
@@ -708,7 +708,7 @@ public partial class AssistantDynamic : AssistantBaseCore<NoSettingsPanel>
private string? ValidateProfileSelection(AssistantProfileSelection profileSelection, Profile? profile)
{
if (profile != null && profile != Profile.NO_PROFILE) return null;
return !string.IsNullOrWhiteSpace(profileSelection.ValidationMessage) ? profileSelection.ValidationMessage : this.T("Please select one of your profiles.");
return !string.IsNullOrWhiteSpace(profileSelection.ValidationMessage) ? profileSelection.ValidationMessage : this.TA("Please select one of your profiles.");
}
private async Task Submit()
@@ -5,13 +5,13 @@
@if (this.provideHistory)
{
<MudPaper Class="pa-3 mb-8 border-dashed border rounded-lg">
<MudTextField T="string" @bind-Text="@this.inputHistory" Validation="@this.ValidateHistory" Label="@T("Previous conversation")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("Provide the previous conversation, e.g., the last e-mail, the last chat, etc.")" Class="mb-3" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.INPUT_TEXT"/>
<MudTextField T="string" @bind-Text="@this.inputHistory" Validation="@this.ValidateHistory" Label="@T("Previous conversation")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@TA("Provide the previous conversation, e.g., the last e-mail, the last chat, etc.")" Class="mb-3" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.INPUT_TEXT"/>
</MudPaper>
}
<MudTextField T="string" @bind-Text="@this.inputGreeting" Label="@T("(Optional) The greeting phrase to use")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.USER" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" Placeholder="@T("Dear Colleagues")" Class="mb-3"/>
<DebouncedTextField @bind-Text="@this.inputBulletPoints" ValidationFunc="@this.ValidateBulletPoints" Icon="@AppIcons.LIST" Label="@T("Your bullet points")" Lines="6" MaxLines="12" Attributes="@USER_INPUT_ATTRIBUTES" HelpText="@T("Bullet list the content of the e-mail roughly. Use dashes (-) to separate the items.")" DebounceTime="TimeSpan.FromSeconds(1)" WhenTextCanged="@this.OnContentChanged" Placeholder="@PLACEHOLDER_BULLET_POINTS"/>
<MudSelect T="string" Label="@T("(Optional) Are any of your points particularly important?")" MultiSelection="@true" @bind-SelectedValues="@this.selectedFoci" Variant="Variant.Outlined" Class="mb-3" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.LIST">
<DebouncedTextField @bind-Text="@this.inputBulletPoints" ValidationFunc="@this.ValidateBulletPoints" Icon="@AppIcons.LIST" Label="@TA("Your bullet points")" Lines="6" MaxLines="12" Attributes="@USER_INPUT_ATTRIBUTES" HelpText="@TA("Bullet list the content of the e-mail roughly. Use dashes (-) to separate the items.")" DebounceTime="TimeSpan.FromSeconds(1)" WhenTextCanged="@this.OnContentChanged" Placeholder="@PLACEHOLDER_BULLET_POINTS"/>
<MudSelect T="string" Label="@TA("(Optional) Are any of your points particularly important?")" MultiSelection="@true" @bind-SelectedValues="@this.selectedFoci" Variant="Variant.Outlined" Class="mb-3" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.LIST">
@foreach (var contentLine in this.bulletPointsLines)
{
<MudSelectItem T="string" Value="@contentLine">
@@ -19,7 +19,7 @@
</MudSelectItem>
}
</MudSelect>
<MudTextField T="string" @bind-Text="@this.inputName" Label="@T("(Optional) Your name for the closing salutation")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.USER" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("Your name for the closing salutation of your e-mail.")" Class="mb-3"/>
<MudTextField T="string" @bind-Text="@this.inputName" Label="@TA("(Optional) Your name for the closing salutation")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.USER" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@TA("Your name for the closing salutation of your e-mail.")" Class="mb-3"/>
<EnumSelection T="WritingStyles" NameFunc="@(style => style.Name)" @bind-Value="@this.selectedWritingStyle" Icon="@AppIcons.WRITING_STYLE" Label="@T("Select the writing style")" ValidateSelection="@this.ValidateWritingStyle"/>
<EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelecting)" @bind-Value="@this.selectedTargetLanguage" ValidateSelection="@this.ValidateTargetLanguage" Icon="@AppIcons.LANGUAGE" Label="@T("Target language")" AllowOther="@true" OtherValue="CommonLanguages.OTHER" @bind-OtherInput="@this.customTargetLanguage" ValidateOther="@this.ValidateCustomLanguage" LabelOther="@T("Custom target language")" />
<ProviderSelection @bind-ProviderSettings="@this.ProviderSettings" ValidateProvider="@this.ValidatingProvider"/>
@@ -12,7 +12,7 @@ public partial class AssistantEMail : AssistantBaseCore<SettingsDialogWritingEMa
protected override string Title => T("E-Mail");
protected override string Description => T("Provide a list of bullet points and some basic information for an e-mail. The assistant will generate an e-mail based on that input.");
protected override string Description => TA("Provide a list of bullet points and some basic information for an e-mail. The assistant will generate an e-mail based on that input.");
// The prompt of this assistant describes an automated system which only writes the email, so the chat gets a prompt of its own, which keeps the settings of the email:
protected override ChatSystemPromptChoice ChatSystemPrompt => ChatSystemPromptChoice.Custom(this.CreateChatSystemPrompt);
@@ -150,12 +150,12 @@ public partial class AssistantEMail : AssistantBaseCore<SettingsDialogWritingEMa
private string? ValidateBulletPoints(string content)
{
if(string.IsNullOrWhiteSpace(content))
return T("Please provide some content for the e-mail.");
return TA("Please provide some content for the e-mail.");
var lines = content.Split('\n', StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
if(!line.TrimStart().StartsWith('-'))
return T("Please start each line of your content list with a dash (-) to create a bullet point list.");
return TA("Please start each line of your content list with a dash (-) to create a bullet point list.");
return null;
}
@@ -163,7 +163,7 @@ public partial class AssistantEMail : AssistantBaseCore<SettingsDialogWritingEMa
private string? ValidateTargetLanguage(CommonLanguages language)
{
if(language is CommonLanguages.AS_IS)
return T("Please select a target language for the e-mail.");
return TA("Please select a target language for the e-mail.");
return null;
}
@@ -171,7 +171,7 @@ public partial class AssistantEMail : AssistantBaseCore<SettingsDialogWritingEMa
private string? ValidateCustomLanguage(string language)
{
if(this.selectedTargetLanguage == CommonLanguages.OTHER && string.IsNullOrWhiteSpace(language))
return T("Please provide a custom language.");
return TA("Please provide a custom language.");
return null;
}
@@ -179,7 +179,7 @@ public partial class AssistantEMail : AssistantBaseCore<SettingsDialogWritingEMa
private string? ValidateWritingStyle(WritingStyles style)
{
if(style == WritingStyles.NONE)
return T("Please select a writing style for the e-mail.");
return TA("Please select a writing style for the e-mail.");
return null;
}
@@ -187,7 +187,7 @@ public partial class AssistantEMail : AssistantBaseCore<SettingsDialogWritingEMa
private string? ValidateHistory(string history)
{
if(this.provideHistory && string.IsNullOrWhiteSpace(history))
return T("Please provide some history for the e-mail.");
return TA("Please provide some history for the e-mail.");
return null;
}
@@ -3,12 +3,14 @@ namespace AIStudio.Assistants.ERI;
public static class AllowedLLMProvidersExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(AllowedLLMProvidersExtensions).Namespace, nameof(AllowedLLMProvidersExtensions));
private static string TA(string fallbackEN) => Tools.PluginSystem.I18N.I.TA(fallbackEN, typeof(AllowedLLMProvidersExtensions).Namespace, nameof(AllowedLLMProvidersExtensions));
extension(AllowedLLMProviders provider)
{
public string Description => provider switch
{
AllowedLLMProviders.NONE => TB("Please select what kind of LLM provider are allowed for this data source"),
AllowedLLMProviders.NONE => TA("Please select which kinds of LLM providers are allowed for this data source."),
AllowedLLMProviders.ANY => TB("Any LLM provider is allowed: users might choose a cloud-based or a self-hosted provider"),
AllowedLLMProviders.SELF_HOSTED => TB("Self-hosted LLM providers are allowed: users cannot choose any cloud-based provider"),
@@ -5,7 +5,7 @@
@using MudExtensions
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
@T("You can imagine it like this: Hypothetically, when Wikipedia implemented the ERI, it would vectorize all pages using an embedding method. All of Wikipedia’s data would remain with Wikipedia, including the vector database (decentralized approach). Then, any AI Studio user could add Wikipedia as a data source to significantly reduce the hallucination of the LLM in knowledge questions.")
@TA("You can imagine it like this: Hypothetically, when Wikipedia implemented the ERI, it would vectorize all pages using an embedding method. All of Wikipedia’s data would remain with Wikipedia, including the vector database (decentralized approach). Then, any AI Studio user could add Wikipedia as a data source to significantly reduce the hallucination of the LLM in knowledge questions.")
</MudJustifiedText>
<MudText Typo="Typo.body1">
@@ -30,13 +30,13 @@
</MudText>
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
@T("Here you have the option to save different configurations for various ERI servers and switch between them. This is useful if you are responsible for multiple ERI servers.")
@TA("Here you have the option to save different configurations for various ERI servers and switch between them. This is useful if you are responsible for multiple ERI servers.")
</MudJustifiedText>
@if(this.SettingsManager.ConfigurationData.ERI.ERIServers.Count is 0)
{
<MudText Typo="Typo.body1" Class="mb-3">
@T("You have not yet added any ERI server presets.")
@TA("You have not yet added any ERI server presets.")
</MudText>
}
else
@@ -63,7 +63,7 @@ else
@if(this.AreServerPresetsBlocked)
{
<MudJustifiedText Typo="Typo.body1" Class="mb-3 mt-3">
@T("Hint: to allow this assistant to manage multiple presets, you must enable the preselection of values in the settings.")
@TA("Hint: to allow this assistant to manage multiple presets, you must enable the preselection of values in the settings.")
</MudJustifiedText>
}
@@ -72,13 +72,13 @@ else
</MudText>
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
@T("The ERI specification will change over time. You probably want to keep your ERI server up to date. This means you might want to regenerate the code for your ERI server. To avoid having to make all inputs each time, all your inputs and decisions can be automatically saved. Would you like this?")
@TA("The ERI specification will change over time. You probably want to keep your ERI server up to date. This means you might want to regenerate the code for your ERI server. To avoid having to enter everything again each time, all your inputs and decisions can be automatically saved. Would you like this?")
</MudJustifiedText>
@if(this.AreServerPresetsBlocked)
{
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
@T("Hint: to allow this assistant to automatically save your changes, you must enable the preselection of values in the settings.")
@TA("Hint: to allow this assistant to automatically save your changes, you must enable the preselection of values in the settings.")
</MudJustifiedText>
}
@@ -89,8 +89,8 @@ else
<MudText Typo="Typo.h4" Class="mt-6 mb-1">
@T("Common ERI server settings")
</MudText>
<MudTextField T="string" Disabled="@this.IsERIInputDisabled" @bind-Text="@this.serverName" Validation="@this.ValidateServerName" Immediate="@true" Label="@T("ERI server name")" HelperText="@T("Please give your ERI server a name that provides information about the data source and/or its intended purpose. The name will be displayed to users in AI Studio.")" Counter="60" MaxLength="60" Variant="Variant.Outlined" Margin="Margin.Normal" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3" OnKeyUp="() => this.ServerNameWasChanged()"/>
<MudTextField T="string" Disabled="@this.IsERIInputDisabled" @bind-Text="@this.serverDescription" Validation="@this.ValidateServerDescription" Immediate="@true" Label="@T("ERI server description")" HelperText="@T("Please provide a brief description of your ERI server. Describe or explain what your ERI server does and what data it uses for this purpose. This description will be shown to users in AI Studio.")" Counter="512" MaxLength="512" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="3" Sizing="InputSizing.Auto" MaxLines="6" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<MudTextField T="string" Disabled="@this.IsERIInputDisabled" @bind-Text="@this.serverName" Validation="@this.ValidateServerName" Immediate="@true" Label="@T("ERI server name")" HelperText="@TA("Please give your ERI server a name that provides information about the data source and/or its intended purpose. The name will be displayed to users in AI Studio.")" Counter="60" MaxLength="60" Variant="Variant.Outlined" Margin="Margin.Normal" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3" OnKeyUp="() => this.ServerNameWasChanged()"/>
<MudTextField T="string" Disabled="@this.IsERIInputDisabled" @bind-Text="@this.serverDescription" Validation="@this.ValidateServerDescription" Immediate="@true" Label="@T("ERI server description")" HelperText="@TA("Please provide a brief description of your ERI server. Describe or explain what your ERI server does and what data it uses for this purpose. This description will be shown to users in AI Studio.")" Counter="512" MaxLength="512" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="3" Sizing="InputSizing.Auto" MaxLines="6" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<MudStack Row="@true" Class="mb-3">
<MudSelect Disabled="@this.IsERIInputDisabled" T="ProgrammingLanguages" @bind-Value="@this.selectedProgrammingLanguage" AdornmentIcon="@AppIcons.CODE" Adornment="Adornment.Start" Label="@T("Programming language")" Variant="Variant.Outlined" Margin="Margin.Dense" Validation="@this.ValidateProgrammingLanguage">
@@ -136,7 +136,7 @@ else
</MudSelect>
@if (this.selectedDataSource is DataSources.CUSTOM)
{
<MudTextField Disabled="@this.IsERIInputDisabled" T="string" @bind-Text="@this.otherDataSource" Validation="@this.ValidateOtherDataSource" Label="@T("Describe your data source")" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="3" Sizing="InputSizing.Auto" MaxLines="6" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudTextField Disabled="@this.IsERIInputDisabled" T="string" @bind-Text="@this.otherDataSource" Validation="@this.ValidateOtherDataSource" Label="@TA("Describe your data source")" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="3" Sizing="InputSizing.Auto" MaxLines="6" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
}
</MudStack>
@@ -155,7 +155,7 @@ else
@if (this.dataSourcePort < 1024)
{
<MudText Typo="Typo.body2">
<b>@T("Warning:")</b> @T("Ports below 1024 are reserved for system services. Your ERI server need to run with elevated permissions (root user).")
<b>@T("Warning:")</b> @TA("Ports below 1024 are reserved for system services. Your ERI server need to run with elevated permissions (root user).")
</MudText>
}
</div>
@@ -190,7 +190,7 @@ else
@if (this.selectedAuthenticationMethods.Contains(Auth.KERBEROS))
{
<MudSelect Disabled="@this.IsERIInputDisabled" T="OperatingSystem" @bind-Value="@this.selectedOperatingSystem" Label="@T("Operating system on which your ERI will run")" Variant="Variant.Outlined" Margin="Margin.Dense" Validation="@this.ValidateOperatingSystem" Class="mb-1">
<MudSelect Disabled="@this.IsERIInputDisabled" T="OperatingSystem" @bind-Value="@this.selectedOperatingSystem" Label="@TA("Operating system on which your ERI server will run")" Variant="Variant.Outlined" Margin="Margin.Dense" Validation="@this.ValidateOperatingSystem" Class="mb-1">
@foreach (var os in Enum.GetValues<OperatingSystem>())
{
<MudSelectItem Value="@os">
@@ -218,11 +218,11 @@ else
</MudText>
<MudJustifiedText Typo="Typo.body1" Class="mb-2">
@T("You will likely use one or more embedding methods to encode the meaning of your data into a typically high-dimensional vector space. In this case, you will use a vector database to store and search these vectors (called embeddings). However, you don't have to use embedding methods. When your retrieval method works without any embedding, you can ignore this section. An example: You store files on a file server, and your retrieval method works exclusively with file names in the file system, so you don't need embeddings.")
@TA("You will likely use one or more embedding methods to encode the meaning of your data into a typically high-dimensional vector space. In this case, you will use a vector database to store and search these vectors (called embeddings). However, you don't have to use embedding methods. When your retrieval method works without any embedding, you can ignore this section. An example: You store files on a file server, and your retrieval method works exclusively with file names in the file system, so you don't need embeddings.")
</MudJustifiedText>
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
@T("You can specify more than one embedding method. This can be useful when you want to use different embeddings for different queries or data types. For example, one embedding for texts, another for images, and a third for videos, etc.")
@TA("You can specify more than one embedding method. This can be useful when you want to use different embeddings for different queries or data types. For example, one embedding for texts, another for images, and a third for videos, etc.")
</MudJustifiedText>
@if (!this.IsNoneERIServerSelected)
@@ -271,7 +271,7 @@ else
</MudText>
<MudJustifiedText Typo="Typo.body1" Class="mb-2">
@T("For your ERI server, you need to retrieve data that matches a chat or prompt in some way. We call this the retrieval process. You must describe at least one such process. You may offer several retrieval processes from which users can choose. This allows you to test with beta users which process works better. Or you might generally want to give users the choice so they can select the process that best suits their circumstances.")
@TA("For your ERI server, you need to retrieve data that matches a chat or prompt in some way. We call this the retrieval process. You must describe at least one such process. You may offer several retrieval processes from which users can choose. This allows you to test with beta users which process works better. Or you might generally want to give users the choice so they can select the process that best suits their circumstances.")
</MudJustifiedText>
@if (!this.IsNoneERIServerSelected)
@@ -313,17 +313,17 @@ else
</MudButton>
<MudJustifiedText Typo="Typo.body1" Class="mb-1">
@T("You can integrate additional libraries. Perhaps you want to evaluate the prompts in advance using a machine learning method or analyze them with a text mining approach? Or maybe you want to preprocess images in the prompts? For such advanced scenarios, you can specify which libraries you want to use here. It's best to describe which library you want to integrate for which purpose. This way, the LLM that writes the ERI server for you can try to use these libraries effectively. This should result in less rework being necessary. If you don't know the necessary libraries, you can instead attempt to describe the intended use. The LLM can then attempt to choose suitable libraries. However, hallucinations can occur, and fictional libraries might be selected.")
@TA("You can integrate additional libraries. Perhaps you want to evaluate the prompts in advance using a machine learning method or analyze them with a text mining approach? Or maybe you want to preprocess images in the prompts? For such advanced scenarios, you can specify which libraries you want to use here. It's best to describe which library you want to integrate for which purpose. This way, the LLM that writes the ERI server for you can try to use these libraries effectively. This should result in less rework being necessary. If you don't know the necessary libraries, you can instead attempt to describe the intended use. The LLM can then attempt to choose suitable libraries. However, hallucinations can occur, and fictional libraries might be selected.")
</MudJustifiedText>
<MudTextField Disabled="@this.IsERIInputDisabled" T="string" @bind-Text="@this.additionalLibraries" Label="@T("(Optional) Additional libraries")" HelperText="@T("Do you want to include additional libraries? Then name them and briefly describe what you want to achieve with them.")" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="3" Sizing="InputSizing.Auto" MaxLines="12" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<MudTextField Disabled="@this.IsERIInputDisabled" T="string" @bind-Text="@this.additionalLibraries" Label="@T("(Optional) Additional libraries")" HelperText="@TA("Do you want to include additional libraries? Then name them and briefly describe what you want to achieve with them.")" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="3" Sizing="InputSizing.Auto" MaxLines="12" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<MudText Typo="Typo.h4" Class="mt-9 mb-1">
@T("Provider selection for generation")
</MudText>
<MudJustifiedText Typo="Typo.body1" Class="mb-2">
@T("The task of writing the ERI server for you is very complex. Therefore, a very powerful LLM is needed to successfully accomplish this task. Small local models will probably not be sufficient. Instead, try using a large cloud-based or a large self-hosted model.")
@TA("The task of writing the ERI server for you is very complex. Therefore, a very powerful LLM is needed to successfully accomplish this task. Small local models will probably not be sufficient. Instead, try using a large cloud-based or a large self-hosted model.")
</MudJustifiedText>
<MudJustifiedText Typo="Typo.body1" Class="mb-2">
@@ -337,12 +337,12 @@ else
</MudText>
<MudJustifiedText Typo="Typo.body1" Class="mb-2">
@T("AI Studio can save the generated code to the file system. You can select a base folder for this. AI Studio ensures that no files are created outside of this base folder. Furthermore, we recommend that you create a Git repository in this folder. This way, you can see what changes the AI has made in which files.")
@TA("AI Studio can save the generated code to the file system. You can select a base folder for this. AI Studio ensures that no files are created outside of this base folder. Furthermore, we recommend that you create a Git repository in this folder. This way, you can see what changes the AI has made in which files.")
</MudJustifiedText>
<MudJustifiedText Typo="Typo.body1" Class="mb-2">
@T("When you rebuild / re-generate the ERI server code, AI Studio proceeds as follows: All files generated last time will be deleted. All other files you have created remain. Then, the AI generates the new files.") <b>@T("But beware:")</b> @T("It may happen that the AI generates a file this time that you manually created last time. In this case, your manually created file will then be overwritten. Therefore, you should always create a Git repository and commit or revert all changes before using this assistant. With a diff visualization, you can immediately see where the AI has made changes. It is best to use an IDE suitable for your selected language for this purpose.")
@TA("When you rebuild / re-generate the ERI server code, AI Studio proceeds as follows: All files generated last time will be deleted. All other files you have created remain. Then, the AI generates the new files.") <b>@T("But beware:")</b> @TA("It may happen that the AI generates a file this time that you manually created last time. In this case, your manually created file will then be overwritten. Therefore, you should always create a Git repository and commit or revert all changes before using this assistant. With a diff visualization, you can immediately see where the AI has made changes. It is best to use an IDE suitable for your selected language for this purpose.")
</MudJustifiedText>
<MudTextSwitch Label="@T("Should we write the generated code to the file system?")" Disabled="@this.IsERIInputDisabled" @bind-Value="@this.writeToFilesystem" LabelOn="@T("Yes, please write or update all generated code to the file system")" LabelOff="@T("No, just show me the code")" />
<SelectDirectory Label="@T("Base directory where to write the code")" @bind-Directory="@this.baseDirectory" Disabled="@this.IsBaseDirectorySelectionDisabled" DirectoryDialogTitle="@T("Select the target directory for the ERI server")" Validation="@this.ValidateDirectory" EnableDragDrop="true" CatchAllDocuments="true" />
<SelectDirectory Label="@T("Base directory where to write the code")" @bind-Directory="@this.baseDirectory" Disabled="@this.IsBaseDirectorySelectionDisabled" DirectoryDialogTitle="@TA("Select the target directory for the ERI server")" Validation="@this.ValidateDirectory" EnableDragDrop="true" CatchAllDocuments="true" />
@@ -349,7 +349,7 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
var dialogParameters = new DialogParameters<ConfirmDialog>
{
{ x => x.Message, string.Format(T("Are you sure you want to delete the ERI server preset '{0}'?"), this.selectedERIServer.ServerName) },
{ x => x.Message, string.Format(TA("Are you sure you want to delete the ERI server preset '{0}'?"), this.selectedERIServer.ServerName) },
};
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>(T("Delete ERI server preset"), dialogParameters, DialogOptions.FULLSCREEN);
@@ -445,13 +445,13 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
private string? ValidateServerName(string name)
{
if(string.IsNullOrWhiteSpace(name))
return T("Please provide a name for your ERI server. This name will be used to identify the server in AI Studio.");
return TA("Please provide a name for your ERI server. This name will be used to identify the server in AI Studio.");
if(name.Length is > 60 or < 6)
return T("The name of your ERI server must be between 6 and 60 characters long.");
return TA("The name of your ERI server must be between 6 and 60 characters long.");
if(this.SettingsManager.ConfigurationData.ERI.ERIServers.Where(n => n != this.selectedERIServer).Any(n => n.ServerName == name))
return T("An ERI server preset with this name already exists. Please choose a different name.");
return TA("An ERI server preset with this name already exists. Please choose a different name.");
return null;
}
@@ -459,10 +459,10 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
private string? ValidateServerDescription(string description)
{
if(string.IsNullOrWhiteSpace(description))
return T("Please provide a description for your ERI server. What data will the server retrieve? This description will be used to inform users about the purpose of your ERI server.");
return TA("Please provide a description for your ERI server. What data will the server retrieve? This description will be used to inform users about the purpose of your ERI server.");
if(description.Length is < 32 or > 512)
return T("The description of your ERI server must be between 32 and 512 characters long.");
return TA("The description of your ERI server must be between 32 and 512 characters long.");
return null;
}
@@ -470,7 +470,7 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
private string? ValidateERIVersion(ERIVersion version)
{
if (version == ERIVersion.NONE)
return T("Please select an ERI specification version for the ERI server.");
return TA("Please select an ERI specification version for the ERI server.");
return null;
}
@@ -481,7 +481,7 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
return null;
if (language == ProgrammingLanguages.NONE)
return T("Please select a programming language for the ERI server.");
return TA("Please select a programming language for the ERI server.");
return null;
}
@@ -492,7 +492,7 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
return null;
if(string.IsNullOrWhiteSpace(language))
return T("Please specify the custom programming language for the ERI server.");
return TA("Please specify the custom programming language for the ERI server.");
return null;
}
@@ -503,7 +503,7 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
return null;
if (dataSource == DataSources.NONE)
return T("Please select a data source for the ERI server.");
return TA("Please select a data source for the ERI server.");
return null;
}
@@ -514,7 +514,7 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
return null;
if(string.IsNullOrWhiteSpace(productName))
return T("Please specify the product name of the data source, e.g., 'MongoDB', 'Redis', 'PostgreSQL', 'Neo4j', or 'MinIO', etc.");
return TA("Please specify the product name of the data source, e.g., 'MongoDB', 'Redis', 'PostgreSQL', 'Neo4j', or 'MinIO', etc.");
return null;
}
@@ -525,7 +525,7 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
return null;
if(string.IsNullOrWhiteSpace(dataSource))
return T("Please describe the data source of your ERI server.");
return TA("Please describe the data source of your ERI server.");
return null;
}
@@ -540,7 +540,7 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
return null;
if(string.IsNullOrWhiteSpace(hostname))
return T("Please provide the hostname of the data source. Use 'localhost' if the data source is on the same machine as the ERI server.");
return TA("Please provide the hostname of the data source. Use 'localhost' if the data source is on the same machine as the ERI server.");
if(hostname.Length > 255)
return T("The hostname of the data source must not exceed 255 characters.");
@@ -558,7 +558,7 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
return null;
if(port is null)
return T("Please provide the port of the data source.");
return TA("Please provide the port of the data source.");
if(port is < 1 or > 65535)
return T("The port of the data source must be between 1 and 65535.");
@@ -606,7 +606,7 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
{
var authenticationMethods = (this.selectedAuthenticationMethods as HashSet<Auth>)!;
if(authenticationMethods.Count == 0)
return T("Please select at least one authentication method for the ERI server.");
return TA("Please select at least one authentication method for the ERI server.");
return null;
}
@@ -636,7 +636,7 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
return null;
if(os is OperatingSystem.NONE)
return T("Please select the operating system on which the ERI server will run. This is necessary when using SSO with Kerberos.");
return TA("Please select the operating system on which the ERI server will run. This is necessary when using SSO with Kerberos.");
return null;
}
@@ -644,12 +644,12 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
private string? ValidateAllowedLLMProviders(AllowedLLMProviders provider)
{
if(provider == AllowedLLMProviders.NONE)
return T("Please select which types of LLMs users are allowed to use with the data from this ERI server.");
return TA("Please select which types of LLMs users are allowed to use with the data from this ERI server.");
return null;
}
private string AuthDescriptionTitle() => this.IsAuthDescriptionOptional() ? T("(Optional) Describe how you planned the authentication process") : T("Describe how you planned the authentication process");
private string AuthDescriptionTitle() => this.IsAuthDescriptionOptional() ? TA("(Optional) Describe how you planned the authentication process") : TA("Describe how you planned the authentication process");
private bool IsAuthDescriptionOptional()
{
@@ -669,10 +669,10 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
{
var authenticationMethods = (this.selectedAuthenticationMethods as HashSet<Auth>)!;
if(authenticationMethods.Any(n => n == Auth.NONE) && authenticationMethods.Count > 1 && string.IsNullOrWhiteSpace(this.authDescription))
return T("Please describe how the selected authentication methods should be used. Especially, explain for what data the NONE method (public access) is used.");
return TA("Please describe how the selected authentication methods should be used. Especially, explain for what data the NONE method (public access) is used.");
if(authenticationMethods.Count > 1 && string.IsNullOrWhiteSpace(this.authDescription))
return T("Please describe how the selected authentication methods should be used.");
return TA("Please describe how the selected authentication methods should be used.");
return null;
}
@@ -683,7 +683,7 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
return null;
if(string.IsNullOrWhiteSpace(path))
return T("Please provide a base directory for the ERI server to write files to.");
return TA("Please provide a base directory for the ERI server to write files to.");
return null;
}
@@ -691,12 +691,12 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
private string GetMultiSelectionAuthText(List<Auth> selectedValues)
{
if(selectedValues.Count == 0)
return T("Please select at least one authentication method");
return TA("Please select at least one authentication method");
if(selectedValues.Count == 1)
return T("You have selected 1 authentication method");
return TA("You have selected 1 authentication method");
return string.Format(T("You have selected {0} authentication methods"), selectedValues.Count);
return string.Format(TA("You have selected {0} authentication methods"), selectedValues.Count);
}
private bool NeedHostnamePort()
@@ -767,8 +767,8 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
return;
var message = this.retrievalProcesses.Any(n => n.Embeddings?.Contains(embeddingInfo) is true)
? string.Format(T("The embedding '{0}' is used in one or more retrieval processes. Are you sure you want to delete it?"), embeddingInfo.EmbeddingName)
: string.Format(T("Are you sure you want to delete the embedding '{0}'?"), embeddingInfo.EmbeddingName);
? string.Format(TA("The embedding '{0}' is used in one or more retrieval processes. Are you sure you want to delete it?"), embeddingInfo.EmbeddingName)
: string.Format(TA("Are you sure you want to delete the embedding '{0}'?"), embeddingInfo.EmbeddingName);
var dialogParameters = new DialogParameters<ConfirmDialog>
{
@@ -844,7 +844,7 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
var dialogParameters = new DialogParameters<ConfirmDialog>
{
{ x => x.Message, string.Format(T("Are you sure you want to delete the retrieval process '{0}'?"), retrievalInfo.Name) },
{ x => x.Message, string.Format(TA("Are you sure you want to delete the retrieval process '{0}'?"), retrievalInfo.Name) },
};
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>(T("Delete Retrieval Process"), dialogParameters, DialogOptions.FULLSCREEN);
@@ -868,7 +868,7 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
if(this.retrievalProcesses.Count == 0)
{
this.AddInputIssue(T("Please describe at least one retrieval process."));
this.AddInputIssue(TA("Please describe at least one retrieval process."));
return;
}
@@ -879,7 +879,7 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
this.eriSpecification = await this.selectedERIVersion.ReadSpecification(this.WebRootFiles);
if (string.IsNullOrWhiteSpace(this.eriSpecification))
{
this.AddInputIssue(T("The ERI specification could not be loaded. Please try again later."));
this.AddInputIssue(TA("The ERI specification could not be loaded. Please try again later."));
return;
}
@@ -917,7 +917,7 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
if (!ERIServerFileList.TryParse(fileListAnswer, out var filesToGenerate))
{
this.Logger.LogWarning("The list of files could not be read from the answer of the model: '{Answer}'", fileListAnswer);
await this.MessageBus.SendWarning(new(AppIcons.SAVE_FAILED, T("The list of files in the answer of the model could not be read, so no files were created. Please try again.")));
await this.MessageBus.SendWarning(new(AppIcons.SAVE_FAILED, TA("The list of files in the answer of the model could not be read, so no files were created. Please try again.")));
return;
}
@@ -11,6 +11,8 @@ internal static class ERIServerFileOutcomeExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(ERIServerFileOutcomeExtensions).Namespace, nameof(ERIServerFileOutcomeExtensions));
private static string TA(string fallbackEN) => Tools.PluginSystem.I18N.I.TA(fallbackEN, typeof(ERIServerFileOutcomeExtensions).Namespace, nameof(ERIServerFileOutcomeExtensions));
/// <param name="outcome">What became of the file.</param>
extension(ERIServerFileOutcome outcome)
{
@@ -25,7 +27,7 @@ internal static class ERIServerFileOutcomeExtensions
private static string ToUserMessageFormat(ERIServerFileOutcome outcome) => outcome switch
{
ERIServerFileOutcome.OUTSIDE_BASE_DIRECTORY => TB("The file '{0}' was not written, because its path leads outside the base directory."),
ERIServerFileOutcome.NO_COMPLETE_CODE_BLOCK => TB("The file '{0}' was not written, because the answer of the model contains no complete code block for it. You find the answer in the conversation."),
ERIServerFileOutcome.NO_COMPLETE_CODE_BLOCK => TA("The file '{0}' was not written, because the answer of the model contains no complete code block for it. You find the answer in the conversation."),
ERIServerFileOutcome.WRITE_FAILED => TB("The file '{0}' could not be written. The log of AI Studio names the reason."),
_ => TB("The file '{0}' was not written."),
@@ -2,6 +2,6 @@
@inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogGrammarSpelling>
<ReadFileContent Text="@T("Load text from file")" @bind-FileContent="@this.inputText" EnableDragDrop="true" CatchAllDocuments="true"/>
<MudTextField T="string" @bind-Text="@this.inputText" Validation="@this.ValidateText" AdornmentIcon="@AppIcons.INPUT_TEXT" Adornment="Adornment.Start" Label="@T("Your input to check")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudTextField T="string" @bind-Text="@this.inputText" Validation="@this.ValidateText" AdornmentIcon="@AppIcons.INPUT_TEXT" Adornment="Adornment.Start" Label="@TA("Your input to check")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelectingOptional)" @bind-Value="@this.selectedTargetLanguage" Icon="@AppIcons.LANGUAGE" Label="@T("Language")" AllowOther="@true" OtherValue="CommonLanguages.OTHER" @bind-OtherInput="@this.customTargetLanguage" ValidateOther="@this.ValidateCustomLanguage" LabelOther="@T("Custom language")" />
<ProviderSelection @bind-ProviderSettings="@this.ProviderSettings" ValidateProvider="@this.ValidatingProvider"/>
@@ -122,7 +122,7 @@ public partial class AssistantGrammarSpelling : AssistantBaseCore<SettingsDialog
private string? ValidateText(string text)
{
if(string.IsNullOrWhiteSpace(text))
return T("Please provide a text as input. You might copy the desired text from a document or a website.");
return TA("Please provide a text as input. You might copy the desired text from a document or a website.");
return null;
}
@@ -130,7 +130,7 @@ public partial class AssistantGrammarSpelling : AssistantBaseCore<SettingsDialog
private string? ValidateCustomLanguage(string language)
{
if(this.selectedTargetLanguage == CommonLanguages.OTHER && string.IsNullOrWhiteSpace(language))
return T("Please provide a custom language.");
return TA("Please provide a custom language.");
return null;
}
@@ -3,7 +3,7 @@
@inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogI18N>
<EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelecting)" @bind-Value="@this.selectedTargetLanguage" ValidateSelection="@this.ValidatingTargetLanguage" Icon="@AppIcons.LANGUAGE" Label="@T("Target language")" AllowOther="@true" OtherValue="CommonLanguages.OTHER" @bind-OtherInput="@this.customTargetLanguage" ValidateOther="@this.ValidateCustomLanguage" LabelOther="@T("Custom target language")" SelectionUpdated="_ => this.OnChangedLanguage()" Disabled="@this.IsProcessing" />
<ConfigurationSelect OptionDescription="@T("Language plugin used for comparision")" SelectedValue="@(() => this.selectedLanguagePluginId)" Data="@ConfigurationSelectDataFactory.GetLanguagesData()" SelectionUpdate="@(async void (id) => await this.OnLanguagePluginChanged(id))" OptionHelp="@T("Select the language plugin used for comparision.")" Disabled="@(() => this.IsProcessing)"/>
<ConfigurationSelect OptionDescription="@T("Language plugin used for comparision")" SelectedValue="@(() => this.selectedLanguagePluginId)" Data="@ConfigurationSelectDataFactory.GetLanguagesData()" SelectionUpdate="@(async void (id) => await this.OnLanguagePluginChanged(id))" OptionHelp="@TA("Select the language plugin used for comparision.")" Disabled="@(() => this.IsProcessing)"/>
@if (this.isLoading)
{
<MudText Typo="Typo.body1" Class="mb-6">
@@ -76,7 +76,7 @@ else if (!this.isLoading && string.IsNullOrWhiteSpace(this.loadingIssue))
@if (this.selectedTargetLanguage is CommonLanguages.EN_US)
{
<MudJustifiedText Typo="Typo.body1" Class="mb-6">
@T("Please note: neither is a translation needed nor performed for English (USA). Anyway, you might want to generate the related Lua code.")
@TA("Please note: neither is a translation needed nor performed for English (USA). Anyway, you might want to generate the related Lua code.")
</MudJustifiedText>
}
else
@@ -15,7 +15,7 @@ public partial class AssistantI18N : AssistantBaseCore<SettingsDialogI18N>
protected override string Title => T("Localization");
protected override string Description => T("Translate MindWork AI Studio text content into another language.");
protected override string Description => TA("Translate MindWork AI Studio text content into another language.");
// This assistant writes language plugins, so no chat continues its conversation:
protected override ChatSystemPromptChoice ChatSystemPrompt => ChatSystemPromptChoice.AI_STUDIO_DEFAULT;
@@ -224,12 +224,12 @@ public partial class AssistantI18N : AssistantBaseCore<SettingsDialogI18N>
this.localizationPossible = false;
if (PluginFactory.RunningPlugins.FirstOrDefault(n => n is PluginLanguage && n.Id == this.selectedLanguagePluginId) is not PluginLanguage comparisonPlugin)
{
this.loadingIssue = string.Format(T("Was not able to load the language plugin for comparison ({0}). Please select a valid, loaded & running language plugin."), this.selectedLanguagePluginId);
this.loadingIssue = string.Format(TA("Was not able to load the language plugin for comparison ({0}). Please select a valid, loaded & running language plugin."), this.selectedLanguagePluginId);
this.selectedLanguagePlugin = null;
}
else if (comparisonPlugin.IETFTag != this.selectedTargetLanguage.IETFTag)
{
this.loadingIssue = string.Format(T("The selected language plugin for comparison uses the IETF tag '{0}' which does not match the selected target language '{1}'. Please select a valid, loaded & running language plugin which matches the target language."), comparisonPlugin.IETFTag, this.selectedTargetLanguage.IETFTag);
this.loadingIssue = string.Format(TA("The selected language plugin for comparison uses the IETF tag '{0}', which does not match the selected target language '{1}'. Please select a valid, loaded & running language plugin which matches the target language."), comparisonPlugin.IETFTag, this.selectedTargetLanguage.IETFTag);
this.selectedLanguagePlugin = null;
}
else
@@ -246,7 +246,7 @@ public partial class AssistantI18N : AssistantBaseCore<SettingsDialogI18N>
{
if (this.selectedLanguagePlugin is null)
{
this.loadingIssue = T("Please select a language plugin for comparison.");
this.loadingIssue = TA("Please select a language plugin for comparison.");
this.localizationPossible = false;
this.isLoading = false;
this.StateHasChanged();
@@ -273,7 +273,7 @@ public partial class AssistantI18N : AssistantBaseCore<SettingsDialogI18N>
break;
case NoPlugin:
this.loadingIssue = T("Was not able to load the I18N plugin. Please check the plugin code.");
this.loadingIssue = TA("Was not able to load the I18N plugin. Please check the plugin code.");
break;
case { IsValid: false } plugin when plugin.Issues.Any():
@@ -313,7 +313,7 @@ public partial class AssistantI18N : AssistantBaseCore<SettingsDialogI18N>
private string? ValidatingTargetLanguage(CommonLanguages language)
{
if(language == CommonLanguages.AS_IS)
return T("Please select a target language.");
return TA("Please select a target language.");
return null;
}
@@ -321,7 +321,7 @@ public partial class AssistantI18N : AssistantBaseCore<SettingsDialogI18N>
private string? ValidateCustomLanguage(string language)
{
if(this.selectedTargetLanguage == CommonLanguages.OTHER && string.IsNullOrWhiteSpace(language))
return T("Please provide a custom language.");
return TA("Please provide a custom language.");
return null;
}
@@ -408,7 +408,15 @@ public partial class AssistantI18N : AssistantBaseCore<SettingsDialogI18N>
if(this.CancellationTokenSource!.IsCancellationRequested)
return;
//
// English addresses everybody alike, so its informal variants read like the
// formal texts of the plugin, also where the plugin words a text differently
// than the source code does:
//
if (this.selectedTargetLanguage is CommonLanguages.EN_US)
I18NAddressPrompt.AlignInformalVariants(this.localizedContent);
//
// Phase 2: Create the Lua code. Each comment names the English text, which
// allTexts.lua holds for every key of the result. The English language plugin
@@ -40,6 +40,24 @@ public static class I18NAddressPrompt
return null;
}
/// <summary>
/// Gives every informal variant the words of its formal text, for a language with one form of address only.
/// </summary>
/// <remarks>
/// English addresses everybody alike, yet its language plugin may word a text differently than the source code
/// does. An informal variant taken from the source code would then differ from the formal text, and the language
/// would offer the choice of address, see <see cref="AIStudio.Tools.PluginSystem.LanguagePluginExtensions"/>.
/// </remarks>
/// <param name="content">All texts of the language plugin, by their keys; changed in place.</param>
public static void AlignInformalVariants(IDictionary<string, string> content)
{
foreach (var key in content.Keys.ToList())
{
if (I18NAddressVariant.TryGetFormalKey(key, out var formalKey) && content.TryGetValue(formalKey, out var formalText))
content[key] = formalText;
}
}
/// <summary>
/// Gets the section of the system prompt about the form of address.
/// </summary>
File diff suppressed because it is too large. Load diff
@@ -1,10 +1,10 @@
@attribute [Route(Routes.ASSISTANT_ICON_FINDER)]
@inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogIconFinder>
<MudTextField T="string" @bind-Text="@this.inputContext" Validation="@this.ValidatingContext" AdornmentIcon="@AppIcons.DESCRIPTION" Adornment="Adornment.Start" Label="@T("Your context")" Variant="Variant.Outlined" Lines="3" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudTextField T="string" @bind-Text="@this.inputContext" Validation="@this.ValidatingContext" AdornmentIcon="@AppIcons.DESCRIPTION" Adornment="Adornment.Start" Label="@TA("Your context")" Variant="Variant.Outlined" Lines="3" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudStack Row="@true" AlignItems="AlignItems.Center" Class="mb-3">
<MudSelect T="IconSources" @bind-Value="@this.selectedIconSource" AdornmentIcon="@AppIcons.ICON_SOURCE" Adornment="Adornment.Start" Label="@T("Your icon source")" Variant="Variant.Outlined" Margin="Margin.Dense">
<MudSelect T="IconSources" @bind-Value="@this.selectedIconSource" AdornmentIcon="@AppIcons.ICON_SOURCE" Adornment="Adornment.Start" Label="@TA("Your icon source")" Variant="Variant.Outlined" Margin="Margin.Dense">
@foreach (var source in Enum.GetValues<IconSources>())
{
<MudSelectItem Value="@source">
@@ -10,7 +10,7 @@ public partial class AssistantIconFinder : AssistantBaseCore<SettingsDialogIconF
protected override string Title => T("Icon Finder");
protected override string Description => T("""Finding the right icon for a context, such as for a piece of text, is not easy. The first challenge: You need to extract a concept from your context, such as from a text. Let's take an example where your text contains statements about multiple departments. The sought-after concept could be "departments." The next challenge is that we need to anticipate the bias of the icon designers: under the search term "departments," there may be no relevant icons or only unsuitable ones. Depending on the icon source, it might be more effective to search for "buildings," for instance. LLMs assist you with both steps.""");
protected override string Description => TA("""Finding the right icon for a context, such as for a piece of text, is not easy. The first challenge: You need to extract a concept from your context, such as from a text. Let's take an example where your text contains statements about multiple departments. The sought-after concept could be "departments." The next challenge is that we need to anticipate the bias of the icon designers: under the search term "departments," there may be no relevant icons or only unsuitable ones. Depending on the icon source, it might be more effective to search for "buildings," for instance. LLMs assist you with both steps.""");
// The chat continues the search for icons, which this prompt describes:
protected override ChatSystemPromptChoice ChatSystemPrompt => ChatSystemPromptChoice.ASSISTANT;
@@ -87,7 +87,7 @@ public partial class AssistantIconFinder : AssistantBaseCore<SettingsDialogIconF
private string? ValidatingContext(string context)
{
if(string.IsNullOrWhiteSpace(context))
return T("Please provide a context. This will help the AI to find the right icon. You might type just a keyword or copy a sentence from your text, e.g., from a slide where you want to use the icon.");
return TA("Please provide a context. This will help the AI to find the right icon. You might type just a keyword or copy a sentence from your text, e.g., from a slide where you want to use the icon.");
return null;
}
@@ -2,19 +2,19 @@
@inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogJobPostings>
<MudTextField T="string" @bind-Text="@this.inputCompanyName" Label="@T("(Optional) The company name")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.COMPANY" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<MudTextField T="string" @bind-Text="@this.inputCountryLegalFramework" Label="@T("Provide the country, where the company is located")" Validation="@this.ValidateCountryLegalFramework" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.COUNTRY" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3" HelperText="@T("This is important to consider the legal framework of the country.")"/>
<MudTextField T="string" @bind-Text="@this.inputCountryLegalFramework" Label="@TA("Provide the country, where the company is located")" Validation="@this.ValidateCountryLegalFramework" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.COUNTRY" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3" HelperText="@T("This is important to consider the legal framework of the country.")"/>
@* Four zones, so no default target: every drop has to be aimed at the field it belongs to. *@
<ReadFileContent Text="@T("Load the mandatory information from file")" @bind-FileContent="@this.inputMandatoryInformation" EnableDragDrop="true"/>
<MudTextField T="string" @bind-Text="@this.inputMandatoryInformation" Label="@T("(Optional) Provide mandatory information")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.JOB_DETAILS" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("Mandatory information that your company requires for all job postings. This can include the company description, etc.")" />
<MudTextField T="string" @bind-Text="@this.inputMandatoryInformation" Label="@T("(Optional) Provide mandatory information")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.JOB_DETAILS" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@TA("Mandatory information that your company requires for all job postings. This can include the company description, etc.")" />
<ReadFileContent Text="@T("Load the job description from file")" @bind-FileContent="@this.inputJobDescription" EnableDragDrop="true"/>
<MudTextField T="string" @bind-Text="@this.inputJobDescription" Label="@T("Job description")" Validation="@this.ValidateJobDescription" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.JOB_DETAILS" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("Describe what the person is supposed to do in the company. This might be just short bullet points.")" />
<MudTextField T="string" @bind-Text="@this.inputJobDescription" Label="@T("Job description")" Validation="@this.ValidateJobDescription" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.JOB_DETAILS" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@TA("Describe what the person is supposed to do in the company. This might be just short bullet points.")" />
<ReadFileContent Text="@T("Load the qualifications from file")" @bind-FileContent="@this.inputQualifications" EnableDragDrop="true"/>
<MudTextField T="string" @bind-Text="@this.inputQualifications" Label="@T("(Optional) Provide necessary job qualifications")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.JOB_DETAILS" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("Describe what the person should bring to the table. This might be just short bullet points.")" />
<MudTextField T="string" @bind-Text="@this.inputQualifications" Label="@T("(Optional) Provide necessary job qualifications")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.JOB_DETAILS" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@TA("Describe what the person should bring to the table. This might be just short bullet points.")" />
<ReadFileContent Text="@T("Load the responsibilities from file")" @bind-FileContent="@this.inputResponsibilities" EnableDragDrop="true"/>
<MudTextField T="string" @bind-Text="@this.inputResponsibilities" Label="@T("(Optional) Provide job responsibilities")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.JOB_DETAILS" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("Describe the responsibilities the person should take on in the company.")" />
<MudTextField T="string" @bind-Text="@this.inputWorkLocation" Label="@T("(Optional) Provide the work location")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.LOCATION" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<MudTextField T="string" @bind-Text="@this.inputEntryDate" Label="@T("(Optional) Provide the entry date")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.DATE" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<MudTextField T="string" @bind-Text="@this.inputValidUntil" Label="@T("(Optional) Provide the date until the job posting is valid")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.DATE" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<MudTextField T="string" @bind-Text="@this.inputResponsibilities" Label="@TA("(Optional) Provide job responsibilities")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.JOB_DETAILS" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@TA("Describe the responsibilities the person should take on in the company.")" />
<MudTextField T="string" @bind-Text="@this.inputWorkLocation" Label="@TA("(Optional) Provide the work location")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.LOCATION" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<MudTextField T="string" @bind-Text="@this.inputEntryDate" Label="@TA("(Optional) Provide the entry date")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.DATE" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<MudTextField T="string" @bind-Text="@this.inputValidUntil" Label="@TA("(Optional) Provide the date until the job posting is valid")" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.DATE" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelectingOptional)" @bind-Value="@this.selectedTargetLanguage" Icon="@AppIcons.LANGUAGE" Label="@T("Target language")" AllowOther="@true" OtherValue="CommonLanguages.OTHER" @bind-OtherInput="@this.customTargetLanguage" ValidateOther="@this.ValidateCustomLanguage" LabelOther="@T("Custom target language")" />
<ProviderSelection @bind-ProviderSettings="@this.ProviderSettings" ValidateProvider="@this.ValidatingProvider"/>
@@ -10,7 +10,7 @@ public partial class AssistantJobPostings : AssistantBaseCore<SettingsDialogJobP
protected override string Title => T("Job Posting");
protected override string Description => T("Provide some key points about the job you want to post. The AI will then formulate a suggestion that you can finalize.");
protected override string Description => TA("Provide some key points about the job you want to post. The AI will then formulate a suggestion that you can finalize.");
// The prompt of this assistant forbids questions, so the chat gets a prompt of its own, which keeps the role and the language:
protected override ChatSystemPromptChoice ChatSystemPrompt => ChatSystemPromptChoice.Custom(this.CreateChatSystemPrompt);
@@ -203,7 +203,7 @@ public partial class AssistantJobPostings : AssistantBaseCore<SettingsDialogJobP
private string? ValidateCustomLanguage(string language)
{
if(this.selectedTargetLanguage == CommonLanguages.OTHER && string.IsNullOrWhiteSpace(language))
return T("Please provide a custom target language.");
return TA("Please provide a custom target language.");
return null;
}
@@ -211,7 +211,7 @@ public partial class AssistantJobPostings : AssistantBaseCore<SettingsDialogJobP
private string? ValidateJobDescription(string jobDescription)
{
if(string.IsNullOrWhiteSpace(jobDescription))
return T("Please provide a job description.");
return TA("Please provide a job description.");
return null;
}
@@ -219,7 +219,7 @@ public partial class AssistantJobPostings : AssistantBaseCore<SettingsDialogJobP
private string? ValidateCountryLegalFramework(string countryLegalFramework)
{
if(string.IsNullOrWhiteSpace(countryLegalFramework))
return T("Please provide the country where the job is posted (legal framework).");
return TA("Please provide the country where the job is posted (legal framework).");
return null;
}
@@ -10,6 +10,6 @@
<ReadFileContent Text="@T("Load the legal document from file")" @bind-FileContent="@this.inputLegalDocument" EnableDragDrop="true"/>
<MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.inputLegalDocument" Validation="@this.ValidatingLegalDocument" AdornmentIcon="@AppIcons.INPUT_TEXT" Adornment="Adornment.Start" Label="@T("Legal document")" Variant="Variant.Outlined" Lines="12" Sizing="InputSizing.Auto" MaxLines="24" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<ReadFileContent Text="@T("Load your questions from file")" @bind-FileContent="@this.inputQuestions" EnableDragDrop="true"/>
<MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.inputQuestions" Validation="@this.ValidatingQuestions" AdornmentIcon="@AppIcons.QUESTIONS" Adornment="Adornment.Start" Label="@T("Your questions")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<ReadFileContent Text="@TA("Load your questions from file")" @bind-FileContent="@this.inputQuestions" EnableDragDrop="true"/>
<MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.inputQuestions" Validation="@this.ValidatingQuestions" AdornmentIcon="@AppIcons.QUESTIONS" Adornment="Adornment.Start" Label="@TA("Your questions")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<ProviderSelection @bind-ProviderSettings="@this.ProviderSettings" ValidateProvider="@this.ValidatingProvider"/>
@@ -10,7 +10,7 @@ public partial class AssistantLegalCheck : AssistantBaseCore<SettingsDialogLegal
protected override string Title => T("Legal Check");
protected override string Description => T("Provide a legal document and ask a question about it. This assistant does not replace legal advice. Consult a lawyer to get professional advice. Remember that LLMs can invent answers and facts. Please do not rely on this answers.");
protected override string Description => TA("Provide a legal document and ask a question about it. This assistant does not replace legal advice. Consult a lawyer to get professional advice. Remember that LLMs can invent answers and facts. Please do not rely on this answers.");
// This prompt answers questions about the legal document, which is what the chat continues:
protected override ChatSystemPromptChoice ChatSystemPrompt => ChatSystemPromptChoice.ASSISTANT;
@@ -26,7 +26,7 @@ public partial class AssistantLegalCheck : AssistantBaseCore<SettingsDialogLegal
protected override IReadOnlyList<IButtonData> FooterButtons => [];
protected override string SubmitText => T("Ask your questions");
protected override string SubmitText => TA("Ask your questions");
protected override Func<Task> SubmitAction => this.AskQuestions;
@@ -104,7 +104,7 @@ public partial class AssistantLegalCheck : AssistantBaseCore<SettingsDialogLegal
private string? ValidatingLegalDocument(string text)
{
if(string.IsNullOrWhiteSpace(text))
return T("Please provide a legal document as input. You might copy the desired text from a document or a website.");
return TA("Please provide a legal document as input. You might copy the desired text from a document or a website.");
return null;
}
@@ -112,7 +112,7 @@ public partial class AssistantLegalCheck : AssistantBaseCore<SettingsDialogLegal
private string? ValidatingQuestions(string text)
{
if(string.IsNullOrWhiteSpace(text))
return T("Please provide your questions as input.");
return TA("Please provide your questions as input.");
return null;
}
@@ -5,7 +5,7 @@
<MudTextField T="string" @bind-Text="@this.inputText" Validation="@this.ValidatingText" AdornmentIcon="@AppIcons.INPUT_TEXT" Adornment="Adornment.Start" Label="@T("Text or email")" Variant="Variant.Outlined" Lines="12" Sizing="InputSizing.Auto" MaxLines="24" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudText Typo="Typo.h6" Class="mb-1 mt-1">@T("Attach documents")</MudText>
<MudJustifiedText Typo="Typo.body1" Class="mb-2">
@T("You can enter text, attach one or more documents, or use both. At least one input is required.")
@TA("You can enter text, attach one or more documents, or use both. At least one input is required.")
</MudJustifiedText>
<div class="mb-3">
<AttachDocuments Name="My Tasks Documents" @bind-DocumentPaths="@this.loadedDocumentPaths" OnChange="@this.OnDocumentsChanged" CatchAllDocuments="true" UseSmallForm="false" Provider="@this.ProviderSettings"/>
@@ -12,7 +12,7 @@ public partial class AssistantMyTasks : AssistantBaseCore<SettingsDialogMyTasks>
protected override string Title => T("My Tasks");
protected override string Description => T("You received a cryptic email or document that was sent to many recipients and you are now wondering if you need to do something? Copy the text into the input field, attach one or more documents, or use both. You also need to select a personal profile. In this profile, you should describe your role in the organization. The AI will then try to give you hints on what your tasks might be.");
protected override string Description => TA("You received a cryptic email or document that was sent to many recipients and you are now wondering if you need to do something? Copy the text into the input field, attach one or more documents, or use both. You also need to select a personal profile. In this profile, you should describe your role in the organization. The AI will then try to give you hints on what your tasks might be.");
// This prompt gives advice in the chosen language, which suits the follow-up questions of the chat:
protected override ChatSystemPromptChoice ChatSystemPrompt => ChatSystemPromptChoice.ASSISTANT;
@@ -142,7 +142,7 @@ public partial class AssistantMyTasks : AssistantBaseCore<SettingsDialogMyTasks>
private string? ValidatingText(string text)
{
if(string.IsNullOrWhiteSpace(text) && !this.HasValidInputDocuments())
return T("Please provide some text or at least one valid document as input. For example, an email.");
return TA("Please provide some text or at least one valid document as input. For example, an email.");
return null;
}
@@ -158,7 +158,7 @@ public partial class AssistantMyTasks : AssistantBaseCore<SettingsDialogMyTasks>
private string? ValidateProfile(Profile profile)
{
if(profile == Profile.NO_PROFILE)
return T("Please select one of your profiles.");
return TA("Please select one of your profiles.");
return null;
}
@@ -166,7 +166,7 @@ public partial class AssistantMyTasks : AssistantBaseCore<SettingsDialogMyTasks>
private string? ValidateCustomLanguage(string language)
{
if(this.selectedTargetLanguage == CommonLanguages.OTHER && string.IsNullOrWhiteSpace(language))
return T("Please provide a custom language.");
return TA("Please provide a custom language.");
return null;
}
@@ -34,32 +34,32 @@
@bind-Text="@this.importantAspects"
Class="mb-3"
Label="@T("(Optional) Important Aspects for the prompt")"
HelperText="@T("(Optional) Specify aspects the optimizer should emphasize in the resulting prompt, such as output structure, or constraints.")"
HelperText="@TA("(Optional) Specify aspects the optimizer should emphasize in the resulting prompt, such as output structure, or constraints.")"
ShrinkLabel="true"
Variant="Variant.Outlined"
AdornmentIcon="@AppIcons.IMPORTANT_ASPECTS"
Adornment="Adornment.Start"/>
<MudStack Row="true" AlignItems="AlignItems.Center" Class="mb-2">
<MudText Typo="Typo.h6">@T("Recommendations for your prompt")</MudText>
<MudText Typo="Typo.h6">@TA("Recommendations for your prompt")</MudText>
</MudStack>
@if (this.ShowUpdatedPromptGuidelinesIndicator)
{
<MudAlert Severity="Severity.Info" Dense="true" Variant="Variant.Outlined" Class="mb-3">
<MudStack Row="true" AlignItems="AlignItems.Center" Wrap="Wrap.Wrap">
<MudText Typo="Typo.body2">@T("Prompt recommendations were updated based on your latest optimization.")</MudText>
<MudText Typo="Typo.body2">@TA("Prompt recommendations were updated based on your latest optimization.")</MudText>
</MudStack>
</MudAlert>
}
@if (!this.useCustomPromptGuide)
{
<MudJustifiedText Class="mb-3">@T("Use these recommendations, that are based on the default prompt guide, to improve your prompts. The suggestions are updated based on your latest prompt optimization.")</MudJustifiedText>
<MudJustifiedText Class="mb-3">@TA("Use these recommendations, which are based on the default prompt guide, to improve your prompts. The suggestions are updated based on your latest prompt optimization.")</MudJustifiedText>
<MudGrid Class="mb-3">
<MudItem xs="12" sm="6" md="4">
<MudTextField T="string" Value="@this.recClarityDirectness" Label="@T("Be clear and direct")" ReadOnly="true" Variant="Variant.Outlined" Lines="2" Sizing="InputSizing.Auto" />
<MudTextField T="string" Value="@this.recClarityDirectness" Label="@TA("Be clear and direct")" ReadOnly="true" Variant="Variant.Outlined" Lines="2" Sizing="InputSizing.Auto" />
</MudItem>
<MudItem xs="12" sm="6" md="4">
<MudTextField T="string" Value="@this.recExamplesContext" Label="@T("Add examples and context")" ReadOnly="true" Variant="Variant.Outlined" Lines="2" Sizing="InputSizing.Auto" />
@@ -71,21 +71,21 @@
<MudTextField T="string" Value="@this.recStructureMarkers" Label="@T("Structure with markers")" ReadOnly="true" Variant="Variant.Outlined" Lines="2" Sizing="InputSizing.Auto" />
</MudItem>
<MudItem xs="12" sm="6" md="4">
<MudTextField T="string" Value="@this.recRoleDefinition" Label="@T("Give the model a role")" ReadOnly="true" Variant="Variant.Outlined" Lines="2" Sizing="InputSizing.Auto" />
<MudTextField T="string" Value="@this.recRoleDefinition" Label="@TA("Give the model a role")" ReadOnly="true" Variant="Variant.Outlined" Lines="2" Sizing="InputSizing.Auto" />
</MudItem>
<MudItem xs="12" sm="6" md="4">
<MudTextField T="string" Value="@this.recLanguageChoice" Label="@T("Choose prompt language deliberately")" ReadOnly="true" Variant="Variant.Outlined" Lines="2" Sizing="InputSizing.Auto" />
<MudTextField T="string" Value="@this.recLanguageChoice" Label="@TA("Choose prompt language deliberately")" ReadOnly="true" Variant="Variant.Outlined" Lines="2" Sizing="InputSizing.Auto" />
</MudItem>
</MudGrid>
}
@if (this.useCustomPromptGuide && this.IsCustomPromptGuideLocked)
{
<MudJustifiedText Class="mb-3">@T("Use the prompt recommendations from the prompt guide of your organization.")</MudJustifiedText>
<MudJustifiedText Class="mb-3">@TA("Use the prompt recommendations from the prompt guide of your organization.")</MudJustifiedText>
}
else if (this.useCustomPromptGuide)
{
<MudJustifiedText Class="mb-3">@T("Use the prompt recommendations from the custom prompt guide.")</MudJustifiedText>
<MudJustifiedText Class="mb-3">@TA("Use the prompt recommendations from the custom prompt guide.")</MudJustifiedText>
}
<MudStack Row="true" AlignItems="AlignItems.Center" Wrap="Wrap.Wrap" StretchItems="StretchItems.None" Class="mb-3">
@@ -30,7 +30,7 @@ public partial class AssistantPromptOptimizer : AssistantBaseCore<SettingsDialog
protected override string Title => T("Prompt Optimizer");
protected override string Description => T("Use an LLM to optimize your prompt by following either the default or your individual prompt guidelines and get targeted recommendations for future versions of the prompt.");
protected override string Description => TA("Use an LLM to optimize your prompt by following either the default or your individual prompt guidelines and get targeted recommendations for future versions of the prompt.");
// Sending to a new chat puts the optimized prompt into its input field, so no chat continues this conversation:
protected override ChatSystemPromptChoice ChatSystemPrompt => ChatSystemPromptChoice.AI_STUDIO_DEFAULT;
@@ -104,7 +104,7 @@ public partial class AssistantPromptOptimizer : AssistantBaseCore<SettingsDialog
new ButtonData
{
Text = T("Improve further"),
Tooltip = T("Moves the optimized prompt into the prompt field so you can optimize it again."),
Tooltip = TA("Moves the optimized prompt into the prompt field so you can optimize it again."),
Icon = AppIcons.USE_AS_INPUT,
Color = Color.Default,
AsyncAction = this.UseOptimizedPromptAsInput,
@@ -332,7 +332,7 @@ public partial class AssistantPromptOptimizer : AssistantBaseCore<SettingsDialog
private string? ValidateInputPrompt(string text)
{
if (string.IsNullOrWhiteSpace(text))
return T("Please provide a prompt or prompt description.");
return TA("Please provide a prompt or prompt description.");
return null;
}
@@ -340,7 +340,7 @@ public partial class AssistantPromptOptimizer : AssistantBaseCore<SettingsDialog
private string? ValidateCustomLanguage(string language)
{
if (this.selectedTargetLanguage == CommonLanguages.OTHER && string.IsNullOrWhiteSpace(language))
return T("Please provide a custom language.");
return TA("Please provide a custom language.");
return null;
}
@@ -374,11 +374,11 @@ public partial class AssistantPromptOptimizer : AssistantBaseCore<SettingsDialog
if (string.IsNullOrWhiteSpace(promptingGuideline))
{
if (this.useCustomPromptGuide && this.IsCustomPromptGuideLocked)
this.AddInputIssue(T("The prompt guide of your organization could not be loaded."));
this.AddInputIssue(TA("The prompt guide of your organization could not be loaded."));
else if (this.useCustomPromptGuide)
this.AddInputIssue(T("Please attach and load a valid custom prompt guide file."));
this.AddInputIssue(TA("Please attach and load a valid custom prompt guide file."));
else
this.AddInputIssue(T("The prompting guideline file could not be loaded. Please verify 'prompting_guideline.md' in Assistants/PromptOptimizer."));
this.AddInputIssue(TA("The prompting guideline file could not be loaded. Please verify 'prompting_guideline.md' in Assistants/PromptOptimizer."));
return;
}
@@ -497,12 +497,12 @@ public partial class AssistantPromptOptimizer : AssistantBaseCore<SettingsDialog
private void ApplyFallbackRecommendations()
{
this.recClarityDirectness = T("Add clearer goals and explicit quality expectations.");
this.recExamplesContext = T("Add short examples and background context for your specific use case.");
this.recSequentialSteps = T("Break the task into numbered steps if order matters.");
this.recStructureMarkers = T("Use headings or markers to separate context, task, and constraints.");
this.recRoleDefinition = T("Define a role for the model to focus output style and expertise.");
this.recLanguageChoice = T("Use English for complex prompts and explicitly request response language if needed.");
this.recClarityDirectness = TA("Add clearer goals and explicit quality expectations.");
this.recExamplesContext = TA("Add short examples and background context for your specific use case.");
this.recSequentialSteps = TA("Break the task into numbered steps if order matters.");
this.recStructureMarkers = TA("Use headings or markers to separate context, task, and constraints.");
this.recRoleDefinition = TA("Define a role for the model to focus output style and expertise.");
this.recLanguageChoice = TA("Use English for complex prompts and explicitly request response language if needed.");
}
private string EmptyFallback(string text)
@@ -542,12 +542,12 @@ public partial class AssistantPromptOptimizer : AssistantBaseCore<SettingsDialog
private void ResetGuidelineSummaryToDefault()
{
this.recClarityDirectness = T("Use clear, explicit instructions and directly state quality expectations.");
this.recExamplesContext = T("Include short examples and context that explain the purpose behind your requirements.");
this.recSequentialSteps = T("Prefer numbered steps when task order matters.");
this.recStructureMarkers = T("Separate context, task, constraints, and output format with headings or markers.");
this.recRoleDefinition = T("Assign a role to shape tone, expertise, and focus.");
this.recLanguageChoice = T("For complex tasks, write prompts in English.");
this.recClarityDirectness = TA("Use clear, explicit instructions and directly state quality expectations.");
this.recExamplesContext = TA("Include short examples and context that explain the purpose behind your requirements.");
this.recSequentialSteps = TA("Prefer numbered steps when task order matters.");
this.recStructureMarkers = TA("Separate context, task, constraints, and output format with headings or markers.");
this.recRoleDefinition = TA("Assign a role to shape tone, expertise, and focus.");
this.recLanguageChoice = TA("For complex tasks, write prompts in English.");
}
private void AddVisibleOptimizedPromptBlock()
@@ -2,7 +2,7 @@
@inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogRewrite>
<ReadFileContent Text="@T("Load text from file")" @bind-FileContent="@this.inputText" EnableDragDrop="true" CatchAllDocuments="true"/>
<MudTextField T="string" @bind-Text="@this.inputText" Validation="@this.ValidateText" AdornmentIcon="@AppIcons.INPUT_TEXT" Adornment="Adornment.Start" Label="@T("Your input to improve")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudTextField T="string" @bind-Text="@this.inputText" Validation="@this.ValidateText" AdornmentIcon="@AppIcons.INPUT_TEXT" Adornment="Adornment.Start" Label="@TA("Your input to improve")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelectingOptional)" @bind-Value="@this.selectedTargetLanguage" Icon="@AppIcons.LANGUAGE" Label="@T("Language")" AllowOther="@true" OtherValue="CommonLanguages.OTHER" @bind-OtherInput="@this.customTargetLanguage" ValidateOther="@this.ValidateCustomLanguage" LabelOther="@T("Custom language")" />
<EnumSelection T="WritingStyles" NameFunc="@(style => style.Name)" @bind-Value="@this.selectedWritingStyle" Icon="@AppIcons.WRITING_STYLE" Label="@T("Writing style")" AllowOther="@false" />
<EnumSelection T="SentenceStructure" NameFunc="@(voice => voice.Name)" @bind-Value="@this.selectedSentenceStructure" Icon="@AppIcons.SENTENCE_STRUCTURE" Label="@T("Sentence structure")" />
@@ -10,7 +10,7 @@ public partial class AssistantRewriteImprove : AssistantBaseCore<SettingsDialogR
protected override string Title => T("Rewrite & Improve Text");
protected override string Description => T("Rewrite and improve your text. Please note, that the capabilities of the different LLM providers will vary.");
protected override string Description => TA("Rewrite and improve your text. Please note, that the capabilities of the different LLM providers will vary.");
// The prompt of this assistant forbids explanations, so the chat gets a prompt of its own, which keeps the style of the text:
protected override ChatSystemPromptChoice ChatSystemPrompt => ChatSystemPromptChoice.Custom(this.CreateChatSystemPrompt);
@@ -58,7 +58,7 @@ public partial class AssistantRewriteImprove : AssistantBaseCore<SettingsDialogR
},
];
protected override string SubmitText => T("Improve your text");
protected override string SubmitText => TA("Improve your text");
protected override Func<Task> SubmitAction => this.RewriteText;
@@ -137,7 +137,7 @@ public partial class AssistantRewriteImprove : AssistantBaseCore<SettingsDialogR
private string? ValidateText(string text)
{
if(string.IsNullOrWhiteSpace(text))
return T("Please provide a text as input. You might copy the desired text from a document or a website.");
return TA("Please provide a text as input. You might copy the desired text from a document or a website.");
return null;
}
@@ -145,7 +145,7 @@ public partial class AssistantRewriteImprove : AssistantBaseCore<SettingsDialogR
private string? ValidateCustomLanguage(string language)
{
if(this.selectedTargetLanguage == CommonLanguages.OTHER && string.IsNullOrWhiteSpace(language))
return T("Please provide a custom language.");
return TA("Please provide a custom language.");
return null;
}
@@ -3,7 +3,7 @@
<MudAlert Severity="Severity.Info" Variant="Variant.Outlined" Dense="true" Class="mb-3">
<MudText Align="Align.Justify">
@T("The quality of this SWOT analysis depends on the material you provide. The AI uses only your input, the attached documents, and the results of the tools you selected. Treat the result as a first draft and check it before you base decisions on it.")
@TA("The quality of this SWOT analysis depends on the material you provide. The AI uses only your input, the attached documents, and the results of the tools you selected. Treat the result as a first draft and check it before you base decisions on it.")
</MudText>
</MudAlert>
@@ -22,14 +22,14 @@
</MudText>
<MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.analysisGoal" Validation="@this.ValidatingAnalysisGoal" AdornmentIcon="@AppIcons.ANALYSIS_GOAL" Adornment="Adornment.Start" Label="@T("Analysis goal")" Variant="Variant.Outlined" Lines="4" Sizing="InputSizing.Auto" Class="mb-3"/>
<ReadFileContent @bind-FileContent="@this.analysisGoal" MediaImportTargetId="swot-analysis-goal" EnableDragDrop="true"/>
<MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.importantAspects" AdornmentIcon="@AppIcons.IMPORTANT_ASPECTS" Adornment="Adornment.Start" Label="@T("(Optional) Analysis focus")" HelperText="@T("Specify topics the SWOT analysis should pay particular attention to.")" Variant="Variant.Outlined" Lines="4" Sizing="InputSizing.Auto" Class="mb-3"/>
<MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.importantAspects" AdornmentIcon="@AppIcons.IMPORTANT_ASPECTS" Adornment="Adornment.Start" Label="@T("(Optional) Analysis focus")" HelperText="@TA("Specify topics the SWOT analysis should pay particular attention to.")" Variant="Variant.Outlined" Lines="4" Sizing="InputSizing.Auto" Class="mb-3"/>
<ReadFileContent @bind-FileContent="@this.importantAspects" MediaImportTargetId="swot-analysis-focus" EnableDragDrop="true"/>
<MudText Typo="Typo.h5" Class="mb-3 mt-6">
@T("Contextual Knowledge")
</MudText>
<MudText Typo="Typo.body2" Class="mb-4">
@T("To enhance the validity of the SWOT analysis, please upload supplementary documents that provide empirical or contextual data for a comprehensive internal and external assessment.")
@TA("To enhance the validity of the SWOT analysis, please upload supplementary documents that provide empirical or contextual data for a comprehensive internal and external assessment.")
</MudText>
<AttachDocuments Name="SWOT Analysis Context Material" @bind-DocumentPaths="@this.contextMaterials" UseSmallForm="false" Provider="@this.ProviderSettings"/>
@@ -170,7 +170,7 @@ public partial class AssistantSWOTAnalysis : AssistantBaseCore<SettingsDialogSWO
private string? ValidatingText(string text)
{
if (string.IsNullOrWhiteSpace(text))
return T("Please provide source material for the SWOT analysis. You can enter text, load a document, or import content from a website.");
return TA("Please provide source material for the SWOT analysis. You can enter text, load a document, or import content from a website.");
return null;
}
@@ -178,7 +178,7 @@ public partial class AssistantSWOTAnalysis : AssistantBaseCore<SettingsDialogSWO
private string? ValidatingAnalysisGoal(string text)
{
if (string.IsNullOrWhiteSpace(text))
return T("Please describe the goal the SWOT analysis should support.");
return TA("Please describe the goal the SWOT analysis should support.");
return null;
}
@@ -186,7 +186,7 @@ public partial class AssistantSWOTAnalysis : AssistantBaseCore<SettingsDialogSWO
private string? ValidateCustomLanguage(string language)
{
if (this.selectedTargetLanguage == CommonLanguages.OTHER && string.IsNullOrWhiteSpace(language))
return T("Please provide a custom language.");
return TA("Please provide a custom language.");
return null;
}
@@ -6,7 +6,7 @@
<MudText Typo="Typo.h5" Class="mb-1 mt-3"> @T("Content to derive slide from")</MudText>
<MudJustifiedText Typo="Typo.body1" Class="mb-2">
@T("You can enter text, use one or more documents or images, or use both. At least one of these options is required.")
@TA("You can enter text, use one or more documents or images, or use both. At least one of these options is required.")
</MudJustifiedText>
<MudTextField T="string" @bind-Text="@this.inputContent" Validation="@this.ValidatingContext" Adornment="Adornment.Start" Lines="6" MaxLines="12" Sizing="InputSizing.Fixed" Label="@T("Text content")" Variant="Variant.Outlined" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
@@ -22,7 +22,7 @@
<MudItem xs="12" lg="6" Class="d-flex flex-column">
<MudText Typo="Typo.h6" Class="mb-1">@T("Pictures for the slides")</MudText>
<MudJustifiedText Typo="Typo.body1" Class="mb-2 flex-grow-1">
@T("Attach the pictures which the presentation must show, e.g., photos, diagrams, or screenshots. Each of them goes on exactly one slide with room for a picture. Only PNG and JPEG pictures are possible. An LLM which can read images sees them; any other LLM knows only their file names, so clear names help.")
@TA("Attach the pictures which the presentation must show, e.g., photos, diagrams, or screenshots. Each of them goes on exactly one slide with room for a picture. Only PNG and JPEG pictures are possible. An LLM which can read images sees them; any other LLM knows only their file names, so clear names help.")
</MudJustifiedText>
<AttachDocuments Name="Pictures for the slides" @bind-DocumentPaths="@this.slidePictures" OnChange="@this.OnSlidePicturesChanged" CatchAllDocuments="false" UseSmallForm="false" AllowedFileTypes="@([FileTypes.SLIDE_PICTURE])" Provider="@this.ProviderSettings"/>
</MudItem>
@@ -35,7 +35,7 @@
<SelectDirectory Directory="@this.pictureLibraryPath" DirectoryChanged="@this.OnPictureLibraryChanged" Label="@T("(Optional) Picture library")" DirectoryDialogTitle="@T("Select a picture library")" Validation="@this.ValidatePictureLibrary" Disabled="@this.IsPictureLibraryLocked" EnableDragDrop="true"/>
@if (this.IsLockedPictureLibraryUnavailable)
{
<MudAlert Severity="Severity.Warning" Dense="true" Class="mb-3">@T("The picture library of your organization is not available right now, e.g., because its network drive cannot be reached. Until it is, the assistant plans the slides without it.")</MudAlert>
<MudAlert Severity="Severity.Warning" Dense="true" Class="mb-3">@TA("The picture library of your organization is not available right now, e.g., because its network drive cannot be reached. Until it is, the assistant plans the slides without it.")</MudAlert>
}
@if (this.PictureLibraryHint is { Length: > 0 } pictureLibraryHint)
{
@@ -52,19 +52,19 @@
<MudText Typo="Typo.h6" Class="mb-1"> @T("Title")</MudText>
<MudJustifiedText Typo="Typo.body1" Class="mb-2">
@T("Please enter a title for the presentation. This will help the LLM to select more relevant content.")
@TA("Please enter a title for the presentation. This will help the LLM to select more relevant content.")
</MudJustifiedText>
<MudTextField T="string" @bind-Text="@this.inputTitle" Validation="@this.ValidatingTitle" Adornment="Adornment.Start" Label="@T("Presentation title")" Variant="Variant.Outlined" Class="mb-1" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudText Typo="Typo.h6" Class="mb-1 mt-3"> @T("Important Aspects")</MudText>
<MudJustifiedText Typo="Typo.body1" Class="mb-2">
@T("You might want to specify important aspects that the LLM should consider when creating the slides. For example, the use of emojis or specific topics that should be highlighted.")
@TA("You might want to specify important aspects that the LLM should consider when creating the slides. For example, the use of emojis or specific topics that should be highlighted.")
</MudJustifiedText>
<MudTextField T="string" Sizing="InputSizing.Auto" Lines="3" @bind-Text="@this.importantAspects" class="mb-1" Label="@T("(Optional) Important Aspects")" ShrinkLabel="true" Variant="Variant.Outlined" AdornmentIcon="@AppIcons.IMPORTANT_ASPECTS" Adornment="Adornment.Start" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudText Typo="Typo.h6" Class="mb-1 mt-3"> @T("Extent of the planned presentation")</MudText>
<MudJustifiedText Typo="Typo.body1" Class="mb-2">
@T("Please specify the extent of the planned presentation. This can be the number of slides, the maximum number of bullet points per slide, or the time specification for the presentation. This will help the LLM to create a presentation that fits your needs. Leave the default values if you don't have specific requirements regarding the extent of the presentation. You might only want to specify one of these parameters, for example the time specification, and leave the others at their default values.")
@TA("Please specify the extent of the planned presentation. This can be the number of slides, the maximum number of bullet points per slide, or the time specification for the presentation. This will help the LLM to create a presentation that fits your needs. Leave the default values if you don't have specific requirements regarding the extent of the presentation. You might only want to specify one of these parameters, for example the time specification, and leave the others at their default values.")
</MudJustifiedText>
<MudGrid>
<MudItem xs="4">
@@ -105,7 +105,7 @@
<MudText Typo="Typo.h6" Class="mb-1 mt-3"> @T("Audience")</MudText>
<MudJustifiedText Typo="Typo.body1" Class="mb-2">
@T("Please specify the audience for the planned presentation. This will help the LLM to create a presentation that fits your needs. You can specify the audience profile, the age group, organizational level, and the expertise. You don't have to specify all of these parameters, for example you might only want to specify the audience profile and leave the other parameters at their default values.")
@TA("Please specify the audience for the planned presentation. This will help the LLM to create a presentation that fits your needs. You can specify the audience profile, the age group, organizational level, and the expertise. You don't have to specify all of these parameters, for example you might only want to specify the audience profile and leave the other parameters at their default values.")
</MudJustifiedText>
<EnumSelection T="AudienceProfile" NameFunc="@(profile => profile.Name)" @bind-Value="@this.selectedAudienceProfile" Icon="@AppIcons.AUDIENCE" Label="@T("Audience profile")" />
<EnumSelection T="AudienceAgeGroup" NameFunc="@(ageGroup => ageGroup.Name)" @bind-Value="@this.selectedAudienceAgeGroup" Icon="@AppIcons.AUDIENCE_AGE_GROUP" Label="@T("Audience age group")" />
@@ -114,7 +114,7 @@
<MudText Typo="Typo.h5" Class="mb-1 mt-6"> @T("PowerPoint template")</MudText>
<MudJustifiedText Typo="Typo.body1" Class="mb-2">
@T("Choose a PowerPoint presentation or template (.pptx, .potx) whose layouts the slides should use. The LLM then plans every slide for one of these layouts, and you can create a PowerPoint file (.pptx) in the design of your template, which other programs such as LibreOffice Impress open as well. OpenDocument presentations (.odp, .otp) cannot serve as a template yet. Without a template, you get an outline, which you can copy or export.")
@TA("Choose a PowerPoint presentation or template (.pptx, .potx) whose layouts the slides should use. The LLM then plans every slide for one of these layouts, and you can create a PowerPoint file (.pptx) in the design of your template, which other programs such as LibreOffice Impress open as well. OpenDocument presentations (.odp, .otp) cannot serve as a template yet. Without a template, you get an outline, which you can copy or export.")
</MudJustifiedText>
<MudJustifiedText Typo="Typo.body1" Class="mb-2">
@SlideAssistantTexts.WhatTheLLMKnowsOfLayouts
@@ -122,7 +122,7 @@
<SelectFile File="@this.templatePath" FileChanged="@this.OnTemplateChanged" Label="@T("PowerPoint template")" FileDialogTitle="@T("Select a PowerPoint template")" Filter="@([FileTypes.POWER_POINT_TEMPLATE])" Validation="@this.ValidateTemplate" Disabled="@this.IsTemplateLocked" EnableDragDrop="true"/>
@if (this.IsLockedTemplateUnavailable)
{
<MudAlert Severity="Severity.Warning" Dense="true" Class="mb-3">@T("The PowerPoint template of your organization is not available right now, e.g., because its network drive cannot be reached. Until it is, the assistant plans an outline only.")</MudAlert>
<MudAlert Severity="Severity.Warning" Dense="true" Class="mb-3">@TA("The PowerPoint template of your organization is not available right now, e.g., because its network drive cannot be reached. Until it is, the assistant plans an outline only.")</MudAlert>
}
@if (!string.IsNullOrWhiteSpace(this.templatePath) && !this.IsTemplateLocked)
{
@@ -137,7 +137,7 @@
<CompactExpansionPanel HeaderText="@T("Advanced Options")" HeaderIcon="@AppIcons.ADVANCED_SETTINGS" Class="mb-3 rounded" @bind-Expanded="@this.advancedOptionsExpanded">
@if (loadedTemplate.VariantLabels.Count > 0)
{
<MudSelect T="string" @bind-Value="@this.variantLabel" Label="@T("Color variant")" HelperText="@T("Your template offers its layouts in several colors. Choose one for the presentation.")" Variant="Variant.Outlined" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.COLOR" Class="mb-3">
<MudSelect T="string" @bind-Value="@this.variantLabel" Label="@T("Color variant")" HelperText="@TA("Your template offers its layouts in several colors. Choose one for the presentation.")" Variant="Variant.Outlined" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.COLOR" Class="mb-3">
@foreach (var label in loadedTemplate.VariantLabels)
{
<MudSelectItem T="string" Value="@label">@label</MudSelectItem>
@@ -145,7 +145,7 @@
</MudSelect>
}
<MudTextField T="string" @bind-Text="@this.footerText" Label="@T("(Optional) Footer")" HelperText="@T("Shown on every slide whose layout has a footer, e.g., your name, organization, and date.")" Variant="Variant.Outlined" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.SLIDE_FOOTER" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudTextField T="string" @bind-Text="@this.footerText" Label="@T("(Optional) Footer")" HelperText="@TA("Shown on every slide whose layout has a footer, e.g., your name, organization, and date.")" Variant="Variant.Outlined" Adornment="Adornment.Start" AdornmentIcon="@AppIcons.SLIDE_FOOTER" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudSwitch T="bool" @bind-Value="@this.keepEmptyPicturePlaceholders" Color="Color.Primary" Class="mx-1">
@T("Keep empty picture placeholders")
@@ -176,15 +176,15 @@ public partial class SlideAssistant
get
{
if (this.slideDeck is null)
return T("Please plan the slides first.");
return TA("Please plan the slides first.");
if (this.template is null)
return T("Please choose a PowerPoint template to create a file from the slides.");
return TA("Please choose a PowerPoint template to create a file from the slides.");
if (!this.PlannedForCurrentTemplate)
return T("The slides were planned for another template. Please plan them again.");
return TA("The slides were planned for another template. Please plan them again.");
return T("Creates a PowerPoint file in the design of your template.");
return TA("Creates a PowerPoint file in the design of your template.");
}
}
@@ -288,7 +288,7 @@ public partial class SlideAssistant
private string? ValidateTemplateSlideUse(TemplateSlide slide, TemplateSlideUse use)
{
if (use is TemplateSlideUse.EDIT && !slide.IsEditable)
return T("The LLM cannot edit this slide, because its layout has no placeholders for content. Please keep it unchanged or leave it out.");
return TA("The LLM cannot edit this slide, because its layout has no placeholders for content. Please keep it unchanged or leave it out.");
return null;
}
@@ -324,7 +324,7 @@ public partial class SlideAssistant
return T("The template file does not exist.");
if (this.template is null)
return T("The template cannot be read. Please choose a PowerPoint presentation or template (.pptx, .potx).");
return TA("The template cannot be read. Please choose a PowerPoint presentation or template (.pptx, .potx).");
if (this.template.Families.Count == 0)
return T("The template has no layouts with room for content.");
@@ -574,7 +574,7 @@ public partial class SlideAssistant
if (!result.IsWritten)
{
this.Logger.LogWarning("The PowerPoint template '{TemplatePath}' changed since the slides were planned, and they no longer fit it.", this.slideDeckTemplatePath);
await this.MessageBus.SendError(new(AppIcons.SLIDES, T("The template has changed since the slides were planned. Please create the slides again.")));
await this.MessageBus.SendError(new(AppIcons.SLIDES, TA("The template has changed since the slides were planned. Please create the slides again.")));
return;
}
@@ -591,7 +591,7 @@ public partial class SlideAssistant
catch (Exception e)
{
this.Logger.LogError(e, "Creating the PowerPoint file '{FilePath}' failed.", targetPath);
await this.MessageBus.SendError(new(AppIcons.SLIDES, T("The PowerPoint file could not be created. Please check that the template can be read and that the target file is not open in another program.")));
await this.MessageBus.SendError(new(AppIcons.SLIDES, TA("The PowerPoint file could not be created. Please check that the template can be read and that the target file is not open in another program.")));
}
finally
{
@@ -15,7 +15,7 @@ public partial class SlideAssistant : AssistantBaseCore<SettingsDialogSlideBuild
protected override string Title => T("Slide Assistant");
protected override string Description => T("This assistant helps you create clear, structured slides from long texts or documents. Enter a presentation title and provide the content either as text or with one or more documents. Important aspects allow you to add instructions to the LLM regarding output or formatting. Set the number of slides either directly or based on your desired presentation duration. You can also limit the number of bullet points per slide. If the default value of 0 is not changed, the LLM will independently determine how many slides or bullet points to generate. The output can be flexibly generated in various languages and tailored to a specific audience. When you choose a PowerPoint template, the slides use its layouts, and you can create a PowerPoint file in its design from the result.");
protected override string Description => TA("This assistant helps you create clear, structured slides from long texts or documents. Enter a presentation title and provide the content either as text or with one or more documents. Important aspects allow you to add instructions to the LLM regarding output or formatting. Set the number of slides either directly or based on your desired presentation duration. You can also limit the number of bullet points per slide. If the default value of 0 is not changed, the LLM will independently determine how many slides or bullet points to generate. The output can be flexibly generated in various languages and tailored to a specific audience. When you choose a PowerPoint template, the slides use its layouts, and you can create a PowerPoint file in its design from the result.");
// The prompt of this assistant demands JSON for the layouts, so the chat gets a prompt of its own, which keeps the limits of the slides:
protected override ChatSystemPromptChoice ChatSystemPrompt => ChatSystemPromptChoice.Custom(this.CreateChatSystemPrompt);
@@ -192,7 +192,7 @@ public partial class SlideAssistant : AssistantBaseCore<SettingsDialogSlideBuild
ContentType = ContentType.TEXT,
Content = new ContentText
{
Text = this.T("The result of your previous Slide Assistant session."),
Text = this.TA("The result of your previous Slide Assistant session."),
FileAttachments = [..this.loadedDocumentPaths, ..this.slidePictures],
}
},
@@ -446,14 +446,14 @@ public partial class SlideAssistant : AssistantBaseCore<SettingsDialogSlideBuild
private string? ValidatingTitle(string text)
{
if(string.IsNullOrWhiteSpace(text))
return T("Please provide a title");
return TA("Please provide a title");
return null;
}
private string? ValidatingContext(string text)
{
if(string.IsNullOrWhiteSpace(text) && !this.HasValidInputDocuments())
return T("Please provide a text or at least one valid document or image.");
return TA("Please provide a text or at least one valid document or image.");
return null;
}
@@ -497,7 +497,7 @@ public partial class SlideAssistant : AssistantBaseCore<SettingsDialogSlideBuild
private string? ValidateCustomLanguage(string language)
{
if(this.selectedTargetLanguage == CommonLanguages.OTHER && string.IsNullOrWhiteSpace(language))
return T("Please provide a custom language.");
return TA("Please provide a custom language.");
return null;
}
@@ -505,7 +505,7 @@ public partial class SlideAssistant : AssistantBaseCore<SettingsDialogSlideBuild
private string? ValidateCustomOccasion(string occasion)
{
if(this.selectedOccasion == PresentationOccasion.OTHER && string.IsNullOrWhiteSpace(occasion))
return T("Please describe the occasion.");
return TA("Please describe the occasion.");
return null;
}
@@ -777,14 +777,14 @@ public partial class SlideAssistant : AssistantBaseCore<SettingsDialogSlideBuild
if (deck is null || deck.Slides.Count == 0 || deck.Slides.Any(slide => !SlideDeckSpecValidator.CanWrite(slide, catalog, chosenTemplateSlideUses)))
{
this.Logger.LogWarning("The slides the model planned cannot be used: {Issues}", string.Join(" | ", issues));
await this.MessageBus.SendError(new(AppIcons.SLIDES, T("The LLM did not describe the slides in a usable form, even after a second request. Please try again, or choose another model.")));
await this.MessageBus.SendError(new(AppIcons.SLIDES, TA("The LLM did not describe the slides in a usable form, even after a second request. Please try again, or choose another model.")));
return;
}
if (issues.Count > 0)
{
this.Logger.LogInformation("The slides the model planned still have issues after the repair round: {Issues}", string.Join(" | ", issues));
await this.MessageBus.SendWarning(new(AppIcons.SLIDES, T("Not every slide fits its layout as planned; for example, a text may run long. Please check the slides before presenting.")));
await this.MessageBus.SendWarning(new(AppIcons.SLIDES, TA("Not every slide fits its layout as planned; for example, a text may run long. Please check the slides before presenting.")));
}
this.slideDeck = deck;
@@ -7,27 +7,27 @@ namespace AIStudio.Assistants.SlideBuilder;
/// </summary>
public static class SlideAssistantTexts
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(SlideAssistantTexts).Namespace, nameof(SlideAssistantTexts));
private static string TA(string fallbackEN) => Tools.PluginSystem.I18N.I.TA(fallbackEN, typeof(SlideAssistantTexts).Namespace, nameof(SlideAssistantTexts));
/// <summary>
/// What the LLM knows about the layouts of a template, and why their names matter.
/// </summary>
public static string WhatTheLLMKnowsOfLayouts => TB("The LLM does not see what your layouts look like. It knows only their names from the slide master of your template, where their placeholders sit, and how much text fits into them. Clear names such as “Chapter” or “Content with picture” therefore help it choose well; in PowerPoint, you rename a layout in the slide master view. Logo, background, and footer come with the layout. Layouts which differ only in their color count as one, and the color applies to the whole presentation.");
public static string WhatTheLLMKnowsOfLayouts => TA("The LLM does not see what your layouts look like. It knows only their names from the slide master of your template, where their placeholders sit, and how much text fits into them. Clear names such as “Chapter” or “Content with picture” therefore help it choose well; in PowerPoint, you rename a layout in the slide master view. Logo, background, and footer come with the layout. Layouts which differ only in their color count as one, and the color applies to the whole presentation.");
/// <summary>
/// What the choice of a layout for a kind of slide does, and what it does not.
/// </summary>
public static string WhatALayoutChoiceDoes => TB("Choose which layout of your template the LLM uses for certain kinds of slides. The lists offer the layouts with room for content. Where you have no preference, the LLM decides by the names and placeholders of the layouts. A choice says which layout such a slide uses, not whether the presentation has one: whether there is, e.g., an agenda, follows from your content and your important aspects. Only for the framing slides, e.g., the table of contents or the imprint, does a choice also add such a slide; their help says so. Each chapter becomes a section in PowerPoint, which the slide sorter shows as an outline.");
public static string WhatALayoutChoiceDoes => TA("Choose which layout of your template the LLM uses for certain kinds of slides. The lists offer the layouts with room for content. Where you have no preference, the LLM decides by the names and placeholders of the layouts. A choice says which layout such a slide uses, not whether the presentation has one: whether there is, e.g., an agenda, follows from your content and your important aspects. Only for the framing slides, e.g., the table of contents or the imprint, does a choice also add such a slide; their help says so. Each chapter becomes a section in PowerPoint, which the slide sorter shows as an outline.");
/// <summary>
/// What keeping the empty picture placeholders does.
/// </summary>
public static string WhatKeepingEmptyPicturePlaceholdersDoes => TB("When a new slide has no picture for a picture placeholder of its layout, it leaves the placeholder out, as every other placeholder without content. Keep these placeholders to insert pictures of your own later: PowerPoint shows them while you edit and hides them in the slide show.");
public static string WhatKeepingEmptyPicturePlaceholdersDoes => TA("When a new slide has no picture for a picture placeholder of its layout, it leaves the placeholder out, as every other placeholder without content. Keep these placeholders to insert pictures of your own later: PowerPoint shows them while you edit and hides them in the slide show.");
/// <summary>
/// What a picture library is, which of its files count, and how the LLM uses them.
/// </summary>
public static string WhatAPictureLibraryOffers => string.Format(TB("Choose a folder with pictures and icons, e.g., the picture library of your organization. The LLM reads only their names, never the pictures themselves, and uses a picture where its name fits a slide; it does not have to use any. So clear names such as “rocket-launch.jpg” help. Only PNG and JPEG pictures count: many icons come as SVG, which the assistant leaves out. A picture whose name, or the name of one of its folders, the chosen folder included, starts with “icon” is an icon. An icon may appear on several slides and goes into picture placeholders of any size, except those which cover half the slide or more, as a background picture does. From a folder with more than {0} pictures, the LLM gets a random {0} of them for each planning."), MaxLibraryPictures);
public static string WhatAPictureLibraryOffers => string.Format(TA("Choose a folder with pictures and icons, e.g., the picture library of your organization. The LLM reads only their names, never the pictures themselves, and uses a picture where its name fits a slide; it does not have to use any. So clear names such as “rocket-launch.jpg” help. Only PNG and JPEG pictures count: many icons come as SVG, which the assistant leaves out. A picture whose name, or the name of one of its folders, the chosen folder included, starts with “icon” is an icon. An icon may appear on several slides and goes into picture placeholders of any size, except those which cover half the slide or more, as a background picture does. From a folder with more than {0} pictures, the LLM gets a random {0} of them for each planning."), MaxLibraryPictures);
/// <summary>
/// The most pictures of a library the LLM reads about, as the user reads the number.
@@ -37,5 +37,5 @@ public static class SlideAssistantTexts
/// <summary>
/// What the presentation does with the slides a template carries besides its layouts.
/// </summary>
public static string WhatHappensToTemplateSlides => TB("Besides its layouts, your file contains slides, e.g., samples of the template or the slides of an earlier presentation. By default, the presentation leaves them out. Choose for each slide whether the presentation keeps it unchanged or lets the LLM edit its content. The LLM uses each of these slides exactly once, keeps them in their order, and may add new slides before, between, and after them. It never copies a slide as a pattern: new slides always come from the layouts of your template.");
public static string WhatHappensToTemplateSlides => TA("Besides its layouts, your file contains slides, e.g., samples of the template or the slides of an earlier presentation. By default, the presentation leaves them out. Choose for each slide whether the presentation keeps it unchanged or lets the LLM edit its content. The LLM uses each of these slides exactly once, keeps them in their order, and may add new slides before, between, and after them. It never copies a slide as a pattern: new slides always come from the layouts of your template.");
}
@@ -1,7 +1,7 @@
@attribute [Route(Routes.ASSISTANT_SYNONYMS)]
@inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogSynonyms>
<MudTextField T="string" @bind-Text="@this.inputText" Validation="@this.ValidatingText" AdornmentIcon="@AppIcons.WORD_OR_PHRASE" Adornment="Adornment.Start" Label="@T("Your word or phrase")" Variant="Variant.Outlined" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudTextField T="string" @bind-Text="@this.inputText" Validation="@this.ValidatingText" AdornmentIcon="@AppIcons.WORD_OR_PHRASE" Adornment="Adornment.Start" Label="@TA("Your word or phrase")" Variant="Variant.Outlined" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudTextField T="string" @bind-Text="@this.inputContext" AdornmentIcon="@AppIcons.DESCRIPTION" Adornment="Adornment.Start" Lines="2" Sizing="InputSizing.Fixed" Label="@T("(Optional) The context for the given word or phrase")" Variant="Variant.Outlined" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelectingOptional)" @bind-Value="@this.selectedLanguage" Icon="@AppIcons.LANGUAGE" Label="@T("Language")" AllowOther="@true" OtherValue="CommonLanguages.OTHER" @bind-OtherInput="@this.customTargetLanguage" ValidateOther="@this.ValidateCustomLanguage" LabelOther="@T("Custom target language")" />
@@ -155,7 +155,7 @@ public partial class AssistantSynonyms : AssistantBaseCore<SettingsDialogSynonym
private string? ValidatingText(string text)
{
if(string.IsNullOrWhiteSpace(text))
return T("Please provide a word or phrase as input.");
return TA("Please provide a word or phrase as input.");
return null;
}
@@ -163,7 +163,7 @@ public partial class AssistantSynonyms : AssistantBaseCore<SettingsDialogSynonym
private string? ValidateCustomLanguage(string language)
{
if(this.selectedLanguage == CommonLanguages.OTHER && string.IsNullOrWhiteSpace(language))
return T("Please provide a custom language.");
return TA("Please provide a custom language.");
return null;
}
@@ -7,8 +7,8 @@
}
<ReadFileContent @bind-FileContent="@this.inputText" EnableDragDrop="true" CatchAllDocuments="true"/>
<MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.inputText" Validation="@this.ValidatingText" AdornmentIcon="@AppIcons.INPUT_TEXT" Adornment="Adornment.Start" Label="@T("Your input")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.inputText" Validation="@this.ValidatingText" AdornmentIcon="@AppIcons.INPUT_TEXT" Adornment="Adornment.Start" Label="@TA("Your input")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<EnumSelection T="CommonLanguages" NameFunc="@(language => language.Name)" @bind-Value="@this.selectedTargetLanguage" Icon="@AppIcons.LANGUAGE" Label="@T("Target language")" AllowOther="@true" @bind-OtherInput="@this.customTargetLanguage" OtherValue="CommonLanguages.OTHER" LabelOther="@T("Custom target language")" ValidateOther="@this.ValidateCustomLanguage" />
<EnumSelection T="Complexity" NameFunc="@(complexity => complexity.Name)" @bind-Value="@this.selectedComplexity" Icon="@AppIcons.TEXT_COMPLEXITY" Label="@T("Target complexity")" AllowOther="@true" @bind-OtherInput="@this.expertInField" OtherValue="Complexity.SCIENTIFIC_LANGUAGE_OTHER_EXPERTS" LabelOther="@T("Your expertise")" ValidateOther="@this.ValidateExpertInField" />
<MudTextField T="string" Sizing="InputSizing.Auto" Lines="2" @bind-Text="@this.importantAspects" class="mb-3" Label="@T("(Optional) Important Aspects")" HelperText="@T("(Optional) Specify aspects for the LLM to focus on when generating a summary, such as summary length or specific topics to emphasize.")" ShrinkLabel="true" Variant="Variant.Outlined" AdornmentIcon="@AppIcons.IMPORTANT_ASPECTS" Adornment="Adornment.Start"/>
<EnumSelection T="Complexity" NameFunc="@(complexity => complexity.Name)" @bind-Value="@this.selectedComplexity" Icon="@AppIcons.TEXT_COMPLEXITY" Label="@T("Target complexity")" AllowOther="@true" @bind-OtherInput="@this.expertInField" OtherValue="Complexity.SCIENTIFIC_LANGUAGE_OTHER_EXPERTS" LabelOther="@TA("Your expertise")" ValidateOther="@this.ValidateExpertInField" />
<MudTextField T="string" Sizing="InputSizing.Auto" Lines="2" @bind-Text="@this.importantAspects" class="mb-3" Label="@T("(Optional) Important Aspects")" HelperText="@TA("(Optional) Specify aspects for the LLM to focus on when generating a summary, such as summary length or specific topics to emphasize.")" ShrinkLabel="true" Variant="Variant.Outlined" AdornmentIcon="@AppIcons.IMPORTANT_ASPECTS" Adornment="Adornment.Start"/>
<ProviderSelection @bind-ProviderSettings="@this.ProviderSettings" ValidateProvider="@this.ValidatingProvider"/>
@@ -10,7 +10,7 @@ public partial class AssistantTextSummarizer : AssistantBaseCore<SettingsDialogT
protected override string Title => T("Text Summarizer");
protected override string Description => T("Summarize long text into a shorter version while retaining the main points. You might want to change the language of the summary to make it more readable. It is also possible to change the complexity of the summary to make it easy to understand.");
protected override string Description => TA("Summarize long text into a shorter version while retaining the main points. You might want to change the language of the summary to make it more readable. It is also possible to change the complexity of the summary to make it easy to understand.");
// The prompt of this assistant asks for the summary only, so the chat gets a prompt of its own, which keeps the settings of the summary:
protected override ChatSystemPromptChoice ChatSystemPrompt => ChatSystemPromptChoice.Custom(this.CreateChatSystemPrompt);
@@ -147,7 +147,7 @@ public partial class AssistantTextSummarizer : AssistantBaseCore<SettingsDialogT
private string? ValidatingText(string text)
{
if(string.IsNullOrWhiteSpace(text))
return T("Please provide a text as input. You might copy the desired text from a document or a website.");
return TA("Please provide a text as input. You might copy the desired text from a document or a website.");
return null;
}
@@ -155,7 +155,7 @@ public partial class AssistantTextSummarizer : AssistantBaseCore<SettingsDialogT
private string? ValidateCustomLanguage(string language)
{
if(this.selectedTargetLanguage == CommonLanguages.OTHER && string.IsNullOrWhiteSpace(language))
return T("Please provide a custom language.");
return TA("Please provide a custom language.");
return null;
}
@@ -163,7 +163,7 @@ public partial class AssistantTextSummarizer : AssistantBaseCore<SettingsDialogT
private string? ValidateExpertInField(string field)
{
if(this.selectedComplexity == Complexity.SCIENTIFIC_LANGUAGE_OTHER_EXPERTS && string.IsNullOrWhiteSpace(field))
return T("Please provide your field of expertise.");
return TA("Please provide your field of expertise.");
return null;
}
@@ -11,11 +11,11 @@
<MudTextSwitch Label="@T("Live translation")" @bind-Value="@this.liveTranslation" LabelOn="@T("Live translation")" LabelOff="@T("No live translation")"/>
@if (this.liveTranslation)
{
<DebouncedTextField Disabled="@this.isAgentRunning" @bind-Text="@this.inputText" ValidationFunc="@this.ValidatingText" Icon="@AppIcons.INPUT_TEXT" Label="@T("Your input")" Lines="6" MaxLines="12" DebounceTime="@TimeSpan.FromMilliseconds(this.SettingsManager.ConfigurationData.Translation.DebounceIntervalMilliseconds)" WhenTextChangedAsync="async _ => await this.TranslateText(force: false)" Attributes="@USER_INPUT_ATTRIBUTES"/>
<DebouncedTextField Disabled="@this.isAgentRunning" @bind-Text="@this.inputText" ValidationFunc="@this.ValidatingText" Icon="@AppIcons.INPUT_TEXT" Label="@TA("Your input")" Lines="6" MaxLines="12" DebounceTime="@TimeSpan.FromMilliseconds(this.SettingsManager.ConfigurationData.Translation.DebounceIntervalMilliseconds)" WhenTextChangedAsync="async _ => await this.TranslateText(force: false)" Attributes="@USER_INPUT_ATTRIBUTES"/>
}
else
{
<MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.inputText" Validation="@this.ValidatingText" AdornmentIcon="@AppIcons.INPUT_TEXT" Adornment="Adornment.Start" Label="@T("Your input")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.inputText" Validation="@this.ValidatingText" AdornmentIcon="@AppIcons.INPUT_TEXT" Adornment="Adornment.Start" Label="@TA("Your input")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
}
<EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelecting)" @bind-Value="@this.selectedTargetLanguage" ValidateSelection="@this.ValidatingTargetLanguage" Icon="@AppIcons.LANGUAGE" Label="@T("Target language")" AllowOther="@true" OtherValue="CommonLanguages.OTHER" @bind-OtherInput="@this.customTargetLanguage" ValidateOther="@this.ValidateCustomLanguage" LabelOther="@T("Custom target language")" />
@@ -151,7 +151,7 @@ public partial class AssistantTranslation : AssistantBaseCore<SettingsDialogTran
private string? ValidatingText(string text)
{
if(string.IsNullOrWhiteSpace(text))
return T("Please provide a text as input. You might copy the desired text from a document or a website.");
return TA("Please provide a text as input. You might copy the desired text from a document or a website.");
return null;
}
@@ -159,7 +159,7 @@ public partial class AssistantTranslation : AssistantBaseCore<SettingsDialogTran
private string? ValidatingTargetLanguage(CommonLanguages language)
{
if(language == CommonLanguages.AS_IS)
return T("Please select a target language.");
return TA("Please select a target language.");
return null;
}
@@ -167,7 +167,7 @@ public partial class AssistantTranslation : AssistantBaseCore<SettingsDialogTran
private string? ValidateCustomLanguage(string language)
{
if(this.selectedTargetLanguage == CommonLanguages.OTHER && string.IsNullOrWhiteSpace(language))
return T("Please provide a custom language.");
return TA("Please provide a custom language.");
return null;
}
@@ -68,7 +68,7 @@
<MudCopyClipboardButton TooltipMessage="@T("Copy project ID")" StringContent="@this.selectedProject.BriefingId.ToString("D")"/>
</MudStack>
<MudText Typo="Typo.body2">
@T("If you need help, report the problem and include the project ID.")
@TA("If you need help, report the problem and include the project ID.")
<MudLink Href="https://github.com/MindWorkAI/AI-Studio" Target="_blank">@T("Report a problem?")</MudLink>
</MudText>
<MudStack Row="true" Spacing="1" Wrap="Wrap.Wrap">
@@ -81,7 +81,7 @@
else if (this.selectedBriefing is null)
{
<MudPaper Outlined="true" Class="pa-6">
<MudText Typo="Typo.h5">@T("Create or import a visual briefing to begin.")</MudText>
<MudText Typo="Typo.h5">@TA("Create or import a visual briefing to begin.")</MudText>
</MudPaper>
}
else
@@ -248,7 +248,7 @@
</MudTooltip>
<MudTooltip Text="@(this.SelectedVersionSupportsEdits
? T("Recompile this version with the current AI Studio version without AI model calls.")
: T("This version has no compatible semantic artifacts. Rebuild the briefing instead."))">
: TA("This version has no compatible semantic artifacts. Rebuild the briefing instead."))">
<span>
<MudButton Variant="Variant.Filled" StartIcon="@AppIcons.RECOMPILE" OnClick="@(() => this.RecompileAsync())" Disabled="@this.CannotRecompile">@T("Recompile briefing")</MudButton>
</span>
@@ -278,7 +278,7 @@
{
<MudAlert Severity="Severity.Warning" Variant="Variant.Outlined" Class="mb-4">
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Wrap="Wrap.Wrap">
<MudText>@T("The updated content no longer fits the current presentation. You can continue as a rebuild without another content model call.")</MudText>
<MudText>@TA("The updated content no longer fits the current presentation. You can continue as a rebuild without another content model call.")</MudText>
<MudButton Variant="Variant.Filled"
Color="Color.Warning"
StartIcon="@AppIcons.REGENERATE"
@@ -169,7 +169,7 @@ public partial class VisualBriefingAssistant
parentRevisionId, generationProvider, generationProfile, reusableBuildId, token),
T("A new visual briefing version was created."),
T("The visual briefing generation was canceled."),
T("The visual briefing operation failed unexpectedly. Copy the technical details for support."));
TA("The visual briefing operation failed unexpectedly. Copy the technical details for support."));
}
/// <summary>
@@ -189,7 +189,7 @@ public partial class VisualBriefingAssistant
token => this.BuildOrchestrator.RecompileAsync(recompileBriefing, parentRevisionId, token),
T("The briefing was recompiled with the current AI Studio version."),
T("The visual briefing recompilation was canceled."),
T("The visual briefing recompilation failed unexpectedly. Copy the technical details for support."));
TA("The visual briefing recompilation failed unexpectedly. Copy the technical details for support."));
}
/// <summary>
@@ -100,13 +100,13 @@ public partial class VisualBriefingAssistant
var parameters = new DialogParameters<SingleInputDialog>
{
{ dialog => dialog.Message, T("Enter a new name for this visual briefing.") },
{ dialog => dialog.Message, TA("Enter a new name for this visual briefing.") },
{ dialog => dialog.InputHeaderText, T("Briefing name") },
{ dialog => dialog.UserInput, this.editor.Name },
{ dialog => dialog.ConfirmText, T("Rename") },
{ dialog => dialog.ConfirmColor, Color.Info },
{ dialog => dialog.AllowEmptyInput, false },
{ dialog => dialog.EmptyInputErrorMessage, T("Please enter a briefing name.") },
{ dialog => dialog.EmptyInputErrorMessage, TA("Please enter a briefing name.") },
};
var reference = await this.DialogService.ShowAsync<SingleInputDialog>(T("Rename visual briefing"), parameters, DialogOptions.FULLSCREEN);
@@ -131,7 +131,7 @@ public partial class VisualBriefingAssistant
parameters.Add(dialog => dialog.Message, string.Format(T("Permanently delete the visual briefing '{0}' and all of its versions and transcripts?"), this.selectedProject.Name));
else
{
var reportingWarning = T("This visual briefing cannot currently be opened. Consider reporting the problem in the [MindWork AI Studio issue tracker](https://github.com/MindWorkAI/AI-Studio), because a future update may make the briefing accessible again.");
var reportingWarning = TA("This visual briefing cannot currently be opened. Consider reporting the problem in the [MindWork AI Studio issue tracker](https://github.com/MindWorkAI/AI-Studio), because a future update may make the briefing accessible again.");
var deletionWarning = T("Permanently delete this visual briefing and all of its versions and transcripts?");
parameters.Add(dialog => dialog.MarkdownBody, $"{reportingWarning}\n\n{deletionWarning}");
}
@@ -42,7 +42,7 @@ public partial class VisualBriefingAssistant
List<string> issues = [.. this.formIssues, .. this.FieldIssues, .. this.SourceIssues];
if (this.selectedBriefing is { Versions.Count: > 0 } && !this.SelectedVersionSupportsEdits)
issues.Add(T("This version has no compatible semantic artifacts. Rebuild the briefing instead."));
issues.Add(TA("This version has no compatible semantic artifacts. Rebuild the briefing instead."));
return [.. issues.Where(issue => !string.IsNullOrWhiteSpace(issue)).Distinct(StringComparer.Ordinal)];
}
@@ -80,12 +80,12 @@ public partial class VisualBriefingAssistant
List<string> issues = [];
if (!this.HasSourceMaterial)
issues.Add(T("Please add at least one source material file."));
issues.Add(TA("Please add at least one source material file."));
// A model can be selected long after the images were attached, so the capability that was
// checked while attaching them has to be checked again here:
if (this.HasImageSources && this.editor.Provider != ProviderSettings.NONE && !this.editor.Provider.SupportsImageInput())
issues.Add(T("Images are not supported by the selected provider and model. Select a model with image support, or remove the image sources."));
issues.Add(TA("Images are not supported by the selected provider and model. Select a model with image support, or remove the image sources."));
foreach (var source in this.selectedBriefing.Sources)
{
@@ -93,11 +93,11 @@ public partial class VisualBriefingAssistant
switch (source.Status)
{
case VisualBriefingSourceStatus.UNREACHABLE:
issues.Add(string.Format(T("The source '{0}' is no longer reachable. Restore or relink it."), fileName));
issues.Add(string.Format(TA("The source '{0}' is no longer reachable. Restore or relink it."), fileName));
break;
case VisualBriefingSourceStatus.TRANSCRIPT_OUTDATED:
issues.Add(string.Format(T("The transcript for '{0}' is missing or outdated. Transcribe the media source again."), fileName));
issues.Add(string.Format(TA("The transcript for '{0}' is missing or outdated. Transcribe the media source again."), fileName));
break;
}
}
@@ -107,7 +107,7 @@ public partial class VisualBriefingAssistant
}
/// <summary>Validates the briefing name.</summary>
private string? ValidateProjectName(string name) => string.IsNullOrWhiteSpace(name) ? T("Please provide a briefing name.") : null;
private string? ValidateProjectName(string name) => string.IsNullOrWhiteSpace(name) ? TA("Please provide a briefing name.") : null;
/// <summary>Validates the selected generation provider.</summary>
/// <remarks>
@@ -117,11 +117,11 @@ public partial class VisualBriefingAssistant
private string? ValidateProvider(ProviderSettings value)
{
if (value == ProviderSettings.NONE || value.UsedLLMProvider is LLMProviders.NONE)
return T("Please select a provider.");
return TA("Please select a provider.");
var restrictions = this.selectedBriefing?.Restrictions ?? ChatRestrictions.NONE;
if (!restrictions.IsLLMProviderAllowed(value) && ChatRestrictions.NONE.IsLLMProviderAllowed(value))
return T("This provider may not see the text sent to this briefing, because of where the text came from. Please select another provider.");
return TA("This provider may not see the text sent to this briefing, because of where the text came from. Please select another provider.");
return null;
}
@@ -129,13 +129,13 @@ public partial class VisualBriefingAssistant
/// <summary>Validates the free-form target language when Other is selected.</summary>
private string? ValidateCustomTargetLanguage(string language) =>
this.editor.TargetLanguage is CommonLanguages.OTHER && string.IsNullOrWhiteSpace(language)
? T("Please provide a custom target language.")
? TA("Please provide a custom target language.")
: null;
/// <summary>Validates the free-form protection level when Other is selected.</summary>
private string? ValidateCustomProtectionLevel(string level) =>
this.editor.ProtectionLevel is VisualBriefingProtectionLevel.OTHER && string.IsNullOrWhiteSpace(level)
? T("Please provide a custom protection level.")
? TA("Please provide a custom protection level.")
: null;
/// <summary>Revalidates after a conditional Other field has been added or removed.</summary>
@@ -118,7 +118,7 @@ public partial class VisualBriefingAssistant
if (PathComparer().Equals(Path.GetFullPath(sourcePath), Path.GetFullPath(response.SaveFilePath)))
{
await this.MessageBus.SendError(new(AppIcons.SAVE_FAILED, T("Choose a different export location so the immutable briefing version is not overwritten.")));
await this.MessageBus.SendError(new(AppIcons.SAVE_FAILED, TA("Choose a different export location so the immutable briefing version is not overwritten.")));
return;
}
@@ -176,7 +176,7 @@ public partial class VisualBriefingAssistant
catch (Exception e)
{
this.Logger.LogError(e, "The visual briefing could not be exported, because the file '{FilePath}' cannot be opened for writing.", targetPath);
await this.MessageBus.SendError(new(AppIcons.EXPORT, T("The visual briefing could not be exported. Please check that the target file is not open in another program.")));
await this.MessageBus.SendError(new(AppIcons.EXPORT, TA("The visual briefing could not be exported. Please check that the target file is not open in another program.")));
return false;
}
@@ -13,6 +13,8 @@ internal static class VisualBriefingFailureExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(VisualBriefingFailureExtensions).Namespace, nameof(VisualBriefingFailureExtensions));
private static string TA(string fallbackEN) => Tools.PluginSystem.I18N.I.TA(fallbackEN, typeof(VisualBriefingFailureExtensions).Namespace, nameof(VisualBriefingFailureExtensions));
/// <param name="failure">The recorded failure.</param>
extension(VisualBriefingFailure failure)
{
@@ -52,30 +54,30 @@ internal static class VisualBriefingFailureExtensions
/// <returns>The localized message.</returns>
private string ToUserMessage() => rule switch
{
VisualBriefingValidationRule.JSON_INVALID => TB("The model did not return valid JSON. Please try again or select another model."),
VisualBriefingValidationRule.VALUE_TYPE_INVALID => TB("The model response contained a value of the wrong type. Please try again or select another model."),
VisualBriefingValidationRule.UNKNOWN_FIELD => TB("The model response contained unexpected fields. Please try again or select another model."),
VisualBriefingValidationRule.CONTRACT_VERSION_UNSUPPORTED => TB("The model response used an unsupported contract version. Please try again or select another model."),
VisualBriefingValidationRule.ID_INVALID => TB("The model response contained an empty, malformed, or duplicated identifier. Please try again or select another model."),
VisualBriefingValidationRule.REFERENCE_INVALID => TB("The model response referenced content that does not exist. Please try again or select another model."),
VisualBriefingValidationRule.SOURCE_COVERAGE_INVALID => TB("The model did not cover every source of this briefing exactly once. Please try again or select another model."),
VisualBriefingValidationRule.ASSET_PLAN_INVALID => TB("The model did not plan every visual asset of this briefing exactly once. Please try again or select another model."),
VisualBriefingValidationRule.SLOT_FULFILLMENT_INVALID => TB("The model did not fill every planned content slot exactly once. Please try again or select another model."),
VisualBriefingValidationRule.SLOT_VALUE_TYPE_INVALID => TB("The model filled a content slot with the wrong kind of value. Please try again or select another model."),
VisualBriefingValidationRule.CHART_SET_INVALID => TB("The charts of the model response did not match the planned briefing elements. Please try again or select another model."),
VisualBriefingValidationRule.CHART_DATA_INVALID => TB("A chart of the model response contained invalid categories or data series. Please try again or select another model."),
VisualBriefingValidationRule.CONTROL_ID_INVALID => TB("An interactive control of the model response used an invalid identifier. Please try again or select another model."),
VisualBriefingValidationRule.CONTROL_TARGET_INVALID => TB("An interactive control of the model response targeted an invalid briefing element. Please try again or select another model."),
VisualBriefingValidationRule.CONTROL_STATE_INVALID => TB("An interactive control of the model response used an invalid initial state. Please try again or select another model."),
VisualBriefingValidationRule.CONTROL_REQUIREMENT_INVALID => TB("A briefing element of the model response was missing its required interactive controls. Please try again or select another model."),
VisualBriefingValidationRule.FORMULA_TARGET_INVALID => TB("A calculation of the model response targeted an invalid briefing element. Please try again or select another model."),
VisualBriefingValidationRule.FORMULA_AST_INVALID => TB("A calculation of the model response used an invalid operation. Please try again or select another model."),
VisualBriefingValidationRule.ACCESSIBILITY_SET_INVALID => TB("The accessibility texts of the model response did not match the briefing elements. Please try again or select another model."),
VisualBriefingValidationRule.ACCESSIBILITY_TEXT_INVALID => TB("An accessibility text of the model response was empty or invalid. Please try again or select another model."),
VisualBriefingValidationRule.LAYOUT_INVALID => TB("The model response used an invalid briefing layout. Please try again or select another model."),
VisualBriefingValidationRule.TEMPLATE_ATTRIBUTE_PROHIBITED => TB("The model response used a prohibited attribute. Please try again or select another model."),
VisualBriefingValidationRule.MODEL_MARKUP_PROHIBITED => TB("The model response contained markup or code, which this briefing does not allow. Please try again or select another model."),
VisualBriefingValidationRule.COMPILER_OUTPUT_INVALID => TB("AI Studio compiled this briefing into an inconsistent result. Please copy the technical details and report this issue."),
VisualBriefingValidationRule.JSON_INVALID => TA("The model did not return valid JSON. Please try again or select another model."),
VisualBriefingValidationRule.VALUE_TYPE_INVALID => TA("The model response contained a value of the wrong type. Please try again or select another model."),
VisualBriefingValidationRule.UNKNOWN_FIELD => TA("The model response contained unexpected fields. Please try again or select another model."),
VisualBriefingValidationRule.CONTRACT_VERSION_UNSUPPORTED => TA("The model response used an unsupported contract version. Please try again or select another model."),
VisualBriefingValidationRule.ID_INVALID => TA("The model response contained an empty, malformed, or duplicated identifier. Please try again or select another model."),
VisualBriefingValidationRule.REFERENCE_INVALID => TA("The model response referenced content that does not exist. Please try again or select another model."),
VisualBriefingValidationRule.SOURCE_COVERAGE_INVALID => TA("The model did not cover every source of this briefing exactly once. Please try again or select another model."),
VisualBriefingValidationRule.ASSET_PLAN_INVALID => TA("The model did not plan every visual asset of this briefing exactly once. Please try again or select another model."),
VisualBriefingValidationRule.SLOT_FULFILLMENT_INVALID => TA("The model did not fill every planned content slot exactly once. Please try again or select another model."),
VisualBriefingValidationRule.SLOT_VALUE_TYPE_INVALID => TA("The model filled a content slot with the wrong kind of value. Please try again or select another model."),
VisualBriefingValidationRule.CHART_SET_INVALID => TA("The charts of the model response did not match the planned briefing elements. Please try again or select another model."),
VisualBriefingValidationRule.CHART_DATA_INVALID => TA("A chart of the model response contained invalid categories or data series. Please try again or select another model."),
VisualBriefingValidationRule.CONTROL_ID_INVALID => TA("An interactive control of the model response used an invalid identifier. Please try again or select another model."),
VisualBriefingValidationRule.CONTROL_TARGET_INVALID => TA("An interactive control of the model response targeted an invalid briefing element. Please try again or select another model."),
VisualBriefingValidationRule.CONTROL_STATE_INVALID => TA("An interactive control of the model response used an invalid initial state. Please try again or select another model."),
VisualBriefingValidationRule.CONTROL_REQUIREMENT_INVALID => TA("A briefing element of the model response was missing its required interactive controls. Please try again or select another model."),
VisualBriefingValidationRule.FORMULA_TARGET_INVALID => TA("A calculation of the model response targeted an invalid briefing element. Please try again or select another model."),
VisualBriefingValidationRule.FORMULA_AST_INVALID => TA("A calculation of the model response used an invalid operation. Please try again or select another model."),
VisualBriefingValidationRule.ACCESSIBILITY_SET_INVALID => TA("The accessibility texts of the model response did not match the briefing elements. Please try again or select another model."),
VisualBriefingValidationRule.ACCESSIBILITY_TEXT_INVALID => TA("An accessibility text of the model response was empty or invalid. Please try again or select another model."),
VisualBriefingValidationRule.LAYOUT_INVALID => TA("The model response used an invalid briefing layout. Please try again or select another model."),
VisualBriefingValidationRule.TEMPLATE_ATTRIBUTE_PROHIBITED => TA("The model response used a prohibited attribute. Please try again or select another model."),
VisualBriefingValidationRule.MODEL_MARKUP_PROHIBITED => TA("The model response contained markup or code, which this briefing does not allow. Please try again or select another model."),
VisualBriefingValidationRule.COMPILER_OUTPUT_INVALID => TA("AI Studio compiled this briefing into an inconsistent result. Please copy the technical details and report this issue."),
_ => string.Empty,
};
@@ -90,27 +92,27 @@ internal static class VisualBriefingFailureExtensions
/// <returns>The localized message.</returns>
private string ToUserMessage() => code switch
{
VisualBriefingFailureCode.PROVIDER_NOT_SELECTED => TB("This briefing has no provider selected. Please select a provider before you generate a briefing."),
VisualBriefingFailureCode.PROVIDER_NOT_ALLOWED => TB("The selected provider may not see the content of this briefing. Please select another provider."),
VisualBriefingFailureCode.MODEL_CAPABILITY_MISSING => TB("The selected model lacks a capability this briefing needs. Please select another model."),
VisualBriefingFailureCode.SOURCE_UNREACHABLE => TB("A source of this briefing can no longer be reached. Please relink or remove the affected source."),
VisualBriefingFailureCode.TRANSCRIPT_UNAVAILABLE => TB("A media transcript of this briefing is missing or outdated. Please transcribe the affected media again."),
VisualBriefingFailureCode.PROVIDER_NOT_SELECTED => TA("This briefing has no provider selected. Please select a provider before you generate a briefing."),
VisualBriefingFailureCode.PROVIDER_NOT_ALLOWED => TA("The selected provider may not see the content of this briefing. Please select another provider."),
VisualBriefingFailureCode.MODEL_CAPABILITY_MISSING => TA("The selected model lacks a capability this briefing needs. Please select another model."),
VisualBriefingFailureCode.SOURCE_UNREACHABLE => TA("A source of this briefing can no longer be reached. Please relink or remove the affected source."),
VisualBriefingFailureCode.TRANSCRIPT_UNAVAILABLE => TA("A media transcript of this briefing is missing or outdated. Please transcribe the affected media again."),
VisualBriefingFailureCode.SOURCE_PREPARATION_FAILED => TB("The sources of this briefing could not be prepared."),
VisualBriefingFailureCode.PROVIDER_CALL_FAILED => TB("The selected provider could not complete this briefing stage."),
VisualBriefingFailureCode.RESPONSE_JSON_INVALID => TB("The model did not return valid JSON. Please try again or select another model."),
VisualBriefingFailureCode.RESPONSE_CONTRACT_INVALID => TB("The model response did not match the required contract. Please try again or select another model."),
VisualBriefingFailureCode.COMPILER_INVARIANT_VIOLATED => TB("AI Studio compiled this briefing into an inconsistent result. Please copy the technical details and report this issue."),
VisualBriefingFailureCode.SOURCE_COVERAGE_INVALID => TB("The model did not cover every source of this briefing exactly once. Please try again or select another model."),
VisualBriefingFailureCode.ASSET_PLAN_INVALID => TB("The model did not plan every visual asset of this briefing exactly once. Please try again or select another model."),
VisualBriefingFailureCode.CONTENT_SIGNATURE_INCOMPATIBLE => TB("The updated content no longer fits the current presentation. You can continue as a rebuild."),
VisualBriefingFailureCode.PRESENTATION_INVALID => TB("The presentation of the model response did not match the briefing contract. Please try again or select another model."),
VisualBriefingFailureCode.RESPONSE_JSON_INVALID => TA("The model did not return valid JSON. Please try again or select another model."),
VisualBriefingFailureCode.RESPONSE_CONTRACT_INVALID => TA("The model response did not match the required contract. Please try again or select another model."),
VisualBriefingFailureCode.COMPILER_INVARIANT_VIOLATED => TA("AI Studio compiled this briefing into an inconsistent result. Please copy the technical details and report this issue."),
VisualBriefingFailureCode.SOURCE_COVERAGE_INVALID => TA("The model did not cover every source of this briefing exactly once. Please try again or select another model."),
VisualBriefingFailureCode.ASSET_PLAN_INVALID => TA("The model did not plan every visual asset of this briefing exactly once. Please try again or select another model."),
VisualBriefingFailureCode.CONTENT_SIGNATURE_INCOMPATIBLE => TA("The updated content no longer fits the current presentation. You can continue as a rebuild."),
VisualBriefingFailureCode.PRESENTATION_INVALID => TA("The presentation of the model response did not match the briefing contract. Please try again or select another model."),
VisualBriefingFailureCode.ASSEMBLY_FAILED => TB("This briefing could not be assembled."),
VisualBriefingFailureCode.ARTIFACT_VALIDATION_FAILED => TB("The assembled briefing did not pass the security validation."),
VisualBriefingFailureCode.STORE_FAILED => TB("The new version of this briefing could not be saved."),
VisualBriefingFailureCode.NO_CHANGES => TB("This operation did not change the briefing, so no new version was created."),
VisualBriefingFailureCode.CANCELED => TB("This visual briefing operation was canceled."),
VisualBriefingFailureCode.BUILD_INTERRUPTED => TB("AI Studio was closed while this briefing was being built. You can resume the build."),
VisualBriefingFailureCode.UNEXPECTED => TB("This visual briefing operation failed because of an unexpected internal error. Please copy the technical details for support."),
VisualBriefingFailureCode.BUILD_INTERRUPTED => TA("AI Studio was closed while this briefing was being built. You can resume the build."),
VisualBriefingFailureCode.UNEXPECTED => TA("This visual briefing operation failed because of an unexpected internal error. Please copy the technical details for support."),
_ => string.Empty,
};
@@ -5,6 +5,8 @@ namespace AIStudio.Chat;
public static class ChatRoleExtensions
{
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(ChatRoleExtensions).Namespace, nameof(ChatRoleExtensions));
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(ChatRoleExtensions).Namespace, nameof(ChatRoleExtensions));
/// <param name="role">The role.</param>
extension(ChatRole role)
@@ -16,7 +18,7 @@ public static class ChatRoleExtensions
public string Name => role switch
{
ChatRole.SYSTEM => TB("System"),
ChatRole.USER => TB("You"),
ChatRole.USER => TA("You"),
ChatRole.AI => TB("AI"),
_ => TB("Unknown"),
@@ -621,7 +621,7 @@ public partial class ContentBlockComponent : MSGComponentBase
var remove = await this.DialogService.ShowMessageBoxAsync(
T("Remove Message"),
T("Do you really want to remove this message?"),
TA("Do you really want to remove this message?"),
T("Yes, remove it"),
T("No, keep it"));
@@ -703,7 +703,7 @@ public partial class ContentBlockComponent : MSGComponentBase
var regenerate = await this.DialogService.ShowMessageBoxAsync(
T("Regenerate Message"),
T("Do you really want to regenerate this message?"),
TA("Do you really want to regenerate this message?"),
T("Yes, regenerate it"),
T("No, keep it"));
@@ -718,7 +718,7 @@ public partial class ContentBlockComponent : MSGComponentBase
var rollback = await this.DialogService.ShowMessageBoxAsync(
T("Roll Back Chat"),
T("Do you really want to roll back this chat to this AI response? All later messages and their attachments will be permanently removed."),
TA("Do you really want to roll back this chat to this AI response? All later messages and their attachments will be permanently removed."),
T("Yes, roll back the chat"),
T("No, keep it"));
@@ -747,7 +747,7 @@ public partial class ContentBlockComponent : MSGComponentBase
var edit = await this.DialogService.ShowMessageBoxAsync(
T("Edit Message"),
T("Do you really want to edit this message? In order to edit this message, the AI response will be deleted."),
TA("Do you really want to edit this message? In order to edit this message, the AI response will be deleted."),
T("Yes, remove the AI response and edit it"),
T("No, keep it"));
+5 -3
View File
@@ -24,6 +24,8 @@ public sealed class ContentText : IContent
private static readonly ILogger<ContentText> LOGGER = Program.LOGGER_FACTORY.CreateLogger<ContentText>();
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(ContentText).Namespace, nameof(ContentText));
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(ContentText).Namespace, nameof(ContentText));
/// <summary>
/// The minimum time between two streaming events, when the user
@@ -178,7 +180,7 @@ public sealed class ContentText : IContent
}
if (Interlocked.Exchange(ref UNSTORED_CONTENT_REPORTED, 1) is 0)
await MessageBus.INSTANCE.SendWarning(new(AppIcons.PROVENANCE_STORE, TB("AI Studio could not store what the AI received separately from your chat. It remains in the chat itself, so you can still read it.")));
await MessageBus.INSTANCE.SendWarning(new(AppIcons.PROVENANCE_STORE, TA("AI Studio could not store what the AI received separately from your chat. It remains in the chat itself, so you can still read it.")));
}
/// <summary>
@@ -429,7 +431,7 @@ public sealed class ContentText : IContent
// The answer is about to be created without the data the user expected it to use.
// Without this message, that answer is indistinguishable from one that did use it:
//
await MessageBus.INSTANCE.SendWarning(new(AppIcons.DATA_SOURCE, TB("Your data sources could not be used. This answer was created without them.")));
await MessageBus.INSTANCE.SendWarning(new(AppIcons.DATA_SOURCE, TA("Your data sources could not be used. This answer was created without them.")));
}
}
@@ -607,7 +609,7 @@ public sealed class ContentText : IContent
return true;
var message = string.Format(
TB("The selected model '{0}' is no longer available from '{1}' (provider={2}). Please adapt your provider settings."),
TA("The selected model '{0}' is no longer available from '{1}' (provider={2}). Please adapt your provider settings."),
chatModel.Id,
provider.InstanceName,
provider.Provider);
@@ -141,9 +141,9 @@ public partial class AssistantBlock<TSettings> : MSGComponentBase, IAssistantCat
{
MediaImportStatus.QUEUED or MediaImportStatus.RUNNING or MediaImportStatus.CANCELING => new(AppIcons.RUNNING, Color.Info, this.T("Media is still being prepared.")),
MediaImportStatus.SUCCEEDED => new(AppIcons.SUCCESS, Color.Success, this.T("The media transcript is ready.")),
MediaImportStatus.WARNING => new(AppIcons.WARNING, Color.Warning, this.T("Media transcription completed with a warning. Open the assistant to review it.")),
MediaImportStatus.FAILED => new(AppIcons.ERROR, Color.Error, this.T("Media transcription failed. Open the assistant to review it.")),
MediaImportStatus.CANCELLED => new(AppIcons.CANCELED, Color.Warning, this.T("Media transcription was canceled. Open the assistant to review it.")),
MediaImportStatus.WARNING => new(AppIcons.WARNING, Color.Warning, this.TA("Media transcription completed with a warning. Open the assistant to review it.")),
MediaImportStatus.FAILED => new(AppIcons.ERROR, Color.Error, this.TA("Media transcription failed. Open the assistant to review it.")),
MediaImportStatus.CANCELLED => new(AppIcons.CANCELED, Color.Warning, this.TA("Media transcription was canceled. Open the assistant to review it.")),
_ => this.AssistantSessionIndicatorWithoutMedia,
};
@@ -152,8 +152,8 @@ public partial class AssistantBlock<TSettings> : MSGComponentBase, IAssistantCat
{
AssistantSessionStatus.RUNNING or AssistantSessionStatus.CANCELING => new(AppIcons.RUNNING, Color.Info, this.T("Assistant is still running.")),
AssistantSessionStatus.COMPLETED => new(AppIcons.SUCCESS, Color.Success, this.T("The result is ready.")),
AssistantSessionStatus.FAILED => new(AppIcons.ERROR, Color.Error, this.T("Assistant failed. Open it to review the result.")),
AssistantSessionStatus.CANCELED => new(AppIcons.CANCELED, Color.Warning, this.T("Assistant was canceled. Open it to review the result.")),
AssistantSessionStatus.FAILED => new(AppIcons.ERROR, Color.Error, this.TA("Assistant failed. Open it to review the result.")),
AssistantSessionStatus.CANCELED => new(AppIcons.CANCELED, Color.Warning, this.TA("Assistant was canceled. Open it to review the result.")),
_ => null,
};
@@ -80,7 +80,7 @@
<MudDivider Vertical="@true" FlexItem="@true" />
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1">
<MudIcon Icon="@AppIcons.LOCK" Size="Size.Small" Color="Color.Success" />
<MudText Typo="Typo.body2">@T("Your organization requires this assistant to stay enabled")</MudText>
<MudText Typo="Typo.body2">@TA("Your organization requires this assistant to stay enabled")</MudText>
</MudStack>
}
}
@@ -212,8 +212,8 @@
<td>
<MudText Typo="Typo.body2">
@(state.IsActivationEnforcedByOrganization
? T("Required by your organization")
: T("Enabled by your organization, you may switch it off"))
? TA("Required by your organization")
: TA("Enabled by your organization, you may switch it off"))
</MudText>
</td>
</tr>
@@ -268,7 +268,7 @@
@if (state.IsEnterpriseApproved)
{
<MudAlert Severity="Severity.Success" Variant="Variant.Text" Dense="@true">
@T("This plugin is approved by your organization. A manual security audit is not required.")
@TA("This plugin is approved by your organization. A manual security audit is not required.")
</MudAlert>
}
else
@@ -32,7 +32,7 @@
}
else if (this.DocumentPaths.Any())
{
<MudTooltip Text="@T("Click the paperclip to attach files, or click the number to see your attached files.")" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
<MudTooltip Text="@TA("Click the paperclip to attach files, or click the number to see your attached files.")" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
<MudBadge
Content="@this.DocumentPaths.Count"
Color="Color.Primary"
@@ -49,7 +49,7 @@
}
else
{
<MudTooltip Text="@T("Click here to attach files.")" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
<MudTooltip Text="@TA("Click here to attach files.")" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
<MudIconButton
Icon="@AppIcons.ATTACH_FILE"
Color="Color.Default"
@@ -70,7 +70,7 @@ else
{
<MudStack Row="true" AlignItems="AlignItems.Center" StretchItems="StretchItems.None" Wrap="Wrap.Wrap">
<MudText Typo="Typo.body1" Inline="true">
@T("Drag and drop files into the marked area or click here to attach documents: ")
@TA("Drag and drop files into the marked area or click here to attach documents: ")
</MudText>
<MudButton
Variant="Variant.Filled"
@@ -367,7 +367,7 @@ public partial class AttachDocuments : MSGComponentBase
this.Logger.LogWarning("Could not access {Count} dropped or selected file(s): {Paths}", inaccessiblePaths.Count, string.Join(", ", inaccessiblePaths));
await this.MessageBus.SendWarning(new(
AppIcons.WARNING,
this.T("Some files could not be accessed. Please select them with the file chooser instead.")));
this.TA("Some files could not be accessed. Please select them with the file chooser instead.")));
}
var existingPaths = pathList.Except(inaccessiblePaths).ToList();
@@ -422,7 +422,7 @@ public partial class AttachDocuments : MSGComponentBase
{
await this.MessageBus.SendWarning(new(
AppIcons.VOICE_TRANSCRIPTION,
this.T("Media files require a configured transcription provider. Configure one in the transcription settings.")));
this.TA("Media files require a configured transcription provider. Configure one in the transcription settings.")));
return attached;
}
@@ -68,7 +68,7 @@
this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is not WorkspaceStorageBehavior.DISABLE_WORKSPACES
&& this.SettingsManager.ConfigurationData.Workspace.DisplayBehavior is WorkspaceDisplayBehavior.TOGGLE_OVERLAY)
{
<MudTooltip Text="@T("Show your workspaces")" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
<MudTooltip Text="@TA("Show your workspaces")" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
<MudIconButton Icon="@AppIcons.WORKSPACES" OnClick="@(() => this.ToggleWorkspaceOverlay())"/>
</MudTooltip>
}
@@ -103,7 +103,7 @@
@if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is not WorkspaceStorageBehavior.DISABLE_WORKSPACES)
{
<MudTooltip Text="@T("Move the chat to a workspace, or to another if it is already in one.")" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
<MudTooltip Text="@TA("Move the chat to a workspace, or to another if it is already in one.")" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
<MudIconButton Icon="@AppIcons.MOVE_TO_WORKSPACE" Disabled="@(!this.CanThreadBeMoved)" OnClick="@this.MoveChatToWorkspace"/>
</MudTooltip>
@@ -151,7 +151,7 @@
@if (PreviewFeatures.PRE_RAG_2024.IsEnabled(this.SettingsManager))
{
<DataSourceSelection @ref="@this.dataSourceSelectionComponent" LLMProvider="@this.Provider" DataSourceOptions="@this.GetCurrentDataSourceOptions()" DataSourceOptionsChanged="@this.DataSourceOptionsWereChanged" DataSourcesAISelected="@this.GetAgentSelectedDataSources()" ReadOnly="@this.IsCurrentChatStreaming" ReadOnlyMessage="@T("Data source changes are locked while a response is running. Your current selection is shown below and applies again from the next message once the run is finished.")"/>
<DataSourceSelection @ref="@this.dataSourceSelectionComponent" LLMProvider="@this.Provider" DataSourceOptions="@this.GetCurrentDataSourceOptions()" DataSourceOptionsChanged="@this.DataSourceOptionsWereChanged" DataSourcesAISelected="@this.GetAgentSelectedDataSources()" ReadOnly="@this.IsCurrentChatStreaming" ReadOnlyMessage="@TA("Data source changes are locked while a response is running. Your current selection is shown below and applies again from the next message once the run is finished.")"/>
}
@if (this.SettingsManager.ConfigurationData.Confidence.ShowProviderConfidence)
@@ -168,7 +168,7 @@
@if (!this.ChatThread.IsLLMProviderAllowed(this.Provider))
{
<MudTooltip Text="@(this.SettingsManager.IsProviderProhibited(this.Provider.UsedLLMProvider) ? T("The use of this provider has been prohibited by your organization. Please select a different provider.") : T("The selected provider is not allowed in this chat due to data security or confidence-level requirements."))" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
<MudTooltip Text="@(this.SettingsManager.IsProviderProhibited(this.Provider.UsedLLMProvider) ? TA("The use of this provider has been prohibited by your organization. Please select a different provider.") : T("The selected provider is not allowed in this chat due to data security or confidence-level requirements."))" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
<MudIconButton Icon="@AppIcons.WARNING" Color="Color.Error"/>
</MudTooltip>
}
@@ -257,7 +257,7 @@ public partial class ChatComponent : MSGComponentBase
budget = string.Format(this.T("{0}, of which approx. {1} from tools"), budget, TokenAmount.Format(this.conversationTokens.ToolTokens, this.currentCulture));
if (this.conversationTokens.DraftTokens > 0)
budget = string.Format(this.T("{0}, plus approx. {1} for your message"), budget, TokenAmount.Format(this.conversationTokens.DraftTokens, this.currentCulture));
budget = string.Format(this.TA("{0}, plus approx. {1} for your message"), budget, TokenAmount.Format(this.conversationTokens.DraftTokens, this.currentCulture));
//
// The pictures of the whole conversation, not of the message being written: every one
@@ -789,16 +789,16 @@ public partial class ChatComponent : MSGComponentBase
private bool IsCurrentChatStreaming => this.ChatThread is not null && this.AIJobService.IsChatGenerationActive(this.ChatThread.ChatId);
private string ProviderPlaceholder => this.IsProviderSelected ? T("Type your input here...") : T("Select a provider first");
private string ProviderPlaceholder => this.IsProviderSelected ? TA("Type your input here...") : TA("Select a provider first");
private string InputLabel
{
get
{
if (this.IsProviderSelected)
return string.Format(T("Your Prompt (use selected instance '{0}', provider '{1}')"), this.Provider.InstanceName, this.Provider.UsedLLMProvider.Name);
return string.Format(TA("Your Prompt (use selected instance '{0}', provider '{1}')"), this.Provider.InstanceName, this.Provider.UsedLLMProvider.Name);
return this.T("Select a provider first");
return this.TA("Select a provider first");
}
}
@@ -833,7 +833,7 @@ public partial class ChatComponent : MSGComponentBase
// The chat template locks the profile for good, an answer being written only until it is complete:
private string ProfileDisabledText => this.currentChatTemplate.AllowProfileUsage
? T("Profile changes are locked while a response is running.")
: T("Profile usage is disabled according to your chat template settings.");
: TA("Profile usage is disabled according to your chat template settings.");
/// <summary>
/// Whether the open chat can move into a workspace, which is exactly when the workspace tree offers it.
@@ -1927,7 +1927,7 @@ public partial class ChatComponent : MSGComponentBase
{
var dialogParameters = new DialogParameters<ConfirmDialog>
{
{ x => x.Message, T("Are you sure you want to start a new chat? All unsaved changes will be lost.") },
{ x => x.Message, TA("Are you sure you want to start a new chat? All unsaved changes will be lost.") },
};
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>(T("Start New Chat"), dialogParameters, DialogOptions.FULLSCREEN);
@@ -2084,7 +2084,7 @@ public partial class ChatComponent : MSGComponentBase
var dialogParameters = new DialogParameters<WorkspaceSelectionDialog>
{
{ x => x.Message, T("Please select the workspace where you want to move the chat to.") },
{ x => x.Message, TA("Please select the workspace where you want to move the chat to.") },
{ x => x.SelectedWorkspace, this.ChatThread?.WorkspaceId ?? Guid.Empty },
{ x => x.ConfirmText, T("Move chat") },
};
@@ -16,7 +16,7 @@
}
</ActivatorContent>
<ChildContent>
<MudMenuItem Icon="@AppIcons.SETTINGS" Label="@T("Manage your templates")" OnClick="@(async () => await this.OpenSettingsDialog())" />
<MudMenuItem Icon="@AppIcons.SETTINGS" Label="@TA("Manage your templates")" OnClick="@(async () => await this.OpenSettingsDialog())" />
<MudDivider/>
<MudMenuItem Icon="@AppIcons.CREATE_CHAT_TEMPLATE" Label="@T("Create template from current chat")" OnClick="@(async () => await this.CreateNewChatTemplateFromChat())" Disabled="@(!this.CanChatThreadBeUsedForTemplate)"/>
<MudDivider/>
@@ -7,7 +7,7 @@
<MudField Label="@this.Label" Variant="@this.Variant" Underline="false" HelperText="@this.OptionHelp" Class="@this.Classes" InnerPadding="false">
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.FlexStart" Wrap="Wrap.NoWrap" StretchItems="this.StretchItems">
@* MudTooltip.RootStyle is set as a workaround for issue -> https://github.com/MudBlazor/MudBlazor/issues/10882 *@
<MudTooltip Text="@TB("This feature is managed by your organization and has therefore been disabled.")" Arrow="true" Placement="Placement.Right" RootStyle="display:inline-flex;">
<MudTooltip Text="@TA("This feature is managed by your organization and has therefore been disabled.")" Arrow="true" Placement="Placement.Right" RootStyle="display:inline-flex;">
<MudIcon Icon="@AppIcons.LOCK" Color="Color.Error" Size="Size.Small" Class="mr-1"/>
</MudTooltip>
@this.Body
@@ -83,7 +83,11 @@ public abstract partial class ConfigurationBase : MSGComponentBase
#endregion
private string TB(string fallbackEN) => this.T(fallbackEN, typeof(ConfigurationBase).Namespace, nameof(ConfigurationBase));
/// <summary>
/// Gets a text of this base class which addresses the reader; the collector files it under ConfigurationBase,
/// not under the component which derives from it.
/// </summary>
private new string TA(string fallbackEN) => this.TA(fallbackEN, typeof(ConfigurationBase).Namespace, nameof(ConfigurationBase));
protected async Task InformAboutChange() => await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
@@ -7,7 +7,7 @@
Text="@this.Text()"
TextChanged="@this.InternalUpdate"
Disabled="@this.IsDisabled"
Placeholder="@(this.IsDisabled ? string.Empty : T("You can also drag & drop the folder here."))"
Placeholder="@(this.IsDisabled ? string.Empty : TA("You can also drag & drop the folder here."))"
Adornment="Adornment.Start"
AdornmentIcon="@this.Icon"
AdornmentColor="@(isDropTarget ? Color.Primary : this.IconColor)"
@@ -7,7 +7,7 @@
Text="@this.Text()"
TextChanged="@this.InternalUpdate"
Disabled="@this.IsDisabled"
Placeholder="@(this.IsDisabled ? string.Empty : T("You can also drag & drop the file here."))"
Placeholder="@(this.IsDisabled ? string.Empty : TA("You can also drag & drop the file here."))"
Adornment="Adornment.Start"
AdornmentIcon="@this.Icon"
AdornmentColor="@(isDropTarget ? Color.Primary : this.IconColor)"
@@ -65,9 +65,9 @@ public partial class ConfigurationInterfaceSize : MSGComponentBase
private string SizeHelp => this.MeasuredScreen switch
{
null => T("AI Studio cannot measure this screen right now, so you cannot set the interface size here."),
{ } screen when this.OffersAppDefault => string.Format(I18N.I.Culture, T("Applies to this screen only ({0}). The app default shows AI Studio in the same size on every laptop. System scaling follows your operating system."), this.DescribeScreen(screen)),
{ } screen => string.Format(I18N.I.Culture, T("Applies to this screen only ({0}). System scaling follows your operating system."), this.DescribeScreen(screen)),
null => TA("AI Studio cannot measure this screen right now, so you cannot set the interface size here."),
{ } screen when this.OffersAppDefault => string.Format(I18N.I.Culture, TA("Applies to this screen only ({0}). The app default shows AI Studio in the same size on every laptop. System scaling follows your operating system."), this.DescribeScreen(screen)),
{ } screen => string.Format(I18N.I.Culture, TA("Applies to this screen only ({0}). System scaling follows your operating system."), this.DescribeScreen(screen)),
};
/// <summary>
@@ -85,8 +85,8 @@ public partial class ConfigurationInterfaceSize : MSGComponentBase
/// a comparison, since the slider starts there when the user comes from the default.
/// </summary>
private string ScaleHelp(InterfaceSizeResponse screen) => this.OffersAppDefault
? string.Format(I18N.I.Culture, T("You can choose from {0} % to {1} %. The app default on this screen is {2} %."), screen.MinPercent, screen.MaxPercent, screen.AppDefaultPercent)
: string.Format(I18N.I.Culture, T("You can choose from {0} % to {1} %. The system scaling on this screen is {2} %."), screen.MinPercent, screen.MaxPercent, screen.SystemPercent);
? string.Format(I18N.I.Culture, TA("You can choose from {0} % to {1} %. The app default on this screen is {2} %."), screen.MinPercent, screen.MaxPercent, screen.AppDefaultPercent)
: string.Format(I18N.I.Culture, TA("You can choose from {0} % to {1} %. The system scaling on this screen is {2} %."), screen.MinPercent, screen.MaxPercent, screen.SystemPercent);
private string DescribeScreen(InterfaceSizeResponse screen) => screen.ScreenDiagonalInches is { } diagonal
? string.Format(I18N.I.Culture, T("{0} × {1} pixels, {2:0.#} inches"), screen.ScreenWidth, screen.ScreenHeight, diagonal)
@@ -1,3 +1,3 @@
@using AIStudio.Settings
@inherits MSGComponentBase
<ConfigurationSelect IsLocked="this.IsLocked" Disabled="this.Disabled" OptionDescription="@T("Select a minimum confidence level")" SelectedValue="@this.FilteredSelectedValue" Data="@ConfigurationSelectDataFactory.GetConfidenceLevelsData(this.SettingsManager, this.RestrictToGlobalMinimumConfidence)" SelectionUpdate="@this.SelectionUpdate" SelectionUpdateAsync="@this.SelectionUpdateAsync" OptionHelp="@T("Choose the minimum confidence level that all LLM providers must meet. This way, you can ensure that only trustworthy providers are used. You cannot use any provider that falls below this level.")"/>
<ConfigurationSelect IsLocked="this.IsLocked" Disabled="this.Disabled" OptionDescription="@TA("Select a minimum confidence level")" SelectedValue="@this.FilteredSelectedValue" Data="@ConfigurationSelectDataFactory.GetConfidenceLevelsData(this.SettingsManager, this.RestrictToGlobalMinimumConfidence)" SelectionUpdate="@this.SelectionUpdate" SelectionUpdateAsync="@this.SelectionUpdateAsync" OptionHelp="@TA("Choose the minimum confidence level that all LLM providers must meet. This way, you can ensure that only trustworthy providers are used. You cannot use any provider that falls below this level.")"/>
@@ -80,9 +80,9 @@ public partial class ConfigurationMultiSelect<TData> : ConfigurationBaseCore
return this.EmptySelectionText ?? T("No items selected.");
if(selectedValues.Count == 1)
return this.SingleSelectionText ?? T("You have selected 1 item.");
return this.SingleSelectionText ?? TA("You have selected 1 item.");
return string.Format(this.MultipleSelectionText ?? T("You have selected {0} items."), selectedValues.Count);
return string.Format(this.MultipleSelectionText ?? TA("You have selected {0} items."), selectedValues.Count);
}
private bool IsLockedValue(TData value) => this.IsItemLocked(value);
@@ -7,7 +7,7 @@ namespace AIStudio.Components;
public partial class ConfigurationProviderSelection : MSGComponentBase
{
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(ConfigurationProviderSelection).Namespace, nameof(ConfigurationProviderSelection));
private new static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(ConfigurationProviderSelection).Namespace, nameof(ConfigurationProviderSelection));
[Parameter]
public Func<string> SelectedValue { get; set; } = () => string.Empty;
@@ -19,7 +19,7 @@ public partial class ConfigurationProviderSelection : MSGComponentBase
public IEnumerable<ConfigurationSelectData<string>> Data { get; set; } = new List<ConfigurationSelectData<string>>();
[Parameter]
public Func<string> HelpText { get; set; } = () => TB("Select a provider that is preselected.");
public Func<string> HelpText { get; set; } = () => TA("Select a provider that is preselected.");
[Parameter]
public Tools.Components Component { get; set; } = Tools.Components.NONE;
@@ -5,7 +5,7 @@
<MudTabPanel Text="@T("Back up")" Icon="@AppIcons.BACKUP" Disabled="@(this.isBusy || this.DataRestoreService.IsPreparing)">
<MudText Typo="Typo.body1" Class="mb-3">
@T("Back up all your data into one file: your settings, chats, plugins, and the indexes of your data sources. Your API keys and passwords stay out of it. AI Studio keeps them in the secure storage of your OS.")
@TA("Back up all your data into one file: your settings, chats, plugins, and the indexes of your data sources. Your API keys and passwords stay out of it. AI Studio keeps them in the secure storage of your OS.")
</MudText>
@if (this.DataBackupService.IsRunning)
@@ -20,7 +20,7 @@
</MudButton>
</MudStack>
<MudText Typo="Typo.caption">
@T("The backup goes on when you leave this page.")
@TA("The backup goes on when you leave this page.")
</MudText>
}
else
@@ -42,7 +42,7 @@
@if (!backupResult.IncludesDataSourceIndexes)
{
<MudText Typo="Typo.body2">
@T("The indexes of your data sources are not part of this backup, because they were not available. After a restore, AI Studio indexes your data sources anew.")
@TA("The indexes of your data sources are not part of this backup, because they were not available. After a restore, AI Studio indexes your data sources anew.")
</MudText>
}
</MudAlert>
@@ -66,13 +66,13 @@
<MudTabPanel Text="@T("Restore")" Icon="@AppIcons.RESTORE_BACKUP" Disabled="@(this.isBusy || this.DataBackupService.IsRunning)">
<MudText Typo="Typo.body1" Class="mb-3">
@T("Restore a backup: replace all your data with those of the backup, e.g., on a new computer, or add only its chats to the chats you have.")
@TA("Restore a backup: replace all your data with those of the backup, e.g., on a new computer, or add only its chats to the chats you have.")
</MudText>
@if (this.DataRestoreService.IsRestoreUnfinished)
{
<MudAlert Severity="Severity.Error" Dense="@true" Class="mb-3">
@T("AI Studio has not finished restoring an earlier backup yet. Please restart AI Studio first.")
@TA("AI Studio has not finished restoring an earlier backup yet. Please restart AI Studio first.")
</MudAlert>
}
@@ -120,7 +120,7 @@
@T("Replace all data")
</MudText>
<MudText Typo="Typo.body2" Class="mb-2">
@T("Replaces your settings, chats, plugins, and the indexes of your data sources with those of the backup. AI Studio restarts to do so. The plugins and settings of your organization stay as they are.")
@TA("Replaces your settings, chats, plugins, and the indexes of your data sources with those of the backup. AI Studio restarts to do so. The plugins and settings of your organization stay as they are.")
</MudText>
@if (this.DataRestoreService.IsPreparing)
@@ -145,7 +145,7 @@
@if (this.DataRestoreService.LastResult is { Success: false } restoreResult)
{
<MudAlert Severity="@(restoreResult.Cancelled ? Severity.Info : Severity.Error)" Dense="@true" Class="mt-3">
@(restoreResult.Cancelled ? T("The restore was stopped. All your data stay as they are.") : restoreResult.Issue)
@(restoreResult.Cancelled ? TA("The restore was stopped. All your data stay as they are.") : restoreResult.Issue)
</MudAlert>
}
@@ -153,7 +153,7 @@
@T("Add chats only")
</MudText>
<MudText Typo="Typo.body2" Class="mb-2">
@T("Adds the chats of the backup to the chats you have. Nothing else changes.")
@TA("Adds the chats of the backup to the chats you have. Nothing else changes.")
</MudText>
<MudSelect T="ChatArchiveCollisionBehavior" @bind-Value="@this.collisionBehavior" Label="@T("When a chat already exists")" Variant="Variant.Outlined" Margin="Margin.Dense" Disabled="@this.isBusy" Class="mb-3">
@@ -177,7 +177,7 @@
</MudButton>
</MudStack>
<MudText Typo="Typo.caption">
@T("Please stay on this page until this is done. Leaving the page stops adding the chats.")
@TA("Please stay on this page until this is done. Leaving the page stops adding the chats.")
</MudText>
}
else
@@ -98,7 +98,7 @@ public partial class DataBackupPanel : MSGComponentBase
private string BackupProgressText => this.DataBackupService.Progress switch
{
{ Phase: DataBackupPhase.COPYING_INDEXES } current => string.Format(T("Copying the indexes of your data sources: {0} of {1}"), current.Processed + 1, current.Total),
{ Phase: DataBackupPhase.COPYING_INDEXES } current => string.Format(TA("Copying the indexes of your data sources: {0} of {1}"), current.Processed + 1, current.Total),
{ Phase: DataBackupPhase.WRITING, Total: > 0 } current => string.Format(T("Writing file {0} of {1}"), current.Processed, current.Total),
_ => T("Preparing the backup"),
};
@@ -225,7 +225,7 @@ public partial class DataBackupPanel : MSGComponentBase
{
var dialogParameters = new DialogParameters<ConfirmDialog>
{
{ x => x.Message, T("Restoring this backup replaces your settings, your chats, your plugins, and the indexes of your data sources with those of the backup. Whatever you changed since the backup was made is lost. Afterward, AI Studio restarts. Do you want to restore this backup?") },
{ x => x.Message, TA("Restoring this backup replaces your settings, your chats, your plugins, and the indexes of your data sources with those of the backup. Whatever you changed since the backup was made is lost. Afterward, AI Studio restarts. Do you want to restore this backup?") },
};
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>(T("Replace All Data"), dialogParameters, DialogOptions.FULLSCREEN);
@@ -12,7 +12,7 @@
<MudText Typo="Typo.h4">
@T("Explanation")
</MudText>
<MudJustifiedMarkdown Value="@T("AI Studio keeps your data in two folders on this computer. When you back up your computer with a tool of your own, such as [Restic](https://restic.net), [Borg](https://www.borgbackup.org), or [Time Machine](https://support.apple.com/en-us/104984), this shows which of their contents belong into the backup and which it can leave out. Click a path to copy it to the clipboard, or use the folder button to open it in your file manager.")"/>
<MudJustifiedMarkdown Value="@TA("AI Studio keeps your data in two folders on this computer. When you back up your computer with a tool of your own, such as [Restic](https://restic.net), [Borg](https://www.borgbackup.org), or [Time Machine](https://support.apple.com/en-us/104984), this shows which of their contents belong in the backup and which it can leave out. Click a path to copy it to the clipboard, or use the folder button to open it in your file manager.")"/>
@foreach (var location in LOCATIONS)
{
@@ -26,7 +26,7 @@
<MudLink OnClick="@(() => this.CopyPath(folder))" Style="min-width: 0; overflow-wrap: anywhere;">
@folder
</MudLink>
<MudTooltip Text="@T("Open in your file manager")">
<MudTooltip Text="@TA("Open in your file manager")">
<MudIconButton Icon="@AppIcons.FOLDER_OPEN"
Size="Size.Medium"
Disabled="@string.IsNullOrWhiteSpace(folder)"
@@ -102,14 +102,14 @@
@T("Good to know")
</MudText>
<MudJustifiedText Class="mb-3" Typo="Typo.body1">
@T("Back up the indexes of your data sources only while AI Studio is closed. AI Studio writes to them while it runs, so a copy made meanwhile may not fit together, and AI Studio would have to embed your data sources anew.")
@TA("Back up the indexes of your data sources only while AI Studio is closed. AI Studio writes to them while it runs, so a copy made meanwhile may not fit together, and AI Studio would have to embed your data sources anew.")
</MudJustifiedText>
<MudJustifiedText Class="mb-3" Typo="Typo.body1">
@T("Your API keys, tokens, and passwords are not in these folders. AI Studio keeps them in the secure storage of your OS. After you restored your data on another computer, enter them there once more.")
@TA("Your API keys, tokens, and passwords are not in these folders. AI Studio keeps them in the secure storage of your OS. After you restored your data on another computer, enter them there once more.")
</MudJustifiedText>
@if (organizationPluginFolders.Count > 0)
{
<MudJustifiedText Class="mb-3" Typo="Typo.body1">
@T("Your organization deployed some plugins among your own ones, for example, with a device management. Their folders do not show this, so the list above names them one by one.")
@TA("Your organization deployed some plugins among your own ones, for example, with a device management. Their folders do not show this, so the list above names them one by one.")
</MudJustifiedText>
}
@@ -43,7 +43,7 @@ public partial class DataFolders : MSGComponentBase
{
var notice = T("The following is meant for experts who back up their computer with a tool of their own.");
return this.SettingsManager.ConfigurationData.App.AllowUserToBackUpData
? $"{notice} {T("To back up your data with AI Studio itself, or to move it to another computer, use Data Backup & Restore on this page or in the settings instead.")}"
? $"{notice} {TA("To back up your data with AI Studio itself, or to move it to another computer, use Data Backup & Restore on this page or in the settings instead.")}"
: notice;
}
}
@@ -75,25 +75,25 @@ public partial class DataFolders : MSGComponentBase
private string Describe(DataBackupEntryKind kind) => kind switch
{
DataBackupEntryKind.SETTINGS => T("Your settings."),
DataBackupEntryKind.WORKSPACES => T("Your chats in workspaces, along with their transcripts."),
DataBackupEntryKind.TEMPORARY_CHATS => T("Your temporary chats, along with their transcripts."),
DataBackupEntryKind.CHAT_PROVENANCE => T("What the AI received in your chats besides your messages, such as the content of attached files, the results of tools, and passages of your data sources. It is part of your chats."),
DataBackupEntryKind.PLUGINS => T("Your plugins, such as the assistants you built, apart from the folders listed below."),
DataBackupEntryKind.TOKENIZERS => T("The tokenizers you chose for your providers."),
DataBackupEntryKind.VISUAL_BRIEFINGS => T("Your projects in the Visual Briefing Assistant."),
DataBackupEntryKind.BEYOND_FACTS_LAB => T("Your preparations in the BeyondFacts Lab, with their material and conversations."),
DataBackupEntryKind.DATA_SOURCE_INDEX => T("The index of your local data sources: which files AI Studio embedded, and their text."),
DataBackupEntryKind.VECTOR_STORES => T("The embeddings of your local data sources."),
DataBackupEntryKind.MEDIA_TRANSCRIPTS => T("The transcripts of the audio and video files in your local data sources."),
DataBackupEntryKind.SETTINGS => TA("Your settings."),
DataBackupEntryKind.WORKSPACES => TA("Your chats in workspaces, along with their transcripts."),
DataBackupEntryKind.TEMPORARY_CHATS => TA("Your temporary chats, along with their transcripts."),
DataBackupEntryKind.CHAT_PROVENANCE => TA("What the AI received in your chats besides your messages, such as the content of attached files, the results of tools, and passages of your data sources. It is part of your chats."),
DataBackupEntryKind.PLUGINS => TA("Your plugins, such as the assistants you built, apart from the folders listed below."),
DataBackupEntryKind.TOKENIZERS => TA("The tokenizers you chose for your providers."),
DataBackupEntryKind.VISUAL_BRIEFINGS => TA("Your projects in the Visual Briefing Assistant."),
DataBackupEntryKind.BEYOND_FACTS_LAB => TA("Your preparations in the BeyondFacts Lab, with their material and conversations."),
DataBackupEntryKind.DATA_SOURCE_INDEX => TA("The index of your local data sources: which files AI Studio embedded, and their text."),
DataBackupEntryKind.VECTOR_STORES => TA("The embeddings of your local data sources."),
DataBackupEntryKind.MEDIA_TRANSCRIPTS => TA("The transcripts of the audio and video files in your local data sources."),
DataBackupEntryKind.SETTINGS_OF_OTHER_VERSIONS => T("Copies of your settings, which every version of AI Studio keeps for itself. Your current settings are all a backup needs."),
DataBackupEntryKind.SETTINGS_OF_OTHER_VERSIONS => TA("Copies of your settings, which every version of AI Studio keeps for itself. Your current settings are all a backup needs."),
DataBackupEntryKind.BUILT_IN_PLUGINS => T("Plugins which come with AI Studio, such as the language packs. AI Studio brings them back by itself."),
DataBackupEntryKind.ORGANIZATION_PLUGINS => T("Plugins of your organization. Your organization brings them back."),
DataBackupEntryKind.ORGANIZATION_PLUGINS => TA("Plugins of your organization. Your organization brings them back."),
DataBackupEntryKind.TEMPORARY_FILES => T("Files which AI Studio needs only for a moment and deletes again."),
DataBackupEntryKind.DOWNLOADED_TOOLS => T("Tools which AI Studio downloaded for this OS, such as Pandoc. On another computer, AI Studio downloads them again."),
DataBackupEntryKind.INTERFACE_KEYS => T("Keys with which AI Studio protects data in its user interface. Only the Flatpak keeps them here, and on another computer, AI Studio creates new ones."),
DataBackupEntryKind.LOGS => T("Log files. They help when something goes wrong, but they hold none of your data."),
DataBackupEntryKind.LOGS => TA("Log files. They help when something goes wrong, but they hold none of your data."),
_ => string.Empty,
};
@@ -37,7 +37,7 @@ public partial class DataSourceAddButtons : MSGComponentBase
/// The rule of the organization comes first: an embedding provider would not make the mailbox possible.
/// </remarks>
private string MailboxMenuText => !this.MayAddMailbox
? T("Mailbox (IMAP), not allowed by your organization")
? TA("Mailbox (IMAP), not allowed by your organization")
: this.HasEmbeddingProvider
? T("Mailbox (IMAP)")
: T("Mailbox (IMAP), requires an embedding provider");
@@ -41,15 +41,15 @@ public partial class DataSourceCloudEmbeddingWarning : MSGComponentBase
private bool SendsMediaToCloudTranscription => !string.IsNullOrWhiteSpace(this.CloudTranscriptionProvider);
private string LabelOn => this.SendsMediaToCloudTranscription
? T("Yes, please send my data to the external providers")
: T("Yes, please send my data to the external embedding provider");
? TA("Yes, please send my data to the external providers")
: TA("Yes, please send my data to the external embedding provider");
private string LabelOff => this.SendsMediaToCloudTranscription
? T("No, I will choose other providers or files")
: T("No, I will choose another embedding");
private string TranscriptionWarningText => string.Format(
T("Warning: Your transcription provider '{0}' is not self-hosted. Audio and video files this data source selects are sent to it to be transcribed, which can cost money. AI Studio keeps every transcript, so an unchanged recording is sent only once. MindWork AI Studio has no control over what that third party does with the recordings after they are sent."),
TA("Warning: Your transcription provider '{0}' is not self-hosted. Audio and video files this data source selects are sent to it to be transcribed, which can cost money. AI Studio keeps every transcript, so an unchanged recording is sent only once. MindWork AI Studio has no control over what that third party does with the recordings after they are sent."),
this.CloudTranscriptionProvider);
private string WarningText
@@ -5,11 +5,11 @@
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
@if (this.AreMailboxesEnabled)
{
@T("You might configure different data sources. A data source can include one file, all files in a directory, a mailbox, or data from your company. Later, you can incorporate these data sources as needed when the AI requires this data to complete a certain task.")
@TA("You might configure different data sources. A data source can include one file, all files in a directory, a mailbox, or data from your company. Later, you can incorporate these data sources as needed when the AI requires this data to complete a certain task.")
}
else
{
@T("You might configure different data sources. A data source can include one file, all files in a directory, or data from your company. Later, you can incorporate these data sources as needed when the AI requires this data to complete a certain task.")
@TA("You might configure different data sources. A data source can include one file, all files in a directory, or data from your company. Later, you can incorporate these data sources as needed when the AI requires this data to complete a certain task.")
}
</MudJustifiedText>
@@ -23,7 +23,7 @@
</MudStack>
<MudPaper Class="pa-3 mb-3 border-dashed border rounded-lg">
<ConfigurationSlider T="int" OptionDescription="@T("Shortest pause between indexing steps")" Min="0" Max="@this.MinimumPauseSliderMax" Step="1" Unit="@T("seconds")" Value="@(() => this.SettingsManager.ConfigurationData.App.DataSourceIndexing.MinimumPauseBetweenStepsSeconds)" ValueUpdate="@(value => this.SettingsManager.ConfigurationData.App.DataSourceIndexing.MinimumPauseBetweenStepsSeconds = value)" OptionHelp="@T("AI Studio indexes large data sources in steps of a few minutes. Between two steps, it waits for a random time between the shortest and the longest pause. This spares an embedding server which many people share, for example in your organization. Leave both at 0 seconds for no pause.")" IsLocked="@(() => IsMinimumPauseLocked)"/>
<ConfigurationSlider T="int" OptionDescription="@T("Shortest pause between indexing steps")" Min="0" Max="@this.MinimumPauseSliderMax" Step="1" Unit="@T("seconds")" Value="@(() => this.SettingsManager.ConfigurationData.App.DataSourceIndexing.MinimumPauseBetweenStepsSeconds)" ValueUpdate="@(value => this.SettingsManager.ConfigurationData.App.DataSourceIndexing.MinimumPauseBetweenStepsSeconds = value)" OptionHelp="@TA("AI Studio indexes large data sources in steps of a few minutes. Between two steps, it waits for a random time between the shortest and the longest pause. This spares an embedding server which many people share, for example in your organization. Leave both at 0 seconds for no pause.")" IsLocked="@(() => IsMinimumPauseLocked)"/>
<ConfigurationSlider T="int" OptionDescription="@T("Longest pause between indexing steps")" Min="@this.MaximumPauseSliderMin" Max="@DataDataSourceIndexing.MAX_PAUSE_BETWEEN_STEPS_SECONDS" Step="1" Unit="@T("seconds")" Value="@(() => this.SettingsManager.ConfigurationData.App.DataSourceIndexing.MaximumPauseBetweenStepsSeconds)" ValueUpdate="@(value => this.SettingsManager.ConfigurationData.App.DataSourceIndexing.MaximumPauseBetweenStepsSeconds = value)" OptionHelp="@T("The upper end of the random pause between two indexing steps. AI Studio allows up to 300 seconds (5 minutes).")" IsLocked="@(() => IsMaximumPauseLocked)"/>
</MudPaper>
@@ -99,7 +99,7 @@
}
@if (context.IsEnterpriseConfiguration)
{
<MudTooltip Text="@T("This data source is managed by your organization.")">
<MudTooltip Text="@TA("This data source is managed by your organization.")">
<MudIconButton Color="Color.Info" Icon="@AppIcons.ORGANIZATION" Disabled="true"/>
</MudTooltip>
}
@@ -124,7 +124,7 @@ public partial class DataSourceManagement : MSGComponentBase
if (status.SkippedDocuments == 0 || status.DataSourceType is DataSourceType.MAILBOX)
return status.StateLabel;
return $"{status.StateLabel} — {string.Format(T("Skipped files: {0}. Open Background embeddings to see why and what you can do."), status.SkippedDocuments)}";
return $"{status.StateLabel} — {string.Format(TA("Skipped files: {0}. Open Background embeddings to see why and what you can do."), status.SkippedDocuments)}";
}
private string GetEmbeddingName(IDataSourceBase dataSource)
@@ -208,7 +208,7 @@ public partial class DataSourceManagement : MSGComponentBase
{
await this.DialogService.ShowMessageBoxAsync(
T("Export ERI Data Source"),
T("Kerberos/SSO ERI data sources cannot be exported yet. Please configure them manually in the configuration plugin."),
TA("Kerberos/SSO ERI data sources cannot be exported yet. Please configure them manually in the configuration plugin."),
T("Close"));
return;
}
@@ -248,7 +248,7 @@ public partial class DataSourceManagement : MSGComponentBase
{
var dialogParameters = new DialogParameters<ConfirmDialog>
{
{ x => x.Message, T("This ERI data source has an access token configured. Do you want to include the encrypted access token in the export? Note: The recipient will need the same encryption secret to use the access token.") },
{ x => x.Message, TA("This ERI data source has an access token configured. Do you want to include the encrypted access token in the export? Note: The recipient will need the same encryption secret to use the access token.") },
};
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>(T("Export Access Token?"), dialogParameters, DialogOptions.FULLSCREEN);
@@ -306,7 +306,7 @@ public partial class DataSourceManagement : MSGComponentBase
var dialogParameters = new DialogParameters<ConfirmDialog>
{
{ x => x.Message, string.Format(T("Are you sure you want to delete the data source '{0}' of type '{1}'?"), dataSource.Name, dataSource.Type.DisplayName) },
{ x => x.Message, string.Format(TA("Are you sure you want to delete the data source '{0}' of type '{1}'?"), dataSource.Name, dataSource.Type.DisplayName) },
};
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>(T("Delete Data Source"), dialogParameters, DialogOptions.FULLSCREEN);
@@ -353,7 +353,7 @@ public partial class DataSourceManagement : MSGComponentBase
if (!this.DataSourceEmbeddingService.IsIndexingPaused)
return false;
await this.DialogService.ShowMessageBoxAsync(title, T("AI Studio is backing up or restoring the indexes of your data sources right now. Please try again once that is done."), T("Close"));
await this.DialogService.ShowMessageBoxAsync(title, TA("AI Studio is backing up or restoring the indexes of your data sources right now. Please try again once that is done."), T("Close"));
return true;
}
@@ -402,7 +402,7 @@ public partial class DataSourceManagement : MSGComponentBase
var dialogParameters = new DialogParameters<ConfirmDialog>
{
{ x => x.Message, string.Format(T("Are you sure you want to delete the mailbox '{0}'? Your mails stay on the server as they are. AI Studio only deletes its index of them and the stored password."), mailbox.Name) },
{ x => x.Message, string.Format(TA("Are you sure you want to delete the mailbox '{0}'? Your mails stay on the server as they are. AI Studio only deletes its index of them and the stored password."), mailbox.Name) },
};
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>(T("Delete Mailbox"), dialogParameters, DialogOptions.FULLSCREEN);
@@ -51,14 +51,14 @@ public partial class DataSourceMissingEmbeddingWarning : MSGComponentBase
{
var problem = this.IsInDataSourceDialog
? T("No embedding provider is configured yet, but this data source needs one.")
: T("No embedding provider is configured yet. Local data sources, such as your files and folders, need one: it prepares your data so that the AI can search it.");
: TA("No embedding provider is configured yet. Local data sources, such as your files and folders, need one: it prepares your data so that the AI can search it.");
if (!this.MayAdd)
return $"{problem} {T("Your organization manages the embedding providers and has not provided one yet. Please ask your IT department.")}";
return $"{problem} {TA("Your organization manages the embedding providers and has not provided one yet. Please ask your IT department.")}";
// Above the table, the buttons speak for themselves. In a dialog, the worry is about what was entered so far:
return this.IsInDataSourceDialog
? $"{problem} {T("You can add one right here; everything you entered in this dialog stays as it is.")}"
? $"{problem} {TA("You can add one right here; everything you entered in this dialog stays as it is.")}"
: problem;
}
}
@@ -4,7 +4,7 @@
@if (this.SelectionMode is DataSourceSelectionMode.SELECTION_MODE)
{
<div class="d-flex">
<MudTooltip Text="@T("Select the data you want to use here.")" Placement="Placement.Top">
<MudTooltip Text="@TA("Select the data you want to use here.")" Placement="Placement.Top">
<MudIconButton Icon="@AppIcons.DATA_SOURCE" Class="@this.PopoverButtonClasses" OnClick="@this.ToggleDataSourceSelection"/>
</MudTooltip>
@@ -18,7 +18,7 @@
</MudText>
<PreviewBeta ChipClass=""/>
<MudSpacer/>
<MudTooltip Text="@T("Manage your data sources")" Placement="Placement.Top">
<MudTooltip Text="@TA("Manage your data sources")" Placement="Placement.Top">
<MudIconButton Icon="@AppIcons.SETTINGS" OnClick="@this.OpenSettingsDialog"/>
</MudTooltip>
</MudStack>
@@ -34,7 +34,7 @@
else if (this.SettingsManager.ConfigurationData.DataSources.Count == 0)
{
<MudJustifiedText Typo="Typo.body2" Class="mb-2">
@T("You haven't configured any data sources. To grant the AI access to your data, you need to add such a source. However, if you wish to use data from your device, you first have to set up a so-called embedding. This embedding is necessary so the AI can effectively search your data, find and retrieve the correct information required for each task. In addition to local data, you can also incorporate your company's data. To do so, your company must provide the data through an ERI (External Retrieval Interface).")
@TA("You haven't configured any data sources. To grant the AI access to your data, you need to add such a source. However, if you wish to use data from your device, you first have to set up a so-called embedding. This embedding is necessary so the AI can effectively search your data, find and retrieve the correct information required for each task. In addition to local data, you can also incorporate your company's data. To do so, your company must provide the data through an ERI (External Retrieval Interface).")
</MudJustifiedText>
<MudStack StretchItems="StretchItems.None" AlignItems="AlignItems.Start">
@@ -67,7 +67,7 @@
}
else
{
<MudTextSwitch Label="@T("Semantic Search")" Value="@this.IsSemanticSearchPreferred" LabelOn="@T("Yes, the AI searches your data sources itself, whenever a question calls for it (Semantic Search).")" LabelOff="@T("No, AI Studio searches your data sources with every message, before the AI answers (classic RAG).")" ValueChanged="@this.SemanticSearchChanged" Dense="@true" Disabled="@this.ReadOnly"/>
<MudTextSwitch Label="@T("Semantic Search")" Value="@this.IsSemanticSearchPreferred" LabelOn="@TA("Yes, the AI searches your data sources itself, whenever a question calls for it (Semantic Search).")" LabelOff="@TA("No, AI Studio searches your data sources with every message, before the AI answers (classic RAG).")" ValueChanged="@this.SemanticSearchChanged" Dense="@true" Disabled="@this.ReadOnly"/>
}
<MudTextSwitch Label="@T("AI-based data source selection")" Value="@this.aiBasedSourceSelection" LabelOn="@T("Yes, let the AI decide which data sources are needed.")" LabelOff="@T("No, I manually decide which data source to use.")" ValueChanged="@this.AutoModeChanged" Dense="@true" Disabled="@this.ReadOnly"/>
@@ -82,13 +82,13 @@
{
case true when this.GetListedDataSources().Count == 0:
<MudText Typo="Typo.body2" Class="mb-2">
@T("Your data sources cannot be used with the selected providers due to data privacy or confidence-level requirements, or they are currently unavailable.")
@TA("Your data sources cannot be used with the selected providers due to data privacy or confidence-level requirements, or they are currently unavailable.")
</MudText>
break;
case false when this.GetListedDataSources().Count == 0:
<MudText Typo="Typo.body2" Class="mb-2">
@T("Your data sources cannot be used with the selected providers due to data privacy or confidence-level requirements, or they are currently unavailable.")
@TA("Your data sources cannot be used with the selected providers due to data privacy or confidence-level requirements, or they are currently unavailable.")
</MudText>
break;
@@ -113,7 +113,7 @@
else if (this.DataSourcesAISelected.Count == 0)
{
<MudText Typo="Typo.body2" Class="mb-2">
@T("The AI evaluates each of your inputs to determine whether and which data sources are necessary. Currently, the AI has not selected any source.")
@TA("The AI evaluates each of your inputs to determine whether and which data sources are necessary. Currently, the AI has not selected any source.")
</MudText>
}
@@ -208,12 +208,12 @@ else if (this.SelectionMode is DataSourceSelectionMode.CONFIGURATION_MODE)
<MudTextSwitch Label="@T("Are data sources enabled?")" Value="@this.areDataSourcesEnabled" LabelOn="@T("Yes, I want to use data sources.")" LabelOff="@T("No, I don't want to use data sources.")" ValueChanged="@this.EnabledChanged" Disabled="@(this.ReadOnly || this.IsPreselectedDataSourcesDisabledLocked())"/>
@if (this.areDataSourcesEnabled)
{
<MudTextSwitch Label="@T("Semantic Search")" Value="@this.IsSemanticSearchPreferred" LabelOn="@T("Yes, the AI searches your data sources itself, whenever a question calls for it (Semantic Search).")" LabelOff="@T("No, AI Studio searches your data sources with every message, before the AI answers (classic RAG).")" ValueChanged="@this.SemanticSearchChanged" Disabled="@(this.ReadOnly || this.IsPreselectedDataSourcesRetrievalModeLocked())"/>
<MudTextSwitch Label="@T("Semantic Search")" Value="@this.IsSemanticSearchPreferred" LabelOn="@TA("Yes, the AI searches your data sources itself, whenever a question calls for it (Semantic Search).")" LabelOff="@TA("No, AI Studio searches your data sources with every message, before the AI answers (classic RAG).")" ValueChanged="@this.SemanticSearchChanged" Disabled="@(this.ReadOnly || this.IsPreselectedDataSourcesRetrievalModeLocked())"/>
@* No provider is known here, so this says in general what the chat itself tells about its model: *@
@if (this.IsSemanticSearchPreferred)
{
<MudJustifiedText Typo="Typo.body2" Class="mb-3">
@T("When the model of a chat cannot use tools, AI Studio uses classic RAG instead and searches your data sources with every message.")
@TA("When the model of a chat cannot use tools, AI Studio uses classic RAG instead and searches your data sources with every message.")
</MudJustifiedText>
}
@@ -222,7 +222,7 @@ else if (this.SelectionMode is DataSourceSelectionMode.CONFIGURATION_MODE)
@* Semantic Search may fall back to searching with every message, so the validation is kept, marked as belonging to that way only: *@
<MudPaper Class="pa-3 mb-3 border-dashed border rounded-lg">
<MudJustifiedText Typo="Typo.body2" Class="mb-2">
@T("Only used with classic RAG, which searches your data sources with every message:")
@TA("Only used with classic RAG, which searches your data sources with every message:")
</MudJustifiedText>
<MudTextSwitch Label="@T("AI-based data validation")" Value="@this.aiBasedValidation" LabelOn="@T("Yes, let the AI validate & filter the retrieved data.")" LabelOff="@T("No, use all data retrieved from the data sources.")" ValueChanged="@this.ValidationModeChanged" Disabled="@(this.ReadOnly || this.IsPreselectedDataSourcesAutomaticValidationLocked())"/>
</MudPaper>
@@ -391,12 +391,12 @@ public partial class DataSourceSelection : MSGComponentBase
private string GetSemanticSearchUnavailableMessage() => this.effectiveRetrievalMode.SemanticSearchBlockReason switch
{
ToolOfferBlockReason.TOOLS_SWITCHED_OFF => T("Your organization has switched tools off, so AI Studio uses classic RAG instead and searches your data sources with every message."),
ToolOfferBlockReason.MODEL_CANNOT_USE_TOOLS => T("The selected model cannot use tools, so AI Studio uses classic RAG instead and searches your data sources with every message."),
ToolOfferBlockReason.TOOL_SWITCHED_OFF => T("Your organization has switched Semantic Search off, so AI Studio uses classic RAG instead and searches your data sources with every message."),
ToolOfferBlockReason.TOOL_SWITCHED_OFF_BY_USER => T("You switched Semantic Search off in the tool settings, so AI Studio uses classic RAG instead and searches your data sources with every message."),
ToolOfferBlockReason.PROVIDER_CONFIDENCE_TOO_LOW => T("The selected provider is not trusted enough for Semantic Search, so AI Studio uses classic RAG instead and searches your data sources with every message."),
_ => T("Semantic Search cannot be used here, so AI Studio uses classic RAG instead and searches your data sources with every message."),
ToolOfferBlockReason.TOOLS_SWITCHED_OFF => TA("Your organization has switched tools off, so AI Studio uses classic RAG instead and searches your data sources with every message."),
ToolOfferBlockReason.MODEL_CANNOT_USE_TOOLS => TA("The selected model cannot use tools, so AI Studio uses classic RAG instead and searches your data sources with every message."),
ToolOfferBlockReason.TOOL_SWITCHED_OFF => TA("Your organization has switched Semantic Search off, so AI Studio uses classic RAG instead and searches your data sources with every message."),
ToolOfferBlockReason.TOOL_SWITCHED_OFF_BY_USER => TA("You switched Semantic Search off in the tool settings, so AI Studio uses classic RAG instead and searches your data sources with every message."),
ToolOfferBlockReason.PROVIDER_CONFIDENCE_TOO_LOW => TA("The selected provider is not trusted enough for Semantic Search, so AI Studio uses classic RAG instead and searches your data sources with every message."),
_ => TA("Semantic Search cannot be used here, so AI Studio uses classic RAG instead and searches your data sources with every message."),
};
private async Task ValidationModeChanged(bool state)
@@ -40,7 +40,7 @@ public partial class DataSourceSelectionRow : MSGComponentBase
private string GetBlockedTooltip() => this.BlockReason switch
{
DataSourceBlockReason.AWAITING_REINDEX => T("This data source is waiting to be indexed again. Until that is finished, it cannot be searched."),
DataSourceBlockReason.NEEDS_REPAIR => T("The index of this data source cannot be read anymore. Open your data source settings with the gear icon above, then use the repair action there."),
DataSourceBlockReason.NEEDS_REPAIR => TA("The index of this data source cannot be read anymore. Open your data source settings with the gear icon above, then use the repair action there."),
_ => string.Empty,
};
@@ -1,13 +1,13 @@
@using AIStudio.Settings.DataModel
@inherits MSGComponentBase
<WorkspaceNameField WorkspaceName="@this.WorkspaceName" WorkspaceNameChanged="@this.SetWorkspaceName" SelectLabel="@T("Existing workspace (Optional)")" Label="@T("Workspace name (Optional)")" HelperText="@T("Choose an existing workspace or enter a name that should be created when the launcher is opened.")" AdornmentIcon="@(this.OpensTemporaryChat ? AppIcons.TEMPORARY_CHAT : AppIcons.NEW_FOLDER)" AdornmentIconSize="Size.Small" TextFieldClass="mb-1"/>
<WorkspaceNameField WorkspaceName="@this.WorkspaceName" WorkspaceNameChanged="@this.SetWorkspaceName" SelectLabel="@T("Existing workspace (Optional)")" Label="@T("Workspace name (Optional)")" HelperText="@TA("Choose an existing workspace or enter a name that should be created when the launcher is opened.")" AdornmentIcon="@(this.OpensTemporaryChat ? AppIcons.TEMPORARY_CHAT : AppIcons.NEW_FOLDER)" AdornmentIconSize="Size.Small" TextFieldClass="mb-1"/>
@* The tile behaves differently with and without a workspace, so the form says which of the two is
chosen right now instead of only explaining that both are possible. *@
<MudText Typo="Typo.body2" Class="mud-text-secondary mb-3">
@(this.OpensTemporaryChat
? T("Without a workspace, the tile opens a disappearing chat: it belongs to no workspace and is deleted according to your workspace maintenance settings.")
? TA("Without a workspace, the tile opens a disappearing chat: it belongs to no workspace and is deleted according to your workspace maintenance settings.")
: T("The tile opens its chat in this workspace and creates the workspace when it does not exist yet."))
</MudText>
@if (this.OpensTemporaryChat && this.SettingsManager.GetChatTemplateWorkspaceName(this.SelectedChatTemplate) is { } templateWorkspaceName)
@@ -17,7 +17,7 @@
@if (this.ShowOpen)
{
<MudTooltip Text="@T("Open this web page in your browser")" Placement="@this.TooltipPlacement" ShowOnFocus="@false">
<MudTooltip Text="@TA("Open this web page in your browser")" Placement="@this.TooltipPlacement" ShowOnFocus="@false">
<MudIconButton Icon="@AppIcons.OPEN_EXTERNAL" Size="Size.Small" Class="icon-button-compact" Href="@this.Path" Target="_blank"/>
</MudTooltip>
}
@@ -46,7 +46,7 @@
{
@if (this.ShowFileManager)
{
<MudTooltip Text="@T("Show this file in the file manager of your system")" Placement="@this.TooltipPlacement" ShowOnFocus="@false">
<MudTooltip Text="@TA("Show this file in the file manager of your system")" Placement="@this.TooltipPlacement" ShowOnFocus="@false">
<MudIconButton Icon="@AppIcons.FOLDER_OPEN" Size="Size.Small" Class="icon-button-compact" OnClick="@this.ShowInFileManager"/>
</MudTooltip>
}
@@ -29,6 +29,8 @@ public partial class FileActions : MSGComponentBase
{
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(FileActions).Namespace, nameof(FileActions));
private new static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(FileActions).Namespace, nameof(FileActions));
/// <summary>
/// What a path names.
/// </summary>
@@ -99,7 +101,7 @@ public partial class FileActions : MSGComponentBase
/// <returns>The tooltip.</returns>
internal static string GetOpenTooltip(int? pageNumber) => pageNumber is { } page
? string.Format(TB("Open the file at page {0}"), page)
: TB("Open the file in the program your system uses for it");
: TA("Open the file in the program your system uses for it");
#region Overrides of ComponentBase
@@ -16,7 +16,7 @@
<MudTextField T="string" InputId="@this.fileInputId" Text="@this.state.FileText" TextChanged="@this.ChangeFilesAsync" Immediate="@true" Disabled="@this.Disabled" Label="@T("Files")" Lines="1" Sizing="InputSizing.Auto" MaxLines="@FilePatternSelection.MAX_FIELD_LINES" Class="pattern-text-field" Variant="Variant.Outlined" Margin="Margin.Dense" Validation="@FileExclusions.ValidateFiles" UserAttributes="@INPUT_ATTRIBUTES" Placeholder="*.min.js;*.webm;draft-*" Adornment="@(this.ShowReset ? Adornment.End : Adornment.None)" AdornmentIcon="@AppIcons.RESTORE_DEFAULT" OnAdornmentClick="@(() => this.RestoreDefaultsAsync(false))" AdornmentAriaLabel="@this.FileRestoreLabel"/>
</MudStack>
<MudText Typo="Typo.caption" Class="mud-text-secondary mt-1">@T("These files and folders are left out, even when a file pattern selects them. Separate entries with a semicolon or a line break. End an entry with a slash to exclude every folder of that name, e.g., node_modules/.")</MudText>
<MudText Typo="Typo.caption" Class="mud-text-secondary mt-1">@TA("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/.")</MudText>
<MudCollapse Expanded="@(this.ShowHelp && this.showHelp)">
<div class="mt-2">
<FilePatternHelp ShowInclusionExamples="@false" ShowExclusionExamples="@true"/>
@@ -2,7 +2,7 @@
<MudPaper Outlined="@true" Class="pa-3" Elevation="0">
<MudText Typo="Typo.subtitle2">@T("Pattern examples")</MudText>
<MudText Typo="Typo.body2" Class="mud-text-secondary mb-2">@T("Separate patterns with semicolons. Exclusions take priority over included files.")</MudText>
<MudText Typo="Typo.body2" Class="mud-text-secondary mb-2">@TA("Separate patterns with semicolons. Exclusions take priority over included files.")</MudText>
<MudSimpleTable Dense="@true" Elevation="0" aria-label="@T("Pattern examples")">
<tbody>
<tr><td><code>*.pdf;*.docx</code></td><td>@T("PDF and Word files")</td></tr>
@@ -5,10 +5,10 @@ namespace AIStudio.Components;
public partial class HalluzinationReminder: ComponentBase
{
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(HalluzinationReminder).Namespace, nameof(HalluzinationReminder));
private static string TA(string fallbackEN) => I18N.I.TA(fallbackEN, typeof(HalluzinationReminder).Namespace, nameof(HalluzinationReminder));
[Parameter]
public string Text { get; set; } = TB("LLMs can make mistakes. Check important information.");
public string Text { get; set; } = TA("LLMs can make mistakes. Check important information.");
[Parameter]
public string ContainerClass { get; set; } = "mt-2 mb-1";
@@ -52,6 +52,20 @@ public abstract class MSGComponentBase : ComponentBase, IDisposable, IAsyncDispo
/// <returns>The text from the language plugin or the English text.</returns>
public string TA(string fallbackEN) => this.GetText(this.Lang, fallbackEN, addressForm: I18N.I.AddressForm);
/// <summary>
/// Gets a text which addresses the reader, in the form of address the person chose, under the key of the given
/// type; see I18N.AddressForm.
/// </summary>
/// <remarks>
/// A base class, such as AssistantBase, needs this for its own texts: the collector files them under the base
/// class, while the component at runtime is a derived one.
/// </remarks>
/// <param name="fallbackEN">The text in English (US).</param>
/// <param name="typeNamespace">The namespace of the type requesting the text, used as part of the key.</param>
/// <param name="typeName">The name of the type requesting the text, used as part of the key.</param>
/// <returns>The text from the language plugin or the English text.</returns>
public string TA(string fallbackEN, string? typeNamespace, string? typeName) => this.GetText(this.Lang, fallbackEN, typeNamespace, typeName, I18N.I.AddressForm);
#region Implementation of IMessageBusReceiver
public async Task ProcessMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data)
@@ -61,9 +75,10 @@ public abstract class MSGComponentBase : ComponentBase, IDisposable, IAsyncDispo
switch (triggeredEvent)
{
case Event.COLOR_THEME_CHANGED:
case Event.ADDRESS_FORM_CHANGED:
this.StateHasChanged();
break;
case Event.PLUGINS_RELOADED:
this.Lang = await this.SettingsManager.GetActiveLanguagePlugin();
await this.InvokeAsync(this.StateHasChanged);
@@ -112,10 +127,11 @@ public abstract class MSGComponentBase : ComponentBase, IDisposable, IAsyncDispo
/// <param name="events">A list of events for which you want to receive messages.</param>
protected void ApplyFilters(ComponentBase[] filterComponents, Event[] events)
{
// Append the color theme changed event to the list of events:
// Append the events which every component handles to the list of events:
var eventsList = new List<Event>(events)
{
Event.COLOR_THEME_CHANGED,
Event.ADDRESS_FORM_CHANGED,
Event.PLUGINS_RELOADED,
};
@@ -49,8 +49,8 @@ public partial class ManagePandocDependency : MSGComponentBase
private string ButtonText => this.IsOutdated ? T("Update Pandoc") : T("Install Pandoc");
private string PromptText => this.IsOutdated
? $"{this.IntroText} {T("Your Pandoc installation is outdated. Please update it to the latest version to ensure compatibility with all features.")}"
: $"{this.IntroText} {T("Pandoc is not installed or not available. Please install it to use the features that require Pandoc.")}";
? $"{this.IntroText} {TA("Your Pandoc installation is outdated. Please update it to the latest version to ensure compatibility with all features.")}"
: $"{this.IntroText} {TA("Pandoc is not installed or not available. Please install it to use the features that require Pandoc.")}";
private async Task ShowPandocDialogAsync()
{
Loaded 100 of 342 files, more files were not shown because too many files have changed in this diff. Show more