diff --git a/app/MindWork AI Studio/Chat/ContentBlockComponent.razor b/app/MindWork AI Studio/Chat/ContentBlockComponent.razor index 75877da..51aca3a 100644 --- a/app/MindWork AI Studio/Chat/ContentBlockComponent.razor +++ b/app/MindWork AI Studio/Chat/ContentBlockComponent.razor @@ -1,7 +1,7 @@ @using AIStudio.Tools @using MudBlazor - + diff --git a/app/MindWork AI Studio/Chat/ContentBlockComponent.razor.cs b/app/MindWork AI Studio/Chat/ContentBlockComponent.razor.cs index a08c5bf..f411b07 100644 --- a/app/MindWork AI Studio/Chat/ContentBlockComponent.razor.cs +++ b/app/MindWork AI Studio/Chat/ContentBlockComponent.razor.cs @@ -33,6 +33,12 @@ public partial class ContentBlockComponent : ComponentBase [Parameter] public DateTimeOffset Time { get; init; } + /// + /// Optional CSS classes. + /// + [Parameter] + public string Class { get; set; } = string.Empty; + [Inject] private Rust Rust { get; init; } = null!; @@ -107,4 +113,6 @@ public partial class ContentBlockComponent : ComponentBase break; } } + + private string CardClasses => $"my-2 rounded-lg {this.Class}"; } \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/AssistantBase.razor b/app/MindWork AI Studio/Components/AssistantBase.razor new file mode 100644 index 0000000..e04bb34 --- /dev/null +++ b/app/MindWork AI Studio/Components/AssistantBase.razor @@ -0,0 +1,39 @@ +@using AIStudio.Chat + + @this.Title + + + + + + + @this.Description + + + @if (this.Body is not null) + { + @this.Body + } + + + @if (this.inputIssues.Any()) + { + + Issues + + @foreach (var issue in this.inputIssues) + { + + @issue + + } + + + } + + @if (this.resultingContentBlock is not null) + { + + } + + \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/AssistantBase.razor.cs b/app/MindWork AI Studio/Components/AssistantBase.razor.cs new file mode 100644 index 0000000..dd99e08 --- /dev/null +++ b/app/MindWork AI Studio/Components/AssistantBase.razor.cs @@ -0,0 +1,104 @@ +using AIStudio.Chat; +using AIStudio.Provider; +using AIStudio.Settings; + +using Microsoft.AspNetCore.Components; + +namespace AIStudio.Components; + +public abstract partial class AssistantBase : ComponentBase +{ + [Inject] + protected SettingsManager SettingsManager { get; set; } = null!; + + [Inject] + protected IJSRuntime JsRuntime { get; init; } = null!; + + [Inject] + protected Random RNG { get; set; } = null!; + + protected abstract string Title { get; } + + protected abstract string Description { get; } + + protected abstract string SystemPrompt { get; } + + private protected virtual RenderFragment? Body => null; + + protected AIStudio.Settings.Provider selectedProvider; + protected MudForm? form; + protected bool inputIsValid; + + private ChatThread? chatThread; + private ContentBlock? resultingContentBlock; + private string[] inputIssues = []; + + #region Overrides of ComponentBase + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + // Reset the validation when not editing and on the first render. + // We don't want to show validation errors when the user opens the dialog. + if(firstRender) + this.form?.ResetValidation(); + + await base.OnAfterRenderAsync(firstRender); + } + + #endregion + + protected void CreateChatThread() + { + this.chatThread = new() + { + WorkspaceId = Guid.Empty, + ChatId = Guid.NewGuid(), + Name = string.Empty, + Seed = this.RNG.Next(), + SystemPrompt = this.SystemPrompt, + Blocks = [], + }; + } + + protected DateTimeOffset AddUserRequest(string request) + { + var time = DateTimeOffset.Now; + this.chatThread!.Blocks.Add(new ContentBlock + { + Time = time, + ContentType = ContentType.TEXT, + Role = ChatRole.USER, + Content = new ContentText + { + Text = request, + }, + }); + + return time; + } + + protected async Task AddAIResponseAsync(DateTimeOffset time) + { + var aiText = new ContentText + { + // We have to wait for the remote + // for the content stream: + InitialRemoteWait = true, + }; + + this.resultingContentBlock = new ContentBlock + { + Time = time, + ContentType = ContentType.TEXT, + Role = ChatRole.AI, + Content = aiText, + }; + + this.chatThread?.Blocks.Add(this.resultingContentBlock); + + // Use the selected provider to get the AI response. + // By awaiting this line, we wait for the entire + // content to be streamed. + await aiText.CreateFromProviderAsync(this.selectedProvider.UsedProvider.CreateProvider(this.selectedProvider.InstanceName, this.selectedProvider.Hostname), this.JsRuntime, this.SettingsManager, this.selectedProvider.Model, this.chatThread); + } +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/AssistantBaseCore.cs b/app/MindWork AI Studio/Components/AssistantBaseCore.cs new file mode 100644 index 0000000..5508b14 --- /dev/null +++ b/app/MindWork AI Studio/Components/AssistantBaseCore.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Rendering; + +namespace AIStudio.Components; + +// +// See https://stackoverflow.com/a/77300384/2258393 for why this class is needed +// + +public abstract class AssistantBaseCore : AssistantBase +{ + private protected sealed override RenderFragment Body => this.BuildRenderTree; + + // Allow content to be provided by a .razor file but without + // overriding the content of the base class + protected new virtual void BuildRenderTree(RenderTreeBuilder builder) + { + } +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Blocks/AssistantBlock.razor b/app/MindWork AI Studio/Components/Blocks/AssistantBlock.razor new file mode 100644 index 0000000..f08d308 --- /dev/null +++ b/app/MindWork AI Studio/Components/Blocks/AssistantBlock.razor @@ -0,0 +1,26 @@ + + + + + + + + @this.Name + + + + + + + + @this.Description + + + + + + @this.ButtonText + + + + \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Blocks/AssistantBlock.razor.cs b/app/MindWork AI Studio/Components/Blocks/AssistantBlock.razor.cs new file mode 100644 index 0000000..1efe6ec --- /dev/null +++ b/app/MindWork AI Studio/Components/Blocks/AssistantBlock.razor.cs @@ -0,0 +1,21 @@ +using Microsoft.AspNetCore.Components; + +namespace AIStudio.Components.Blocks; + +public partial class AssistantBlock : ComponentBase +{ + [Parameter] + public string Name { get; set; } = string.Empty; + + [Parameter] + public string Description { get; set; } = string.Empty; + + [Parameter] + public string Icon { get; set; } = Icons.Material.Filled.DisabledByDefault; + + [Parameter] + public string ButtonText { get; set; } = "Start"; + + [Parameter] + public string Link { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Blocks/Changelog.Logs.cs b/app/MindWork AI Studio/Components/Blocks/Changelog.Logs.cs index b5f7d14..5afac32 100644 --- a/app/MindWork AI Studio/Components/Blocks/Changelog.Logs.cs +++ b/app/MindWork AI Studio/Components/Blocks/Changelog.Logs.cs @@ -13,7 +13,8 @@ public partial class Changelog public static readonly Log[] LOGS = [ - new (161, "v0.7.1, build 161 (2024-07-13 12:44 UTC)", "v0.7.1.md"), + new (162, "v0.8.0, build 162 (2024-07-14 19:39 UTC)", "v0.8.0.md"), + new (161, "v0.7.1, build 161 (2024-07-13 11:42 UTC)", "v0.7.1.md"), new (160, "v0.7.0, build 160 (2024-07-13 08:21 UTC)", "v0.7.0.md"), new (159, "v0.6.3, build 159 (2024-07-03 18:26 UTC)", "v0.6.3.md"), new (158, "v0.6.2, build 158 (2024-07-01 18:03 UTC)", "v0.6.2.md"), diff --git a/app/MindWork AI Studio/Components/Blocks/InnerScrolling.razor b/app/MindWork AI Studio/Components/Blocks/InnerScrolling.razor index 24c2ab7..f0c66d6 100644 --- a/app/MindWork AI Studio/Components/Blocks/InnerScrolling.razor +++ b/app/MindWork AI Studio/Components/Blocks/InnerScrolling.razor @@ -1,4 +1,4 @@ -@inherits AIStudio.Tools.MSGComponentBase +@inherits MSGComponentBase
diff --git a/app/MindWork AI Studio/Components/Layout/MainLayout.razor b/app/MindWork AI Studio/Components/Layout/MainLayout.razor index f791489..052ec94 100644 --- a/app/MindWork AI Studio/Components/Layout/MainLayout.razor +++ b/app/MindWork AI Studio/Components/Layout/MainLayout.razor @@ -13,6 +13,9 @@ Chat + + Assistants + Supporters diff --git a/app/MindWork AI Studio/Tools/MSGComponentBase.cs b/app/MindWork AI Studio/Components/MSGComponentBase.cs similarity index 96% rename from app/MindWork AI Studio/Tools/MSGComponentBase.cs rename to app/MindWork AI Studio/Components/MSGComponentBase.cs index ff72e0e..c1606ba 100644 --- a/app/MindWork AI Studio/Tools/MSGComponentBase.cs +++ b/app/MindWork AI Studio/Components/MSGComponentBase.cs @@ -1,6 +1,8 @@ +using AIStudio.Tools; + using Microsoft.AspNetCore.Components; -namespace AIStudio.Tools; +namespace AIStudio.Components; public abstract class MSGComponentBase : ComponentBase, IDisposable, IMessageBusReceiver { diff --git a/app/MindWork AI Studio/Components/Pages/Assistants.razor b/app/MindWork AI Studio/Components/Pages/Assistants.razor new file mode 100644 index 0000000..8bd4ea8 --- /dev/null +++ b/app/MindWork AI Studio/Components/Pages/Assistants.razor @@ -0,0 +1,11 @@ +@page "/assistants" + + + Assistants + + + + + + + \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Pages/Assistants.razor.cs b/app/MindWork AI Studio/Components/Pages/Assistants.razor.cs new file mode 100644 index 0000000..9a71f4e --- /dev/null +++ b/app/MindWork AI Studio/Components/Pages/Assistants.razor.cs @@ -0,0 +1,5 @@ +using Microsoft.AspNetCore.Components; + +namespace AIStudio.Components.Pages; + +public partial class Assistants : ComponentBase; \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Pages/Chat.razor b/app/MindWork AI Studio/Components/Pages/Chat.razor index 0017303..edd8551 100644 --- a/app/MindWork AI Studio/Components/Pages/Chat.razor +++ b/app/MindWork AI Studio/Components/Pages/Chat.razor @@ -2,7 +2,7 @@ @using AIStudio.Chat @using AIStudio.Settings -@inherits AIStudio.Tools.MSGComponentBase +@inherits MSGComponentBase @if (this.chatThread is not null && this.chatThread.WorkspaceId != Guid.Empty) diff --git a/app/MindWork AI Studio/Components/Pages/IconFinder/AssistantIconFinder.razor b/app/MindWork AI Studio/Components/Pages/IconFinder/AssistantIconFinder.razor new file mode 100644 index 0000000..fb042b9 --- /dev/null +++ b/app/MindWork AI Studio/Components/Pages/IconFinder/AssistantIconFinder.razor @@ -0,0 +1,29 @@ +@page "/assistant/icons" +@using AIStudio.Settings +@inherits AssistantBaseCore + + + + + + @foreach (var source in Enum.GetValues()) + { + @source.Name() + } + + @if (this.selectedIconSource is not IconSources.GENERIC) + { + Open website + } + + + + @foreach (var provider in this.SettingsManager.ConfigurationData.Providers) + { + + } + + + + Find icon + \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Pages/IconFinder/AssistantIconFinder.razor.cs b/app/MindWork AI Studio/Components/Pages/IconFinder/AssistantIconFinder.razor.cs new file mode 100644 index 0000000..e595837 --- /dev/null +++ b/app/MindWork AI Studio/Components/Pages/IconFinder/AssistantIconFinder.razor.cs @@ -0,0 +1,65 @@ +using AIStudio.Provider; + +namespace AIStudio.Components.Pages.IconFinder; + +public partial class AssistantIconFinder : AssistantBaseCore +{ + private string inputContext = string.Empty; + private IconSources selectedIconSource; + + protected override string Title => "Icon Finder"; + + protected override string Description => + """ + 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 SystemPrompt => + """ + I can search for icons using US English keywords. Please help me come up with the right search queries. + I don't want you to translate my requests word-for-word into US English. Instead, you should provide keywords + that are likely to yield suitable icons. For example, I might ask for an icon about departments, but icons + related to the keyword "buildings" might be the best match. Provide your keywords in a Markdown list without + quotation marks. + """; + + private string? ValidatingContext(string context) + { + if(string.IsNullOrWhiteSpace(context)) + return "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; + } + + private string? ValidatingProvider(AIStudio.Settings.Provider provider) + { + if(provider.UsedProvider == Providers.NONE) + return "Please select a provider."; + + return null; + } + + private async Task FindIcon() + { + await this.form!.Validate(); + if (!this.inputIsValid) + return; + + this.CreateChatThread(); + var time = this.AddUserRequest( + $""" + {this.selectedIconSource.Prompt()} I search for an icon for the following context: + + ``` + {this.inputContext} + ``` + """); + + await this.AddAIResponseAsync(time); + } +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Pages/IconFinder/IconSourceExtensions.cs b/app/MindWork AI Studio/Components/Pages/IconFinder/IconSourceExtensions.cs new file mode 100644 index 0000000..42acf8c --- /dev/null +++ b/app/MindWork AI Studio/Components/Pages/IconFinder/IconSourceExtensions.cs @@ -0,0 +1,40 @@ +namespace AIStudio.Components.Pages.IconFinder; + +public static class IconSourceExtensions +{ + public static string Name(this IconSources iconSource) => 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, + }; + + 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/", + + _ => string.Empty, + }; +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Pages/IconFinder/IconSources.cs b/app/MindWork AI Studio/Components/Pages/IconFinder/IconSources.cs new file mode 100644 index 0000000..fe477f9 --- /dev/null +++ b/app/MindWork AI Studio/Components/Pages/IconFinder/IconSources.cs @@ -0,0 +1,13 @@ +namespace AIStudio.Components.Pages.IconFinder; + +public enum IconSources +{ + GENERIC, + + ICONS8, + FLAT_ICON, + FONT_AWESOME, + MATERIAL_ICONS, + FEATHER_ICONS, + BOOTSTRAP_ICONS, +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Pages/TextSummarizer/AssistantTextSummarizer.razor b/app/MindWork AI Studio/Components/Pages/TextSummarizer/AssistantTextSummarizer.razor new file mode 100644 index 0000000..56da6e6 --- /dev/null +++ b/app/MindWork AI Studio/Components/Pages/TextSummarizer/AssistantTextSummarizer.razor @@ -0,0 +1,43 @@ +@page "/assistant/summarizer" +@using AIStudio.Settings +@using AIStudio.Tools +@inherits AssistantBaseCore + + + + + + @foreach (var targetLanguage in Enum.GetValues()) + { + @targetLanguage.Name() + } + + @if (this.selectedTargetLanguage is CommonLanguages.OTHER) + { + + } + + + + + @foreach (var targetComplexity in Enum.GetValues()) + { + @targetComplexity.Name() + } + + @if (this.selectedComplexity is Complexity.SCIENTIFIC_LANGUAGE_OTHER_EXPERTS) + { + + } + + + + @foreach (var provider in this.SettingsManager.ConfigurationData.Providers) + { + + } + + + + Summarize + \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Pages/TextSummarizer/AssistantTextSummarizer.razor.cs b/app/MindWork AI Studio/Components/Pages/TextSummarizer/AssistantTextSummarizer.razor.cs new file mode 100644 index 0000000..2bf92e4 --- /dev/null +++ b/app/MindWork AI Studio/Components/Pages/TextSummarizer/AssistantTextSummarizer.razor.cs @@ -0,0 +1,86 @@ +using AIStudio.Provider; +using AIStudio.Tools; + +namespace AIStudio.Components.Pages.TextSummarizer; + +public partial class AssistantTextSummarizer : AssistantBaseCore +{ + protected override string Title => "Text Summarizer"; + + protected override string Description => + """ + 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 SystemPrompt => + """ + You get a long text as input. The user wants to get a summary of the text. + The user might want to change the language of the summary. In this case, + you should provide a summary in the requested language. Eventually, the user + want to change the complexity of the text. In this case, you should provide + a summary with the requested complexity. In any case, do not add any information. + """; + + private string inputText = string.Empty; + private CommonLanguages selectedTargetLanguage; + private string customTargetLanguage = string.Empty; + private Complexity selectedComplexity; + private string expertInField = string.Empty; + + private string? ValidatingText(string text) + { + if(string.IsNullOrWhiteSpace(text)) + return "Please provide a text as input. You might copy the desired text from a document or a website."; + + return null; + } + + private string? ValidatingProvider(AIStudio.Settings.Provider provider) + { + if(provider.UsedProvider == Providers.NONE) + return "Please select a provider."; + + return null; + } + + private string? ValidateCustomLanguage(string language) + { + if(this.selectedTargetLanguage == CommonLanguages.OTHER && string.IsNullOrWhiteSpace(language)) + return "Please provide a custom language."; + + return null; + } + + private string? ValidateExpertInField(string field) + { + if(this.selectedComplexity == Complexity.SCIENTIFIC_LANGUAGE_OTHER_EXPERTS && string.IsNullOrWhiteSpace(field)) + return "Please provide your field of expertise."; + + return null; + } + + private async Task SummarizeText() + { + await this.form!.Validate(); + if (!this.inputIsValid) + return; + + this.CreateChatThread(); + var time = this.AddUserRequest( + $""" + {this.selectedTargetLanguage.Prompt(this.customTargetLanguage)} + {this.selectedComplexity.Prompt(this.expertInField)} + + Please summarize the following text: + + ``` + {this.inputText} + ``` + """); + + await this.AddAIResponseAsync(time); + } +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Pages/TextSummarizer/CommonLanguagePrompts.cs b/app/MindWork AI Studio/Components/Pages/TextSummarizer/CommonLanguagePrompts.cs new file mode 100644 index 0000000..73bd72c --- /dev/null +++ b/app/MindWork AI Studio/Components/Pages/TextSummarizer/CommonLanguagePrompts.cs @@ -0,0 +1,14 @@ +using AIStudio.Tools; + +namespace AIStudio.Components.Pages.TextSummarizer; + +public static class CommonLanguagePrompts +{ + public static string Prompt(this CommonLanguages language, string customLanguage) => language switch + { + CommonLanguages.AS_IS => "Do not change the language of the text.", + CommonLanguages.OTHER => $"Output you summary in {customLanguage}.", + + _ => $"Output your summary in {language.Name()} ({language}).", + }; +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Pages/TextSummarizer/Complexity.cs b/app/MindWork AI Studio/Components/Pages/TextSummarizer/Complexity.cs new file mode 100644 index 0000000..0c9125e --- /dev/null +++ b/app/MindWork AI Studio/Components/Pages/TextSummarizer/Complexity.cs @@ -0,0 +1,13 @@ +namespace AIStudio.Components.Pages.TextSummarizer; + +public enum Complexity +{ + NO_CHANGE, + + SIMPLE_LANGUAGE, + TEEN_LANGUAGE, + EVERYDAY_LANGUAGE, + POPULAR_SCIENCE_LANGUAGE, + SCIENTIFIC_LANGUAGE_FIELD_EXPERTS, + SCIENTIFIC_LANGUAGE_OTHER_EXPERTS, +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Pages/TextSummarizer/ComplexityExtensions.cs b/app/MindWork AI Studio/Components/Pages/TextSummarizer/ComplexityExtensions.cs new file mode 100644 index 0000000..19a335c --- /dev/null +++ b/app/MindWork AI Studio/Components/Pages/TextSummarizer/ComplexityExtensions.cs @@ -0,0 +1,32 @@ +namespace AIStudio.Components.Pages.TextSummarizer; + +public static class ComplexityExtensions +{ + public static string Name(this Complexity complexity) => complexity switch + { + Complexity.NO_CHANGE => "No change in complexity", + + Complexity.SIMPLE_LANGUAGE => "Simple language, e.g., for children", + Complexity.TEEN_LANGUAGE => "Teen language, e.g., for teenagers", + Complexity.EVERYDAY_LANGUAGE => "Everyday language, e.g., for adults", + Complexity.POPULAR_SCIENCE_LANGUAGE => "Popular science language, e.g., for people interested in science", + Complexity.SCIENTIFIC_LANGUAGE_FIELD_EXPERTS => "Scientific language for experts in this field", + Complexity.SCIENTIFIC_LANGUAGE_OTHER_EXPERTS => "Scientific language for experts from other fields (interdisciplinary)", + + _ => "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.", + + 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.", + }; +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Pages/Translator/AssistantTranslator.razor b/app/MindWork AI Studio/Components/Pages/Translator/AssistantTranslator.razor new file mode 100644 index 0000000..80004e9 --- /dev/null +++ b/app/MindWork AI Studio/Components/Pages/Translator/AssistantTranslator.razor @@ -0,0 +1,50 @@ +@page "/assistant/translator" +@using AIStudio.Settings +@using AIStudio.Tools +@inherits AssistantBaseCore + + + + @(this.liveTranslation ? "Live translation" : "No live translation") + + + +@if (this.liveTranslation) +{ + +} +else +{ + +} + + + + @foreach (var targetLanguage in Enum.GetValues()) + { + if (targetLanguage is CommonLanguages.AS_IS) + { + Please select the target language + } + else + { + @targetLanguage.Name() + } + } + + @if (this.selectedTargetLanguage is CommonLanguages.OTHER) + { + + } + + + + @foreach (var provider in this.SettingsManager.ConfigurationData.Providers) + { + + } + + + + Translate + \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Pages/Translator/AssistantTranslator.razor.cs b/app/MindWork AI Studio/Components/Pages/Translator/AssistantTranslator.razor.cs new file mode 100644 index 0000000..cdd022b --- /dev/null +++ b/app/MindWork AI Studio/Components/Pages/Translator/AssistantTranslator.razor.cs @@ -0,0 +1,83 @@ +using AIStudio.Provider; +using AIStudio.Tools; + +namespace AIStudio.Components.Pages.Translator; + +public partial class AssistantTranslator : AssistantBaseCore +{ + protected override string Title => "Translator"; + + protected override string Description => + """ + Translate text from one language to another. + """; + + protected override string SystemPrompt => + """ + You get text in a source language as input. The user wants to get the text translated into a target language. + Provide the translation in the requested language. Do not add any information. Correct any spelling or grammar mistakes. + Do not ask for additional information. Do not mirror the user's language. Do not mirror the task. When the target + language requires, e.g., shorter sentences, you should split the text into shorter sentences. + """; + + private bool liveTranslation; + private string inputText = string.Empty; + private string inputTextLastTranslation = string.Empty; + private CommonLanguages selectedTargetLanguage; + private string customTargetLanguage = string.Empty; + + private string? ValidatingText(string text) + { + if(string.IsNullOrWhiteSpace(text)) + return "Please provide a text as input. You might copy the desired text from a document or a website."; + + return null; + } + + private string? ValidatingProvider(AIStudio.Settings.Provider provider) + { + if(provider.UsedProvider == Providers.NONE) + return "Please select a provider."; + + return null; + } + + private string? ValidatingTargetLanguage(CommonLanguages language) + { + if(language == CommonLanguages.AS_IS) + return "Please select a target language."; + + return null; + } + + private string? ValidateCustomLanguage(string language) + { + if(this.selectedTargetLanguage == CommonLanguages.OTHER && string.IsNullOrWhiteSpace(language)) + return "Please provide a custom language."; + + return null; + } + + private async Task TranslateText(bool force) + { + if (!this.inputIsValid) + return; + + if(!force && this.inputText == this.inputTextLastTranslation) + return; + + this.inputTextLastTranslation = this.inputText; + this.CreateChatThread(); + var time = this.AddUserRequest( + $""" + {this.selectedTargetLanguage.Prompt(this.customTargetLanguage)} + + The given text is: + + --- + {this.inputText} + """); + + await this.AddAIResponseAsync(time); + } +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Pages/Translator/CommonLanguageExtension.cs b/app/MindWork AI Studio/Components/Pages/Translator/CommonLanguageExtension.cs new file mode 100644 index 0000000..3754515 --- /dev/null +++ b/app/MindWork AI Studio/Components/Pages/Translator/CommonLanguageExtension.cs @@ -0,0 +1,13 @@ +using AIStudio.Tools; + +namespace AIStudio.Components.Pages.Translator; + +public static class CommonLanguageExtension +{ + public static string Prompt(this CommonLanguages language, string customLanguage) => language switch + { + CommonLanguages.OTHER => $"Translate the text in {customLanguage}.", + + _ => $"Translate the given text in {language.Name()} ({language}).", + }; +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/CommonLanguageExtensions.cs b/app/MindWork AI Studio/Tools/CommonLanguageExtensions.cs new file mode 100644 index 0000000..5d932a2 --- /dev/null +++ b/app/MindWork AI Studio/Tools/CommonLanguageExtensions.cs @@ -0,0 +1,22 @@ +namespace AIStudio.Tools; + +public static class CommonLanguageExtensions +{ + public static string Name(this CommonLanguages language) => language switch + { + CommonLanguages.AS_IS => "Do not change the language", + + CommonLanguages.EN_US => "English (US)", + CommonLanguages.EN_GB => "English (UK)", + CommonLanguages.ZH_CN => "Chinese (Simplified)", + CommonLanguages.HI_IN => "Hindi (India)", + CommonLanguages.ES_ES => "Spanish (Spain)", + CommonLanguages.FR_FR => "French (France)", + CommonLanguages.DE_DE => "German (Germany)", + CommonLanguages.DE_AT => "German (Austria)", + CommonLanguages.DE_CH => "German (Switzerland)", + CommonLanguages.JA_JP => "Japanese (Japan)", + + _ => "Other", + }; +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/CommonLanguages.cs b/app/MindWork AI Studio/Tools/CommonLanguages.cs new file mode 100644 index 0000000..afa83f6 --- /dev/null +++ b/app/MindWork AI Studio/Tools/CommonLanguages.cs @@ -0,0 +1,19 @@ +namespace AIStudio.Tools; + +public enum CommonLanguages +{ + AS_IS, + + EN_US, + EN_GB, + ZH_CN, + HI_IN, + ES_ES, + FR_FR, + DE_DE, + DE_CH, + DE_AT, + JA_JP, + + OTHER, +} \ No newline at end of file diff --git a/app/MindWork AI Studio/wwwroot/changelog/v0.8.0.md b/app/MindWork AI Studio/wwwroot/changelog/v0.8.0.md new file mode 100644 index 0000000..b2a75b1 --- /dev/null +++ b/app/MindWork AI Studio/wwwroot/changelog/v0.8.0.md @@ -0,0 +1,5 @@ +# v0.8.0, build 162 (2024-07-14 19:39 UTC) +- Added overview of assistants +- Added icon finder assistant +- Added text summarization assistant +- Added translation assistant \ No newline at end of file diff --git a/metadata.txt b/metadata.txt index 5cd1614..783d0a4 100644 --- a/metadata.txt +++ b/metadata.txt @@ -1,9 +1,9 @@ -0.7.1 -2024-07-13 11:42:46 UTC -161 +0.8.0 +2024-07-14 19:39:09 UTC +162 8.0.107 (commit 1bdaef7265) 8.0.7 (commit 2aade6beb0) 1.79.0 (commit 129f3b996) 6.20.0 1.6.1 -d781e48ae66, release +ba6610bd964, release diff --git a/runtime/Cargo.lock b/runtime/Cargo.lock index 06771de..7225ed9 100644 --- a/runtime/Cargo.lock +++ b/runtime/Cargo.lock @@ -2313,7 +2313,7 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mindwork-ai-studio" -version = "0.7.1" +version = "0.8.0" dependencies = [ "arboard", "flexi_logger", diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 4a16c09..e2f33b5 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mindwork-ai-studio" -version = "0.7.1" +version = "0.8.0" edition = "2021" description = "MindWork AI Studio" authors = ["Thorsten Sommer"] diff --git a/runtime/tauri.conf.json b/runtime/tauri.conf.json index 11e3744..dc0a6a0 100644 --- a/runtime/tauri.conf.json +++ b/runtime/tauri.conf.json @@ -6,7 +6,7 @@ }, "package": { "productName": "MindWork AI Studio", - "version": "0.7.1" + "version": "0.8.0" }, "tauri": { "allowlist": {