import requests import json import os from dataclasses import dataclass from typing import List READ_KEY_FROM_FILE = True def read_json_to_dict(file_path) -> dict: try: with open(file_path, 'r') as file: data = json.load(file) return data except FileNotFoundError: print("File not found at the specified path.") return {} except json.JSONDecodeError: print("Error decoding JSON file.") return {} DietChoices = [ None, "balanced", "high-fiber", "high-protein", "low-carb", "low-fat", "low-sodium"] HealthChoices = [ None, "alcohol-cocktail", "alcohol-free", "celery-free", "crustacean-free", "dairy-free", "DASH", "egg-free", "fish-free", "fodmap-free", "gluten-free", "immuno-supportive", "keto-friendly", "kidney-friendly", "kosher", "low-fat-abs", "low-potassium", "low-sugar", "lupine-free", "Mediterranean", "mollusk-free", "mustard-free", "no-oil-added", "paleo", "peanut-free", "pescatarian", "pork-free", "red-meat-free", "sesame-free", "shellfish-free", "soy-free", "sugar-conscious", "sulfite-free", "tree-nut-free", "vegan", "vegetarian", "wheat-free"] CuisineTypeChoices = [ None, "American", "Asian", "British", "Caribbean", "Central Europe", "Chinese", "Eastern Europe", "French", "Indian", "Italian", "Japanese", "Kosher", "Mediterranean", "Mexican", "Middle Eastern", "Nordic", "South American", "South East Asian"] MealTypeChoices = [ None, "Breakfast", "Dinner", "Lunch", "Snack", "Teatime"] ParamQueryString = [ {"param": 'calories', "param_query_string": 'calories'}, {"param": 'protein', "param_query_string": 'nutrients[PROCNT]'}, {"param": 'carbs', "param_query_string": 'nutrients[CHOCDF.net]'}, {"param": 'fat', "param_query_string": 'nutrients[FAT]'}, {"param": 'added_sugar', "param_query_string": 'nutrients[SUGAR.added]'}, {"param": 'sodium', "param_query_string": 'nutrients[NA]'}, {"param": 'saturated_fat', "param_query_string": 'nutrients[FASAT]'}, {"param": 'fiber', "param_query_string": 'nutrients[FIBTG]'}, ] @dataclass class Recipe: name: str cuisine_type: list calories: int protein_g: int carbs_g: int fat_g: int servings: int ingredients: list edamam_url: str source_url: str def get_param_query_string(param, param_query_string_list) -> str: for item in param_query_string_list: if item['param'] == param: return item['param_query_string'] return "" def update_params(params, param_to_update, min_val, max_val): param_query_string = get_param_query_string(param_to_update, ParamQueryString) if not bool(param_query_string): print("Error: could not update params") return if min_val!=None and max_val==None: params.update({param_query_string: f"{str(min_val)}+"}) if min_val==None and max_val!=None: params.update({param_query_string: f"{str(max_val)}"}) if min_val!=None and max_val!=None: params.update({param_query_string: f"{str(min_val)}-{str(max_val)}"}) def get_recipes( edamam_app_id: str, edamam_app_key: str, calories_min: float | None = None, calories_max: float | None = None, protein_min_g: float | None = None, protein_max_g: float | None = None, carbs_min_g: float | None = None, carbs_max_g: float | None = None, fat_min_g: float | None = None, fat_max_g: float | None = None, included: str | None = None, excluded: List[str] | None = None, added_sugar_min_g: float | None = None, added_sugar_max_g: float | None = None, sodium_min_mg: float | None = None, sodium_max_mg: float | None = None, saturated_fat_min_g: float | None = None, saturated_fat_max_g: float | None = None, fiber_min_g: float | None = None, fiber_max_g: float | None = None, cuisine_type: List[str] | None = None, meal_type: List[str] | None = None, diet: List[str] | None = None, health: List[str] | None = None, nb_recipes: int = 1, ) -> list: if not edamam_app_id or not edamam_app_key: return [] params = { 'type': 'any', 'app_id': edamam_app_id, 'app_key': edamam_app_key, 'calories': f"{str(calories_min)}-{str(calories_max)}", 'q': included, 'excluded': excluded, 'diet': diet, 'health': health, 'cuisineType': cuisine_type, 'mealType': meal_type, } update_params(params, 'calories', calories_min, calories_max) update_params(params, 'protein', protein_min_g, protein_max_g) update_params(params, 'carbs', carbs_min_g, carbs_max_g) update_params(params, 'fat', fat_min_g, fat_max_g) update_params(params, 'added_sugar', added_sugar_min_g, added_sugar_max_g) update_params(params, 'sodium', sodium_min_mg, sodium_max_mg) update_params(params, 'saturated_fat', saturated_fat_min_g, saturated_fat_max_g) update_params(params, 'fiber', fiber_min_g, fiber_max_g) """Get raw recipes from edamam""" response = requests.get(url='https://api.edamam.com/api/recipes/v2', params=params) """Convert to list of Recipe objects""" recipes = [] if response.status_code == 200: results = response.json()['hits'] if results: for item in results: if (len(recipes) < nb_recipes): recipe = item['recipe'] servings = int(recipe['yield']) recipes.append( Recipe( name=recipe['label'], cuisine_type=recipe['cuisineType'], calories=round(recipe['totalNutrients']['ENERC_KCAL']['quantity']/servings), protein_g=round(recipe['totalNutrients']['PROCNT']['quantity']/servings), carbs_g=round(recipe['totalNutrients']['CHOCDF']['quantity']/servings), fat_g=round(recipe['totalNutrients']['FAT']['quantity']/servings), servings=servings, ingredients=recipe['ingredientLines'], edamam_url=recipe['shareAs'], source_url=recipe['url'], ) ) else: break return recipes else: return [] else: print(f"Error {response.status_code}: {response.text}") return [] """Print Recipe object information to string""" def print2string_recipe(recipe: Recipe) -> str: string = f"" if recipe: string += f"********\n" string += f"Recipe: {recipe.name}\n" string += f"Calories: {recipe.calories}kcal\n" string += f"Protein: {recipe.protein_g}g\n" string += f"Carbs: {recipe.carbs_g}g\n" string += f"Fat: {recipe.fat_g}g\n" string += f"Ingredients for {recipe.servings} servings:\n" for ingredient in recipe.ingredients: string += f"- {ingredient}\n" string += f"URL: {recipe.edamam_url}\n" else: string += "No recipe found\n" return string if __name__ == "__main__": if READ_KEY_FROM_FILE: CURRENT_DIR = os.path.dirname(os.path.realpath(__file__)) edamam_app_id = read_json_to_dict(file_path=f"{CURRENT_DIR}/api_key.json")['edamam_app_id'] edamam_app_key = read_json_to_dict(file_path=f"{CURRENT_DIR}/api_key.json")['edamam_app_key'] else: edamam_app_id = input('Enter your edamam app id: ') edamam_app_key = input('Enter your edamam app key: ') """Compute macronutrients in grams from percent""" calories = 700 protein_min_percent = 10 protein_max_percent = 35 carbs_min_percent = 45 carbs_max_percent = 65 fat_min_percent = 10 fat_max_percent = 25 calories_div_100_div_4 = calories / 100.0 / 4.0 calories_div_100_div_9 = calories / 100.0 / 9.0 protein_min_g = round(protein_min_percent * calories_div_100_div_4) protein_max_g = round(protein_max_percent * calories_div_100_div_4) carbs_min_g = round(carbs_min_percent * calories_div_100_div_4) carbs_max_g = round(carbs_max_percent * calories_div_100_div_4) fat_min_g = round(fat_min_percent * calories_div_100_div_9) fat_max_g = round(fat_max_percent * calories_div_100_div_9) recipes = get_recipes( edamam_app_id=edamam_app_id, edamam_app_key=edamam_app_key, calories_min=None, calories_max=calories, protein_min_g=protein_min_g, protein_max_g=protein_max_g, carbs_min_g=carbs_min_g, carbs_max_g=carbs_max_g, fat_min_g=fat_min_g, fat_max_g=fat_max_g, included="chicken", excluded=["sesame"], nb_recipes=5) for recipe in recipes: print() print(print2string_recipe(recipe))