ConsumeWise / api /nutrient_analyzer.py
sonika1503
Add application file
33b10b6
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))