public CategorizationResult Categorize(Recipe recipe) { var result = new CategorizationResult(); this.CategorizeMeal(recipe, result); this.CategorizeDiet(recipe, result); this.CategorizeNutrition(recipe, result); this.CategorizeSkill(recipe, result); this.CategorizeTaste(recipe, result); return result; }
private void CategorizeDiet(Recipe recipe, CategorizationResult result) { var ingredientMeta = recipe.Ingredients.Select(ing => ing.Ingredient.Metadata).ToArray(); var glutenFree = ingredientMeta.All(ing => ing.HasGluten == false); var noAnimals = ingredientMeta.All(ing => ing.HasAnimal == false); var noMeat = ingredientMeta.All(ing => ing.HasMeat == false); var noPork = ingredientMeta.All(ing => ing.HasPork == false); var noRedMeat = ingredientMeta.All(ing => ing.HasRedMeat == false); result.DietGlutenFree = glutenFree; result.DietNoAnimals = noAnimals; result.DietNoMeat = noMeat; result.DietNoPork = noPork; result.DietNoRedMeat = noRedMeat; }
private void CategorizeMeal(Recipe recipe, CategorizationResult result) { IRecipeClassification trainedRecipe = this.analyzer.GetTrainedRecipe(recipe.Id); if (trainedRecipe != null) { result.MealBreakfast = trainedRecipe.IsBreakfast; result.MealLunch = trainedRecipe.IsLunch; result.MealDinner = trainedRecipe.IsDinner; result.MealDessert = trainedRecipe.IsDessert; } else { var analysis = this.analyzer.GetPrediction(recipe); result.MealBreakfast = analysis.FirstPlace.Equals(Category.Breakfast) || analysis.SecondPlace.Equals(Category.Breakfast); result.MealLunch = analysis.FirstPlace.Equals(Category.Lunch) || analysis.SecondPlace.Equals(Category.Lunch); result.MealDinner = analysis.FirstPlace.Equals(Category.Dinner) || analysis.SecondPlace.Equals(Category.Dinner); result.MealDessert = analysis.FirstPlace.Equals(Category.Dessert) || analysis.SecondPlace.Equals(Category.Dessert); } }
private void CategorizeNutrition(Recipe recipe, CategorizationResult result) { float totalGrams = 0; float totalFat = 0; float totalSugar = 0; float totalCal = 0; float totalSodium = 0; float totalCarbs = 0; var noMatch = false; // First, convert every ingredient to weight foreach (var usage in recipe.Ingredients) { // No amount specified for this ingredient if (usage.Amount == null) { noMatch = true; continue; } var meta = usage.Ingredient.Metadata; if (meta == null) { noMatch = true; continue; } var amount = FormConversion.GetWeightForUsage(usage); if (amount == null) { noMatch = true; continue; // Cannot convert this ingredient to grams, skip it } var grams = amount.SizeHigh; totalGrams += grams; if (!(meta.FatPerUnit.HasValue && meta.SugarPerUnit.HasValue && meta.CaloriesPerUnit.HasValue && meta.SodiumPerUnit.HasValue && meta.CarbsPerUnit.HasValue)) { noMatch = true; } else { totalFat += (meta.FatPerUnit.Value * grams) / 100f; // Total fat per 100g totalSugar += (meta.SugarPerUnit.Value * grams) / 100f; // Total sugar per 100g; totalCal += (meta.CaloriesPerUnit.Value * grams) / 100f; // Total Calories per 100g totalSodium += (meta.SodiumPerUnit.Value * grams) / 100f; // Total sodium per 100g totalCarbs += (meta.CarbsPerUnit.Value * grams) / 100f; // Total carbs per 100g } } result.USDAMatch = !noMatch; // Set to true if every ingredient has an exact USDA match // Set totals result.NutritionTotalFat = (short)totalFat; result.NutritionTotalSugar = (short)totalSugar; result.NutritionTotalCalories = (short)totalCal; result.NutritionTotalSodium = (short)totalSodium; result.NutritionTotalCarbs = (short)totalCarbs; // Flag RecipeMetadata depending on totals in recipe if (!noMatch) { result.NutritionLowFat = totalFat <= (totalCal * 0.03); // Definition of Low Fat is 3g of fat per 100 Cal result.NutritionLowSugar = totalSugar <= (totalCal * 0.02); // There is no FDA definition of "Low Sugar" (Can estimate 2g of sugar per 100 Cal or less) result.NutritionLowCalorie = totalCal <= (totalGrams * 1.2); // Definition of Low Calorie is 120 cal per 100g result.NutritionLowSodium = totalSodium <= (totalGrams * 1.4); // Definition of Low Sodium is 140mg per 100g result.NutritionLowCarb = totalCarbs <= (totalCal * 0.05); // No definition for Low Carb, but we can use 5g per 100 Cal or less } }
private void CategorizeTaste(Recipe recipe, CategorizationResult result) { var totalMass = new Amount(0, Units.Gram); float totalSweet = 0f, totalSpicy = 0f; foreach (var usage in recipe.Ingredients) { if (usage.Amount == null) { continue; } if (usage.Ingredient.Metadata == null) { continue; } var meta = usage.Ingredient.Metadata; var amt = FormConversion.GetWeightForUsage(usage); if (amt == null) { continue; } totalMass += amt; totalSweet += amt.SizeHigh * meta.Sweet; totalSpicy += amt.SizeHigh * meta.Spicy; } if (totalMass.SizeHigh == 0) { return; // Nothing to calc, exit } var maxRating = totalMass.SizeHigh * 4; var recipeSweet = totalSweet / maxRating; // Pct sweet the recipe is var recipeSpicy = totalSpicy / maxRating; // Pct spicy the recipe is result.TasteSavoryToSweet = Convert.ToByte(recipeSweet * 100); // Scale in terms of percentage result.TasteMildToSpicy = Convert.ToByte(recipeSpicy * 100); }
private void CategorizeSkill(Recipe recipe, CategorizationResult result) { // Common: Has 3 or more ingredients and all ingredients are considered "common" result.SkillCommon = recipe.Ingredients.Length >= 3 && recipe.Ingredients.All(i => this.commonIngredients.ContainsKey(i.Ingredient.Id)); result.Commonality = Convert.ToSingle(result.SkillCommon ? recipe.Ingredients.Average(i => this.commonIngredients[i.Ingredient.Id].Commonality) : 0f); // Easy: Has the word "easy" in the title, or (prep <= 15min and ingredients <= 5) result.SkillEasy = recipe.Title.ToLower().Contains("easy") || (recipe.PrepTime <= 15 && recipe.Ingredients.Length <= 5); // Quick: prep <= 10 and cooktime <= 20 result.SkillQuick = recipe.PrepTime <= 10 && recipe.CookTime <= 20; }