Source: site.view [edit]
Function name: guessFoodClassification
Arguments: dish,ingredients,cuisineStyle
Description:
Page type: webl
Render function:  
Module: global

Page source:

// ************************************************************
// WineCom.webl
//   Encapsulates Wine.com's APIs
//
// Implemented Functions:
//     guessFoodClassification(Ingredients, Dish)
//     findWineRecommendation(FoodClassification)
//
// Author: Adam Cheyer
// ************************************************************

// Structure representing foodType, Ingredients, and Styles, with some keywords to help guessing
var winePairingData = `foodType, 3008, Meat, meat
    ingredient, 3015, Beef, steak
    style, 3019, Herbs, herb
    style, 3020, Hot Spices, spice|chili powder|chili
    style, 3021, Mushroom, mushrooms
    style, 3022, Stew, stew
    style, 3023, BBQ, barbecue
    style, 3024, Burgers, hamburger|burger
    ingredient, 3016, Lamb, lamb
    style, 3025, Herbs, herb
    style, 3026, Hot Spices, spice|chili powder|chili
    ingredient, 3017, Pork, pig
    style, 3027, Herbs, herb
    style, 3028, Hot Spices, spice|chili powder|chili
    style, 3029, Mushroom, mushrooms
    style, 3030, Sausage, sausage
    style, 3031, Tenderloin, loin
    style, 3032, BBQ, barbecue
    style, 3033, Breaded, breadcrumbs
    style, 3034, Fruit, fruit|apple
    ingredient, 3018, Veal, veal
    style, 3035, Herbs, herb
    style, 3036, Lemon/Citrus, lemon|orange
    style, 3037, Mushroom, mushrooms
    style, 3038, Breaded, breadcrumbs
    style, 3039, Chops, chop
    foodType, 3009, Cheese, frommage
    ingredient, 3040, Blue, blue
    ingredient, 3041, Cheddar, cheddar
    ingredient, 3042, Creamy, creamcheese
    ingredient, 3043, Goat, goat
    ingredient, 3044, Hard, firm
    ingredient, 3045, Semi-Firm, semifirm
    ingredient, 3046, Stinky, smelly
    foodType, 3010, Dessert, dessert
    ingredient, 3047, Berries, strawberries|raspberries
    ingredient, 3048, Chocolate, chocolate
    ingredient, 3049, Cream or Custard, cream|custard
    ingredient, 3050, Lemon, lemon|lime
    foodType, 3012, Pasta & Grains, pasta|noodles|spaghetti|penne|lasagna|lasagne
    ingredient, 3055, Lasagne, lasagna|lasagne|italian
    style, 3060, Meat, meat sauce|bolognese|hamburger|sausage
    style, 3061, Vegetable, vegetables
    ingredient, 3056, Paella, paella
    ingredient, 3057, Pasta,pasta|noodles|spaghetti|penne|italian
    style, 3067, Meat, meat sauce|bolognese
    style, 3068, Mushroom, mushrooms
    style, 3069, Pesto, pesto
    style, 3070, Tomato-base, tomato|bolognese
    style, 3071, Vegetable, vegetables
    style, 3072, White Sauce/Seafood, flour|seafood|fish
    style, 3073, Cream-Based, cream
    ingredient, 3058, Pizza, pizza
    style, 3062, Meat, sausage|hamburger|american
    style, 3063, Vegetable, vegetables|onions|pepper
    ingredient, 3059, Risotto, risotta
    style, 3064, Mushroom, mushrooms
    style, 3065, Plain, plain
    style, 3066, Primavera, primavera
    foodType, 3013, Poultry, poultry
    ingredient, 3074, Cassoulet, cassoulet
    ingredient, 3075, Chicken, chicken
    style, 3078, Herbs, herb
    style, 3079, Lemon/Citrus, lemon|citrus
    style, 3080, Mushroom, mushrooms
    style, 3081, Mustard, mustard
    style, 3082, Spicy, spice
    style, 3083, BBQ, barbecue
    style, 3084, Cream-Based, cream
    style, 3085, Fried, fried
    ingredient, 3076, Duck, canard|french
    style, 3086, Seared, sear
    style, 3087, Confit, confit
    style, 3088, Fois Gras, fois gras
    style, 3089, Fruit, fruit
    ingredient, 3077, Turkey, turkey
    style, 3090, Lemon/Citrus, lemon|citrus
    style, 3091, Roasted, roast
    style, 3092, Breaded, breadcrumbs
    foodType, 3014, Seafood, seafood|fish
    ingredient, 3093, Crab, crab
    style, 3102, Soft Shelled, shell|shelled
    style, 3103, Spicy, spice
    style, 3104, Butter, butter
    style, 3105, Crab Cakes, crab cakes
    ingredient, 3094, Lobster, lobster
    style, 3106, Butter, butter
    ingredient, 3095, Oysters, oyster
    ingredient, 3096, Salmon, salmon
    style, 3107, Herbs, herb
    style, 3108, Mustard, mustard
    style, 3109, Grilled, grill
    ingredient, 3097, Scallops, scallop
    style, 3110, Herbs, herb
    style, 3111, Lemon/Citrus, lemon|citrus
    style, 3112, Butter, butter
    ingredient, 3098, Shrimp, shrimp
    style, 3113, Lemon/Citrus, lemon|citrus
    style, 3114, Herbs, herb
    ingredient, 3099, Sushi, sushi
    ingredient, 3100, Tuna, tuna|ahi
    style, 3115, Seared, seared
    style, 3116, Spicy, spice
    ingredient, 3101, White Fish, white fish
    style, 3117, Herbs, herb
    style, 3118, Hot Spices, spice
    style, 3119, Lemon/Citrus, lemon|citrus
    style, 3120, Stew, stew
    style, 3121, Fish Tacos, tacos|mexican
    style, 3122, Fried, fried
`;

