From 054f0967dd0071d688f99bad61f9aa05b54832b4 Mon Sep 17 00:00:00 2001 From: Nikola Metulev <711864+nmetulev@users.noreply.github.com> Date: Mon, 10 Feb 2025 21:33:08 -0800 Subject: [PATCH 01/13] testing wcr api compatibility --- AIDevGallery/Models/ModelCompatibility.cs | 19 ++++++++- AIDevGallery/Utils/WcrCompatibilityChecker.cs | 41 +++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 AIDevGallery/Utils/WcrCompatibilityChecker.cs diff --git a/AIDevGallery/Models/ModelCompatibility.cs b/AIDevGallery/Models/ModelCompatibility.cs index 3705740d..cdd15f8d 100644 --- a/AIDevGallery/Models/ModelCompatibility.cs +++ b/AIDevGallery/Models/ModelCompatibility.cs @@ -3,6 +3,7 @@ using AIDevGallery.Utils; using System; +using Utils; namespace AIDevGallery.Models; @@ -20,9 +21,23 @@ private ModelCompatibility() public static ModelCompatibility GetModelCompatibility(ModelDetails modelDetails) { string description = string.Empty; - ModelCompatibilityState compatibility; - if (modelDetails.HardwareAccelerators.Contains(HardwareAccelerator.CPU) || + + // check if WCR API + if (modelDetails.Url.StartsWith("file://", StringComparison.InvariantCultureIgnoreCase)) + { + var apiKey = modelDetails.Url.Substring(7); + if (WcrCompatibilityChecker.GetApiAvailability(apiKey) != WcrApiAvailability.NotSupported) + { + compatibility = ModelCompatibilityState.Compatible; + } + else + { + compatibility = ModelCompatibilityState.NotCompatible; + description = "This Windows Copilot Runtime API requires a Copilot+ PC and a Windows 11 Insider Preview Build 26120.3073 (Dev and Beta Channels)."; + } + } + else if (modelDetails.HardwareAccelerators.Contains(HardwareAccelerator.CPU) || (modelDetails.HardwareAccelerators.Contains(HardwareAccelerator.QNN) && DeviceUtils.IsArm64())) { compatibility = ModelCompatibilityState.Compatible; diff --git a/AIDevGallery/Utils/WcrCompatibilityChecker.cs b/AIDevGallery/Utils/WcrCompatibilityChecker.cs new file mode 100644 index 00000000..b20c91b9 --- /dev/null +++ b/AIDevGallery/Utils/WcrCompatibilityChecker.cs @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Windows.AI.Generative; +using System; +using System.Collections.Generic; + +namespace Utils; +internal static class WcrCompatibilityChecker +{ + private static readonly Dictionary> CompatibilityCheckers = new Dictionary> + { + { + "phi-silica", LanguageModel.IsAvailable + } + }; + + public static WcrApiAvailability GetApiAvailability(string key) + { + if (!CompatibilityCheckers.TryGetValue(key, out Func? isAvailable)) + { + return WcrApiAvailability.NotSupported; + } + + try + { + return isAvailable() ? WcrApiAvailability.Available : WcrApiAvailability.NotAvailable; + } + catch + { + return WcrApiAvailability.NotSupported; + } + } +} + +internal enum WcrApiAvailability +{ + Available, + NotAvailable, + NotSupported +} \ No newline at end of file From 55c85e531da551bda1860f02c1ab1d30bc17f5b2 Mon Sep 17 00:00:00 2001 From: Nikola Metulev <711864+nmetulev@users.noreply.github.com> Date: Mon, 10 Feb 2025 21:51:41 -0800 Subject: [PATCH 02/13] improve api checker to use types instead of strings --- AIDevGallery/Models/ModelCompatibility.cs | 4 +++- AIDevGallery/Utils/WcrCompatibilityChecker.cs | 9 +++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/AIDevGallery/Models/ModelCompatibility.cs b/AIDevGallery/Models/ModelCompatibility.cs index cdd15f8d..a0adce42 100644 --- a/AIDevGallery/Models/ModelCompatibility.cs +++ b/AIDevGallery/Models/ModelCompatibility.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using AIDevGallery.Samples; using AIDevGallery.Utils; using System; using Utils; @@ -27,7 +28,8 @@ public static ModelCompatibility GetModelCompatibility(ModelDetails modelDetails if (modelDetails.Url.StartsWith("file://", StringComparison.InvariantCultureIgnoreCase)) { var apiKey = modelDetails.Url.Substring(7); - if (WcrCompatibilityChecker.GetApiAvailability(apiKey) != WcrApiAvailability.NotSupported) + + if (Enum.TryParse(apiKey, out ModelType apiType) && WcrCompatibilityChecker.GetApiAvailability(apiType) != WcrApiAvailability.NotSupported) { compatibility = ModelCompatibilityState.Compatible; } diff --git a/AIDevGallery/Utils/WcrCompatibilityChecker.cs b/AIDevGallery/Utils/WcrCompatibilityChecker.cs index b20c91b9..8a6ed6e7 100644 --- a/AIDevGallery/Utils/WcrCompatibilityChecker.cs +++ b/AIDevGallery/Utils/WcrCompatibilityChecker.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using AIDevGallery.Models; using Microsoft.Windows.AI.Generative; using System; using System.Collections.Generic; @@ -8,16 +9,16 @@ namespace Utils; internal static class WcrCompatibilityChecker { - private static readonly Dictionary> CompatibilityCheckers = new Dictionary> + private static readonly Dictionary> CompatibilityCheckers = new Dictionary> { { - "phi-silica", LanguageModel.IsAvailable + ModelType.PhiSilica, LanguageModel.IsAvailable } }; - public static WcrApiAvailability GetApiAvailability(string key) + public static WcrApiAvailability GetApiAvailability(ModelType type) { - if (!CompatibilityCheckers.TryGetValue(key, out Func? isAvailable)) + if (!CompatibilityCheckers.TryGetValue(type, out Func? isAvailable)) { return WcrApiAvailability.NotSupported; } From 4a583ab5469dc7f1e23a8ebbd579bc347f22af84 Mon Sep 17 00:00:00 2001 From: Nikola Metulev <711864+nmetulev@users.noreply.github.com> Date: Mon, 10 Feb 2025 21:59:00 -0800 Subject: [PATCH 03/13] added all api compatibility checker --- AIDevGallery/Utils/WcrCompatibilityChecker.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/AIDevGallery/Utils/WcrCompatibilityChecker.cs b/AIDevGallery/Utils/WcrCompatibilityChecker.cs index 8a6ed6e7..ef9793df 100644 --- a/AIDevGallery/Utils/WcrCompatibilityChecker.cs +++ b/AIDevGallery/Utils/WcrCompatibilityChecker.cs @@ -2,7 +2,9 @@ // Licensed under the MIT License. using AIDevGallery.Models; +using Microsoft.Graphics.Imaging; using Microsoft.Windows.AI.Generative; +using Microsoft.Windows.Vision; using System; using System.Collections.Generic; @@ -13,6 +15,18 @@ internal static class WcrCompatibilityChecker { { ModelType.PhiSilica, LanguageModel.IsAvailable + }, + { + ModelType.TextRecognitionOCR, TextRecognizer.IsAvailable + }, + { + ModelType.ImageScaler, ImageScaler.IsAvailable + }, + { + ModelType.BackgroundRemover, ImageObjectExtractor.IsAvailable + }, + { + ModelType.ImageDescription, ImageDescriptionGenerator.IsAvailable } }; From 008a51b13c6dbc9f1b21df320eb97611ddcf8e7b Mon Sep 17 00:00:00 2001 From: Nikola Metulev <711864+nmetulev@users.noreply.github.com> Date: Mon, 10 Feb 2025 22:11:55 -0800 Subject: [PATCH 04/13] added new hardware accelerator and added wcr api filter option --- AIDevGallery.SourceGenerator/Models/HardwareAccelerator.cs | 3 ++- AIDevGallery/Helpers/ModelDetailsHelper.cs | 2 +- AIDevGallery/Models/Samples.cs | 3 ++- AIDevGallery/Pages/ScenarioSelectionPage.xaml.cs | 3 +-- .../ProjectGenerator/Template/Utils/HardwareAccelerator.cs | 3 ++- AIDevGallery/Utils/AppUtils.cs | 4 ++++ 6 files changed, 12 insertions(+), 6 deletions(-) diff --git a/AIDevGallery.SourceGenerator/Models/HardwareAccelerator.cs b/AIDevGallery.SourceGenerator/Models/HardwareAccelerator.cs index 64da1c35..2d3e57f7 100644 --- a/AIDevGallery.SourceGenerator/Models/HardwareAccelerator.cs +++ b/AIDevGallery.SourceGenerator/Models/HardwareAccelerator.cs @@ -10,5 +10,6 @@ internal enum HardwareAccelerator { CPU, DML, - QNN + QNN, + WCRAPI } \ No newline at end of file diff --git a/AIDevGallery/Helpers/ModelDetailsHelper.cs b/AIDevGallery/Helpers/ModelDetailsHelper.cs index f5a63fa8..1220b657 100644 --- a/AIDevGallery/Helpers/ModelDetailsHelper.cs +++ b/AIDevGallery/Helpers/ModelDetailsHelper.cs @@ -34,7 +34,7 @@ public static ModelDetails GetModelDetailsFromApiDefinition(ModelType modelType, Id = apiDefinition.Id, Icon = apiDefinition.Icon, Name = apiDefinition.Name, - HardwareAccelerators = [HardwareAccelerator.QNN], + HardwareAccelerators = [HardwareAccelerator.WCRAPI], IsUserAdded = false, SupportedOnQualcomm = true, ReadmeUrl = apiDefinition.ReadmeUrl, diff --git a/AIDevGallery/Models/Samples.cs b/AIDevGallery/Models/Samples.cs index 57b16079..e6f5d6cd 100644 --- a/AIDevGallery/Models/Samples.cs +++ b/AIDevGallery/Models/Samples.cs @@ -156,7 +156,8 @@ internal enum HardwareAccelerator { CPU, DML, - QNN + QNN, + WCRAPI } #pragma warning restore SA1402 // File may only contain a single type diff --git a/AIDevGallery/Pages/ScenarioSelectionPage.xaml.cs b/AIDevGallery/Pages/ScenarioSelectionPage.xaml.cs index 88639965..de8ef348 100644 --- a/AIDevGallery/Pages/ScenarioSelectionPage.xaml.cs +++ b/AIDevGallery/Pages/ScenarioSelectionPage.xaml.cs @@ -21,8 +21,7 @@ internal record FilterRecord(string? Tag, string Text); new(null, "All" ), new("npu", "NPU" ), new("gpu", "GPU" ), - - // new("wcr-api", "WCR API" ) + new("wcr-api", "WCR API" ) ]; private static LastInternalNavigation? lastInternalNavigation; diff --git a/AIDevGallery/ProjectGenerator/Template/Utils/HardwareAccelerator.cs b/AIDevGallery/ProjectGenerator/Template/Utils/HardwareAccelerator.cs index e6a08d3c..2b64b73e 100644 --- a/AIDevGallery/ProjectGenerator/Template/Utils/HardwareAccelerator.cs +++ b/AIDevGallery/ProjectGenerator/Template/Utils/HardwareAccelerator.cs @@ -4,5 +4,6 @@ internal enum HardwareAccelerator { CPU, DML, - QNN + QNN, + WCRAPI } \ No newline at end of file diff --git a/AIDevGallery/Utils/AppUtils.cs b/AIDevGallery/Utils/AppUtils.cs index c7931012..8ba06079 100644 --- a/AIDevGallery/Utils/AppUtils.cs +++ b/AIDevGallery/Utils/AppUtils.cs @@ -85,6 +85,8 @@ public static string GetHardwareAcceleratorString(HardwareAccelerator hardwareAc return "GPU"; case HardwareAccelerator.QNN: return "NPU"; + case HardwareAccelerator.WCRAPI: + return "WCR"; default: return hardwareAccelerator.ToString(); } @@ -101,6 +103,8 @@ public static string GetHardwareAcceleratorDescription(HardwareAccelerator hardw return "This model will run on supported GPUs with DirectML"; case HardwareAccelerator.QNN: return "This model will run on Qualcomm NPUs"; + case HardwareAccelerator.WCRAPI: + return "The model used by this Windows Copilot Runtime API will run on NPU"; } } From d06526ebc3c7898e1322ac32144b791e9af79561 Mon Sep 17 00:00:00 2001 From: Nikola Metulev <711864+nmetulev@users.noreply.github.com> Date: Mon, 10 Feb 2025 22:19:58 -0800 Subject: [PATCH 05/13] sort wcr apis first --- .../Controls/ModelSelectionControl.xaml.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/AIDevGallery/Controls/ModelSelectionControl.xaml.cs b/AIDevGallery/Controls/ModelSelectionControl.xaml.cs index d7be0b92..684cee0f 100644 --- a/AIDevGallery/Controls/ModelSelectionControl.xaml.cs +++ b/AIDevGallery/Controls/ModelSelectionControl.xaml.cs @@ -265,9 +265,24 @@ private void PopulateModelDetailsLists() } } + SortModels(AvailableModels); + SortModels(DownloadableModels); + SortModels(UnavailableModels); + SetHeaderVisibilityStates(); } + private void SortModels(ObservableCollection models) + where T : IModelView + { + var sortedModels = models.OrderByDescending(m => m.ModelDetails.HardwareAccelerators.Contains(HardwareAccelerator.WCRAPI)).ToList(); + models.Clear(); + foreach (var model in sortedModels) + { + models.Add(model); + } + } + private void OpenModelFolder_Click(object sender, RoutedEventArgs e) { if (sender is MenuFlyoutItem btn && btn.Tag is ModelDetails details) From 2302522a5ec60fece9af11d9ad852d0b22b7e4b7 Mon Sep 17 00:00:00 2001 From: Nikola Metulev <711864+nmetulev@users.noreply.github.com> Date: Tue, 11 Feb 2025 21:11:32 -0800 Subject: [PATCH 06/13] minor cleanup --- AIDevGallery/Models/ModelCompatibility.cs | 2 -- AIDevGallery/Utils/WcrCompatibilityChecker.cs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/AIDevGallery/Models/ModelCompatibility.cs b/AIDevGallery/Models/ModelCompatibility.cs index a0adce42..9e0477c4 100644 --- a/AIDevGallery/Models/ModelCompatibility.cs +++ b/AIDevGallery/Models/ModelCompatibility.cs @@ -1,10 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using AIDevGallery.Samples; using AIDevGallery.Utils; using System; -using Utils; namespace AIDevGallery.Models; diff --git a/AIDevGallery/Utils/WcrCompatibilityChecker.cs b/AIDevGallery/Utils/WcrCompatibilityChecker.cs index ef9793df..da30ccf7 100644 --- a/AIDevGallery/Utils/WcrCompatibilityChecker.cs +++ b/AIDevGallery/Utils/WcrCompatibilityChecker.cs @@ -8,7 +8,7 @@ using System; using System.Collections.Generic; -namespace Utils; +namespace AIDevGallery.Utils; internal static class WcrCompatibilityChecker { private static readonly Dictionary> CompatibilityCheckers = new Dictionary> From ccc75dfaa52abc2da039251c878a8f294a33b8fe Mon Sep 17 00:00:00 2001 From: Nikola Metulev <711864+nmetulev@users.noreply.github.com> Date: Tue, 11 Feb 2025 23:08:50 -0800 Subject: [PATCH 07/13] Adding WcrModelDownloader --- .../{ => WcrApis}/PhiSilicaClient.cs | 0 .../WcrApis/WcrModelDownloader.xaml | 67 +++++++ .../WcrApis/WcrModelDownloader.xaml.cs | 149 ++++++++++++++++ .../Samples/WCRAPIs/BackgroundRemover.xaml | 167 +++++++++--------- .../Samples/WCRAPIs/BackgroundRemover.xaml.cs | 25 ++- 5 files changed, 319 insertions(+), 89 deletions(-) rename AIDevGallery/Samples/SharedCode/{ => WcrApis}/PhiSilicaClient.cs (100%) create mode 100644 AIDevGallery/Samples/SharedCode/WcrApis/WcrModelDownloader.xaml create mode 100644 AIDevGallery/Samples/SharedCode/WcrApis/WcrModelDownloader.xaml.cs diff --git a/AIDevGallery/Samples/SharedCode/PhiSilicaClient.cs b/AIDevGallery/Samples/SharedCode/WcrApis/PhiSilicaClient.cs similarity index 100% rename from AIDevGallery/Samples/SharedCode/PhiSilicaClient.cs rename to AIDevGallery/Samples/SharedCode/WcrApis/PhiSilicaClient.cs diff --git a/AIDevGallery/Samples/SharedCode/WcrApis/WcrModelDownloader.xaml b/AIDevGallery/Samples/SharedCode/WcrApis/WcrModelDownloader.xaml new file mode 100644 index 00000000..85bfd535 --- /dev/null +++ b/AIDevGallery/Samples/SharedCode/WcrApis/WcrModelDownloader.xaml @@ -0,0 +1,67 @@ + + + + + + + This Windows Copilot Runtime API requires a model download. Click "Make Available" to request the model download via Windows Update. + + + + + + + + + Windows Update + + + + + + + + + + + + diff --git a/AIDevGallery/Samples/SharedCode/WcrApis/WcrModelDownloader.xaml.cs b/AIDevGallery/Samples/SharedCode/WcrApis/WcrModelDownloader.xaml.cs new file mode 100644 index 00000000..37ec0c33 --- /dev/null +++ b/AIDevGallery/Samples/SharedCode/WcrApis/WcrModelDownloader.xaml.cs @@ -0,0 +1,149 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.Windows.Management.Deployment; +using System; +using System.Threading.Tasks; +using Windows.Foundation; +using Windows.System; + +namespace AIDevGallery.Samples.TempSharedCode; +internal sealed partial class WcrModelDownloader : UserControl +{ + public event EventHandler? DownloadClicked; + + public int DownloadProgress + { + get { return (int)GetValue(DownloadProgressProperty); } + set { SetValue(DownloadProgressProperty, value); } + } + + // Using a DependencyProperty as the backing store for DownloadProgress. This enables animation, styling, binding, etc... + public static readonly DependencyProperty DownloadProgressProperty = + DependencyProperty.Register("DownloadProgress", typeof(int), typeof(WcrModelDownloader), new PropertyMetadata(0)); + + public string ErrorMessage + { + get { return (string)GetValue(ErrorMessageProperty); } + set { SetValue(ErrorMessageProperty, value); } + } + + // Using a DependencyProperty as the backing store for ErrorMessage. This enables animation, styling, binding, etc... + public static readonly DependencyProperty ErrorMessageProperty = + DependencyProperty.Register("ErrorMessage", typeof(string), typeof(WcrModelDownloader), new PropertyMetadata("Error downloading model")); + + public WcrApiDownloadState State + { + get { return (WcrApiDownloadState)GetValue(StateProperty); } + set { SetValue(StateProperty, value); } + } + + // Using a DependencyProperty as the backing store for State. This enables animation, styling, binding, etc... + public static readonly DependencyProperty StateProperty = + DependencyProperty.Register("State", typeof(WcrApiDownloadState), typeof(WcrModelDownloader), new PropertyMetadata(WcrApiDownloadState.NotStarted, OnStateChanged)); + + private static void OnStateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((WcrModelDownloader)d).UpdateState((WcrApiDownloadState)e.NewValue); + } + + private void UpdateState(WcrApiDownloadState state) + { + switch (state) + { + case WcrApiDownloadState.NotStarted: + NotDownloadedContent.Visibility = Visibility.Visible; + loadingRingContainer.Visibility = Visibility.Collapsed; + errorContent.Visibility = Visibility.Collapsed; + this.Visibility = Visibility.Visible; + break; + case WcrApiDownloadState.Downloading: + NotDownloadedContent.Visibility = Visibility.Collapsed; + loadingRingContainer.Visibility = Visibility.Visible; + errorContent.Visibility = Visibility.Collapsed; + this.Visibility = Visibility.Visible; + break; + case WcrApiDownloadState.Downloaded: + NotDownloadedContent.Visibility = Visibility.Collapsed; + loadingRingContainer.Visibility = Visibility.Collapsed; + errorContent.Visibility = Visibility.Collapsed; + this.Visibility = Visibility.Collapsed; + break; + case WcrApiDownloadState.Error: + NotDownloadedContent.Visibility = Visibility.Collapsed; + loadingRingContainer.Visibility = Visibility.Collapsed; + errorContent.Visibility = Visibility.Visible; + this.Visibility = Visibility.Visible; + break; + default: + break; + } + } + + public WcrModelDownloader() + { + this.InitializeComponent(); + } + + public async Task SetDownloadOperation(IAsyncOperationWithProgress operation) + { + if (operation == null) + { + return false; + } + + operation.Progress = (result, progress) => + { + DispatcherQueue.TryEnqueue(() => + { + DownloadProgress = (int)(progress.Progress * 100); + }); + }; + + State = WcrApiDownloadState.Downloading; + + try + { + var result = await operation; + + if (result.Status == PackageDeploymentStatus.CompletedSuccess) + { + State = WcrApiDownloadState.Downloaded; + return true; + } + else + { + State = WcrApiDownloadState.Error; + ErrorMessage = result.ExtendedError.Message; + } + } + catch (Exception ex) + { + ErrorMessage = ex.Message; + State = WcrApiDownloadState.Error; + } + + return false; + } + + private void DownloadModelClicked(object sender, RoutedEventArgs e) + { + DownloadClicked?.Invoke(this, EventArgs.Empty); + } + + private async void WindowsUpdateHyperlinkClicked(Microsoft.UI.Xaml.Documents.Hyperlink sender, Microsoft.UI.Xaml.Documents.HyperlinkClickEventArgs args) + { + var uri = new Uri("ms-settings:windowsupdate"); + await Launcher.LaunchUriAsync(uri); + } +} + +internal enum WcrApiDownloadState +{ + NotStarted, + Downloading, + Downloaded, + Error +} \ No newline at end of file diff --git a/AIDevGallery/Samples/WCRAPIs/BackgroundRemover.xaml b/AIDevGallery/Samples/WCRAPIs/BackgroundRemover.xaml index b33b716f..e7d9fe34 100644 --- a/AIDevGallery/Samples/WCRAPIs/BackgroundRemover.xaml +++ b/AIDevGallery/Samples/WCRAPIs/BackgroundRemover.xaml @@ -3,101 +3,104 @@ x:Class="AIDevGallery.Samples.WCRAPIs.BackgroundRemover" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:controls="using:AIDevGallery.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:muxc="using:Microsoft.UI.Xaml.Controls" xmlns:samples="using:AIDevGallery.Samples" + xmlns:controls="using:AIDevGallery.Samples.TempSharedCode" mc:Ignorable="d"> - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + - @@ -170,11 +170,19 @@ Click="ModelCard_Click" Icon="{ui:FontIcon Glyph=}" Tag="{x:Bind ModelDetails}" + Visibility="{x:Bind ModelDetails.Size, Converter={StaticResource NotZeroToVisibilityConverter}}" Text="View model card" /> + @@ -265,7 +273,7 @@ ToolTipService.ToolTip="More info"> - + @@ -434,7 +442,7 @@ ToolTipService.ToolTip="More info"> - + @@ -528,11 +536,19 @@ Click="ModelCard_Click" Icon="{ui:FontIcon Glyph=}" Tag="{x:Bind ModelDetails}" + Visibility="{x:Bind ModelDetails.Size, Converter={StaticResource NotZeroToVisibilityConverter}}" Text="View model card" /> + diff --git a/AIDevGallery/Controls/ModelSelectionControl.xaml.cs b/AIDevGallery/Controls/ModelSelectionControl.xaml.cs index 684cee0f..958c3c37 100644 --- a/AIDevGallery/Controls/ModelSelectionControl.xaml.cs +++ b/AIDevGallery/Controls/ModelSelectionControl.xaml.cs @@ -367,6 +367,18 @@ private void ModelCard_Click(object sender, RoutedEventArgs e) } } + private void ApiDocumentation_Click(object sender, RoutedEventArgs e) + { + if (sender is MenuFlyoutItem btn && btn.Tag is ModelDetails details) + { + // we are in the sample view, open in app modelcard + if (ModelCardVisibility == Visibility.Visible) + { + App.MainWindow.Navigate("apis", details); + } + } + } + private void CopyModelPath_Click(object sender, RoutedEventArgs e) { if (sender is MenuFlyoutItem btn && btn.Tag is ModelDetails details) diff --git a/AIDevGallery/MainWindow.xaml.cs b/AIDevGallery/MainWindow.xaml.cs index e673c359..76e6f4b0 100644 --- a/AIDevGallery/MainWindow.xaml.cs +++ b/AIDevGallery/MainWindow.xaml.cs @@ -97,7 +97,7 @@ private void Navigate(Type page, object? param = null) if (page == typeof(APISelectionPage) && NavFrame.Content is APISelectionPage apiPage && param != null) { // No need to navigate to the APISelectionPage again, we just want to navigate to the right subpage - apiPage.SetSelectedAPIInMenu((ModelType)param); + apiPage.SetSelectedApiInMenu((ModelType)param); } else { diff --git a/AIDevGallery/Pages/APISelectionPage.xaml.cs b/AIDevGallery/Pages/APISelectionPage.xaml.cs index 07d18f48..1ef88b6c 100644 --- a/AIDevGallery/Pages/APISelectionPage.xaml.cs +++ b/AIDevGallery/Pages/APISelectionPage.xaml.cs @@ -6,6 +6,7 @@ using AIDevGallery.Telemetry.Events; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Navigation; +using System; using System.Collections.Generic; namespace AIDevGallery.Pages; @@ -25,7 +26,13 @@ protected override void OnNavigatedTo(NavigationEventArgs e) { if (e.Parameter is ModelType type) { - SetSelectedAPIInMenu(type); + SetSelectedApiInMenu(type); + } + else if (e.Parameter is ModelDetails details && + details.Url.StartsWith("file://", StringComparison.InvariantCultureIgnoreCase) && + Enum.TryParse(details.Url.Substring(7), out ModelType apiType)) + { + SetSelectedApiInMenu(apiType); } else { @@ -63,7 +70,7 @@ private void NavView_SelectionChanged(NavigationView sender, NavigationViewSelec } } - public void SetSelectedAPIInMenu(ModelType selectedType) + public void SetSelectedApiInMenu(ModelType selectedType) { foreach (var item in NavView.MenuItems) { From 2241160a607c32bae7b5694e65c3eeabb24ced13 Mon Sep 17 00:00:00 2001 From: Nikola Metulev <711864+nmetulev@users.noreply.github.com> Date: Thu, 13 Feb 2025 10:25:26 -0800 Subject: [PATCH 12/13] addressing pr feedback --- .../Controls/ModelSelectionControl.xaml.cs | 28 ++++++++----------- AIDevGallery/Models/ModelCompatibility.cs | 6 ++-- AIDevGallery/Pages/APISelectionPage.xaml.cs | 5 ++-- 3 files changed, 17 insertions(+), 22 deletions(-) diff --git a/AIDevGallery/Controls/ModelSelectionControl.xaml.cs b/AIDevGallery/Controls/ModelSelectionControl.xaml.cs index 958c3c37..10cc964d 100644 --- a/AIDevGallery/Controls/ModelSelectionControl.xaml.cs +++ b/AIDevGallery/Controls/ModelSelectionControl.xaml.cs @@ -240,13 +240,22 @@ private void PopulateModelDetailsLists() if (modelDetails.Compatibility.CompatibilityState == ModelCompatibilityState.Compatible) { - AvailableModels.Add(new AvailableModel(modelDetails)); + if (modelDetails.HardwareAccelerators.Contains(HardwareAccelerator.WCRAPI)) + { + // insert APIs on top + AvailableModels.Insert(0, new AvailableModel(modelDetails)); + } + else + { + AvailableModels.Add(new AvailableModel(modelDetails)); + } } else { if (model.Size == 0) { - UnavailableModels.Add(new BaseModel(modelDetails)); + // insert APIs on top + UnavailableModels.Insert(0, new BaseModel(modelDetails)); } else { @@ -265,24 +274,9 @@ private void PopulateModelDetailsLists() } } - SortModels(AvailableModels); - SortModels(DownloadableModels); - SortModels(UnavailableModels); - SetHeaderVisibilityStates(); } - private void SortModels(ObservableCollection models) - where T : IModelView - { - var sortedModels = models.OrderByDescending(m => m.ModelDetails.HardwareAccelerators.Contains(HardwareAccelerator.WCRAPI)).ToList(); - models.Clear(); - foreach (var model in sortedModels) - { - models.Add(model); - } - } - private void OpenModelFolder_Click(object sender, RoutedEventArgs e) { if (sender is MenuFlyoutItem btn && btn.Tag is ModelDetails details) diff --git a/AIDevGallery/Models/ModelCompatibility.cs b/AIDevGallery/Models/ModelCompatibility.cs index 9e0477c4..e33c2563 100644 --- a/AIDevGallery/Models/ModelCompatibility.cs +++ b/AIDevGallery/Models/ModelCompatibility.cs @@ -3,6 +3,7 @@ using AIDevGallery.Utils; using System; +using System.Linq; namespace AIDevGallery.Models; @@ -25,9 +26,8 @@ public static ModelCompatibility GetModelCompatibility(ModelDetails modelDetails // check if WCR API if (modelDetails.Url.StartsWith("file://", StringComparison.InvariantCultureIgnoreCase)) { - var apiKey = modelDetails.Url.Substring(7); - - if (Enum.TryParse(apiKey, out ModelType apiType) && WcrCompatibilityChecker.GetApiAvailability(apiType) != WcrApiAvailability.NotSupported) + if (Samples.ModelTypeHelpers.ApiDefinitionDetails.Any(md => md.Value.Id == modelDetails.Id) && + WcrCompatibilityChecker.GetApiAvailability(Samples.ModelTypeHelpers.ApiDefinitionDetails.FirstOrDefault(md => md.Value.Id == modelDetails.Id).Key) != WcrApiAvailability.NotSupported) { compatibility = ModelCompatibilityState.Compatible; } diff --git a/AIDevGallery/Pages/APISelectionPage.xaml.cs b/AIDevGallery/Pages/APISelectionPage.xaml.cs index 1ef88b6c..b7aeb97b 100644 --- a/AIDevGallery/Pages/APISelectionPage.xaml.cs +++ b/AIDevGallery/Pages/APISelectionPage.xaml.cs @@ -8,6 +8,7 @@ using Microsoft.UI.Xaml.Navigation; using System; using System.Collections.Generic; +using System.Linq; namespace AIDevGallery.Pages; @@ -30,9 +31,9 @@ protected override void OnNavigatedTo(NavigationEventArgs e) } else if (e.Parameter is ModelDetails details && details.Url.StartsWith("file://", StringComparison.InvariantCultureIgnoreCase) && - Enum.TryParse(details.Url.Substring(7), out ModelType apiType)) + ModelTypeHelpers.ApiDefinitionDetails.Any(md => md.Value.Id == details.Id)) { - SetSelectedApiInMenu(apiType); + SetSelectedApiInMenu(ModelTypeHelpers.ApiDefinitionDetails.FirstOrDefault(md => md.Value.Id == details.Id).Key); } else { From 4e6acdae63b68a499b5227172ed959dce3de1c06 Mon Sep 17 00:00:00 2001 From: Nikola Metulev <711864+nmetulev@users.noreply.github.com> Date: Thu, 13 Feb 2025 13:04:35 -0800 Subject: [PATCH 13/13] Addressed PR Comments --- AIDevGallery/Models/ModelCompatibility.cs | 7 ++++--- AIDevGallery/Pages/APISelectionPage.xaml.cs | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/AIDevGallery/Models/ModelCompatibility.cs b/AIDevGallery/Models/ModelCompatibility.cs index e33c2563..bbc783c9 100644 --- a/AIDevGallery/Models/ModelCompatibility.cs +++ b/AIDevGallery/Models/ModelCompatibility.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using AIDevGallery.Samples; using AIDevGallery.Utils; using System; using System.Linq; @@ -24,10 +25,10 @@ public static ModelCompatibility GetModelCompatibility(ModelDetails modelDetails ModelCompatibilityState compatibility; // check if WCR API - if (modelDetails.Url.StartsWith("file://", StringComparison.InvariantCultureIgnoreCase)) + if (ModelTypeHelpers.ApiDefinitionDetails.Any(md => md.Value.Id == modelDetails.Id)) { - if (Samples.ModelTypeHelpers.ApiDefinitionDetails.Any(md => md.Value.Id == modelDetails.Id) && - WcrCompatibilityChecker.GetApiAvailability(Samples.ModelTypeHelpers.ApiDefinitionDetails.FirstOrDefault(md => md.Value.Id == modelDetails.Id).Key) != WcrApiAvailability.NotSupported) + var apiType = ModelTypeHelpers.ApiDefinitionDetails.FirstOrDefault(md => md.Value.Id == modelDetails.Id).Key; + if (WcrCompatibilityChecker.GetApiAvailability(apiType) != WcrApiAvailability.NotSupported) { compatibility = ModelCompatibilityState.Compatible; } diff --git a/AIDevGallery/Pages/APISelectionPage.xaml.cs b/AIDevGallery/Pages/APISelectionPage.xaml.cs index b7aeb97b..c494045b 100644 --- a/AIDevGallery/Pages/APISelectionPage.xaml.cs +++ b/AIDevGallery/Pages/APISelectionPage.xaml.cs @@ -30,10 +30,10 @@ protected override void OnNavigatedTo(NavigationEventArgs e) SetSelectedApiInMenu(type); } else if (e.Parameter is ModelDetails details && - details.Url.StartsWith("file://", StringComparison.InvariantCultureIgnoreCase) && ModelTypeHelpers.ApiDefinitionDetails.Any(md => md.Value.Id == details.Id)) { - SetSelectedApiInMenu(ModelTypeHelpers.ApiDefinitionDetails.FirstOrDefault(md => md.Value.Id == details.Id).Key); + var apiType = ModelTypeHelpers.ApiDefinitionDetails.FirstOrDefault(md => md.Value.Id == details.Id).Key; + SetSelectedApiInMenu(apiType); } else {