import sys from .icmr import analyze_nutrients from .rda import find_nutrition, rda_analysis, analyze_nutrition_icmr_rda import os import json, asyncio from fastapi import FastAPI, HTTPException from typing import List, Dict, Any from pydantic import BaseModel app = FastAPI() def find_product_nutrients(product_info_from_db): #GET Response: {'_id': '6714f0487a0e96d7aae2e839', #'brandName': 'Parle', 'claims': ['This product does not contain gold'], #'fssaiLicenseNumbers': [10013022002253], #'ingredients': [{'metadata': '', 'name': 'Refined Wheat Flour (Maida)', 'percent': '63%'}, {'metadata': '', 'name': 'Sugar', 'percent': ''}, {'metadata': '', 'name': 'Refined Palm Oil', 'percent': ''}, {'metadata': '(Glucose, Levulose)', 'name': 'Invert Sugar Syrup', 'percent': ''}, {'metadata': 'I', 'name': 'Sugar Citric Acid', 'percent': ''}, {'metadata': '', 'name': 'Milk Solids', 'percent': '1%'}, {'metadata': '', 'name': 'Iodised Salt', 'percent': ''}, {'metadata': '503(I), 500 (I)', 'name': 'Raising Agents', 'percent': ''}, {'metadata': '1101 (i)', 'name': 'Flour Treatment Agent', 'percent': ''}, {'metadata': 'Diacetyl Tartaric and Fatty Acid Esters of Glycerol (of Vegetable Origin)', 'name': 'Emulsifier', 'percent': ''}, {'metadata': 'Vanilla', 'name': 'Artificial Flavouring Substances', 'percent': ''}], #'nutritionalInformation': [{'name': 'Energy', 'unit': 'kcal', 'values': [{'base': 'per 100 g','value': 462}]}, #{'name': 'Protein', 'unit': 'g', 'values': [{'base': 'per 100 g', 'value': 6.7}]}, #{'name': 'Carbohydrate', 'unit': 'g', 'values': [{'base': 'per 100 g', 'value': 76.0}, {'base': 'of which sugars', 'value': 26.9}]}, #{'name': 'Fat', 'unit': 'g', 'values': [{'base': 'per 100 g', 'value': 14.6}, {'base': 'Saturated Fat', 'value': 6.8}, {'base': 'Trans Fat', 'value': 0}]}, #{'name': 'Total Sugars', 'unit': 'g', 'values': [{'base': 'per 100 g', 'value': 27.7}]}, #{'name': 'Added Sugars', 'unit': 'g', 'values': [{'base': 'per 100 g', 'value': 26.9}]}, #{'name': 'Cholesterol', 'unit': 'mg', 'values': [{'base': 'per 100 g', 'value': 0}]}, #{'name': 'Sodium', 'unit': 'mg', 'values': [{'base': 'per 100 g', 'value': 281}]}], #'packagingSize': {'quantity': 82, 'unit': 'g'}, #'productName': 'Parle-G Gold Biscuits', #'servingSize': {'quantity': 18.8, 'unit': 'g'}, #'servingsPerPack': 3.98, #'shelfLife': '7 months from packaging'} product_type = None calories = None sugar = None total_sugar = None added_sugar = None salt = None serving_size = None if product_info_from_db["servingSize"]["unit"].lower() == "g": product_type = "solid" elif product_info_from_db["servingSize"]["unit"].lower() == "ml": product_type = "liquid" serving_size = product_info_from_db["servingSize"]["quantity"] for item in product_info_from_db["nutritionalInformation"]: if 'energy' in item['name'].lower(): calories = item['values'][0]['value'] if 'total sugar' in item['name'].lower(): total_sugar = item['values'][0]['value'] if 'added sugar' in item['name'].lower(): added_sugar = item['values'][0]['value'] if 'sugar' in item['name'].lower() and 'added sugar' not in item['name'].lower() and 'total sugar' not in item['name'].lower(): sugar = item['values'][0]['value'] if 'salt' in item['name'].lower(): if salt is None: salt = 0 salt += item['values'][0]['value'] if salt is None: salt = 0 for item in product_info_from_db["nutritionalInformation"]: if 'sodium' in item['name'].lower(): salt += item['values'][0]['value'] if added_sugar is not None and added_sugar > 0 and sugar is None: sugar = added_sugar elif total_sugar is not None and total_sugar > 0 and added_sugar is None and sugar is None: sugar = total_sugar return product_type, calories, sugar, salt, serving_size # Define the request body using a simple BaseModel (without complex pydantic models if not needed) class NutrientAnalysisRequest(BaseModel): product_info_from_db: dict @app.post("/api/nutrient-analysis") async def get_nutrient_analysis(request: NutrientAnalysisRequest): product_info = request.product_info_from_db try: if ("nutritionalInformation" not in product_info or "servingSize" not in product_info or "quantity" not in product_info["servingSize"]): return {"nutrition_analysis" : ""} if (len(product_info["nutritionalInformation"]) == 0 or product_info["servingSize"]["quantity"] == 0): return {"nutrition_analysis" : ""} nutritional_information = product_info["nutritionalInformation"] serving_size = product_info["servingSize"]["quantity"] if nutritional_information: try: product_type, calories, sugar, salt, serving_size = find_product_nutrients(product_info) except Exception as e: print(f"Error in find_product_nutrients: {str(e)}", exc_info=True) raise if product_type is not None and serving_size is not None and serving_size > 0: # Parallel execution of nutrient analysis tasks try: nutrient_analysis, nutrient_analysis_rda_data = await asyncio.gather( analyze_nutrients(product_type, calories, sugar, salt, serving_size), rda_analysis(nutritional_information, serving_size) ) print(f"DEBUG : ICMR based analysis is {nutrient_analysis}") # Or with a try-except approach try: print(f"DEBUG : RDA Data is {nutrient_analysis_rda_data} with userServingSize of type {type(nutrient_analysis_rda_data['userServingSize'])} and nutritionPerServing of type {type(nutrient_analysis_rda_data['nutritionPerServing'])}") except KeyError as e: print(f"DEBUG: Missing key in nutrient_analysis_rda_data - {e}") except Exception as e: raise try: nutrient_analysis_rda = find_nutrition(nutrient_analysis_rda_data) print(f"DEBUG : RDA based analysis is {nutrient_analysis_rda}") except Exception as e: raise try: nutritional_level = await analyze_nutrition_icmr_rda(nutrient_analysis, nutrient_analysis_rda) print(f"DEBUG : ICMR and RDA based analysis is {nutritional_level}") return {"nutrition_analysis" : nutritional_level} except Exception as e: raise else: error_msg = "Product information in the db is corrupt" raise HTTPException(status_code=400, detail=error_msg) else: error_msg = "Nutritional information is required" raise HTTPException(status_code=400, detail=error_msg) except HTTPException as http_ex: raise http_ex except Exception as e: raise HTTPException(status_code=500, detail=str(e))