Recipe Search
POST
https://api.whisk.com/recipe/v2/search
Request Body
200 This will return a collection of recipes objects (see Recipe Data section for more information).
Copy {
"data" : [
{
"content" : {
"id" : "97f77cceca5d11e7ae7e42010a9a0035" ,
"name" : "Quick coronation chicken sandwich" ,
"description": "Use leftover roast chicken to make a delicious coronation chicken sandwich ready to pack in your lunchbox.",
"images" : [
{
"url": "http://cdnwp.audiencemedia.com/wp-content/uploads/2015/01/478091-1-eng-GB_coronation-chick-sandwich-470x540.jpg",
"responsive" : {
"url": "https://lh3.googleusercontent.com/crjY_vyxK8kdBYYBd6VVtlGwIXuG3pn9DuCSWP4-_VtURbrYfpKPrYDMmrlCwc8kqSAsgCBtjhqU2C7PEjU0wMDh4FSK",
"width" : 470 ,
"height" : 540
}
} ,
...
] ,
"source" : {
"name" : "deliciousmagazine.co.uk" ,
"displayName" : "delicious. magazine" ,
"sourceRecipeUrl" : "http://www.deliciousmagazine.co.uk/recipes/quick-coronation-chicken-sandwich/" ,
"license" : "Fairuse" ,
"image" : {
"url": "https://res.cloudinary.com/whisk/image/upload/v1401879186/content/publisher_logos/delicious-magazine-logo.png",
"responsive" : {
"url": "https://res.cloudinary.com/whisk/image/upload/v1401879186/content/publisher_logos/delicious-magazine-logo.png",
"width" : 200 ,
"height" : 200
}
}
} ,
"author" : {
"name" : "Author name" ,
"image" : {
"url": "https://whisk-res.cloudinary.com/image/upload/v1523894700/custom_upload/ba4d7363cd46c736675d2cc08754f5bc.png",
"responsive" : {
"url": "https://whisk-res.cloudinary.com/image/upload/v1523894700/custom_upload/ba4d7363cd46c736675d2cc08754f5bc.png",
"width" : 800 ,
"height" : 800
}
}
} ,
"numberOfServings" : 1 ,
"labels" : {
"mealType" : [] ,
"cuisine" : [] ,
"category" : [
{
"name" : "quick-and-easy" ,
"displayName" : "Quick and easy"
}
]
}
} ,
"matchedIngredients" : [
{
"name" : "meat"
} ,
{
"name" : "bread"
}
]
} ,
{
"content" : {
...
}
}
] ,
"paging" : {
"cursors" : {
"after" : "eyJpZCI6ImNhZjVlOWY3Y2YxNzFkYjBmZTdkYjJmOTM4M2M0ZDIzIiwiaW5kZXgiOjF9"
} ,
"total" : 1300
}
Logic for A/B was temporarily disabled. It could be enabled again by request
Internal logic on whisk back-end was updated for this endpoint. Implicit profile functionality and A/B test were implemented.
For ST Cooking user_id
for which embeddings were uploaded, search results will be generated by elastic Search according to corresponded embedding.
A/B test was added on the BE. Users splitted by murmurHash2 (64)
into 2 groups:
Provide results with implicit profile functionality
Provide results without implicit profile functionality
So for first group embeddings should be added for only first group while call method = 'whisk.api.recipe.v2.RecipeAPI/SearchRecipes'
The Search API accepts a query object that looks similar to this:
Copy {
"query" : "string" ,
"language" : "string" ,
"country" : "string" ,
"min_ingredients_should_match" : 0 ,
"max_time_in_minutes" : 0 ,
"min_health_score" : 0 ,
"ordering" : "ORDERING_INVALID" ,
"has_instructions" : true ,
"paging" : {
...
} ,
"labels" : [
...
] ,
"exclude_ingredients" : {
...
} ,
"include_ingredients" : {
...
} ,
"glycemic_filter" : {
...
} ,
"nutrition" : [
...
] ,
"fields" : [
...
] ,
"custom_labels" : {
...
} ,
"apply_implicit_preferences" : true
}
It is made up of the following attributes:
In addition to the base attributes, there are additional objects that contain more detailed information on the search parameters.
Paging
Copy "paging" : {
"limit" : 0,
"cursors" : {
"after" : "string" ,
"before" : "string"
}
},
Labels
Copy "labels" : [
{
"label" : {
"diet" : "DIET_INVALID" ,
"category" : "CATEGORY_INVALID" ,
"avoidance" : "AVOIDANCE_INVALID" ,
"cuisine" : "CUISINE_INVALID" ,
"meal_type" : "MEAL_TYPE_INVALID" ,
"nutrition" : "NUTRITION_INVALID" ,
"feature" : "string" ,
"holiday" : "HOLIDAY_INVALID" ,
"seasonality" : "SEASONALITY_INVALID"
},
"boost" : true
}
],
Exclude Ingredients
Copy "exclude_ingredients" : {
"list" : [
"string"
]
},
Include Ingredients
Copy "include_ingredients" : {
"list" : [
"string"
]
},
Glycemic Filter
Copy "glycemic_filter" : {
"glycemic_index" : 0,
"glycemic_load_total" : 0,
"glycemic_load_serving" : 0
},
Nutrition
Allow to use numeric values of
Energy - NUTRITION_ENERGY
Proteine - NUTRITION_PROTEINE
Carbohydrate - NUTRITION_CARBOHYDRATE
Values can set by using gt
,lt
,gte
,lte
expressions, for example:
Copy "nutrition" : [
{
"nutrition" : "NUTRITION_ENERGY" ,
"condition" : "CONDITION_GTE" ,
"value" : 50.0000000000001
} ,
{
"nutrition" : "NUTRITION_ENERGY" ,
"condition" : "CONDITION_LTE" ,
"value" : 100.1
}
]
Ordering
Copy "ordering" : "ORDERING_INVALID" ,
Fields
Copy "fields" : [
"RECIPE_FIELD_INVALID"
],
Custom Labels
Copy "custom_labels" : {
"everywhere" : {
"in" : [
{
"group" : "string" ,
"label" : "string"
}
],
"boost_in" : [
{
"group" : "string" ,
"label" : "string"
}
]
},
"in_recipe" : {
"in" : [
{
"group" : "string" ,
"label" : "string"
}
],
"boost_in" : [
{
"group" : "string" ,
"label" : "string"
}
]
},
"in_ingredients" : {
"in" : [
{
"group" : "string" ,
"label" : "string"
}
],
"boost_in" : [
{
"group" : "string" ,
"label" : "string"
}
]
},
"in_instruction_steps" : {
"in" : [
{
"group" : "string" ,
"label" : "string"
}
],
"boost_in" : [
{
"group" : "string" ,
"label" : "string"
}
]
}
}
Recipes with Full license
Copy "whisk_origin_recipes": true
Apply Implicit Preferences
Field manages search resultes. Two options available: Search results with user's embedding, for users who accepted this type of search in ST app; And regular search results.
Default value: true
Fallback if embedding is not available: regular search results
Copy "apply_implicit_preferences": true
Sample Request
Copy curl -X POST "https://api.whisk.com/recipe/v2/search" \
-H "accept: application/json" \
-H "Authorization: Token <Access-Token>" \
-H "Content-Type: application/json" \
-d "{ \"language\": \"en\", \"paging\" : {\"limit\": 2}}"
Use-case request examples
Boost recipes by certain device, technique, ingredient
Using recipe labels to search or boost recipes will now also take intents set for this recipe into account. I.e. if a recipe has intents for an oven and search is performed with "device": "DEVICE_OVEN"
, the recipe will be boosted.
Copy curl -X POST "https://api.whisk.com/recipe/v2/search" \
-H "accept: application/json" \
-H "Authorization: Token <Access-Token>" \
-H "Content-Type: application/json" \
-d '{
"language": "ko",
"country": "KR",
"labels": [
{
"label": {
"device": "DEVICE_OVEN"
},
"boost": true
},
{
"label": {
"technique": "TECHNIQUE_GRILLING"
},
"boost": true
}
],
"include_ingredients": {
"list": [
"Beef Tenderloin"
]
},
"min_ingredients_should_match": 0
}'
Search recipe with certain device intents
Note: recipes AI identified to be suitable for cooking with a device will also be returned, currently there's no way to search recipes strictly with intents defined
You may find the complete list of devices supported in search on API definition page under the section request body
-> model
-> labels
-> device
or in whisk.api.shared.v1.Device
model
Copy curl -X POST "https://api.whisk.com/recipe/v2/search" \
-H "accept: application/json" \
-H "Authorization: Token <Access-Token>" \
-H "Content-Type: application/json" \
-d '{
"language": "ko",
"country": "KR",
"labels": [
{
"label": {
"device": "DEVICE_PRESSURE_COOKER"
},
"boost": false
}
],
"fields": [
" RECIPE_FIELD_INSTRUCTIONS", "RECIPE_FIELD_INSTRUCTION_INTENTS"
],
}'
Note: the instructions.steps.intents
field is deprecated and will not be extended.
You will find intents in instructions.steps.instruction_intents.attributes
field. Each intent comes as an object with following fields
equipment_action
- describes what equipment and in what mode is going to be used (utensils like frying pan does not have modes or attributes at all)
attributes
- the conditions to be used when cooking, the list may be empty which usually means until user stops the program on her own
The complete list of supported equipment, modes and attributes can be found inside whisk.api.recipe.v2.Intents
model
e.g.
Copy ...
"instructions": {
"steps": [
{
"text": "After chicken is 'well-boiled' (the oil should be floating on top of the frying pan liquid), add the garam masala and turmeric and turn off the heat. Season with salt to taste. Stir all together and serve.",
"intents": [
{
"name": "AirFryer.PreHeating",
"options": [
{
"key": "Temperature",
"value": 200,
"unit": "celsius"
},
{
"key": "Duration",
"value": 10,
"unit": "minute"
}
]
}
],
"instruction_intents": {
"intents": [
{
"attributes": [
{
"temperature": {
"value": {
"plain_value": 200
},
"unit": "UNIT_CELSIUS"
}
},
{
"duration": {
"value": {
"plain_value": 600
},
"unit": "UNIT_SECONDS"
}
}
],
"equipment_action": {
"air_fryer": {
"mode": "MODE_HEAT"
}
}
},
{
"attributes": [
{
"duration": {
"value": {
"plain_value": 600
},
"unit": "UNIT_SECONDS"
}
},
{
"gas": {
"value": {
"plain_value": 3
},
"unit": "UNIT_LEVEL"
}
}
],
"equipment_action": {
"oven": {
"mode": "MODE_GAS"
}
}
},
{
"equipment_action": {
"microwave": {
"mode": "MODE_DEFROST"
}
}
},
{
"attributes": [
{
"speed": {
"value": "LEVEL_MEDIUM",
"unit": "UNIT_LEVEL"
}
},
{
"duration": {
"value": {
"plain_value": 900
},
"unit": "UNIT_SECONDS"
}
}
],
"equipment_action": {
"food_processor": {
"mode": "MODE_PREPARE"
}
}
},
{
"attributes": [
{
"duration": {
"value": {
"plain_value": 600
},
"unit": "UNIT_SECONDS"
}
}
],
"equipment_action": {
"pressure_cooker": {
"mode": "MODE_MULTIGRAIN"
}
}
},
{
"attributes": [
{
"duration": {
"value": {
"plain_value": 600
},
"unit": "UNIT_SECONDS"
}
}
],
"equipment_action": {
"slow_cooker": {
"mode": "MODE_KEEPWARM"
}
}
}
]
}
}
]
},
...
Last updated 6 months ago