Collaborama About Help Contact Anonymous [login] Source: site.view [edit] Function name: findWineRecommendation Arguments: foodType,style,ingredient,appellation,varietal,vineyard Description: Page type: webl Render function: Module: global Page source: // ************************************************************ // WineCom.webl // Encapsulates Wine.com's APIs // // Implemented Functions: // 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; // ------------------------------------------------------------ // Format the food classification structure in an indented printout // ------------------------------------------------------------ var PrettyFormat = fun(pre, struc) var res = ""; every obj in struc do res = res + pre + obj.type + ":" + obj.name + "\n"; var c = obj.children ? nil; if c != nil then res = res + PrettyFormat(pre + " ", c) end end; return res end; // ------------------------------------------------------------ // Finds a matching object // ------------------------------------------------------------ var getMatchingObj = fun(path, lst) var n = First(path); every obj in lst do if (obj.name == n) then if Rest(path) == [] then return obj else return getMatchingObj(Rest(path), obj.children) end end end; return nil end; // ------------------------------------------------------------ // Build the correct query link using foodType, ingredient, and style // ------------------------------------------------------------ var ConstructLink = fun(structure, foodType, ingredient, style) var obj = getMatchingObj([ foodType ], structure); var args = "N=7155+" + obj.id; var name = "/V6/Pairing-Wine-With-" + foodType; // this.ActiveFoodType.UrlName; PrintLn("FoodType: " + ToString(foodType) + " Ingredient: " + ToString(ingredient) + " Style: " + ToString(style)); if (ingredient != nil) then obj = getMatchingObj([ foodType, ingredient ], structure); args = "N=7155+" + obj.id; var c = obj.children ? nil; PrintLn("MAT OBJ: " + ToString(obj)); if (c != nil) then name = "/V6/Pairing-Wine-With-" + ingredient; // this.ActiveIngredient.UrlName; else name = "/V6/Pairing-Wine-With-" + ingredient + "-" + foodType; end; if (style != nil) then obj = getMatchingObj([foodType, ingredient, style], structure); PrintLn("MAT OBJ2: " + ToString(obj)); args = "N=7155+" + obj.id; if (obj.type == "style") then name = "/V6/Pairing-Wine-With-" + "-" + ingredient + "-" + style; else name = "/V6/Pairing-Wine-With-" + "-" + ingredient + "-" + foodType; end end; end; return "http://www.wine.com" + name + "/winefoodpairing.aspx?" + args + "&show=true"; end; // ------------------------------------------------------------ // Pulls out textual recommendation description from webpage, // along with a recommended varietal and appellation // ------------------------------------------------------------ var getRecommendation = fun(P) if (P == nil) then return nil end; var recommendation = nil; var varietal = nil; var appellation = nil; var vintage = nil; var wineName = nil; // Pull out description text var i = 0; var D = Elem(P, "div"); while (i < Size(D)) do var id = D[i].id ? nil; if id == "ctl00_BodyContent_ctrResults_pnlMessage" then recommendation = Str_Trim(Text(D[i])); i = 10000 end; i = i + 1; end; // Look for appellation and varietal from one of the recommended bottles of wine i = 0; var A = Elem(P, "a"); while (i < Size(A)) do var id = A[i].id ? nil; if Str_EndsWith(ToString(id),"ctrProduct_hlName") then wineName = Str_Trim(Text(A[i])) ? nil; var m = Str_Match(wineName, `.*(\d\d\d\d)`) ? nil; vintage = (m[1] ? nil); if (wineName != nil and recommendation != nil) then recommendation = recommendation + ".\n\nExemplar: " + wineName; end end; if Str_EndsWith(ToString(id),"ctrProduct_lnkVarietal") then varietal = Str_Trim(Text(A[i])); end; if Str_EndsWith(ToString(id),"lnkAppellation") then appellation = Str_Trim(Text(A[i])); end; if (varietal != nil and appellation != nil) then i = 10000 end; i = i + 1; end; if (recommendation != nil) then return [. recommendation = recommendation, varietal = varietal, appellation = appellation, vintage=vintage, wineItemName = wineName .] else return nil end end; // ------------------------------------------------------------ // Check if an incoming command line argument (string) is nil // ------------------------------------------------------------ var checkNil = fun(arg) if arg == "nil" or arg == "" then arg = nil end; return arg; end; // ------------------------------------------------------------ // Implements findWineRecommendation function // Inputs: FoodClassification (foodType, ingredient, style) // Outputs: wineRecommendation (description: string) // ------------------------------------------------------------ var findWineRecommendation = fun(foodType, style, ingredient, appellation, varietal, vineyard) foodType = checkNil(foodType); style = checkNil(style); ingredient = checkNil(ingredient); appellation = checkNil(appellation); varietal = checkNil(varietal); vineyard = checkNil(vineyard); if (foodType != nil) then var structure = buildStructure("foodType", []); // PrettyFormat("", structure); var link = ConstructLink(structure, foodType, ingredient, style); //PrintLn("Getting URL for wine recommendation: " + link); link = Wub_ReplaceAll(link, " ", "%20"); var P = GetURL(link) ? nil; var rec = getRecommendation(P); //PrintLn("Recommendation: " + ToString(rec)); if (rec != nil) then var showIt = true; if (appellation != nil and (Str_ToLowerCase(appellation) != Str_ToLowerCase(rec.appellation))) then showIt = false; //PrintLn("FAILED COMPARISON: '" + varietal + "' and '" + rec.varietal + "'"); end; if (varietal != nil and (Str_ToLowerCase(varietal) != Str_ToLowerCase(rec.varietal))) then showIt = false; //PrintLn("FAILED COMPARISON: '" + varietal + "' and '" + rec.varietal + "'"); end; if (vineyard != nil) then showIt = false; //PrintLn("FAILED COMPARISON: '" + vineyard + "'"); end; if (showIt) then return [[. description=rec.recommendation, appellation=rec.appellation, varietal=rec.varietal, wineItemName=rec.wineItemName, vintage=rec.vintage .]]; else return [] end else return [] end else return [] end end; var res = findWineRecommendation(foodType, style, ingredient, appellation, varietal, vineyard); NewPage(WubCall("toJSON", [res]), "text/plain");