mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-19 22:58:00 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b99866b8fe | ||
|
|
e9998348c5 | ||
|
|
0ad7b8d4dd | ||
|
|
4175387a93 | ||
|
|
1cac1a7913 | ||
|
|
5fa2f3c822 | ||
|
|
5608b48a2d | ||
|
|
bf01fbd706 | ||
|
|
4722c1baa1 | ||
|
|
222c1e929f | ||
|
|
2a648105e6 | ||
|
|
09f5b83e66 | ||
|
|
7a5f2d4aec | ||
|
|
0d1164c0eb | ||
|
|
54588fc92d | ||
|
|
a5bdb3267b | ||
|
|
d7c124926b | ||
|
|
00f45f8998 | ||
|
|
d0d9fa3d22 | ||
|
|
b3dd213538 | ||
|
|
9dfabb3c55 | ||
|
|
d0dbbccd56 | ||
|
|
75576129fe | ||
|
|
2efd08dbbc | ||
|
|
4bd22108de | ||
|
|
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
@@ -249,18 +249,6 @@ jobs:
|
||||
cd publish/dotnet
|
||||
mv mindworkAIStudio.exe "../../app/MindWork AI Studio/bin/dist/mindworkAIStudioServer${{ matrix.dotnet_name_postfix }}"
|
||||
|
||||
- name: Create parts for the Rust cache key (Unix)
|
||||
if: matrix.platform != 'windows-latest'
|
||||
run: |
|
||||
cd runtime
|
||||
echo "CARGO_LOCK_HASH=${{ hashFiles('**/Cargo.lock') }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Create parts for the Rust cache key (Windows)
|
||||
if: matrix.platform == 'windows-latest'
|
||||
run: |
|
||||
cd runtime
|
||||
echo "CARGO_LOCK_HASH=${{ hashFiles('**/Cargo.lock') }}" >> $env:GITHUB_ENV
|
||||
|
||||
- name: Cache Rust
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
@@ -272,17 +260,7 @@ jobs:
|
||||
~/.rustup/toolchains
|
||||
runtime/target
|
||||
|
||||
# When the entire key matches, Rust might just create the bundles using the current .NET build:
|
||||
key: target-${{ matrix.dotnet_runtime }}-rust-${{ env.RUST_VERSION }}-dependencies-${{ env.CARGO_LOCK_HASH }}
|
||||
|
||||
# - 1st key: the Rust runtime dependencies changed. Anyway, we might be able to re-use many previously built packages.
|
||||
#
|
||||
# - No match: alright, a new Rust version was released. Sadly, we cannot re-use anything now. Why?
|
||||
# The updated Rust compiler might mitigate some bugs or vulnerabilities. In order to apply
|
||||
# these changes to our app, we have to re-compile everything. That's the reason why it makes
|
||||
# no sense to use more parts for the cache key, like Tauri or Tauri build versions.
|
||||
restore-keys: |
|
||||
target-${{ matrix.dotnet_runtime }}-rust-${{ env.RUST_VERSION }}-dependencies-
|
||||
key: target-${{ matrix.dotnet_runtime }}-rust-${{ env.RUST_VERSION }}
|
||||
|
||||
- name: Setup Rust (stable)
|
||||
uses: dtolnay/rust-toolchain@master
|
||||
@@ -478,30 +456,13 @@ jobs:
|
||||
cd publish/dotnet
|
||||
mv mindworkAIStudio "../../app/MindWork AI Studio/bin/dist/mindworkAIStudioServer-aarch64-unknown-linux-gnu"
|
||||
|
||||
- name: Create parts for the Rust cache key
|
||||
if: ${{ env.SKIP != 'true' }}
|
||||
run: |
|
||||
cd runtime
|
||||
echo "CARGO_LOCK_HASH=${{ hashFiles('**/Cargo.lock') }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Cache linux arm64 runner image
|
||||
if: ${{ env.SKIP != 'true' }}
|
||||
uses: actions/cache@v4
|
||||
id: linux_arm_cache
|
||||
with:
|
||||
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 }}
|
||||
|
||||
# - 1st key: the Rust runtime dependencies changed. Anyway, we might be able to re-use many previously built packages.
|
||||
#
|
||||
# - No match: alright, a new Rust version was released. Sadly, we cannot re-use anything now. Why?
|
||||
# The updated Rust compiler might mitigate some bugs or vulnerabilities. In order to apply
|
||||
# these changes to our app, we have to re-compile everything. That's the reason why it makes
|
||||
# no sense to use more parts for the cache key, like Tauri or Tauri build versions.
|
||||
restore-keys: |
|
||||
target-linux-arm64-rust-${{ env.RUST_VERSION }}-dependencies-
|
||||
path: ${{ runner.temp }}/linux_arm_qemu_cache.img
|
||||
key: target-linux-arm64-rust-${{ env.RUST_VERSION }}
|
||||
|
||||
- name: Build linux arm runner image
|
||||
uses: pguyot/arm-runner-action@v2
|
||||
@@ -544,7 +505,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 +513,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,19 +535,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
|
||||
|
||||
- name: Debug
|
||||
if: ${{ env.SKIP != 'true' }}
|
||||
run: |
|
||||
echo "Current directory: $(pwd)"
|
||||
ls -lhat
|
||||
|
||||
echo "Searching for linux_arm_qemu_cache.img"
|
||||
find $RUNNER_TEMP -name 'linux_arm_qemu_cache.img' -print 2>/dev/null
|
||||
|
||||
echo "Searching for mind-work-ai-studio_*.deb"
|
||||
find . -name 'mind-work-ai-studio_*.deb' -print 2>/dev/null
|
||||
|
||||
# Save the built libraries for the next job:
|
||||
rm -fr /rust-cache/target
|
||||
cp -Rp target /rust-cache
|
||||
|
||||
- name: Update the runner image to cache the Rust runtime build
|
||||
if: ${{ env.SKIP != 'true' }}
|
||||
@@ -729,6 +689,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 +757,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 +805,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,5 +1,6 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=AI/@EntryIndexedValue">AI</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=LLM/@EntryIndexedValue">LLM</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=LM/@EntryIndexedValue">LM</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MSG/@EntryIndexedValue">MSG</s:String>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=ollama/@EntryIndexedValue">True</s:Boolean>
|
||||
|
||||
@@ -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>
|
||||
+2
-7
@@ -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"/>
|
||||
@@ -49,8 +48,4 @@
|
||||
}
|
||||
|
||||
<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.CreateAgenda()">
|
||||
Create agenda
|
||||
</MudButton>
|
||||
<ProviderSelection @bind-ProviderSettings="@this.providerSettings" ValidateProvider="@this.ValidatingProvider"/>
|
||||
+80
-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
|
||||
{
|
||||
public override Tools.Components Component => Tools.Components.AGENDA_ASSISTANT;
|
||||
|
||||
protected override string Title => "Agenda Planner";
|
||||
|
||||
protected override string Description =>
|
||||
@@ -93,6 +95,75 @@ public partial class AssistantAgenda : AssistantBaseCore
|
||||
- Mary Jane: Work package 3
|
||||
""";
|
||||
|
||||
protected override IReadOnlyList<IButtonData> FooterButtons => [];
|
||||
|
||||
protected override string SubmitText => "Create Agenda";
|
||||
|
||||
protected override Func<Task> SubmitAction => this.CreateAgenda;
|
||||
|
||||
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 +193,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 +300,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 +360,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,114 @@
|
||||
@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)
|
||||
{
|
||||
<CascadingValue Value="@this">
|
||||
@this.Body
|
||||
</CascadingValue>
|
||||
|
||||
<MudButton Disabled="@this.SubmitDisabled" Variant="Variant.Filled" Class="mb-3" OnClick="() => this.SubmitAction()" Style="@this.SubmitButtonStyle">
|
||||
@this.SubmitText
|
||||
</MudButton>
|
||||
}
|
||||
</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" Style="@this.GetSendToColor()" Class="rounded">
|
||||
@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" Style="@this.GetSendToColor()" Class="rounded">
|
||||
@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" Style="@this.GetResetColor()" StartIcon="@Icons.Material.Filled.Refresh" OnClick="() => this.InnerResetForm()">
|
||||
Reset
|
||||
</MudButton>
|
||||
|
||||
@if (this.SettingsManager.ConfigurationData.LLMProviders.ShowProviderConfidence)
|
||||
{
|
||||
<ConfidenceInfo Mode="ConfidenceInfoMode.BUTTON" LLMProvider="@this.providerSettings.UsedLLMProvider"/>
|
||||
}
|
||||
|
||||
@if (this.AllowProfiles && this.ShowProfileSelection)
|
||||
{
|
||||
<ProfileSelection MarginLeft="" @bind-CurrentProfile="@this.currentProfile"/>
|
||||
}
|
||||
</MudStack>
|
||||
</FooterContent>
|
||||
</InnerScrolling>
|
||||
@@ -0,0 +1,306 @@
|
||||
using AIStudio.Chat;
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Settings;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
using RustService = AIStudio.Tools.RustService;
|
||||
|
||||
namespace AIStudio.Assistants;
|
||||
|
||||
public abstract partial class AssistantBase : ComponentBase, IMessageBusReceiver, IDisposable
|
||||
{
|
||||
[Inject]
|
||||
protected SettingsManager SettingsManager { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected IJSRuntime JsRuntime { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected ThreadSafeRandom RNG { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected ISnackbar Snackbar { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected RustService RustService { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected NavigationManager NavigationManager { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected ILogger<AssistantBase> Logger { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private MudTheme ColorTheme { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private MessageBus MessageBus { get; init; } = null!;
|
||||
|
||||
internal const string AFTER_RESULT_DIV_ID = "afterAssistantResult";
|
||||
internal const string RESULT_DIV_ID = "assistantResult";
|
||||
|
||||
protected abstract string Title { get; }
|
||||
|
||||
protected abstract string Description { get; }
|
||||
|
||||
protected abstract string SystemPrompt { get; }
|
||||
|
||||
public 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();
|
||||
|
||||
protected abstract string SubmitText { get; }
|
||||
|
||||
protected abstract Func<Task> SubmitAction { get; }
|
||||
|
||||
protected virtual bool SubmitDisabled => false;
|
||||
|
||||
private protected virtual RenderFragment? Body => null;
|
||||
|
||||
protected virtual bool ShowResult => true;
|
||||
|
||||
protected virtual bool AllowProfiles => true;
|
||||
|
||||
protected virtual bool ShowProfileSelection => true;
|
||||
|
||||
protected virtual bool ShowDedicatedProgress => false;
|
||||
|
||||
protected virtual ChatThread ConvertToChatThread => this.chatThread ?? new();
|
||||
|
||||
protected virtual IReadOnlyList<IButtonData> FooterButtons => [];
|
||||
|
||||
protected static readonly Dictionary<string, object?> USER_INPUT_ATTRIBUTES = new();
|
||||
|
||||
protected AIStudio.Settings.Provider providerSettings;
|
||||
protected MudForm? form;
|
||||
protected bool inputIsValid;
|
||||
protected Profile currentProfile = Profile.NO_PROFILE;
|
||||
|
||||
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);
|
||||
this.currentProfile = this.SettingsManager.GetPreselectedProfile(this.Component);
|
||||
|
||||
this.MessageBus.RegisterComponent(this);
|
||||
this.MessageBus.ApplyFilters(this, [], [ Event.COLOR_THEME_CHANGED ]);
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
// Configure the spellchecking for the user input:
|
||||
this.SettingsManager.InjectSpellchecking(USER_INPUT_ATTRIBUTES);
|
||||
|
||||
await base.OnParametersSetAsync();
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
// Reset the validation when not editing and on the first render.
|
||||
// We don't want to show validation errors when the user opens the dialog.
|
||||
if(firstRender)
|
||||
this.form?.ResetValidation();
|
||||
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IMessageBusReceiver
|
||||
|
||||
public Task ProcessMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data)
|
||||
{
|
||||
switch (triggeredEvent)
|
||||
{
|
||||
case Event.COLOR_THEME_CHANGED:
|
||||
this.StateHasChanged();
|
||||
break;
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<TResult?> ProcessMessageWithResult<TPayload, TResult>(ComponentBase? sendingComponent, Event triggeredEvent, TPayload? data)
|
||||
{
|
||||
return Task.FromResult<TResult?>(default);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private string SubmitButtonStyle => this.SettingsManager.ConfigurationData.LLMProviders.ShowProviderConfidence ? this.providerSettings.UsedLLMProvider.GetConfidence(this.SettingsManager).StyleBorder(this.SettingsManager) : string.Empty;
|
||||
|
||||
protected string? ValidatingProvider(AIStudio.Settings.Provider provider)
|
||||
{
|
||||
if(provider.UsedLLMProvider == LLMProviders.NONE)
|
||||
return "Please select a provider.";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void CreateChatThread()
|
||||
{
|
||||
this.chatThread = new()
|
||||
{
|
||||
WorkspaceId = Guid.Empty,
|
||||
ChatId = Guid.NewGuid(),
|
||||
Name = string.Empty,
|
||||
Seed = this.RNG.Next(),
|
||||
SystemPrompt = !this.AllowProfiles ? this.SystemPrompt :
|
||||
$"""
|
||||
{this.SystemPrompt}
|
||||
|
||||
{this.currentProfile.ToSystemPrompt()}
|
||||
""",
|
||||
Blocks = [],
|
||||
};
|
||||
}
|
||||
|
||||
protected DateTimeOffset AddUserRequest(string request)
|
||||
{
|
||||
var time = DateTimeOffset.Now;
|
||||
this.chatThread!.Blocks.Add(new ContentBlock
|
||||
{
|
||||
Time = time,
|
||||
ContentType = ContentType.TEXT,
|
||||
Role = ChatRole.USER,
|
||||
Content = new ContentText
|
||||
{
|
||||
Text = request,
|
||||
},
|
||||
});
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
protected async Task<string> AddAIResponseAsync(DateTimeOffset time)
|
||||
{
|
||||
var aiText = new ContentText
|
||||
{
|
||||
// We have to wait for the remote
|
||||
// for the content stream:
|
||||
InitialRemoteWait = true,
|
||||
};
|
||||
|
||||
this.resultingContentBlock = new ContentBlock
|
||||
{
|
||||
Time = time,
|
||||
ContentType = ContentType.TEXT,
|
||||
Role = ChatRole.AI,
|
||||
Content = aiText,
|
||||
};
|
||||
|
||||
this.chatThread?.Blocks.Add(this.resultingContentBlock);
|
||||
this.isProcessing = true;
|
||||
this.StateHasChanged();
|
||||
|
||||
// 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.Logger), this.SettingsManager, this.providerSettings.Model, this.chatThread);
|
||||
|
||||
this.isProcessing = false;
|
||||
this.StateHasChanged();
|
||||
|
||||
// Return the AI response:
|
||||
return aiText.Text;
|
||||
}
|
||||
|
||||
protected async Task CopyToClipboard()
|
||||
{
|
||||
await this.RustService.CopyText2Clipboard(this.Snackbar, this.Result2Copy());
|
||||
}
|
||||
|
||||
private static string? GetButtonIcon(string icon)
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(icon))
|
||||
return null;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
private string GetResetColor() => this.SettingsManager.IsDarkMode switch
|
||||
{
|
||||
true => $"background-color: #804000",
|
||||
false => $"background-color: {this.ColorTheme.GetCurrentPalette(this.SettingsManager).Warning.Value}",
|
||||
};
|
||||
|
||||
private string GetSendToColor() => this.SettingsManager.IsDarkMode switch
|
||||
{
|
||||
true => $"background-color: #004080",
|
||||
false => $"background-color: {this.ColorTheme.GetCurrentPalette(this.SettingsManager).InfoLighten}",
|
||||
};
|
||||
|
||||
#region Implementation of IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.MessageBus.Unregister(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
+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
|
||||
+4
-7
@@ -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>
|
||||
}
|
||||
@@ -23,8 +24,4 @@
|
||||
</MudStack>
|
||||
|
||||
<MudTextField T="string" @bind-Text="@this.questions" Validation="@this.ValidateQuestions" AdornmentIcon="@Icons.Material.Filled.QuestionMark" Adornment="Adornment.Start" Label="Your question(s)" 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 Variant="Variant.Filled" Color="Color.Info" OnClick="() => this.GetSupport()" Class="mb-3">
|
||||
Get support
|
||||
</MudButton>
|
||||
<ProviderSelection @bind-ProviderSettings="@this.providerSettings" ValidateProvider="@this.ValidatingProvider"/>
|
||||
+53
-9
@@ -1,9 +1,11 @@
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Components.Pages.Coding;
|
||||
namespace AIStudio.Assistants.Coding;
|
||||
|
||||
public partial class AssistantCoding : AssistantBaseCore
|
||||
{
|
||||
public override Tools.Components Component => Tools.Components.CODING_ASSISTANT;
|
||||
|
||||
protected override string Title => "Coding Assistant";
|
||||
|
||||
protected override string Description =>
|
||||
@@ -24,6 +26,34 @@ 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 string SubmitText => "Get Support";
|
||||
|
||||
protected override Func<Task> SubmitAction => this.GetSupport;
|
||||
|
||||
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 +63,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 +101,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 +127,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,23 @@
|
||||
@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"/>
|
||||
@@ -0,0 +1,249 @@
|
||||
using System.Text;
|
||||
|
||||
using AIStudio.Chat;
|
||||
|
||||
namespace AIStudio.Assistants.EMail;
|
||||
|
||||
public partial class AssistantEMail : AssistantBaseCore
|
||||
{
|
||||
public 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 string SubmitText => "Create email";
|
||||
|
||||
protected override Func<Task> SubmitAction => this.CreateMail;
|
||||
|
||||
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.",
|
||||
};
|
||||
}
|
||||
+2
-7
@@ -1,11 +1,6 @@
|
||||
@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"/>
|
||||
<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" />
|
||||
<ProviderSelection @bind-ProviderSettings="@this.providerSettings" ValidateProvider="@this.ValidatingProvider"/>
|
||||
|
||||
<MudButton Variant="Variant.Filled" Class="mb-3" OnClick="() => this.ProofreadText()">
|
||||
Proofread
|
||||
</MudButton>
|
||||
<ProviderSelection @bind-ProviderSettings="@this.providerSettings" ValidateProvider="@this.ValidatingProvider"/>
|
||||
+47
-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
|
||||
{
|
||||
public override Tools.Components Component => Tools.Components.GRAMMAR_SPELLING_ASSISTANT;
|
||||
|
||||
protected override string Title => "Grammar & Spelling Checker";
|
||||
|
||||
protected override string Description =>
|
||||
@@ -20,27 +22,65 @@ public partial class AssistantGrammarSpelling : AssistantBaseCore
|
||||
Your response includes only the corrected text. Do not explain your changes. If no changes are needed,
|
||||
you return the text unchanged.
|
||||
""";
|
||||
|
||||
protected override bool AllowProfiles => false;
|
||||
|
||||
protected override bool ShowResult => false;
|
||||
|
||||
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 string SubmitText => "Proofread";
|
||||
|
||||
protected override Func<Task> SubmitAction => this.ProofreadText;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
+2
-6
@@ -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"/>
|
||||
@@ -15,8 +15,4 @@
|
||||
<MudButton Href="@this.selectedIconSource.URL()" Target="_blank" Variant="Variant.Filled" Size="Size.Medium">Open website</MudButton>
|
||||
}
|
||||
</MudStack>
|
||||
<ProviderSelection @bind-ProviderSettings="@this.providerSettings" ValidateProvider="@this.ValidatingProvider"/>
|
||||
|
||||
<MudButton Variant="Variant.Filled" Class="mb-3" OnClick="() => this.FindIcon()">
|
||||
Find icon
|
||||
</MudButton>
|
||||
<ProviderSelection @bind-ProviderSettings="@this.providerSettings" ValidateProvider="@this.ValidatingProvider"/>
|
||||
+46
-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
|
||||
public override Tools.Components Component => Tools.Components.ICON_FINDER_ASSISTANT;
|
||||
|
||||
protected override string Title => "Icon Finder";
|
||||
|
||||
@@ -41,6 +25,50 @@ public partial class AssistantIconFinder : AssistantBaseCore
|
||||
quotation marks.
|
||||
""";
|
||||
|
||||
protected override bool AllowProfiles => false;
|
||||
|
||||
protected override IReadOnlyList<IButtonData> FooterButtons => [];
|
||||
|
||||
protected override string SubmitText => "Find Icon";
|
||||
|
||||
protected override Func<Task> SubmitAction => this.FindIcon;
|
||||
|
||||
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,11 @@
|
||||
@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"/>
|
||||
@@ -0,0 +1,93 @@
|
||||
namespace AIStudio.Assistants.LegalCheck;
|
||||
|
||||
public partial class AssistantLegalCheck : AssistantBaseCore
|
||||
{
|
||||
public 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 string SubmitText => "Ask your questions";
|
||||
|
||||
protected override Func<Task> SubmitAction => this.AksQuestions;
|
||||
|
||||
protected override bool SubmitDisabled => this.isAgentRunning;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
@attribute [Route(Routes.ASSISTANT_MY_TASKS)]
|
||||
@inherits AssistantBaseCore
|
||||
|
||||
<ProfileFormSelection Validation="@this.ValidateProfile" @bind-Profile="@this.currentProfile"/>
|
||||
<MudTextField T="string" @bind-Text="@this.inputText" Validation="@this.ValidatingText" AdornmentIcon="@Icons.Material.Filled.DocumentScanner" Adornment="Adornment.Start" Label="Text or email" Variant="Variant.Outlined" Lines="12" AutoGrow="@true" MaxLines="24" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
|
||||
<EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelectingOptional())" @bind-Value="@this.selectedTargetLanguage" 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"/>
|
||||
@@ -0,0 +1,123 @@
|
||||
using AIStudio.Settings;
|
||||
|
||||
namespace AIStudio.Assistants.MyTasks;
|
||||
|
||||
public partial class AssistantMyTasks : AssistantBaseCore
|
||||
{
|
||||
public override Tools.Components Component => Tools.Components.MY_TASKS_ASSISTANT;
|
||||
|
||||
protected override string Title => "My Tasks";
|
||||
|
||||
protected override string Description =>
|
||||
"""
|
||||
You received a cryptic email that was sent to many recipients and you are now wondering
|
||||
if you need to do something? Copy the email into the input field. You also need to select
|
||||
a personal profile. In this profile, you should describe your role in the organization.
|
||||
The AI will then try to give you hints on what your tasks might be.
|
||||
""";
|
||||
|
||||
protected override string SystemPrompt =>
|
||||
$"""
|
||||
You are a friendly and professional business expert. You receive business emails, protocols,
|
||||
reports, etc. as input. Additionally, you know the user's role in the organization. The user
|
||||
wonders if any tasks arise for them in their role based on the text. You now try to give hints
|
||||
and advice on whether and what the user should do. When you believe there are no tasks for the
|
||||
user, you tell them this. You consider typical business etiquette in your advice.
|
||||
|
||||
You write your advice in the following language: {this.SystemPromptLanguage()}.
|
||||
""";
|
||||
|
||||
protected override IReadOnlyList<IButtonData> FooterButtons => [];
|
||||
|
||||
protected override string SubmitText => "Analyze text";
|
||||
|
||||
protected override Func<Task> SubmitAction => this.AnalyzeText;
|
||||
|
||||
protected override bool ShowProfileSelection => false;
|
||||
|
||||
protected override void ResetFrom()
|
||||
{
|
||||
this.inputText = string.Empty;
|
||||
if (!this.MightPreselectValues())
|
||||
{
|
||||
this.selectedTargetLanguage = CommonLanguages.AS_IS;
|
||||
this.customTargetLanguage = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool MightPreselectValues()
|
||||
{
|
||||
if (this.SettingsManager.ConfigurationData.MyTasks.PreselectOptions)
|
||||
{
|
||||
this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.MyTasks.PreselectedTargetLanguage;
|
||||
this.customTargetLanguage = this.SettingsManager.ConfigurationData.MyTasks.PreselectOtherLanguage;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private string inputText = string.Empty;
|
||||
private CommonLanguages selectedTargetLanguage = CommonLanguages.AS_IS;
|
||||
private string customTargetLanguage = string.Empty;
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages<string>(Event.SEND_TO_MY_TASKS_ASSISTANT).FirstOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputText = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private string? ValidatingText(string text)
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(text))
|
||||
return "Please provide some text as input. For example, an email.";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string? ValidateProfile(Profile profile)
|
||||
{
|
||||
if(profile == default || profile == Profile.NO_PROFILE)
|
||||
return "Please select one of your profiles.";
|
||||
|
||||
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 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 async Task AnalyzeText()
|
||||
{
|
||||
await this.form!.Validate();
|
||||
if (!this.inputIsValid)
|
||||
return;
|
||||
|
||||
this.CreateChatThread();
|
||||
var time = this.AddUserRequest(this.inputText);
|
||||
|
||||
await this.AddAIResponseAsync(time);
|
||||
}
|
||||
}
|
||||
+3
-7
@@ -1,12 +1,8 @@
|
||||
@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" />
|
||||
<ProviderSelection @bind-ProviderSettings="@this.providerSettings" ValidateProvider="@this.ValidatingProvider"/>
|
||||
|
||||
<MudButton Variant="Variant.Filled" Class="mb-3" OnClick="() => this.RewriteText()">
|
||||
Improve
|
||||
</MudButton>
|
||||
<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"/>
|
||||
+56
-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
|
||||
{
|
||||
public override Tools.Components Component => Tools.Components.REWRITE_ASSISTANT;
|
||||
|
||||
protected override string Title => "Rewrite & Improve Text";
|
||||
|
||||
protected override string Description =>
|
||||
@@ -18,35 +20,72 @@ 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 AllowProfiles => false;
|
||||
|
||||
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 string SubmitText => "Improve";
|
||||
|
||||
protected override Func<Task> SubmitAction => this.RewriteText;
|
||||
|
||||
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 +96,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.",
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
@attribute [Route(Routes.ASSISTANT_SYNONYMS)]
|
||||
@inherits AssistantBaseCore
|
||||
|
||||
<MudTextField T="string" @bind-Text="@this.inputText" Validation="@this.ValidatingText" AdornmentIcon="@Icons.Material.Filled.Spellcheck" Adornment="Adornment.Start" Label="Your word or phrase" Variant="Variant.Outlined" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
|
||||
<MudTextField T="string" @bind-Text="@this.inputContext" AdornmentIcon="@Icons.Material.Filled.Description" Adornment="Adornment.Start" Lines="2" AutoGrow="@false" Label="(Optional) The context for the given word or phrase" Variant="Variant.Outlined" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
|
||||
|
||||
<EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelectingOptional())" @bind-Value="@this.selectedLanguage" Icon="@Icons.Material.Filled.Translate" Label="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"/>
|
||||
@@ -0,0 +1,170 @@
|
||||
using AIStudio.Chat;
|
||||
|
||||
namespace AIStudio.Assistants.Synonym;
|
||||
|
||||
public partial class AssistantSynonyms : AssistantBaseCore
|
||||
{
|
||||
public override Tools.Components Component => Tools.Components.SYNONYMS_ASSISTANT;
|
||||
|
||||
protected override string Title => "Synonyms";
|
||||
|
||||
protected override string Description =>
|
||||
"""
|
||||
Find synonyms for words or phrases.
|
||||
""";
|
||||
|
||||
protected override string SystemPrompt =>
|
||||
$"""
|
||||
You have a PhD in linguistics. Therefore, you are an expert in the {this.SystemPromptLanguage()} language.
|
||||
You receive a word or phrase as input. You might also receive some context. You then provide
|
||||
a list of synonyms as a Markdown list.
|
||||
|
||||
First, derive possible meanings from the word, phrase, and context, when available. Then, provide
|
||||
possible synonyms for each meaning.
|
||||
|
||||
Example for the word "learn" and the language English (US):
|
||||
|
||||
Derive possible meanings (*this list is not part of the output*):
|
||||
- Meaning "to learn"
|
||||
- Meaning "to retain"
|
||||
|
||||
Next, provide possible synonyms for each meaning, which is your output:
|
||||
|
||||
# Meaning "to learn"
|
||||
- absorb
|
||||
- study
|
||||
- acquire
|
||||
- advance
|
||||
- practice
|
||||
|
||||
# Meaning "to retain"
|
||||
- remember
|
||||
- note
|
||||
- realize
|
||||
|
||||
You do not ask follow-up questions and never repeat the task instructions. When you do not know
|
||||
any synonyms for the given word or phrase, you state this. Your output is always in
|
||||
the {this.SystemPromptLanguage()} language.
|
||||
""";
|
||||
|
||||
protected override bool AllowProfiles => false;
|
||||
|
||||
protected override IReadOnlyList<IButtonData> FooterButtons => [];
|
||||
|
||||
protected override string SubmitText => "Find synonyms";
|
||||
|
||||
protected override Func<Task> SubmitAction => this.FindSynonyms;
|
||||
|
||||
protected override ChatThread ConvertToChatThread => (this.chatThread ?? new()) with
|
||||
{
|
||||
SystemPrompt = SystemPrompts.DEFAULT,
|
||||
};
|
||||
|
||||
protected override void ResetFrom()
|
||||
{
|
||||
this.inputText = string.Empty;
|
||||
this.inputContext = string.Empty;
|
||||
if (!this.MightPreselectValues())
|
||||
{
|
||||
this.selectedLanguage = CommonLanguages.AS_IS;
|
||||
this.customTargetLanguage = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool MightPreselectValues()
|
||||
{
|
||||
if (this.SettingsManager.ConfigurationData.Synonyms.PreselectOptions)
|
||||
{
|
||||
this.selectedLanguage = this.SettingsManager.ConfigurationData.Synonyms.PreselectedLanguage;
|
||||
this.customTargetLanguage = this.SettingsManager.ConfigurationData.Synonyms.PreselectedOtherLanguage;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private string inputText = string.Empty;
|
||||
private string inputContext = string.Empty;
|
||||
private CommonLanguages selectedLanguage;
|
||||
private string customTargetLanguage = string.Empty;
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages<string>(Event.SEND_TO_SYNONYMS_ASSISTANT).FirstOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputContext = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private string? ValidatingText(string text)
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(text))
|
||||
return "Please provide a word or phrase as input.";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string? ValidateCustomLanguage(string language)
|
||||
{
|
||||
if(this.selectedLanguage == CommonLanguages.OTHER && string.IsNullOrWhiteSpace(language))
|
||||
return "Please provide a custom language.";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string SystemPromptLanguage()
|
||||
{
|
||||
var lang = this.selectedLanguage switch
|
||||
{
|
||||
CommonLanguages.AS_IS => "source",
|
||||
CommonLanguages.OTHER => this.customTargetLanguage,
|
||||
|
||||
_ => $"{this.selectedLanguage.Name()}",
|
||||
};
|
||||
|
||||
if (string.IsNullOrWhiteSpace(lang))
|
||||
return "source";
|
||||
|
||||
return lang;
|
||||
}
|
||||
|
||||
private string UserPromptContext()
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(this.inputContext))
|
||||
return string.Empty;
|
||||
|
||||
return $"""
|
||||
The given context is:
|
||||
|
||||
```
|
||||
{this.inputContext}
|
||||
```
|
||||
|
||||
""";
|
||||
}
|
||||
|
||||
private async Task FindSynonyms()
|
||||
{
|
||||
await this.form!.Validate();
|
||||
if (!this.inputIsValid)
|
||||
return;
|
||||
|
||||
this.CreateChatThread();
|
||||
var time = this.AddUserRequest(
|
||||
$"""
|
||||
{this.UserPromptContext()}
|
||||
The given word or phrase is:
|
||||
|
||||
```
|
||||
{this.inputText}
|
||||
```
|
||||
""");
|
||||
|
||||
await this.AddAIResponseAsync(time);
|
||||
}
|
||||
}
|
||||
+2
-7
@@ -1,5 +1,4 @@
|
||||
@page "/assistant/summarizer"
|
||||
@using AIStudio.Tools
|
||||
@attribute [Route(Routes.ASSISTANT_SUMMARIZER)]
|
||||
@inherits AssistantBaseCore
|
||||
|
||||
@if (!this.SettingsManager.ConfigurationData.TextSummarizer.HideWebContentReader)
|
||||
@@ -10,8 +9,4 @@
|
||||
<MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.inputText" Validation="@this.ValidatingText" AdornmentIcon="@Icons.Material.Filled.DocumentScanner" Adornment="Adornment.Start" Label="Your input" Variant="Variant.Outlined" Lines="6" AutoGrow="@true" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
|
||||
<EnumSelection T="CommonLanguages" NameFunc="@(language => language.Name())" @bind-Value="@this.selectedTargetLanguage" Icon="@Icons.Material.Filled.Translate" Label="Target language" AllowOther="@true" @bind-OtherInput="@this.customTargetLanguage" OtherValue="CommonLanguages.OTHER" LabelOther="Custom target language" ValidateOther="@this.ValidateCustomLanguage" />
|
||||
<EnumSelection T="Complexity" NameFunc="@(complexity => complexity.Name())" @bind-Value="@this.selectedComplexity" Icon="@Icons.Material.Filled.Layers" Label="Target complexity" AllowOther="@true" @bind-OtherInput="@this.expertInField" OtherValue="Complexity.SCIENTIFIC_LANGUAGE_OTHER_EXPERTS" LabelOther="Your expertise" ValidateOther="@this.ValidateExpertInField" />
|
||||
<ProviderSelection @bind-ProviderSettings="@this.providerSettings" ValidateProvider="@this.ValidatingProvider"/>
|
||||
|
||||
<MudButton Variant="Variant.Filled" Class="mb-3" OnClick="() => this.SummarizeText()" Disabled="@this.isAgentRunning">
|
||||
Summarize
|
||||
</MudButton>
|
||||
<ProviderSelection @bind-ProviderSettings="@this.providerSettings" ValidateProvider="@this.ValidatingProvider"/>
|
||||
+48
-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
|
||||
{
|
||||
public override Tools.Components Component => Tools.Components.TEXT_SUMMARIZER_ASSISTANT;
|
||||
|
||||
protected override string Title => "Text Summarizer";
|
||||
|
||||
protected override string Description =>
|
||||
@@ -23,6 +25,47 @@ public partial class AssistantTextSummarizer : AssistantBaseCore
|
||||
a summary with the requested complexity. In any case, do not add any information.
|
||||
""";
|
||||
|
||||
protected override bool AllowProfiles => false;
|
||||
|
||||
protected override IReadOnlyList<IButtonData> FooterButtons => [];
|
||||
|
||||
protected override string SubmitText => "Summarize";
|
||||
|
||||
protected override Func<Task> SubmitAction => this.SummarizeText;
|
||||
|
||||
protected override bool SubmitDisabled => this.isAgentRunning;
|
||||
|
||||
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 +77,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
|
||||
{
|
||||
+2
-7
@@ -1,5 +1,4 @@
|
||||
@page "/assistant/translation"
|
||||
@using AIStudio.Tools
|
||||
@attribute [Route(Routes.ASSISTANT_TRANSLATION)]
|
||||
@inherits AssistantBaseCore
|
||||
|
||||
@if (!this.SettingsManager.ConfigurationData.Translation.HideWebContentReader)
|
||||
@@ -18,8 +17,4 @@ else
|
||||
}
|
||||
|
||||
<EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelecting())" @bind-Value="@this.selectedTargetLanguage" ValidateSelection="@this.ValidatingTargetLanguage" 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 Disabled="@this.isAgentRunning" Variant="Variant.Filled" Class="mb-3" OnClick="() => this.TranslateText(force: true)">
|
||||
Translate
|
||||
</MudButton>
|
||||
<ProviderSelection @bind-ProviderSettings="@this.providerSettings" ValidateProvider="@this.ValidatingProvider"/>
|
||||
+47
-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
|
||||
{
|
||||
public override Tools.Components Component => Tools.Components.TRANSLATION_ASSISTANT;
|
||||
|
||||
protected override string Title => "Translation";
|
||||
|
||||
protected override string Description =>
|
||||
@@ -19,6 +21,46 @@ public partial class AssistantTranslation : AssistantBaseCore
|
||||
language requires, e.g., shorter sentences, you should split the text into shorter sentences.
|
||||
""";
|
||||
|
||||
protected override bool AllowProfiles => false;
|
||||
|
||||
protected override IReadOnlyList<IButtonData> FooterButtons => [];
|
||||
|
||||
protected override string SubmitText => "Translate";
|
||||
|
||||
protected override Func<Task> SubmitAction => () => this.TranslateText(true);
|
||||
|
||||
protected override bool SubmitDisabled => this.isAgentRunning;
|
||||
|
||||
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 +72,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>
|
||||
@@ -1,160 +0,0 @@
|
||||
using AIStudio.Chat;
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Tools;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public abstract partial class AssistantBase : ComponentBase
|
||||
{
|
||||
[Inject]
|
||||
protected SettingsManager SettingsManager { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected IJSRuntime JsRuntime { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected ThreadSafeRandom RNG { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected ISnackbar Snackbar { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected Rust Rust { get; init; } = null!;
|
||||
|
||||
internal const string AFTER_RESULT_DIV_ID = "afterAssistantResult";
|
||||
internal const string ASSISTANT_RESULT_DIV_ID = "assistantResult";
|
||||
|
||||
protected abstract string Title { get; }
|
||||
|
||||
protected abstract string Description { get; }
|
||||
|
||||
protected abstract string SystemPrompt { get; }
|
||||
|
||||
private protected virtual RenderFragment? Body => null;
|
||||
|
||||
protected virtual bool ShowResult => true;
|
||||
|
||||
protected virtual bool ShowDedicatedProgress => false;
|
||||
|
||||
protected virtual IReadOnlyList<ButtonData> FooterButtons => [];
|
||||
|
||||
protected static readonly Dictionary<string, object?> USER_INPUT_ATTRIBUTES = new();
|
||||
|
||||
protected AIStudio.Settings.Provider providerSettings;
|
||||
protected MudForm? form;
|
||||
protected bool inputIsValid;
|
||||
|
||||
private ChatThread? chatThread;
|
||||
private ContentBlock? resultingContentBlock;
|
||||
private string[] inputIssues = [];
|
||||
private bool isProcessing;
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
// Configure the spellchecking for the user input:
|
||||
this.SettingsManager.InjectSpellchecking(USER_INPUT_ATTRIBUTES);
|
||||
|
||||
await base.OnParametersSetAsync();
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
// Reset the validation when not editing and on the first render.
|
||||
// We don't want to show validation errors when the user opens the dialog.
|
||||
if(firstRender)
|
||||
this.form?.ResetValidation();
|
||||
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected string? ValidatingProvider(AIStudio.Settings.Provider provider)
|
||||
{
|
||||
if(provider.UsedProvider == Providers.NONE)
|
||||
return "Please select a provider.";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void CreateChatThread()
|
||||
{
|
||||
this.chatThread = new()
|
||||
{
|
||||
WorkspaceId = Guid.Empty,
|
||||
ChatId = Guid.NewGuid(),
|
||||
Name = string.Empty,
|
||||
Seed = this.RNG.Next(),
|
||||
SystemPrompt = this.SystemPrompt,
|
||||
Blocks = [],
|
||||
};
|
||||
}
|
||||
|
||||
protected DateTimeOffset AddUserRequest(string request)
|
||||
{
|
||||
var time = DateTimeOffset.Now;
|
||||
this.chatThread!.Blocks.Add(new ContentBlock
|
||||
{
|
||||
Time = time,
|
||||
ContentType = ContentType.TEXT,
|
||||
Role = ChatRole.USER,
|
||||
Content = new ContentText
|
||||
{
|
||||
Text = request,
|
||||
},
|
||||
});
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
protected async Task<string> AddAIResponseAsync(DateTimeOffset time)
|
||||
{
|
||||
var aiText = new ContentText
|
||||
{
|
||||
// We have to wait for the remote
|
||||
// for the content stream:
|
||||
InitialRemoteWait = true,
|
||||
};
|
||||
|
||||
this.resultingContentBlock = new ContentBlock
|
||||
{
|
||||
Time = time,
|
||||
ContentType = ContentType.TEXT,
|
||||
Role = ChatRole.AI,
|
||||
Content = aiText,
|
||||
};
|
||||
|
||||
this.chatThread?.Blocks.Add(this.resultingContentBlock);
|
||||
this.isProcessing = true;
|
||||
this.StateHasChanged();
|
||||
|
||||
// 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);
|
||||
|
||||
this.isProcessing = false;
|
||||
this.StateHasChanged();
|
||||
|
||||
// Return the AI response:
|
||||
return aiText.Text;
|
||||
}
|
||||
|
||||
protected async Task CopyToClipboard(string text)
|
||||
{
|
||||
await this.Rust.CopyText2Clipboard(this.JsRuntime, this.Snackbar, text);
|
||||
}
|
||||
|
||||
private static string? GetButtonIcon(string icon)
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(icon))
|
||||
return null;
|
||||
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
<MudCard Outlined="@true" Style="border-width: 2px; border-color: #0d47a1; border-radius: 12px; border-style: solid; max-width: 20em;">
|
||||
<MudCard Outlined="@true" Style="@this.BlockStyle">
|
||||
<MudCardHeader>
|
||||
<CardHeaderContent>
|
||||
<MudStack AlignItems="AlignItems.Center" Row="@true">
|
||||
@@ -0,0 +1,82 @@
|
||||
using AIStudio.Settings;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public partial class AssistantBlock : ComponentBase, IMessageBusReceiver, IDisposable
|
||||
{
|
||||
[Parameter]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public string Icon { get; set; } = Icons.Material.Filled.DisabledByDefault;
|
||||
|
||||
[Parameter]
|
||||
public string ButtonText { get; set; } = "Start";
|
||||
|
||||
[Parameter]
|
||||
public string Link { get; set; } = string.Empty;
|
||||
|
||||
[Inject]
|
||||
private MudTheme ColorTheme { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private SettingsManager SettingsManager { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private MessageBus MessageBus { get; init; } = null!;
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
this.MessageBus.RegisterComponent(this);
|
||||
this.MessageBus.ApplyFilters(this, [], [ Event.COLOR_THEME_CHANGED ]);
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IMessageBusReceiver
|
||||
|
||||
public Task ProcessMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data)
|
||||
{
|
||||
switch (triggeredEvent)
|
||||
{
|
||||
case Event.COLOR_THEME_CHANGED:
|
||||
this.StateHasChanged();
|
||||
break;
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<TResult?> ProcessMessageWithResult<TPayload, TResult>(ComponentBase? sendingComponent, Event triggeredEvent, TPayload? data)
|
||||
{
|
||||
return Task.FromResult<TResult?>(default);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private string BorderColor => this.SettingsManager.IsDarkMode switch
|
||||
{
|
||||
true => this.ColorTheme.GetCurrentPalette(this.SettingsManager).GrayLight,
|
||||
false => this.ColorTheme.GetCurrentPalette(this.SettingsManager).Primary.Value,
|
||||
};
|
||||
|
||||
private string BlockStyle => $"border-width: 2px; border-color: {this.BorderColor}; border-radius: 12px; border-style: solid; max-width: 20em;";
|
||||
|
||||
#region Implementation of IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.MessageBus.Unregister(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components.Blocks;
|
||||
|
||||
public partial class AssistantBlock : ComponentBase
|
||||
{
|
||||
[Parameter]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public string Icon { get; set; } = Icons.Material.Filled.DisabledByDefault;
|
||||
|
||||
[Parameter]
|
||||
public string ButtonText { get; set; } = "Start";
|
||||
|
||||
[Parameter]
|
||||
public string Link { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -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,26 +0,0 @@
|
||||
using AIStudio.Settings;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components.Blocks;
|
||||
|
||||
public partial class ProviderSelection : ComponentBase
|
||||
{
|
||||
[Parameter]
|
||||
public Settings.Provider ProviderSettings { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<Settings.Provider> ProviderSettingsChanged { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public Func<Settings.Provider, string?> ValidateProvider { get; set; } = _ => null;
|
||||
|
||||
[Inject]
|
||||
protected SettingsManager SettingsManager { get; set; } = null!;
|
||||
|
||||
private async Task SelectionChanged(Settings.Provider provider)
|
||||
{
|
||||
this.ProviderSettings = provider;
|
||||
await this.ProviderSettingsChanged.InvokeAsync(provider);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace AIStudio.Components.Blocks;
|
||||
|
||||
public readonly record struct TreeDivider : ITreeItem;
|
||||
+17
-1
@@ -1,4 +1,4 @@
|
||||
namespace AIStudio.Components.Blocks;
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public partial class Changelog
|
||||
{
|
||||
@@ -13,6 +13,22 @@ public partial class Changelog
|
||||
|
||||
public static readonly Log[] LOGS =
|
||||
[
|
||||
new (186, "v0.9.11, build 186 (2024-09-15 10:33 UTC)", "v0.9.11.md"),
|
||||
new (185, "v0.9.10, build 185 (2024-09-12 20:52 UTC)", "v0.9.10.md"),
|
||||
new (184, "v0.9.9, build 184 (2024-09-11 21:10 UTC)", "v0.9.9.md"),
|
||||
new (183, "v0.9.8, build 183 (2024-09-09 13:10 UTC)", "v0.9.8.md"),
|
||||
new (182, "v0.9.7, build 182 (2024-09-08 20:55 UTC)", "v0.9.7.md"),
|
||||
new (181, "v0.9.6, build 181 (2024-09-08 09:30 UTC)", "v0.9.6.md"),
|
||||
new (180, "v0.9.5, build 180 (2024-09-07 16:33 UTC)", "v0.9.5.md"),
|
||||
new (179, "v0.9.4, build 179 (2024-09-06 20:11 UTC)", "v0.9.4.md"),
|
||||
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
|
||||
{
|
||||
@@ -0,0 +1,58 @@
|
||||
@using AIStudio.Provider
|
||||
<div class="d-flex">
|
||||
<MudTooltip Text="Shows and hides the confidence card with information about the selected LLM provider.">
|
||||
@if (this.Mode is ConfidenceInfoMode.ICON)
|
||||
{
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Security" Class="confidence-icon" Style="@this.LLMProvider.GetConfidence(this.SettingsManager).SetColorStyle(this.SettingsManager)" OnClick="@(() => this.ToggleConfidence())"/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudButton Variant="Variant.Filled" StartIcon="@Icons.Material.Filled.Security" IconClass="confidence-icon" Style="@this.LLMProvider.GetConfidence(this.SettingsManager).SetColorStyle(this.SettingsManager)" OnClick="@(() => this.ToggleConfidence())">
|
||||
Confidence
|
||||
</MudButton>
|
||||
}
|
||||
</MudTooltip>
|
||||
|
||||
<MudPopover Open="@this.showConfidence" AnchorOrigin="Origin.TopLeft" TransformOrigin="Origin.BottomLeft" Style="@this.GetPopoverStyle()" DropShadow="@true" Class="border-solid border-4 rounded-lg">
|
||||
<MudCard>
|
||||
<MudCardHeader>
|
||||
<CardHeaderContent>
|
||||
<MudText Typo="Typo.h5">Confidence Card</MudText>
|
||||
</CardHeaderContent>
|
||||
</MudCardHeader>
|
||||
<MudCardContent>
|
||||
<MudText Typo="Typo.h6">Description</MudText>
|
||||
<MudMarkdown Value="@this.currentConfidence.Description"/>
|
||||
|
||||
@if (this.currentConfidence.Sources.Count > 0)
|
||||
{
|
||||
<MudText Typo="Typo.h6">Sources</MudText>
|
||||
<MudList T="@string">
|
||||
@foreach (var sourceTuple in this.GetConfidenceSources())
|
||||
{
|
||||
<MudListItem Icon="@Icons.Material.Filled.Link" Href="@sourceTuple.Source" Target="_blank" Text="@sourceTuple.Index"/>
|
||||
}
|
||||
</MudList>
|
||||
}
|
||||
|
||||
@if (!string.IsNullOrWhiteSpace(this.currentConfidence.Region))
|
||||
{
|
||||
<MudText Typo="Typo.h6">Region</MudText>
|
||||
<MudText Typo="Typo.body1" Class="mb-3">
|
||||
<b>@this.currentConfidence.Region</b>
|
||||
</MudText>
|
||||
}
|
||||
|
||||
<MudText Typo="Typo.h6">Confidence Level</MudText>
|
||||
<MudText Typo="Typo.body1" Style="@this.GetCurrentConfidenceColor()">
|
||||
<b>@this.currentConfidence.Level.GetName()</b>
|
||||
</MudText>
|
||||
</MudCardContent>
|
||||
<MudCardActions>
|
||||
<MudButton Variant="Variant.Filled" OnClick="@(() => this.HideConfidence())">
|
||||
Close
|
||||
</MudButton>
|
||||
</MudCardActions>
|
||||
</MudCard>
|
||||
</MudPopover>
|
||||
</div>
|
||||
@@ -0,0 +1,94 @@
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Settings;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public partial class ConfidenceInfo : ComponentBase, IMessageBusReceiver, IDisposable
|
||||
{
|
||||
[Parameter]
|
||||
public ConfidenceInfoMode Mode { get; set; } = ConfidenceInfoMode.BUTTON;
|
||||
|
||||
[Parameter]
|
||||
public LLMProviders LLMProvider { get; set; }
|
||||
|
||||
[Inject]
|
||||
private SettingsManager SettingsManager { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private MessageBus MessageBus { get; init; } = null!;
|
||||
|
||||
private Confidence currentConfidence;
|
||||
private bool showConfidence;
|
||||
|
||||
public ConfidenceInfo()
|
||||
{
|
||||
this.currentConfidence = LLMProviders.NONE.GetConfidence(this.SettingsManager);
|
||||
}
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
this.MessageBus.RegisterComponent(this);
|
||||
this.MessageBus.ApplyFilters(this, [], [ Event.COLOR_THEME_CHANGED ]);
|
||||
|
||||
this.currentConfidence = this.LLMProvider.GetConfidence(this.SettingsManager);
|
||||
await base.OnParametersSetAsync();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void ToggleConfidence()
|
||||
{
|
||||
this.showConfidence = !this.showConfidence;
|
||||
}
|
||||
|
||||
private void HideConfidence()
|
||||
{
|
||||
this.showConfidence = false;
|
||||
}
|
||||
|
||||
private IEnumerable<(string Index, string Source)> GetConfidenceSources()
|
||||
{
|
||||
var index = 0;
|
||||
foreach (var source in this.currentConfidence.Sources)
|
||||
yield return ($"Source {++index}", source);
|
||||
}
|
||||
|
||||
private string GetCurrentConfidenceColor() => $"color: {this.currentConfidence.Level.GetColor(this.SettingsManager)};";
|
||||
|
||||
private string GetPopoverStyle() => $"border-color: {this.currentConfidence.Level.GetColor(this.SettingsManager)}; max-width: calc(35vw);";
|
||||
|
||||
#region Implementation of IMessageBusReceiver
|
||||
|
||||
public Task ProcessMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data)
|
||||
{
|
||||
switch (triggeredEvent)
|
||||
{
|
||||
case Event.COLOR_THEME_CHANGED:
|
||||
this.showConfidence = false;
|
||||
this.StateHasChanged();
|
||||
break;
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<TResult?> ProcessMessageWithResult<TPayload, TResult>(ComponentBase? sendingComponent, Event triggeredEvent, TPayload? data)
|
||||
{
|
||||
return Task.FromResult<TResult?>(default);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.MessageBus.Unregister(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public enum ConfidenceInfoMode
|
||||
{
|
||||
BUTTON,
|
||||
ICON,
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Tools;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
@using AIStudio.Settings
|
||||
<ConfigurationSelect Disabled="@this.Disabled" OptionDescription="Select a minimum confidence level" SelectedValue="@this.FilteredSelectedValue" Data="@ConfigurationSelectDataFactory.GetConfidenceLevelsData(this.SettingsManager, this.RestrictToGlobalMinimumConfidence)" SelectionUpdate="@this.SelectionUpdate" OptionHelp="Choose the minimum confidence level that all LLM providers must meet. This way, you can ensure that only trustworthy providers are used. You cannot use any provider that falls below this level."/>
|
||||
@@ -0,0 +1,51 @@
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Settings;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Components;
|
||||
|
||||
public partial class ConfigurationMinConfidenceSelection : ComponentBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The selected value.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<ConfidenceLevel> SelectedValue { get; set; } = () => default!;
|
||||
|
||||
/// <summary>
|
||||
/// An action that is called when the selection changes.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Action<ConfidenceLevel> SelectionUpdate { get; set; } = _ => { };
|
||||
|
||||
/// <summary>
|
||||
/// Is the selection component disabled?
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<bool> Disabled { get; set; } = () => false;
|
||||
|
||||
/// <summary>
|
||||
/// Boolean value indicating whether the selection is restricted to a global minimum confidence level.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool RestrictToGlobalMinimumConfidence { get; set; }
|
||||
|
||||
[Inject]
|
||||
private SettingsManager SettingsManager { get; init; } = null!;
|
||||
|
||||
private ConfidenceLevel FilteredSelectedValue()
|
||||
{
|
||||
if (this.SelectedValue() is ConfidenceLevel.NONE)
|
||||
return ConfidenceLevel.NONE;
|
||||
|
||||
if(this.RestrictToGlobalMinimumConfidence && this.SettingsManager.ConfigurationData.LLMProviders.EnforceGlobalMinimumConfidence)
|
||||
{
|
||||
var minimumLevel = this.SettingsManager.ConfigurationData.LLMProviders.GlobalMinimumConfidence;
|
||||
if(this.SelectedValue() < minimumLevel)
|
||||
return minimumLevel;
|
||||
}
|
||||
|
||||
return this.SelectedValue();
|
||||
}
|
||||
}
|
||||
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.FilteredData()" SelectedValue="@this.SelectedValue" SelectionUpdate="@this.SelectionUpdate"/>
|
||||
+19
-2
@@ -1,9 +1,9 @@
|
||||
using AIStudio.Provider;
|
||||
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 +22,12 @@ 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.";
|
||||
|
||||
[Parameter]
|
||||
public Tools.Components Component { get; set; } = Tools.Components.NONE;
|
||||
|
||||
[Inject]
|
||||
private SettingsManager SettingsManager { get; init; } = null!;
|
||||
|
||||
@@ -41,6 +47,17 @@ public partial class ConfigurationProviderSelection : ComponentBase, IMessageBus
|
||||
|
||||
#endregion
|
||||
|
||||
private IEnumerable<ConfigurationSelectData<string>> FilteredData()
|
||||
{
|
||||
var minimumLevel = this.SettingsManager.GetMinimumConfidenceLevel(this.Component);
|
||||
foreach (var providerId in this.Data)
|
||||
{
|
||||
var provider = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == providerId.Value);
|
||||
if (provider.UsedLLMProvider.GetConfidence(this.SettingsManager).Level >= minimumLevel)
|
||||
yield return providerId;
|
||||
}
|
||||
}
|
||||
|
||||
#region Implementation of IMessageBusReceiver
|
||||
|
||||
public async Task ProcessMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data)
|
||||
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>
|
||||
+13
-4
@@ -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
|
||||
|
||||
@@ -39,7 +43,7 @@ public partial class InnerScrolling : MSGComponentBase
|
||||
|
||||
#region Overrides of MSGComponentBase
|
||||
|
||||
public override Task ProcessMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
|
||||
public override Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
|
||||
{
|
||||
switch (triggeredEvent)
|
||||
{
|
||||
@@ -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;
|
||||
@@ -21,7 +19,22 @@ public abstract class MSGComponentBase : ComponentBase, IDisposable, IMessageBus
|
||||
|
||||
#region Implementation of IMessageBusReceiver
|
||||
|
||||
public abstract Task ProcessMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data);
|
||||
public Task ProcessMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data)
|
||||
{
|
||||
switch (triggeredEvent)
|
||||
{
|
||||
case Event.COLOR_THEME_CHANGED:
|
||||
this.StateHasChanged();
|
||||
break;
|
||||
|
||||
default:
|
||||
return this.ProcessIncomingMessage(sendingComponent, triggeredEvent, data);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public abstract Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data);
|
||||
|
||||
public abstract Task<TResult?> ProcessMessageWithResult<TPayload, TResult>(ComponentBase? sendingComponent, Event triggeredEvent, TPayload? data);
|
||||
|
||||
@@ -48,6 +61,12 @@ public abstract class MSGComponentBase : ComponentBase, IDisposable, IMessageBus
|
||||
|
||||
protected void ApplyFilters(ComponentBase[] components, Event[] events)
|
||||
{
|
||||
this.MessageBus.ApplyFilters(this, components, events);
|
||||
// Append the color theme changed event to the list of events:
|
||||
var eventsList = new List<Event>(events)
|
||||
{
|
||||
Event.COLOR_THEME_CHANGED
|
||||
};
|
||||
|
||||
this.MessageBus.ApplyFilters(this, components, eventsList.ToArray());
|
||||
}
|
||||
}
|
||||
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
|
||||
{
|
||||
Loaded 100 of 283 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user