Esempio n. 1
0
        public async Task <IActionResult> Index()
        {
            var actions = GetActions();

            var timeOfDayFeature = GetTimeOfDay();
            var userOsFeature    = GetUserOs(Request.Headers["User-Agent"]);

            var currentContext = new List <object> {
                new { time = timeOfDayFeature },
                new { userOs = userOsFeature }
            };

            var request  = new RankRequest(actions, currentContext);
            var response = await _personalizerClient.RankAsync(request);

            return(View(new PersonalizerModel
            {
                PersonalizerEventId = response.EventId,
                PersonalizerEventStartTime = DateTime.UtcNow,

                Action = response.RewardActionId,
                TimeOfDay = timeOfDayFeature,
                UserOs = userOsFeature,
                Ranking = response.Ranking
            }));
        }
Esempio n. 2
0
        private async Task RankWithNoOptions(PersonalizerClient client)
        {
            IList <object> contextFeatures = new List <object>()
            {
                new { Features = new { day = "tuesday", time = "night", weather = "rainy" } },
                new { Features = new { userId = "1234", payingUser = true, favoriteGenre = "documentary", hoursOnSite = 0.12, lastwatchedType = "movie" } }
            };
            IList <PersonalizerRankableAction> actions = new List <PersonalizerRankableAction>();

            actions.Add(
                new PersonalizerRankableAction(
                    id: "Person1",
                    features:
                    new List <object>()
            {
                new { videoType = "documentary", videoLength = 35, director = "CarlSagan" }, new { mostWatchedByAge = "30-35" }
            }
                    ));
            actions.Add(
                new PersonalizerRankableAction(
                    id: "Person2",
                    features:
                    new List <object>()
            {
                new { videoType = "documentary", videoLength = 35, director = "CarlSagan" }, new { mostWatchedByAge = "40-45" }
            }
                    ));
            // Action
            PersonalizerRankResult response = await client.RankAsync(actions, contextFeatures);

            Assert.AreEqual(actions.Count, response.Ranking.Count);
        }
Esempio n. 3
0
        public async Task RankNullParameters()
        {
            PersonalizerClient client = GetPersonalizerClient();
            IList <PersonalizerRankableAction> actions = new List <PersonalizerRankableAction>();

            actions.Add
                (new PersonalizerRankableAction(
                    id: "Person",
                    features:
                    new List <object>()
            {
                new { videoType = "documentary", videoLength = 35, director = "CarlSagan" }, new { mostWatchedByAge = "30-35" }
            }
                    ));
            var request = new PersonalizerRankOptions(actions);
            // Action
            PersonalizerRankResult response = await client.RankAsync(request);

            // Assert
            Assert.AreEqual(actions.Count, response.Ranking.Count);
            for (int i = 0; i < response.Ranking.Count; i++)
            {
                Assert.AreEqual(actions[i].Id, response.Ranking[i].Id);
            }
        }
Esempio n. 4
0
        public async Task RankServerFeatures()
        {
            PersonalizerClient client          = GetPersonalizerClient();
            IList <object>     contextFeatures = new List <object>()
            {
                new { Features = new { day = "tuesday", time = "night", weather = "rainy" } },
                new { Features = new { userId = "1234", payingUser = true, favoriteGenre = "documentary", hoursOnSite = 0.12, lastwatchedType = "movie" } }
            };
            IList <PersonalizerRankableAction> actions = new List <PersonalizerRankableAction>();

            actions.Add(
                new PersonalizerRankableAction(
                    id: "Person1",
                    features:
                    new List <object>()
            {
                new { videoType = "documentary", videoLength = 35, director = "CarlSagan" }, new { mostWatchedByAge = "30-35" }
            }
                    ));
            actions.Add(
                new PersonalizerRankableAction(
                    id: "Person2",
                    features:
                    new List <object>()
            {
                new { videoType = "documentary", videoLength = 35, director = "CarlSagan" }, new { mostWatchedByAge = "40-45" }
            }
                    ));
            IList <string> excludeActions = new List <string> {
                "Person1"
            };
            string eventId = "123456789";
            var    request = new PersonalizerRankOptions(actions, contextFeatures, excludeActions, eventId);
            // Action
            PersonalizerRankResult response = await client.RankAsync(request);

            // Assert
            Assert.AreEqual(eventId, response.EventId);
            Assert.AreEqual(actions.Count, response.Ranking.Count);
            for (int i = 0; i < response.Ranking.Count; i++)
            {
                Assert.AreEqual(actions[i].Id, response.Ranking[i].Id);
            }
        }
