"""Per-serving macro estimator — ingredient lookup, no extra model call needed.""" from __future__ import annotations # (calories kcal, protein g, carbs g, fat g, fiber g) per 100 g _MACROS: dict[str, tuple[float, float, float, float, float]] = { # proteins "chicken": (165, 31, 0, 3.6, 0), "beef": (250, 26, 0, 16, 0), "pork": (242, 27, 0, 14, 0), "fish": (130, 20, 0, 5, 0), "salmon": (208, 20, 0, 13, 0), "tuna": (130, 29, 0, 0.5, 0), "shrimp": (99, 24, 0, 0.3, 0), "egg": (155, 13, 1.1, 11, 0), "eggs": (155, 13, 1.1, 11, 0), "tofu": (76, 8, 1.9, 4.8, 0.3), # dairy "milk": (61, 3.2, 4.8, 3.3, 0), "cheese": (402, 25, 1.3, 33, 0), "butter": (717, 0.9, 0.1, 81, 0), "yogurt": (59, 3.5, 4.7, 3.3, 0), "cream": (340, 2.1, 2.8, 36, 0), # starches "rice": (130, 2.7, 28, 0.3, 0.4), "pasta": (158, 5.8, 31, 0.9, 1.8), "bread": (265, 9, 49, 3.2, 2.7), "potato": (77, 2, 17, 0.1, 2.2), "potatoes": (77, 2, 17, 0.1, 2.2), "flour": (364, 10, 76, 1, 2.7), "oats": (389, 17, 66, 7, 10.6), "quinoa": (120, 4.1, 21, 1.9, 2.8), "lentils": (116, 9, 20, 0.4, 7.9), "beans": (347, 21, 60, 1.2, 15), "chickpeas": (164, 8.9, 27, 2.6, 7.6), # vegetables "tomato": (18, 0.9, 3.9, 0.2, 1.2), "tomatoes": (18, 0.9, 3.9, 0.2, 1.2), "onion": (40, 1.1, 9.3, 0.1, 1.7), "onions": (40, 1.1, 9.3, 0.1, 1.7), "garlic": (149, 6.4, 33, 0.5, 2.1), "carrot": (41, 0.9, 10, 0.2, 2.8), "carrots": (41, 0.9, 10, 0.2, 2.8), "broccoli": (34, 2.8, 7, 0.4, 2.6), "spinach": (23, 2.9, 3.6, 0.4, 2.2), "pepper": (31, 1, 6, 0.3, 2.1), "peppers": (31, 1, 6, 0.3, 2.1), "mushroom": (22, 3.1, 3.3, 0.3, 1), "mushrooms": (22, 3.1, 3.3, 0.3, 1), "zucchini": (17, 1.2, 3.1, 0.3, 1), "corn": (86, 3.3, 19, 1.4, 2.7), "lettuce": (15, 1.4, 2.9, 0.2, 1.3), "cucumber": (16, 0.7, 3.6, 0.1, 0.5), "eggplant": (25, 1, 5.9, 0.2, 3), "cabbage": (25, 1.3, 5.8, 0.1, 2.5), "celery": (16, 0.7, 3, 0.2, 1.6), "leek": (61, 1.5, 14, 0.3, 1.8), # fruits "apple": (52, 0.3, 14, 0.2, 2.4), "banana": (89, 1.1, 23, 0.3, 2.6), "lemon": (29, 1.1, 9.3, 0.3, 2.8), "lime": (30, 0.7, 10.5, 0.2, 2.8), "orange": (47, 0.9, 12, 0.1, 2.4), # fats & condiments "olive oil": (884, 0, 0, 100, 0), "oil": (884, 0, 0, 100, 0), "soy sauce": (53, 8.1, 4.9, 0.1, 0.8), "honey": (304, 0.3, 82, 0, 0.2), "sugar": (387, 0, 100, 0, 0), "salt": (0, 0, 0, 0, 0), "vinegar": (18, 0, 0.9, 0, 0), } # Typical portion weight per ingredient (grams) _GRAMS: dict[str, int] = { "egg": 50, "eggs": 100, "butter": 15, "olive oil": 14, "oil": 14, "soy sauce": 15, "salt": 3, "garlic": 10, "honey": 21, "sugar": 12, "lemon": 30, "lime": 30, } _DEFAULT_GRAMS = 80 def compute_nutrition(ingredients: list[str], servings: int = 2) -> dict[str, float]: """Return per-serving macro estimates keyed to the NutritionGrid format.""" cal = prot = carb = fat = fib = 0.0 for ing in ingredients: key = ing.lower().strip() row = _MACROS.get(key) or _MACROS.get(key.split()[0]) if key else None if row is None: continue grams = _GRAMS.get(key, _DEFAULT_GRAMS) f = grams / 100 c, p, cb, ft, fb = row cal += c * f prot += p * f carb += cb * f fat += ft * f fib += fb * f sv = max(servings, 1) return { "calories": round(cal / sv), "protein_g": round(prot / sv, 1), "carbs_g": round(carb / sv, 1), "fat_g": round(fat / sv, 1), "fiber_g": round(fib / sv, 1), }