Example #1
0
 protected override string ExtractIntent(Item item)
 {
     try
     {
         Phrase phrase = new Phrase(item.Name);
         if (phrase.Task != null)
         {
             string verb = phrase.Task.Verb.ToLower();
             string noun = phrase.Task.Article.ToLower();
             Intent intent = Storage.NewSuggestionsContext.Intents.FirstOrDefault(i => i.Verb == verb && i.Noun == noun);
             if (intent != null)
                 return intent.WorkflowType;
         }
     }
     catch (Exception ex)
     {
         TraceLog.TraceException("Could not initialize NLP engine", ex);
     }
     return base.ExtractIntent(item);
 }
Example #2
0
        private Status GenerateSuggestions(WorkflowInstance workflowInstance, ServerEntity entity, Dictionary<string, string> suggestionList)
        {
            Item item = entity as Item;
            if (item == null)
            {
                TraceLog.TraceError("Entity is not an Item");
                return Status.Error;
            }

            User user = UserContext.GetUser(item.UserID, true);
            if (user == null)
            {
                TraceLog.TraceError("Could not find the user associated with Item " + item.Name);
                return Status.Error;
            }

            ADGraphAPI adApi = new ADGraphAPI();
            string adRefreshToken = null;

            // check for FB and/or AD credentials
            UserCredential cred = user.GetCredential(UserCredential.FacebookConsent);
            if (cred != null && cred.AccessToken != null) { adApi.FacebookAccessToken = cred.AccessToken; }
            cred = user.GetCredential(UserCredential.CloudADConsent);
            if (cred != null && cred.RenewalToken != null) { adRefreshToken = cred.RenewalToken; }

            if (adApi.FacebookAccessToken == null && adRefreshToken == null)
            {   // user not having either token is not an error condition, but there is no way to generate suggestions
                // just move forward from this state
                return Status.Complete;
            }

            // if a refresh token exists for AD, get an access token from Azure ACS for the Azure AD service
            if (adRefreshToken != null)
            {
                try
                {
                    AccessTokenRequestWithRefreshToken request = new AccessTokenRequestWithRefreshToken(new Uri(AzureOAuthConfiguration.GetTokenUri()))
                    {
                        RefreshToken = adRefreshToken,
                        ClientId = AzureOAuthConfiguration.GetClientIdentity(),
                        ClientSecret = AzureOAuthConfiguration.ClientSecret,
                        Scope = AzureOAuthConfiguration.RelyingPartyRealm,
                    };
                    OAuthMessage message = OAuthClient.GetAccessToken(request);
                    AccessTokenResponse authzResponse = message as AccessTokenResponse;
                    adApi.ADAccessToken = authzResponse.AccessToken;

                    // workaround for ACS trashing the refresh token
                    if (!String.IsNullOrEmpty(authzResponse.RefreshToken))
                    {
                        TraceLog.TraceInfo("Storing new CloudAD refresh token");
                        user.AddCredential(UserCredential.CloudADConsent, authzResponse.AccessToken, null, authzResponse.RefreshToken);
                        UserContext.SaveChanges();
                    }
                }
                catch (Exception ex)
                {
                    TraceLog.TraceException("Could not contact ACS to get an access token", ex);

                    // Facebook credentials are not available
                    if (adApi.FacebookAccessToken == null)
                        return Status.Pending;  // could be a temporary outage, do not move off this state
                }
            }

            // extract a subject hint if one hasn't been discovered yet
            string subjectHint = GetInstanceData(workflowInstance, ActivityVariables.SubjectHint);
            if (String.IsNullOrEmpty(subjectHint))
            {
                try
                {
                    Phrase phrase = new Phrase(item.Name);
                    if (phrase.Task != null)
                    {
                        subjectHint = phrase.Task.Subject;
                        if (!String.IsNullOrWhiteSpace(subjectHint))
                            StoreInstanceData(workflowInstance, ActivityVariables.SubjectHint, subjectHint);
                    }
                }
                catch (Exception ex)
                {
                    TraceLog.TraceException("Could not initialize NLP engine", ex);
                }
            }

            // get contacts from Cloud AD and Facebook via the AD Graph Person service
            // TODO: also get local contacts from the Contacts folder
            try
            {
                var results = adApi.Query(subjectHint ?? "");
                foreach (var subject in results)
                {
                    // serialize an existing contact corresponding to the subject,
                    // or generate a new serialized contact if one wasn't found
                    Item contact = MakeContact(workflowInstance, item, subject);
                    suggestionList[contact.Name] = JsonSerializer.Serialize(contact);
                }
            }
            catch (Exception ex)
            {
                TraceLog.TraceException("Could not contact Person Service", ex);
                return Status.Error;
            }

            // inexact match
            return Status.Pending;
        }
