mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-31 09:27:03 +01:00
Compare commits
11 Commits
main
...
shawn/APIm
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2128505de8 | ||
|
|
0f4ead7069 | ||
|
|
3749f3e87d | ||
|
|
d341bd2ca6 | ||
|
|
20dcb6fb47 | ||
|
|
72f84f9652 | ||
|
|
64dafff7c4 | ||
|
|
927d190cf2 | ||
|
|
667800eb86 | ||
|
|
35cab47465 | ||
|
|
c1603b189f |
@@ -335,6 +335,7 @@
|
||||
<converters:CountToVisibilityConverter x:Key="CountToVisibilityConverter" />
|
||||
<converters:CountToInvertedVisibilityConverter x:Key="CountToInvertedVisibilityConverter" />
|
||||
<converters:ServiceTypeToIconConverter x:Key="ServiceTypeToIconConverter" />
|
||||
<converters:PasteAIUsageToStringConverter x:Key="PasteAIUsageToStringConverter" />
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid x:Name="PromptBoxGrid" Loaded="Grid_Loaded">
|
||||
@@ -430,12 +431,20 @@
|
||||
Grid.Row="1"
|
||||
MinHeight="104"
|
||||
MaxHeight="320">
|
||||
<TextBlock
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
IsTextSelectionEnabled="True"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind ViewModel.CustomFormatResult, Mode=OneWay}"
|
||||
TextWrapping="Wrap" />
|
||||
<StackPanel>
|
||||
<TextBlock
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
IsTextSelectionEnabled="True"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind ViewModel.CustomFormatResult, Mode=OneWay}"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="{x:Bind ViewModel.HasCustomFormatText, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
<Image
|
||||
HorizontalAlignment="Left"
|
||||
Source="{x:Bind ViewModel.CustomFormatImageResult, Mode=OneWay}"
|
||||
Stretch="Uniform"
|
||||
Visibility="{x:Bind ViewModel.HasCustomFormatImage, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
<Rectangle
|
||||
@@ -602,20 +611,37 @@
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind ServiceType, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
<Border
|
||||
<StackPanel
|
||||
Grid.Column="2"
|
||||
Padding="2,0,2,0"
|
||||
VerticalAlignment="Center"
|
||||
BorderBrush="{ThemeResource ControlStrokeColorSecondary}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="{StaticResource ControlCornerRadius}"
|
||||
Visibility="{x:Bind IsLocalModel, Mode=OneWay}">
|
||||
<TextBlock
|
||||
x:Uid="LocalModelBadge"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
FontSize="10"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
|
||||
</Border>
|
||||
Orientation="Horizontal"
|
||||
Spacing="4">
|
||||
<Border
|
||||
Padding="2,0,2,0"
|
||||
VerticalAlignment="Center"
|
||||
BorderBrush="{ThemeResource ControlStrokeColorSecondary}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="{StaticResource ControlCornerRadius}">
|
||||
<TextBlock
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
FontSize="10"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Text="{x:Bind Usage, Mode=OneWay, Converter={StaticResource PasteAIUsageToStringConverter}}" />
|
||||
</Border>
|
||||
<Border
|
||||
Padding="2,0,2,0"
|
||||
VerticalAlignment="Center"
|
||||
BorderBrush="{ThemeResource ControlStrokeColorSecondary}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="{StaticResource ControlCornerRadius}"
|
||||
Visibility="{x:Bind IsLocalModel, Mode=OneWay}">
|
||||
<TextBlock
|
||||
x:Uid="LocalModelBadge"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
FontSize="10"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
|
||||
</Border>
|
||||
</StackPanel>
|
||||
<!--<Border
|
||||
Grid.Column="2"
|
||||
Padding="2,0,2,0"
|
||||
|
||||
@@ -164,7 +164,7 @@ namespace AdvancedPaste.Controls
|
||||
return;
|
||||
}
|
||||
|
||||
var flyout = FlyoutBase.GetAttachedFlyout(AIProviderButton);
|
||||
var flyout = AIProviderButton.Flyout;
|
||||
|
||||
if (AIProviderListView.SelectedItem is not PasteAIProviderDefinition provider)
|
||||
{
|
||||
@@ -180,7 +180,6 @@ namespace AdvancedPaste.Controls
|
||||
if (ViewModel.SetActiveProviderCommand.CanExecute(provider))
|
||||
{
|
||||
await ViewModel.SetActiveProviderCommand.ExecuteAsync(provider);
|
||||
SyncProviderSelection();
|
||||
}
|
||||
|
||||
flyout?.Hide();
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using AdvancedPaste.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
|
||||
namespace AdvancedPaste.Converters;
|
||||
|
||||
public sealed partial class PasteAIUsageToStringConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
var usage = value switch
|
||||
{
|
||||
string s => PasteAIUsageExtensions.FromConfigString(s),
|
||||
PasteAIUsage u => u,
|
||||
_ => PasteAIUsage.ChatCompletion,
|
||||
};
|
||||
|
||||
return ResourceLoaderInstance.ResourceLoader.GetString($"PasteAIUsage_{usage}");
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,13 @@ internal static class DataPackageHelpers
|
||||
return dataPackage;
|
||||
}
|
||||
|
||||
internal static DataPackage CreateFromImage(RandomAccessStreamReference imageStreamRef)
|
||||
{
|
||||
DataPackage dataPackage = new();
|
||||
dataPackage.SetBitmap(imageStreamRef);
|
||||
return dataPackage;
|
||||
}
|
||||
|
||||
internal static async Task<DataPackage> CreateFromFileAsync(string fileName)
|
||||
{
|
||||
var storageFile = await StorageFile.GetFileFromPathAsync(fileName);
|
||||
|
||||
@@ -168,6 +168,9 @@ namespace AdvancedPaste.Services.CustomActions
|
||||
ModelPath = provider.ModelPath,
|
||||
SystemPrompt = systemPrompt,
|
||||
ModerationEnabled = provider.ModerationEnabled,
|
||||
Usage = provider.UsageKind,
|
||||
ImageWidth = provider.ImageWidth,
|
||||
ImageHeight = provider.ImageHeight,
|
||||
};
|
||||
|
||||
return providerConfig;
|
||||
|
||||
@@ -28,5 +28,11 @@ namespace AdvancedPaste.Services.CustomActions
|
||||
public string SystemPrompt { get; set; }
|
||||
|
||||
public bool ModerationEnabled { get; set; }
|
||||
|
||||
public PasteAIUsage Usage { get; set; }
|
||||
|
||||
public int ImageWidth { get; set; }
|
||||
|
||||
public int ImageHeight { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AdvancedPaste.Helpers;
|
||||
@@ -16,6 +17,7 @@ using Microsoft.SemanticKernel.Connectors.Google;
|
||||
using Microsoft.SemanticKernel.Connectors.MistralAI;
|
||||
using Microsoft.SemanticKernel.Connectors.Ollama;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Microsoft.SemanticKernel.TextToImage;
|
||||
|
||||
namespace AdvancedPaste.Services.CustomActions
|
||||
{
|
||||
@@ -73,6 +75,69 @@ namespace AdvancedPaste.Services.CustomActions
|
||||
|
||||
var executionSettings = CreateExecutionSettings();
|
||||
var kernel = CreateKernel();
|
||||
|
||||
switch (_config.Usage)
|
||||
{
|
||||
case PasteAIUsage.TextToImage:
|
||||
var imageDescription = string.IsNullOrWhiteSpace(prompt) ? inputText : $"{inputText}. {prompt}";
|
||||
return await ProcessTextToImageAsync(kernel, imageDescription, cancellationToken);
|
||||
case PasteAIUsage.ChatCompletion:
|
||||
default:
|
||||
var userMessageContent = $"""
|
||||
User instructions:
|
||||
{prompt}
|
||||
|
||||
Clipboard Content:
|
||||
{inputText}
|
||||
|
||||
Output:
|
||||
""";
|
||||
return await ProcessChatCompletionAsync(kernel, request, userMessageContent, systemPrompt, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string> ProcessTextToImageAsync(Kernel kernel, string userMessageContent, CancellationToken cancellationToken)
|
||||
{
|
||||
#pragma warning disable SKEXP0001
|
||||
var imageService = kernel.GetRequiredService<ITextToImageService>();
|
||||
var width = _config.ImageWidth > 0 ? _config.ImageWidth : 1024;
|
||||
var height = _config.ImageHeight > 0 ? _config.ImageHeight : 1024;
|
||||
var settings = new OpenAITextToImageExecutionSettings
|
||||
{
|
||||
Size = (width, height),
|
||||
};
|
||||
|
||||
var generatedImages = await imageService.GetImageContentsAsync(new TextContent(userMessageContent), settings, cancellationToken: cancellationToken);
|
||||
|
||||
if (generatedImages.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException("No image generated.");
|
||||
}
|
||||
|
||||
var imageContent = generatedImages[0];
|
||||
|
||||
if (imageContent.Data.HasValue)
|
||||
{
|
||||
var base64 = Convert.ToBase64String(imageContent.Data.Value.ToArray());
|
||||
return $"data:{imageContent.MimeType ?? "image/png"};base64,{base64}";
|
||||
}
|
||||
else if (imageContent.Uri != null)
|
||||
{
|
||||
using var client = new HttpClient();
|
||||
var imageBytes = await client.GetByteArrayAsync(imageContent.Uri, cancellationToken);
|
||||
var base64 = Convert.ToBase64String(imageBytes);
|
||||
return $"data:image/png;base64,{base64}";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Generated image contains no data.");
|
||||
}
|
||||
#pragma warning restore SKEXP0001
|
||||
}
|
||||
|
||||
private async Task<string> ProcessChatCompletionAsync(Kernel kernel, PasteAIRequest request, string userMessageContent, string systemPrompt, CancellationToken cancellationToken)
|
||||
{
|
||||
var executionSettings = CreateExecutionSettings();
|
||||
var modelId = _config.Model;
|
||||
|
||||
IChatCompletionService chatService;
|
||||
@@ -95,29 +160,20 @@ namespace AdvancedPaste.Services.CustomActions
|
||||
var chatHistory = new ChatHistory();
|
||||
chatHistory.AddSystemMessage(systemPrompt);
|
||||
|
||||
if (imageBytes != null)
|
||||
if (request.ImageBytes != null)
|
||||
{
|
||||
var collection = new ChatMessageContentItemCollection();
|
||||
if (!string.IsNullOrWhiteSpace(inputText))
|
||||
if (!string.IsNullOrWhiteSpace(request.InputText))
|
||||
{
|
||||
collection.Add(new TextContent($"Clipboard Content:\n{inputText}"));
|
||||
collection.Add(new TextContent($"Clipboard Content:\n{request.InputText}"));
|
||||
}
|
||||
|
||||
collection.Add(new ImageContent(imageBytes, request.ImageMimeType ?? "image/png"));
|
||||
collection.Add(new TextContent($"User instructions:\n{prompt}\n\nOutput:"));
|
||||
collection.Add(new ImageContent(request.ImageBytes, request.ImageMimeType ?? "image/png"));
|
||||
collection.Add(new TextContent($"User instructions:\n{request.Prompt}\n\nOutput:"));
|
||||
chatHistory.AddUserMessage(collection);
|
||||
}
|
||||
else
|
||||
{
|
||||
var userMessageContent = $"""
|
||||
User instructions:
|
||||
{prompt}
|
||||
|
||||
Clipboard Content:
|
||||
{inputText}
|
||||
|
||||
Output:
|
||||
""";
|
||||
chatHistory.AddUserMessage(userMessageContent);
|
||||
}
|
||||
|
||||
@@ -142,11 +198,31 @@ namespace AdvancedPaste.Services.CustomActions
|
||||
switch (_serviceType)
|
||||
{
|
||||
case AIServiceType.OpenAI:
|
||||
kernelBuilder.AddOpenAIChatCompletion(_config.Model, apiKey, serviceId: _config.Model);
|
||||
if (_config.Usage == PasteAIUsage.TextToImage)
|
||||
{
|
||||
#pragma warning disable SKEXP0010
|
||||
kernelBuilder.AddOpenAITextToImage(apiKey, modelId: _config.Model);
|
||||
#pragma warning restore SKEXP0010
|
||||
}
|
||||
else
|
||||
{
|
||||
kernelBuilder.AddOpenAIChatCompletion(_config.Model, apiKey, serviceId: _config.Model);
|
||||
}
|
||||
|
||||
break;
|
||||
case AIServiceType.AzureOpenAI:
|
||||
var deploymentName = string.IsNullOrWhiteSpace(_config.DeploymentName) ? _config.Model : _config.DeploymentName;
|
||||
kernelBuilder.AddAzureOpenAIChatCompletion(deploymentName, RequireEndpoint(endpoint, _serviceType), apiKey, serviceId: _config.Model);
|
||||
if (_config.Usage == PasteAIUsage.TextToImage)
|
||||
{
|
||||
#pragma warning disable SKEXP0010
|
||||
kernelBuilder.AddAzureOpenAITextToImage(deploymentName, RequireEndpoint(endpoint, _serviceType), apiKey);
|
||||
#pragma warning restore SKEXP0010
|
||||
}
|
||||
else
|
||||
{
|
||||
kernelBuilder.AddAzureOpenAIChatCompletion(deploymentName, RequireEndpoint(endpoint, _serviceType), apiKey, serviceId: _config.Model);
|
||||
}
|
||||
|
||||
break;
|
||||
case AIServiceType.Mistral:
|
||||
kernelBuilder.AddMistralChatCompletion(_config.Model, apiKey: apiKey);
|
||||
|
||||
@@ -372,4 +372,10 @@
|
||||
<value>Unable to load Foundry Local model: {0}</value>
|
||||
<comment>{0} is the model identifier. Do not translate {0}.</comment>
|
||||
</data>
|
||||
<data name="PasteAIUsage_ChatCompletion" xml:space="preserve">
|
||||
<value>Chat completion</value>
|
||||
</data>
|
||||
<data name="PasteAIUsage_TextToImage" xml:space="preserve">
|
||||
<value>Text to image</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -7,6 +7,7 @@ using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
@@ -614,8 +615,40 @@ namespace AdvancedPaste.ViewModels
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(HasCustomFormatImage))]
|
||||
[NotifyPropertyChangedFor(nameof(HasCustomFormatText))]
|
||||
[NotifyPropertyChangedFor(nameof(CustomFormatImageResult))]
|
||||
private string _customFormatResult;
|
||||
|
||||
public bool HasCustomFormatImage => CustomFormatResult?.StartsWith("data:image", StringComparison.OrdinalIgnoreCase) ?? false;
|
||||
|
||||
public bool HasCustomFormatText => !HasCustomFormatImage;
|
||||
|
||||
public ImageSource CustomFormatImageResult
|
||||
{
|
||||
get
|
||||
{
|
||||
if (HasCustomFormatImage && !string.IsNullOrEmpty(CustomFormatResult))
|
||||
{
|
||||
try
|
||||
{
|
||||
var base64Data = CustomFormatResult.Split(',')[1];
|
||||
var bytes = Convert.FromBase64String(base64Data);
|
||||
var stream = new System.IO.MemoryStream(bytes);
|
||||
var image = new BitmapImage();
|
||||
image.SetSource(stream.AsRandomAccessStream());
|
||||
return image;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Failed to create image source from data URI", ex);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public async Task PasteCustomAsync()
|
||||
{
|
||||
@@ -623,7 +656,25 @@ namespace AdvancedPaste.ViewModels
|
||||
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
{
|
||||
await CopyPasteAndHideAsync(DataPackageHelpers.CreateFromText(text));
|
||||
if (text.StartsWith("data:image", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
try
|
||||
{
|
||||
var base64Data = text.Split(',')[1];
|
||||
var bytes = Convert.FromBase64String(base64Data);
|
||||
var stream = new System.IO.MemoryStream(bytes);
|
||||
var dataPackage = DataPackageHelpers.CreateFromImage(Windows.Storage.Streams.RandomAccessStreamReference.CreateFromStream(stream.AsRandomAccessStream()));
|
||||
await CopyPasteAndHideAsync(dataPackage);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Failed to paste image from data URI", ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await CopyPasteAndHideAsync(DataPackageHelpers.CreateFromText(text));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -895,11 +946,6 @@ namespace AdvancedPaste.ViewModels
|
||||
Logger.LogError("Failed to activate AI provider", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateAIProviderActiveFlags();
|
||||
OnPropertyChanged(nameof(AIProviders));
|
||||
NotifyActiveProviderChanged();
|
||||
EnqueueRefreshPasteFormats();
|
||||
}
|
||||
|
||||
public async Task CancelPasteActionAsync()
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
private string _id = Guid.NewGuid().ToString("N");
|
||||
private string _serviceType = "OpenAI";
|
||||
private string _usage = "ChatCompletion";
|
||||
private string _modelName = string.Empty;
|
||||
private string _endpointUrl = string.Empty;
|
||||
private string _apiVersion = string.Empty;
|
||||
@@ -27,6 +28,8 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
private bool _isActive;
|
||||
private bool _enableAdvancedAI;
|
||||
private bool _isLocalModel;
|
||||
private int _imageWidth = 1024;
|
||||
private int _imageHeight = 1024;
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
@@ -50,6 +53,20 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
}
|
||||
}
|
||||
|
||||
[JsonPropertyName("usage")]
|
||||
public string Usage
|
||||
{
|
||||
get => _usage;
|
||||
set => SetProperty(ref _usage, string.IsNullOrWhiteSpace(value) ? "ChatCompletion" : value); // TODO: Localization support
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public PasteAIUsage UsageKind
|
||||
{
|
||||
get => PasteAIUsageExtensions.FromConfigString(Usage);
|
||||
set => Usage = value.ToConfigString();
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public AIServiceType ServiceTypeKind
|
||||
{
|
||||
@@ -126,6 +143,20 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
set => SetProperty(ref _isLocalModel, value);
|
||||
}
|
||||
|
||||
[JsonPropertyName("image-width")]
|
||||
public int ImageWidth
|
||||
{
|
||||
get => _imageWidth;
|
||||
set => SetProperty(ref _imageWidth, value);
|
||||
}
|
||||
|
||||
[JsonPropertyName("image-height")]
|
||||
public int ImageHeight
|
||||
{
|
||||
get => _imageHeight;
|
||||
set => SetProperty(ref _imageHeight, value);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsActive
|
||||
{
|
||||
@@ -142,6 +173,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
Id = Id,
|
||||
ServiceType = ServiceType,
|
||||
Usage = Usage,
|
||||
ModelName = ModelName,
|
||||
EndpointUrl = EndpointUrl,
|
||||
ApiVersion = ApiVersion,
|
||||
@@ -151,6 +183,8 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
ModerationEnabled = ModerationEnabled,
|
||||
EnableAdvancedAI = EnableAdvancedAI,
|
||||
IsLocalModel = IsLocalModel,
|
||||
ImageWidth = ImageWidth,
|
||||
ImageHeight = ImageHeight,
|
||||
IsActive = IsActive,
|
||||
};
|
||||
}
|
||||
|
||||
12
src/settings-ui/Settings.UI.Library/PasteAIUsage.cs
Normal file
12
src/settings-ui/Settings.UI.Library/PasteAIUsage.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public enum PasteAIUsage
|
||||
{
|
||||
ChatCompletion,
|
||||
TextToImage,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public static class PasteAIUsageExtensions
|
||||
{
|
||||
public static string ToConfigString(this PasteAIUsage usage)
|
||||
{
|
||||
return usage switch
|
||||
{
|
||||
PasteAIUsage.ChatCompletion => "ChatCompletion",
|
||||
PasteAIUsage.TextToImage => "TextToImage",
|
||||
_ => "ChatCompletion",
|
||||
};
|
||||
}
|
||||
|
||||
public static PasteAIUsage FromConfigString(string usage)
|
||||
{
|
||||
return usage switch
|
||||
{
|
||||
"TextToImage" => PasteAIUsage.TextToImage,
|
||||
_ => PasteAIUsage.ChatCompletion,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using Microsoft.PowerToys.Settings.UI.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Converters;
|
||||
|
||||
public sealed partial class PasteAIUsageToStringConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
var usage = value switch
|
||||
{
|
||||
string s => PasteAIUsageExtensions.FromConfigString(s),
|
||||
PasteAIUsage u => u,
|
||||
_ => PasteAIUsage.ChatCompletion,
|
||||
};
|
||||
|
||||
return ResourceLoaderInstance.ResourceLoader.GetString($"PasteAIUsage_{usage}_Label");
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,7 @@
|
||||
</Style>
|
||||
|
||||
<converters:ServiceTypeToIconConverter x:Key="ServiceTypeToIconConverter" />
|
||||
<converters:PasteAIUsageToStringConverter x:Key="PasteAIUsageToStringConverter" />
|
||||
<DataTemplate x:Key="AdditionalActionTemplate" x:DataType="models:AdvancedPasteAdditionalAction">
|
||||
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
<controls:ShortcutControl
|
||||
@@ -118,6 +119,18 @@
|
||||
Header="{x:Bind ModelName, Mode=OneWay}"
|
||||
HeaderIcon="{x:Bind ServiceType, Mode=OneWay, Converter={StaticResource ServiceTypeToIconConverter}}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<Border
|
||||
Padding="8,4"
|
||||
VerticalAlignment="Center"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4">
|
||||
<TextBlock
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Text="{x:Bind Usage, Mode=OneWay, Converter={StaticResource PasteAIUsageToStringConverter}}" />
|
||||
</Border>
|
||||
<Button
|
||||
Padding="8"
|
||||
Background="Transparent"
|
||||
@@ -493,6 +506,39 @@
|
||||
Margin="0,8,0,48"
|
||||
Orientation="Vertical"
|
||||
Spacing="16">
|
||||
<ComboBox
|
||||
x:Name="PasteAIUsageComboBox"
|
||||
x:Uid="AdvancedPaste_Usage"
|
||||
MinWidth="200"
|
||||
HorizontalAlignment="Stretch"
|
||||
Header="Usage"
|
||||
SelectedValue="{x:Bind ViewModel.PasteAIProviderDraft.Usage, Mode=TwoWay}"
|
||||
SelectedValuePath="Tag"
|
||||
SelectionChanged="PasteAIUsageComboBox_SelectionChanged"
|
||||
Visibility="{x:Bind GetUsageVisibility(ViewModel.PasteAIProviderDraft.ServiceType), Mode=OneWay}">
|
||||
<ComboBoxItem x:Uid="PasteAIUsage_ChatCompletion" Tag="ChatCompletion" />
|
||||
<ComboBoxItem x:Uid="PasteAIUsage_TextToImage" Tag="TextToImage" />
|
||||
</ComboBox>
|
||||
<StackPanel
|
||||
x:Name="PasteAIImageResolutionPanel"
|
||||
Orientation="Horizontal"
|
||||
Spacing="8"
|
||||
Visibility="{x:Bind GetImageResolutionVisibility(ViewModel.PasteAIProviderDraft.Usage), Mode=OneWay}">
|
||||
<TextBox
|
||||
x:Name="PasteAIImageWidthTextBox"
|
||||
x:Uid="AdvancedPaste_ImgOutputWidth"
|
||||
MinWidth="96"
|
||||
Text="{x:Bind ViewModel.PasteAIProviderDraft.ImageWidth, Mode=TwoWay}" />
|
||||
<TextBlock
|
||||
Margin="0,0,0,8"
|
||||
VerticalAlignment="Bottom"
|
||||
Text="x" />
|
||||
<TextBox
|
||||
x:Name="PasteAIImageHeightTextBox"
|
||||
x:Uid="AdvancedPaste_ImgOutputHeight"
|
||||
MinWidth="96"
|
||||
Text="{x:Bind ViewModel.PasteAIProviderDraft.ImageHeight, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
<TextBox
|
||||
x:Name="PasteAIModelNameTextBox"
|
||||
x:Uid="AdvancedPaste_ModelName"
|
||||
|
||||
@@ -303,6 +303,45 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
System.Diagnostics.Debug.WriteLine($"{configType} API key saved successfully");
|
||||
}
|
||||
|
||||
public Visibility GetUsageVisibility(string serviceType)
|
||||
{
|
||||
if (string.IsNullOrEmpty(serviceType))
|
||||
{
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
|
||||
return (serviceType.Equals("OpenAI", StringComparison.OrdinalIgnoreCase) ||
|
||||
serviceType.Equals("AzureOpenAI", StringComparison.OrdinalIgnoreCase))
|
||||
? Visibility.Visible
|
||||
: Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public Visibility GetImageResolutionVisibility(string usage)
|
||||
{
|
||||
return string.Equals(usage, "TextToImage", StringComparison.OrdinalIgnoreCase)
|
||||
? Visibility.Visible
|
||||
: Visibility.Collapsed;
|
||||
}
|
||||
|
||||
private void PasteAIUsageComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (ViewModel?.PasteAIProviderDraft == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var comboBox = (ComboBox)sender;
|
||||
if (comboBox.SelectedValue is string usage && usage == "TextToImage")
|
||||
{
|
||||
ViewModel.PasteAIProviderDraft.EnableAdvancedAI = false;
|
||||
PasteAIEnableAdvancedAICheckBox.IsEnabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
PasteAIEnableAdvancedAICheckBox.IsEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePasteAIUIVisibility()
|
||||
{
|
||||
var draft = ViewModel?.PasteAIProviderDraft;
|
||||
@@ -345,6 +384,17 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
PasteAIEnableAdvancedAICheckBox.Visibility = showAdvancedAI ? Visibility.Visible : Visibility.Collapsed;
|
||||
PasteAIApiKeyPasswordBox.Visibility = requiresApiKey ? Visibility.Visible : Visibility.Collapsed;
|
||||
PasteAIModelNameTextBox.Visibility = isFoundryLocal ? Visibility.Collapsed : Visibility.Visible;
|
||||
PasteAIImageResolutionPanel.Visibility = GetImageResolutionVisibility(draft.Usage);
|
||||
|
||||
if (draft.Usage == "TextToImage")
|
||||
{
|
||||
draft.EnableAdvancedAI = false;
|
||||
PasteAIEnableAdvancedAICheckBox.IsEnabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
PasteAIEnableAdvancedAICheckBox.IsEnabled = true;
|
||||
}
|
||||
|
||||
if (requiresApiKey)
|
||||
{
|
||||
|
||||
@@ -5769,4 +5769,22 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
|
||||
<data name="LightSwitch_FollowNightLightCardMessage.Text" xml:space="preserve">
|
||||
<value>Following Night Light settings.</value>
|
||||
</data>
|
||||
<data name="PasteAIUsage_ChatCompletion_Label" xml:space="preserve">
|
||||
<value>Chat completion</value>
|
||||
</data>
|
||||
<data name="PasteAIUsage_TextToImage_Label" xml:space="preserve">
|
||||
<value>Text to image</value>
|
||||
</data>
|
||||
<data name="PasteAIUsage_ChatCompletion.Content" xml:space="preserve">
|
||||
<value>Chat completion</value>
|
||||
</data>
|
||||
<data name="PasteAIUsage_TextToImage.Content" xml:space="preserve">
|
||||
<value>Text to image</value>
|
||||
</data>
|
||||
<data name="AdvancedPaste_ImgOutputWidth.Header" xml:space="preserve">
|
||||
<value>Image output width</value>
|
||||
</data>
|
||||
<data name="AdvancedPaste_ImgOutputHeight.Header" xml:space="preserve">
|
||||
<value>Image output height</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -949,6 +949,9 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
target.ModerationEnabled = source.ModerationEnabled;
|
||||
target.EnableAdvancedAI = source.EnableAdvancedAI;
|
||||
target.IsLocalModel = source.IsLocalModel;
|
||||
target.Usage = source.Usage;
|
||||
target.ImageWidth = source.ImageWidth;
|
||||
target.ImageHeight = source.ImageHeight;
|
||||
}
|
||||
|
||||
private void RemovePasteAICredentials(string providerId, string serviceType)
|
||||
|
||||
Reference in New Issue
Block a user