Esempio n. 5
0
        public static async Task <IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req, ILogger log)
        {
            try
            {
                string requestBody = String.Empty;
                using (StreamReader sReader = new StreamReader(req.Body))
                {
                    requestBody = await sReader.ReadToEndAsync();
                }
                var recommendationRequest = JsonConvert.DeserializeObject <RecommendationRequest>(requestBody);

                var personalizerEndpoint = Environment.GetEnvironmentVariable("AzurePersonalizerEndpoint", EnvironmentVariableTarget.Process);
                var personalizerKey      = Environment.GetEnvironmentVariable("AzurePersonalizerKey", EnvironmentVariableTarget.Process);
                if (!string.IsNullOrWhiteSpace(personalizerEndpoint) || !string.IsNullOrWhiteSpace(personalizerKey))
                {
                    var personalizerClient = new PersonalizerClient(
                        new ApiKeyServiceClientCredentials(personalizerKey))
                    {
                        Endpoint = personalizerEndpoint
                    };

                    var actions         = GetRankableActions(recommendationRequest.Catalogitems);
                    var contextFeatures = GetContextFeatures(recommendationRequest.UserName);
                    var excludeActions  = new List <string>();
                    var request         = new RankRequest(actions, contextFeatures, excludeActions, Guid.NewGuid().ToString());
                    var response        = await personalizerClient.RankAsync(request);

                    var recommendationReponse = new RecommendationResponse
                    {
                        eventId         = response.EventId,
                        PrefferedItemId = Convert.ToInt32(response.RewardActionId)
                    };

                    return(new OkObjectResult(recommendationReponse));
                }
                return(new BadRequestObjectResult("No endpoint or key configured"));
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                return(new BadRequestObjectResult(ex));
            }
        }
Esempio n. 6
0
        private async Task <RankResponse> ChooseRankAsync(ITurnContext turnContext, string eventId, CancellationToken cancellationToken)
        {
            IList <object> contextFeature = new List <object>
            {
                new { weather = _rlFeaturesManager.RLFeatures.Weather.ToString() },
                new { dayofweek = _rlFeaturesManager.RLFeatures.DayOfWeek.ToString() },
            };

            Random rand = new Random(DateTime.UtcNow.Millisecond);
            IList <RankableAction> actions = new List <RankableAction>();
            var coffees     = Enum.GetValues(typeof(Coffees));
            var beansOrigin = Enum.GetValues(typeof(CoffeeBeansOrigin));
            var organic     = Enum.GetValues(typeof(Organic));
            var roast       = Enum.GetValues(typeof(CoffeeRoast));
            var teas        = Enum.GetValues(typeof(Teas));

            foreach (var coffee in coffees)
            {
                actions.Add(new RankableAction
                {
                    Id       = coffee.ToString(),
                    Features =
                        new List <object>()
                    {
                        new { BeansOrigin = beansOrigin.GetValue(rand.Next(0, beansOrigin.Length)).ToString() },
                        new { Organic = organic.GetValue(rand.Next(0, organic.Length)).ToString() },
                        new { Roast = roast.GetValue(rand.Next(0, roast.Length)).ToString() },
                    },
                });
            }

            foreach (var tea in teas)
            {
                actions.Add(new RankableAction
                {
                    Id       = tea.ToString(),
                    Features =
                        new List <object>()
                    {
                        new { Organic = organic.GetValue(rand.Next(0, organic.Length)).ToString() },
                    },
                });
            }

            var request = new RankRequest(actions, contextFeature, null, eventId);
            await turnContext.SendActivityAsync(
                "===== DEBUG MESSAGE CALL TO RANK =====\n" +
                "This is what is getting sent to Rank:\n" +
                $"{JsonConvert.SerializeObject(request, Formatting.Indented)}\n",
                cancellationToken : cancellationToken);

            var response = await _personalizerClient.RankAsync(request, cancellationToken);

            await turnContext.SendActivityAsync(
                $"===== DEBUG MESSAGE RETURN FROM RANK =====\n" +
                "This is what Rank returned:\n" +
                $"{JsonConvert.SerializeObject(response, Formatting.Indented)}\n",
                cancellationToken : cancellationToken);

            return(response);
        }
