Moved all extension methods into extension blocks (#1155)

This commit is contained in:
Thorsten Sommer authored and GitHub committed 2026-11-04 10:46:18 +01:00
1 parent acc7d09fa2
commit c0a75f39ac
138 files changed
+5884 -4954

No files matched your search

@@ -4,23 +4,26 @@ public static class NumberParticipantsExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(NumberParticipantsExtensions).Namespace, nameof(NumberParticipantsExtensions));
public static string Name(this NumberParticipants numberParticipants) => numberParticipants switch
extension(NumberParticipants numberParticipants)
{
NumberParticipants.NOT_SPECIFIED => TB("Please select how many participants are expected"),
public string Name() => numberParticipants switch
{
NumberParticipants.NOT_SPECIFIED => TB("Please select how many participants are expected"),
NumberParticipants.PEER_TO_PEER => TB("2 (peer to peer)"),
NumberParticipants.PEER_TO_PEER => TB("2 (peer to peer)"),
NumberParticipants.SMALL_GROUP => TB("3 - 5 (small group)"),
NumberParticipants.LARGE_GROUP => TB("6 - 12 (large group)"),
NumberParticipants.MULTIPLE_SMALL_GROUPS => TB("13 - 20 (multiple small groups)"),
NumberParticipants.MULTIPLE_LARGE_GROUPS => TB("21 - 30 (multiple large groups)"),
NumberParticipants.SMALL_GROUP => TB("3 - 5 (small group)"),
NumberParticipants.LARGE_GROUP => TB("6 - 12 (large group)"),
NumberParticipants.MULTIPLE_SMALL_GROUPS => TB("13 - 20 (multiple small groups)"),
NumberParticipants.MULTIPLE_LARGE_GROUPS => TB("21 - 30 (multiple large groups)"),
NumberParticipants.SYMPOSIUM => TB("31 - 100 (symposium)"),
NumberParticipants.CONFERENCE => TB("101 - 200 (conference)"),
NumberParticipants.CONGRESS => TB("201 - 1,000 (congress)"),
NumberParticipants.SYMPOSIUM => TB("31 - 100 (symposium)"),
NumberParticipants.CONFERENCE => TB("101 - 200 (conference)"),
NumberParticipants.CONGRESS => TB("201 - 1,000 (congress)"),
NumberParticipants.LARGE_EVENT => TB("1,000+ (large event)"),
NumberParticipants.LARGE_EVENT => TB("1,000+ (large event)"),
_ => "Unknown"
};
_ => "Unknown"
};
}
}
@@ -6,27 +6,30 @@ public static class BatchProcessingCsvSeparatorExtensions
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(BatchProcessingCsvSeparatorExtensions).Namespace, nameof(BatchProcessingCsvSeparatorExtensions));
public static string Name(this BatchProcessingCsvSeparator separator) => separator switch
extension(BatchProcessingCsvSeparator separator)
{
BatchProcessingCsvSeparator.COMMA => TB("Comma (,)"),
BatchProcessingCsvSeparator.SEMICOLON => TB("Semicolon (;)"),
BatchProcessingCsvSeparator.PIPE => TB("Vertical bar (|)"),
BatchProcessingCsvSeparator.TAB => TB("Tab"),
BatchProcessingCsvSeparator.CUSTOM => TB("Custom character"),
public string Name() => separator switch
{
BatchProcessingCsvSeparator.COMMA => TB("Comma (,)"),
BatchProcessingCsvSeparator.SEMICOLON => TB("Semicolon (;)"),
BatchProcessingCsvSeparator.PIPE => TB("Vertical bar (|)"),
BatchProcessingCsvSeparator.TAB => TB("Tab"),
BatchProcessingCsvSeparator.CUSTOM => TB("Custom character"),
_ => TB("Unknown"),
};
_ => TB("Unknown"),
};
public static char Character(this BatchProcessingCsvSeparator separator, string customSeparator) => separator switch
{
BatchProcessingCsvSeparator.COMMA => ',',
BatchProcessingCsvSeparator.SEMICOLON => ';',
BatchProcessingCsvSeparator.PIPE => '|',
BatchProcessingCsvSeparator.TAB => '\t',
BatchProcessingCsvSeparator.CUSTOM when IsValidCustomSeparator(customSeparator) => customSeparator[0],
public char Character(string customSeparator) => separator switch
{
BatchProcessingCsvSeparator.COMMA => ',',
BatchProcessingCsvSeparator.SEMICOLON => ';',
BatchProcessingCsvSeparator.PIPE => '|',
BatchProcessingCsvSeparator.TAB => '\t',
BatchProcessingCsvSeparator.CUSTOM when IsValidCustomSeparator(customSeparator) => customSeparator[0],
_ => DEFAULT_SEPARATOR,
};
_ => DEFAULT_SEPARATOR,
};
}
internal static bool IsValidCustomSeparator(string separator)
{
@@ -4,11 +4,14 @@ public static class BatchProcessingOutputModeExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(BatchProcessingOutputModeExtensions).Namespace, nameof(BatchProcessingOutputModeExtensions));
public static string Name(this BatchProcessingOutputMode outputMode) => outputMode switch
extension(BatchProcessingOutputMode outputMode)
{
BatchProcessingOutputMode.INDIVIDUAL_FILES => TB("One file per document"),
BatchProcessingOutputMode.TABLE_ONLY => TB("One CSV results table, where each answer becomes one row"),
public string Name() => outputMode switch
{
BatchProcessingOutputMode.INDIVIDUAL_FILES => TB("One file per document"),
BatchProcessingOutputMode.TABLE_ONLY => TB("One CSV results table, where each answer becomes one row"),
_ => TB("Unknown output mode"),
};
_ => TB("Unknown output mode"),
};
}
}
@@ -4,12 +4,15 @@ public static class BatchProcessingPromptSourceExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(BatchProcessingPromptSourceExtensions).Namespace, nameof(BatchProcessingPromptSourceExtensions));
public static string Name(this BatchProcessingPromptSource promptSource) => promptSource switch
extension(BatchProcessingPromptSource promptSource)
{
BatchProcessingPromptSource.FREE_PROMPT => TB("Use a free prompt"),
BatchProcessingPromptSource.POLICY => TB("Use a document analysis policy"),
BatchProcessingPromptSource.FILE_IMPORT => TB("Import from a file (.md)"),
public string Name() => promptSource switch
{
BatchProcessingPromptSource.FREE_PROMPT => TB("Use a free prompt"),
BatchProcessingPromptSource.POLICY => TB("Use a document analysis policy"),
BatchProcessingPromptSource.FILE_IMPORT => TB("Import from a file (.md)"),
_ => TB("Unknown prompt source"),
};
_ => TB("Unknown prompt source"),
};
}
}
@@ -2,22 +2,25 @@ namespace AIStudio.Assistants.Builder;
public static class LuaResponseParseErrorExtension
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(LuaResponseParseError).Namespace, nameof(LuaResponseParseError));
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(LuaResponseParseErrorExtension).Namespace, nameof(LuaResponseParseErrorExtension));
public static string GetMessage(this LuaResponseParseError parseError, string technicalDetails) => parseError switch
extension(LuaResponseParseError parseError)
{
LuaResponseParseError.MISSING_JSON_OBJECT => TB("The model response is missing or unreadable."),
LuaResponseParseError.INVALID_JSON => string.IsNullOrWhiteSpace(technicalDetails)
? TB("The model returned an invalid response.")
: string.Format(TB("The model returned an invalid response: {0}"), technicalDetails),
LuaResponseParseError.EMPTY_JSON_OBJECT => TB("The model returned an empty JSON object."),
LuaResponseParseError.UNSUPPORTED_SCHEMA_VERSION => TB("The model responded with an unsupported or deprecated JSON schema."),
LuaResponseParseError.MISSING_PLUGIN_METADATA => TB("The model's answer is missing the plugin metadata."),
LuaResponseParseError.MISSING_ASSISTANT_METADATA => TB("The model's answer is missing the assistant metadata."),
LuaResponseParseError.INCOMPLETE_PLUGIN_METADATA => TB("The model's answer contains incomplete plugin metadata."),
LuaResponseParseError.INCOMPLETE_ASSISTANT_METADATA => TB("The model's answer contains incomplete assistant metadata."),
LuaResponseParseError.MISSING_LUA => TB("The model response does not contain the generated Lua plugin code."),
LuaResponseParseError.LUA_MISSING_ID => TB("The generated Lua plugin code does not contain a readable plugin ID."),
_ => TB("The model returned an unusable JSON response."),
};
public string GetMessage(string technicalDetails) => parseError switch
{
LuaResponseParseError.MISSING_JSON_OBJECT => TB("The model response is missing or unreadable."),
LuaResponseParseError.INVALID_JSON => string.IsNullOrWhiteSpace(technicalDetails)
? TB("The model returned an invalid response.")
: string.Format(TB("The model returned an invalid response: {0}"), technicalDetails),
LuaResponseParseError.EMPTY_JSON_OBJECT => TB("The model returned an empty JSON object."),
LuaResponseParseError.UNSUPPORTED_SCHEMA_VERSION => TB("The model responded with an unsupported or deprecated JSON schema."),
LuaResponseParseError.MISSING_PLUGIN_METADATA => TB("The model's answer is missing the plugin metadata."),
LuaResponseParseError.MISSING_ASSISTANT_METADATA => TB("The model's answer is missing the assistant metadata."),
LuaResponseParseError.INCOMPLETE_PLUGIN_METADATA => TB("The model's answer contains incomplete plugin metadata."),
LuaResponseParseError.INCOMPLETE_ASSISTANT_METADATA => TB("The model's answer contains incomplete assistant metadata."),
LuaResponseParseError.MISSING_LUA => TB("The model response does not contain the generated Lua plugin code."),
LuaResponseParseError.LUA_MISSING_ID => TB("The generated Lua plugin code does not contain a readable plugin ID."),
_ => TB("The model returned an unusable JSON response."),
};
}
}
@@ -4,42 +4,45 @@ public static class CommonCodingLanguageExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(CommonCodingLanguageExtensions).Namespace, nameof(CommonCodingLanguageExtensions));
public static string Name(this CommonCodingLanguages language) => language switch
{
CommonCodingLanguages.NONE => TB("None"),
extension(CommonCodingLanguages language)
{
public string Name() => language switch
{
CommonCodingLanguages.NONE => TB("None"),
CommonCodingLanguages.BASH => "Bash",
CommonCodingLanguages.BLAZOR => ".NET Blazor",
CommonCodingLanguages.C => "C",
CommonCodingLanguages.CPP => "C++",
CommonCodingLanguages.CSHARP => "C#",
CommonCodingLanguages.CSS => "CSS",
CommonCodingLanguages.FORTRAN => "Fortran",
CommonCodingLanguages.GDSCRIPT => "GDScript",
CommonCodingLanguages.GO => "Go",
CommonCodingLanguages.HTML => "HTML",
CommonCodingLanguages.JAVA => "Java",
CommonCodingLanguages.JAVASCRIPT => "JavaScript",
CommonCodingLanguages.JSON => "JSON",
CommonCodingLanguages.JULIA => "Julia",
CommonCodingLanguages.KOTLIN => "Kotlin",
CommonCodingLanguages.LUA => "Lua",
CommonCodingLanguages.MARKDOWN => "Markdown",
CommonCodingLanguages.MATHEMATICA => "Mathematica",
CommonCodingLanguages.MATLAB => "MATLAB",
CommonCodingLanguages.PHP => "PHP",
CommonCodingLanguages.POWERSHELL => "PowerShell",
CommonCodingLanguages.PROLOG => "Prolog",
CommonCodingLanguages.PYTHON => "Python",
CommonCodingLanguages.R => "R",
CommonCodingLanguages.RUBY => "Ruby",
CommonCodingLanguages.RUST => "Rust",
CommonCodingLanguages.SQL => "SQL",
CommonCodingLanguages.SWIFT => "Swift",
CommonCodingLanguages.TYPESCRIPT => "TypeScript",
CommonCodingLanguages.XML => "XML",
CommonCodingLanguages.BASH => "Bash",
CommonCodingLanguages.BLAZOR => ".NET Blazor",
CommonCodingLanguages.C => "C",
CommonCodingLanguages.CPP => "C++",
CommonCodingLanguages.CSHARP => "C#",
CommonCodingLanguages.CSS => "CSS",
CommonCodingLanguages.FORTRAN => "Fortran",
CommonCodingLanguages.GDSCRIPT => "GDScript",
CommonCodingLanguages.GO => "Go",
CommonCodingLanguages.HTML => "HTML",
CommonCodingLanguages.JAVA => "Java",
CommonCodingLanguages.JAVASCRIPT => "JavaScript",
CommonCodingLanguages.JSON => "JSON",
CommonCodingLanguages.JULIA => "Julia",
CommonCodingLanguages.KOTLIN => "Kotlin",
CommonCodingLanguages.LUA => "Lua",
CommonCodingLanguages.MARKDOWN => "Markdown",
CommonCodingLanguages.MATHEMATICA => "Mathematica",
CommonCodingLanguages.MATLAB => "MATLAB",
CommonCodingLanguages.PHP => "PHP",
CommonCodingLanguages.POWERSHELL => "PowerShell",
CommonCodingLanguages.PROLOG => "Prolog",
CommonCodingLanguages.PYTHON => "Python",
CommonCodingLanguages.R => "R",
CommonCodingLanguages.RUBY => "Ruby",
CommonCodingLanguages.RUST => "Rust",
CommonCodingLanguages.SQL => "SQL",
CommonCodingLanguages.SWIFT => "Swift",
CommonCodingLanguages.TYPESCRIPT => "TypeScript",
CommonCodingLanguages.XML => "XML",
CommonCodingLanguages.OTHER => TB("Other"),
_ => TB("Unknown")
};
CommonCodingLanguages.OTHER => TB("Other"),
_ => TB("Unknown")
};
}
}
@@ -4,23 +4,26 @@ public static class WritingStylesExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(WritingStylesExtensions).Namespace, nameof(WritingStylesExtensions));
public static string Name(this WritingStyles style) => style switch
extension(WritingStyles style)
{
WritingStyles.ACADEMIC => TB("Academic"),
WritingStyles.PERSONAL => TB("Personal"),
WritingStyles.BUSINESS_FORMAL => TB("Business formal"),
WritingStyles.BUSINESS_INFORMAL => TB("Business informal"),
public string Name() => style switch
{
WritingStyles.ACADEMIC => TB("Academic"),
WritingStyles.PERSONAL => TB("Personal"),
WritingStyles.BUSINESS_FORMAL => TB("Business formal"),
WritingStyles.BUSINESS_INFORMAL => TB("Business informal"),
_ => TB("Not specified"),
};
public static string Prompt(this WritingStyles style) => style switch
{
WritingStyles.ACADEMIC => "Use an academic style for communication in an academic context like between students and professors.",
WritingStyles.PERSONAL => "Use a personal style for communication between friends and family.",
WritingStyles.BUSINESS_FORMAL => "Use a formal business style for this e-mail.",
WritingStyles.BUSINESS_INFORMAL => "Use an informal business style for this e-mail.",
_ => TB("Not specified"),
};
public string Prompt() => style switch
{
WritingStyles.ACADEMIC => "Use an academic style for communication in an academic context like between students and professors.",
WritingStyles.PERSONAL => "Use a personal style for communication between friends and family.",
WritingStyles.BUSINESS_FORMAL => "Use a formal business style for this e-mail.",
WritingStyles.BUSINESS_INFORMAL => "Use an informal business style for this e-mail.",
_ => "Use a formal business style for this e-mail.",
};
_ => "Use a formal business style for this e-mail.",
};
}
}
@@ -4,12 +4,15 @@ public static class AllowedLLMProvidersExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(AllowedLLMProvidersExtensions).Namespace, nameof(AllowedLLMProvidersExtensions));
public static string Description(this AllowedLLMProviders provider) => provider switch
extension(AllowedLLMProviders provider)
{
AllowedLLMProviders.NONE => TB("Please select what kind of LLM provider 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"),
public string Description() => provider switch
{
AllowedLLMProviders.NONE => TB("Please select what kind of LLM provider 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"),
_ => TB("Unknown option was selected")
};
_ => TB("Unknown option was selected")
};
}
}
@@ -4,25 +4,28 @@ public static class AuthExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(AuthExtensions).Namespace, nameof(AuthExtensions));
public static string Name(this Auth auth) => auth switch
extension(Auth auth)
{
Auth.NONE => TB("No login necessary: useful for public data sources"),
public string Name() => auth switch
{
Auth.NONE => TB("No login necessary: useful for public data sources"),
Auth.KERBEROS => TB("Login by single-sign-on (SSO) using Kerberos: very complex to implement and to operate, useful for many users"),
Auth.USERNAME_PASSWORD => TB("Login by username and password: simple to implement and to operate, useful for few users; easy to use for users"),
Auth.TOKEN => TB("Login by token: simple to implement and to operate, useful for few users; unusual for many users"),
Auth.KERBEROS => TB("Login by single-sign-on (SSO) using Kerberos: very complex to implement and to operate, useful for many users"),
Auth.USERNAME_PASSWORD => TB("Login by username and password: simple to implement and to operate, useful for few users; easy to use for users"),
Auth.TOKEN => TB("Login by token: simple to implement and to operate, useful for few users; unusual for many users"),
_ => TB("Unknown login method")
};
public static string ToPrompt(this Auth auth) => auth switch
{
Auth.NONE => "No login is necessary, the data source is public.",
_ => TB("Unknown login method")
};
public string ToPrompt() => auth switch
{
Auth.NONE => "No login is necessary, the data source is public.",
Auth.KERBEROS => "Login by single-sign-on (SSO) using Kerberos.",
Auth.USERNAME_PASSWORD => "Login by username and password.",
Auth.TOKEN => "Login by static token per user.",
Auth.KERBEROS => "Login by single-sign-on (SSO) using Kerberos.",
Auth.USERNAME_PASSWORD => "Login by username and password.",
Auth.TOKEN => "Login by static token per user.",
_ => string.Empty,
};
_ => string.Empty,
};
}
}
@@ -4,18 +4,21 @@ public static class DataSourcesExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(DataSourcesExtensions).Namespace, nameof(DataSourcesExtensions));
public static string Name(this DataSources dataSource) => dataSource switch
extension(DataSources dataSource)
{
DataSources.NONE => TB("No data source selected"),
DataSources.CUSTOM => TB("Custom description"),
public string Name() => dataSource switch
{
DataSources.NONE => TB("No data source selected"),
DataSources.CUSTOM => TB("Custom description"),
DataSources.FILE_SYSTEM => TB("File system (local or network share)"),
DataSources.OBJECT_STORAGE => TB("Object storage, like Amazon S3, MinIO, etc."),
DataSources.KEY_VALUE_STORE => TB("Key-Value store, like Redis, etc."),
DataSources.DOCUMENT_STORE => TB("Document store, like MongoDB, etc."),
DataSources.RELATIONAL_DATABASE => TB("Relational database, like MySQL, PostgreSQL, etc."),
DataSources.GRAPH_DATABASE => TB("Graph database, like Neo4j, ArangoDB, etc."),
DataSources.FILE_SYSTEM => TB("File system (local or network share)"),
DataSources.OBJECT_STORAGE => TB("Object storage, like Amazon S3, MinIO, etc."),
DataSources.KEY_VALUE_STORE => TB("Key-Value store, like Redis, etc."),
DataSources.DOCUMENT_STORE => TB("Document store, like MongoDB, etc."),
DataSources.RELATIONAL_DATABASE => TB("Relational database, like MySQL, PostgreSQL, etc."),
DataSources.GRAPH_DATABASE => TB("Graph database, like Neo4j, ArangoDB, etc."),
_ => TB("Unknown data source")
};
_ => TB("Unknown data source")
};
}
}
@@ -11,13 +11,16 @@ internal static class ERIServerFileOutcomeExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(ERIServerFileOutcomeExtensions).Namespace, nameof(ERIServerFileOutcomeExtensions));
/// <summary>
/// Gets the localized message which explains why a file was not written.
/// </summary>
/// <param name="outcome">What became of the file.</param>
/// <param name="file">The path of the file, as the model named it.</param>
/// <returns>The localized message.</returns>
internal static string ToUserMessage(this ERIServerFileOutcome outcome, string file) => string.Format(ToUserMessageFormat(outcome), file);
extension(ERIServerFileOutcome outcome)
{
/// <summary>
/// Gets the localized message which explains why a file was not written.
/// </summary>
/// <param name="file">The path of the file, as the model named it.</param>
/// <returns>The localized message.</returns>
internal string ToUserMessage(string file) => string.Format(ToUserMessageFormat(outcome), file);
}
private static string ToUserMessageFormat(ERIServerFileOutcome outcome) => outcome switch
{
@@ -2,14 +2,17 @@ namespace AIStudio.Assistants.ERI;
public static class ERIVersionExtensions
{
public static Task<string> ReadSpecification(this ERIVersion version, WebRootFiles webRootFiles) => webRootFiles.ReadTextAsync(version.SpecificationURL());
public static string SpecificationURL(this ERIVersion version)
extension(ERIVersion version)
{
var nameLower = version.ToString().ToLowerInvariant();
var filename = $"{nameLower}.json";
return $"specs/eri/{filename}";
}
public Task<string> ReadSpecification(WebRootFiles webRootFiles) => webRootFiles.ReadTextAsync(version.SpecificationURL());
public static bool WasSpecificationSelected(this ERIVersion version) => version != ERIVersion.NONE;
public string SpecificationURL()
{
var nameLower = version.ToString().ToLowerInvariant();
var filename = $"{nameLower}.json";
return $"specs/eri/{filename}";
}
public bool WasSpecificationSelected() => version != ERIVersion.NONE;
}
}
@@ -4,23 +4,26 @@ public static class OperatingSystemExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(OperatingSystemExtensions).Namespace, nameof(OperatingSystemExtensions));
public static string Name(this OperatingSystem os) => os switch
extension(OperatingSystem os)
{
OperatingSystem.NONE => TB("No operating system specified"),
public string Name() => os switch
{
OperatingSystem.NONE => TB("No operating system specified"),
OperatingSystem.WINDOWS => TB("Windows"),
OperatingSystem.LINUX => TB("Linux"),
OperatingSystem.WINDOWS => TB("Windows"),
OperatingSystem.LINUX => TB("Linux"),
_ => TB("Unknown operating system")
};
public static string ToPrompt(this OperatingSystem os) => os switch
{
OperatingSystem.NONE => "No operating system specified",
_ => TB("Unknown operating system")
};
public string ToPrompt() => os switch
{
OperatingSystem.NONE => "No operating system specified",
OperatingSystem.WINDOWS => "Windows",
OperatingSystem.LINUX => "Linux",
OperatingSystem.WINDOWS => "Windows",
OperatingSystem.LINUX => "Linux",
_ => "Unknown operating system"
};
_ => "Unknown operating system"
};
}
}
@@ -4,43 +4,46 @@ public static class ProgrammingLanguagesExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(ProgrammingLanguagesExtensions).Namespace, nameof(ProgrammingLanguagesExtensions));
public static string Name(this ProgrammingLanguages language) => language switch
{
ProgrammingLanguages.NONE => TB("No programming language selected"),
extension(ProgrammingLanguages language)
{
public string Name() => language switch
{
ProgrammingLanguages.NONE => TB("No programming language selected"),
ProgrammingLanguages.C => "C",
ProgrammingLanguages.CPP => "C++",
ProgrammingLanguages.CSHARP => "C#",
ProgrammingLanguages.GO => "Go",
ProgrammingLanguages.JAVA => "Java",
ProgrammingLanguages.JAVASCRIPT => "JavaScript",
ProgrammingLanguages.JULIA => "Julia",
ProgrammingLanguages.MATLAB => "MATLAB",
ProgrammingLanguages.PHP => "PHP",
ProgrammingLanguages.PYTHON => "Python",
ProgrammingLanguages.RUST => "Rust",
ProgrammingLanguages.C => "C",
ProgrammingLanguages.CPP => "C++",
ProgrammingLanguages.CSHARP => "C#",
ProgrammingLanguages.GO => "Go",
ProgrammingLanguages.JAVA => "Java",
ProgrammingLanguages.JAVASCRIPT => "JavaScript",
ProgrammingLanguages.JULIA => "Julia",
ProgrammingLanguages.MATLAB => "MATLAB",
ProgrammingLanguages.PHP => "PHP",
ProgrammingLanguages.PYTHON => "Python",
ProgrammingLanguages.RUST => "Rust",
ProgrammingLanguages.OTHER => TB("Other"),
_ => TB("Unknown")
};
public static string ToPrompt(this ProgrammingLanguages language) => language switch
{
ProgrammingLanguages.NONE => "No programming language selected",
ProgrammingLanguages.OTHER => TB("Other"),
_ => TB("Unknown")
};
public string ToPrompt() => language switch
{
ProgrammingLanguages.NONE => "No programming language selected",
ProgrammingLanguages.C => "C",
ProgrammingLanguages.CPP => "C++",
ProgrammingLanguages.CSHARP => "C#",
ProgrammingLanguages.GO => "Go",
ProgrammingLanguages.JAVA => "Java",
ProgrammingLanguages.JAVASCRIPT => "JavaScript",
ProgrammingLanguages.JULIA => "Julia",
ProgrammingLanguages.MATLAB => "MATLAB",
ProgrammingLanguages.PHP => "PHP",
ProgrammingLanguages.PYTHON => "Python",
ProgrammingLanguages.RUST => "Rust",
ProgrammingLanguages.C => "C",
ProgrammingLanguages.CPP => "C++",
ProgrammingLanguages.CSHARP => "C#",
ProgrammingLanguages.GO => "Go",
ProgrammingLanguages.JAVA => "Java",
ProgrammingLanguages.JAVASCRIPT => "JavaScript",
ProgrammingLanguages.JULIA => "Julia",
ProgrammingLanguages.MATLAB => "MATLAB",
ProgrammingLanguages.PHP => "PHP",
ProgrammingLanguages.PYTHON => "Python",
ProgrammingLanguages.RUST => "Rust",
ProgrammingLanguages.OTHER => "Other",
_ => "Unknown"
};
ProgrammingLanguages.OTHER => "Other",
_ => "Unknown"
};
}
}
@@ -2,39 +2,42 @@ namespace AIStudio.Assistants.IconFinder;
public static class IconSourceExtensions
{
public static string Name(this IconSources iconSource) => iconSource switch
extension(IconSources iconSource)
{
IconSources.FLAT_ICON => "Flaticon",
IconSources.FONT_AWESOME => "Font Awesome",
IconSources.MATERIAL_ICONS => "Material Icons",
IconSources.FEATHER_ICONS => "Feather Icons",
IconSources.BOOTSTRAP_ICONS => "Bootstrap Icons",
IconSources.ICONS8 => "Icons8",
public string Name() => iconSource switch
{
IconSources.FLAT_ICON => "Flaticon",
IconSources.FONT_AWESOME => "Font Awesome",
IconSources.MATERIAL_ICONS => "Material Icons",
IconSources.FEATHER_ICONS => "Feather Icons",
IconSources.BOOTSTRAP_ICONS => "Bootstrap Icons",
IconSources.ICONS8 => "Icons8",
_ => "Generic",
};
public static string Prompt(this IconSources iconSource) => iconSource switch
{
IconSources.FLAT_ICON => "My icon source is Flaticon.",
IconSources.FONT_AWESOME => "I look for an icon on Font Awesome. Please provide just valid icon names. Valid icon names are using the format `fa-icon-name`.",
IconSources.MATERIAL_ICONS => "I look for a Material icon. Please provide just valid icon names. Valid icon names are using the format `IconName`.",
IconSources.FEATHER_ICONS => "My icon source is Feather Icons. Please provide just valid icon names. Valid icon names usiing the format `icon-name`.",
IconSources.BOOTSTRAP_ICONS => "I look for an icon for Bootstrap. Please provide just valid icon names. Valid icon names are using the format `bi-icon-name`.",
IconSources.ICONS8 => "I look for an icon on Icons8.",
_ => string.Empty,
};
_ => "Generic",
};
public static string URL(this IconSources iconSource) => iconSource switch
{
IconSources.FLAT_ICON => "https://www.flaticon.com/",
IconSources.FONT_AWESOME => "https://fontawesome.com/",
IconSources.MATERIAL_ICONS => "https://material.io/resources/icons/",
IconSources.FEATHER_ICONS => "https://feathericons.com/",
IconSources.BOOTSTRAP_ICONS => "https://icons.getbootstrap.com/",
IconSources.ICONS8 => "https://icons8.com/",
public string Prompt() => iconSource switch
{
IconSources.FLAT_ICON => "My icon source is Flaticon.",
IconSources.FONT_AWESOME => "I look for an icon on Font Awesome. Please provide just valid icon names. Valid icon names are using the format `fa-icon-name`.",
IconSources.MATERIAL_ICONS => "I look for a Material icon. Please provide just valid icon names. Valid icon names are using the format `IconName`.",
IconSources.FEATHER_ICONS => "My icon source is Feather Icons. Please provide just valid icon names. Valid icon names usiing the format `icon-name`.",
IconSources.BOOTSTRAP_ICONS => "I look for an icon for Bootstrap. Please provide just valid icon names. Valid icon names are using the format `bi-icon-name`.",
IconSources.ICONS8 => "I look for an icon on Icons8.",
_ => string.Empty,
};
_ => string.Empty,
};
public string URL() => iconSource switch
{
IconSources.FLAT_ICON => "https://www.flaticon.com/",
IconSources.FONT_AWESOME => "https://fontawesome.com/",
IconSources.MATERIAL_ICONS => "https://material.io/resources/icons/",
IconSources.FEATHER_ICONS => "https://feathericons.com/",
IconSources.BOOTSTRAP_ICONS => "https://icons.getbootstrap.com/",
IconSources.ICONS8 => "https://icons8.com/",
_ => string.Empty,
};
}
}
@@ -4,19 +4,22 @@ public static class SentenceStructureExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(SentenceStructureExtensions).Namespace, nameof(SentenceStructureExtensions));
public static string Name(this SentenceStructure sentenceStructure) => sentenceStructure switch
extension(SentenceStructure sentenceStructure)
{
SentenceStructure.ACTIVE => TB("Active voice"),
SentenceStructure.PASSIVE => TB("Passive voice"),
public string Name() => sentenceStructure switch
{
SentenceStructure.ACTIVE => TB("Active voice"),
SentenceStructure.PASSIVE => TB("Passive voice"),
_ => TB("Not Specified"),
};
_ => TB("Not Specified"),
};
public static string Prompt(this SentenceStructure sentenceStructure) => sentenceStructure switch
{
SentenceStructure.ACTIVE => " Use an active voice for the sentence structure.",
SentenceStructure.PASSIVE => " Use a passive voice for the sentence structure.",
public string Prompt() => sentenceStructure switch
{
SentenceStructure.ACTIVE => " Use an active voice for the sentence structure.",
SentenceStructure.PASSIVE => " Use a passive voice for the sentence structure.",
_ => string.Empty,
};
_ => string.Empty,
};
}
}
@@ -4,35 +4,38 @@ public static class WritingStylesExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(WritingStylesExtensions).Namespace, nameof(WritingStylesExtensions));
public static string Name(this WritingStyles style) => style switch
extension(WritingStyles style)
{
WritingStyles.EVERYDAY => TB("Everyday (personal texts, social media)"),
WritingStyles.BUSINESS => TB("Business (business emails, reports, presentations)"),
WritingStyles.SCIENTIFIC => TB("Scientific (scientific papers, research reports)"),
WritingStyles.JOURNALISTIC => TB("Journalistic (magazines, newspapers, news)"),
WritingStyles.LITERARY => TB("Literary (fiction, poetry)"),
WritingStyles.TECHNICAL => TB("Technical (manuals, documentation)"),
WritingStyles.MARKETING => TB("Marketing (advertisements, sales texts)"),
WritingStyles.ACADEMIC => TB("Academic (essays, seminar papers)"),
WritingStyles.LEGAL => TB("Legal (legal texts, contracts)"),
WritingStyles.CHANGELOG => TB("Changelog (release notes, version history)"),
public string Name() => style switch
{
WritingStyles.EVERYDAY => TB("Everyday (personal texts, social media)"),
WritingStyles.BUSINESS => TB("Business (business emails, reports, presentations)"),
WritingStyles.SCIENTIFIC => TB("Scientific (scientific papers, research reports)"),
WritingStyles.JOURNALISTIC => TB("Journalistic (magazines, newspapers, news)"),
WritingStyles.LITERARY => TB("Literary (fiction, poetry)"),
WritingStyles.TECHNICAL => TB("Technical (manuals, documentation)"),
WritingStyles.MARKETING => TB("Marketing (advertisements, sales texts)"),
WritingStyles.ACADEMIC => TB("Academic (essays, seminar papers)"),
WritingStyles.LEGAL => TB("Legal (legal texts, contracts)"),
WritingStyles.CHANGELOG => TB("Changelog (release notes, version history)"),
_ => TB("Not specified"),
};
_ => TB("Not specified"),
};
public static string Prompt(this WritingStyles style) => style switch
{
WritingStyles.EVERYDAY => "Use a everyday style like for personal texts, social media, and informal communication.",
WritingStyles.BUSINESS => "Use a business style like for business emails, reports, and presentations. Most important is clarity and professionalism.",
WritingStyles.SCIENTIFIC => "Use a scientific style like for scientific papers, research reports, and academic writing. Most important is precision and objectivity.",
WritingStyles.JOURNALISTIC => "Use a journalistic style like for magazines, newspapers, and news. Most important is readability and engaging content.",
WritingStyles.LITERARY => "Use a literary style like for fiction, poetry, and creative writing. Most important is creativity and emotional impact.",
WritingStyles.TECHNICAL => "Use a technical style like for manuals, documentation, and technical writing. Most important is clarity and precision.",
WritingStyles.MARKETING => "Use a marketing style like for advertisements, sales texts, and promotional content. Most important is persuasiveness and engagement.",
WritingStyles.ACADEMIC => "Use a academic style like for essays, seminar papers, and academic writing. Most important is clarity and objectivity.",
WritingStyles.LEGAL => "Use a legal style like for legal texts, contracts, and official documents. Most important is precision and legal correctness. Use formal legal language.",
WritingStyles.CHANGELOG => "Use a changelog style like for release notes, version history, and software updates. Most important is clarity and conciseness. The changelog is structured as a Markdown list. Most list items start with one of the following verbs: Added, Changed, Deprecated, Removed, Fixed, Refactored, Improved, or Upgraded -- these verbs should also translated to the target language. Also, changelogs use past tense.",
public string Prompt() => style switch
{
WritingStyles.EVERYDAY => "Use a everyday style like for personal texts, social media, and informal communication.",
WritingStyles.BUSINESS => "Use a business style like for business emails, reports, and presentations. Most important is clarity and professionalism.",
WritingStyles.SCIENTIFIC => "Use a scientific style like for scientific papers, research reports, and academic writing. Most important is precision and objectivity.",
WritingStyles.JOURNALISTIC => "Use a journalistic style like for magazines, newspapers, and news. Most important is readability and engaging content.",
WritingStyles.LITERARY => "Use a literary style like for fiction, poetry, and creative writing. Most important is creativity and emotional impact.",
WritingStyles.TECHNICAL => "Use a technical style like for manuals, documentation, and technical writing. Most important is clarity and precision.",
WritingStyles.MARKETING => "Use a marketing style like for advertisements, sales texts, and promotional content. Most important is persuasiveness and engagement.",
WritingStyles.ACADEMIC => "Use a academic style like for essays, seminar papers, and academic writing. Most important is clarity and objectivity.",
WritingStyles.LEGAL => "Use a legal style like for legal texts, contracts, and official documents. Most important is precision and legal correctness. Use formal legal language.",
WritingStyles.CHANGELOG => "Use a changelog style like for release notes, version history, and software updates. Most important is clarity and conciseness. The changelog is structured as a Markdown list. Most list items start with one of the following verbs: Added, Changed, Deprecated, Removed, Fixed, Refactored, Improved, or Upgraded -- these verbs should also translated to the target language. Also, changelogs use past tense.",
_ => "Keep the style of the text as it is.",
};
_ => "Keep the style of the text as it is.",
};
}
}
@@ -2,29 +2,32 @@ namespace AIStudio.Assistants.SWOTAnalysis;
internal static class SwotAnalysisCategoryExtensions
{
/// <summary>
/// The name of the category in the JSON the models read and write, e.g., "strengths".
/// </summary>
public static string JsonName(this SwotAnalysisCategory category) => category switch
extension(SwotAnalysisCategory category)
{
SwotAnalysisCategory.STRENGTHS => "strengths",
SwotAnalysisCategory.WEAKNESSES => "weaknesses",
SwotAnalysisCategory.OPPORTUNITIES => "opportunities",
SwotAnalysisCategory.THREATS => "threats",
/// <summary>
/// The name of the category in the JSON the models read and write, e.g., "strengths".
/// </summary>
public string JsonName() => category switch
{
SwotAnalysisCategory.STRENGTHS => "strengths",
SwotAnalysisCategory.WEAKNESSES => "weaknesses",
SwotAnalysisCategory.OPPORTUNITIES => "opportunities",
SwotAnalysisCategory.THREATS => "threats",
_ => string.Empty,
};
_ => string.Empty,
};
/// <summary>
/// The letter the factor IDs of the category start with, e.g., S1 for the first strength.
/// </summary>
public static string FactorIdPrefix(this SwotAnalysisCategory category) => category switch
{
SwotAnalysisCategory.STRENGTHS => "S",
SwotAnalysisCategory.WEAKNESSES => "W",
SwotAnalysisCategory.OPPORTUNITIES => "O",
SwotAnalysisCategory.THREATS => "T",
/// <summary>
/// The letter the factor IDs of the category start with, e.g., S1 for the first strength.
/// </summary>
public string FactorIdPrefix() => category switch
{
SwotAnalysisCategory.STRENGTHS => "S",
SwotAnalysisCategory.WEAKNESSES => "W",
SwotAnalysisCategory.OPPORTUNITIES => "O",
SwotAnalysisCategory.THREATS => "T",
_ => string.Empty,
};
_ => string.Empty,
};
}
}
@@ -4,23 +4,26 @@ public static class AudienceAgeGroupExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(AudienceAgeGroupExtensions).Namespace, nameof(AudienceAgeGroupExtensions));
public static string Name(this AudienceAgeGroup ageGroup) => ageGroup switch
extension(AudienceAgeGroup ageGroup)
{
AudienceAgeGroup.UNSPECIFIED => TB("Unspecified age group"),
AudienceAgeGroup.CHILDREN => TB("Children"),
AudienceAgeGroup.TEENAGERS => TB("Teenagers"),
AudienceAgeGroup.ADULTS => TB("Adults"),
public string Name() => ageGroup switch
{
AudienceAgeGroup.UNSPECIFIED => TB("Unspecified age group"),
AudienceAgeGroup.CHILDREN => TB("Children"),
AudienceAgeGroup.TEENAGERS => TB("Teenagers"),
AudienceAgeGroup.ADULTS => TB("Adults"),
_ => TB("Unspecified age group"),
};
_ => TB("Unspecified age group"),
};
public static string Prompt(this AudienceAgeGroup ageGroup) => ageGroup switch
{
AudienceAgeGroup.UNSPECIFIED => "Do not tailor the text to a specific age group.",
AudienceAgeGroup.CHILDREN => "Use simple, concrete language with short sentences and minimal jargon.",
AudienceAgeGroup.TEENAGERS => "Use clear, approachable language with relatable examples and limited jargon.",
AudienceAgeGroup.ADULTS => "Use adult-appropriate language with clear structure and direct explanations.",
public string Prompt() => ageGroup switch
{
AudienceAgeGroup.UNSPECIFIED => "Do not tailor the text to a specific age group.",
AudienceAgeGroup.CHILDREN => "Use simple, concrete language with short sentences and minimal jargon.",
AudienceAgeGroup.TEENAGERS => "Use clear, approachable language with relatable examples and limited jargon.",
AudienceAgeGroup.ADULTS => "Use adult-appropriate language with clear structure and direct explanations.",
_ => "Do not tailor the text to a specific age group.",
};
_ => "Do not tailor the text to a specific age group.",
};
}
}
@@ -4,25 +4,28 @@ public static class AudienceExpertiseExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(AudienceExpertiseExtensions).Namespace, nameof(AudienceExpertiseExtensions));
public static string Name(this AudienceExpertise expertise) => expertise switch
extension(AudienceExpertise expertise)
{
AudienceExpertise.UNSPECIFIED => TB("Unspecified expertise"),
AudienceExpertise.NON_EXPERTS => TB("No expertise"),
AudienceExpertise.BASIC => TB("Basic expertise"),
AudienceExpertise.INTERMEDIATE => TB("Intermediate expertise"),
AudienceExpertise.EXPERTS => TB("Experts"),
public string Name() => expertise switch
{
AudienceExpertise.UNSPECIFIED => TB("Unspecified expertise"),
AudienceExpertise.NON_EXPERTS => TB("No expertise"),
AudienceExpertise.BASIC => TB("Basic expertise"),
AudienceExpertise.INTERMEDIATE => TB("Intermediate expertise"),
AudienceExpertise.EXPERTS => TB("Experts"),
_ => TB("Unspecified expertise"),
};
_ => TB("Unspecified expertise"),
};
public static string Prompt(this AudienceExpertise expertise) => expertise switch
{
AudienceExpertise.UNSPECIFIED => "Do not tailor the text to a specific expertise level.",
AudienceExpertise.NON_EXPERTS => "Avoid jargon and explain specialized concepts plainly.",
AudienceExpertise.BASIC => "Use simple terminology and briefly explain important technical terms.",
AudienceExpertise.INTERMEDIATE => "Assume some familiarity with the topic, but still explain important details clearly.",
AudienceExpertise.EXPERTS => "Assume deep familiarity with the topic and use precise domain-specific terminology.",
public string Prompt() => expertise switch
{
AudienceExpertise.UNSPECIFIED => "Do not tailor the text to a specific expertise level.",
AudienceExpertise.NON_EXPERTS => "Avoid jargon and explain specialized concepts plainly.",
AudienceExpertise.BASIC => "Use simple terminology and briefly explain important technical terms.",
AudienceExpertise.INTERMEDIATE => "Assume some familiarity with the topic, but still explain important details clearly.",
AudienceExpertise.EXPERTS => "Assume deep familiarity with the topic and use precise domain-specific terminology.",
_ => "Do not tailor the text to a specific expertise level.",
};
_ => "Do not tailor the text to a specific expertise level.",
};
}
}
@@ -4,29 +4,32 @@ public static class AudienceOrganizationalLevelExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(AudienceOrganizationalLevelExtensions).Namespace, nameof(AudienceOrganizationalLevelExtensions));
public static string Name(this AudienceOrganizationalLevel level) => level switch
extension(AudienceOrganizationalLevel level)
{
AudienceOrganizationalLevel.UNSPECIFIED => TB("Unspecified organizational level"),
AudienceOrganizationalLevel.TRAINEES => TB("Trainees"),
AudienceOrganizationalLevel.INDIVIDUAL_CONTRIBUTORS => TB("Individual contributors"),
AudienceOrganizationalLevel.TEAM_LEADS => TB("Team leads"),
AudienceOrganizationalLevel.MANAGERS => TB("Managers"),
AudienceOrganizationalLevel.EXECUTIVES => TB("Executives"),
AudienceOrganizationalLevel.BOARD_MEMBERS => TB("Board members"),
public string Name() => level switch
{
AudienceOrganizationalLevel.UNSPECIFIED => TB("Unspecified organizational level"),
AudienceOrganizationalLevel.TRAINEES => TB("Trainees"),
AudienceOrganizationalLevel.INDIVIDUAL_CONTRIBUTORS => TB("Individual contributors"),
AudienceOrganizationalLevel.TEAM_LEADS => TB("Team leads"),
AudienceOrganizationalLevel.MANAGERS => TB("Managers"),
AudienceOrganizationalLevel.EXECUTIVES => TB("Executives"),
AudienceOrganizationalLevel.BOARD_MEMBERS => TB("Board members"),
_ => TB("Unspecified organizational level"),
};
_ => TB("Unspecified organizational level"),
};
public static string Prompt(this AudienceOrganizationalLevel level) => level switch
{
AudienceOrganizationalLevel.UNSPECIFIED => "Do not tailor the text to a specific organizational level.",
AudienceOrganizationalLevel.TRAINEES => "Keep the content supportive and introductory. Explain context and avoid assuming prior organizational knowledge.",
AudienceOrganizationalLevel.INDIVIDUAL_CONTRIBUTORS => "Focus on execution, clarity, responsibilities, and practical next steps.",
AudienceOrganizationalLevel.TEAM_LEADS => "Focus on coordination, tradeoffs, risks, and concrete actions for a small team.",
AudienceOrganizationalLevel.MANAGERS => "Focus on planning, priorities, outcomes, risks, and resource implications.",
AudienceOrganizationalLevel.EXECUTIVES => "Focus on strategy, business impact, risks, and the decisions required.",
AudienceOrganizationalLevel.BOARD_MEMBERS => "Provide a concise executive-level summary with governance, strategy, risk, and decision relevance.",
public string Prompt() => level switch
{
AudienceOrganizationalLevel.UNSPECIFIED => "Do not tailor the text to a specific organizational level.",
AudienceOrganizationalLevel.TRAINEES => "Keep the content supportive and introductory. Explain context and avoid assuming prior organizational knowledge.",
AudienceOrganizationalLevel.INDIVIDUAL_CONTRIBUTORS => "Focus on execution, clarity, responsibilities, and practical next steps.",
AudienceOrganizationalLevel.TEAM_LEADS => "Focus on coordination, tradeoffs, risks, and concrete actions for a small team.",
AudienceOrganizationalLevel.MANAGERS => "Focus on planning, priorities, outcomes, risks, and resource implications.",
AudienceOrganizationalLevel.EXECUTIVES => "Focus on strategy, business impact, risks, and the decisions required.",
AudienceOrganizationalLevel.BOARD_MEMBERS => "Provide a concise executive-level summary with governance, strategy, risk, and decision relevance.",
_ => "Do not tailor the text to a specific organizational level.",
};
_ => "Do not tailor the text to a specific organizational level.",
};
}
}
@@ -4,37 +4,40 @@ public static class AudienceProfileExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(AudienceProfileExtensions).Namespace, nameof(AudienceProfileExtensions));
public static string Name(this AudienceProfile profile) => profile switch
extension(AudienceProfile profile)
{
AudienceProfile.UNSPECIFIED => TB("Unspecified audience profile"),
AudienceProfile.STUDENTS => TB("Students"),
AudienceProfile.SCIENTISTS => TB("Scientists"),
AudienceProfile.LAWYERS => TB("Lawyers"),
AudienceProfile.INVESTORS => TB("Investors"),
AudienceProfile.ENGINEERS => TB("Engineers"),
AudienceProfile.SOFTWARE_DEVELOPERS => TB("Software developers"),
AudienceProfile.JOURNALISTS => TB("Journalists"),
AudienceProfile.HEALTHCARE_PROFESSIONALS => TB("Healthcare professionals"),
AudienceProfile.PUBLIC_OFFICIALS => TB("Public officials"),
AudienceProfile.BUSINESS_PROFESSIONALS => TB("Business professionals"),
public string Name() => profile switch
{
AudienceProfile.UNSPECIFIED => TB("Unspecified audience profile"),
AudienceProfile.STUDENTS => TB("Students"),
AudienceProfile.SCIENTISTS => TB("Scientists"),
AudienceProfile.LAWYERS => TB("Lawyers"),
AudienceProfile.INVESTORS => TB("Investors"),
AudienceProfile.ENGINEERS => TB("Engineers"),
AudienceProfile.SOFTWARE_DEVELOPERS => TB("Software developers"),
AudienceProfile.JOURNALISTS => TB("Journalists"),
AudienceProfile.HEALTHCARE_PROFESSIONALS => TB("Healthcare professionals"),
AudienceProfile.PUBLIC_OFFICIALS => TB("Public officials"),
AudienceProfile.BUSINESS_PROFESSIONALS => TB("Business professionals"),
_ => TB("Unspecified audience profile"),
};
_ => TB("Unspecified audience profile"),
};
public static string Prompt(this AudienceProfile profile) => profile switch
{
AudienceProfile.UNSPECIFIED => "Do not tailor the text to a specific audience profile.",
AudienceProfile.STUDENTS => "Write for students. Keep it structured, easy to study, and focused on key takeaways.",
AudienceProfile.SCIENTISTS => "Use precise, technical language. Structure the content logically and focus on methods, evidence, and results.",
AudienceProfile.LAWYERS => "Write with precise wording. Emphasize definitions, implications, compliance, and risks.",
AudienceProfile.INVESTORS => "Focus on market potential, business model, differentiation, traction, risks, and financial upside.",
AudienceProfile.ENGINEERS => "Be technically precise and practical. Focus on systems, constraints, implementation, and tradeoffs.",
AudienceProfile.SOFTWARE_DEVELOPERS => "Use concise technical language. Focus on architecture, implementation details, tradeoffs, and maintainability.",
AudienceProfile.JOURNALISTS => "Be clear, factual, and concise. Highlight the most newsworthy points and explain relevance plainly.",
AudienceProfile.HEALTHCARE_PROFESSIONALS => "Use accurate professional language. Emphasize outcomes, safety, evidence, and practical implications.",
AudienceProfile.PUBLIC_OFFICIALS => "Focus on public impact, feasibility, budget, compliance, risks, and implementation in a neutral institutional tone.",
AudienceProfile.BUSINESS_PROFESSIONALS => "Be clear, practical, and concise. Focus on business relevance, decisions, and next steps.",
public string Prompt() => profile switch
{
AudienceProfile.UNSPECIFIED => "Do not tailor the text to a specific audience profile.",
AudienceProfile.STUDENTS => "Write for students. Keep it structured, easy to study, and focused on key takeaways.",
AudienceProfile.SCIENTISTS => "Use precise, technical language. Structure the content logically and focus on methods, evidence, and results.",
AudienceProfile.LAWYERS => "Write with precise wording. Emphasize definitions, implications, compliance, and risks.",
AudienceProfile.INVESTORS => "Focus on market potential, business model, differentiation, traction, risks, and financial upside.",
AudienceProfile.ENGINEERS => "Be technically precise and practical. Focus on systems, constraints, implementation, and tradeoffs.",
AudienceProfile.SOFTWARE_DEVELOPERS => "Use concise technical language. Focus on architecture, implementation details, tradeoffs, and maintainability.",
AudienceProfile.JOURNALISTS => "Be clear, factual, and concise. Highlight the most newsworthy points and explain relevance plainly.",
AudienceProfile.HEALTHCARE_PROFESSIONALS => "Use accurate professional language. Emphasize outcomes, safety, evidence, and practical implications.",
AudienceProfile.PUBLIC_OFFICIALS => "Focus on public impact, feasibility, budget, compliance, risks, and implementation in a neutral institutional tone.",
AudienceProfile.BUSINESS_PROFESSIONALS => "Be clear, practical, and concise. Focus on business relevance, decisions, and next steps.",
_ => "Do not tailor the text to a specific audience profile.",
};
_ => "Do not tailor the text to a specific audience profile.",
};
}
}
@@ -4,53 +4,56 @@ public static class PresentationOccasionExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(PresentationOccasionExtensions).Namespace, nameof(PresentationOccasionExtensions));
public static string Name(this PresentationOccasion occasion) => occasion switch
{
PresentationOccasion.UNSPECIFIED => TB("Unspecified occasion"),
PresentationOccasion.TALK => TB("Talk"),
PresentationOccasion.KEYNOTE => TB("Keynote"),
PresentationOccasion.CONFERENCE_TALK => TB("Conference talk"),
PresentationOccasion.LECTURE => TB("Lecture"),
PresentationOccasion.TRAINING => TB("Training"),
PresentationOccasion.WORKSHOP => TB("Workshop of one day"),
PresentationOccasion.MULTI_DAY_WORKSHOP => TB("Workshop of several days"),
PresentationOccasion.THESIS_DEFENSE => TB("Defense of a thesis or dissertation"),
PresentationOccasion.RESEARCH_RESULTS => TB("Presentation of research results"),
PresentationOccasion.PROJECT_REPORT => TB("Project or status report"),
PresentationOccasion.MANAGEMENT_REPORT => TB("Report to management"),
PresentationOccasion.PITCH => TB("Pitch"),
PresentationOccasion.PRODUCT_PRESENTATION => TB("Product presentation"),
PresentationOccasion.KICK_OFF => TB("Kick-off"),
PresentationOccasion.TEAM_MEETING => TB("Team meeting"),
PresentationOccasion.OTHER => TB("Other occasion"),
_ => TB("Unspecified occasion"),
};
/// <summary>
/// Tells the model what the occasion means for the structure of the presentation.
/// </summary>
/// <param name="occasion">The occasion.</param>
/// <param name="customOccasion">The occasion the user described, for OTHER.</param>
public static string Prompt(this PresentationOccasion occasion, string customOccasion) => occasion switch
extension(PresentationOccasion occasion)
{
PresentationOccasion.TALK => "The presentation accompanies a talk. Structure it for a speaker who talks the audience through it.",
PresentationOccasion.KEYNOTE => "The presentation accompanies a keynote. Favor few words per slide, strong key messages, and a story which carries the audience.",
PresentationOccasion.CONFERENCE_TALK => "The presentation accompanies a talk at a conference. Keep to the essentials of a short time slot, and end with the key messages and room for questions.",
PresentationOccasion.LECTURE => "The presentation accompanies a lecture. Teach step by step, with examples, and where it suits, end chapters with an interim summary or with room for questions.",
PresentationOccasion.TRAINING => "The presentation accompanies a training. Teach practical skills step by step, with examples and exercises where the content offers them.",
PresentationOccasion.WORKSHOP => "The presentation accompanies a workshop of one day. Plan for interaction, e.g., exercises, group work, or discussions, and for the breaks the schedule of the content has.",
PresentationOccasion.MULTI_DAY_WORKSHOP => "The presentation accompanies a workshop of several days. Plan for interaction, mark where a day ends and the next one starts, and look back at the start of each day, following the schedule of the content.",
PresentationOccasion.THESIS_DEFENSE => "The presentation defends a thesis or a dissertation before a committee. Present the research questions, the method, the results, and the contribution precisely, and anticipate critical questions.",
PresentationOccasion.RESEARCH_RESULTS => "The presentation presents research results. Present the questions, the method, the results, and their meaning precisely and comprehensibly.",
PresentationOccasion.PROJECT_REPORT => "The presentation reports on a project. Present the status, the progress, the problems, and the next steps clearly.",
PresentationOccasion.MANAGEMENT_REPORT => "The presentation reports to management and may prepare a decision. Lead with the key messages, keep details short, and state clearly what is to be decided.",
PresentationOccasion.PITCH => "The presentation pitches an idea, a product, or an offer. Lead with the benefit for the audience, and end with a clear call to action.",
PresentationOccasion.PRODUCT_PRESENTATION => "The presentation presents a product. Show what it does and what it brings the audience, with examples.",
PresentationOccasion.KICK_OFF => "The presentation opens a project at its kick-off. Present the goals, the team, the plan, and how the work is organized.",
PresentationOccasion.TEAM_MEETING => "The presentation serves a team meeting. Keep it short and practical, with clear points and next steps.",
PresentationOccasion.OTHER => $"The presentation is for this occasion: {customOccasion}. Structure it accordingly.",
public string Name() => occasion switch
{
PresentationOccasion.UNSPECIFIED => TB("Unspecified occasion"),
PresentationOccasion.TALK => TB("Talk"),
PresentationOccasion.KEYNOTE => TB("Keynote"),
PresentationOccasion.CONFERENCE_TALK => TB("Conference talk"),
PresentationOccasion.LECTURE => TB("Lecture"),
PresentationOccasion.TRAINING => TB("Training"),
PresentationOccasion.WORKSHOP => TB("Workshop of one day"),
PresentationOccasion.MULTI_DAY_WORKSHOP => TB("Workshop of several days"),
PresentationOccasion.THESIS_DEFENSE => TB("Defense of a thesis or dissertation"),
PresentationOccasion.RESEARCH_RESULTS => TB("Presentation of research results"),
PresentationOccasion.PROJECT_REPORT => TB("Project or status report"),
PresentationOccasion.MANAGEMENT_REPORT => TB("Report to management"),
PresentationOccasion.PITCH => TB("Pitch"),
PresentationOccasion.PRODUCT_PRESENTATION => TB("Product presentation"),
PresentationOccasion.KICK_OFF => TB("Kick-off"),
PresentationOccasion.TEAM_MEETING => TB("Team meeting"),
PresentationOccasion.OTHER => TB("Other occasion"),
_ => "No particular occasion is given. Structure the presentation by its content.",
};
_ => TB("Unspecified occasion"),
};
/// <summary>
/// Tells the model what the occasion means for the structure of the presentation.
/// </summary>
/// <param name="customOccasion">The occasion the user described, for OTHER.</param>
public string Prompt(string customOccasion) => occasion switch
{
PresentationOccasion.TALK => "The presentation accompanies a talk. Structure it for a speaker who talks the audience through it.",
PresentationOccasion.KEYNOTE => "The presentation accompanies a keynote. Favor few words per slide, strong key messages, and a story which carries the audience.",
PresentationOccasion.CONFERENCE_TALK => "The presentation accompanies a talk at a conference. Keep to the essentials of a short time slot, and end with the key messages and room for questions.",
PresentationOccasion.LECTURE => "The presentation accompanies a lecture. Teach step by step, with examples, and where it suits, end chapters with an interim summary or with room for questions.",
PresentationOccasion.TRAINING => "The presentation accompanies a training. Teach practical skills step by step, with examples and exercises where the content offers them.",
PresentationOccasion.WORKSHOP => "The presentation accompanies a workshop of one day. Plan for interaction, e.g., exercises, group work, or discussions, and for the breaks the schedule of the content has.",
PresentationOccasion.MULTI_DAY_WORKSHOP => "The presentation accompanies a workshop of several days. Plan for interaction, mark where a day ends and the next one starts, and look back at the start of each day, following the schedule of the content.",
PresentationOccasion.THESIS_DEFENSE => "The presentation defends a thesis or a dissertation before a committee. Present the research questions, the method, the results, and the contribution precisely, and anticipate critical questions.",
PresentationOccasion.RESEARCH_RESULTS => "The presentation presents research results. Present the questions, the method, the results, and their meaning precisely and comprehensibly.",
PresentationOccasion.PROJECT_REPORT => "The presentation reports on a project. Present the status, the progress, the problems, and the next steps clearly.",
PresentationOccasion.MANAGEMENT_REPORT => "The presentation reports to management and may prepare a decision. Lead with the key messages, keep details short, and state clearly what is to be decided.",
PresentationOccasion.PITCH => "The presentation pitches an idea, a product, or an offer. Lead with the benefit for the audience, and end with a clear call to action.",
PresentationOccasion.PRODUCT_PRESENTATION => "The presentation presents a product. Show what it does and what it brings the audience, with examples.",
PresentationOccasion.KICK_OFF => "The presentation opens a project at its kick-off. Present the goals, the team, the plan, and how the work is organized.",
PresentationOccasion.TEAM_MEETING => "The presentation serves a team meeting. Keep it short and practical, with clear points and next steps.",
PresentationOccasion.OTHER => $"The presentation is for this occasion: {customOccasion}. Structure it accordingly.",
_ => "No particular occasion is given. Structure the presentation by its content.",
};
}
}
@@ -11,20 +11,23 @@ internal static class TemplateSlideExtensions
/// </summary>
private const int MAX_SLIDE_TITLE_CHARACTERS = 60;
/// <summary>
/// How the forms name a slide of the template: by its number and its title, and what is special about it.
/// </summary>
/// <remarks>
/// The title tells the slides apart at a glance, since a template rarely gives its slides more
/// than a title. A long one is cut, so that the label stays on one line.
/// </remarks>
public static string Label(this TemplateSlide slide)
extension(TemplateSlide slide)
{
var title = slide.Title.Length > MAX_SLIDE_TITLE_CHARACTERS ? $"{slide.Title[..MAX_SLIDE_TITLE_CHARACTERS].TrimEnd()}…" : slide.Title;
var label = title.Length > 0 ? string.Format(TB("Slide {0}: {1}"), slide.Number, title) : string.Format(TB("Slide {0}"), slide.Number);
if (slide.IsHidden)
label = $"{label} ({TB("hidden")})";
/// <summary>
/// How the forms name a slide of the template: by its number and its title, and what is special about it.
/// </summary>
/// <remarks>
/// The title tells the slides apart at a glance, since a template rarely gives its slides more
/// than a title. A long one is cut, so that the label stays on one line.
/// </remarks>
public string Label()
{
var title = slide.Title.Length > MAX_SLIDE_TITLE_CHARACTERS ? $"{slide.Title[..MAX_SLIDE_TITLE_CHARACTERS].TrimEnd()}…" : slide.Title;
var label = title.Length > 0 ? string.Format(TB("Slide {0}: {1}"), slide.Number, title) : string.Format(TB("Slide {0}"), slide.Number);
if (slide.IsHidden)
label = $"{label} ({TB("hidden")})";
return label;
return label;
}
}
}
@@ -6,12 +6,15 @@ internal static class TemplateSlideUseExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(TemplateSlideUseExtensions).Namespace, nameof(TemplateSlideUseExtensions));
public static string Name(this TemplateSlideUse use) => use switch
extension(TemplateSlideUse use)
{
TemplateSlideUse.OMIT => TB("Leave out"),
TemplateSlideUse.KEEP => TB("Keep unchanged"),
TemplateSlideUse.EDIT => TB("Let the LLM edit it"),
public string Name() => use switch
{
TemplateSlideUse.OMIT => TB("Leave out"),
TemplateSlideUse.KEEP => TB("Keep unchanged"),
TemplateSlideUse.EDIT => TB("Let the LLM edit it"),
_ => TB("Leave out"),
};
_ => TB("Leave out"),
};
}
}
@@ -4,31 +4,34 @@ public static class ComplexityExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(ComplexityExtensions).Namespace, nameof(ComplexityExtensions));
public static string Name(this Complexity complexity) => complexity switch
extension(Complexity complexity)
{
Complexity.NO_CHANGE => TB("No change in complexity"),
public string Name() => complexity switch
{
Complexity.NO_CHANGE => TB("No change in complexity"),
Complexity.SIMPLE_LANGUAGE => TB("Simple language, e.g., for children"),
Complexity.TEEN_LANGUAGE => TB("Teen language, e.g., for teenagers"),
Complexity.EVERYDAY_LANGUAGE => TB("Everyday language, e.g., for adults"),
Complexity.POPULAR_SCIENCE_LANGUAGE => TB("Popular science language, e.g., for people interested in science"),
Complexity.SCIENTIFIC_LANGUAGE_FIELD_EXPERTS => TB("Scientific language for experts in this field"),
Complexity.SCIENTIFIC_LANGUAGE_OTHER_EXPERTS => TB("Scientific language for experts from other fields (interdisciplinary)"),
Complexity.SIMPLE_LANGUAGE => TB("Simple language, e.g., for children"),
Complexity.TEEN_LANGUAGE => TB("Teen language, e.g., for teenagers"),
Complexity.EVERYDAY_LANGUAGE => TB("Everyday language, e.g., for adults"),
Complexity.POPULAR_SCIENCE_LANGUAGE => TB("Popular science language, e.g., for people interested in science"),
Complexity.SCIENTIFIC_LANGUAGE_FIELD_EXPERTS => TB("Scientific language for experts in this field"),
Complexity.SCIENTIFIC_LANGUAGE_OTHER_EXPERTS => TB("Scientific language for experts from other fields (interdisciplinary)"),
_ => TB("No change in complexity"),
};
public static string Prompt(this Complexity complexity, string expertInField) => complexity switch
{
Complexity.NO_CHANGE => "Do not change the complexity of the text.",
_ => TB("No change in complexity"),
};
public string Prompt(string expertInField) => complexity switch
{
Complexity.NO_CHANGE => "Do not change the complexity of the text.",
Complexity.SIMPLE_LANGUAGE => "Simplify the language, e.g., for 8 to 12-year-old children. Might use short sentences and simple words. You could use analogies to explain complex terms.",
Complexity.TEEN_LANGUAGE => "Use a language suitable for teenagers, e.g., 16 to 19 years old. Might use teenage slang and analogies to explain complex terms.",
Complexity.EVERYDAY_LANGUAGE => "Use everyday language suitable for adults. Avoid specific scientific terms. Use everday analogies to explain complex terms.",
Complexity.POPULAR_SCIENCE_LANGUAGE => "Use popular science language, e.g., for people interested in science. The text should be easy to understand, though. Use analogies to explain complex terms.",
Complexity.SCIENTIFIC_LANGUAGE_FIELD_EXPERTS => "Use scientific language for experts in the field of the texts subject. Use specific terms for this field.",
Complexity.SCIENTIFIC_LANGUAGE_OTHER_EXPERTS => $"The reader is an expert in {expertInField}. Change the language so that it is suitable. Explain specific terms, so that the reader within his field can understand the text. You might use analogies to explain complex terms.",
Complexity.SIMPLE_LANGUAGE => "Simplify the language, e.g., for 8 to 12-year-old children. Might use short sentences and simple words. You could use analogies to explain complex terms.",
Complexity.TEEN_LANGUAGE => "Use a language suitable for teenagers, e.g., 16 to 19 years old. Might use teenage slang and analogies to explain complex terms.",
Complexity.EVERYDAY_LANGUAGE => "Use everyday language suitable for adults. Avoid specific scientific terms. Use everday analogies to explain complex terms.",
Complexity.POPULAR_SCIENCE_LANGUAGE => "Use popular science language, e.g., for people interested in science. The text should be easy to understand, though. Use analogies to explain complex terms.",
Complexity.SCIENTIFIC_LANGUAGE_FIELD_EXPERTS => "Use scientific language for experts in the field of the texts subject. Use specific terms for this field.",
Complexity.SCIENTIFIC_LANGUAGE_OTHER_EXPERTS => $"The reader is an expert in {expertInField}. Change the language so that it is suitable. Explain specific terms, so that the reader within his field can understand the text. You might use analogies to explain complex terms.",
_ => "Do not change the complexity of the text.",
};
_ => "Do not change the complexity of the text.",
};
}
}
@@ -13,12 +13,15 @@ internal static class VisualBriefingFailureExtensions
{
private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(VisualBriefingFailureExtensions).Namespace, nameof(VisualBriefingFailureExtensions));
/// <summary>
/// Gets the localized message for one recorded failure.
/// </summary>
/// <param name="failure">The recorded failure.</param>
/// <returns>The localized message.</returns>
internal static string ToUserMessage(this VisualBriefingFailure failure) => ToUserMessage(failure.Code, failure.ValidationRule);
extension(VisualBriefingFailure failure)
{
/// <summary>
/// Gets the localized message for one recorded failure.
/// </summary>
/// <returns>The localized message.</returns>
internal string ToUserMessage() => ToUserMessage(failure.Code, failure.ValidationRule);
}
/// <summary>
/// Gets the localized message for one failure code and validation rule.
@@ -40,70 +43,76 @@ internal static class VisualBriefingFailureExtensions
_ => code.ToUserMessage(),
};
/// <summary>
/// Gets the localized message for one validation rule.
/// </summary>
/// <param name="rule">The stable validation rule.</param>
/// <returns>The localized message.</returns>
private static string ToUserMessage(this VisualBriefingValidationRule rule) => rule switch
extension(VisualBriefingValidationRule rule)
{
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."),
/// <summary>
/// Gets the localized message for one validation rule.
/// </summary>
/// <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."),
_ => string.Empty,
};
_ => string.Empty,
};
}
/// <summary>
/// Gets the localized message for one failure code.
/// </summary>
/// <param name="code">The stable failure code.</param>
/// <returns>The localized message.</returns>
private static string ToUserMessage(this VisualBriefingFailureCode code) => code switch
extension(VisualBriefingFailureCode code)
{
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.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.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."),
/// <summary>
/// Gets the localized message for one failure code.
/// </summary>
/// <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.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.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."),
_ => string.Empty,
};
_ => string.Empty,
};
}
}
@@ -15,55 +15,58 @@ internal static class VisualBriefingPreviewEndpoint
{
private const string ROUTE = "/visual-briefing/preview/{briefingId:guid}/{revisionId:guid}";
/// <summary>
/// Maps the visual briefing preview endpoint.
/// </summary>
/// <param name="app">The web application.</param>
public static void MapVisualBriefingPreview(this WebApplication app) => app.MapGet(
ROUTE,
async (
Guid briefingId,
Guid revisionId,
string? token,
HttpContext context,
VisualBriefingPreviewTokenService tokenService,
VisualBriefingStore store,
ILoggerFactory loggerFactory,
CancellationToken cancellationToken) =>
{
var logger = loggerFactory.CreateLogger(nameof(VisualBriefingPreviewEndpoint));
if (!tokenService.Validate(token, briefingId, revisionId))
extension(WebApplication app)
{
/// <summary>
/// Maps the visual briefing preview endpoint.
/// </summary>
public void MapVisualBriefingPreview() => app.MapGet(
ROUTE,
async (
Guid briefingId,
Guid revisionId,
string? token,
HttpContext context,
VisualBriefingPreviewTokenService tokenService,
VisualBriefingStore store,
ILoggerFactory loggerFactory,
CancellationToken cancellationToken) =>
{
logger.LogWarning(
Event(VisualBriefingLogEventId.PREVIEW_REJECTED),
"Visual briefing preview token rejected. BriefingId={BriefingId} RevisionId={RevisionId}",
briefingId,
revisionId);
var logger = loggerFactory.CreateLogger(nameof(VisualBriefingPreviewEndpoint));
if (!tokenService.Validate(token, briefingId, revisionId))
{
logger.LogWarning(
Event(VisualBriefingLogEventId.PREVIEW_REJECTED),
"Visual briefing preview token rejected. BriefingId={BriefingId} RevisionId={RevisionId}",
briefingId,
revisionId);
return Results.NotFound();
}
return Results.NotFound();
}
// The store re-validates the stored artifact before handing out a stream, so a manually
// modified file on disk never reaches the preview:
var preview = await store.OpenIntegrityCheckedVersionAsync(briefingId, revisionId, cancellationToken);
if (preview is null)
{
logger.LogWarning(
Event(VisualBriefingLogEventId.SECURITY_REJECTED),
"Visual briefing preview artifact rejected. BriefingId={BriefingId} RevisionId={RevisionId}",
briefingId,
revisionId);
// The store re-validates the stored artifact before handing out a stream, so a manually
// modified file on disk never reaches the preview:
var preview = await store.OpenIntegrityCheckedVersionAsync(briefingId, revisionId, cancellationToken);
if (preview is null)
{
logger.LogWarning(
Event(VisualBriefingLogEventId.SECURITY_REJECTED),
"Visual briefing preview artifact rejected. BriefingId={BriefingId} RevisionId={RevisionId}",
briefingId,
revisionId);
return Results.NotFound();
}
return Results.NotFound();
}
context.Response.Headers.CacheControl = "no-store";
context.Response.Headers.XContentTypeOptions = "nosniff";
context.Response.Headers["Referrer-Policy"] = "no-referrer";
context.Response.Headers.ContentSecurityPolicy = VisualBriefingArtifactService.GetContentSecurityPolicy(preview.Value.Parts);
context.Response.Headers.CacheControl = "no-store";
context.Response.Headers.XContentTypeOptions = "nosniff";
context.Response.Headers["Referrer-Policy"] = "no-referrer";
context.Response.Headers.ContentSecurityPolicy = VisualBriefingArtifactService.GetContentSecurityPolicy(preview.Value.Parts);
return Results.File(preview.Value.Stream, "text/html; charset=utf-8", enableRangeProcessing: false);
});
return Results.File(preview.Value.Stream, "text/html; charset=utf-8", enableRangeProcessing: false);
});
}
/// <summary>
/// Creates the log event ID for one visual briefing log event.