diff --git a/src/DynamoCore/Models/RunSettings.cs b/src/DynamoCore/Models/RunSettings.cs index 8f27254ae3d..ba7aa809210 100644 --- a/src/DynamoCore/Models/RunSettings.cs +++ b/src/DynamoCore/Models/RunSettings.cs @@ -12,6 +12,7 @@ public enum RunType { Manual, Automatic, Periodic } /// Node Autocomplete suggestion values /// public enum NodeAutocompleteSuggestion { MLRecommendation, ObjectType } + /// /// The RunSettings object contains properties which control /// how execution is carried out. diff --git a/src/DynamoCore/Properties/Resources.Designer.cs b/src/DynamoCore/Properties/Resources.Designer.cs index 373edd5032d..be85c54796b 100644 --- a/src/DynamoCore/Properties/Resources.Designer.cs +++ b/src/DynamoCore/Properties/Resources.Designer.cs @@ -88,6 +88,60 @@ public static string Autocomplete { } } + /// + /// Looks up a localized string similar to We are not very confident that the nodes below will work, you may try them or. + /// + public static string AutocompleteLowConfidenceMessage { + get { + return ResourceManager.GetString("AutocompleteLowConfidenceMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to to view more options. + /// + public static string AutocompleteLowConfidenceMessageAditional { + get { + return ResourceManager.GetString("AutocompleteLowConfidenceMessageAditional", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Low confidence. + /// + public static string AutocompleteLowConfidenceTitle { + get { + return ResourceManager.GetString("AutocompleteLowConfidenceTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Low Confidence Tooltip. + /// + public static string AutocompleteLowConfidenceTooltip { + get { + return ResourceManager.GetString("AutocompleteLowConfidenceTooltip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There’s no node that we can recommend to you, you may try. + /// + public static string AutocompleteNoRecommendationsMessage { + get { + return ResourceManager.GetString("AutocompleteNoRecommendationsMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No recommendations. + /// + public static string AutocompleteNoRecommendationsTitle { + get { + return ResourceManager.GetString("AutocompleteNoRecommendationsTitle", resourceCulture); + } + } + /// /// Looks up a localized string similar to Search Autocomplete Results. /// @@ -97,6 +151,15 @@ public static string AutocompleteSearchTextBlockText { } } + /// + /// Looks up a localized string similar to switching to Object Type Autocomplete. + /// + public static string AutocompleteSwitchToObjectTypeMessage { + get { + return ResourceManager.GetString("AutocompleteSwitchToObjectTypeMessage", resourceCulture); + } + } + /// /// Looks up a localized string similar to Original file '{0}' gets backed up at '{1}'. /// diff --git a/src/DynamoCore/Properties/Resources.en-US.resx b/src/DynamoCore/Properties/Resources.en-US.resx index aa4d19d3c3a..08de2083e93 100644 --- a/src/DynamoCore/Properties/Resources.en-US.resx +++ b/src/DynamoCore/Properties/Resources.en-US.resx @@ -1,4 +1,4 @@ - + - - \ No newline at end of file + + diff --git a/src/DynamoCoreWpf/ViewModels/Menu/PreferencesViewModel.cs b/src/DynamoCoreWpf/ViewModels/Menu/PreferencesViewModel.cs index 712830b760f..898b1ab4402 100644 --- a/src/DynamoCoreWpf/ViewModels/Menu/PreferencesViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Menu/PreferencesViewModel.cs @@ -277,6 +277,7 @@ public bool NodeAutocompleteMachineLearningIsChecked preferenceSettings.DefaultNodeAutocompleteSuggestion = NodeAutocompleteSuggestion.ObjectType; nodeAutocompleteSuggestion = NodeAutocompleteSuggestion.ObjectType; } + dynamoViewModel.HomeSpaceViewModel.NodeAutoCompleteSearchViewModel.ResetAutoCompleteSearchViewState(); RaisePropertyChanged(nameof(nodeAutocompleteSuggestion)); } } diff --git a/src/DynamoCoreWpf/ViewModels/Search/NodeAutoCompleteSearchViewModel.cs b/src/DynamoCoreWpf/ViewModels/Search/NodeAutoCompleteSearchViewModel.cs index 77c2b335404..7cc1da2eb21 100644 --- a/src/DynamoCoreWpf/ViewModels/Search/NodeAutoCompleteSearchViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Search/NodeAutoCompleteSearchViewModel.cs @@ -18,10 +18,14 @@ namespace Dynamo.ViewModels /// public class NodeAutoCompleteSearchViewModel : SearchViewModel { - internal PortViewModel PortViewModel { get; set; } private List searchElementsCache; private List defaultSearchElementsCache; + private string lowConfidenceMessageAdditional; + private string noRecommendationsOrLowConfidenceMessage; + private string noRecommendationsOrLowConfidenceTitle; + private bool displayNoRecommendationsLowConfidence; + private bool displayLowConfidence; /// /// Cache of default node suggestions, use it in case where @@ -30,12 +34,107 @@ public class NodeAutoCompleteSearchViewModel : SearchViewModel /// internal IEnumerable DefaultResults { get; set; } + /// + /// For checking if the ML method is selected + /// + public bool IsDisplayingMLRecommendation + { + get + { + return dynamoViewModel.PreferenceSettings.DefaultNodeAutocompleteSuggestion == Models.NodeAutocompleteSuggestion.MLRecommendation; + } + } + + /// + /// The No Recommendations or Low Confidence Title + /// + public string NoRecommendationsOrLowConfidenceTitle + { + get { return noRecommendationsOrLowConfidenceTitle; } + set + { + noRecommendationsOrLowConfidenceTitle = value; + RaisePropertyChanged(nameof(NoRecommendationsOrLowConfidenceTitle)); + } + } + + /// + /// The No Recommendations or Low Confidence message + /// + public string NoRecommendationsOrLowConfidenceMessage + { + get { return noRecommendationsOrLowConfidenceMessage; } + set + { + noRecommendationsOrLowConfidenceMessage = value; + RaisePropertyChanged(nameof(NoRecommendationsOrLowConfidenceMessage)); + } + } + + /// + /// The Low Confidence additonal message + /// + public string LowConfidenceMessageAdditional + { + get { return lowConfidenceMessageAdditional; } + set + { + lowConfidenceMessageAdditional = value; + RaisePropertyChanged(nameof(LowConfidenceMessageAdditional)); + } + } + + /// + /// Indicates if display the No recommendations / Low confidence message (image and texts) + /// + public bool DisplayNoRecommendationsLowConfidence + { + get { return displayNoRecommendationsLowConfidence; } + set + { + displayNoRecommendationsLowConfidence = value; + RaisePropertyChanged(nameof(DisplayNoRecommendationsLowConfidence)); + } + } + + /// + /// Indicates if display the Low confidence option and Tooltip + /// + public bool DisplayLowConfidence + { + get { return displayLowConfidence; } + set + { + displayLowConfidence = value; + RaisePropertyChanged(nameof(DisplayLowConfidence)); + } + } + + /// + /// Constructor + /// + /// Dynamo ViewModel internal NodeAutoCompleteSearchViewModel(DynamoViewModel dynamoViewModel) : base(dynamoViewModel) { // Off load some time consuming operation here InitializeDefaultAutoCompleteCandidates(); } + /// + /// Reset Node AutoComplete search view state + /// + internal void ResetAutoCompleteSearchViewState() + { + if (!IsDisplayingMLRecommendation) + { + NoRecommendationsOrLowConfidenceMessage = string.Empty; + NoRecommendationsOrLowConfidenceTitle = string.Empty; + LowConfidenceMessageAdditional = string.Empty; + DisplayNoRecommendationsLowConfidence = false; + DisplayLowConfidence = false; + } + PopulateAutoCompleteCandidates(); + } private void InitializeDefaultAutoCompleteCandidates() { @@ -53,22 +152,103 @@ private void InitializeDefaultAutoCompleteCandidates() } DefaultResults = candidates; } - + + internal void DisplayMachineLearningResults() + { + // Case 1: no results (0 items) + FilteredResults = new List(); + DisplayNoRecommendationsLowConfidence = true; + DisplayLowConfidence = false; + NoRecommendationsOrLowConfidenceTitle = Resources.AutocompleteNoRecommendationsTitle; + NoRecommendationsOrLowConfidenceMessage = Resources.AutocompleteNoRecommendationsMessage; + DisplayLowConfidence = false; + + // Case 2: the result has at least one item assuming each node could be by recommendation or by use + /* + FilteredResults = DefaultResults.Where(e => e.Name == "Watch 3D" || e.Name == "Python Script").ToList(); + + foreach (var item in FilteredResults) + { + item.AutoCompletionNodeMachineLearningInfo.ViewConfidenceScoreRecentUse = true; + item.AutoCompletionNodeMachineLearningInfo.IsByUse = true; + } + DisplayNoRecommendationsLowConfidence = !FilteredResults.Where(n => n.AutoCompletionNodeMachineLearningInfo.IsByRecommendation).Any(); + DisplayLowConfidence = false; + NoRecommendationsOrLowConfidenceTitle = Resources.AutocompleteNoRecommendationsTitle; + NoRecommendationsOrLowConfidenceMessage = Resources.AutocompleteNoRecommendationsMessage; + DisplayLowConfidence = false; + */ + + // Case 3: Confidence score are under a threshold, assuming the minimum value is 50 and some result nodes are under it + /* + FilteredResults = DefaultResults.Where(e => e.Name == "Watch 3D" || e.Name == "Python Script").ToList(); + + foreach (var item in FilteredResults) + { + item.Model.AutoCompletionNodeMachineLearningInfo.ViewConfidenceScoreRecentUse = true; + item.Model.AutoCompletionNodeMachineLearningInfo.IsByUse = false; + } + FilteredResults.ToList()[0].Model.AutoCompletionNodeMachineLearningInfo.ConfidenceScore = 50; + FilteredResults.ToList()[1].Model.AutoCompletionNodeMachineLearningInfo.ConfidenceScore = 40; + RaisePropertyChanged("ViewConfidenceScoreRecentUse"); + + DisplayNoRecommendationsLowConfidence = !FilteredResults.Where(n => n.Model.AutoCompletionNodeMachineLearningInfo.ConfidenceScore >= 50).Any(); + NoRecommendationsOrLowConfidenceMessage = Resources.AutocompleteNoRecommendationsMessage; + DisplayLowConfidence = FilteredResults.Where(n => n.Model.AutoCompletionNodeMachineLearningInfo.IsByRecommendation).Count() == FilteredResults.Count(); + */ + + + // Case 4: Confidence score are under a threshold, assuming the minimum value is 50 and all results nodes are under it + /* + FilteredResults = DefaultResults.Where(e => e.Name == "Watch 3D" || e.Name == "Python Script").ToList(); + foreach (var item in FilteredResults) + { + item.AutoCompletionNodeMachineLearningInfo.ViewConfidenceScoreRecentUse = true; + item.AutoCompletionNodeMachineLearningInfo.IsByUse = false; + } + FilteredResults.ToList()[0].AutoCompletionNodeMachineLearningInfo.ConfidenceScore = 30; + FilteredResults.ToList()[1].AutoCompletionNodeMachineLearningInfo.ConfidenceScore = 40; + + if (!FilteredResults.Where(n => n.AutoCompletionNodeMachineLearningInfo.ConfidenceScore >= 50).Any()) + { + FilteredResults = new List(); + DisplayNoRecommendationsLowConfidence = true; + NoRecommendationsOrLowConfidenceTitle = Resources.AutocompleteLowConfidenceTitle; + NoRecommendationsOrLowConfidenceMessage = Resources.AutocompleteLowConfidenceMessage; + LowConfidenceMessageAdditional = Resources.AutocompleteLowConfidenceMessageAditional; + DisplayLowConfidence = true; + } + */ + } + internal void PopulateAutoCompleteCandidates() { if (PortViewModel == null) return; - searchElementsCache = GetMatchingSearchElements().ToList(); - - // If node match searchElements found, use default suggestions. - // These default suggestions will be populated based on the port type. - if (!searchElementsCache.Any()) + if (IsDisplayingMLRecommendation) { - PopulateDefaultAutoCompleteCandidates(); + // TODO: Add a function call to send port and node info to get suggestions + DisplayMachineLearningResults(); } else { - FilteredResults = GetViewModelForNodeSearchElements(searchElementsCache); + // Only call GetMatchingSearchElements() for object type match comparison + searchElementsCache = GetMatchingSearchElements().ToList(); + // If node match searchElements found, use default suggestions. + // These default suggestions will be populated based on the port type. + if (!searchElementsCache.Any()) + { + PopulateDefaultAutoCompleteCandidates(); + } + else + { + FilteredResults = GetViewModelForNodeSearchElements(searchElementsCache); + } + + foreach (var item in FilteredResults) + { + item.Model.AutoCompletionNodeMachineLearningInfo.ViewConfidenceScoreRecentUse = false; + } } } @@ -127,7 +307,7 @@ internal void SearchAutoCompleteCandidates(string input) { if (searchElementsCache.Any()) { - FilteredResults = GetViewModelForNodeSearchElements(searchElementsCache); + FilteredResults = GetViewModelForNodeSearchElements(searchElementsCache); } else { @@ -146,7 +326,7 @@ internal void SearchAutoCompleteCandidates(string input) { var foundNodes = Search(input, defaultSearchElementsCache); FilteredResults = new List(foundNodes).OrderBy(x => x.Name).ThenBy(x => x.Description); - } + } } } @@ -298,15 +478,6 @@ private bool DerivesFrom(string typea, string typeb, ProtoCore.Core core) } } - /// - /// For checking if the ML method is selected - /// - public bool IsDisplayingMLRecommendation - { - get { return dynamoViewModel.PreferenceSettings.DefaultNodeAutocompleteSuggestion == Models.NodeAutocompleteSuggestion.MLRecommendation; } - set { } - } - /// /// Compares NodeSearchElements based on their typeDistance from a given type 'typeNameToCompareTo' /// diff --git a/src/DynamoCoreWpf/ViewModels/Search/NodeSearchElementViewModel.cs b/src/DynamoCoreWpf/ViewModels/Search/NodeSearchElementViewModel.cs index f0c43b5ab7e..8fd50529b15 100644 --- a/src/DynamoCoreWpf/ViewModels/Search/NodeSearchElementViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Search/NodeSearchElementViewModel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Windows; diff --git a/test/DynamoCoreWpfTests/NodeAutoCompleteSearchTests.cs b/test/DynamoCoreWpfTests/NodeAutoCompleteSearchTests.cs index ded7bcd82a9..4162d4a9569 100644 --- a/test/DynamoCoreWpfTests/NodeAutoCompleteSearchTests.cs +++ b/test/DynamoCoreWpfTests/NodeAutoCompleteSearchTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Dynamo.Controls; @@ -111,6 +111,9 @@ public void NodeSuggestions_CanAutoCompleteOnCustomNodes() var searchViewModel = ViewModel.CurrentSpaceViewModel.NodeAutoCompleteSearchViewModel; searchViewModel.PortViewModel = inPorts[1]; + // Set the suggestion to ObjectType + searchViewModel.dynamoViewModel.PreferenceSettings.DefaultNodeAutocompleteSuggestion = NodeAutocompleteSuggestion.ObjectType; + // The initial list will fill the FilteredResults with a few options - all basic input types searchViewModel.PopulateAutoCompleteCandidates(); Assert.AreEqual(8, searchViewModel.FilteredResults.Count()); @@ -134,6 +137,9 @@ public void NodeSuggestions_CanAutoCompleteOnCustomNodesOutPort() var searchViewModel = ViewModel.CurrentSpaceViewModel.NodeAutoCompleteSearchViewModel; searchViewModel.PortViewModel = outPorts[1]; + // Set the suggestion to ObjectType + searchViewModel.dynamoViewModel.PreferenceSettings.DefaultNodeAutocompleteSuggestion = NodeAutocompleteSuggestion.ObjectType; + // The initial list will fill the FilteredResults with a few options - all basic input types searchViewModel.PopulateAutoCompleteCandidates(); Assert.AreEqual(7, searchViewModel.FilteredResults.Count()); @@ -414,6 +420,9 @@ public void NodeSuggestions_DefaultSuggestions() var suggestions = searchViewModel.GetMatchingSearchElements(); Assert.AreEqual(0, suggestions.Count()); + // Set the suggestion to ObjectType + searchViewModel.dynamoViewModel.PreferenceSettings.DefaultNodeAutocompleteSuggestion = NodeAutocompleteSuggestion.ObjectType; + // The initial list will fill the FilteredResults with a few options - all basic input types searchViewModel.PopulateAutoCompleteCandidates(); Assert.AreEqual(5, searchViewModel.FilteredResults.Count()); @@ -466,6 +475,9 @@ public void NodeSuggestions_SkippedSuggestions() var suggestions = searchViewModel.GetMatchingSearchElements(); Assert.AreEqual(0, suggestions.Count()); + // Set the suggestion to ObjectType + searchViewModel.dynamoViewModel.PreferenceSettings.DefaultNodeAutocompleteSuggestion = NodeAutocompleteSuggestion.ObjectType; + // The initial list will fill the FilteredResults with a list of default options searchViewModel.PopulateAutoCompleteCandidates(); Assert.AreEqual(2, searchViewModel.FilteredResults.Count());