Source code for langchain_community.utilities.passio_nutrition_ai
"""Util that invokes the Passio Nutrition AI API."""fromdatetimeimportdatetime,timedeltafromtypingimportAny,Callable,Dict,Optional,finalimportrequestsfromlangchain_core.pydantic_v1importBaseModel,Field,root_validatorfromlangchain_core.utilsimportget_from_dict_or_env
[docs]classNoDiskStorage:"""Mixin to prevent storing on disk."""@finaldef__getstate__(self)->None:raiseAttributeError("Do not store on disk.")@finaldef__setstate__(self,state:Any)->None:raiseAttributeError("Do not store on disk.")
try:fromtenacityimport(retry,retry_if_result,stop_after_attempt,wait_exponential,wait_random,)exceptImportError:# No retries if tenacity is not installed.defretry_fallback(f:Callable[...,Any],*args:Any,**kwargs:Any)->Callable[...,Any]:returnfdefstop_after_attempt_fallback(n:int)->None:returnNonedefwait_random_fallback(a:float,b:float)->None:returnNonedefwait_exponential_fallback(multiplier:float=1,min:float=0,max:float=float("inf"))->None:returnNone
[docs]defis_http_retryable(rsp:requests.Response)->bool:"""Check if a HTTP response is retryable."""returnbool(rsp)andrsp.status_codein[408,425,429,500,502,503,504]
[docs]classManagedPassioLifeAuth(NoDiskStorage):"""Manage the token for the NutritionAI API."""_access_token_expiry:Optional[datetime]
[docs]defrefresh_access_token(self)->None:"""Refresh the access token for the NutritionAI API."""rsp=self._http_get(self.subscription_key)ifnotrsp:raiseValueError("Could not get access token")self._last_token=token=rsp.json()self._customer_id=token["customer_id"]self._access_token=token["access_token"]self._access_token_expiry=(datetime.now()+timedelta(seconds=token["expires_in"])-timedelta(seconds=5))
# 5 seconds: approximate time for a token refresh to be processed.DEFAULT_NUTRITIONAI_API_URL=("https://api.passiolife.com/v2/products/napi/food/search/advanced")
[docs]classNutritionAIAPI(BaseModel):"""Wrapper for the Passio Nutrition AI API."""nutritionai_subscription_key:strnutritionai_api_url:str=Field(default=DEFAULT_NUTRITIONAI_API_URL)more_kwargs:dict=Field(default_factory=dict)auth_:ManagedPassioLifeAuthclassConfig:arbitrary_types_allowed=Trueextra="forbid"@retry(retry=retry_if_result(is_http_retryable),stop=stop_after_attempt(4),wait=wait_random(0,0.3)+wait_exponential(multiplier=1,min=0.1,max=2),)def_http_get(self,params:dict)->requests.Response:returnrequests.get(self.nutritionai_api_url,headers=self.auth_.headers,params=params,# type: ignore)def_api_call_results(self,search_term:str)->dict:"""Call the NutritionAI API and return the results."""rsp=self._http_get({"term":search_term,**self.more_kwargs})ifnotrsp:raiseValueError("Could not get NutritionAI API results")rsp.raise_for_status()returnrsp.json()@root_validator(pre=True)defvalidate_environment(cls,values:Dict)->Dict:"""Validate that api key and endpoint exists in environment."""nutritionai_subscription_key=get_from_dict_or_env(values,"nutritionai_subscription_key","NUTRITIONAI_SUBSCRIPTION_KEY")values["nutritionai_subscription_key"]=nutritionai_subscription_keynutritionai_api_url=get_from_dict_or_env(values,"nutritionai_api_url","NUTRITIONAI_API_URL",DEFAULT_NUTRITIONAI_API_URL,)values["nutritionai_api_url"]=nutritionai_api_urlvalues["auth_"]=ManagedPassioLifeAuth(nutritionai_subscription_key)returnvalues
[docs]defrun(self,query:str)->Optional[Dict]:"""Run query through NutrtitionAI API and parse result."""results=self._api_call_results(query)ifresultsandlen(results)<1:returnNonereturnresults