var lines = Str_Split(winePairingData, "\n");
var count = 0;


// ------------------------------------------------------------
// Parse the ingredient data and build a representative structure
// ------------------------------------------------------------
var buildStructure = fun(itemType, exitList)
   var res = [];
   var last = nil;
   var obj = nil;
   while (count < Size(lines)) do
      var cols = Str_Split(lines[count], ",");
      last = obj;
      obj = [. type=Str_Trim(cols[0]), id=Str_Trim(cols[1]), name=Str_Trim(cols[2]), synonyms=(Str_Split(Str_Trim(cols[3]), "|")?nil) .];
      count = count + 1;

      if (obj.type == itemType) then
         res = res + [obj]
      else
         if (obj.type member exitList) then
            count = count - 1;
            return res
         end;
         count = count - 1;
         last.children := buildStructure(obj.type, [itemType] + exitList);
      end;
   end;
   return res
end;



// ------------------------------------------------------------
// Checks whether current foodClassification is a match for ingredients list
// ------------------------------------------------------------
var matchesIngredients = fun(obj, ingredients)
   var ok = Str_ToLowerCase(obj.name) member ingredients;
   if !ok and (obj.synonyms != nil) then
      every syn in obj.synonyms do
         ok = ok or (Str_ToLowerCase(Str_Trim(syn)) member ingredients)
      end;
   end;
   return ok
end;

// ------------------------------------------------------------
// Returns a list of matching Classifications for a list of ingredients
// returns count=N, path=...
// ------------------------------------------------------------
var bestMatch = fun(ingredients, struc)
   var res = [];
   every obj in struc do
       var cnt = 0;
       if matchesIngredients(obj, ingredients) then
          if obj.type == "ingredient" then
             cnt = 5
          elsif obj.type == "foodType" then
             cnt = 7
          else
             cnt = 1
          end;
          res = res + [ [. count=cnt, path=obj.name .] ];
       end;
       var c = obj.children ? nil;
       if c != nil then
          every match in bestMatch(ingredients, c) do
             res = res + [ [. count = cnt + match.count, path = obj.name + "," + match.path .] ];
          end
       end
   end;
   return res
end;


// ------------------------------------------------------------
// Given a dish name and it's list of ingredients, try to guess
//   which would be the best food classification.
// ------------------------------------------------------------
var callGuessFoodClassification = fun(dish, ingredients, cuisine)

   if (Size(ingredients) == 1) and (dish == nil) then
      dish = ingredients[0]
   end;
                                                                                               
   if (cuisine != nil) and (dish == nil) then
      dish = cuisine
   end;
                                                                                               

   var res = [];
   var structure = buildStructure("foodType", []);

   if (dish != nil) then
      every word in Str_Split(dish, " ") do
         ingredients = ingredients + [ Str_ToLowerCase(Str_Trim(word)) ]
      end
   end;
                                                                                               
   if (cuisine != nil) then
      ingredients = ingredients + [ Str_ToLowerCase(Str_Trim(cuisine)) ]
   end;
                                                                                               
   if (dish != nil) then
      res = [ [. dish = dish .] ];
   end;                                                                                               

   var match = Sort(bestMatch(ingredients, structure),
        fun(a, b)
           var diff = a.count - b.count;
           if diff > 0 then -1
           elsif diff == 0 then 0
             else 1
           end
        end);

   PrintLn("Matches: " + ToString(match));

   if Size(match) > 0 then
      var cols = Str_Split(match[0].path, ",");
      var type = cols[0] ? nil;
      var ingredient = cols[1] ? nil;
      var style = cols[2] ? nil;
      res = [[. dish = ToString(dish), foodType = cols[0] .]];
      if (ingredient != nil) then
         res[0].ingredient := ingredient
      end;
      if (style != nil) then
         res[0].style := style
      end;
   end;
   res;
end;


// ------------------------------------------------------------
// Implements guessFoodClassification function
//   Inputs:  dish, ingredients
//   Outputs: foodClassfication
// ------------------------------------------------------------
var guessFoodClassification = fun(dish, ingredients, cuisineStyle)
    var res = [];
    if Stringp(ingredients) then
       ingredients = [ ingredients ]
    end;                                                                                              
    if (ingredients == nil) and (dish != nil) then
       ingredients = []
    end;                                                                                         
    if (ingredients != nil) then
       res = callGuessFoodClassification(dish, ingredients, cuisineStyle);
    end;
    return res
end;
                                                                                               
var CleanArg = fun(a)                                                                                               
   if Str_StartsWith(a, `\[`) then
      a = WubEval(a);
   elsif a == "nil" or a == "" then
      a = nil                                                                                               
   else
      if Str_StartsWith(a, `"`) and Str_EndsWith(a, `"`) then
         a = Select(a, 1, Size(a) - 2)                                                                                               
      end;
   end;                                                                                               
   return a                                                                                               
end;

var res = guessFoodClassification(CleanArg(dish), CleanArg(ingredients), CleanArg(cuisineStyle));
NewPage(WubCall("toJSON", [res]), "text/plain");