From 81de985580734d6c1e3609c6a2afd5f4ea2cfe96 Mon Sep 17 00:00:00 2001 From: Matthias Guillitte Date: Mon, 27 Jul 2026 14:37:05 +0200 Subject: [PATCH] Answer with cooking plan and save edamam API tokens --- cloud/APIs/edamam.py | 895 ++++++++++++++++++++++++++++++++++ cloud/app.py | 16 +- cloud/microwaveCookPlanner.py | 98 ++++ 3 files changed, 1006 insertions(+), 3 deletions(-) create mode 100644 cloud/microwaveCookPlanner.py diff --git a/cloud/APIs/edamam.py b/cloud/APIs/edamam.py index f28e84d..4df7280 100644 --- a/cloud/APIs/edamam.py +++ b/cloud/APIs/edamam.py @@ -1,9 +1,11 @@ import os import requests from typing import Dict, Any, Optional +import json EDAMAM_APP_ID__FOOD = os.getenv("EDAMAM_APP_ID__FOOD", None) EDAMAM_APP_KEY__FOOD = os.getenv("EDAMAM_APP_KEY__FOOD", None) +SAVE_EDAMAM_API_TOKEN = os.getenv("SAVE_EDAMAM_API_TOKEN", False) class EdamamAPI: """Wrapper around Edamam Food Database API 2.0 (Vision & Nutrients)""" @@ -14,6 +16,899 @@ class EdamamAPI: pass def analyze_dish_image(self, image_file_path: str): + if SAVE_EDAMAM_API_TOKEN: + return json.loads(""" + { + "combined": { + "problems": [], + "recipe": { + "calories": 306, + "cautions": [ + "GLUTEN", + "WHEAT", + "MILK", + "SULFITES", + "FODMAP" + ], + "dietLabels": [], + "healthLabels": [ + "EGG_FREE", + "PEANUT_FREE", + "TREE_NUT_FREE", + "SOY_FREE", + "FISH_FREE", + "SHELLFISH_FREE", + "CRUSTACEAN_FREE", + "CELERY_FREE", + "MUSTARD_FREE", + "SESAME_FREE", + "LUPINE_FREE", + "MOLLUSK_FREE", + "ALCOHOL_FREE" + ], + "ingredientLines": [ + "90 g (3 oz) Beef chunks", + "100 g (0.75 cup) Potatoes, cubed", + "40 g (0.33 cup) Carrots, sliced", + "30 g (0.25 cup) Green beans", + "120 g (0.5 cup) Brown gravy or stew sauce", + "Salt and pepper to taste" + ], + "label": "Beef Stew with Vegetables (Frozen Meal)", + "totalDaily": { + "CA": { + "label": "Calcium", + "quantity": 9.808827779627787, + "unit": "%" + }, + "CHOCDF": { + "label": "Carbs", + "quantity": 9.07220373540042, + "unit": "%" + }, + "CHOCDF.net": { + "label": "Carbohydrates (net)", + "quantity": 0.0, + "unit": "g" + }, + "CHOLE": { + "label": "Cholesterol", + "quantity": 20.837056709550403, + "unit": "%" + }, + "ENERC_KCAL": { + "label": "Energy", + "quantity": 13.100053025164515, + "unit": "%" + }, + "FASAT": { + "label": "Saturated", + "quantity": 17.148508115376796, + "unit": "%" + }, + "FAT": { + "label": "Fat", + "quantity": 14.902089676480887, + "unit": "%" + }, + "FE": { + "label": "Iron", + "quantity": 21.951689781236098, + "unit": "%" + }, + "FIBTG": { + "label": "Fiber", + "quantity": 13.858671762525935, + "unit": "%" + }, + "FOLDFE": { + "label": "Folate equivalent (total)", + "quantity": 10.817828789332737, + "unit": "%" + }, + "K": { + "label": "Potassium", + "quantity": 28.904445650775536, + "unit": "%" + }, + "MG": { + "label": "Magnesium", + "quantity": 15.863016599088612, + "unit": "%" + }, + "NA": { + "label": "Sodium", + "quantity": 60.46248, + "unit": "%" + }, + "NIA": { + "label": "Niacin (B3)", + "quantity": 66.37252070251446, + "unit": "%" + }, + "P": { + "label": "Phosphorus", + "quantity": 25.034580972170218, + "unit": "%" + }, + "PROCNT": { + "label": "Protein", + "quantity": 21.91938193709794, + "unit": "%" + }, + "RIBF": { + "label": "Riboflavin (B2)", + "quantity": 73.88477475545037, + "unit": "%" + }, + "THIA": { + "label": "Thiamin (B1)", + "quantity": 84.12049444050538, + "unit": "%" + }, + "TOCPHA": { + "label": "Vitamin E", + "quantity": 12.990953399638641, + "unit": "%" + }, + "VITA_RAE": { + "label": "Vitamin A", + "quantity": 45.87938825251855, + "unit": "%" + }, + "VITB12": { + "label": "Vitamin B12", + "quantity": 113.07016020542191, + "unit": "%" + }, + "VITB6A": { + "label": "Vitamin B6", + "quantity": 90.1530888403073, + "unit": "%" + }, + "VITC": { + "label": "Vitamin C", + "quantity": 35.18207820897409, + "unit": "%" + }, + "VITD": { + "label": "Vitamin D", + "quantity": 13.66228503481425, + "unit": "%" + }, + "VITK1": { + "label": "Vitamin K", + "quantity": 27.534449511962567, + "unit": "%" + }, + "ZN": { + "label": "Zinc", + "quantity": 55.091388643252344, + "unit": "%" + } + }, + "totalNutrients": { + "CA": { + "label": "Calcium", + "quantity": 127.51476113516124, + "unit": "mg" + }, + "CHOCDF": { + "label": "Carbs", + "quantity": 26.573051753721295, + "unit": "g" + }, + "CHOCDF.net": { + "label": "Carbohydrates (net)", + "quantity": 21.30675648396144, + "unit": "g" + }, + "CHOLE": { + "label": "Cholesterol", + "quantity": 73.23964970198097, + "unit": "mg" + }, + "ENERC_KCAL": { + "label": "Energy", + "quantity": 306.9669925121675, + "unit": "kcal" + }, + "FAMS": { + "label": "Monounsaturated", + "quantity": 5.622055495052523, + "unit": "g" + }, + "FAPU": { + "label": "Polyunsaturated", + "quantity": 1.5770619917608195, + "unit": "g" + }, + "FASAT": { + "label": "Saturated", + "quantity": 4.0183241641356675, + "unit": "g" + }, + "FAT": { + "label": "Fat", + "quantity": 11.639773878137946, + "unit": "g" + }, + "FATRN": { + "label": "Trans", + "quantity": 0.24391676668519283, + "unit": "g" + }, + "FE": { + "label": "Iron", + "quantity": 3.9513041606224975, + "unit": "mg" + }, + "FIBTG": { + "label": "Fiber", + "quantity": 5.266295269759856, + "unit": "g" + }, + "FOLAC": { + "label": "Folic acid", + "quantity": 18.024043373983595, + "unit": "\u00b5g" + }, + "FOLDFE": { + "label": "Folate equivalent (total)", + "quantity": 43.271315157330946, + "unit": "\u00b5g" + }, + "FOLFD": { + "label": "Folate (food)", + "quantity": 40.54129806334046, + "unit": "\u00b5g" + }, + "K": { + "label": "Potassium", + "quantity": 982.7511521263683, + "unit": "mg" + }, + "MG": { + "label": "Magnesium", + "quantity": 66.62466971617216, + "unit": "mg" + }, + "NA": { + "label": "Sodium", + "quantity": 906.9372000000001, + "unit": "mg" + }, + "NIA": { + "label": "Niacin (B3)", + "quantity": 10.619603312402313, + "unit": "mg" + }, + "P": { + "label": "Phosphorus", + "quantity": 312.93226215212775, + "unit": "mg" + }, + "PROCNT": { + "label": "Protein", + "quantity": 25.68129586205237, + "unit": "g" + }, + "RIBF": { + "label": "Riboflavin (B2)", + "quantity": 0.9605020718208549, + "unit": "mg" + }, + "SUGAR": { + "label": "Sugars", + "quantity": 8.053516658227332, + "unit": "g" + }, + "SUGAR.added": { + "label": "Sugars, added", + "quantity": 2.3940423830596225, + "unit": "g" + }, + "Sugar.alcohol": { + "label": "Sugar alcohol", + "quantity": 0.0, + "unit": "g" + }, + "THIA": { + "label": "Thiamin (B1)", + "quantity": 1.0094459332860646, + "unit": "mg" + }, + "TOCPHA": { + "label": "Vitamin E", + "quantity": 1.9486430099457963, + "unit": "mg" + }, + "VITA_RAE": { + "label": "Vitamin A", + "quantity": 412.914494272667, + "unit": "\u00b5g" + }, + "VITB12": { + "label": "Vitamin B12", + "quantity": 2.7136838449301255, + "unit": "\u00b5g" + }, + "VITB6A": { + "label": "Vitamin B6", + "quantity": 1.5326025102852243, + "unit": "mg" + }, + "VITC": { + "label": "Vitamin C", + "quantity": 31.66387038807668, + "unit": "mg" + }, + "VITD": { + "label": "Vitamin D", + "quantity": 2.73245700696285, + "unit": "\u00b5g" + }, + "VITK1": { + "label": "Vitamin K", + "quantity": 33.04133941435508, + "unit": "\u00b5g" + }, + "WATER": { + "label": "Water", + "quantity": 321.1285604946806, + "unit": "g" + }, + "ZN": { + "label": "Zinc", + "quantity": 6.060052750757758, + "unit": "mg" + } + }, + "totalWeight": 390.7575715150228, + "translations": [ + { + "id": "EGG_FREE", + "label": "Egg-Free", + "type": "health" + }, + { + "id": "PEANUT_FREE", + "label": "Peanut-Free", + "type": "health" + }, + { + "id": "TREE_NUT_FREE", + "label": "Tree-Nut-Free", + "type": "health" + }, + { + "id": "SOY_FREE", + "label": "Soy-Free", + "type": "health" + }, + { + "id": "FISH_FREE", + "label": "Fish-Free", + "type": "health" + }, + { + "id": "SHELLFISH_FREE", + "label": "Shellfish-Free", + "type": "health" + }, + { + "id": "CRUSTACEAN_FREE", + "label": "Crustacean-Free", + "type": "health" + }, + { + "id": "CELERY_FREE", + "label": "Celery-Free", + "type": "health" + }, + { + "id": "MUSTARD_FREE", + "label": "Mustard-Free", + "type": "health" + }, + { + "id": "SESAME_FREE", + "label": "Sesame-Free", + "type": "health" + }, + { + "id": "LUPINE_FREE", + "label": "Lupine-Free", + "type": "health" + }, + { + "id": "MOLLUSK_FREE", + "label": "Mollusk-Free", + "type": "health" + }, + { + "id": "ALCOHOL_FREE", + "label": "Alcohol-Free", + "type": "health" + }, + { + "id": "GLUTEN", + "label": "Gluten", + "type": "caution" + }, + { + "id": "WHEAT", + "label": "Wheat", + "type": "caution" + }, + { + "id": "MILK", + "label": "Milk", + "type": "caution" + }, + { + "id": "SULFITES", + "label": "Sulfites", + "type": "caution" + }, + { + "id": "FODMAP", + "label": "FODMAP", + "type": "caution" + } + ], + "uri": "http://www.edamam.com/ontologies/edamam.owl#recipe_e59b15e71cd34bf4b7c02c2f545e40f3", + "yield": 1.0 + } + }, + "dishes": [ + { + "problems": [], + "recipe": { + "calories": 306, + "cautions": [ + "GLUTEN", + "WHEAT", + "MILK", + "SULFITES", + "FODMAP" + ], + "dietLabels": [], + "healthLabels": [ + "EGG_FREE", + "PEANUT_FREE", + "TREE_NUT_FREE", + "SOY_FREE", + "FISH_FREE", + "SHELLFISH_FREE", + "CRUSTACEAN_FREE", + "CELERY_FREE", + "MUSTARD_FREE", + "SESAME_FREE", + "LUPINE_FREE", + "MOLLUSK_FREE", + "ALCOHOL_FREE" + ], + "ingredientLines": [ + "90 g (3 oz) Beef chunks", + "100 g (0.75 cup) Potatoes, cubed", + "40 g (0.33 cup) Carrots, sliced", + "30 g (0.25 cup) Green beans", + "120 g (0.5 cup) Brown gravy or stew sauce", + "Salt and pepper to taste" + ], + "label": "Beef Stew with Vegetables (Frozen Meal)", + "totalDaily": { + "CA": { + "label": "Calcium", + "quantity": 9.808827779627787, + "unit": "%" + }, + "CHOCDF": { + "label": "Carbs", + "quantity": 9.07220373540042, + "unit": "%" + }, + "CHOCDF.net": { + "label": "Carbohydrates (net)", + "quantity": 0.0, + "unit": "g" + }, + "CHOLE": { + "label": "Cholesterol", + "quantity": 20.837056709550403, + "unit": "%" + }, + "ENERC_KCAL": { + "label": "Energy", + "quantity": 13.100053025164515, + "unit": "%" + }, + "FASAT": { + "label": "Saturated", + "quantity": 17.148508115376796, + "unit": "%" + }, + "FAT": { + "label": "Fat", + "quantity": 14.902089676480887, + "unit": "%" + }, + "FE": { + "label": "Iron", + "quantity": 21.951689781236098, + "unit": "%" + }, + "FIBTG": { + "label": "Fiber", + "quantity": 13.858671762525935, + "unit": "%" + }, + "FOLDFE": { + "label": "Folate equivalent (total)", + "quantity": 10.817828789332737, + "unit": "%" + }, + "K": { + "label": "Potassium", + "quantity": 28.904445650775536, + "unit": "%" + }, + "MG": { + "label": "Magnesium", + "quantity": 15.863016599088612, + "unit": "%" + }, + "NA": { + "label": "Sodium", + "quantity": 60.46248, + "unit": "%" + }, + "NIA": { + "label": "Niacin (B3)", + "quantity": 66.37252070251446, + "unit": "%" + }, + "P": { + "label": "Phosphorus", + "quantity": 25.034580972170218, + "unit": "%" + }, + "PROCNT": { + "label": "Protein", + "quantity": 21.91938193709794, + "unit": "%" + }, + "RIBF": { + "label": "Riboflavin (B2)", + "quantity": 73.88477475545037, + "unit": "%" + }, + "THIA": { + "label": "Thiamin (B1)", + "quantity": 84.12049444050538, + "unit": "%" + }, + "TOCPHA": { + "label": "Vitamin E", + "quantity": 12.990953399638641, + "unit": "%" + }, + "VITA_RAE": { + "label": "Vitamin A", + "quantity": 45.87938825251855, + "unit": "%" + }, + "VITB12": { + "label": "Vitamin B12", + "quantity": 113.07016020542191, + "unit": "%" + }, + "VITB6A": { + "label": "Vitamin B6", + "quantity": 90.1530888403073, + "unit": "%" + }, + "VITC": { + "label": "Vitamin C", + "quantity": 35.18207820897409, + "unit": "%" + }, + "VITD": { + "label": "Vitamin D", + "quantity": 13.66228503481425, + "unit": "%" + }, + "VITK1": { + "label": "Vitamin K", + "quantity": 27.534449511962567, + "unit": "%" + }, + "ZN": { + "label": "Zinc", + "quantity": 55.091388643252344, + "unit": "%" + } + }, + "totalNutrients": { + "CA": { + "label": "Calcium", + "quantity": 127.51476113516124, + "unit": "mg" + }, + "CHOCDF": { + "label": "Carbs", + "quantity": 26.573051753721295, + "unit": "g" + }, + "CHOCDF.net": { + "label": "Carbohydrates (net)", + "quantity": 21.30675648396144, + "unit": "g" + }, + "CHOLE": { + "label": "Cholesterol", + "quantity": 73.23964970198097, + "unit": "mg" + }, + "ENERC_KCAL": { + "label": "Energy", + "quantity": 306.9669925121675, + "unit": "kcal" + }, + "FAMS": { + "label": "Monounsaturated", + "quantity": 5.622055495052523, + "unit": "g" + }, + "FAPU": { + "label": "Polyunsaturated", + "quantity": 1.5770619917608195, + "unit": "g" + }, + "FASAT": { + "label": "Saturated", + "quantity": 4.0183241641356675, + "unit": "g" + }, + "FAT": { + "label": "Fat", + "quantity": 11.639773878137946, + "unit": "g" + }, + "FATRN": { + "label": "Trans", + "quantity": 0.24391676668519283, + "unit": "g" + }, + "FE": { + "label": "Iron", + "quantity": 3.9513041606224975, + "unit": "mg" + }, + "FIBTG": { + "label": "Fiber", + "quantity": 5.266295269759856, + "unit": "g" + }, + "FOLAC": { + "label": "Folic acid", + "quantity": 18.024043373983595, + "unit": "\u00b5g" + }, + "FOLDFE": { + "label": "Folate equivalent (total)", + "quantity": 43.271315157330946, + "unit": "\u00b5g" + }, + "FOLFD": { + "label": "Folate (food)", + "quantity": 40.54129806334046, + "unit": "\u00b5g" + }, + "K": { + "label": "Potassium", + "quantity": 982.7511521263683, + "unit": "mg" + }, + "MG": { + "label": "Magnesium", + "quantity": 66.62466971617216, + "unit": "mg" + }, + "NA": { + "label": "Sodium", + "quantity": 906.9372000000001, + "unit": "mg" + }, + "NIA": { + "label": "Niacin (B3)", + "quantity": 10.619603312402313, + "unit": "mg" + }, + "P": { + "label": "Phosphorus", + "quantity": 312.93226215212775, + "unit": "mg" + }, + "PROCNT": { + "label": "Protein", + "quantity": 25.68129586205237, + "unit": "g" + }, + "RIBF": { + "label": "Riboflavin (B2)", + "quantity": 0.9605020718208549, + "unit": "mg" + }, + "SUGAR": { + "label": "Sugars", + "quantity": 8.053516658227332, + "unit": "g" + }, + "SUGAR.added": { + "label": "Sugars, added", + "quantity": 2.3940423830596225, + "unit": "g" + }, + "Sugar.alcohol": { + "label": "Sugar alcohol", + "quantity": 0.0, + "unit": "g" + }, + "THIA": { + "label": "Thiamin (B1)", + "quantity": 1.0094459332860646, + "unit": "mg" + }, + "TOCPHA": { + "label": "Vitamin E", + "quantity": 1.9486430099457963, + "unit": "mg" + }, + "VITA_RAE": { + "label": "Vitamin A", + "quantity": 412.914494272667, + "unit": "\u00b5g" + }, + "VITB12": { + "label": "Vitamin B12", + "quantity": 2.7136838449301255, + "unit": "\u00b5g" + }, + "VITB6A": { + "label": "Vitamin B6", + "quantity": 1.5326025102852243, + "unit": "mg" + }, + "VITC": { + "label": "Vitamin C", + "quantity": 31.66387038807668, + "unit": "mg" + }, + "VITD": { + "label": "Vitamin D", + "quantity": 2.73245700696285, + "unit": "\u00b5g" + }, + "VITK1": { + "label": "Vitamin K", + "quantity": 33.04133941435508, + "unit": "\u00b5g" + }, + "WATER": { + "label": "Water", + "quantity": 321.1285604946806, + "unit": "g" + }, + "ZN": { + "label": "Zinc", + "quantity": 6.060052750757758, + "unit": "mg" + } + }, + "totalWeight": 390.7575715150228, + "translations": [ + { + "id": "EGG_FREE", + "label": "Egg-Free", + "type": "health" + }, + { + "id": "PEANUT_FREE", + "label": "Peanut-Free", + "type": "health" + }, + { + "id": "TREE_NUT_FREE", + "label": "Tree-Nut-Free", + "type": "health" + }, + { + "id": "SOY_FREE", + "label": "Soy-Free", + "type": "health" + }, + { + "id": "FISH_FREE", + "label": "Fish-Free", + "type": "health" + }, + { + "id": "SHELLFISH_FREE", + "label": "Shellfish-Free", + "type": "health" + }, + { + "id": "CRUSTACEAN_FREE", + "label": "Crustacean-Free", + "type": "health" + }, + { + "id": "CELERY_FREE", + "label": "Celery-Free", + "type": "health" + }, + { + "id": "MUSTARD_FREE", + "label": "Mustard-Free", + "type": "health" + }, + { + "id": "SESAME_FREE", + "label": "Sesame-Free", + "type": "health" + }, + { + "id": "LUPINE_FREE", + "label": "Lupine-Free", + "type": "health" + }, + { + "id": "MOLLUSK_FREE", + "label": "Mollusk-Free", + "type": "health" + }, + { + "id": "ALCOHOL_FREE", + "label": "Alcohol-Free", + "type": "health" + }, + { + "id": "GLUTEN", + "label": "Gluten", + "type": "caution" + }, + { + "id": "WHEAT", + "label": "Wheat", + "type": "caution" + }, + { + "id": "MILK", + "label": "Milk", + "type": "caution" + }, + { + "id": "SULFITES", + "label": "Sulfites", + "type": "caution" + }, + { + "id": "FODMAP", + "label": "FODMAP", + "type": "caution" + } + ], + "uri": "http://www.edamam.com/ontologies/edamam.owl#recipe_e59b15e71cd34bf4b7c02c2f545e40f3", + "yield": 1.0 + } + } + ] + } + + """) + url = "https://api.edamam.com/api/vision/v1/nutrients" # Query parameters as specified by the YAML schema diff --git a/cloud/app.py b/cloud/app.py index dc714ba..1debd3f 100644 --- a/cloud/app.py +++ b/cloud/app.py @@ -5,6 +5,7 @@ from flask import Flask, request, jsonify from pymongo import MongoClient from APIs import generate, EdamamAPI import sys +from microwaveCookPlanner import MicrowaveCookPlanner sys.path.insert(0, '..') try: from shared import config @@ -28,6 +29,11 @@ device_network_collection = db["device_network"] CAMERA_IMAGE_DIR = "storage/dishCameraImages" os.makedirs(CAMERA_IMAGE_DIR, exist_ok=True) +# --------------------------------------------------------- +# Classes +# --------------------------------------------------------- +microwave_cook_planner = MicrowaveCookPlanner() + # --------------------------------------------------------- # Routes # --------------------------------------------------------- @@ -72,14 +78,18 @@ def cooking_params(): # Remove the Mongo-injected '_id' object before returning the response data.pop("_id", None) - return jsonify({"message": "Cooking parameters saved successfully", "data": data}), 201 except Exception as e: return jsonify({"error": f"Database error: {str(e)}"}), 500 # 3. Returns with the cooking parameters - - + cooking_plan = microwave_cook_planner.generate_plan( + image_path=data.get("camera_image"), + height_cm=data.get("height_cm", 4.0), + initial_temp_c=data.get("initial_temp_c", 20.0), + microwave_wattage=data.get("microwave_wattage", 900) + ) + return jsonify(cooking_plan), 201 @app.route("/device-network", methods=["POST"]) def device_network(): diff --git a/cloud/microwaveCookPlanner.py b/cloud/microwaveCookPlanner.py new file mode 100644 index 0000000..9593004 --- /dev/null +++ b/cloud/microwaveCookPlanner.py @@ -0,0 +1,98 @@ +from typing import Dict, Any +from APIs.edamam import EdamamAPI +from microwaveDishAnalyzer import MicrowaveDishAnalyzer +from microwaveThermalEngine import MicrowaveThermalEngine, DishThermalState + + +class MicrowaveCookPlanner: + """Orchestrates Edamam API, Dish Analyzer, and Thermal Engine into a single workflow.""" + + def __init__(self, cm_per_pixel: float = 0.05): + self.edamam_api = EdamamAPI() + self.analyzer = MicrowaveDishAnalyzer(cm_per_pixel=cm_per_pixel) + self.engine = MicrowaveThermalEngine() + + def _extract_edamam_data(self, edamam_resp: Dict[str, Any]) -> tuple[str, float, Dict[str, float]]: + """Parses Edamam Vision response to extract label, total mass, and macronutrient grams.""" + recipe = edamam_resp.get("combined", {}).get("recipe", {}) + + # Fallback to first dish if 'combined' is empty + if not recipe and edamam_resp.get("dishes"): + recipe = edamam_resp["dishes"][0].get("recipe", {}) + + label = recipe.get("label", "Unknown Dish") + total_weight = float(recipe.get("totalWeight", 300.0)) # Default 300g fallback + + nutrients = recipe.get("totalNutrients", {}) + + # Extract macronutrients in grams (Edamam nutrient codes) + fat_g = float(nutrients.get("FAT", {}).get("quantity", 0.0)) + protein_g = float(nutrients.get("PROCNT", {}).get("quantity", 0.0)) + carbs_g = float(nutrients.get("CHOCDF", {}).get("quantity", 0.0)) + + # Water is sometimes omitted in Edamam; infer remaining mass as water if missing + if "WATER" in nutrients: + water_g = float(nutrients["WATER"].get("quantity", 0.0)) + else: + water_g = max(0.0, total_weight - (fat_g + protein_g + carbs_g)) + + macros = { + "water_g": water_g, + "fat_g": fat_g, + "protein_g": protein_g, + "carbs_g": carbs_g, + } + + return label, total_weight, macros + + def generate_plan( + self, + image_path: str, + height_cm: float, + initial_temp_c: float, + microwave_wattage: int = 900 + ) -> Dict[str, Any]: + """Main pipeline call to parse an image and return cooking parameters.""" + + # 1. Vision & Nutrient Analysis + edamam_resp = self.edamam_api.analyze_dish_image(image_path) + food_label, edamam_mass_g, macros = self._extract_edamam_data(edamam_resp) + + # 2. Geometric Volume Calculation + vol_data = self.analyzer.estimate_volume( + image_path=image_path, + height_cm=height_cm, + food_label=food_label + ) + + # 3. Mass Cross-Validation & Density Check + mass_data = self.analyzer.reconcile_mass( + edamam_mass_g=edamam_mass_g, + volume_cm3=vol_data["volume_cm3"], + food_label=food_label + ) + final_mass_g = mass_data["final_mass_g"] + + # 4. Thermal State Creation + thermal_state = DishThermalState( + food_name=food_label, + macronutrients=macros, + estimated_mass_g=final_mass_g, + initial_temp_c=initial_temp_c, + volume_cm3=vol_data["volume_cm3"] + ) + + # 5. Cook Plan Calculation + cook_plan = self.engine.calculate_cook_plan( + state=thermal_state, + microwave_wattage=microwave_wattage + ) + + # Return consolidated output + return { + "dish_name": food_label, + "reconciled_mass_g": final_mass_g, + "mass_validation_status": mass_data["status"], + "cook_plan": cook_plan, + "geometry": vol_data + } \ No newline at end of file