Esempio n. 7
0
        public async Task Init()
        {
            News.IsVisible    = false;
            Loading.IsVisible = true;

            var feeds = new List <System.Threading.Tasks.Task <Feed> >()
            {
                FeedReader.ReadAsync("https://feeds.expressen.se/sport/"),
                FeedReader.ReadAsync("https://www.aftonbladet.se/sportbladet/rss.xml"),
            };

            await Task.WhenAll(feeds);

            var items = new List <FeedItem>();

            foreach (var feed in feeds)
            {
                var result = feed.Result;

                items.AddRange(result.Items);
            }

            var actions = new List <RankableAction>();

            foreach (var item in items.OrderByDescending(x => x.PublishingDate).Take(50))
            {
                string source = null;

                foreach (var feed in feeds)
                {
                    if (feed.Result.Items.Contains(item))
                    {
                        source = feed.Result.Link;
                        break;
                    }
                }

                var features = new List <object>()
                {
                    new { item.Title },
                    new { item.Author },
                    new { item.Description },
                    new { source }
                };

                var action = new RankableAction(item.Id, features);
                actions.Add(action);
            }



            string timeOfDay = null;

            if (DateTime.Now.Hour > 22 || DateTime.Now.Hour < 5)
            {
                timeOfDay = "night";
            }
            else if (DateTime.Now.Hour >= 5 && DateTime.Now.Hour < 12)
            {
                timeOfDay = "morning";
            }
            else if (DateTime.Now.Hour >= 12 && DateTime.Now.Hour < 17)
            {
                timeOfDay = "afternoon";
            }
            else
            {
                timeOfDay = "evening";
            }

            var context = new List <object>()
            {
                new { timeOfDay }
            };

            eventId = Guid.NewGuid().ToString();

            var rankRequest = new RankRequest()
            {
                Actions         = actions,
                ContextFeatures = context,
                ExcludedActions = new List <string>(),
                EventId         = eventId
            };

            try
            {
                var rankResult = await client.RankAsync(rankRequest);

                source = new List <Item>();

                foreach (var ranked in rankResult.Ranking.OrderByDescending(x => x.Probability))
                {
                    var feedItem = items.Single(x => x.Id == ranked.Id);

                    var urls = Regex.Matches(feedItem.Description, @"(http|ftp|https):\/\/([\w\-_]+(?:(?:\.[\w\-_]+)+))([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?");

                    var itm = new Item()
                    {
                        FeedItem = feedItem,
                        Image    = urls.FirstOrDefault()?.Value
                    };

                    foreach (var feed in feeds)
                    {
                        if (feed.Result.Items.Contains(feedItem))
                        {
                            itm.Source = feed.Result.Link;
                            break;
                        }
                    }

                    source.Add(itm);
                }

                News.ItemsSource = source;
            }
            catch (Exception ex)
            {
                source = new List <Item>();

                foreach (var feedItem in items)
                {
                    var urls = Regex.Matches(feedItem.Description, @"(http|ftp|https):\/\/([\w\-_]+(?:(?:\.[\w\-_]+)+))([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?");

                    var itm = new Item()
                    {
                        FeedItem = feedItem,
                        Image    = urls.FirstOrDefault()?.Value
                    };

                    foreach (var feed in feeds)
                    {
                        if (feed.Result.Items.Contains(feedItem))
                        {
                            itm.Source = feed.Result.Link;
                            break;
                        }
                    }

                    source.Add(itm);
                }

                News.ItemsSource = source;
            }

            News.ScrollTo(source.First(), ScrollToPosition.Start, false);
            News.IsVisible    = true;
            Loading.IsVisible = false;
        }