Example #3
0
        private Status GenerateSuggestions(WorkflowInstance workflowInstance, ServerEntity entity, Dictionary<string, string> suggestionList)
        {
            Item item = entity as Item;
            if (item == null)
            {
                TraceLog.TraceError("Entity is not an Item");
                return Status.Error;
            }

            // if an intent was already matched, return it now
            var intentFV = item.GetFieldValue(ExtendedFieldNames.Intent);
            if (intentFV != null && !String.IsNullOrWhiteSpace(intentFV.Value))
            {
                var wt = SuggestionsContext.WorkflowTypes.FirstOrDefault(t => t.Type == intentFV.Value);
                if (wt != null)
                {
                    suggestionList[wt.Type] = wt.Type;
                    return Status.Complete;
                }
            }

            // run NLP engine over the task name to extract intent (verb / noun) as well as a subject hint
            string name = item.Name;
            string verb = null;
            string noun = null;
            string subject = null;
            try
            {
                Phrase phrase = new Phrase(name);
                if (phrase.Task != null)
                {
                    verb = phrase.Task.Verb.ToLower();
                    noun = phrase.Task.Article.ToLower();
                    subject = phrase.Task.Subject;
                    if (!String.IsNullOrWhiteSpace(subject))
                        StoreInstanceData(workflowInstance, ActivityVariables.SubjectHint, subject);
                }
            }
            catch (Exception ex)
            {
                TraceLog.TraceException("Could not initialize NLP engine", ex);
            }

            // if NLP failed (e.g. data file not found), do "poor man's NLP" - assume a structure like <verb> <noun> [{for,with} <subject>]
            if (verb == null)
            {
                string sentence = name.ToLower();

                // remove extra whitespace and filler words
                StringBuilder sb = new StringBuilder();
                foreach (var word in sentence.Split(new char[] { ' ', '\n', '\t' }, StringSplitOptions.RemoveEmptyEntries))
                {
                    bool add = true;
                    foreach (var filler in "a;an;the".Split(';'))
                        if (word == filler)
                        {
                            add = false;
                            break;
                        }
                    if (add)
                        sb.AppendFormat("{0} ", word);
                }
                sentence = sb.ToString().Trim();

                // poor man's NLP - assume first word is verb, second word is noun
                string[] parts = sentence.Split(' ');

                if (parts.Length >= 2)
                {
                    verb = parts[0];
                    noun = parts[1];
                }
                if (parts.Length >= 4)
                {
                    if (parts[2] == "for" || parts[2] == "with")
                    {
                        // capitalize and store the word following "for" in the SubjectHint workflow parameter
                        subject = parts[3];
                        subject = subject.Substring(0, 1).ToUpper() + subject.Substring(1);
                        StoreInstanceData(workflowInstance, ActivityVariables.SubjectHint, subject);
                    }
                }
            }

            // try to find an intent that exactly matches the verb/noun extracted by the NLP step
            Intent intent = SuggestionsContext.Intents.FirstOrDefault(i => i.Verb == verb && i.Noun == noun);
            if (intent != null)
            {
                var wt = SuggestionsContext.WorkflowTypes.FirstOrDefault(t => t.Type == intent.WorkflowType);
                if (wt != null)
                {
                    suggestionList[intent.WorkflowType] = wt.Type;
                    return Status.Complete;
                }
            }

            // get a list of all approximate matches and surface as suggestions to the user
            var intentList = SuggestionsContext.Intents.Where(i => i.Verb == verb || i.Noun == noun);
            foreach (var i in intentList)
                suggestionList[i.WorkflowType] = i.WorkflowType;

            // if there are no suggestions, we can terminate this workflow
            if (suggestionList.Count == 0)
            {
                TraceLog.TraceError("No possible intents were found, terminating workflow");
                return Status.Error;
            }

            return Status.Pending;
        }