├── .vscode └── settings.json ├── assets └── README │ ├── image.png │ ├── image-1.png │ ├── image-2.png │ ├── image-3.png │ ├── image-4.png │ ├── image-5.png │ └── image-6.png ├── PromptPlayground ├── Assets │ ├── logo.ico │ └── logo.png ├── ViewModels │ ├── ViewModelBase.cs │ ├── ConfigViewModels │ │ ├── LLM │ │ │ ├── ILLMConfigViewModel.cs │ │ │ ├── OpenAIConfigViewModel.cs │ │ │ ├── DashScopeConfigViewModel.cs │ │ │ ├── AzureOpenAIConfigViewModel.cs │ │ │ ├── LLamaSharpConfigViewModel.cs │ │ │ └── BaiduConfigViewModel.cs │ │ ├── IConfigViewModel.cs │ │ └── ConfigAttribute.cs │ ├── ResultsViewModel.cs │ ├── StatusViewModel.cs │ ├── AboutViewModel.cs │ ├── MainViewModel.cs │ ├── GenerateResult.cs │ ├── VariablesViewModel.cs │ ├── PluginViewModel.cs │ ├── PluginsViewModel.cs │ ├── ConfigViewModel.cs │ └── SemanticFunctionViewModel.cs ├── Constants.cs ├── Views │ ├── MainWindow.axaml.cs │ ├── ResultsView.axaml.cs │ ├── PluginsView.axaml.cs │ ├── MainWindow.axaml │ ├── AboutView.axaml.cs │ ├── ConfigWindow.axaml.cs │ ├── VariablesWindows.axaml.cs │ ├── EditorView.axaml.cs │ ├── VariablesWindows.axaml │ ├── AboutView.axaml │ ├── MainView.axaml │ ├── PluginsView.axaml │ ├── EditorView.axaml │ ├── ConfigWindow.axaml │ ├── ResultsView.axaml │ └── MainView.axaml.cs ├── Messages │ ├── CopyTextMessage.cs │ ├── FunctionCreateMessage.cs │ ├── FunctionSelectedMessage.cs │ ├── PluginOpenMessage.cs │ ├── FunctionOpenMessage.cs │ ├── CloseFunctionMessage.cs │ ├── ConfigurationRequestMessage.cs │ ├── RequestVariablesMessage.cs │ ├── ConfirmRequestMessage.cs │ ├── FileOrFolderPathMessage.cs │ └── NotificationMessage.cs ├── App.axaml ├── Services │ ├── Models │ │ └── GenerationResultStore.cs │ ├── ProfileService.cs │ ├── DbStore.cs │ └── PromptService.cs ├── Converters │ ├── NullToVisibilityConverter.cs │ └── StringToBooleanConverter.cs ├── Program.cs ├── app.manifest ├── App.axaml.cs ├── Migrations │ ├── 20240221112923_GenerationResultStore.cs │ ├── DbStoreModelSnapshot.cs │ └── 20240221112923_GenerationResultStore.Designer.cs ├── Behaviors │ └── DocumentTextBindingBehavior.cs └── PromptPlayground.csproj ├── Directory.Build.props ├── LICENSE ├── README_CN.md ├── PromptPlayground.sln ├── CONTRIBUTING.md ├── README.md ├── .gitattributes ├── installer.iss ├── CODE_OF_CONDUCT.md └── .gitignore /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "dotnet.defaultSolution": "PromptPlayground.sln" 3 | } -------------------------------------------------------------------------------- /assets/README/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xbotter/PromptPlayground/HEAD/assets/README/image.png -------------------------------------------------------------------------------- /assets/README/image-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xbotter/PromptPlayground/HEAD/assets/README/image-1.png -------------------------------------------------------------------------------- /assets/README/image-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xbotter/PromptPlayground/HEAD/assets/README/image-2.png -------------------------------------------------------------------------------- /assets/README/image-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xbotter/PromptPlayground/HEAD/assets/README/image-3.png -------------------------------------------------------------------------------- /assets/README/image-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xbotter/PromptPlayground/HEAD/assets/README/image-4.png -------------------------------------------------------------------------------- /assets/README/image-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xbotter/PromptPlayground/HEAD/assets/README/image-5.png -------------------------------------------------------------------------------- /assets/README/image-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xbotter/PromptPlayground/HEAD/assets/README/image-6.png -------------------------------------------------------------------------------- /PromptPlayground/Assets/logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xbotter/PromptPlayground/HEAD/PromptPlayground/Assets/logo.ico -------------------------------------------------------------------------------- /PromptPlayground/Assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xbotter/PromptPlayground/HEAD/PromptPlayground/Assets/logo.png -------------------------------------------------------------------------------- /PromptPlayground/ViewModels/ViewModelBase.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | 3 | namespace PromptPlayground.ViewModels; 4 | 5 | public class ViewModelBase : ObservableObject 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /PromptPlayground/Constants.cs: -------------------------------------------------------------------------------- 1 | namespace PromptPlayground 2 | { 3 | internal static class Constants 4 | { 5 | public const string SkPrompt = "skprompt.txt"; 6 | public const string SkConfig = "config.json"; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /PromptPlayground/Views/MainWindow.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace PromptPlayground.Views; 4 | 5 | public partial class MainWindow : Window 6 | { 7 | public MainWindow() 8 | { 9 | InitializeComponent(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /PromptPlayground/Messages/CopyTextMessage.cs: -------------------------------------------------------------------------------- 1 | namespace PromptPlayground.Services 2 | { 3 | public class CopyTextMessage 4 | { 5 | public CopyTextMessage(string text) 6 | { 7 | this.Text = text; 8 | } 9 | 10 | public string Text { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | enable 4 | 0.7.1 5 | 6 | 7 | 8 | none 9 | false 10 | 11 | 12 | -------------------------------------------------------------------------------- /PromptPlayground/Messages/FunctionCreateMessage.cs: -------------------------------------------------------------------------------- 1 | namespace PromptPlayground.ViewModels 2 | { 3 | public class FunctionCreateMessage 4 | { 5 | public FunctionCreateMessage(SemanticFunctionViewModel? function = null) 6 | { 7 | Function = function; 8 | } 9 | 10 | public SemanticFunctionViewModel? Function { get; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /PromptPlayground/Messages/FunctionSelectedMessage.cs: -------------------------------------------------------------------------------- 1 | using PromptPlayground.ViewModels; 2 | 3 | namespace PromptPlayground.Messages 4 | { 5 | public class FunctionSelectedMessage 6 | { 7 | public SemanticFunctionViewModel Function { get; set; } 8 | 9 | public FunctionSelectedMessage(SemanticFunctionViewModel viewModel) 10 | { 11 | this.Function = viewModel; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /PromptPlayground/Messages/PluginOpenMessage.cs: -------------------------------------------------------------------------------- 1 | using PromptPlayground.Messages; 2 | 3 | namespace PromptPlayground.ViewModels 4 | { 5 | public class PluginOpenMessage : FileOrFolderPathMessage 6 | { 7 | public PluginOpenMessage(string path) : base(path) { } 8 | } 9 | 10 | public class PluginCloseMessage : FileOrFolderPathMessage 11 | { 12 | public PluginCloseMessage(string path) : base(path) { } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /PromptPlayground/Views/ResultsView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Controls.Notifications; 4 | using Avalonia.Interactivity; 5 | using CommunityToolkit.Mvvm.Messaging; 6 | using PromptPlayground.Services; 7 | using PromptPlayground.ViewModels; 8 | using System; 9 | 10 | namespace PromptPlayground.Views; 11 | 12 | public partial class ResultsView : UserControl 13 | { 14 | public ResultsView() 15 | { 16 | InitializeComponent(); 17 | } 18 | } -------------------------------------------------------------------------------- /PromptPlayground/Messages/FunctionOpenMessage.cs: -------------------------------------------------------------------------------- 1 | using PromptPlayground.Messages; 2 | 3 | namespace PromptPlayground.ViewModels 4 | { 5 | public class FunctionOpenMessage : FileOrFolderPathMessage 6 | { 7 | public FunctionOpenMessage(string folder) : base(folder) 8 | { 9 | 10 | } 11 | } 12 | 13 | public class FunctionSavedMessage : FileOrFolderPathMessage 14 | { 15 | public FunctionSavedMessage(string folder) : base(folder) 16 | { 17 | 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /PromptPlayground/ViewModels/ConfigViewModels/LLM/ILLMConfigViewModel.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.SemanticKernel; 2 | using PromptPlayground.Services; 3 | using System.Collections.Generic; 4 | using System.Collections.ObjectModel; 5 | using System.Linq; 6 | 7 | namespace PromptPlayground.ViewModels.ConfigViewModels.LLM 8 | { 9 | public interface ILLMConfigViewModel : IConfigViewModel 10 | { 11 | public IKernelBuilder CreateKernelBuilder(); 12 | public ResultTokenUsage? GetUsage(FunctionResult resultModel); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /PromptPlayground/Messages/CloseFunctionMessage.cs: -------------------------------------------------------------------------------- 1 | using PromptPlayground.ViewModels; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace PromptPlayground.Messages 9 | { 10 | public class CloseFunctionMessage 11 | { 12 | public CloseFunctionMessage(SemanticFunctionViewModel function) 13 | { 14 | Function = function; 15 | } 16 | 17 | public SemanticFunctionViewModel Function { get; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /PromptPlayground/Messages/ConfigurationRequestMessage.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.Messaging.Messages; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace PromptPlayground.Messages 9 | { 10 | public class ConfigurationRequestMessage : RequestMessage 11 | { 12 | public ConfigurationRequestMessage(string config) 13 | { 14 | Config = config; 15 | } 16 | 17 | public string Config { get; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /PromptPlayground/Views/PluginsView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Interactivity; 3 | using Avalonia.Platform.Storage; 4 | using PromptPlayground.ViewModels; 5 | using System; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Threading.Tasks; 9 | 10 | namespace PromptPlayground.Views; 11 | 12 | public partial class PluginsView : UserControl 13 | { 14 | public PluginsViewModel Model => (this.DataContext as PluginsViewModel)!; 15 | 16 | public PluginsView() 17 | { 18 | InitializeComponent(); 19 | this.DataContext = new PluginsViewModel(); 20 | } 21 | } -------------------------------------------------------------------------------- /PromptPlayground/App.axaml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /PromptPlayground/Messages/RequestVariablesMessage.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.Messaging.Messages; 2 | using PromptPlayground.ViewModels; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace PromptPlayground.Messages 10 | { 11 | public class RequestVariablesMessage : AsyncRequestMessage 12 | { 13 | public RequestVariablesMessage(List variables) 14 | { 15 | Variables = variables; 16 | } 17 | public List Variables { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /PromptPlayground/Messages/ConfirmRequestMessage.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.Messaging.Messages; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace PromptPlayground.Messages 9 | { 10 | public class ConfirmRequestMessage : AsyncRequestMessage 11 | { 12 | public string Title { get; set; } 13 | public string? Message { get; set; } 14 | public ConfirmRequestMessage(string title, string? message) 15 | { 16 | Title = title; 17 | Message = message; 18 | } 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /PromptPlayground/Services/Models/GenerationResultStore.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace PromptPlayground.Services.Models 8 | { 9 | internal class GenerationResultStore 10 | { 11 | public long Id { get; set; } 12 | public required string FunctionPath { get; set; } 13 | public required string Text { get; set; } 14 | public required string RenderedPrompt { get; set; } 15 | public ResultTokenUsage? Usage { get; set; } 16 | public DateTime CreatedAt { get; set; } 17 | public TimeSpan Elapsed { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /PromptPlayground/Views/MainWindow.axaml: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /PromptPlayground/Messages/FileOrFolderPathMessage.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.Messaging.Messages; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace PromptPlayground.Messages 9 | { 10 | public abstract class FileOrFolderPathMessage 11 | { 12 | public string? Path { get; set; } 13 | public FileOrFolderPathMessage(string? path) 14 | { 15 | Path = path; 16 | } 17 | } 18 | 19 | public class RequestFileOpen : AsyncRequestMessage 20 | { 21 | 22 | } 23 | public class RequestFolderOpen : AsyncRequestMessage 24 | { 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /PromptPlayground/Converters/NullToVisibilityConverter.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Data.Converters; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Globalization; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace PromptPlayground.Converters 10 | { 11 | public class NullToVisibilityConverter : IValueConverter 12 | { 13 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) 14 | { 15 | return value != null; 16 | } 17 | 18 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) 19 | { 20 | throw new NotImplementedException(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /PromptPlayground/Messages/NotificationMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace PromptPlayground.Messages 8 | { 9 | public class NotificationMessage 10 | { 11 | public enum NotificationType 12 | { 13 | Information, 14 | Success, 15 | Warning, 16 | Error 17 | } 18 | public NotificationType Level { get; set; } 19 | public string Title { get; set; } 20 | public string? Message { get; set; } 21 | public NotificationMessage(string title, string? message, NotificationType level = NotificationType.Information) 22 | { 23 | Level = level; 24 | Title = title; 25 | Message = message; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /PromptPlayground/Views/AboutView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Interactivity; 4 | using Avalonia.Styling; 5 | 6 | namespace PromptPlayground.Views 7 | { 8 | public partial class AboutView : Window 9 | { 10 | public AboutView() 11 | { 12 | InitializeComponent(); 13 | } 14 | 15 | public void CloseClick(object sender, RoutedEventArgs e) 16 | { 17 | this.Close(); 18 | } 19 | 20 | private void ToggleTheme(object sender, RoutedEventArgs e) 21 | { 22 | var app = Application.Current; 23 | if (app is not null) 24 | { 25 | var theme = app.ActualThemeVariant; 26 | app.RequestedThemeVariant = theme == ThemeVariant.Dark ? ThemeVariant.Light : ThemeVariant.Dark; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /PromptPlayground/Program.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Projektanker.Icons.Avalonia.MaterialDesign; 3 | using Projektanker.Icons.Avalonia; 4 | using System; 5 | 6 | namespace PromptPlayground; 7 | class Program 8 | { 9 | // Initialization code. Don't use any Avalonia, third-party APIs or any 10 | // SynchronizationContext-reliant code before AppMain is called: things aren't initialized 11 | // yet and stuff might break. 12 | [STAThread] 13 | public static void Main(string[] args) => BuildAvaloniaApp() 14 | .StartWithClassicDesktopLifetime(args); 15 | 16 | // Avalonia configuration, don't remove; also used by visual designer. 17 | public static AppBuilder BuildAvaloniaApp() 18 | { 19 | IconProvider.Current 20 | .Register(); 21 | return AppBuilder.Configure() 22 | .UsePlatformDetect() 23 | .WithInterFont() 24 | .LogToTrace(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /PromptPlayground/Views/ConfigWindow.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Interactivity; 3 | using PromptPlayground.ViewModels; 4 | using System; 5 | 6 | namespace PromptPlayground.Views; 7 | 8 | public partial class ConfigWindow : Window 9 | { 10 | public ConfigWindow() 11 | { 12 | InitializeComponent(); 13 | this.Closed += ConfigWindow_Closed; 14 | } 15 | 16 | private void ConfigWindow_Closed(object? sender, EventArgs e) 17 | { 18 | if (this.DataContext is ConfigViewModel config) 19 | { 20 | config.ReloadConfig(); 21 | } 22 | } 23 | 24 | public void SaveConfig(object? sender, RoutedEventArgs e) 25 | { 26 | if (this.DataContext is ConfigViewModel config) 27 | { 28 | config.SaveConfig(); 29 | } 30 | this.Close(); 31 | } 32 | public void ResetConfig(object? sender, RoutedEventArgs e) 33 | { 34 | this.Close(); 35 | } 36 | } -------------------------------------------------------------------------------- /PromptPlayground/app.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /PromptPlayground/ViewModels/ResultsViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | using CommunityToolkit.Mvvm.Messaging; 3 | using PromptPlayground.Messages; 4 | using PromptPlayground.Services; 5 | using System.Collections.ObjectModel; 6 | 7 | namespace PromptPlayground.ViewModels 8 | { 9 | public class ResultsViewModel : ObservableRecipient, IRecipient 10 | { 11 | private SemanticFunctionViewModel function; 12 | public ObservableCollection Results => function.Results; 13 | public AverageResult AverageResult => function.Average; 14 | 15 | public ResultsViewModel(SemanticFunctionViewModel function) 16 | { 17 | this.function = function; 18 | IsActive = true; 19 | } 20 | 21 | public void Receive(FunctionSelectedMessage message) 22 | { 23 | this.function = message.Function; 24 | OnPropertyChanged(nameof(Results)); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /PromptPlayground/Converters/StringToBooleanConverter.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Data.Converters; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Globalization; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace PromptPlayground.Converters 10 | { 11 | public class StringToBooleanConverter : IValueConverter 12 | { 13 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) 14 | { 15 | if (value == null || parameter == null || !(value is string) || !(parameter is string)) 16 | { 17 | return false; 18 | } 19 | 20 | var strValue = (string)value; 21 | var strParameter = (string)parameter; 22 | 23 | return strValue.Equals(strParameter, StringComparison.OrdinalIgnoreCase); 24 | } 25 | 26 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) 27 | { 28 | throw new NotSupportedException(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /PromptPlayground/Views/VariablesWindows.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Interactivity; 3 | using PromptPlayground.ViewModels; 4 | 5 | namespace PromptPlayground.Views; 6 | 7 | public partial class VariablesWindows : Window 8 | { 9 | private VariablesViewModel Model => (this.DataContext as VariablesViewModel)!; 10 | public VariablesWindows() 11 | { 12 | InitializeComponent(); 13 | } 14 | 15 | protected override void OnClosing(WindowClosingEventArgs e) 16 | { 17 | if (!this.Model.IsCanceled) 18 | { 19 | if (!e.IsProgrammatic) 20 | { 21 | this.Model.IsCanceled = true; 22 | } 23 | } 24 | } 25 | 26 | public void OnCanceledClick(object sender, RoutedEventArgs e) 27 | { 28 | this.Model.IsCanceled = true; 29 | this.Close(); 30 | } 31 | public void OnContinuedClick(object sender, RoutedEventArgs e) 32 | { 33 | if ((this.DataContext as VariablesViewModel)!.Configured()) 34 | { 35 | this.Close(); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 xbotter 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PromptPlayground/App.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls.ApplicationLifetimes; 3 | using Avalonia.Data.Core.Plugins; 4 | using Avalonia.Markup.Xaml; 5 | 6 | using PromptPlayground.ViewModels; 7 | using PromptPlayground.Views; 8 | 9 | namespace PromptPlayground; 10 | 11 | public partial class App : Application 12 | { 13 | public override void Initialize() 14 | { 15 | AvaloniaXamlLoader.Load(this); 16 | } 17 | 18 | public override void OnFrameworkInitializationCompleted() 19 | { 20 | // Line below is needed to remove Avalonia data validation. 21 | // Without this line you will get duplicate validations from both Avalonia and CT 22 | BindingPlugins.DataValidators.RemoveAt(0); 23 | 24 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) 25 | { 26 | desktop.MainWindow = new MainWindow 27 | { 28 | DataContext = new MainViewModel() 29 | }; 30 | } 31 | else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform) 32 | { 33 | singleViewPlatform.MainView = new MainView 34 | { 35 | DataContext = new MainViewModel() 36 | }; 37 | } 38 | 39 | base.OnFrameworkInitializationCompleted(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /PromptPlayground/ViewModels/StatusViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | using CommunityToolkit.Mvvm.Messaging; 3 | using CommunityToolkit.Mvvm.Messaging.Messages; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace PromptPlayground.ViewModels 11 | { 12 | public partial class StatusViewModel : ObservableRecipient, IRecipient>, IRecipient 13 | { 14 | [ObservableProperty] 15 | public string text = string.Empty; 16 | 17 | [ObservableProperty] 18 | private bool loading = false; 19 | 20 | public StatusViewModel() 21 | { 22 | this.IsActive = true; 23 | 24 | WeakReferenceMessenger.Default.Register, string>(this, "Status"); 25 | } 26 | 27 | public void Receive(ValueChangedMessage message) 28 | { 29 | 30 | } 31 | 32 | public void Receive(LoadingStatus message) 33 | { 34 | this.Loading = message.IsRunning; 35 | } 36 | } 37 | } 38 | public class LoadingStatus 39 | { 40 | public LoadingStatus(bool isRunning) 41 | { 42 | IsRunning = isRunning; 43 | } 44 | 45 | public bool IsRunning { get; set; } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /PromptPlayground/ViewModels/AboutViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | using CommunityToolkit.Mvvm.Input; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Diagnostics; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Net.Http; 9 | using System.Reflection; 10 | using System.Text; 11 | using System.Threading.Tasks; 12 | 13 | namespace PromptPlayground.ViewModels 14 | { 15 | public partial class AboutViewModel : ViewModelBase 16 | { 17 | 18 | const string GitHubLink = "https://github.com/xbotter/PromptPlayground"; 19 | const string ReleaseLink = GitHubLink + "/releases/latest"; 20 | 21 | public Version? CurrentVersion { get; set; } 22 | 23 | public AboutViewModel() 24 | { 25 | CurrentVersion = Assembly.GetExecutingAssembly().GetName().Version; 26 | } 27 | 28 | 29 | [RelayCommand] 30 | public void OpenGitHub() => OpenLink(GitHubLink); 31 | 32 | [RelayCommand] 33 | public void CheckVersion() => OpenLink(ReleaseLink); 34 | 35 | public static void OpenLink(string link) 36 | { 37 | var psi = new ProcessStartInfo() 38 | { 39 | FileName = link, 40 | UseShellExecute = true 41 | }; 42 | Process.Start(psi); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /PromptPlayground/ViewModels/ConfigViewModels/LLM/OpenAIConfigViewModel.cs: -------------------------------------------------------------------------------- 1 | using Azure.AI.OpenAI; 2 | using Microsoft.SemanticKernel; 3 | using PromptPlayground.Services; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace PromptPlayground.ViewModels.ConfigViewModels.LLM 11 | { 12 | internal class OpenAIConfigViewModel : ConfigViewModelBase, ILLMConfigViewModel 13 | { 14 | public OpenAIConfigViewModel(IConfigAttributesProvider provider) : base(provider) 15 | { 16 | RequireAttribute(ConfigAttribute.OpenAIModel); 17 | RequireAttribute(ConfigAttribute.OpenAIApiKey); 18 | } 19 | 20 | public override string Name => "OpenAI"; 21 | 22 | public IKernelBuilder CreateKernelBuilder() 23 | { 24 | var model = GetAttribute(ConfigAttribute.OpenAIModel); 25 | var apiKey = GetAttribute(ConfigAttribute.OpenAIApiKey); 26 | 27 | return Kernel.CreateBuilder() 28 | .AddOpenAIChatCompletion(model, apiKey); 29 | } 30 | 31 | public ResultTokenUsage? GetUsage(FunctionResult result) 32 | { 33 | var usage = result.Metadata?["Usage"] as CompletionsUsage; 34 | if (usage == null) 35 | { 36 | return null; 37 | } 38 | return new ResultTokenUsage(usage.TotalTokens, usage.PromptTokens, usage.CompletionTokens); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /PromptPlayground/Services/ProfileService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace PromptPlayground.Services 9 | { 10 | internal class ProfileService 11 | { 12 | private readonly string _profile; 13 | 14 | public ProfileService(string profile) 15 | { 16 | this._profile = profile; 17 | } 18 | 19 | public string ProfilePath() 20 | { 21 | var userProfile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); 22 | var profileFolder = Path.Combine(userProfile, ".prompt_playground"); 23 | if (!Directory.Exists(profileFolder)) 24 | { 25 | Directory.CreateDirectory(profileFolder); 26 | } 27 | return Path.Combine(profileFolder, $"{_profile}"); 28 | } 29 | 30 | 31 | 32 | public T? Get() 33 | { 34 | var path = ProfilePath(); 35 | if (!File.Exists(path)) 36 | { 37 | return default; 38 | } 39 | var json = File.ReadAllText(path); 40 | return System.Text.Json.JsonSerializer.Deserialize(json); 41 | } 42 | 43 | public void Save(T profile) 44 | { 45 | var path = ProfilePath(); 46 | var json = System.Text.Json.JsonSerializer.Serialize(profile); 47 | File.WriteAllText(path, json, Encoding.UTF8); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /PromptPlayground/ViewModels/ConfigViewModels/LLM/DashScopeConfigViewModel.cs: -------------------------------------------------------------------------------- 1 | using Azure.AI.OpenAI; 2 | using DashScope; 3 | using DashScope.Models; 4 | using Microsoft.SemanticKernel; 5 | using PromptPlayground.Services; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | 12 | namespace PromptPlayground.ViewModels.ConfigViewModels.LLM 13 | { 14 | internal class DashScopeConfigViewModel : ConfigViewModelBase, ILLMConfigViewModel 15 | { 16 | public override string Name => "DashScope"; 17 | 18 | public DashScopeConfigViewModel(IConfigAttributesProvider provider) : base(provider) 19 | { 20 | RequireAttribute(ConfigAttribute.DashScopeApiKey); 21 | RequireAttribute(ConfigAttribute.DashScopeModel); 22 | } 23 | 24 | public IKernelBuilder CreateKernelBuilder() 25 | { 26 | var apiKey = GetAttribute(ConfigAttribute.DashScopeApiKey); 27 | var model = GetAttribute(ConfigAttribute.DashScopeModel); 28 | 29 | return Kernel.CreateBuilder().WithDashScopeCompletionService(apiKey, model); 30 | } 31 | 32 | public ResultTokenUsage? GetUsage(FunctionResult resultModel) 33 | { 34 | var usage = resultModel.Metadata?["Usage"] as CompletionUsage; 35 | if (usage == null) 36 | { 37 | return null; 38 | } 39 | return new ResultTokenUsage(usage.InputTokens + usage.OutputTokens, usage.InputTokens, usage.OutputTokens); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /PromptPlayground/Views/EditorView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Controls.Notifications; 4 | using Avalonia.Interactivity; 5 | using Avalonia.Platform.Storage; 6 | using AvaloniaEdit; 7 | using AvaloniaEdit.TextMate; 8 | using CommunityToolkit.Mvvm.Messaging; 9 | using Microsoft.SemanticKernel; 10 | using MsBox.Avalonia; 11 | using PromptPlayground.Messages; 12 | using PromptPlayground.Services; 13 | using PromptPlayground.ViewModels; 14 | using PromptPlayground.ViewModels.ConfigViewModels; 15 | using PromptPlayground.ViewModels.ConfigViewModels.LLM; 16 | using System; 17 | using System.IO; 18 | using System.Linq; 19 | using System.Threading; 20 | using System.Threading.Tasks; 21 | using TextMateSharp.Grammars; 22 | 23 | namespace PromptPlayground.Views; 24 | 25 | public partial class EditorView : UserControl, IRecipient 26 | { 27 | public EditorView() 28 | { 29 | InitializeComponent(); 30 | WeakReferenceMessenger.Default.RegisterAll(this); 31 | } 32 | 33 | protected override void OnInitialized() 34 | { 35 | base.OnInitialized(); 36 | 37 | var _editor = this.FindControl("prompt"); 38 | 39 | var _registryOptions = new RegistryOptions(ThemeName.LightPlus); 40 | 41 | var _textMateInstallation = _editor.InstallTextMate(_registryOptions); 42 | 43 | _textMateInstallation.SetGrammar(_registryOptions.GetScopeByLanguageId(_registryOptions.GetLanguageByExtension(".handlebars").Id)); 44 | } 45 | 46 | public void Receive(FunctionSelectedMessage message) 47 | { 48 | this.DataContext = message.Function; 49 | } 50 | } -------------------------------------------------------------------------------- /PromptPlayground/ViewModels/MainViewModel.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using CommunityToolkit.Mvvm.ComponentModel; 3 | using CommunityToolkit.Mvvm.Input; 4 | using CommunityToolkit.Mvvm.Messaging; 5 | using CommunityToolkit.Mvvm.Messaging.Messages; 6 | using PromptPlayground.Messages; 7 | using System; 8 | using System.Threading.Tasks; 9 | 10 | namespace PromptPlayground.ViewModels; 11 | 12 | public partial class MainViewModel : ViewModelBase 13 | { 14 | static IMessenger Messenger => WeakReferenceMessenger.Default; 15 | 16 | public ConfigViewModel Config { get; set; } = new(true); 17 | 18 | public StatusViewModel Status { get; set; } = new(); 19 | 20 | public AboutViewModel About { get; set; } = new(); 21 | 22 | 23 | public MainViewModel() 24 | { 25 | WeakReferenceMessenger.Default.RegisterAll(this); 26 | } 27 | 28 | [RelayCommand] 29 | public static void NewFile() 30 | { 31 | WeakReferenceMessenger.Default.Send(new FunctionCreateMessage()); 32 | } 33 | 34 | [RelayCommand] 35 | public async Task OpenFileAsync() 36 | { 37 | var response = await Messenger.Send(); 38 | 39 | if (!string.IsNullOrWhiteSpace(response)) 40 | { 41 | WeakReferenceMessenger.Default.Send(new FunctionOpenMessage(response)); 42 | } 43 | } 44 | 45 | [RelayCommand] 46 | public async Task OpenFolderAsync() 47 | { 48 | var response = await Messenger.Send(); 49 | 50 | if (!string.IsNullOrWhiteSpace(response)) 51 | { 52 | WeakReferenceMessenger.Default.Send(new PluginOpenMessage(response!)); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /PromptPlayground/Migrations/20240221112923_GenerationResultStore.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | 4 | #nullable disable 5 | 6 | namespace PromptPlayground.Migrations 7 | { 8 | /// 9 | public partial class GenerationResultStore : Migration 10 | { 11 | /// 12 | protected override void Up(MigrationBuilder migrationBuilder) 13 | { 14 | migrationBuilder.CreateTable( 15 | name: "GenerationResultStores", 16 | columns: table => new 17 | { 18 | Id = table.Column(type: "INTEGER", nullable: false) 19 | .Annotation("Sqlite:Autoincrement", true), 20 | FunctionPath = table.Column(type: "TEXT", nullable: false), 21 | Text = table.Column(type: "TEXT", nullable: false), 22 | RenderedPrompt = table.Column(type: "TEXT", nullable: false), 23 | CreatedAt = table.Column(type: "TEXT", nullable: false), 24 | Elapsed = table.Column(type: "TEXT", nullable: false), 25 | Usage = table.Column(type: "TEXT", nullable: true) 26 | }, 27 | constraints: table => 28 | { 29 | table.PrimaryKey("PK_GenerationResultStores", x => x.Id); 30 | }); 31 | } 32 | 33 | /// 34 | protected override void Down(MigrationBuilder migrationBuilder) 35 | { 36 | migrationBuilder.DropTable( 37 | name: "GenerationResultStores"); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # Prompt Playground 2 | 3 | 一个简易的Semantic Kernel提示词调试工具。 4 | 5 | ## 使用方法 🐣 6 | 7 | ### 下载安装 8 | 9 | 1. 从Release下载最新的安装包。 10 | 2. 安装运行即可。 11 | 12 | ### 首次使用 13 | 14 | 首次使用需要先进入配置设置。 15 | 16 | 点击菜单的配置,即可进入配置界面。 17 | ![Configuration](assets/README/image-5.png) 18 | 19 | 目前模型的选择支持: 20 | 21 | 1. Azure OpenAI ChatCompletion (gpt-35/gpt-4) 22 | 1. OpenAI ChatCompletion 23 | 1. Baidu ERNIE-Bot 24 | 1. Aliyun DashScope 25 | 26 | `生成数量`指最大生成结果数量,默认为3。 27 | 28 | 填写入对应的参数,关闭即可。 29 | 30 | ### 直接使用 31 | 32 | 在主界面的提示词框中直接输入提示词,点击`生成`(Ctrl+G/Ctrl+Enter)即可。 33 | 34 | ### 导入skprompt 35 | 36 | 点击菜单栏的`打开文件`按钮,选择skprompt.txt文件,即可自动导入提示词,同时会导入对于config.json文件。 37 | 38 | 对于没有config.json文件的skprompt,会自动创建一个默认的config.json文件。 39 | 40 | 点击输入框上方的Tab,可以切换到config.json编辑界面。 41 | 42 | ### 保存skprompt 43 | 44 | 对于skprompt.txt或者config.json文件修改后,点击保存(Ctrl+S)按钮,即可保存到对应的文件。 45 | 46 | ## 导入Semantic Plugin 47 | 48 | 1. 点击菜单栏,选择[打开文件夹],选择包含Semantic Functions的文件夹 49 | 1. 展开侧边栏,即可看到当前文件夹下的所有Semantic Functions 50 | 1. 选择对应的 Function ,即可进行编辑运行 51 | 52 | ## 截图 53 | 54 | ![界面截图](assets/README/image-4.png) 55 | 56 | ## 构建 🛠 57 | 58 | 1. 安装 .NET 8 SDK 59 | 2. 下载源码 60 | 3. 运行 `dotnet build` 即可 61 | 62 | ## Roadmap 🚧 63 | 64 | See [Roadmap](https://github.com/xbotter/PromptPlayground/issues/1) 65 | 66 | ## Dependencies 📦 67 | 68 | - [AvaloniaUI](https://github.com/AvaloniaUI/Avalonia) 69 | - [Semi.Avalonia](https://github.com/irihitech/Semi.Avalonia) 70 | - [AvaloniaEdit](https://github.com/AvaloniaUI/AvaloniaEdit) 71 | - [Icons.Avalonia](https://github.com/Projektanker/Icons.Avalonia) 72 | - [Semantic-Kernel](https://github.com/microsoft/semantic-kernel) 73 | - [semantic-kernel-ERNIE-Bot](https://github.com/custouch/semantic-kernel-ERNIE-Bot) 74 | 75 | ## License 📃 76 | 77 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details 78 | -------------------------------------------------------------------------------- /PromptPlayground/ViewModels/ConfigViewModels/LLM/AzureOpenAIConfigViewModel.cs: -------------------------------------------------------------------------------- 1 | using Azure.AI.OpenAI; 2 | using Microsoft; 3 | using Microsoft.SemanticKernel; 4 | using PromptPlayground.Services; 5 | 6 | namespace PromptPlayground.ViewModels.ConfigViewModels.LLM 7 | { 8 | public class AzureOpenAIConfigViewModel : ConfigViewModelBase, ILLMConfigViewModel 9 | { 10 | public AzureOpenAIConfigViewModel(IConfigAttributesProvider provider) : base(provider) 11 | { 12 | RequireAttribute(ConfigAttribute.AzureDeployment); 13 | RequireAttribute(ConfigAttribute.AzureEndpoint); 14 | RequireAttribute(ConfigAttribute.AzureSecret); 15 | } 16 | public override string Name => "Azure OpenAI"; 17 | 18 | public IKernelBuilder CreateKernelBuilder() 19 | { 20 | Requires.NotNullOrWhiteSpace(GetAttribute(ConfigAttribute.AzureDeployment), ConfigAttribute.AzureDeployment); 21 | Requires.NotNullOrWhiteSpace(GetAttribute(ConfigAttribute.AzureEndpoint), ConfigAttribute.AzureEndpoint); 22 | Requires.NotNullOrWhiteSpace(GetAttribute(ConfigAttribute.AzureSecret), ConfigAttribute.AzureSecret); 23 | 24 | return Kernel.CreateBuilder() 25 | .AddAzureOpenAIChatCompletion(GetAttribute(ConfigAttribute.AzureDeployment), 26 | GetAttribute(ConfigAttribute.AzureEndpoint), 27 | GetAttribute(ConfigAttribute.AzureSecret)); 28 | } 29 | 30 | public ResultTokenUsage? GetUsage(FunctionResult result) 31 | { 32 | var usage = result.Metadata?["Usage"] as CompletionsUsage; 33 | if (usage != null) 34 | { 35 | return new ResultTokenUsage(usage.TotalTokens, usage.PromptTokens, usage.CompletionTokens); 36 | } 37 | return null; 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /PromptPlayground/ViewModels/GenerateResult.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | using CommunityToolkit.Mvvm.Input; 3 | using CommunityToolkit.Mvvm.Messaging; 4 | using PromptPlayground.ViewModels; 5 | using System; 6 | using System.Collections.Generic; 7 | 8 | namespace PromptPlayground.Services 9 | { 10 | public partial class AverageResult : ViewModelBase 11 | { 12 | [ObservableProperty] 13 | private bool hasResults = false; 14 | 15 | [ObservableProperty] 16 | private TimeSpan elapsed; 17 | 18 | [ObservableProperty] 19 | private ResultTokenUsage? tokenUsage; 20 | 21 | } 22 | 23 | public partial class GenerateResult : ViewModelBase 24 | { 25 | [ObservableProperty] 26 | private string text = string.Empty; 27 | 28 | [ObservableProperty] 29 | private TimeSpan? elapsed; 30 | 31 | [ObservableProperty] 32 | private string? error; 33 | 34 | [ObservableProperty] 35 | private string? promptRendered; 36 | 37 | [ObservableProperty] 38 | private ResultTokenUsage? tokenUsage; 39 | 40 | public bool HasError => !string.IsNullOrWhiteSpace(Error); 41 | 42 | [RelayCommand] 43 | public void CopyPrompt() 44 | { 45 | if (!string.IsNullOrWhiteSpace(PromptRendered)) 46 | { 47 | WeakReferenceMessenger.Default.Send(new CopyTextMessage(PromptRendered)); 48 | } 49 | } 50 | 51 | [RelayCommand] 52 | public void CopyText() 53 | { 54 | if (!string.IsNullOrWhiteSpace(Text) && !HasError) 55 | { 56 | WeakReferenceMessenger.Default.Send(new CopyTextMessage(Text)); 57 | } 58 | } 59 | 60 | } 61 | 62 | public record ResultTokenUsage(int Total, int Prompt, int Completion); 63 | } 64 | -------------------------------------------------------------------------------- /PromptPlayground/ViewModels/ConfigViewModels/LLM/LLamaSharpConfigViewModel.cs: -------------------------------------------------------------------------------- 1 | using LLama.Common; 2 | using LLama; 3 | using LLamaSharp.SemanticKernel.TextCompletion; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.SemanticKernel; 6 | using Microsoft.SemanticKernel.TextGeneration; 7 | using PromptPlayground.Services; 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Text; 12 | using System.Threading.Tasks; 13 | 14 | namespace PromptPlayground.ViewModels.ConfigViewModels.LLM 15 | { 16 | internal class LlamaSharpConfigViewModel : ConfigViewModelBase, ILLMConfigViewModel 17 | { 18 | private string? _modelPath; 19 | private LLamaWeights? _model; 20 | public LlamaSharpConfigViewModel(IConfigAttributesProvider provider) : base(provider) 21 | { 22 | RequireAttribute(ConfigAttribute.LlamaModelPath); 23 | } 24 | public override string Name => "LlamaSharp"; 25 | 26 | public IKernelBuilder CreateKernelBuilder() 27 | { 28 | var modelPath = this.GetAttribute(ConfigAttribute.LlamaModelPath); 29 | var parameters = new ModelParams(modelPath); 30 | 31 | if (_model is null || _modelPath != modelPath) 32 | { 33 | _model?.Dispose(); 34 | _modelPath = modelPath; 35 | _model = LLamaWeights.LoadFromFile(parameters); 36 | } 37 | 38 | var ex = new StatelessExecutor(_model, parameters); 39 | 40 | var builder = Kernel.CreateBuilder(); 41 | builder.Services.AddKeyedSingleton("local-llama", new LLamaSharpTextCompletion(ex)); 42 | 43 | return builder; 44 | } 45 | 46 | public ResultTokenUsage? GetUsage(FunctionResult resultModel) 47 | { 48 | return null; 49 | } 50 | 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /PromptPlayground.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.6.33815.320 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PromptPlayground", "PromptPlayground\PromptPlayground.csproj", "{0452BA27-AF15-4889-B534-E85EE87E422B}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DBEE43A7-A207-4531-AB49-FE0D366424D6}" 9 | ProjectSection(SolutionItems) = preProject 10 | Directory.Build.props = Directory.Build.props 11 | README.md = README.md 12 | README_CN.md = README_CN.md 13 | EndProjectSection 14 | EndProject 15 | Global 16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 17 | Debug|Any CPU = Debug|Any CPU 18 | Debug|x64 = Debug|x64 19 | Release|Any CPU = Release|Any CPU 20 | Release|x64 = Release|x64 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {0452BA27-AF15-4889-B534-E85EE87E422B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {0452BA27-AF15-4889-B534-E85EE87E422B}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {0452BA27-AF15-4889-B534-E85EE87E422B}.Debug|x64.ActiveCfg = Debug|x64 26 | {0452BA27-AF15-4889-B534-E85EE87E422B}.Debug|x64.Build.0 = Debug|x64 27 | {0452BA27-AF15-4889-B534-E85EE87E422B}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {0452BA27-AF15-4889-B534-E85EE87E422B}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {0452BA27-AF15-4889-B534-E85EE87E422B}.Release|x64.ActiveCfg = Release|x64 30 | {0452BA27-AF15-4889-B534-E85EE87E422B}.Release|x64.Build.0 = Release|x64 31 | EndGlobalSection 32 | GlobalSection(SolutionProperties) = preSolution 33 | HideSolutionNode = FALSE 34 | EndGlobalSection 35 | GlobalSection(ExtensibilityGlobals) = postSolution 36 | SolutionGuid = {DC3B9235-110A-41D4-80FF-1BB0DE75AEDF} 37 | EndGlobalSection 38 | EndGlobal 39 | -------------------------------------------------------------------------------- /PromptPlayground/ViewModels/ConfigViewModels/IConfigViewModel.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.SemanticKernel; 2 | using PromptPlayground.Services; 3 | using PromptPlayground.ViewModels.ConfigViewModels.LLM; 4 | 5 | using System.Collections.Generic; 6 | using System.Collections.ObjectModel; 7 | using System.ComponentModel.DataAnnotations; 8 | using System.Linq; 9 | using System.Reactive; 10 | using System.Reactive.Linq; 11 | 12 | namespace PromptPlayground.ViewModels.ConfigViewModels 13 | { 14 | public interface IConfigViewModel 15 | { 16 | string Name { get; } 17 | public IList SelectAttributes(IList allAttributes); 18 | } 19 | 20 | public abstract class ConfigViewModelBase : ViewModelBase, IConfigViewModel 21 | { 22 | protected readonly IConfigAttributesProvider provider; 23 | private List _requiredAttributes = []; 24 | 25 | public ConfigViewModelBase(IConfigAttributesProvider provider) 26 | { 27 | this.provider = provider; 28 | } 29 | public abstract string Name { get; } 30 | 31 | public IList SelectAttributes(IList allAttributes) 32 | { 33 | return allAttributes.Where(_ => _requiredAttributes.Contains(_.Name)).ToList(); 34 | } 35 | 36 | protected void RequireAttribute(string attribute) 37 | { 38 | if (!_requiredAttributes.Contains(attribute)) 39 | { 40 | _requiredAttributes.Add(attribute); 41 | } 42 | } 43 | protected string GetAttribute(string name) 44 | { 45 | return provider.AllAttributes.FirstOrDefault(_ => _.Name == name)?.Value ?? string.Empty; 46 | } 47 | } 48 | 49 | 50 | public interface IConfigAttributesProvider 51 | { 52 | IList AllAttributes { get; } 53 | ILLMConfigViewModel GetLLM(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /PromptPlayground/ViewModels/ConfigViewModels/LLM/BaiduConfigViewModel.cs: -------------------------------------------------------------------------------- 1 | using ERNIE_Bot.SDK; 2 | using ERNIE_Bot.SDK.Models; 3 | using Microsoft; 4 | using Microsoft.SemanticKernel; 5 | using PromptPlayground.Services; 6 | 7 | namespace PromptPlayground.ViewModels.ConfigViewModels.LLM 8 | { 9 | public class BaiduConfigViewModel : ConfigViewModelBase, ILLMConfigViewModel 10 | { 11 | const string ClientId = ConfigAttribute.BaiduClientId; 12 | const string Secret = ConfigAttribute.BaiduSecret; 13 | 14 | public override string Name => "Baidu"; 15 | 16 | public BaiduConfigViewModel(IConfigAttributesProvider provider) : base(provider) 17 | { 18 | RequireAttribute(ConfigAttribute.BaiduModel); 19 | RequireAttribute(ClientId); 20 | RequireAttribute(Secret); 21 | } 22 | public IKernelBuilder CreateKernelBuilder() 23 | { 24 | return Kernel.CreateBuilder() 25 | .WithERNIEBotChatCompletionService(GetAttribute(ClientId), GetAttribute(Secret), modelEndpoint: ModelEndpoint); 26 | } 27 | public ResultTokenUsage? GetUsage(FunctionResult result) 28 | { 29 | var usage = result.Metadata?["Usage"] as UsageData; 30 | if (usage == null) 31 | { 32 | return null; 33 | } 34 | return new ResultTokenUsage(usage.TotalTokens, usage.PromptTokens, usage.CompletionTokens); 35 | } 36 | 37 | private ModelEndpoint ModelEndpoint => 38 | GetAttribute(ConfigAttribute.BaiduModel) switch 39 | { 40 | "BLOOMZ_7B" => ModelEndpoints.BLOOMZ_7B, 41 | "Ernie-Bot-turbo" => ModelEndpoints.ERNIE_Bot_Turbo, 42 | "Ernie-Bot-4" => ModelEndpoints.ERNIE_Bot_4, 43 | "Ernie-Bot 8k" => ModelEndpoints.ERNIE_Bot_8K, 44 | "Ernie-Bot-speed" => ModelEndpoints.ERNIE_Bot_Speed, 45 | _ => ModelEndpoints.ERNIE_Bot 46 | }; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /PromptPlayground/Behaviors/DocumentTextBindingBehavior.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Xaml.Interactivity; 3 | using AvaloniaEdit; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace PromptPlayground.Behaviors; 11 | 12 | public class DocumentTextBindingBehavior : Behavior 13 | { 14 | private TextEditor? _textEditor; 15 | 16 | public static readonly StyledProperty TextProperty = 17 | AvaloniaProperty.Register(nameof(Text)); 18 | 19 | public string Text 20 | { 21 | get => GetValue(TextProperty); 22 | set => SetValue(TextProperty, value); 23 | } 24 | 25 | protected override void OnAttached() 26 | { 27 | base.OnAttached(); 28 | 29 | if (AssociatedObject is TextEditor textEditor) 30 | { 31 | _textEditor = textEditor; 32 | _textEditor.TextChanged += TextChanged; 33 | this.GetObservable(TextProperty).Subscribe(TextPropertyChanged); 34 | } 35 | } 36 | 37 | protected override void OnDetaching() 38 | { 39 | base.OnDetaching(); 40 | 41 | if (_textEditor != null) 42 | { 43 | _textEditor.TextChanged -= TextChanged; 44 | } 45 | } 46 | 47 | private void TextChanged(object? sender, EventArgs eventArgs) 48 | { 49 | if (_textEditor != null && _textEditor.Document != null) 50 | { 51 | Text = _textEditor.Document.Text; 52 | } 53 | } 54 | 55 | private void TextPropertyChanged(string text) 56 | { 57 | if (_textEditor != null && _textEditor.Document != null && text != null) 58 | { 59 | var caretOffset = _textEditor.CaretOffset; 60 | _textEditor.Document.Text = text; 61 | if (caretOffset <= text.Length) 62 | { 63 | _textEditor.CaretOffset = caretOffset; 64 | } 65 | else 66 | { 67 | _textEditor.CaretOffset = 0; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /PromptPlayground/Services/DbStore.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Design; 3 | using PromptPlayground.Services.Models; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace PromptPlayground.Services 11 | { 12 | internal class DbStore : DbContext 13 | { 14 | static string defaultConnectionString; 15 | public static DbStore NewScoped 16 | { 17 | get 18 | { 19 | var options = new DbContextOptionsBuilder() 20 | .UseSqlite(defaultConnectionString) 21 | .Options; 22 | return new DbStore(options); 23 | } 24 | } 25 | 26 | static DbStore() 27 | { 28 | var path = new ProfileService("store.db").ProfilePath(); 29 | defaultConnectionString = $"Data Source={path};Mode=ReadWriteCreate;Cache=Shared"; 30 | 31 | var db = NewScoped; 32 | db.Database.Migrate(); 33 | } 34 | 35 | public DbStore(DbContextOptions options) : base(options) 36 | { 37 | 38 | } 39 | 40 | public DbSet GenerationResultStores { get; set; } 41 | 42 | protected override void OnModelCreating(ModelBuilder modelBuilder) 43 | { 44 | base.OnModelCreating(modelBuilder); 45 | 46 | modelBuilder.Entity( 47 | entity => 48 | { 49 | entity.OwnsOne(_ => _.Usage, builder => 50 | { 51 | builder.ToJson(); 52 | }); 53 | }); 54 | } 55 | } 56 | 57 | internal class DbStoreContextFactory : IDesignTimeDbContextFactory 58 | { 59 | public DbStore CreateDbContext(string[] args) 60 | { 61 | var options = new DbContextOptionsBuilder() 62 | .UseSqlite("Data Source=design.db") 63 | .Options; 64 | return new DbStore(options); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /PromptPlayground/ViewModels/VariablesViewModel.cs: -------------------------------------------------------------------------------- 1 | using Bogus; 2 | using CommunityToolkit.Mvvm.ComponentModel; 3 | using System.Collections.Generic; 4 | using System.Collections.ObjectModel; 5 | using System.Linq; 6 | 7 | namespace PromptPlayground.ViewModels 8 | { 9 | public class VariablesViewModel : ViewModelBase 10 | { 11 | static readonly Dictionary _variablesCache = []; 12 | 13 | /// 14 | /// only for design time 15 | /// 16 | public VariablesViewModel() 17 | { 18 | Variables = new ObservableCollection([.. new Faker() 19 | .RuleFor(x => x.Name, f => f.Lorem.Word()) 20 | .Generate(5)]); 21 | } 22 | 23 | public VariablesViewModel(List variables) 24 | { 25 | Variables = new ObservableCollection(variables); 26 | 27 | foreach (var var in Variables) 28 | { 29 | if (_variablesCache.TryGetValue(var.Name, out string? value)) 30 | { 31 | var.Value = value; 32 | } 33 | else if (string.IsNullOrWhiteSpace(var.Value) && !string.IsNullOrWhiteSpace(var.DefaultValue)) 34 | { 35 | var.Value = var.DefaultValue; 36 | } 37 | } 38 | } 39 | public bool IsCanceled { get; set; } 40 | public ObservableCollection Variables { get; set; } 41 | 42 | public bool Configured() 43 | { 44 | foreach (var var in Variables) 45 | { 46 | if (var.IsRequired && string.IsNullOrWhiteSpace(var.Value)) 47 | { 48 | return false; 49 | } 50 | if (var.Value != var.DefaultValue) 51 | { 52 | _variablesCache[var.Name] = var.Value; 53 | } 54 | } 55 | return true; 56 | } 57 | } 58 | public class Variable : ObservableObject 59 | { 60 | public string Name { get; set; } = string.Empty; 61 | public string Value { get; set; } = string.Empty; 62 | public string? DefaultValue { get; set; } 63 | public bool IsRequired { get; set; } = false; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /PromptPlayground/Views/VariablesWindows.axaml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 49 | 50 | 30 | 31 | Prompt Playground 36 | 37 | 42 | 43 | 44 | 49 | 50 | 51 | 52 | 53 | 54 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /PromptPlayground/Migrations/DbStoreModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 6 | using PromptPlayground.Services; 7 | 8 | #nullable disable 9 | 10 | namespace PromptPlayground.Migrations 11 | { 12 | [DbContext(typeof(DbStore))] 13 | partial class DbStoreModelSnapshot : ModelSnapshot 14 | { 15 | protected override void BuildModel(ModelBuilder modelBuilder) 16 | { 17 | #pragma warning disable 612, 618 18 | modelBuilder.HasAnnotation("ProductVersion", "8.0.2"); 19 | 20 | modelBuilder.Entity("PromptPlayground.Services.Models.GenerationResultStore", b => 21 | { 22 | b.Property("Id") 23 | .ValueGeneratedOnAdd() 24 | .HasColumnType("INTEGER"); 25 | 26 | b.Property("CreatedAt") 27 | .HasColumnType("TEXT"); 28 | 29 | b.Property("Elapsed") 30 | .HasColumnType("TEXT"); 31 | 32 | b.Property("FunctionPath") 33 | .IsRequired() 34 | .HasColumnType("TEXT"); 35 | 36 | b.Property("RenderedPrompt") 37 | .IsRequired() 38 | .HasColumnType("TEXT"); 39 | 40 | b.Property("Text") 41 | .IsRequired() 42 | .HasColumnType("TEXT"); 43 | 44 | b.HasKey("Id"); 45 | 46 | b.ToTable("GenerationResultStores"); 47 | }); 48 | 49 | modelBuilder.Entity("PromptPlayground.Services.Models.GenerationResultStore", b => 50 | { 51 | b.OwnsOne("PromptPlayground.Services.ResultTokenUsage", "Usage", b1 => 52 | { 53 | b1.Property("GenerationResultStoreId") 54 | .HasColumnType("INTEGER"); 55 | 56 | b1.Property("Completion") 57 | .HasColumnType("INTEGER"); 58 | 59 | b1.Property("Prompt") 60 | .HasColumnType("INTEGER"); 61 | 62 | b1.Property("Total") 63 | .HasColumnType("INTEGER"); 64 | 65 | b1.HasKey("GenerationResultStoreId"); 66 | 67 | b1.ToTable("GenerationResultStores"); 68 | 69 | b1.ToJson("Usage"); 70 | 71 | b1.WithOwner() 72 | .HasForeignKey("GenerationResultStoreId"); 73 | }); 74 | 75 | b.Navigation("Usage"); 76 | }); 77 | #pragma warning restore 612, 618 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /PromptPlayground/Views/MainView.axaml: -------------------------------------------------------------------------------- 1 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /PromptPlayground/Views/PluginsView.axaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 0 13 | 0 14 | 0 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 34 | 41 | 42 | 43 | 44 | 45 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /PromptPlayground/Migrations/20240221112923_GenerationResultStore.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Migrations; 6 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 7 | using PromptPlayground.Services; 8 | 9 | #nullable disable 10 | 11 | namespace PromptPlayground.Migrations 12 | { 13 | [DbContext(typeof(DbStore))] 14 | [Migration("20240221112923_GenerationResultStore")] 15 | partial class GenerationResultStore 16 | { 17 | /// 18 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 19 | { 20 | #pragma warning disable 612, 618 21 | modelBuilder.HasAnnotation("ProductVersion", "8.0.2"); 22 | 23 | modelBuilder.Entity("PromptPlayground.Services.Models.GenerationResultStore", b => 24 | { 25 | b.Property("Id") 26 | .ValueGeneratedOnAdd() 27 | .HasColumnType("INTEGER"); 28 | 29 | b.Property("CreatedAt") 30 | .HasColumnType("TEXT"); 31 | 32 | b.Property("Elapsed") 33 | .HasColumnType("TEXT"); 34 | 35 | b.Property("FunctionPath") 36 | .IsRequired() 37 | .HasColumnType("TEXT"); 38 | 39 | b.Property("RenderedPrompt") 40 | .IsRequired() 41 | .HasColumnType("TEXT"); 42 | 43 | b.Property("Text") 44 | .IsRequired() 45 | .HasColumnType("TEXT"); 46 | 47 | b.HasKey("Id"); 48 | 49 | b.ToTable("GenerationResultStores"); 50 | }); 51 | 52 | modelBuilder.Entity("PromptPlayground.Services.Models.GenerationResultStore", b => 53 | { 54 | b.OwnsOne("PromptPlayground.Services.ResultTokenUsage", "Usage", b1 => 55 | { 56 | b1.Property("GenerationResultStoreId") 57 | .HasColumnType("INTEGER"); 58 | 59 | b1.Property("Completion") 60 | .HasColumnType("INTEGER"); 61 | 62 | b1.Property("Prompt") 63 | .HasColumnType("INTEGER"); 64 | 65 | b1.Property("Total") 66 | .HasColumnType("INTEGER"); 67 | 68 | b1.HasKey("GenerationResultStoreId"); 69 | 70 | b1.ToTable("GenerationResultStores"); 71 | 72 | b1.ToJson("Usage"); 73 | 74 | b1.WithOwner() 75 | .HasForeignKey("GenerationResultStoreId"); 76 | }); 77 | 78 | b.Navigation("Usage"); 79 | }); 80 | #pragma warning restore 612, 618 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /PromptPlayground/PromptPlayground.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | WinExe 4 | net8.0 5 | enable 6 | latest 7 | true 8 | Assets\logo.ico 9 | false 10 | AnyCPU;x64 11 | SKEXP0001;SKEXP0002;SKEXP0004;SKEXP0050 12 | true 13 | app.manifest 14 | true 15 | prompt-playground 16 | 17 | 18 | $(DefineConstants);WINDOWS 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | all 47 | runtime; build; native; contentfiles; analyzers; buildtransitive 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | PluginsView.axaml 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /PromptPlayground/Views/EditorView.axaml: -------------------------------------------------------------------------------- 1 | 14 | 15 | 26 | 27 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 69 | 70 |