Esempio n. 8
0
        /// <summary>
        /// Approach
        /// 1. Generate actions
        /// 2. Generate user contexts
        ///		For each user context
        ///			Get actions
        ///			For each action, calculate a score for the user
        ///				If the top action recommended by the service also has the top like score, send 1 back to the API.
        ///				Variant a: ScoreHalfRewards = false, send back 0 to the API otherwise.
        ///				Variant b: ScoreHalfRewards = true, if the top action recommended by the service has the second-highest like score, send 0.5 back to the API.
        /// </summary>
        /// <param name="endpoint"></param>
        /// <param name="apiKey"></param>
        /// <param name="scoreHalfRewards"></param>
        /// <returns></returns>
        public async Task <List <SegmentScore> > ProcessAsync(string endpoint, string apiKey, bool scoreHalfRewards, int howManyActions, int howManyUserContexts, int howManyUsersPerSegment, int segmentPauseMilliseconds)
        {
            this.HowManyActions           = howManyActions;
            this.HowManyUserContexts      = howManyUserContexts;
            this.HowManyUsersPerSegment   = howManyUsersPerSegment;
            this.SegmentPauseMilliseconds = segmentPauseMilliseconds;

            List <SegmentScore> result = new List <SegmentScore>();

            int overallCounter = 0;

            SegmentScore segmentScore = new SegmentScore();

            segmentScore.Segment = 1;

            using (PersonalizerClient client = InitializePersonalizerClient(endpoint, apiKey))
            {
                // Iterate through each context - i.e. each interaction where we want to get a ranked list of choices
                foreach (var context in UserContexts)
                {
                    overallCounter++;
                    segmentScore.Count++;

                    // Each interaction (context + choices -> ranked choices -> user behavior -> send feedback) requires a unique ID to correlate throughout
                    string eventId = Guid.NewGuid().ToString();

                    var          rankingRequest = new RankRequest(this.Actions, context, null, eventId, false);
                    RankResponse response       = await client.RankAsync(rankingRequest);

                    // These are our calcs for points, for THIS user/context, for each of the actions
                    IDictionary <string, int> actionScoresForContext = this.GetActionScoresForContext(context);

                    // Using THIS user/context's points for each action, calculate a reward based on whether the API "got it right"
                    double reward = CalculateReward(actionScoresForContext, response.RewardActionId, scoreHalfRewards);

                    Console.WriteLine($"Iteration {overallCounter} = reward {reward}");

                    // Send feedback to the API - for this event (ranking interaction), what is the reward we calculated
                    await client.RewardAsync(response.EventId, new RewardRequest(reward));

                    // We are tracking segments of users so we can more clearly track reward accumulation / API performance
                    // Manage this segment's rewards here
                    segmentScore.TotalReward += reward;

                    if (reward > 0)
                    {
                        if (reward == 1)
                        {
                            segmentScore.CountRewardFull++;
                        }
                        else if (reward < 1)
                        {
                            segmentScore.CountRewardHalf++;
                        }
                    }

                    if (segmentScore.Count % this.HowManyUsersPerSegment == 0)
                    {
                        result.Add(segmentScore);

                        int newSegment = segmentScore.Segment + 1;
                        segmentScore = new SegmentScore()
                        {
                            Segment = newSegment
                        };

                        // As we complete each segment of users let's pause for a time to allow the API to retrain
                        // This is artificial so we can watch the API's performance improve in this contrived app
                        // In the real world we wouldn't do this since ongoing usage would be far lengthier than a quick sample app like this
                        if (overallCounter < this.HowManyUserContexts)
                        {
                            Console.WriteLine();
                            Console.WriteLine("Sleeping for service training...");
                            Thread.Sleep(this.SegmentPauseMilliseconds);
                            Console.WriteLine("Completed sleep, continuing");
                            Console.WriteLine();
                        }
                    }
                }
            }

            return(result);
        }
