From 4cb49d9f277c74d0d5e83ad575dccedd584088e2 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Thu, 1 Aug 2024 21:53:28 +0200 Subject: [PATCH] Allow reading web content into assistants (#63) --- app/MindWork AI Studio/Agents/AgentBase.cs | 109 ++++++++ .../Agents/AgentTextContentCleaner.cs | 94 +++++++ app/MindWork AI Studio/Agents/IAgent.cs | 55 ++++ app/MindWork AI Studio/Agents/Type.cs | 27 ++ app/MindWork AI Studio/Chat/ChatRole.cs | 1 + .../Components/AssistantBase.razor.cs | 3 +- .../Components/Blocks/Changelog.Logs.cs | 1 + .../Components/Blocks/ReadWebContent.razor | 31 +++ .../Components/Blocks/ReadWebContent.razor.cs | 198 ++++++++++++++ .../Components/Blocks/ReadWebContentSteps.cs | 10 + .../Components/Blocks/Workspaces.razor.cs | 6 +- .../Components/Pages/About.razor | 2 + .../Components/Pages/Chat.razor.cs | 2 +- .../Components/Pages/Settings.razor | 20 +- .../AssistantTextSummarizer.razor | 11 +- .../AssistantTextSummarizer.razor.cs | 1 + .../Translation/AssistantTranslation.razor | 13 +- .../Translation/AssistantTranslation.razor.cs | 1 + .../MindWork AI Studio.csproj | 2 + app/MindWork AI Studio/Program.cs | 5 +- .../Provider/Anthropic/ProviderAnthropic.cs | 1 + .../Provider/Fireworks/ProviderFireworks.cs | 1 + .../Provider/Mistral/ProviderMistral.cs | 1 + .../Provider/OpenAI/ProviderOpenAI.cs | 1 + .../Provider/SelfHosted/ProviderSelfHosted.cs | 1 + .../Settings/DataModel/Data.cs | 45 +++ app/MindWork AI Studio/Tools/HTMLParser.cs | 57 ++++ app/MindWork AI Studio/Tools/Process.cs | 67 +++++ .../Tools/ProcessStepValue.cs | 258 ++++++++++++++++++ .../Tools/ThreadSafeRandom.cs | 88 ++++++ app/MindWork AI Studio/packages.lock.json | 17 +- .../wwwroot/changelog/v0.8.6.md | 8 +- metadata.txt | 8 +- runtime/Cargo.lock | 2 +- runtime/Cargo.toml | 2 +- runtime/tauri.conf.json | 2 +- 36 files changed, 1127 insertions(+), 24 deletions(-) create mode 100644 app/MindWork AI Studio/Agents/AgentBase.cs create mode 100644 app/MindWork AI Studio/Agents/AgentTextContentCleaner.cs create mode 100644 app/MindWork AI Studio/Agents/IAgent.cs create mode 100644 app/MindWork AI Studio/Agents/Type.cs create mode 100644 app/MindWork AI Studio/Components/Blocks/ReadWebContent.razor create mode 100644 app/MindWork AI Studio/Components/Blocks/ReadWebContent.razor.cs create mode 100644 app/MindWork AI Studio/Components/Blocks/ReadWebContentSteps.cs create mode 100644 app/MindWork AI Studio/Tools/HTMLParser.cs create mode 100644 app/MindWork AI Studio/Tools/Process.cs create mode 100644 app/MindWork AI Studio/Tools/ProcessStepValue.cs create mode 100644 app/MindWork AI Studio/Tools/ThreadSafeRandom.cs diff --git a/app/MindWork AI Studio/Agents/AgentBase.cs b/app/MindWork AI Studio/Agents/AgentBase.cs new file mode 100644 index 0000000..191ca27 --- /dev/null +++ b/app/MindWork AI Studio/Agents/AgentBase.cs @@ -0,0 +1,109 @@ +using AIStudio.Chat; +using AIStudio.Provider; +using AIStudio.Settings; +using AIStudio.Tools; + +// ReSharper disable MemberCanBePrivate.Global + +namespace AIStudio.Agents; + +public abstract class AgentBase(SettingsManager settingsManager, IJSRuntime jsRuntime, ThreadSafeRandom rng) : IAgent +{ + protected SettingsManager SettingsManager { get; init; } = settingsManager; + + protected IJSRuntime JsRuntime { get; init; } = jsRuntime; + + protected ThreadSafeRandom RNG { get; init; } = rng; + + /// + /// Represents the type or category of this agent. + /// + protected abstract Type Type { get; } + + /// + /// The name of the agent. + /// + public abstract string Id { get; } + + /// + /// The agent's job description. Will be used for the system prompt. + /// + protected abstract string JobDescription { get; } + + /// + /// Represents the system prompt provided for the agent. + /// + protected abstract string SystemPrompt(string additionalData); + + #region Implementation of IAgent + + public abstract AIStudio.Settings.Provider? ProviderSettings { get; set; } + + public abstract Task ProcessContext(ChatThread chatThread, IDictionary additionalData); + + public abstract Task ProcessInput(ContentBlock input, IDictionary additionalData); + + public abstract Task MadeDecision(ContentBlock input); + + public abstract IReadOnlyCollection GetContext(); + + public abstract IReadOnlyCollection GetAnswers(); + + #endregion + + protected ChatThread CreateChatThread(string systemPrompt) => new() + { + WorkspaceId = Guid.Empty, + ChatId = Guid.NewGuid(), + Name = string.Empty, + Seed = this.RNG.Next(), + SystemPrompt = systemPrompt, + Blocks = [], + }; + + protected DateTimeOffset AddUserRequest(ChatThread thread, string request) + { + var time = DateTimeOffset.Now; + thread.Blocks.Add(new ContentBlock + { + Time = time, + ContentType = ContentType.TEXT, + Role = ChatRole.USER, + Content = new ContentText + { + Text = request, + }, + }); + + return time; + } + + protected async Task AddAIResponseAsync(ChatThread thread, DateTimeOffset time) + { + if(this.ProviderSettings is null) + return; + + var providerSettings = this.ProviderSettings.Value; + var aiText = new ContentText + { + // We have to wait for the remote + // for the content stream: + InitialRemoteWait = true, + }; + + var resultingContentBlock = new ContentBlock + { + Time = time, + ContentType = ContentType.TEXT, + Role = ChatRole.AI, + Content = aiText, + }; + + thread.Blocks.Add(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(providerSettings.CreateProvider(), this.JsRuntime, this.SettingsManager, providerSettings.Model, thread); + } +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Agents/AgentTextContentCleaner.cs b/app/MindWork AI Studio/Agents/AgentTextContentCleaner.cs new file mode 100644 index 0000000..83fe48f --- /dev/null +++ b/app/MindWork AI Studio/Agents/AgentTextContentCleaner.cs @@ -0,0 +1,94 @@ +using AIStudio.Chat; +using AIStudio.Settings; +using AIStudio.Tools; + +namespace AIStudio.Agents; + +public sealed class AgentTextContentCleaner(SettingsManager settingsManager, IJSRuntime jsRuntime, ThreadSafeRandom rng) : AgentBase(settingsManager, jsRuntime, rng) +{ + private static readonly ContentBlock EMPTY_BLOCK = new() + { + Content = null, + ContentType = ContentType.NONE, + Role = ChatRole.AGENT, + Time = DateTimeOffset.UtcNow, + }; + + private readonly List context = new(); + private readonly List answers = new(); + + #region Overrides of AgentBase + + public override Settings.Provider? ProviderSettings { get; set; } + + protected override Type Type => Type.SYSTEM; + + public override string Id => "Text Content Cleaner"; + + protected override string JobDescription => + """ + You receive a Markdown document as input. Your goal is to identify the main content of the document + and return it including Markdown formatting. Remove areas that do not belong to the main part of the + document. For a blog article, return only the text of the article with its formatting. For a scientific + paper, only the contents of the paper. Delete elements of navigation, advertisements, HTML artifacts, + cookie banners, etc. If the content contains images, these images remain. The same applies to links. + Ensure that links and images are present as valid Markdown: + + - Syntax of links: [link text](URL) + - Syntax of images: ![alt text](URL) + + If you find relative links or images with relative paths, correct them to absolute paths. For this + purpose, here is the source URL: + """; + + protected override string SystemPrompt(string additionalData) => $"{this.JobDescription} `{additionalData}`."; + + /// + public override async Task ProcessContext(ChatThread chatThread, IDictionary additionalData) + { + // We process the last block of the chat thread. Then, we add the result + // to the chat thread as the last block: + var answer = await this.ProcessInput(chatThread.Blocks[^1], additionalData); + chatThread.Blocks.Add(answer); + + this.context.Clear(); + this.context.AddRange(chatThread.Blocks); + + return chatThread; + } + + // + public override async Task ProcessInput(ContentBlock input, IDictionary additionalData) + { + if (input.Content is not ContentText text) + return EMPTY_BLOCK; + + if(text.InitialRemoteWait || text.IsStreaming) + return EMPTY_BLOCK; + + if(string.IsNullOrWhiteSpace(text.Text)) + return EMPTY_BLOCK; + + if(!additionalData.TryGetValue("sourceURL", out var sourceURL) || string.IsNullOrWhiteSpace(sourceURL)) + return EMPTY_BLOCK; + + var thread = this.CreateChatThread(this.SystemPrompt(sourceURL)); + var time = this.AddUserRequest(thread, text.Text); + await this.AddAIResponseAsync(thread, time); + + var answer = thread.Blocks[^1]; + this.answers.Add(answer); + return answer; + } + + // + public override Task MadeDecision(ContentBlock input) => Task.FromResult(true); + + // + public override IReadOnlyCollection GetContext() => this.context; + + // + public override IReadOnlyCollection GetAnswers() => this.answers; + + #endregion +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Agents/IAgent.cs b/app/MindWork AI Studio/Agents/IAgent.cs new file mode 100644 index 0000000..e101f2e --- /dev/null +++ b/app/MindWork AI Studio/Agents/IAgent.cs @@ -0,0 +1,55 @@ +using AIStudio.Chat; + +namespace AIStudio.Agents; + +public interface IAgent +{ + /// + /// Gets the name of the agent. + /// + public string Id { get; } + + /// + /// The provider to use for this agent. + /// + public AIStudio.Settings.Provider? ProviderSettings { get; set; } + + /// + /// Processes a chat thread (i.e., context) and returns the updated thread. + /// + /// The chat thread to process. The thread is the context for the agent. + /// Additional data to use for processing the chat thread. + /// The updated chat thread. The last content block of the thread is the agent's response. + public Task ProcessContext(ChatThread chatThread, IDictionary additionalData); + + /// + /// Processes the input content block and returns the agent's response. + /// + /// The content block to process. It represents the input. + /// Additional data to use for processing the input. + /// The content block representing the agent's response. + public Task ProcessInput(ContentBlock input, IDictionary additionalData); + + /// + /// The agent makes a decision based on the input. + /// + /// The content block to process. Should be a question or a request. + /// + /// True if a decision has been made based on the input, false otherwise. + /// + public Task MadeDecision(ContentBlock input); + + /// + /// Retrieves the context of the agent. + /// + /// The collection of content blocks representing the agent's context. This includes the user's and the other agent's messages. + public IReadOnlyCollection GetContext(); + + /// + /// Retrieves the answers from the agent's context. + /// + /// + /// The collection of content blocks representing the answers provided by this agent. + /// + public IReadOnlyCollection GetAnswers(); +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Agents/Type.cs b/app/MindWork AI Studio/Agents/Type.cs new file mode 100644 index 0000000..559f100 --- /dev/null +++ b/app/MindWork AI Studio/Agents/Type.cs @@ -0,0 +1,27 @@ +namespace AIStudio.Agents; + +public enum Type +{ + /// + /// Represents an unspecified agent type. + /// + UNSPECIFIED = 0, + + /// + /// Represents a conversational agent who produces human-like responses and feedback (depending on the context and its job description). + /// For example, an expert agent for a specific domain. Answers might be detailed and informative. + /// + CONVERSATIONAL, + + /// + /// Represents a worker agent type who performs tasks and provides information or services (depending on the context and its job description). + /// For example, a quality assurance agent who assesses the quality of a product or service. Answers might be short and concise. + /// + WORKER, + + /// + /// Represents the system agent type who processes the input and provides a specific response (depending on the context and its job description). + /// For example, a HTML content agent who processes the arbitrary HTML content and provides a structured Markdown response. Answers might be structured and formatted. + /// + SYSTEM, +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Chat/ChatRole.cs b/app/MindWork AI Studio/Chat/ChatRole.cs index 2b8712b..339be97 100644 --- a/app/MindWork AI Studio/Chat/ChatRole.cs +++ b/app/MindWork AI Studio/Chat/ChatRole.cs @@ -11,6 +11,7 @@ public enum ChatRole SYSTEM, USER, AI, + AGENT, } /// diff --git a/app/MindWork AI Studio/Components/AssistantBase.razor.cs b/app/MindWork AI Studio/Components/AssistantBase.razor.cs index a2e46ea..5ef9e70 100644 --- a/app/MindWork AI Studio/Components/AssistantBase.razor.cs +++ b/app/MindWork AI Studio/Components/AssistantBase.razor.cs @@ -1,6 +1,7 @@ using AIStudio.Chat; using AIStudio.Provider; using AIStudio.Settings; +using AIStudio.Tools; using Microsoft.AspNetCore.Components; @@ -15,7 +16,7 @@ public abstract partial class AssistantBase : ComponentBase protected IJSRuntime JsRuntime { get; init; } = null!; [Inject] - protected Random RNG { get; set; } = null!; + protected ThreadSafeRandom RNG { get; init; } = null!; protected abstract string Title { get; } diff --git a/app/MindWork AI Studio/Components/Blocks/Changelog.Logs.cs b/app/MindWork AI Studio/Components/Blocks/Changelog.Logs.cs index 244198c..833794a 100644 --- a/app/MindWork AI Studio/Components/Blocks/Changelog.Logs.cs +++ b/app/MindWork AI Studio/Components/Blocks/Changelog.Logs.cs @@ -13,6 +13,7 @@ public partial class Changelog public static readonly Log[] LOGS = [ + new (168, "v0.8.6, build 168 (2024-08-01 19:50 UTC)", "v0.8.6.md"), new (167, "v0.8.5, build 167 (2024-07-28 16:44 UTC)", "v0.8.5.md"), new (166, "v0.8.4, build 166 (2024-07-26 06:53 UTC)", "v0.8.4.md"), new (165, "v0.8.3, build 165 (2024-07-25 13:25 UTC)", "v0.8.3.md"), diff --git a/app/MindWork AI Studio/Components/Blocks/ReadWebContent.razor b/app/MindWork AI Studio/Components/Blocks/ReadWebContent.razor new file mode 100644 index 0000000..8b33a12 --- /dev/null +++ b/app/MindWork AI Studio/Components/Blocks/ReadWebContent.razor @@ -0,0 +1,31 @@ + + + + @(this.showWebContentReader ? "Show web content options" : "Hide web content options") + + + + @if (this.showWebContentReader) + { + + + @(this.useContentCleanerAgent ? "The content is cleaned using an LLM agent: the main content is extracted, advertisements and other irrelevant things are attempted to be removed; relative links are attempted to be converted into absolute links so that they can be used." : "No content cleaning") + + + + + + Fetch + + + @if (this.AgentIsRunning) + { +
+ +
+
+ +
+ } + } +
\ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Blocks/ReadWebContent.razor.cs b/app/MindWork AI Studio/Components/Blocks/ReadWebContent.razor.cs new file mode 100644 index 0000000..56cbd60 --- /dev/null +++ b/app/MindWork AI Studio/Components/Blocks/ReadWebContent.razor.cs @@ -0,0 +1,198 @@ +using AIStudio.Agents; +using AIStudio.Chat; +using AIStudio.Settings; +using AIStudio.Tools; + +using Microsoft.AspNetCore.Components; + +namespace AIStudio.Components.Blocks; + +public partial class ReadWebContent : ComponentBase +{ + [Inject] + private HTMLParser HTMLParser { get; init; } = null!; + + [Inject] + private AgentTextContentCleaner AgentTextContentCleaner { get; init; } = null!; + + [Inject] + protected SettingsManager SettingsManager { get; set; } = null!; + + [Inject] + protected IJSRuntime JsRuntime { get; init; } = null!; + + [Parameter] + public string Content { get; set; } = string.Empty; + + [Parameter] + public EventCallback ContentChanged { get; set; } + + [Parameter] + public Settings.Provider ProviderSettings { get; set; } + + [Parameter] + public bool AgentIsRunning { get; set; } + + [Parameter] + public EventCallback AgentIsRunningChanged { get; set; } + + [Parameter] + public bool Preselect { get; set; } + + [Parameter] + public bool PreselectContentCleanerAgent { get; set; } + + private Process process = Process.INSTANCE; + private ProcessStepValue processStep; + + private bool showWebContentReader; + private bool useContentCleanerAgent; + private string providedURL = string.Empty; + private bool urlIsValid; + private bool isProviderValid; + + private Settings.Provider providerSettings; + + #region Overrides of ComponentBase + + protected override async Task OnInitializedAsync() + { + if(this.Preselect) + this.showWebContentReader = true; + + if(this.PreselectContentCleanerAgent) + this.useContentCleanerAgent = true; + + if (this.SettingsManager.ConfigurationData.PreselectAgentTextContentCleanerOptions) + this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.PreselectedAgentTextContentCleanerProvider); + else + this.providerSettings = this.ProviderSettings; + + await base.OnInitializedAsync(); + } + + protected override async Task OnParametersSetAsync() + { + if (!this.SettingsManager.ConfigurationData.PreselectAgentTextContentCleanerOptions) + this.providerSettings = this.ProviderSettings; + + await base.OnParametersSetAsync(); + } + + #endregion + + private async Task LoadFromWeb() + { + if(!this.IsReady) + return; + + var markdown = string.Empty; + try + { + this.processStep = this.process[ReadWebContentSteps.LOADING]; + this.StateHasChanged(); + + var html = await this.HTMLParser.LoadWebContentHTML(new Uri(this.providedURL)); + + this.processStep = this.process[ReadWebContentSteps.PARSING]; + this.StateHasChanged(); + markdown = this.HTMLParser.ParseToMarkdown(html); + + if (this.useContentCleanerAgent) + { + this.AgentTextContentCleaner.ProviderSettings = this.providerSettings; + var additionalData = new Dictionary + { + { "sourceURL", this.providedURL }, + }; + + this.processStep = this.process[ReadWebContentSteps.CLEANING]; + this.AgentIsRunning = true; + await this.AgentIsRunningChanged.InvokeAsync(this.AgentIsRunning); + this.StateHasChanged(); + + var contentBlock = await this.AgentTextContentCleaner.ProcessInput(new ContentBlock + { + Time = DateTimeOffset.UtcNow, + ContentType = ContentType.TEXT, + Role = ChatRole.USER, + Content = new ContentText + { + Text = markdown, + }, + }, additionalData); + + markdown = contentBlock.Content is ContentText text ? text.Text : markdown; + + this.processStep = this.process[ReadWebContentSteps.DONE]; + this.AgentIsRunning = false; + await this.AgentIsRunningChanged.InvokeAsync(this.AgentIsRunning); + this.StateHasChanged(); + } + } + catch + { + if (this.AgentIsRunning) + { + this.processStep = this.process[ReadWebContentSteps.START]; + this.AgentIsRunning = false; + await this.AgentIsRunningChanged.InvokeAsync(this.AgentIsRunning); + this.StateHasChanged(); + } + } + + this.Content = markdown; + await this.ContentChanged.InvokeAsync(this.Content); + } + + private bool IsReady + { + get + { + if(!this.urlIsValid) + return false; + + if(this.useContentCleanerAgent && !this.isProviderValid) + return false; + + return true; + } + } + + private string? ValidateProvider(bool shouldUseAgent) + { + if(shouldUseAgent && this.providerSettings == default) + { + this.isProviderValid = false; + return "Please select a provider to use the cleanup agent."; + } + + this.isProviderValid = true; + return null; + } + + private string? ValidateURL(string url) + { + if(string.IsNullOrWhiteSpace(url)) + { + this.urlIsValid = false; + return "Please provide a URL to load the content from."; + } + + var urlParsingResult = Uri.TryCreate(url, UriKind.Absolute, out var uriResult); + if(!urlParsingResult) + { + this.urlIsValid = false; + return "Please provide a valid URL."; + } + + if(uriResult is not { Scheme: "http" or "https" }) + { + this.urlIsValid = false; + return "Please provide a valid HTTP or HTTPS URL."; + } + + this.urlIsValid = true; + return null; + } +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Blocks/ReadWebContentSteps.cs b/app/MindWork AI Studio/Components/Blocks/ReadWebContentSteps.cs new file mode 100644 index 0000000..3dafa01 --- /dev/null +++ b/app/MindWork AI Studio/Components/Blocks/ReadWebContentSteps.cs @@ -0,0 +1,10 @@ +namespace AIStudio.Components.Blocks; + +public enum ReadWebContentSteps +{ + START, + LOADING, + PARSING, + CLEANING, + DONE, +} diff --git a/app/MindWork AI Studio/Components/Blocks/Workspaces.razor.cs b/app/MindWork AI Studio/Components/Blocks/Workspaces.razor.cs index 02ef041..19802ef 100644 --- a/app/MindWork AI Studio/Components/Blocks/Workspaces.razor.cs +++ b/app/MindWork AI Studio/Components/Blocks/Workspaces.razor.cs @@ -16,13 +16,13 @@ namespace AIStudio.Components.Blocks; public partial class Workspaces : ComponentBase { [Inject] - private SettingsManager SettingsManager { get; set; } = null!; + private SettingsManager SettingsManager { get; init; } = null!; [Inject] - private IDialogService DialogService { get; set; } = null!; + private IDialogService DialogService { get; init; } = null!; [Inject] - public Random RNG { get; set; } = null!; + private ThreadSafeRandom RNG { get; init; } = null!; [Parameter] public ChatThread? CurrentChatThread { get; set; } diff --git a/app/MindWork AI Studio/Components/Pages/About.razor b/app/MindWork AI Studio/Components/Pages/About.razor index 6aa02ba..0f29700 100644 --- a/app/MindWork AI Studio/Components/Pages/About.razor +++ b/app/MindWork AI Studio/Components/Pages/About.razor @@ -47,6 +47,8 @@ + + diff --git a/app/MindWork AI Studio/Components/Pages/Chat.razor.cs b/app/MindWork AI Studio/Components/Pages/Chat.razor.cs index d880982..05eae50 100644 --- a/app/MindWork AI Studio/Components/Pages/Chat.razor.cs +++ b/app/MindWork AI Studio/Components/Pages/Chat.razor.cs @@ -25,7 +25,7 @@ public partial class Chat : MSGComponentBase, IAsyncDisposable public IJSRuntime JsRuntime { get; init; } = null!; [Inject] - public Random RNG { get; set; } = null!; + private ThreadSafeRandom RNG { get; init; } = null!; [Inject] public IDialogService DialogService { get; set; } = null!; diff --git a/app/MindWork AI Studio/Components/Pages/Settings.razor b/app/MindWork AI Studio/Components/Pages/Settings.razor index 6551a72..0f0e788 100644 --- a/app/MindWork AI Studio/Components/Pages/Settings.razor +++ b/app/MindWork AI Studio/Components/Pages/Settings.razor @@ -82,7 +82,7 @@ - Assistants Options + Assistant Options Icon Finder Options @@ -93,8 +93,11 @@ Translator Options + + + @if (this.SettingsManager.ConfigurationData.PreselectedTranslationTargetLanguage is CommonLanguages.OTHER) @@ -117,8 +120,11 @@ Text Summarizer Options + + + @if (this.SettingsManager.ConfigurationData.PreselectedTextSummarizerTargetLanguage is CommonLanguages.OTHER) { @@ -131,5 +137,17 @@ } + + LLM Agent Options + + Text Content Cleaner Agent + + + Use Case: this agent is used to clean up text content. It extracts the main content, removes advertisements and other irrelevant things, + and attempts to convert relative links into absolute links so that they can be used. + + + + \ 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 index d290541..82f138e 100644 --- a/app/MindWork AI Studio/Components/Pages/TextSummarizer/AssistantTextSummarizer.razor +++ b/app/MindWork AI Studio/Components/Pages/TextSummarizer/AssistantTextSummarizer.razor @@ -3,7 +3,12 @@ @using AIStudio.Tools @inherits AssistantBaseCore - +@if (!this.SettingsManager.ConfigurationData.HideWebContentReaderForTextSummarizer) +{ + +} + + @@ -31,13 +36,13 @@ } - + @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 index 829206d..9a1b3f8 100644 --- a/app/MindWork AI Studio/Components/Pages/TextSummarizer/AssistantTextSummarizer.razor.cs +++ b/app/MindWork AI Studio/Components/Pages/TextSummarizer/AssistantTextSummarizer.razor.cs @@ -24,6 +24,7 @@ public partial class AssistantTextSummarizer : AssistantBaseCore """; private string inputText = string.Empty; + private bool isAgentRunning; private CommonLanguages selectedTargetLanguage; private string customTargetLanguage = string.Empty; private Complexity selectedComplexity; diff --git a/app/MindWork AI Studio/Components/Pages/Translation/AssistantTranslation.razor b/app/MindWork AI Studio/Components/Pages/Translation/AssistantTranslation.razor index 8d14032..2b03eca 100644 --- a/app/MindWork AI Studio/Components/Pages/Translation/AssistantTranslation.razor +++ b/app/MindWork AI Studio/Components/Pages/Translation/AssistantTranslation.razor @@ -3,6 +3,11 @@ @using AIStudio.Tools @inherits AssistantBaseCore +@if (!this.SettingsManager.ConfigurationData.HideWebContentReaderForTranslation) +{ + +} + @(this.liveTranslation ? "Live translation" : "No live translation") @@ -11,11 +16,11 @@ @if (this.liveTranslation) { - + } else { - + } @@ -38,13 +43,13 @@ else } - + @foreach (var provider in this.SettingsManager.ConfigurationData.Providers) { } - + Translate \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/Pages/Translation/AssistantTranslation.razor.cs b/app/MindWork AI Studio/Components/Pages/Translation/AssistantTranslation.razor.cs index 1ae77c1..e21dcd3 100644 --- a/app/MindWork AI Studio/Components/Pages/Translation/AssistantTranslation.razor.cs +++ b/app/MindWork AI Studio/Components/Pages/Translation/AssistantTranslation.razor.cs @@ -20,6 +20,7 @@ public partial class AssistantTranslation : AssistantBaseCore """; private bool liveTranslation; + private bool isAgentRunning; private string inputText = string.Empty; private string inputTextLastTranslation = string.Empty; private CommonLanguages selectedTargetLanguage; diff --git a/app/MindWork AI Studio/MindWork AI Studio.csproj b/app/MindWork AI Studio/MindWork AI Studio.csproj index 9d6605a..a24bc83 100644 --- a/app/MindWork AI Studio/MindWork AI Studio.csproj +++ b/app/MindWork AI Studio/MindWork AI Studio.csproj @@ -45,9 +45,11 @@ + + diff --git a/app/MindWork AI Studio/Program.cs b/app/MindWork AI Studio/Program.cs index 1ca814e..5bc114a 100644 --- a/app/MindWork AI Studio/Program.cs +++ b/app/MindWork AI Studio/Program.cs @@ -1,4 +1,5 @@ using AIStudio; +using AIStudio.Agents; using AIStudio.Components; using AIStudio.Settings; using AIStudio.Tools; @@ -29,7 +30,9 @@ builder.Services.AddSingleton(MessageBus.INSTANCE); builder.Services.AddSingleton(); builder.Services.AddMudMarkdownClipboardService(); builder.Services.AddSingleton(); -builder.Services.AddSingleton(); +builder.Services.AddSingleton(); +builder.Services.AddTransient(); +builder.Services.AddTransient(); builder.Services.AddHostedService(); builder.Services.AddHostedService(); builder.Services.AddRazorComponents() diff --git a/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs b/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs index 89c6fe0..ffeb255 100644 --- a/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs +++ b/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs @@ -41,6 +41,7 @@ public sealed class ProviderAnthropic() : BaseProvider("https://api.anthropic.co { ChatRole.USER => "user", ChatRole.AI => "assistant", + ChatRole.AGENT => "assistant", _ => "user", }, diff --git a/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs b/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs index 2f6d1ea..cf29a6d 100644 --- a/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs +++ b/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs @@ -52,6 +52,7 @@ public class ProviderFireworks() : BaseProvider("https://api.fireworks.ai/infere { ChatRole.USER => "user", ChatRole.AI => "assistant", + ChatRole.AGENT => "assistant", ChatRole.SYSTEM => "system", _ => "user", diff --git a/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs b/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs index 95256fb..c351081 100644 --- a/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs +++ b/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs @@ -51,6 +51,7 @@ public sealed class ProviderMistral() : BaseProvider("https://api.mistral.ai/v1/ { ChatRole.USER => "user", ChatRole.AI => "assistant", + ChatRole.AGENT => "assistant", ChatRole.SYSTEM => "system", _ => "user", diff --git a/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs b/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs index a18a403..6e4af60 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs @@ -55,6 +55,7 @@ public sealed class ProviderOpenAI() : BaseProvider("https://api.openai.com/v1/" { ChatRole.USER => "user", ChatRole.AI => "assistant", + ChatRole.AGENT => "assistant", ChatRole.SYSTEM => "system", _ => "user", diff --git a/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs b/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs index 7790d2e..623c3b1 100644 --- a/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs +++ b/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs @@ -44,6 +44,7 @@ public sealed class ProviderSelfHosted(Settings.Provider provider) : BaseProvide { ChatRole.USER => "user", ChatRole.AI => "assistant", + ChatRole.AGENT => "assistant", ChatRole.SYSTEM => "system", _ => "user", diff --git a/app/MindWork AI Studio/Settings/DataModel/Data.cs b/app/MindWork AI Studio/Settings/DataModel/Data.cs index 26639b6..7ed6022 100644 --- a/app/MindWork AI Studio/Settings/DataModel/Data.cs +++ b/app/MindWork AI Studio/Settings/DataModel/Data.cs @@ -120,6 +120,21 @@ public sealed class Data ///
public bool PreselectLiveTranslation { get; set; } + /// + /// Hide the web content reader? + /// + public bool HideWebContentReaderForTranslation { get; set; } + + /// + /// Preselect the web content reader? + /// + public bool PreselectWebContentReaderForTranslation { get; set; } + + /// + /// Preselect the content cleaner agent? + /// + public bool PreselectContentCleanerAgentForTranslation { get; set; } + /// /// Preselect the target language? /// @@ -173,6 +188,22 @@ public sealed class Data /// public bool PreselectTextSummarizerOptions { get; set; } + + /// + /// Hide the web content reader? + /// + public bool HideWebContentReaderForTextSummarizer { get; set; } + + /// + /// Preselect the web content reader? + /// + public bool PreselectWebContentReaderForTextSummarizer { get; set; } + + /// + /// Preselect the content cleaner agent? + /// + public bool PreselectContentCleanerAgentForTextSummarizer { get; set; } + /// /// Preselect the target language? /// @@ -199,4 +230,18 @@ public sealed class Data public string PreselectedTextSummarizerProvider { get; set; } = string.Empty; #endregion + + #region Agent: Text Content Cleaner Settings + + /// + /// Preselect any text content cleaner options? + /// + public bool PreselectAgentTextContentCleanerOptions { get; set; } + + /// + /// Preselect a text content cleaner provider? + /// + public string PreselectedAgentTextContentCleanerProvider { get; set; } = string.Empty; + + #endregion } \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/HTMLParser.cs b/app/MindWork AI Studio/Tools/HTMLParser.cs new file mode 100644 index 0000000..4f9dca2 --- /dev/null +++ b/app/MindWork AI Studio/Tools/HTMLParser.cs @@ -0,0 +1,57 @@ +using System.Net; +using System.Text; + +using HtmlAgilityPack; + +using ReverseMarkdown; + +namespace AIStudio.Tools; + +public sealed class HTMLParser +{ + private static readonly Config MARKDOWN_PARSER_CONFIG = new() + { + UnknownTags = Config.UnknownTagsOption.Bypass, + RemoveComments = true, + SmartHrefHandling = true + }; + + /// + /// Loads the web content from the specified URL. + /// + /// The URL of the web page. + /// The web content as text. + public async Task LoadWebContentText(Uri url) + { + var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)); + var parser = new HtmlWeb(); + var doc = await parser.LoadFromWebAsync(url, Encoding.UTF8, new NetworkCredential(), cts.Token); + return doc.ParsedText; + } + + /// + /// Loads the web content from the specified URL and returns it as an HTML string. + /// + /// The URL of the web page. + /// The web content as an HTML string. + public async Task LoadWebContentHTML(Uri url) + { + var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)); + var parser = new HtmlWeb(); + var doc = await parser.LoadFromWebAsync(url, Encoding.UTF8, new NetworkCredential(), cts.Token); + var innerHtml = doc.DocumentNode.InnerHtml; + + return innerHtml; + } + + /// + /// Converts HTML content to the Markdown format. + /// + /// The HTML content to parse. + /// The converted Markdown content. + public string ParseToMarkdown(string html) + { + var markdownConverter = new Converter(MARKDOWN_PARSER_CONFIG); + return markdownConverter.Convert(html); + } +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/Process.cs b/app/MindWork AI Studio/Tools/Process.cs new file mode 100644 index 0000000..5348891 --- /dev/null +++ b/app/MindWork AI Studio/Tools/Process.cs @@ -0,0 +1,67 @@ +using System.Text; + +namespace AIStudio.Tools; + +public sealed class Process where T : struct, Enum +{ + public static readonly Process INSTANCE = new(); + + private readonly Dictionary stepsData = []; + private readonly int min = int.MaxValue; + private readonly int max = int.MinValue; + private readonly string[] labels; + + private Process() + { + var values = Enum.GetValues(); + this.labels = new string[values.Length]; + + for (var i = 0; i < values.Length; i++) + { + var value = values[i]; + var stepValue = Convert.ToInt32(value); + var stepName = DeriveName(value); + + this.labels[i] = stepName; + this.stepsData[value] = new ProcessStepValue(stepValue, stepName); + + if (stepValue < this.min) + this.min = stepValue; + + if (stepValue > this.max) + this.max = stepValue; + } + } + + private static string DeriveName(T value) + { + var text = value.ToString(); + if (!text.Contains('_')) + { + text = text.ToLowerInvariant(); + text = char.ToUpperInvariant(text[0]) + text[1..]; + } + else + { + var parts = text.Split('_'); + var sb = new StringBuilder(); + foreach (var part in parts) + { + sb.Append(char.ToUpperInvariant(part[0])); + sb.Append(part[1..].ToLowerInvariant()); + } + + text = sb.ToString(); + } + + return text; + } + + public string[] Labels => this.labels; + + public int Min => this.min; + + public int Max => this.max; + + public ProcessStepValue this[T step] => this.stepsData[step]; +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ProcessStepValue.cs b/app/MindWork AI Studio/Tools/ProcessStepValue.cs new file mode 100644 index 0000000..b75b5e0 --- /dev/null +++ b/app/MindWork AI Studio/Tools/ProcessStepValue.cs @@ -0,0 +1,258 @@ +using System.Globalization; +using System.Numerics; + +namespace AIStudio.Tools; + +public readonly record struct ProcessStepValue(int Step, string Name) : INumber +{ + public static implicit operator int(ProcessStepValue process) => process.Step; + + #region INumber implementation + + #region Implementation of IComparable + + public int CompareTo(object? obj) => this.Step.CompareTo(obj); + + #endregion + + #region Implementation of IComparable + + public int CompareTo(ProcessStepValue other) => this.Step.CompareTo(other.Step); + + #endregion + + #region Implementation of IFormattable + + public string ToString(string? format, IFormatProvider? formatProvider) => this.Step.ToString(format, formatProvider); + + #endregion + + #region Implementation of IParsable + + public static ProcessStepValue Parse(string s, IFormatProvider? provider) => new(int.Parse(s, provider), string.Empty); + + public static bool TryParse(string? s, IFormatProvider? provider, out ProcessStepValue result) + { + if (int.TryParse(s, provider, out var stepValue)) + { + result = new ProcessStepValue(stepValue, string.Empty); + return true; + } + + result = default; + return false; + } + #endregion + + #region Implementation of ISpanFormattable + + public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) => this.Step.TryFormat(destination, out charsWritten, format, provider); + + #endregion + + #region Implementation of ISpanParsable + + public static ProcessStepValue Parse(ReadOnlySpan s, IFormatProvider? provider) => new(int.Parse(s, provider), string.Empty); + + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, out ProcessStepValue result) + { + if (int.TryParse(s, provider, out int stepValue)) + { + result = new ProcessStepValue(stepValue, string.Empty); + return true; + } + + result = default; + return false; + } + + #endregion + + #region Implementation of IAdditionOperators + + public static ProcessStepValue operator +(ProcessStepValue left, ProcessStepValue right) => left with { Step = left.Step + right.Step }; + + #endregion + + #region Implementation of IAdditiveIdentity + + public static ProcessStepValue AdditiveIdentity => new(0, string.Empty); + + #endregion + + #region Implementation of IComparisonOperators + + public static bool operator >(ProcessStepValue left, ProcessStepValue right) => left.Step > right.Step; + + public static bool operator >=(ProcessStepValue left, ProcessStepValue right) => left.Step >= right.Step; + + public static bool operator <(ProcessStepValue left, ProcessStepValue right) => left.Step < right.Step; + + public static bool operator <=(ProcessStepValue left, ProcessStepValue right) => left.Step <= right.Step; + + #endregion + + #region Implementation of IDecrementOperators + + public static ProcessStepValue operator --(ProcessStepValue value) => value with { Step = value.Step - 1 }; + + #endregion + + #region Implementation of IDivisionOperators + + public static ProcessStepValue operator /(ProcessStepValue left, ProcessStepValue right) => left with { Step = left.Step / right.Step }; + + #endregion + + #region Implementation of IIncrementOperators + + public static ProcessStepValue operator ++(ProcessStepValue value) => value with { Step = value.Step + 1 }; + + #endregion + + #region Implementation of IModulusOperators + + public static ProcessStepValue operator %(ProcessStepValue left, ProcessStepValue right) => left with { Step = left.Step % right.Step }; + + #endregion + + #region Implementation of IMultiplicativeIdentity + + public static ProcessStepValue MultiplicativeIdentity => new(1, string.Empty); + + #endregion + + #region Implementation of IMultiplyOperators + + public static ProcessStepValue operator *(ProcessStepValue left, ProcessStepValue right) => left with { Step = left.Step * right.Step }; + + #endregion + + #region Implementation of ISubtractionOperators + + public static ProcessStepValue operator -(ProcessStepValue left, ProcessStepValue right) => left with { Step = left.Step - right.Step }; + + #endregion + + #region Implementation of IUnaryNegationOperators + + public static ProcessStepValue operator -(ProcessStepValue value) => value with { Step = -value.Step }; + + #endregion + + #region Implementation of IUnaryPlusOperators + + public static ProcessStepValue operator +(ProcessStepValue value) => value; + + #endregion + + #region Implementation of INumberBase + + public static ProcessStepValue Abs(ProcessStepValue value) => value with { Step = Math.Abs(value.Step) }; + + public static bool IsCanonical(ProcessStepValue value) => true; + public static bool IsComplexNumber(ProcessStepValue value) => false; + public static bool IsEvenInteger(ProcessStepValue value) => value.Step % 2 == 0; + public static bool IsFinite(ProcessStepValue value) => true; + public static bool IsImaginaryNumber(ProcessStepValue value) => false; + public static bool IsInfinity(ProcessStepValue value) => false; + public static bool IsInteger(ProcessStepValue value) => true; + public static bool IsNaN(ProcessStepValue value) => false; + public static bool IsNegative(ProcessStepValue value) => value.Step < 0; + public static bool IsNegativeInfinity(ProcessStepValue value) => false; + public static bool IsNormal(ProcessStepValue value) => true; + public static bool IsOddInteger(ProcessStepValue value) => value.Step % 2 != 0; + public static bool IsPositive(ProcessStepValue value) => value.Step > 0; + public static bool IsPositiveInfinity(ProcessStepValue value) => false; + public static bool IsRealNumber(ProcessStepValue value) => true; + public static bool IsSubnormal(ProcessStepValue value) => false; + public static bool IsZero(ProcessStepValue value) => value.Step == 0; + public static ProcessStepValue MaxMagnitude(ProcessStepValue x, ProcessStepValue y) + { + return x with { Step = Math.Max(Math.Abs(x.Step), Math.Abs(y.Step)) }; + } + + public static ProcessStepValue MaxMagnitudeNumber(ProcessStepValue x, ProcessStepValue y) => MaxMagnitude(x, y); + + public static ProcessStepValue MinMagnitude(ProcessStepValue x, ProcessStepValue y) => x with { Step = Math.Min(Math.Abs(x.Step), Math.Abs(y.Step)) }; + + public static ProcessStepValue MinMagnitudeNumber(ProcessStepValue x, ProcessStepValue y) => MinMagnitude(x, y); + + public static ProcessStepValue Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider) => new(int.Parse(s, style, provider), string.Empty); + + public static ProcessStepValue Parse(string s, NumberStyles style, IFormatProvider? provider) => new(int.Parse(s, style, provider), string.Empty); + + public static bool TryConvertFromChecked(TOther value, out ProcessStepValue result) where TOther : INumberBase + { + if (TOther.TryConvertToChecked(value, out int intValue)) + { + result = new ProcessStepValue(intValue, string.Empty); + return true; + } + + result = default; + return false; + } + + public static bool TryConvertFromSaturating(TOther value, out ProcessStepValue result) where TOther : INumberBase + { + if (TOther.TryConvertToSaturating(value, out int intValue)) + { + result = new ProcessStepValue(intValue, string.Empty); + return true; + } + result = default; + return false; + } + + public static bool TryConvertFromTruncating(TOther value, out ProcessStepValue result) where TOther : INumberBase + { + if (TOther.TryConvertToTruncating(value, out int intValue)) + { + result = new ProcessStepValue(intValue, string.Empty); + return true; + } + result = default; + return false; + } + + public static bool TryConvertToChecked(ProcessStepValue value, out TOther result) where TOther : INumberBase => TOther.TryConvertFromChecked(value.Step, out result!); + + public static bool TryConvertToSaturating(ProcessStepValue value, out TOther result) where TOther : INumberBase => TOther.TryConvertFromSaturating(value.Step, out result!); + + public static bool TryConvertToTruncating(ProcessStepValue value, out TOther result) where TOther : INumberBase => TOther.TryConvertFromTruncating(value.Step, out result!); + + public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out ProcessStepValue result) + { + if (int.TryParse(s, style, provider, out var stepValue)) + { + result = new ProcessStepValue(stepValue, string.Empty); + return true; + } + + result = default; + return false; + } + + public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out ProcessStepValue result) + { + if (int.TryParse(s, style, provider, out var stepValue)) + { + result = new ProcessStepValue(stepValue, string.Empty); + return true; + } + + result = default; + return false; + } + + public static ProcessStepValue One => new(1, string.Empty); + + public static int Radix => 2; + + public static ProcessStepValue Zero => new(0, string.Empty); + + #endregion + + #endregion +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ThreadSafeRandom.cs b/app/MindWork AI Studio/Tools/ThreadSafeRandom.cs new file mode 100644 index 0000000..27bb61a --- /dev/null +++ b/app/MindWork AI Studio/Tools/ThreadSafeRandom.cs @@ -0,0 +1,88 @@ +namespace AIStudio.Tools; + +/// +public sealed class ThreadSafeRandom : Random +{ + private static readonly object LOCK = new(); + + #region Overrides of Random + + /// + public override int Next() + { + lock (LOCK) + return base.Next(); + } + + /// + public override int Next(int maxValue) + { + lock (LOCK) + return base.Next(maxValue); + } + + /// + public override int Next(int minValue, int maxValue) + { + lock (LOCK) + return base.Next(minValue, maxValue); + } + + /// + public override void NextBytes(byte[] buffer) + { + lock (LOCK) + base.NextBytes(buffer); + } + + /// + public override void NextBytes(Span buffer) + { + lock (LOCK) + base.NextBytes(buffer); + } + + /// + public override double NextDouble() + { + lock (LOCK) + return base.NextDouble(); + } + + /// + public override long NextInt64() + { + lock (LOCK) + return base.NextInt64(); + } + + /// + public override long NextInt64(long maxValue) + { + lock (LOCK) + return base.NextInt64(maxValue); + } + + /// + public override long NextInt64(long minValue, long maxValue) + { + lock (LOCK) + return base.NextInt64(minValue, maxValue); + } + + /// + public override float NextSingle() + { + lock (LOCK) + return base.NextSingle(); + } + + /// + protected override double Sample() + { + lock (LOCK) + return base.Sample(); + } + + #endregion +} \ No newline at end of file diff --git a/app/MindWork AI Studio/packages.lock.json b/app/MindWork AI Studio/packages.lock.json index 5dd25e9..220be60 100644 --- a/app/MindWork AI Studio/packages.lock.json +++ b/app/MindWork AI Studio/packages.lock.json @@ -2,6 +2,12 @@ "version": 1, "dependencies": { "net8.0": { + "HtmlAgilityPack": { + "type": "Direct", + "requested": "[1.11.62, )", + "resolved": "1.11.62", + "contentHash": "KS4h7ZjWsO6YixRfQgYdR+PZMbTaZod1LBPi+1Ph7dJCARzQm7DOKe5HPhP/o0EWX5l7QCgAZHa4VOa4pQa8JQ==" + }, "Microsoft.Extensions.FileProviders.Embedded": { "type": "Direct", "requested": "[8.0.7, )", @@ -38,6 +44,15 @@ "MudBlazor": "6.20.0" } }, + "ReverseMarkdown": { + "type": "Direct", + "requested": "[4.6.0, )", + "resolved": "4.6.0", + "contentHash": "ehNpMz3yQwd7P/vHpwi4KyDlT8UtVmtiL+NTb6mFEPzbLqJXbRIGF4OxEA5tuBA5Cfwhzf537TX1UIB6dUpo7A==", + "dependencies": { + "HtmlAgilityPack": "1.11.61" + } + }, "Markdig": { "type": "Transitive", "resolved": "0.37.0", @@ -163,6 +178,6 @@ "contentHash": "FHNOatmUq0sqJOkTx+UF/9YK1f180cnW5FVqnQMvYUN0elp6wFzbtPSiqbo1/ru8ICp43JM1i7kKkk6GsNGHlA==" } }, - "net8.0/osx-x64": {} + "net8.0/osx-arm64": {} } } \ No newline at end of file diff --git a/app/MindWork AI Studio/wwwroot/changelog/v0.8.6.md b/app/MindWork AI Studio/wwwroot/changelog/v0.8.6.md index 00280c0..2025227 100644 --- a/app/MindWork AI Studio/wwwroot/changelog/v0.8.6.md +++ b/app/MindWork AI Studio/wwwroot/changelog/v0.8.6.md @@ -1,5 +1,9 @@ -# v0.8.6, build 168 +# v0.8.6, build 168 (2024-08-01 19:50 UTC) - Added possibility to configure a default provider for chats +- Added architecture for future agent usage +- Added a first agent to read, analyze and extract text from Markdown data +- Added option to read web content into translation and text summarization assistants - Improved the readability of the `settings.json` file by using indentation and enum names instead of numbers - Improved assistant overview; assistants will now wrap to the next line if there are too many to fit on the row -- Increased the default value for the live translation delay from 1,000 to 1,500 ms \ No newline at end of file +- Increased the default value for the live translation delay from 1,000 to 3_000 ms +- Fixed random number generator usage to be thread-safe \ No newline at end of file diff --git a/metadata.txt b/metadata.txt index 0d4231b..51f9c8e 100644 --- a/metadata.txt +++ b/metadata.txt @@ -1,9 +1,9 @@ -0.8.5 -2024-07-28 16:44:01 UTC -167 +0.8.6 +2024-08-01 19:50:02 UTC +168 8.0.107 (commit 1bdaef7265) 8.0.7 (commit 2aade6beb0) 1.80.0 (commit 051478957) 7.4.0 1.7.1 -c1b92a05fc7, release +199be1e863f, release diff --git a/runtime/Cargo.lock b/runtime/Cargo.lock index fdbe55d..a7bc970 100644 --- a/runtime/Cargo.lock +++ b/runtime/Cargo.lock @@ -2308,7 +2308,7 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mindwork-ai-studio" -version = "0.8.5" +version = "0.8.6" dependencies = [ "arboard", "flexi_logger", diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index feda293..8f64fca 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mindwork-ai-studio" -version = "0.8.5" +version = "0.8.6" edition = "2021" description = "MindWork AI Studio" authors = ["Thorsten Sommer"] diff --git a/runtime/tauri.conf.json b/runtime/tauri.conf.json index 1799966..315a8a3 100644 --- a/runtime/tauri.conf.json +++ b/runtime/tauri.conf.json @@ -6,7 +6,7 @@ }, "package": { "productName": "MindWork AI Studio", - "version": "0.8.5" + "version": "0.8.6" }, "tauri": { "allowlist": {