mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-19 21:58:00 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ea767cb45 | ||
|
|
11846e279c | ||
|
|
c861d71383 | ||
|
|
6fbf32d8a2 | ||
|
|
4216a29325 | ||
|
|
45770c2cd7 | ||
|
|
57905d5510 | ||
|
|
e999aab7c0 | ||
|
|
c47d3893ff | ||
|
|
09c1b77414 | ||
|
|
ea083fdec2 | ||
|
|
ceabcdb26e | ||
|
|
a25793ff11 | ||
|
|
8d8a47b43b | ||
|
|
2889581702 | ||
|
|
12602ba8dd | ||
|
|
e4b8487945 | ||
|
|
fc64c0b505 | ||
|
|
47f5756e5a | ||
|
|
e4ef4bc06e | ||
|
|
ae17104886 | ||
|
|
2d82fcc5e1 | ||
|
|
69a6fcf094 | ||
|
|
4aaa2fcbea | ||
|
|
d855a33e6f | ||
|
|
ca16a749fd | ||
|
|
bcdbf7dcbd | ||
|
|
537a608e7a | ||
|
|
a6c5b3de23 | ||
|
|
3fd0d4d5c1 | ||
|
|
5efb6b0158 | ||
|
|
1b3fff67ec | ||
|
|
3409872090 | ||
|
|
18718a6c47 | ||
|
|
34884859d7 | ||
|
|
50bf0baff7 | ||
|
|
83fe126c9f | ||
|
|
37b38e6a40 | ||
|
|
1d1af91f3e | ||
|
|
a18cb22263 | ||
|
|
f8e06faea5 | ||
|
|
8aeeda5dca | ||
|
|
909fbe89bb |
No files matched your search
@@ -489,7 +489,7 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: linux_arm_cache
|
||||
with:
|
||||
path: $RUNNER_TEMP/linux_arm_qemu_cache.img
|
||||
path: ${{ runner.temp }}/linux_arm_qemu_cache.img
|
||||
|
||||
# When the entire key matches, Rust might just create the bundles using the current .NET build:
|
||||
key: target-linux-arm64-rust-${{ env.RUST_VERSION }}-dependencies-${{ env.CARGO_LOCK_HASH }}
|
||||
@@ -544,7 +544,7 @@ jobs:
|
||||
- name: Add the built runner image to the cache
|
||||
if: ${{ steps.linux_arm_cache.outputs.cache-hit != 'true' && env.SKIP != 'true' }}
|
||||
run: |
|
||||
mv ${{ steps.build-linux-arm-runner.outputs.image }} $RUNNER_TEMP/linux_arm_qemu_cache.img
|
||||
mv ${{ steps.build-linux-arm-runner.outputs.image }} ${{ runner.temp }}/linux_arm_qemu_cache.img
|
||||
|
||||
- name: Build Tauri project
|
||||
if: ${{ env.SKIP != 'true' }}
|
||||
@@ -552,11 +552,12 @@ jobs:
|
||||
id: build-linux-arm
|
||||
|
||||
with:
|
||||
base_image: file://$RUNNER_TEMP/linux_arm_qemu_cache.img
|
||||
base_image: file://${{ runner.temp }}/linux_arm_qemu_cache.img
|
||||
cpu: cortex-a53
|
||||
optimize_image: false
|
||||
copy_artifact_path: runtime
|
||||
copy_artifact_dest: result
|
||||
bind_mount_repository: true
|
||||
|
||||
#
|
||||
# We do not need to set the PRIVATE_PUBLISH_KEY and PRIVATE_PUBLISH_KEY_PASSWORD here,
|
||||
@@ -573,7 +574,17 @@ jobs:
|
||||
export CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse
|
||||
source "$HOME/.cargo/env"
|
||||
cd runtime
|
||||
|
||||
# Try to restore the Rust cache from previous build:
|
||||
mkdir -p /rust-cache/target
|
||||
rm -fr target
|
||||
cp -Rp /rust-cache/target target
|
||||
|
||||
cargo tauri build --target aarch64-unknown-linux-gnu --bundles deb
|
||||
|
||||
# Save the built libraries for the next job:
|
||||
rm -fr /rust-cache/target
|
||||
cp -Rp target /rust-cache
|
||||
|
||||
- name: Debug
|
||||
if: ${{ env.SKIP != 'true' }}
|
||||
@@ -729,6 +740,9 @@ jobs:
|
||||
# Replace newlines in changelog with \n
|
||||
changelog=$(echo "$CHANGELOG" | awk '{printf "%s\\n", $0}')
|
||||
|
||||
# Escape double quotes in changelog:
|
||||
changelog=$(echo "$changelog" | sed 's/"/\\"/g')
|
||||
|
||||
# Create the latest.json file:
|
||||
cat <<EOOOF > $GITHUB_WORKSPACE/release/assets/latest.json
|
||||
{
|
||||
@@ -794,7 +808,11 @@ jobs:
|
||||
|
||||
- name: Append scan results to changelog
|
||||
run: |
|
||||
changelog="${{ env.CHANGELOG }}"
|
||||
changelog=$(cat <<'EOOOOOOOF'
|
||||
${{ env.CHANGELOG }}
|
||||
EOOOOOOOF
|
||||
)
|
||||
|
||||
links="${{ steps.virus_total.outputs.analysis }}"
|
||||
|
||||
# Create a temporary file for the changelog:
|
||||
@@ -838,7 +856,7 @@ jobs:
|
||||
- name: Create release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
prerelease: false
|
||||
prerelease: true
|
||||
draft: false
|
||||
make_latest: true
|
||||
body: ${{ env.CHANGELOG }}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# MindWork AI Studio
|
||||

|
||||

|
||||

|
||||
|
||||
MindWork AI Studio is a desktop application available for macOS, Windows, and Linux. It provides a unified chat interface for Large Language Models (LLMs). You bring your own API key for the respective LLM provider to use the models. The API keys are securely stored by the operating system.
|
||||
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
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
|
||||
public abstract class AgentBase(ILogger<AgentBase> logger, SettingsManager settingsManager, ThreadSafeRandom rng) : IAgent
|
||||
{
|
||||
protected SettingsManager SettingsManager { get; init; } = settingsManager;
|
||||
|
||||
protected IJSRuntime JsRuntime { get; init; } = jsRuntime;
|
||||
|
||||
protected ThreadSafeRandom RNG { get; init; } = rng;
|
||||
|
||||
protected ILogger<AgentBase> Logger { get; init; } = logger;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the type or category of this agent.
|
||||
@@ -104,6 +103,6 @@ public abstract class AgentBase(SettingsManager settingsManager, IJSRuntime jsRu
|
||||
// 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);
|
||||
await aiText.CreateFromProviderAsync(providerSettings.CreateProvider(this.Logger), this.SettingsManager, providerSettings.Model, thread);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
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)
|
||||
public sealed class AgentTextContentCleaner(ILogger<AgentBase> logger, SettingsManager settingsManager, ThreadSafeRandom rng) : AgentBase(logger, settingsManager, rng)
|
||||
{
|
||||
private static readonly ContentBlock EMPTY_BLOCK = new()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
|
||||
@* ReSharper disable Html.PathError *@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title>MindWork AI Studio</title>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<base href="/"/>
|
||||
|
||||
<link rel="icon" type="image/png" href="favicon.png"/>
|
||||
<link href="system/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
|
||||
<link href="system/MudBlazor.Markdown/MudBlazor.Markdown.min.css" rel="stylesheet" />
|
||||
<link href="app.css" rel="stylesheet" />
|
||||
<HeadOutlet/>
|
||||
<script src="diff.js"></script>
|
||||
</head>
|
||||
|
||||
<body style="overflow: hidden;">
|
||||
<Routes @rendermode="new InteractiveServerRenderMode(prerender: false)"/>
|
||||
<script src="_framework/blazor.web.js" autostart="false"></script>
|
||||
<script src="boot.js"></script>
|
||||
<script src="system/MudBlazor/MudBlazor.min.js"></script>
|
||||
<script src="system/MudBlazor.Markdown/MudBlazor.Markdown.min.js"></script>
|
||||
<script src="app.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+1
-2
@@ -1,5 +1,4 @@
|
||||
@page "/assistant/agenda"
|
||||
@using AIStudio.Tools
|
||||
@attribute [Route(Routes.ASSISTANT_AGENDA)]
|
||||
@inherits AssistantBaseCore
|
||||
|
||||
<MudTextField T="string" @bind-Text="@this.inputName" Validation="@this.ValidateName" Label="Meeting Name" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Tag" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="Name the meeting, seminar, etc." Placeholder="Weekly jour fixe" Class="mb-3"/>
|
||||
+76
-25
@@ -1,11 +1,13 @@
|
||||
using System.Text;
|
||||
|
||||
using AIStudio.Tools;
|
||||
using AIStudio.Chat;
|
||||
|
||||
namespace AIStudio.Components.Pages.Agenda;
|
||||
namespace AIStudio.Assistants.Agenda;
|
||||
|
||||
public partial class AssistantAgenda : AssistantBaseCore
|
||||
{
|
||||
protected override Tools.Components Component => Tools.Components.AGENDA_ASSISTANT;
|
||||
|
||||
protected override string Title => "Agenda Planner";
|
||||
|
||||
protected override string Description =>
|
||||
@@ -93,6 +95,71 @@ public partial class AssistantAgenda : AssistantBaseCore
|
||||
- Mary Jane: Work package 3
|
||||
""";
|
||||
|
||||
protected override IReadOnlyList<IButtonData> FooterButtons => [];
|
||||
|
||||
protected override ChatThread ConvertToChatThread => (this.chatThread ?? new()) with
|
||||
{
|
||||
SystemPrompt = SystemPrompts.DEFAULT,
|
||||
};
|
||||
|
||||
protected override void ResetFrom()
|
||||
{
|
||||
this.inputContent = string.Empty;
|
||||
this.contentLines.Clear();
|
||||
this.selectedFoci = [];
|
||||
this.justBriefly = [];
|
||||
this.inputWhoIsPresenting = string.Empty;
|
||||
if (!this.MightPreselectValues())
|
||||
{
|
||||
this.inputTopic = string.Empty;
|
||||
this.inputName = string.Empty;
|
||||
this.inputDuration = string.Empty;
|
||||
this.inputStartTime = string.Empty;
|
||||
this.inputObjective = string.Empty;
|
||||
this.inputModerator = string.Empty;
|
||||
this.selectedTargetLanguage = CommonLanguages.AS_IS;
|
||||
this.customTargetLanguage = string.Empty;
|
||||
this.introduceParticipants = false;
|
||||
this.isMeetingVirtual = true;
|
||||
this.inputLocation = string.Empty;
|
||||
this.goingToDinner = false;
|
||||
this.doingSocialActivity = false;
|
||||
this.needToArriveAndDepart = false;
|
||||
this.durationLunchBreak = 0;
|
||||
this.durationBreaks = 0;
|
||||
this.activeParticipation = false;
|
||||
this.numberParticipants = NumberParticipants.NOT_SPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool MightPreselectValues()
|
||||
{
|
||||
if (this.SettingsManager.ConfigurationData.Agenda.PreselectOptions)
|
||||
{
|
||||
this.inputTopic = this.SettingsManager.ConfigurationData.Agenda.PreselectTopic;
|
||||
this.inputName = this.SettingsManager.ConfigurationData.Agenda.PreselectName;
|
||||
this.inputDuration = this.SettingsManager.ConfigurationData.Agenda.PreselectDuration;
|
||||
this.inputStartTime = this.SettingsManager.ConfigurationData.Agenda.PreselectStartTime;
|
||||
this.inputObjective = this.SettingsManager.ConfigurationData.Agenda.PreselectObjective;
|
||||
this.inputModerator = this.SettingsManager.ConfigurationData.Agenda.PreselectModerator;
|
||||
this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.Agenda.PreselectedTargetLanguage;
|
||||
this.customTargetLanguage = this.SettingsManager.ConfigurationData.Agenda.PreselectedOtherLanguage;
|
||||
this.introduceParticipants = this.SettingsManager.ConfigurationData.Agenda.PreselectIntroduceParticipants;
|
||||
this.isMeetingVirtual = this.SettingsManager.ConfigurationData.Agenda.PreselectIsMeetingVirtual;
|
||||
this.inputLocation = this.SettingsManager.ConfigurationData.Agenda.PreselectLocation;
|
||||
this.goingToDinner = this.SettingsManager.ConfigurationData.Agenda.PreselectJointDinner;
|
||||
this.doingSocialActivity = this.SettingsManager.ConfigurationData.Agenda.PreselectSocialActivity;
|
||||
this.needToArriveAndDepart = this.SettingsManager.ConfigurationData.Agenda.PreselectArriveAndDepart;
|
||||
this.durationLunchBreak = this.SettingsManager.ConfigurationData.Agenda.PreselectLunchTime;
|
||||
this.durationBreaks = this.SettingsManager.ConfigurationData.Agenda.PreselectBreakTime;
|
||||
this.activeParticipation = this.SettingsManager.ConfigurationData.Agenda.PreselectActiveParticipation;
|
||||
this.numberParticipants = this.SettingsManager.ConfigurationData.Agenda.PreselectNumberParticipants;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private string inputTopic = string.Empty;
|
||||
private string inputName = string.Empty;
|
||||
private string inputContent = string.Empty;
|
||||
@@ -122,28 +189,9 @@ public partial class AssistantAgenda : AssistantBaseCore
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
if (this.SettingsManager.ConfigurationData.Agenda.PreselectOptions)
|
||||
{
|
||||
this.inputTopic = this.SettingsManager.ConfigurationData.Agenda.PreselectTopic;
|
||||
this.inputName = this.SettingsManager.ConfigurationData.Agenda.PreselectName;
|
||||
this.inputDuration = this.SettingsManager.ConfigurationData.Agenda.PreselectDuration;
|
||||
this.inputStartTime = this.SettingsManager.ConfigurationData.Agenda.PreselectStartTime;
|
||||
this.inputObjective = this.SettingsManager.ConfigurationData.Agenda.PreselectObjective;
|
||||
this.inputModerator = this.SettingsManager.ConfigurationData.Agenda.PreselectModerator;
|
||||
this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.Agenda.PreselectedTargetLanguage;
|
||||
this.customTargetLanguage = this.SettingsManager.ConfigurationData.Agenda.PreselectedOtherLanguage;
|
||||
this.introduceParticipants = this.SettingsManager.ConfigurationData.Agenda.PreselectIntroduceParticipants;
|
||||
this.isMeetingVirtual = this.SettingsManager.ConfigurationData.Agenda.PreselectIsMeetingVirtual;
|
||||
this.inputLocation = this.SettingsManager.ConfigurationData.Agenda.PreselectLocation;
|
||||
this.goingToDinner = this.SettingsManager.ConfigurationData.Agenda.PreselectJointDinner;
|
||||
this.doingSocialActivity = this.SettingsManager.ConfigurationData.Agenda.PreselectSocialActivity;
|
||||
this.needToArriveAndDepart = this.SettingsManager.ConfigurationData.Agenda.PreselectArriveAndDepart;
|
||||
this.durationLunchBreak = this.SettingsManager.ConfigurationData.Agenda.PreselectLunchTime;
|
||||
this.durationBreaks = this.SettingsManager.ConfigurationData.Agenda.PreselectBreakTime;
|
||||
this.activeParticipation = this.SettingsManager.ConfigurationData.Agenda.PreselectActiveParticipation;
|
||||
this.numberParticipants = this.SettingsManager.ConfigurationData.Agenda.PreselectNumberParticipants;
|
||||
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.Agenda.PreselectedProvider);
|
||||
}
|
||||
var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages<string>(Event.SEND_TO_AGENDA_ASSISTANT).FirstOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputContent = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
@@ -248,7 +296,7 @@ public partial class AssistantAgenda : AssistantBaseCore
|
||||
if(string.IsNullOrWhiteSpace(content))
|
||||
return "Please provide some content for the agenda. What are the main points of the meeting or the seminar?";
|
||||
|
||||
var lines = content.Split('\n');
|
||||
var lines = content.Split('\n', StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
if(!line.TrimStart().StartsWith('-'))
|
||||
return "Please start each line of your content list with a dash (-) to create a bullet point list.";
|
||||
@@ -308,6 +356,9 @@ public partial class AssistantAgenda : AssistantBaseCore
|
||||
|
||||
private string PromptLanguage()
|
||||
{
|
||||
if(this.selectedTargetLanguage is CommonLanguages.AS_IS)
|
||||
return "Use the same language as the input.";
|
||||
|
||||
if(this.selectedTargetLanguage is CommonLanguages.OTHER)
|
||||
return this.customTargetLanguage;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace AIStudio.Components.Pages.Agenda;
|
||||
namespace AIStudio.Assistants.Agenda;
|
||||
|
||||
public enum NumberParticipants
|
||||
{
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace AIStudio.Components.Pages.Agenda;
|
||||
namespace AIStudio.Assistants.Agenda;
|
||||
|
||||
public static class NumberParticipantsExtensions
|
||||
{
|
||||
@@ -0,0 +1,98 @@
|
||||
@using AIStudio.Chat
|
||||
|
||||
<MudText Typo="Typo.h3" Class="mb-2 mr-3">
|
||||
@(this.Title)
|
||||
</MudText>
|
||||
|
||||
<InnerScrolling HeaderHeight="6em">
|
||||
<ChildContent>
|
||||
<MudForm @ref="@(this.form)" @bind-IsValid="@(this.inputIsValid)" @bind-Errors="@(this.inputIssues)" Class="pr-2">
|
||||
<MudText Typo="Typo.body1" Align="Align.Justify" Class="mb-6">
|
||||
@(this.Description)
|
||||
</MudText>
|
||||
|
||||
@if (this.Body is not null)
|
||||
{
|
||||
@(this.Body)
|
||||
}
|
||||
</MudForm>
|
||||
<Issues IssuesData="@(this.inputIssues)"/>
|
||||
|
||||
@if (this.ShowDedicatedProgress && this.isProcessing)
|
||||
{
|
||||
<MudProgressLinear Color="Color.Primary" Indeterminate="true" Class="mb-6" />
|
||||
}
|
||||
|
||||
<div id="@RESULT_DIV_ID" class="mr-2 mt-3">
|
||||
</div>
|
||||
|
||||
@if (this.ShowResult && this.resultingContentBlock is not null)
|
||||
{
|
||||
<ContentBlockComponent Role="@(this.resultingContentBlock.Role)" Type="@(this.resultingContentBlock.ContentType)" Time="@(this.resultingContentBlock.Time)" Content="@(this.resultingContentBlock.Content)"/>
|
||||
}
|
||||
|
||||
<div id="@AFTER_RESULT_DIV_ID" class="mt-3">
|
||||
</div>
|
||||
</ChildContent>
|
||||
<FooterContent>
|
||||
<MudStack Row="@true" Wrap="Wrap.Wrap" Class="ma-1">
|
||||
|
||||
@if (!this.FooterButtons.Any(x => x.Type is ButtonTypes.SEND_TO))
|
||||
{
|
||||
<MudMenu StartIcon="@Icons.Material.Filled.Apps" EndIcon="@Icons.Material.Filled.KeyboardArrowDown" Label="Send to ..." Variant="Variant.Filled" Color="Color.Info">
|
||||
@foreach (var assistant in Enum.GetValues<Components>().OrderBy(n => n.Name().Length))
|
||||
{
|
||||
if (assistant is Components.NONE || this.Component == assistant)
|
||||
continue;
|
||||
|
||||
<MudMenuItem OnClick="() => this.SendToAssistant(assistant, new())">
|
||||
@assistant.Name()
|
||||
</MudMenuItem>
|
||||
}
|
||||
</MudMenu>
|
||||
}
|
||||
|
||||
@foreach (var button in this.FooterButtons)
|
||||
{
|
||||
switch (button)
|
||||
{
|
||||
case ButtonData buttonData when !string.IsNullOrWhiteSpace(buttonData.Tooltip):
|
||||
<MudTooltip Text="@buttonData.Tooltip">
|
||||
<MudButton Variant="Variant.Filled" Color="@buttonData.Color" StartIcon="@GetButtonIcon(buttonData.Icon)" OnClick="async () => await buttonData.AsyncAction()">
|
||||
@buttonData.Text
|
||||
</MudButton>
|
||||
</MudTooltip>
|
||||
break;
|
||||
|
||||
case ButtonData buttonData:
|
||||
<MudButton Variant="Variant.Filled" Color="@buttonData.Color" StartIcon="@GetButtonIcon(buttonData.Icon)" OnClick="async () => await buttonData.AsyncAction()">
|
||||
@buttonData.Text
|
||||
</MudButton>
|
||||
break;
|
||||
|
||||
case SendToButton sendToButton:
|
||||
<MudMenu StartIcon="@Icons.Material.Filled.Apps" EndIcon="@Icons.Material.Filled.KeyboardArrowDown" Label="Send to ..." Variant="Variant.Filled" Color="Color.Info">
|
||||
@foreach (var assistant in Enum.GetValues<Components>().OrderBy(n => n.Name().Length))
|
||||
{
|
||||
if(assistant is Components.NONE || sendToButton.Self == assistant)
|
||||
continue;
|
||||
|
||||
<MudMenuItem OnClick="() => this.SendToAssistant(assistant, sendToButton)">
|
||||
@assistant.Name()
|
||||
</MudMenuItem>
|
||||
}
|
||||
</MudMenu>
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
<MudButton Variant="Variant.Filled" StartIcon="@Icons.Material.Filled.ContentCopy" OnClick="() => this.CopyToClipboard()">
|
||||
Copy result
|
||||
</MudButton>
|
||||
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Warning" StartIcon="@Icons.Material.Filled.Refresh" OnClick="() => this.InnerResetForm()">
|
||||
Reset
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
</FooterContent>
|
||||
</InnerScrolling>
|
||||
+85
-10
@@ -1,16 +1,17 @@
|
||||
using AIStudio.Chat;
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Tools;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components;
|
||||
using RustService = AIStudio.Tools.RustService;
|
||||
|
||||
namespace AIStudio.Assistants;
|
||||
|
||||
public abstract partial class AssistantBase : ComponentBase
|
||||
{
|
||||
[Inject]
|
||||
protected SettingsManager SettingsManager { get; set; } = null!;
|
||||
protected SettingsManager SettingsManager { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected IJSRuntime JsRuntime { get; init; } = null!;
|
||||
@@ -22,10 +23,16 @@ public abstract partial class AssistantBase : ComponentBase
|
||||
protected ISnackbar Snackbar { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected Rust Rust { get; init; } = null!;
|
||||
protected RustService RustService { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected NavigationManager NavigationManager { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected ILogger<AssistantBase> Logger { get; init; } = null!;
|
||||
|
||||
internal const string AFTER_RESULT_DIV_ID = "afterAssistantResult";
|
||||
internal const string ASSISTANT_RESULT_DIV_ID = "assistantResult";
|
||||
internal const string RESULT_DIV_ID = "assistantResult";
|
||||
|
||||
protected abstract string Title { get; }
|
||||
|
||||
@@ -33,13 +40,27 @@ public abstract partial class AssistantBase : ComponentBase
|
||||
|
||||
protected abstract string SystemPrompt { get; }
|
||||
|
||||
protected abstract Tools.Components Component { get; }
|
||||
|
||||
protected virtual Func<string> Result2Copy => () => this.resultingContentBlock is null ? string.Empty : this.resultingContentBlock.Content switch
|
||||
{
|
||||
ContentText textBlock => textBlock.Text,
|
||||
_ => string.Empty,
|
||||
};
|
||||
|
||||
protected abstract void ResetFrom();
|
||||
|
||||
protected abstract bool MightPreselectValues();
|
||||
|
||||
private protected virtual RenderFragment? Body => null;
|
||||
|
||||
protected virtual bool ShowResult => true;
|
||||
|
||||
protected virtual bool ShowDedicatedProgress => false;
|
||||
|
||||
protected virtual IReadOnlyList<ButtonData> FooterButtons => [];
|
||||
protected virtual ChatThread ConvertToChatThread => this.chatThread ?? new();
|
||||
|
||||
protected virtual IReadOnlyList<IButtonData> FooterButtons => [];
|
||||
|
||||
protected static readonly Dictionary<string, object?> USER_INPUT_ATTRIBUTES = new();
|
||||
|
||||
@@ -47,13 +68,20 @@ public abstract partial class AssistantBase : ComponentBase
|
||||
protected MudForm? form;
|
||||
protected bool inputIsValid;
|
||||
|
||||
private ChatThread? chatThread;
|
||||
protected ChatThread? chatThread;
|
||||
private ContentBlock? resultingContentBlock;
|
||||
private string[] inputIssues = [];
|
||||
private bool isProcessing;
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
this.MightPreselectValues();
|
||||
this.providerSettings = this.SettingsManager.GetPreselectedProvider(this.Component);
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
// Configure the spellchecking for the user input:
|
||||
@@ -136,7 +164,7 @@ public abstract partial class AssistantBase : ComponentBase
|
||||
// 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.providerSettings.CreateProvider(), this.JsRuntime, this.SettingsManager, this.providerSettings.Model, this.chatThread);
|
||||
await aiText.CreateFromProviderAsync(this.providerSettings.CreateProvider(this.Logger), this.SettingsManager, this.providerSettings.Model, this.chatThread);
|
||||
|
||||
this.isProcessing = false;
|
||||
this.StateHasChanged();
|
||||
@@ -145,9 +173,9 @@ public abstract partial class AssistantBase : ComponentBase
|
||||
return aiText.Text;
|
||||
}
|
||||
|
||||
protected async Task CopyToClipboard(string text)
|
||||
protected async Task CopyToClipboard()
|
||||
{
|
||||
await this.Rust.CopyText2Clipboard(this.JsRuntime, this.Snackbar, text);
|
||||
await this.RustService.CopyText2Clipboard(this.Snackbar, this.Result2Copy());
|
||||
}
|
||||
|
||||
private static string? GetButtonIcon(string icon)
|
||||
@@ -157,4 +185,51 @@ public abstract partial class AssistantBase : ComponentBase
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
private Task SendToAssistant(Tools.Components destination, SendToButton sendToButton)
|
||||
{
|
||||
var contentToSend = sendToButton.UseResultingContentBlockData switch
|
||||
{
|
||||
false => sendToButton.GetText(),
|
||||
true => this.resultingContentBlock?.Content switch
|
||||
{
|
||||
ContentText textBlock => textBlock.Text,
|
||||
_ => string.Empty,
|
||||
},
|
||||
};
|
||||
|
||||
var sendToData = destination.GetData();
|
||||
switch (destination)
|
||||
{
|
||||
case Tools.Components.CHAT:
|
||||
MessageBus.INSTANCE.DeferMessage(this, sendToData.Event, this.ConvertToChatThread);
|
||||
break;
|
||||
|
||||
default:
|
||||
MessageBus.INSTANCE.DeferMessage(this, sendToData.Event, contentToSend);
|
||||
break;
|
||||
}
|
||||
|
||||
this.NavigationManager.NavigateTo(sendToData.Route);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task InnerResetForm()
|
||||
{
|
||||
this.resultingContentBlock = null;
|
||||
this.providerSettings = default;
|
||||
|
||||
await this.JsRuntime.ClearDiv(RESULT_DIV_ID);
|
||||
await this.JsRuntime.ClearDiv(AFTER_RESULT_DIV_ID);
|
||||
|
||||
this.ResetFrom();
|
||||
this.providerSettings = this.SettingsManager.GetPreselectedProvider(this.Component);
|
||||
|
||||
this.inputIsValid = false;
|
||||
this.inputIssues = [];
|
||||
|
||||
this.form?.ResetValidation();
|
||||
this.StateHasChanged();
|
||||
this.form?.ResetValidation();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Rendering;
|
||||
|
||||
namespace AIStudio.Components;
|
||||
namespace AIStudio.Assistants;
|
||||
|
||||
//
|
||||
// See https://stackoverflow.com/a/77300384/2258393 for why this class is necessary
|
||||
+3
-2
@@ -1,11 +1,12 @@
|
||||
@page "/assistant/coding"
|
||||
@attribute [Route(Routes.ASSISTANT_CODING)]
|
||||
@inherits AssistantBaseCore
|
||||
|
||||
<MudExpansionPanels Class="mb-3">
|
||||
@for (var contextIndex = 0; contextIndex < this.codingContexts.Count; contextIndex++)
|
||||
{
|
||||
var codingContext = this.codingContexts[contextIndex];
|
||||
<ExpansionPanel HeaderText="@codingContext.Id" HeaderIcon="@Icons.Material.Filled.Code">
|
||||
var index = contextIndex;
|
||||
<ExpansionPanel HeaderText="@codingContext.Id" HeaderIcon="@Icons.Material.Filled.Code" ShowEndButton="@true" EndButtonColor="Color.Error" EndButtonIcon="@Icons.Material.Filled.Delete" EndButtonTooltip="Delete context" EndButtonClickAsync="@(() => this.DeleteContext(index))">
|
||||
<CodingContextItem @bind-CodingContext="@codingContext"/>
|
||||
</ExpansionPanel>
|
||||
}
|
||||
+49
-9
@@ -1,9 +1,11 @@
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Components.Pages.Coding;
|
||||
namespace AIStudio.Assistants.Coding;
|
||||
|
||||
public partial class AssistantCoding : AssistantBaseCore
|
||||
{
|
||||
protected override Tools.Components Component => Tools.Components.CODING_ASSISTANT;
|
||||
|
||||
protected override string Title => "Coding Assistant";
|
||||
|
||||
protected override string Description =>
|
||||
@@ -24,6 +26,30 @@ public partial class AssistantCoding : AssistantBaseCore
|
||||
When the user asks in a different language than English, you answer in the same language!
|
||||
""";
|
||||
|
||||
protected override IReadOnlyList<IButtonData> FooterButtons => [];
|
||||
|
||||
protected override void ResetFrom()
|
||||
{
|
||||
this.codingContexts.Clear();
|
||||
this.compilerMessages = string.Empty;
|
||||
this.questions = string.Empty;
|
||||
if (!this.MightPreselectValues())
|
||||
{
|
||||
this.provideCompilerMessages = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool MightPreselectValues()
|
||||
{
|
||||
if (this.SettingsManager.ConfigurationData.Coding.PreselectOptions)
|
||||
{
|
||||
this.provideCompilerMessages = this.SettingsManager.ConfigurationData.Coding.PreselectCompilerMessages;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private readonly List<CodingContext> codingContexts = new();
|
||||
private bool provideCompilerMessages;
|
||||
private string compilerMessages = string.Empty;
|
||||
@@ -33,11 +59,9 @@ public partial class AssistantCoding : AssistantBaseCore
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
if (this.SettingsManager.ConfigurationData.Coding.PreselectOptions)
|
||||
{
|
||||
this.provideCompilerMessages = this.SettingsManager.ConfigurationData.Coding.PreselectCompilerMessages;
|
||||
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.Coding.PreselectedProvider);
|
||||
}
|
||||
var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages<string>(Event.SEND_TO_CODING_ASSISTANT).FirstOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.questions = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
@@ -73,6 +97,18 @@ public partial class AssistantCoding : AssistantBaseCore
|
||||
});
|
||||
}
|
||||
|
||||
private ValueTask DeleteContext(int index)
|
||||
{
|
||||
if(this.codingContexts.Count < index + 1)
|
||||
return ValueTask.CompletedTask;
|
||||
|
||||
this.codingContexts.RemoveAt(index);
|
||||
this.form?.ResetValidation();
|
||||
|
||||
this.StateHasChanged();
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task GetSupport()
|
||||
{
|
||||
await this.form!.Validate();
|
||||
@@ -87,9 +123,13 @@ public partial class AssistantCoding : AssistantBaseCore
|
||||
foreach (var codingContext in this.codingContexts)
|
||||
{
|
||||
sbContext.AppendLine($"ID: {codingContext.Id}");
|
||||
sbContext.AppendLine($"Language: {codingContext.Language.Name()}");
|
||||
sbContext.AppendLine($"Other Language: {codingContext.OtherLanguage}");
|
||||
sbContext.AppendLine($"Content:");
|
||||
|
||||
if(codingContext.Language is not CommonCodingLanguages.OTHER)
|
||||
sbContext.AppendLine($"Language: {codingContext.Language.Name()}");
|
||||
else
|
||||
sbContext.AppendLine($"Language: {codingContext.OtherLanguage}");
|
||||
|
||||
sbContext.AppendLine("Content:");
|
||||
sbContext.AppendLine("```");
|
||||
sbContext.AppendLine(codingContext.Code);
|
||||
sbContext.AppendLine("```");
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace AIStudio.Components.Pages.Coding;
|
||||
namespace AIStudio.Assistants.Coding;
|
||||
|
||||
public sealed class CodingContext(string id, CommonCodingLanguages language, string otherLanguage, string code)
|
||||
{
|
||||
File renamed without changes.
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components.Pages.Coding;
|
||||
namespace AIStudio.Assistants.Coding;
|
||||
|
||||
public partial class CodingContextItem : ComponentBase
|
||||
{
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace AIStudio.Components.Pages.Coding;
|
||||
namespace AIStudio.Assistants.Coding;
|
||||
|
||||
public static class CommonCodingLanguageExtensions
|
||||
{
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace AIStudio.Components.Pages.Coding;
|
||||
namespace AIStudio.Assistants.Coding;
|
||||
|
||||
public enum CommonCodingLanguages
|
||||
{
|
||||
@@ -0,0 +1,27 @@
|
||||
@attribute [Route(Routes.ASSISTANT_EMAIL)]
|
||||
@inherits AssistantBaseCore
|
||||
|
||||
<MudTextSwitch Label="Is there a history, a previous conversation?" @bind-Value="@this.provideHistory" LabelOn="Yes, I provide the previous conversation" LabelOff="No, I don't provide a previous conversation" />
|
||||
@if (this.provideHistory)
|
||||
{
|
||||
<MudPaper Class="pa-3 mb-8 border-dashed border rounded-lg">
|
||||
<MudTextField T="string" @bind-Text="@this.inputHistory" Validation="@this.ValidateHistory" Label="Previous conversation" Variant="Variant.Outlined" Lines="6" AutoGrow="@true" MaxLines="12" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="Provide the previous conversation, e.g., the last e-mail, the last chat, etc." Class="mb-3" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.DocumentScanner"/>
|
||||
</MudPaper>
|
||||
}
|
||||
|
||||
<MudTextField T="string" @bind-Text="@this.inputGreeting" Label="(Optional) The greeting phrase to use" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Person" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" Placeholder="Dear Colleagues" Class="mb-3"/>
|
||||
<MudTextField T="string" @bind-Text="@this.inputBulletPoints" Validation="@this.ValidateBulletPoints" AdornmentIcon="@Icons.Material.Filled.ListAlt" Adornment="Adornment.Start" Label="Your bullet points" Variant="Variant.Outlined" Lines="6" AutoGrow="@true" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="Bullet list the content of the e-mail roughly. Use dashes (-) to separate the items." Immediate="@false" DebounceInterval="1_000" OnDebounceIntervalElapsed="@this.OnContentChanged" Placeholder="@PLACEHOLDER_BULLET_POINTS"/>
|
||||
<MudSelect T="string" Label="(Optional) Are any of your points particularly important?" MultiSelection="@true" @bind-SelectedValues="@this.selectedFoci" Variant="Variant.Outlined" Class="mb-3" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.ListAlt">
|
||||
@foreach (var contentLine in this.bulletPointsLines)
|
||||
{
|
||||
<MudSelectItem T="string" Value="@contentLine">@contentLine</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudTextField T="string" @bind-Text="@this.inputName" Label="(Optional) Your name for the closing salutation" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Person" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="Your name for the closing salutation of your e-mail." Class="mb-3"/>
|
||||
<EnumSelection T="WritingStyles" NameFunc="@(style => style.Name())" @bind-Value="@this.selectedWritingStyle" Icon="@Icons.Material.Filled.Edit" Label="Select the writing style" ValidateSelection="@this.ValidateWritingStyle"/>
|
||||
<EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelecting())" @bind-Value="@this.selectedTargetLanguage" ValidateSelection="@this.ValidateTargetLanguage" Icon="@Icons.Material.Filled.Translate" Label="Target language" AllowOther="@true" OtherValue="CommonLanguages.OTHER" @bind-OtherInput="@this.customTargetLanguage" ValidateOther="@this.ValidateCustomLanguage" LabelOther="Custom target language" />
|
||||
<ProviderSelection @bind-ProviderSettings="@this.providerSettings" ValidateProvider="@this.ValidatingProvider"/>
|
||||
|
||||
<MudButton Variant="Variant.Filled" Class="mb-3" OnClick="() => this.CreateMail()">
|
||||
Create e-mail
|
||||
</MudButton>
|
||||
@@ -0,0 +1,245 @@
|
||||
using System.Text;
|
||||
|
||||
using AIStudio.Chat;
|
||||
|
||||
namespace AIStudio.Assistants.EMail;
|
||||
|
||||
public partial class AssistantEMail : AssistantBaseCore
|
||||
{
|
||||
protected override Tools.Components Component => Tools.Components.EMAIL_ASSISTANT;
|
||||
|
||||
protected override string Title => "E-Mail";
|
||||
|
||||
protected override string Description =>
|
||||
"""
|
||||
Provide a list of bullet points and some basic information for an e-mail. The assistant will generate an e-mail based on that input.
|
||||
""";
|
||||
|
||||
protected override string SystemPrompt =>
|
||||
$"""
|
||||
You are an automated system that writes emails. {this.SystemPromptHistory()} The user provides you with bullet points on what
|
||||
he want to address in the response. Regarding the writing style of the email: {this.selectedWritingStyle.Prompt()}
|
||||
{this.SystemPromptGreeting()} {this.SystemPromptName()} You write the email in the following language: {this.SystemPromptLanguage()}.
|
||||
""";
|
||||
|
||||
protected override IReadOnlyList<IButtonData> FooterButtons => [];
|
||||
|
||||
protected override ChatThread ConvertToChatThread => (this.chatThread ?? new()) with
|
||||
{
|
||||
SystemPrompt = SystemPrompts.DEFAULT,
|
||||
};
|
||||
|
||||
protected override void ResetFrom()
|
||||
{
|
||||
this.inputBulletPoints = string.Empty;
|
||||
this.bulletPointsLines.Clear();
|
||||
this.selectedFoci = [];
|
||||
this.provideHistory = false;
|
||||
this.inputHistory = string.Empty;
|
||||
if (!this.MightPreselectValues())
|
||||
{
|
||||
this.inputName = string.Empty;
|
||||
this.selectedTargetLanguage = CommonLanguages.AS_IS;
|
||||
this.customTargetLanguage = string.Empty;
|
||||
this.selectedWritingStyle = WritingStyles.NONE;
|
||||
this.inputGreeting = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool MightPreselectValues()
|
||||
{
|
||||
if (this.SettingsManager.ConfigurationData.EMail.PreselectOptions)
|
||||
{
|
||||
this.inputName = this.SettingsManager.ConfigurationData.EMail.SenderName;
|
||||
this.inputGreeting = this.SettingsManager.ConfigurationData.EMail.Greeting;
|
||||
this.selectedWritingStyle = this.SettingsManager.ConfigurationData.EMail.PreselectedWritingStyle;
|
||||
this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.EMail.PreselectedTargetLanguage;
|
||||
this.customTargetLanguage = this.SettingsManager.ConfigurationData.EMail.PreselectOtherLanguage;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private const string PLACEHOLDER_BULLET_POINTS = """
|
||||
- The last meeting was good
|
||||
- Thank you for feedback
|
||||
- Next is milestone 3
|
||||
- I need your input by next Wednesday
|
||||
""";
|
||||
|
||||
private WritingStyles selectedWritingStyle = WritingStyles.NONE;
|
||||
private string inputGreeting = string.Empty;
|
||||
private string inputBulletPoints = string.Empty;
|
||||
private readonly List<string> bulletPointsLines = [];
|
||||
private IEnumerable<string> selectedFoci = new HashSet<string>();
|
||||
private string inputName = string.Empty;
|
||||
private CommonLanguages selectedTargetLanguage = CommonLanguages.AS_IS;
|
||||
private string customTargetLanguage = string.Empty;
|
||||
private bool provideHistory;
|
||||
private string inputHistory = string.Empty;
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages<string>(Event.SEND_TO_EMAIL_ASSISTANT).FirstOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputBulletPoints = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private string? ValidateBulletPoints(string content)
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(content))
|
||||
return "Please provide some content for the e-mail.";
|
||||
|
||||
var lines = content.Split('\n', StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
if(!line.TrimStart().StartsWith('-'))
|
||||
return "Please start each line of your content list with a dash (-) to create a bullet point list.";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string? ValidateTargetLanguage(CommonLanguages language)
|
||||
{
|
||||
if(language is CommonLanguages.AS_IS)
|
||||
return "Please select a target language for the e-mail.";
|
||||
|
||||
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? ValidateWritingStyle(WritingStyles style)
|
||||
{
|
||||
if(style == WritingStyles.NONE)
|
||||
return "Please select a writing style for the e-mail.";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string? ValidateHistory(string history)
|
||||
{
|
||||
if(this.provideHistory && string.IsNullOrWhiteSpace(history))
|
||||
return "Please provide some history for the e-mail.";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void OnContentChanged(string content)
|
||||
{
|
||||
this.bulletPointsLines.Clear();
|
||||
var previousSelectedFoci = new HashSet<string>();
|
||||
foreach (var line in content.AsSpan().EnumerateLines())
|
||||
{
|
||||
var trimmedLine = line.Trim();
|
||||
if (trimmedLine.StartsWith("-"))
|
||||
trimmedLine = trimmedLine[1..].Trim();
|
||||
|
||||
if (trimmedLine.Length == 0)
|
||||
continue;
|
||||
|
||||
var finalLine = trimmedLine.ToString();
|
||||
if(this.selectedFoci.Any(x => x.StartsWith(finalLine, StringComparison.InvariantCultureIgnoreCase)))
|
||||
previousSelectedFoci.Add(finalLine);
|
||||
|
||||
this.bulletPointsLines.Add(finalLine);
|
||||
}
|
||||
|
||||
this.selectedFoci = previousSelectedFoci;
|
||||
}
|
||||
|
||||
private string SystemPromptHistory()
|
||||
{
|
||||
if (this.provideHistory)
|
||||
return "You receive the previous conversation as context.";
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private string SystemPromptGreeting()
|
||||
{
|
||||
if(!string.IsNullOrWhiteSpace(this.inputGreeting))
|
||||
return $"Your greeting should consider the following formulation: {this.inputGreeting}.";
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private string SystemPromptName()
|
||||
{
|
||||
if(!string.IsNullOrWhiteSpace(this.inputName))
|
||||
return $"For the closing phrase of the email, please use the following name: {this.inputName}.";
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private string SystemPromptLanguage()
|
||||
{
|
||||
if(this.selectedTargetLanguage is CommonLanguages.AS_IS)
|
||||
return "Use the same language as the input";
|
||||
|
||||
if(this.selectedTargetLanguage is CommonLanguages.OTHER)
|
||||
return this.customTargetLanguage;
|
||||
|
||||
return this.selectedTargetLanguage.Name();
|
||||
}
|
||||
|
||||
private string PromptFoci()
|
||||
{
|
||||
if(!this.selectedFoci.Any())
|
||||
return string.Empty;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("I want to amplify the following points:");
|
||||
foreach (var focus in this.selectedFoci)
|
||||
sb.AppendLine($"- {focus}");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private string PromptHistory()
|
||||
{
|
||||
if(!this.provideHistory)
|
||||
return string.Empty;
|
||||
|
||||
return $"""
|
||||
The previous conversation was:
|
||||
|
||||
```
|
||||
{this.inputHistory}
|
||||
```
|
||||
""";
|
||||
}
|
||||
|
||||
private async Task CreateMail()
|
||||
{
|
||||
await this.form!.Validate();
|
||||
if (!this.inputIsValid)
|
||||
return;
|
||||
|
||||
this.CreateChatThread();
|
||||
var time = this.AddUserRequest(
|
||||
$"""
|
||||
{this.PromptHistory()}
|
||||
|
||||
My bullet points for the e-mail are:
|
||||
|
||||
{this.inputBulletPoints}
|
||||
|
||||
{this.PromptFoci()}
|
||||
""");
|
||||
|
||||
await this.AddAIResponseAsync(time);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace AIStudio.Assistants.EMail;
|
||||
|
||||
public enum WritingStyles
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
BUSINESS_FORMAL,
|
||||
BUSINESS_INFORMAL,
|
||||
ACADEMIC,
|
||||
PERSONAL,
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace AIStudio.Assistants.EMail;
|
||||
|
||||
public static class WritingStylesExtensions
|
||||
{
|
||||
public static string Name(this WritingStyles style) => style switch
|
||||
{
|
||||
WritingStyles.ACADEMIC => "Academic",
|
||||
WritingStyles.PERSONAL => "Personal",
|
||||
WritingStyles.BUSINESS_FORMAL => "Business formal",
|
||||
WritingStyles.BUSINESS_INFORMAL => "Business informal",
|
||||
|
||||
_ => "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.",
|
||||
|
||||
_ => "Use a formal business style for this e-mail.",
|
||||
};
|
||||
}
|
||||
+1
-2
@@ -1,5 +1,4 @@
|
||||
@using AIStudio.Tools
|
||||
@page "/assistant/grammar-spelling"
|
||||
@attribute [Route(Routes.ASSISTANT_GRAMMAR_SPELLING)]
|
||||
@inherits AssistantBaseCore
|
||||
|
||||
<MudTextField T="string" @bind-Text="@this.inputText" Validation="@this.ValidateText" AdornmentIcon="@Icons.Material.Filled.DocumentScanner" Adornment="Adornment.Start" Label="Your input to check" Variant="Variant.Outlined" Lines="6" AutoGrow="@true" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
|
||||
+41
-7
@@ -1,9 +1,11 @@
|
||||
using AIStudio.Tools;
|
||||
using AIStudio.Chat;
|
||||
|
||||
namespace AIStudio.Components.Pages.GrammarSpelling;
|
||||
namespace AIStudio.Assistants.GrammarSpelling;
|
||||
|
||||
public partial class AssistantGrammarSpelling : AssistantBaseCore
|
||||
{
|
||||
protected override Tools.Components Component => Tools.Components.GRAMMAR_SPELLING_ASSISTANT;
|
||||
|
||||
protected override string Title => "Grammar & Spelling Checker";
|
||||
|
||||
protected override string Description =>
|
||||
@@ -25,22 +27,54 @@ public partial class AssistantGrammarSpelling : AssistantBaseCore
|
||||
|
||||
protected override bool ShowDedicatedProgress => true;
|
||||
|
||||
protected override IReadOnlyList<ButtonData> FooterButtons => new[]
|
||||
protected override Func<string> Result2Copy => () => this.correctedText;
|
||||
|
||||
protected override IReadOnlyList<IButtonData> FooterButtons =>
|
||||
[
|
||||
new SendToButton
|
||||
{
|
||||
Self = Tools.Components.GRAMMAR_SPELLING_ASSISTANT,
|
||||
UseResultingContentBlockData = false,
|
||||
GetText = () => string.IsNullOrWhiteSpace(this.correctedText) ? this.inputText : this.correctedText
|
||||
},
|
||||
];
|
||||
|
||||
protected override ChatThread ConvertToChatThread => (this.chatThread ?? new()) with
|
||||
{
|
||||
new ButtonData("Copy result", Icons.Material.Filled.ContentCopy, Color.Default, string.Empty, () => this.CopyToClipboard(this.correctedText)),
|
||||
SystemPrompt = SystemPrompts.DEFAULT,
|
||||
};
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
protected override void ResetFrom()
|
||||
{
|
||||
this.inputText = string.Empty;
|
||||
this.correctedText = string.Empty;
|
||||
if (!this.MightPreselectValues())
|
||||
{
|
||||
this.selectedTargetLanguage = CommonLanguages.AS_IS;
|
||||
this.customTargetLanguage = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
protected override bool MightPreselectValues()
|
||||
{
|
||||
if (this.SettingsManager.ConfigurationData.GrammarSpelling.PreselectOptions)
|
||||
{
|
||||
this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.GrammarSpelling.PreselectedTargetLanguage;
|
||||
this.customTargetLanguage = this.SettingsManager.ConfigurationData.GrammarSpelling.PreselectedOtherLanguage;
|
||||
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.GrammarSpelling.PreselectedProvider);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages<string>(Event.SEND_TO_GRAMMAR_SPELLING_ASSISTANT).FirstOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputText = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
@page "/assistant/icons"
|
||||
@attribute [Route(Routes.ASSISTANT_ICON_FINDER)]
|
||||
@inherits AssistantBaseCore
|
||||
|
||||
<MudTextField T="string" @bind-Text="@this.inputContext" Validation="@this.ValidatingContext" AdornmentIcon="@Icons.Material.Filled.Description" Adornment="Adornment.Start" Label="Your context" Variant="Variant.Outlined" Lines="3" AutoGrow="@true" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
|
||||
+40
-18
@@ -1,24 +1,8 @@
|
||||
namespace AIStudio.Components.Pages.IconFinder;
|
||||
namespace AIStudio.Assistants.IconFinder;
|
||||
|
||||
public partial class AssistantIconFinder : AssistantBaseCore
|
||||
{
|
||||
private string inputContext = string.Empty;
|
||||
private IconSources selectedIconSource;
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
if (this.SettingsManager.ConfigurationData.IconFinder.PreselectOptions)
|
||||
{
|
||||
this.selectedIconSource = this.SettingsManager.ConfigurationData.IconFinder.PreselectedSource;
|
||||
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.IconFinder.PreselectedProvider);
|
||||
}
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
#endregion
|
||||
protected override Tools.Components Component => Tools.Components.ICON_FINDER_ASSISTANT;
|
||||
|
||||
protected override string Title => "Icon Finder";
|
||||
|
||||
@@ -40,7 +24,45 @@ public partial class AssistantIconFinder : AssistantBaseCore
|
||||
related to the keyword "buildings" might be the best match. Provide your keywords in a Markdown list without
|
||||
quotation marks.
|
||||
""";
|
||||
|
||||
protected override IReadOnlyList<IButtonData> FooterButtons => [];
|
||||
|
||||
protected override void ResetFrom()
|
||||
{
|
||||
this.inputContext = string.Empty;
|
||||
if (!this.MightPreselectValues())
|
||||
{
|
||||
this.selectedIconSource = IconSources.GENERIC;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool MightPreselectValues()
|
||||
{
|
||||
if (this.SettingsManager.ConfigurationData.IconFinder.PreselectOptions)
|
||||
{
|
||||
this.selectedIconSource = this.SettingsManager.ConfigurationData.IconFinder.PreselectedSource;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private string inputContext = string.Empty;
|
||||
private IconSources selectedIconSource;
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages<string>(Event.SEND_TO_ICON_FINDER_ASSISTANT).FirstOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputContext = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private string? ValidatingContext(string context)
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(context))
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace AIStudio.Components.Pages.IconFinder;
|
||||
namespace AIStudio.Assistants.IconFinder;
|
||||
|
||||
public static class IconSourceExtensions
|
||||
{
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace AIStudio.Components.Pages.IconFinder;
|
||||
namespace AIStudio.Assistants.IconFinder;
|
||||
|
||||
public enum IconSources
|
||||
{
|
||||
@@ -0,0 +1,15 @@
|
||||
@attribute [Route(Routes.ASSISTANT_LEGAL_CHECK)]
|
||||
@inherits AssistantBaseCore
|
||||
|
||||
@if (!this.SettingsManager.ConfigurationData.LegalCheck.HideWebContentReader)
|
||||
{
|
||||
<ReadWebContent @bind-Content="@this.inputLegalDocument" ProviderSettings="@this.providerSettings" @bind-AgentIsRunning="@this.isAgentRunning" Preselect="@(this.SettingsManager.ConfigurationData.LegalCheck.PreselectOptions && this.SettingsManager.ConfigurationData.LegalCheck.PreselectWebContentReader)" PreselectContentCleanerAgent="@(this.SettingsManager.ConfigurationData.LegalCheck.PreselectOptions && this.SettingsManager.ConfigurationData.LegalCheck.PreselectContentCleanerAgent)"/>
|
||||
}
|
||||
|
||||
<MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.inputLegalDocument" Validation="@this.ValidatingLegalDocument" AdornmentIcon="@Icons.Material.Filled.DocumentScanner" Adornment="Adornment.Start" Label="Legal document" Variant="Variant.Outlined" Lines="12" AutoGrow="@true" MaxLines="24" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
|
||||
<MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.inputQuestions" Validation="@this.ValidatingQuestions" AdornmentIcon="@Icons.Material.Filled.QuestionAnswer" Adornment="Adornment.Start" Label="Your questions" Variant="Variant.Outlined" Lines="6" AutoGrow="@true" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
|
||||
<ProviderSelection @bind-ProviderSettings="@this.providerSettings" ValidateProvider="@this.ValidatingProvider"/>
|
||||
|
||||
<MudButton Disabled="@this.isAgentRunning" Variant="Variant.Filled" Class="mb-3" OnClick="() => this.AksQuestions()">
|
||||
Ask your questions
|
||||
</MudButton>
|
||||
@@ -0,0 +1,87 @@
|
||||
namespace AIStudio.Assistants.LegalCheck;
|
||||
|
||||
public partial class AssistantLegalCheck : AssistantBaseCore
|
||||
{
|
||||
protected override Tools.Components Component => Tools.Components.LEGAL_CHECK_ASSISTANT;
|
||||
|
||||
protected override string Title => "Legal Check";
|
||||
|
||||
protected override string Description =>
|
||||
"""
|
||||
Provide a legal document and ask a question about it. This assistant does not
|
||||
replace legal advice. Consult a lawyer to get professional advice. Remember
|
||||
that LLMs can invent answers and facts. Please do not rely on this answers.
|
||||
""";
|
||||
|
||||
protected override string SystemPrompt =>
|
||||
"""
|
||||
You are an expert in legal matters. You have studied international law and are familiar with the law in
|
||||
various countries. You receive a legal document and answer the user's questions. You are a friendly and
|
||||
professional assistant. You respond to the user in the language in which the questions were asked. If
|
||||
you are unsure, unfamiliar with the legal area, or do not know the answers, you inform the user.
|
||||
Never invent facts!
|
||||
""";
|
||||
|
||||
protected override IReadOnlyList<IButtonData> FooterButtons => [];
|
||||
|
||||
protected override void ResetFrom()
|
||||
{
|
||||
this.inputLegalDocument = string.Empty;
|
||||
this.inputQuestions = string.Empty;
|
||||
this.MightPreselectValues();
|
||||
}
|
||||
|
||||
protected override bool MightPreselectValues() => false;
|
||||
|
||||
private bool isAgentRunning;
|
||||
private string inputLegalDocument = string.Empty;
|
||||
private string inputQuestions = string.Empty;
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages<string>(Event.SEND_TO_LEGAL_CHECK_ASSISTANT).FirstOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputQuestions = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private string? ValidatingLegalDocument(string text)
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(text))
|
||||
return "Please provide a legal document as input. You might copy the desired text from a document or a website.";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string? ValidatingQuestions(string text)
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(text))
|
||||
return "Please provide your questions as input.";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private async Task AksQuestions()
|
||||
{
|
||||
await this.form!.Validate();
|
||||
if (!this.inputIsValid)
|
||||
return;
|
||||
|
||||
this.CreateChatThread();
|
||||
var time = this.AddUserRequest(
|
||||
$"""
|
||||
# The legal document
|
||||
{this.inputLegalDocument}
|
||||
|
||||
# The questions
|
||||
{this.inputQuestions}
|
||||
""");
|
||||
|
||||
await this.AddAIResponseAsync(time);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
@using AIStudio.Tools
|
||||
@page "/assistant/rewrite-improve"
|
||||
@attribute [Route(Routes.ASSISTANT_REWRITE)]
|
||||
@inherits AssistantBaseCore
|
||||
|
||||
<MudTextField T="string" @bind-Text="@this.inputText" Validation="@this.ValidateText" AdornmentIcon="@Icons.Material.Filled.DocumentScanner" Adornment="Adornment.Start" Label="Your input to improve" Variant="Variant.Outlined" Lines="6" AutoGrow="@true" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
|
||||
<EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelectingOptional())" @bind-Value="@this.selectedTargetLanguage" Icon="@Icons.Material.Filled.Translate" Label="Language" AllowOther="@true" OtherValue="CommonLanguages.OTHER" @bind-OtherInput="@this.customTargetLanguage" ValidateOther="@this.ValidateCustomLanguage" LabelOther="Custom language" />
|
||||
<EnumSelection T="WritingStyles" NameFunc="@(style => style.Name())" @bind-Value="@this.selectedWritingStyle" Icon="@Icons.Material.Filled.Edit" Label="Writing style" AllowOther="@false" />
|
||||
<EnumSelection T="SentenceStructure" NameFunc="@(voice => voice.Name())" @bind-Value="@this.selectedSentenceStructure" Icon="@Icons.Material.Filled.Person4" Label="Sentence structure" />
|
||||
<ProviderSelection @bind-ProviderSettings="@this.providerSettings" ValidateProvider="@this.ValidatingProvider"/>
|
||||
|
||||
<MudButton Variant="Variant.Filled" Class="mb-3" OnClick="() => this.RewriteText()">
|
||||
+50
-16
@@ -1,9 +1,11 @@
|
||||
using AIStudio.Tools;
|
||||
using AIStudio.Chat;
|
||||
|
||||
namespace AIStudio.Components.Pages.RewriteImprove;
|
||||
namespace AIStudio.Assistants.RewriteImprove;
|
||||
|
||||
public partial class AssistantRewriteImprove : AssistantBaseCore
|
||||
{
|
||||
protected override Tools.Components Component => Tools.Components.REWRITE_ASSISTANT;
|
||||
|
||||
protected override string Title => "Rewrite & Improve Text";
|
||||
|
||||
protected override string Description =>
|
||||
@@ -18,35 +20,66 @@ public partial class AssistantRewriteImprove : AssistantBaseCore
|
||||
text. You can also correct spelling and grammar issues. You never add additional information. You never
|
||||
ask the user for additional information. Your response only contains the improved text. You do not explain
|
||||
your changes. If no changes are needed, you return the text unchanged.
|
||||
The style of the text: {this.selectedWritingStyle.Prompt()}. You follow the rules according
|
||||
to {this.SystemPromptLanguage()} in all your changes.
|
||||
The style of the text: {this.selectedWritingStyle.Prompt()}.{this.selectedSentenceStructure.Prompt()}
|
||||
You follow the rules according to {this.SystemPromptLanguage()} in all your changes.
|
||||
""";
|
||||
|
||||
protected override bool ShowResult => false;
|
||||
|
||||
#region Overrides of AssistantBase
|
||||
|
||||
protected override bool ShowDedicatedProgress => true;
|
||||
|
||||
#endregion
|
||||
|
||||
protected override IReadOnlyList<ButtonData> FooterButtons => new[]
|
||||
{
|
||||
new ButtonData("Copy result", Icons.Material.Filled.ContentCopy, Color.Default, string.Empty, () => this.CopyToClipboard(this.rewrittenText)),
|
||||
};
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
protected override Func<string> Result2Copy => () => this.rewrittenText;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
protected override IReadOnlyList<IButtonData> FooterButtons =>
|
||||
[
|
||||
new SendToButton
|
||||
{
|
||||
Self = Tools.Components.REWRITE_ASSISTANT,
|
||||
UseResultingContentBlockData = false,
|
||||
GetText = () => string.IsNullOrWhiteSpace(this.rewrittenText) ? this.inputText : this.rewrittenText,
|
||||
},
|
||||
];
|
||||
|
||||
protected override ChatThread ConvertToChatThread => (this.chatThread ?? new()) with
|
||||
{
|
||||
SystemPrompt = SystemPrompts.DEFAULT,
|
||||
};
|
||||
|
||||
protected override void ResetFrom()
|
||||
{
|
||||
this.inputText = string.Empty;
|
||||
this.rewrittenText = string.Empty;
|
||||
if (!this.MightPreselectValues())
|
||||
{
|
||||
this.selectedTargetLanguage = CommonLanguages.AS_IS;
|
||||
this.customTargetLanguage = string.Empty;
|
||||
this.selectedWritingStyle = WritingStyles.NOT_SPECIFIED;
|
||||
this.selectedSentenceStructure = SentenceStructure.NOT_SPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool MightPreselectValues()
|
||||
{
|
||||
if (this.SettingsManager.ConfigurationData.RewriteImprove.PreselectOptions)
|
||||
{
|
||||
this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.RewriteImprove.PreselectedTargetLanguage;
|
||||
this.customTargetLanguage = this.SettingsManager.ConfigurationData.RewriteImprove.PreselectedOtherLanguage;
|
||||
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.RewriteImprove.PreselectedProvider);
|
||||
this.selectedWritingStyle = this.SettingsManager.ConfigurationData.RewriteImprove.PreselectedWritingStyle;
|
||||
this.selectedSentenceStructure = this.SettingsManager.ConfigurationData.RewriteImprove.PreselectedSentenceStructure;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages<string>(Event.SEND_TO_REWRITE_ASSISTANT).FirstOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputText = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
@@ -57,6 +90,7 @@ public partial class AssistantRewriteImprove : AssistantBaseCore
|
||||
private string customTargetLanguage = string.Empty;
|
||||
private string rewrittenText = string.Empty;
|
||||
private WritingStyles selectedWritingStyle;
|
||||
private SentenceStructure selectedSentenceStructure;
|
||||
|
||||
private string? ValidateText(string text)
|
||||
{
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace AIStudio.Assistants.RewriteImprove;
|
||||
|
||||
public enum SentenceStructure
|
||||
{
|
||||
NOT_SPECIFIED = 0,
|
||||
|
||||
ACTIVE,
|
||||
PASSIVE,
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
namespace AIStudio.Assistants.RewriteImprove;
|
||||
|
||||
public static class SentenceStructureExtensions
|
||||
{
|
||||
public static string Name(this SentenceStructure sentenceStructure) => sentenceStructure switch
|
||||
{
|
||||
SentenceStructure.ACTIVE => "Active voice",
|
||||
SentenceStructure.PASSIVE => "Passive voice",
|
||||
|
||||
_ => "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.",
|
||||
|
||||
_ => string.Empty,
|
||||
};
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace AIStudio.Components.Pages.RewriteImprove;
|
||||
namespace AIStudio.Assistants.RewriteImprove;
|
||||
|
||||
public enum WritingStyles
|
||||
{
|
||||
@@ -0,0 +1,34 @@
|
||||
namespace AIStudio.Assistants.RewriteImprove;
|
||||
|
||||
public static class WritingStylesExtensions
|
||||
{
|
||||
public static string Name(this WritingStyles style) => style switch
|
||||
{
|
||||
WritingStyles.EVERYDAY => "Everyday (personal texts, social media)",
|
||||
WritingStyles.BUSINESS => "Business (business emails, reports, presentations)",
|
||||
WritingStyles.SCIENTIFIC => "Scientific (scientific papers, research reports)",
|
||||
WritingStyles.JOURNALISTIC => "Journalistic (magazines, newspapers, news)",
|
||||
WritingStyles.LITERARY => "Literary (fiction, poetry)",
|
||||
WritingStyles.TECHNICAL => "Technical (manuals, documentation)",
|
||||
WritingStyles.MARKETING => "Marketing (advertisements, sales texts)",
|
||||
WritingStyles.ACADEMIC => "Academic (essays, seminar papers)",
|
||||
WritingStyles.LEGAL => "Legal (legal texts, contracts)",
|
||||
|
||||
_ => "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.",
|
||||
|
||||
_ => "Keep the style of the text as it is.",
|
||||
};
|
||||
}
|
||||
+1
-2
@@ -1,5 +1,4 @@
|
||||
@page "/assistant/summarizer"
|
||||
@using AIStudio.Tools
|
||||
@attribute [Route(Routes.ASSISTANT_SUMMARIZER)]
|
||||
@inherits AssistantBaseCore
|
||||
|
||||
@if (!this.SettingsManager.ConfigurationData.TextSummarizer.HideWebContentReader)
|
||||
+40
-10
@@ -1,9 +1,11 @@
|
||||
using AIStudio.Tools;
|
||||
using AIStudio.Chat;
|
||||
|
||||
namespace AIStudio.Components.Pages.TextSummarizer;
|
||||
namespace AIStudio.Assistants.TextSummarizer;
|
||||
|
||||
public partial class AssistantTextSummarizer : AssistantBaseCore
|
||||
{
|
||||
protected override Tools.Components Component => Tools.Components.TEXT_SUMMARIZER_ASSISTANT;
|
||||
|
||||
protected override string Title => "Text Summarizer";
|
||||
|
||||
protected override string Description =>
|
||||
@@ -23,6 +25,39 @@ public partial class AssistantTextSummarizer : AssistantBaseCore
|
||||
a summary with the requested complexity. In any case, do not add any information.
|
||||
""";
|
||||
|
||||
protected override IReadOnlyList<IButtonData> FooterButtons => [];
|
||||
|
||||
protected override ChatThread ConvertToChatThread => (this.chatThread ?? new()) with
|
||||
{
|
||||
SystemPrompt = SystemPrompts.DEFAULT,
|
||||
};
|
||||
|
||||
protected override void ResetFrom()
|
||||
{
|
||||
this.inputText = string.Empty;
|
||||
if(!this.MightPreselectValues())
|
||||
{
|
||||
this.selectedTargetLanguage = CommonLanguages.AS_IS;
|
||||
this.customTargetLanguage = string.Empty;
|
||||
this.selectedComplexity = Complexity.NO_CHANGE;
|
||||
this.expertInField = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool MightPreselectValues()
|
||||
{
|
||||
if (this.SettingsManager.ConfigurationData.TextSummarizer.PreselectOptions)
|
||||
{
|
||||
this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.TextSummarizer.PreselectedTargetLanguage;
|
||||
this.customTargetLanguage = this.SettingsManager.ConfigurationData.TextSummarizer.PreselectedOtherLanguage;
|
||||
this.selectedComplexity = this.SettingsManager.ConfigurationData.TextSummarizer.PreselectedComplexity;
|
||||
this.expertInField = this.SettingsManager.ConfigurationData.TextSummarizer.PreselectedExpertInField;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private string inputText = string.Empty;
|
||||
private bool isAgentRunning;
|
||||
private CommonLanguages selectedTargetLanguage;
|
||||
@@ -34,14 +69,9 @@ public partial class AssistantTextSummarizer : AssistantBaseCore
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
if(this.SettingsManager.ConfigurationData.TextSummarizer.PreselectOptions)
|
||||
{
|
||||
this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.TextSummarizer.PreselectedTargetLanguage;
|
||||
this.customTargetLanguage = this.SettingsManager.ConfigurationData.TextSummarizer.PreselectedOtherLanguage;
|
||||
this.selectedComplexity = this.SettingsManager.ConfigurationData.TextSummarizer.PreselectedComplexity;
|
||||
this.expertInField = this.SettingsManager.ConfigurationData.TextSummarizer.PreselectedExpertInField;
|
||||
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.TextSummarizer.PreselectedProvider);
|
||||
}
|
||||
var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages<string>(Event.SEND_TO_TEXT_SUMMARIZER_ASSISTANT).FirstOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputText = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace AIStudio.Components.Pages.TextSummarizer;
|
||||
namespace AIStudio.Assistants.TextSummarizer;
|
||||
|
||||
public enum Complexity
|
||||
{
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace AIStudio.Components.Pages.TextSummarizer;
|
||||
namespace AIStudio.Assistants.TextSummarizer;
|
||||
|
||||
public static class ComplexityExtensions
|
||||
{
|
||||
+1
-2
@@ -1,5 +1,4 @@
|
||||
@page "/assistant/translation"
|
||||
@using AIStudio.Tools
|
||||
@attribute [Route(Routes.ASSISTANT_TRANSLATION)]
|
||||
@inherits AssistantBaseCore
|
||||
|
||||
@if (!this.SettingsManager.ConfigurationData.Translation.HideWebContentReader)
|
||||
+39
-9
@@ -1,9 +1,11 @@
|
||||
using AIStudio.Tools;
|
||||
using AIStudio.Chat;
|
||||
|
||||
namespace AIStudio.Components.Pages.Translation;
|
||||
namespace AIStudio.Assistants.Translation;
|
||||
|
||||
public partial class AssistantTranslation : AssistantBaseCore
|
||||
{
|
||||
protected override Tools.Components Component => Tools.Components.TRANSLATION_ASSISTANT;
|
||||
|
||||
protected override string Title => "Translation";
|
||||
|
||||
protected override string Description =>
|
||||
@@ -19,6 +21,38 @@ public partial class AssistantTranslation : AssistantBaseCore
|
||||
language requires, e.g., shorter sentences, you should split the text into shorter sentences.
|
||||
""";
|
||||
|
||||
protected override IReadOnlyList<IButtonData> FooterButtons => [];
|
||||
|
||||
protected override ChatThread ConvertToChatThread => (this.chatThread ?? new()) with
|
||||
{
|
||||
SystemPrompt = SystemPrompts.DEFAULT,
|
||||
};
|
||||
|
||||
protected override void ResetFrom()
|
||||
{
|
||||
this.inputText = string.Empty;
|
||||
this.inputTextLastTranslation = string.Empty;
|
||||
if (!this.MightPreselectValues())
|
||||
{
|
||||
this.liveTranslation = false;
|
||||
this.selectedTargetLanguage = CommonLanguages.AS_IS;
|
||||
this.customTargetLanguage = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool MightPreselectValues()
|
||||
{
|
||||
if (this.SettingsManager.ConfigurationData.Translation.PreselectOptions)
|
||||
{
|
||||
this.liveTranslation = this.SettingsManager.ConfigurationData.Translation.PreselectLiveTranslation;
|
||||
this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.Translation.PreselectedTargetLanguage;
|
||||
this.customTargetLanguage = this.SettingsManager.ConfigurationData.Translation.PreselectOtherLanguage;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool liveTranslation;
|
||||
private bool isAgentRunning;
|
||||
private string inputText = string.Empty;
|
||||
@@ -30,13 +64,9 @@ public partial class AssistantTranslation : AssistantBaseCore
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
if (this.SettingsManager.ConfigurationData.Translation.PreselectOptions)
|
||||
{
|
||||
this.liveTranslation = this.SettingsManager.ConfigurationData.Translation.PreselectLiveTranslation;
|
||||
this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.Translation.PreselectedTargetLanguage;
|
||||
this.customTargetLanguage = this.SettingsManager.ConfigurationData.Translation.PreselectOtherLanguage;
|
||||
this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.Translation.PreselectedProvider);
|
||||
}
|
||||
var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages<string>(Event.SEND_TO_TRANSLATION_ASSISTANT).FirstOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputText = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
@using AIStudio
|
||||
@using AIStudio.Tools
|
||||
@using AIStudio.Components
|
||||
@using MudBlazor
|
||||
@@ -3,7 +3,7 @@ namespace AIStudio.Chat;
|
||||
/// <summary>
|
||||
/// Data structure for a chat thread.
|
||||
/// </summary>
|
||||
public sealed class ChatThread
|
||||
public sealed record ChatThread
|
||||
{
|
||||
/// <summary>
|
||||
/// The unique identifier of the chat thread.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using AIStudio.Tools;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
using RustService = AIStudio.Tools.RustService;
|
||||
|
||||
namespace AIStudio.Chat;
|
||||
|
||||
/// <summary>
|
||||
@@ -40,10 +40,7 @@ public partial class ContentBlockComponent : ComponentBase
|
||||
public string Class { get; set; } = string.Empty;
|
||||
|
||||
[Inject]
|
||||
private Rust Rust { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private IJSRuntime JsRuntime { get; init; } = null!;
|
||||
private RustService RustService { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private ISnackbar Snackbar { get; init; } = null!;
|
||||
@@ -100,7 +97,7 @@ public partial class ContentBlockComponent : ComponentBase
|
||||
{
|
||||
case ContentType.TEXT:
|
||||
var textContent = (ContentText) this.Content;
|
||||
await this.Rust.CopyText2Clipboard(this.JsRuntime, this.Snackbar, textContent.Text);
|
||||
await this.RustService.CopyText2Clipboard(this.Snackbar, textContent.Text);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -29,7 +29,7 @@ public sealed class ContentImage : IContent
|
||||
public Func<Task> StreamingEvent { get; set; } = () => Task.CompletedTask;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task CreateFromProviderAsync(IProvider provider, IJSRuntime jsRuntime, SettingsManager settings, Model chatModel, ChatThread chatChatThread, CancellationToken token = default)
|
||||
public Task CreateFromProviderAsync(IProvider provider, SettingsManager settings, Model chatModel, ChatThread chatChatThread, CancellationToken token = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -35,18 +35,18 @@ public sealed class ContentText : IContent
|
||||
public Func<Task> StreamingEvent { get; set; } = () => Task.CompletedTask;
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task CreateFromProviderAsync(IProvider provider, IJSRuntime jsRuntime, SettingsManager settings, Model chatModel, ChatThread? chatThread, CancellationToken token = default)
|
||||
public async Task CreateFromProviderAsync(IProvider provider, SettingsManager settings, Model chatModel, ChatThread? chatThread, CancellationToken token = default)
|
||||
{
|
||||
if(chatThread is null)
|
||||
return;
|
||||
|
||||
// Store the last time we got a response. We use this later,
|
||||
// Store the last time we got a response. We use this ater
|
||||
// to determine whether we should notify the UI about the
|
||||
// new content or not. Depends on the energy saving mode
|
||||
// the user chose.
|
||||
var last = DateTimeOffset.Now;
|
||||
|
||||
// Start another thread by using a task, to uncouple
|
||||
// Start another thread by using a task to uncouple
|
||||
// the UI thread from the AI processing:
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
@@ -54,7 +54,7 @@ public sealed class ContentText : IContent
|
||||
this.InitialRemoteWait = true;
|
||||
|
||||
// Iterate over the responses from the AI:
|
||||
await foreach (var deltaText in provider.StreamChatCompletion(jsRuntime, settings, chatModel, chatThread, token))
|
||||
await foreach (var deltaText in provider.StreamChatCompletion(chatModel, chatThread, token))
|
||||
{
|
||||
// When the user cancels the request, we stop the loop:
|
||||
if (token.IsCancellationRequested)
|
||||
@@ -89,7 +89,7 @@ public sealed class ContentText : IContent
|
||||
}
|
||||
|
||||
// Stop the waiting animation (in case the loop
|
||||
// was stopped or no content was received):
|
||||
// was stopped, or no content was received):
|
||||
this.InitialRemoteWait = false;
|
||||
this.IsStreaming = false;
|
||||
}, token);
|
||||
|
||||
@@ -42,5 +42,5 @@ public interface IContent
|
||||
/// <summary>
|
||||
/// Uses the provider to create the content.
|
||||
/// </summary>
|
||||
public Task CreateFromProviderAsync(IProvider provider, IJSRuntime jsRuntime, SettingsManager settings, Model chatModel, ChatThread chatChatThread, CancellationToken token = default);
|
||||
public Task CreateFromProviderAsync(IProvider provider, SettingsManager settings, Model chatModel, ChatThread chatChatThread, CancellationToken token = default);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace AIStudio.Chat;
|
||||
|
||||
public static class SystemPrompts
|
||||
{
|
||||
public const string DEFAULT = "You are a helpful assistant!";
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
@* ReSharper disable Html.PathError *@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title>MindWork AI Studio</title>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<base href="/"/>
|
||||
|
||||
<link rel="icon" type="image/png" href="favicon.png"/>
|
||||
<link href="system/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
|
||||
<link href="system/MudBlazor.Markdown/MudBlazor.Markdown.min.css" rel="stylesheet" />
|
||||
<link href="app.css" rel="stylesheet" />
|
||||
<HeadOutlet/>
|
||||
<script src="diff.js"></script>
|
||||
</head>
|
||||
|
||||
<body style="overflow: hidden;">
|
||||
<Routes @rendermode="new InteractiveServerRenderMode(prerender: false)"/>
|
||||
<script src="_framework/blazor.web.js" autostart="false"></script>
|
||||
<script src="boot.js"></script>
|
||||
<script src="system/MudBlazor/MudBlazor.min.js"></script>
|
||||
<script src="system/MudBlazor.Markdown/MudBlazor.Markdown.min.js"></script>
|
||||
<script src="app.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,59 +0,0 @@
|
||||
@using AIStudio.Chat
|
||||
<MudText Typo="Typo.h3" Class="mb-2 mr-3">
|
||||
@this.Title
|
||||
</MudText>
|
||||
|
||||
<InnerScrolling HeaderHeight="12.3em">
|
||||
<ChildContent>
|
||||
<MudForm @ref="@this.form" @bind-IsValid="@this.inputIsValid" @bind-Errors="@this.inputIssues" Class="pr-2">
|
||||
<MudText Typo="Typo.body1" Align="Align.Justify" Class="mb-6">
|
||||
@this.Description
|
||||
</MudText>
|
||||
|
||||
@if (this.Body is not null)
|
||||
{
|
||||
@this.Body
|
||||
}
|
||||
</MudForm>
|
||||
<Issues IssuesData="@this.inputIssues"/>
|
||||
|
||||
@if (this.ShowDedicatedProgress && this.isProcessing)
|
||||
{
|
||||
<MudProgressLinear Color="Color.Primary" Indeterminate="true" Class="mb-6" />
|
||||
}
|
||||
<div id="@ASSISTANT_RESULT_DIV_ID" class="mr-2 mt-3">
|
||||
@if (this.ShowResult && this.resultingContentBlock is not null)
|
||||
{
|
||||
<ContentBlockComponent Role="@this.resultingContentBlock.Role" Type="@this.resultingContentBlock.ContentType" Time="@this.resultingContentBlock.Time" Content="@this.resultingContentBlock.Content"/>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div id="@AFTER_RESULT_DIV_ID" class="mt-3">
|
||||
</div>
|
||||
|
||||
@if (this.FooterButtons.Count > 0)
|
||||
{
|
||||
<MudStack Row="@true" Wrap="Wrap.Wrap" Class="mt-3 mr-2">
|
||||
@foreach (var buttonData in this.FooterButtons)
|
||||
{
|
||||
switch (buttonData)
|
||||
{
|
||||
case var _ when !string.IsNullOrWhiteSpace(buttonData.Tooltip):
|
||||
<MudTooltip Text="@buttonData.Tooltip">
|
||||
<MudButton Variant="Variant.Filled" Color="@buttonData.Color" StartIcon="@GetButtonIcon(buttonData.Icon)" OnClick="async () => await buttonData.AsyncAction()">
|
||||
@buttonData.Text
|
||||
</MudButton>
|
||||
</MudTooltip>
|
||||
break;
|
||||
|
||||
default:
|
||||
<MudButton Variant="Variant.Filled" Color="@buttonData.Color" StartIcon="@GetButtonIcon(buttonData.Icon)" OnClick="async () => await buttonData.AsyncAction()">
|
||||
@buttonData.Text
|
||||
</MudButton>
|
||||
break;
|
||||
}
|
||||
}
|
||||
</MudStack>
|
||||
}
|
||||
</ChildContent>
|
||||
</InnerScrolling>
|
||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components.Blocks;
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public partial class AssistantBlock : ComponentBase
|
||||
{
|
||||
@@ -1 +0,0 @@
|
||||
<ConfigurationSelect OptionDescription="Preselected provider" Disabled="@this.Disabled" OptionHelp="Select a provider that is preselected." Data="@this.Data" SelectedValue="@this.SelectedValue" SelectionUpdate="@this.SelectionUpdate"/>
|
||||
@@ -1,11 +0,0 @@
|
||||
<MudExpansionPanel Class="border-solid border rounded-lg" Expanded="@this.IsExpanded">
|
||||
<TitleContent>
|
||||
<div class="d-flex align-center">
|
||||
<MudIcon Icon="@this.HeaderIcon" Size="@this.IconSize" Color="@this.IconColor" class="mr-3"/>
|
||||
<MudText Typo="Typo.h6">@this.HeaderText</MudText>
|
||||
</div>
|
||||
</TitleContent>
|
||||
<ChildContent>
|
||||
@this.ChildContent
|
||||
</ChildContent>
|
||||
</MudExpansionPanel>
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace AIStudio.Components.Blocks;
|
||||
|
||||
public interface ITreeItem;
|
||||
@@ -1,9 +0,0 @@
|
||||
@inherits MSGComponentBase
|
||||
|
||||
<div class="d-flex flex-column" style="@this.Height">
|
||||
<div class="flex-auto overflow-auto">
|
||||
@this.ChildContent
|
||||
</div>
|
||||
|
||||
@this.FooterContent
|
||||
</div>
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace AIStudio.Components.Blocks;
|
||||
|
||||
public readonly record struct TreeDivider : ITreeItem;
|
||||
+9
-1
@@ -1,4 +1,4 @@
|
||||
namespace AIStudio.Components.Blocks;
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public partial class Changelog
|
||||
{
|
||||
@@ -13,6 +13,14 @@ public partial class Changelog
|
||||
|
||||
public static readonly Log[] LOGS =
|
||||
[
|
||||
new (178, "v0.9.3, build 178 (2024-09-06 11:06 UTC)", "v0.9.3.md"),
|
||||
new (177, "v0.9.2, build 177 (2024-09-05 09:19 UTC)", "v0.9.2.md"),
|
||||
new (176, "v0.9.1, build 176 (2024-09-04 13:48 UTC)", "v0.9.1.md"),
|
||||
new (175, "v0.9.0, build 175 (2024-09-03 16:00 UTC)", "v0.9.0.md"),
|
||||
new (174, "v0.8.12, build 174 (2024-08-24 08:30 UTC)", "v0.8.12.md"),
|
||||
new (173, "v0.8.11, build 173 (2024-08-21 07:03 UTC)", "v0.8.11.md"),
|
||||
new (172, "v0.8.10, build 172 (2024-08-18 19:44 UTC)", "v0.8.10.md"),
|
||||
new (171, "v0.8.9, build 171 (2024-08-18 10:35 UTC)", "v0.8.9.md"),
|
||||
new (170, "v0.8.8, build 170 (2024-08-14 06:30 UTC)", "v0.8.8.md"),
|
||||
new (169, "v0.8.7, build 169 (2024-08-01 19:08 UTC)", "v0.8.7.md"),
|
||||
new (168, "v0.8.6, build 168 (2024-08-01 19:50 UTC)", "v0.8.6.md"),
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
@using AIStudio.Tools
|
||||
<MudSelect T="Log" @bind-Value="@this.SelectedLog" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Schedule" Margin="Margin.Dense" Label="Changelog" Class="mb-2 rounded-lg" Variant="Variant.Outlined" SelectedValuesChanged="() => this.ReadLogAsync()" OnKeyUp="() => this.ReadLogAsync()">
|
||||
@foreach (var log in LOGS)
|
||||
{
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components.Blocks;
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public partial class Changelog : ComponentBase
|
||||
{
|
||||
@@ -1,5 +1,4 @@
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Tools;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
|
||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components.Blocks;
|
||||
namespace AIStudio.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Configuration component for any boolean option.
|
||||
@@ -0,0 +1 @@
|
||||
<ConfigurationSelect OptionDescription="Preselected provider" Disabled="@this.Disabled" OptionHelp="@this.HelpText()" Data="@this.Data" SelectedValue="@this.SelectedValue" SelectionUpdate="@this.SelectionUpdate"/>
|
||||
+4
-2
@@ -1,9 +1,8 @@
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Tools;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components.Blocks;
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public partial class ConfigurationProviderSelection : ComponentBase, IMessageBusReceiver, IDisposable
|
||||
{
|
||||
@@ -22,6 +21,9 @@ public partial class ConfigurationProviderSelection : ComponentBase, IMessageBus
|
||||
[Parameter]
|
||||
public Func<bool> Disabled { get; set; } = () => false;
|
||||
|
||||
[Parameter]
|
||||
public Func<string> HelpText { get; set; } = () => "Select a provider that is preselected.";
|
||||
|
||||
[Inject]
|
||||
private SettingsManager SettingsManager { get; init; } = null!;
|
||||
|
||||
File renamed without changes.
+1
-1
@@ -2,7 +2,7 @@ using AIStudio.Settings;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components.Blocks;
|
||||
namespace AIStudio.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Configuration component for selecting a value from a list.
|
||||
File renamed without changes.
+1
-1
@@ -2,7 +2,7 @@ using System.Numerics;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components.Blocks;
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public partial class ConfigurationSlider<T> : ConfigurationBase where T : struct, INumber<T>
|
||||
{
|
||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components.Blocks;
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public partial class ConfigurationText : ConfigurationBase
|
||||
{
|
||||
File renamed without changes.
+1
-1
@@ -2,7 +2,7 @@ using AIStudio.Settings;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components.Blocks;
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public partial class EnumSelection<T> : EnumSelectionBase where T : struct, Enum
|
||||
{
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components.Blocks;
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public abstract class EnumSelectionBase : ComponentBase
|
||||
{
|
||||
@@ -0,0 +1,25 @@
|
||||
<MudExpansionPanel Class="border-solid border rounded-lg" Expanded="@this.IsExpanded">
|
||||
<TitleContent>
|
||||
<div class="d-flex align-center">
|
||||
<MudIcon Icon="@this.HeaderIcon" Size="@this.IconSize" Color="@this.IconColor" class="mr-3"/>
|
||||
<MudText Typo="Typo.h6">@this.HeaderText</MudText>
|
||||
@if (this.ShowEndButton)
|
||||
{
|
||||
<MudSpacer/>
|
||||
if (!string.IsNullOrWhiteSpace(this.EndButtonTooltip))
|
||||
{
|
||||
<MudTooltip Text="@this.EndButtonTooltip">
|
||||
<MudIconButton Icon="@this.EndButtonIcon" Color="@this.EndButtonColor" Size="Size.Medium" OnClick="async () => await this.EndButtonClickAsync()"/>
|
||||
</MudTooltip>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudIconButton Icon="@this.EndButtonIcon" Color="@this.EndButtonColor" Size="Size.Medium" OnClick="async () => await this.EndButtonClickAsync()"/>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</TitleContent>
|
||||
<ChildContent>
|
||||
@this.ChildContent
|
||||
</ChildContent>
|
||||
</MudExpansionPanel>
|
||||
+16
-1
@@ -1,6 +1,6 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components.Blocks;
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public partial class ExpansionPanel : ComponentBase
|
||||
{
|
||||
@@ -21,4 +21,19 @@ public partial class ExpansionPanel : ComponentBase
|
||||
|
||||
[Parameter]
|
||||
public bool IsExpanded { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public bool ShowEndButton { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public Func<ValueTask> EndButtonClickAsync { get; set; } = () => ValueTask.CompletedTask;
|
||||
|
||||
[Parameter]
|
||||
public string EndButtonIcon { get; set; } = Icons.Material.Filled.Delete;
|
||||
|
||||
[Parameter]
|
||||
public Color EndButtonColor { get; set; } = Color.Error;
|
||||
|
||||
[Parameter]
|
||||
public string EndButtonTooltip { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public interface ITreeItem;
|
||||
@@ -0,0 +1,18 @@
|
||||
@inherits MSGComponentBase
|
||||
|
||||
<div class="d-flex flex-column" style="@this.Height">
|
||||
<div class="flex-auto overflow-auto">
|
||||
@this.ChildContent
|
||||
|
||||
<div @ref="@this.AnchorAfterChildContent">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (this.FooterContent is not null)
|
||||
{
|
||||
<MudPaper Class="pa-3 border-solid border rounded-lg">
|
||||
@this.FooterContent
|
||||
</MudPaper>
|
||||
}
|
||||
</div>
|
||||
+12
-3
@@ -1,9 +1,8 @@
|
||||
using AIStudio.Components.Layout;
|
||||
using AIStudio.Tools;
|
||||
using AIStudio.Layout;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components.Blocks;
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public partial class InnerScrolling : MSGComponentBase
|
||||
{
|
||||
@@ -26,6 +25,11 @@ public partial class InnerScrolling : MSGComponentBase
|
||||
|
||||
[CascadingParameter]
|
||||
private MainLayout MainLayout { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
private IJSRuntime JsRuntime { get; init; } = null!;
|
||||
|
||||
private ElementReference AnchorAfterChildContent { get; set; }
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
@@ -59,4 +63,9 @@ public partial class InnerScrolling : MSGComponentBase
|
||||
#endregion
|
||||
|
||||
private string Height => $"height: calc(100vh - {this.HeaderHeight} - {this.MainLayout.AdditionalHeight});";
|
||||
|
||||
public async Task ScrollToBottom()
|
||||
{
|
||||
await this.AnchorAfterChildContent.ScrollIntoViewAsync(this.JsRuntime);
|
||||
}
|
||||
}
|
||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components.Blocks;
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public partial class Issues : ComponentBase
|
||||
{
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace AIStudio.Components.Layout;
|
||||
|
||||
public record NavBarItem(string Name, string Icon, Color IconColor, string Path, bool MatchAll);
|
||||
@@ -1,5 +1,3 @@
|
||||
using AIStudio.Tools;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components;
|
||||
|
||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components.Blocks;
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public partial class Motivation : ComponentBase
|
||||
{
|
||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components.Blocks;
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public partial class MudTextList : ComponentBase
|
||||
{
|
||||
File renamed without changes.
+1
-1
@@ -2,7 +2,7 @@ using System.Numerics;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components.Blocks;
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public partial class MudTextSlider<T> : ComponentBase where T : struct, INumber<T>
|
||||
{
|
||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components.Blocks;
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public partial class MudTextSwitch : ComponentBase
|
||||
{
|
||||
@@ -1,5 +0,0 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components.Pages;
|
||||
|
||||
public partial class Assistants : ComponentBase;
|
||||
@@ -1,93 +0,0 @@
|
||||
@page "/chat"
|
||||
@using AIStudio.Chat
|
||||
@using AIStudio.Settings.DataModel
|
||||
|
||||
@inherits MSGComponentBase
|
||||
|
||||
<MudText Typo="Typo.h3" Class="mb-2 mr-3">
|
||||
@if (this.chatThread is not null && this.chatThread.WorkspaceId != Guid.Empty)
|
||||
{
|
||||
@($"Chat in Workspace \"{this.currentWorkspaceName}\"")
|
||||
}
|
||||
else
|
||||
{
|
||||
@("Temporary Chat")
|
||||
}
|
||||
</MudText>
|
||||
|
||||
<ProviderSelection @bind-ProviderSettings="@this.providerSettings"/>
|
||||
<InnerScrolling HeaderHeight="12.3em">
|
||||
<ChildContent>
|
||||
@if (this.chatThread is not null)
|
||||
{
|
||||
foreach (var block in this.chatThread.Blocks.OrderBy(n => n.Time))
|
||||
{
|
||||
<ContentBlockComponent Role="@block.Role" Type="@block.ContentType" Time="@block.Time" Content="@block.Content"/>
|
||||
}
|
||||
}
|
||||
</ChildContent>
|
||||
<FooterContent>
|
||||
<MudPaper Style="flex: 0 0 auto;">
|
||||
<MudTextField T="string" @ref="@this.inputField" @bind-Text="@this.userInput" Variant="Variant.Outlined" AutoGrow="@true" Lines="3" MaxLines="12" Label="@this.InputLabel" Placeholder="@this.ProviderPlaceholder" Adornment="Adornment.End" AdornmentIcon="@Icons.Material.Filled.Send" OnAdornmentClick="() => this.SendMessage()" ReadOnly="!this.IsProviderSelected || this.isStreaming" Immediate="@true" OnKeyUp="this.InputKeyEvent" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
|
||||
</MudPaper>
|
||||
<MudPaper Class="mt-1" Outlined="@true">
|
||||
<MudToolBar WrapContent="true">
|
||||
@if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is not WorkspaceStorageBehavior.DISABLE_WORKSPACES)
|
||||
{
|
||||
<MudTooltip Text="Your workspaces" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.SnippetFolder" OnClick="() => this.ToggleWorkspaces()"/>
|
||||
</MudTooltip>
|
||||
}
|
||||
|
||||
@if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is WorkspaceStorageBehavior.STORE_CHATS_MANUALLY)
|
||||
{
|
||||
<MudTooltip Text="Save chat" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Save" OnClick="() => this.SaveThread()" Disabled="@(!this.CanThreadBeSaved)"/>
|
||||
</MudTooltip>
|
||||
}
|
||||
|
||||
<MudTooltip Text="Start temporary chat" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.AddComment" OnClick="() => this.StartNewChat(useSameWorkspace: false)"/>
|
||||
</MudTooltip>
|
||||
|
||||
@if (!string.IsNullOrWhiteSpace(this.currentWorkspaceName))
|
||||
{
|
||||
<MudTooltip Text="@this.TooltipAddChatToWorkspace" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.CommentBank" OnClick="() => this.StartNewChat(useSameWorkspace: true)"/>
|
||||
</MudTooltip>
|
||||
}
|
||||
|
||||
@if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is WorkspaceStorageBehavior.STORE_CHATS_AUTOMATICALLY)
|
||||
{
|
||||
<MudTooltip Text="Delete this chat & start a new one" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Refresh" OnClick="() => this.StartNewChat(useSameWorkspace: true, deletePreviousChat: true)" Disabled="@(!this.CanThreadBeSaved)"/>
|
||||
</MudTooltip>
|
||||
}
|
||||
|
||||
@if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is not WorkspaceStorageBehavior.DISABLE_WORKSPACES)
|
||||
{
|
||||
<MudTooltip Text="Move the chat to a workspace, or to another if it is already in one." Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.MoveToInbox" Disabled="@(!this.CanThreadBeSaved)" OnClick="() => this.MoveChatToWorkspace()"/>
|
||||
</MudTooltip>
|
||||
}
|
||||
</MudToolBar>
|
||||
</MudPaper>
|
||||
</FooterContent>
|
||||
</InnerScrolling>
|
||||
|
||||
@if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior != WorkspaceStorageBehavior.DISABLE_WORKSPACES)
|
||||
{
|
||||
<MudDrawer @bind-Open="@this.workspacesVisible" Width="40em" Height="100%" Anchor="Anchor.Start" Variant="DrawerVariant.Temporary" Elevation="1">
|
||||
<MudDrawerHeader>
|
||||
<MudStack Row="@true" AlignItems="AlignItems.Center">
|
||||
<MudText Typo="Typo.h6" Class="mr-3">
|
||||
Your workspaces
|
||||
</MudText>
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Close" Variant="Variant.Filled" Color="Color.Default" Size="Size.Small" OnClick="() => this.ToggleWorkspaces()"/>
|
||||
</MudStack>
|
||||
</MudDrawerHeader>
|
||||
<MudDrawerContainer Class="ml-6">
|
||||
<Workspaces @ref="this.workspaces" @bind-CurrentChatThread="@this.chatThread" LoadedChatWasChanged="this.LoadedChatChanged"/>
|
||||
</MudDrawerContainer>
|
||||
</MudDrawer>
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
namespace AIStudio.Components.Pages.RewriteImprove;
|
||||
|
||||
public static class WritingStylesExtensions
|
||||
{
|
||||
public static string Name(this WritingStyles style)
|
||||
{
|
||||
return style switch
|
||||
{
|
||||
WritingStyles.EVERYDAY => "Everyday (personal texts, social media)",
|
||||
WritingStyles.BUSINESS => "Business (business emails, reports, presentations)",
|
||||
WritingStyles.SCIENTIFIC => "Scientific (scientific papers, research reports)",
|
||||
WritingStyles.JOURNALISTIC => "Journalistic (magazines, newspapers, news)",
|
||||
WritingStyles.LITERARY => "Literary (fiction, poetry)",
|
||||
WritingStyles.TECHNICAL => "Technical (manuals, documentation)",
|
||||
WritingStyles.MARKETING => "Marketing (advertisements, sales texts)",
|
||||
WritingStyles.ACADEMIC => "Academic (essays, seminar papers)",
|
||||
WritingStyles.LEGAL => "Legal (legal texts, contracts)",
|
||||
|
||||
_ => "Not specified",
|
||||
};
|
||||
}
|
||||
|
||||
public static string Prompt(this WritingStyles style)
|
||||
{
|
||||
return 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.",
|
||||
|
||||
_ => "Keep the style of the text as it is.",
|
||||
};
|
||||
}
|
||||
}
|
||||
File renamed without changes.
+1
-3
@@ -1,8 +1,6 @@
|
||||
using AIStudio.Tools;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components.Blocks;
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public partial class ProcessComponent<T> : ComponentBase where T : struct, Enum
|
||||
{
|
||||
File renamed without changes.
+1
-1
@@ -2,7 +2,7 @@ using AIStudio.Settings;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components.Blocks;
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public partial class ProviderSelection : ComponentBase
|
||||
{
|
||||
Loaded 100 of 229 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user