Esempio n. 9
0
        public async Task <ActionResult <RankedRecipes> > GetRecommendations()
        {
            try
            {
                if (!HttpContext.User.Identity.IsAuthenticated)
                {
                    throw new Exception();
                }

                var apiKey          = (await _context.AppSettings.FirstOrDefaultAsync(setting => setting.EnumCode == (int)Enums.AppSetting.PersonalizerApiKey)).Value;
                var serviceEndpoint = (await _context.AppSettings.FirstOrDefaultAsync(setting => setting.EnumCode == (int)Enums.AppSetting.PersonalizerServiceEndpoint)).Value;

                PersonalizerClient client = new PersonalizerClient(new ApiKeyServiceClientCredentials(apiKey))
                {
                    Endpoint = serviceEndpoint
                };

                var idUser = GetUserId();

                var userRecipeTags = await _context.AspNetUserRecipeTag.Where(userTag => userTag.IdUser == idUser)
                                     .Join(
                    _context.RecipeTags,
                    userTag => userTag.IdRecipeTag,
                    tag => tag.Id,
                    (userTag, tag) => tag)
                                     .Join(
                    _context.RecipeTagTypes,
                    tag => tag.IdRecipeTagType,
                    type => type.Id,
                    (tag, type) => new { tag, type }).ToListAsync();

                var userRecipeTagDictionary = userRecipeTags.GroupBy(recipe => recipe.type).ToDictionary(mapping => mapping.Key.EnumCode, mapping => userRecipeTags.Where(tag => tag.type.Id == mapping.Key.Id).Select(tag => tag.tag.Name));

                IList <object> currentContext = new List <object>()
                {
                    new { Cuisine = userRecipeTagDictionary.ContainsKey((int)Shared.Enums.Recipe.RecipeTagType.Cuisine) ? string.Join(',', userRecipeTagDictionary[(int)Shared.Enums.Recipe.RecipeTagType.Cuisine]) : string.Empty },
                    new { Dietary = userRecipeTagDictionary.ContainsKey((int)Shared.Enums.Recipe.RecipeTagType.Dietary) ? string.Join(',', userRecipeTagDictionary[(int)Shared.Enums.Recipe.RecipeTagType.Dietary]) : string.Empty },
                    new { Occasion = userRecipeTagDictionary.ContainsKey((int)Shared.Enums.Recipe.RecipeTagType.Occasion) ? string.Join(',', userRecipeTagDictionary[(int)Shared.Enums.Recipe.RecipeTagType.Occasion]) : string.Empty },
                    new { Meal = userRecipeTagDictionary.ContainsKey((int)Shared.Enums.Recipe.RecipeTagType.Meal) ? string.Join(',', userRecipeTagDictionary[(int)Shared.Enums.Recipe.RecipeTagType.Meal]) : string.Empty },
                    new { Seasonal = userRecipeTagDictionary.ContainsKey((int)Shared.Enums.Recipe.RecipeTagType.Seasonal) ? string.Join(',', userRecipeTagDictionary[(int)Shared.Enums.Recipe.RecipeTagType.Seasonal]) : string.Empty },
                    new { Holiday = userRecipeTagDictionary.ContainsKey((int)Shared.Enums.Recipe.RecipeTagType.Holiday) ? string.Join(',', userRecipeTagDictionary[(int)Shared.Enums.Recipe.RecipeTagType.Holiday]) : string.Empty }
                };

                (IEnumerable <Recipe> recipes, string selectedSearchCriteria) = await GetUserRecipes();

                if (recipes != null)
                {
                    var recipeWithTags = recipes.Join(_context.Recipe_RecipeTags,
                                                      recipe => recipe.Id,
                                                      recipeTagMapping => recipeTagMapping.IdRecipe,
                                                      (recipe, recipeTagMapping) => new { recipe, recipeTagMapping })
                                         .Join(_context.RecipeTags,
                                               recipeTagMapping => recipeTagMapping.recipeTagMapping.IdRecipeTag,
                                               recipeTag => recipeTag.Id,
                                               (recipeTagMapping, recipeTag) => new { recipeTagMapping.recipe, recipeTag })
                                         .Join(_context.RecipeTagTypes,
                                               tag => tag.recipeTag.IdRecipeTagType,
                                               type => type.Id,
                                               (tag, type) => new { tag.recipe, tag.recipeTag, type }).ToList();

                    var recipeWithTagsDictionary   = recipeWithTags.GroupBy(recipe => recipe.recipe).ToDictionary(group => group.Key, group => recipeWithTags.Where(item => item.recipe == group.Key).Select(item => item));
                    IList <RankableAction> actions = recipeWithTagsDictionary.Select(recipe => new RankableAction()
                    {
                        Id       = recipe.Key.Id.ToString(),
                        Features = new List <object>()
                        {
                            new { Cuisine = string.Join(',', recipe.Value.Where(item => item.type.EnumCode == (int)Shared.Enums.Recipe.RecipeTagType.Cuisine).Select(item => item.recipeTag.Name)) },
                            new { Dietary = string.Join(',', recipe.Value.Where(item => item.type.EnumCode == (int)Shared.Enums.Recipe.RecipeTagType.Dietary).Select(item => item.recipeTag.Name)) },
                            new { Occasion = string.Join(',', recipe.Value.Where(item => item.type.EnumCode == (int)Shared.Enums.Recipe.RecipeTagType.Occasion).Select(item => item.recipeTag.Name)) },
                            new { Meal = string.Join(',', recipe.Value.Where(item => item.type.EnumCode == (int)Shared.Enums.Recipe.RecipeTagType.Meal).Select(item => item.recipeTag.Name)) },
                            new { Seasonal = string.Join(',', recipe.Value.Where(item => item.type.EnumCode == (int)Shared.Enums.Recipe.RecipeTagType.Seasonal).Select(item => item.recipeTag.Name)) },
                            new { Holiday = string.Join(',', recipe.Value.Where(item => item.type.EnumCode == (int)Shared.Enums.Recipe.RecipeTagType.Holiday).Select(item => item.recipeTag.Name)) }
                        }
                    }).Take(50).ToList();

                    IList <string> excludeActions = new List <string>();
                    var            eventId        = Guid.NewGuid().ToString();

                    // Rank the actions
                    var          request  = new RankRequest(actions, currentContext, excludeActions, eventId);
                    RankResponse response = await client.RankAsync(request);

                    var rankedRecipes = await GetRecipes(response.Ranking, Convert.ToInt64(response.RewardActionId));

                    return(new RankedRecipes()
                    {
                        EventId = response.EventId,
                        RecommendedRecipeId = Convert.ToInt64(response.RewardActionId),
                        Recipes = rankedRecipes,
                        RecipeSearchCriteria = selectedSearchCriteria
                    });
                }

                return(null);
            }
            catch (Exception)
            {
                return(StatusCode(StatusCodes.Status500InternalServerError, "Error retrieving recipes"));
            }
        }