šŸ Python SDK Documentation

The easiest way to get accurate nutrition data in Python

View on PyPI
pip install avocavo-nutrition

Installation

# Install the Python SDK
pip install avocavo-nutrition

# Or with conda
conda install -c conda-forge avocavo-nutrition

Requirements

  • • Python 3.7+
  • • requests library (automatically installed)
  • • keyring library for secure credential storage

Quick Start

šŸ” OAuth Login (Recommended)

import avocavo_nutrition as av

# One-time OAuth login (opens browser)
av.login()  # Google OAuth (default)

# Now use the nutrition API without API keys!
result = av.analyze_ingredient("2 cups chocolate chips")
print(f"Calories: {result.nutrition.calories}")
print(f"Protein: {result.nutrition.protein}g")
print(f"USDA: {result.usda_match.description}")

šŸ”‘ Direct API Key

from avocavo_nutrition import NutritionAPI

client = NutritionAPI(api_key="your_api_key_here")
result = client.analyze_ingredient("1 cup rice")
print(f"Calories: {result.nutrition.calories}")

šŸš€ Get Started

Start with 1,000 free API calls - no credit card required!Get your free API key →

Authentication

Option 1: OAuth Login (Recommended)

import avocavo_nutrition as av

# Login once, use everywhere
av.login()  # Opens browser for Google OAuth

# Credentials stored securely with keyring
result = av.analyze_ingredient("1 cup rice")

# Check login status
if av.is_logged_in():
    user = av.get_current_user()
    print(f"Logged in as: {user['email']}")

# Logout when done
av.logout()

Option 2: Direct API Key

from avocavo_nutrition import NutritionAPI

# Direct API key usage
client = NutritionAPI(api_key="your_api_key")
result = client.analyze_ingredient("1 cup rice")

Option 3: Environment Variable

# Set environment variable
export AVOCAVO_API_KEY="your_api_key_here"

# API key automatically detected
import avocavo_nutrition as av
result = av.analyze_ingredient("1 cup rice")

🄬 Analyze Ingredients

Basic Usage

import avocavo_nutrition as av

# Any ingredient with quantity
result = av.analyze_ingredient("2 tbsp olive oil")

if result.success:
    nutrition = result.nutrition
    print(f"Calories: {nutrition.calories}")
    print(f"Fat: {nutrition.fat}g")
    print(f"Protein: {nutrition.protein}g")
    print(f"Carbs: {nutrition.carbs}g")
    print(f"Fiber: {nutrition.fiber}g")
    print(f"Sodium: {nutrition.sodium}mg")
    
    # USDA verification
    usda = result.usda_match
    print(f"\nUSDA FDC ID: {usda.fdc_id}")
    print(f"Description: {usda.description}")
    print(f"Data Type: {usda.data_type}")
    print(f"Verify: {result.verification_url}")
else:
    print(f"Error: {result.error}")

Complete Nutrition Data

result = av.analyze_ingredient("1 cup cooked brown rice")
nutrition = result.nutrition

# Core nutrients
print(f"Calories: {nutrition.calories}")
print(f"Protein: {nutrition.protein}g")
print(f"Carbohydrates: {nutrition.carbs}g") 
print(f"Total Fat: {nutrition.fat}g")

# Detailed breakdown
print(f"Dietary Fiber: {nutrition.fiber}g")
print(f"Sugars: {nutrition.sugar}g")
print(f"Saturated Fat: {nutrition.saturated_fat}g")

# Minerals
print(f"Sodium: {nutrition.sodium}mg")
print(f"Calcium: {nutrition.calcium}mg")
print(f"Iron: {nutrition.iron}mg")
print(f"Potassium: {nutrition.potassium}mg")

# Vitamins (when available)
print(f"Vitamin A: {nutrition.vitamin_a}mcg")
print(f"Vitamin C: {nutrition.vitamin_c}mg")

# System performance & caching (NEW in v1.7.3+)
print(f"\nFrom Cache: {result.from_cache}")            # True/False
print(f"Cache Type: {result.cache_type}")               # "redis" | "supabase" | None  
print(f"Processing Time: {result.processing_time_ms}ms") # Sub-second response
print(f"Method Used: {result.method_used}")             # "llm_driven_search" | "sql_exact"

# Parsing details (NEW in v1.7.3+)
print(f"\nParsing Info:")
print(f"Estimated Grams: {result.estimated_grams}")     # 195.0
print(f"Parsed Name: {result.ingredient_name}")         # "1 cup cooked brown rice"

šŸ’” Ingredient Format Tips

  • • Include quantities: "1 cup rice" instead of just "rice"
  • • Be specific: "brown rice" vs "white rice"
  • • Use common units: cups, tablespoons, ounces, grams
  • • Include cooking method: "grilled chicken" vs "fried chicken"
  • • Advanced: Natural language works too! "1 handful", "a splash", "a pinch"

šŸš€ Advanced Parsing Examples

šŸŽÆ Industry-Leading Natural Language Processing

Our 7-tier hierarchical parsing system handles complex ingredient descriptions that no other nutrition API can process accurately. Perfect for real-world recipes with natural language ingredients.

# Complex natural language ingredients that work perfectly
import avocavo_nutrition as av

# Natural language portions that other APIs can't handle
ingredients = [
    "1 handful of baby spinach",
    "a splash of vanilla extract", 
    "1 very small pinch of salt",
    "2 medium bananas, ripe",
    "a drizzle of extra virgin olive oil",
    "1 generous dollop of Greek yogurt",
    "a few sprigs of fresh thyme",
    "1 small bunch of fresh cilantro",
    "a squeeze of fresh lemon juice"
]

print("Advanced Parsing Demonstration:")
print("=" * 50)

for ingredient in ingredients:
    result = av.analyze_ingredient(ingredient)
    
    if result.success:
        print(f"āœ… {ingredient}")
        print(f"   Calories: {result.nutrition.calories}")
        print(f"   Method: {result.method_used}")
        print(f"   Parsing: {result.parsing.quantity} {result.parsing.unit} {result.parsing.ingredient_name}")
        print(f"   Estimated grams: {result.estimated_grams}g")
        print()
    else:
        print(f"āŒ {ingredient}: {result.error}")

# Advanced Recipe with Mixed Ingredient Types
print("\n" + "=" * 50)
print("Advanced Recipe Analysis:")
print("=" * 50)

recipe = av.analyze_recipe([
    "2 cups all-purpose flour",        # Traditional measurement
    "1 handful of baby spinach",       # Natural language portion
    "a splash of vanilla extract",     # Vague quantity description
    "1 very small pinch of salt",      # Size modifier + traditional
    "2 medium bananas, ripe",          # Size + ripeness descriptor
    "a drizzle of olive oil",          # Cooking-style portion
    "1 generous dollop of yogurt"      # Informal + size modifier
], servings=4)

if recipe.success:
    print(f"Recipe Analysis Success! ({recipe.processing_time_ms}ms)")
    print(f"Per serving: {recipe.nutrition.per_serving.calories} calories")
    print(f"USDA matches: {recipe.usda_matches}/{len(recipe.nutrition.ingredients)}")
    print("\nIngredient breakdown:")
    
    for ingredient in recipe.nutrition.ingredients:
        if ingredient.success:
            print(f"  āœ… {ingredient.ingredient}: {ingredient.nutrition.calories} cal")
            print(f"     Parsing method: {ingredient.method_used}")
            print(f"     USDA verified: {ingredient.usda_match.description if ingredient.usda_match else 'N/A'}")
        else:
            print(f"  āŒ {ingredient.ingredient}: Failed")
else:
    print(f"Recipe failed: {recipe.error}")

print("\nšŸŽÆ Key Features Demonstrated:")
print("• Size modifiers: 'very small', 'medium', 'generous'")
print("• Natural portions: 'handful', 'splash', 'drizzle', 'dollop'")
print("• Complex descriptors: 'extra virgin', 'fresh', 'ripe'")
print("• Traditional + modern mixing in same recipe")
print("• 100% USDA-verifiable results with parsing transparency")

šŸ” Understanding the Response

šŸŽÆ Full Transparency

Every response includes detailed parsing information so you can understand exactly how we processed your ingredient. This transparency helps you trust our results and optimize your inputs.

Complete Response Breakdown

import avocavo_nutrition as av

# Get detailed response with full parsing breakdown
result = av.analyze_ingredient("1 handful of baby spinach")

print("šŸ” PARSING TRANSPARENCY:")
print("=" * 50)
print(f"Original input: {result.original_ingredient}")    # "1 handful of baby spinach"
print(f"Extracted quantity: {result.parsing.quantity}")   # 1
print(f"Recognized unit: {result.parsing.unit}")          # "handful"
print(f"Clean ingredient: {result.parsing.ingredient_name}")  # "baby spinach"
print(f"Estimated grams: {result.estimated_grams}")       # 30

print("\nšŸŽÆ HOW WE FOUND THE ANSWER:")
print("=" * 50)
print(f"Method used: {result.method_used}")               # "tiered_portion_conversion"
print(f"Parsing tier: {result.portion_source}")           # "tier_3_adjusted"
print(f"Processing time: {result.processing_time_ms}ms")   # 23.4
print(f"From cache: {result.cached}")                     # False

print("\nāœ… USDA VERIFICATION:")
print("=" * 50)
print(f"USDA FDC ID: {result.usda_match.fdc_id}")        # 168462
print(f"Description: {result.usda_match.description}")    # "Spinach, baby, raw"
print(f"Data type: {result.usda_match.data_type}")        # "sr_legacy_food"
print(f"Verify at: {result.verification_url}")

print("\nšŸ„— NUTRITION RESULTS:")
print("=" * 50)
print(f"Calories: {result.nutrition.calories}")           # 7
print(f"Protein: {result.nutrition.protein}g")            # 0.9
print(f"Total fat: {result.nutrition.total_fat}g")        # 0.1
print(f"Carbs: {result.nutrition.carbohydrates}g")        # 1.1
print(f"Fiber: {result.nutrition.fiber}g")                # 0.7
print(f"Sodium: {result.nutrition.sodium}mg")             # 24

šŸŽÆ 7-Tier Parsing System Explained

# See exactly how different ingredients are parsed:

# TIER 1: Direct SQL Match (fastest)
result = av.analyze_ingredient("1 cup rice")
print(f"Method: {result.method_used}")          # "sql_exact"
print(f"Tier: {result.portion_source}")         # "tier_1_exact"

# TIER 2: Fuzzy Match (spelling variations)
result = av.analyze_ingredient("1 cup ryce")
print(f"Method: {result.method_used}")          # "fuzzy_match"
print(f"Tier: {result.portion_source}")         # "tier_2_fuzzy"

# TIER 3: Size Modifier Applied
result = av.analyze_ingredient("1 large apple")
print(f"Method: {result.method_used}")          # "portion_adjusted"
print(f"Tier: {result.portion_source}")         # "tier_3_adjusted"

# TIER 4: Complex Modifier Processing
result = av.analyze_ingredient("1 very small pinch of salt")
print(f"Method: {result.method_used}")          # "modifier_adjusted_conversion"
print(f"Tier: {result.portion_source}")         # "tier_4_with_modifier"

# TIER 5: Generic Portion Fallback
result = av.analyze_ingredient("a splash of vanilla extract")
print(f"Method: {result.method_used}")          # "small_measurement_fallback"
print(f"Tier: {result.portion_source}")         # "tier_5_generic"

# TIER 6: Small Measurement Handling
result = av.analyze_ingredient("a dash of cinnamon")
print(f"Method: {result.method_used}")          # "small_measurement"
print(f"Tier: {result.portion_source}")         # "tier_6_small_measurement"

# TIER 7: Smart USDA Matching
result = av.analyze_ingredient("about 2 heaping tablespoons of chunky peanut butter")
print(f"Method: {result.method_used}")          # "llm_driven_search"
print(f"Tier: {result.portion_source}")         # "tier_7_semantic_match"

šŸ“Š Response Fields Guide

Processing Methods

  • • sql_exact: Direct database match
  • • fuzzy_match: Similarity matching
  • • portion_adjusted: Size scaling applied
  • • modifier_adjusted_conversion: Complex modifiers
  • • small_measurement_fallback: Small portions
  • • tiered_portion_conversion: Multi-tier processing
  • • llm_driven_search: AI-powered parsing

šŸ” AI-Powered Parsing (Tier 7)

  • • Purpose: Parse complex natural language descriptions
  • • Process: AI extracts quantity, unit, and ingredient name
  • • Key: AI never generates nutrition data - only parses text
  • • Result: Parsed ingredients are looked up in USDA database
  • • Guarantee: All nutrition data is 100% USDA-verified
  • • No Hallucination: AI cannot invent nutrition facts

šŸ³ Analyze Recipes

Basic Recipe Analysis

import avocavo_nutrition as av

# Full recipe with per-serving calculations
recipe = av.analyze_recipe([
    "2 cups all-purpose flour",
    "1 cup whole milk",
    "2 large eggs", 
    "1/4 cup sugar",
    "2 tsp baking powder",
    "1/2 tsp salt"
], servings=8)

if recipe.success:
    # Per serving nutrition
    per_serving = recipe.nutrition.per_serving
    print(f"Per serving ({recipe.servings} servings):")
    print(f"  Calories: {per_serving.calories}")
    print(f"  Protein: {per_serving.protein}g")
    print(f"  Carbs: {per_serving.carbs}g")
    print(f"  Fat: {per_serving.fat}g")
    
    # Total recipe nutrition
    total = recipe.nutrition.total
    print(f"\nTotal recipe:")
    print(f"  Calories: {total.calories}")
    print(f"  Protein: {total.protein}g")
    
    # Recipe-level performance (NEW in v1.7.3+)
    print(f"\nRecipe Performance:")
    print(f"  USDA Matches: {recipe.usda_matches}")           # Number of USDA-verifiable ingredients
    print(f"  Processing Time: {recipe.processing_time_ms}ms") # Total processing time
    # Note: All nutrition data is USDA-verifiable via included FDC IDs and verification URLs
    
    # Individual ingredient details (NEW in v1.7.3+)
    print(f"\nIngredient Details:")
    for ingredient in recipe.nutrition.ingredients:
        if ingredient.success:
            print(f"  āœ… {ingredient.ingredient}: {ingredient.nutrition.calories} cal")
            if ingredient.usda_match:
                print(f"     USDA: {ingredient.usda_match.description}")
                print(f"     Verify: {ingredient.verification_url}")
        else:
            print(f"  āŒ {ingredient.ingredient}: Failed to analyze")
else:
    print(f"Recipe analysis failed: {recipe.error}")

Advanced Recipe Analysis

# Analyze recipe with metadata
recipe_data = {
    "name": "Healthy Green Smoothie",
    "description": "A nutritious smoothie packed with vitamins",
    "ingredients": [
        "1 banana",
        "100g spinach", 
        "1 cup almond milk",
        "1 tbsp honey",
        "1/2 cup frozen mango"
    ],
    "servings": 2,
    "prep_time": 5,  # minutes
    "cook_time": 0
}

recipe = av.analyze_recipe(
    ingredients=recipe_data["ingredients"],
    servings=recipe_data["servings"],
    name=recipe_data["name"]
)

# Calculate nutrition density
if recipe.success:
    per_serving = recipe.nutrition.per_serving
    
    # Macronutrient percentages
    total_cals = per_serving.calories
    protein_cals = per_serving.protein * 4
    carb_cals = per_serving.carbs * 4  
    fat_cals = per_serving.fat * 9
    
    print(f"Macronutrient breakdown per serving:")
    print(f"  Protein: {protein_cals/total_cals*100:.1f}%")
    print(f"  Carbs: {carb_cals/total_cals*100:.1f}%") 
    print(f"  Fat: {fat_cals/total_cals*100:.1f}%")
    
    # Nutrition density score
    fiber_score = min(per_serving.fiber / 25 * 100, 100)  # 25g daily target
    protein_score = min(per_serving.protein / 50 * 100, 100)  # 50g daily target
    
    print(f"\nNutrition Quality:")
    print(f"  Fiber Score: {fiber_score:.1f}/100")
    print(f"  Protein Score: {protein_score:.1f}/100")

⚔ Batch Processing

šŸš€ Batch Processing Limits

Batch processing is available on all plans with varying limits: Free (5), Starter (10), Professional (20), Enterprise (50+) ingredients per batch.

Basic Batch Analysis

import avocavo_nutrition as av

# Analyze multiple ingredients efficiently
ingredients_list = [
    "1 cup quinoa",
    "2 tbsp olive oil", 
    "4 oz salmon",
    "1 cup spinach",
    "1/4 cup almonds"
]

batch_result = av.analyze_batch(ingredients_list)

print(f"Batch Analysis Results:")
print(f"Success rate: {batch_result.success_rate}%")
print(f"Processed: {len(batch_result.results)} ingredients")
print(f"Processing time: {batch_result.total_processing_time_ms}ms")

# Iterate through results
for item in batch_result.results:
    if item.success:
        print(f"āœ… {item.ingredient}: {item.nutrition.calories} cal, {item.nutrition.protein}g protein")
    else:
        print(f"āŒ {item.ingredient}: {item.error}")

# Calculate totals
total_calories = sum(item.nutrition.calories for item in batch_result.results if item.success)
total_protein = sum(item.nutrition.protein for item in batch_result.results if item.success)

print(f"\nTotal: {total_calories} calories, {total_protein}g protein")

Advanced Batch Processing

# Batch processing with error handling and progress
import time

def analyze_shopping_list(ingredients, chunk_size=5):
    """Analyze a large shopping list in chunks"""
    results = []
    
    # Process in chunks to respect rate limits
    for i in range(0, len(ingredients), chunk_size):
        chunk = ingredients[i:i + chunk_size]
        print(f"Processing chunk {i//chunk_size + 1}/{(len(ingredients)-1)//chunk_size + 1}...")
        
        try:
            batch_result = av.analyze_batch(chunk)
            results.extend(batch_result.results)
            
            # Show progress
            successful = sum(1 for r in batch_result.results if r.success)
            print(f"  āœ… {successful}/{len(chunk)} successful")
            
        except Exception as e:
            print(f"  āŒ Chunk failed: {e}")
            # Continue with next chunk
            
        # Brief pause between chunks
        time.sleep(0.1)
    
    return results

# Usage
shopping_list = [
    "2 lbs ground beef", "1 dozen eggs", "1 gallon milk",
    "2 lbs chicken breast", "1 bag brown rice", "2 lbs bananas",
    "1 lb spinach", "1 lb carrots", "1 jar peanut butter",
    "1 loaf whole wheat bread", "1 lb oats", "1 lb almonds"
]

results = analyze_shopping_list(shopping_list)

# Summarize results
successful_results = [r for r in results if r.success]
total_calories = sum(r.nutrition.calories for r in successful_results)
total_cost_estimate = len(successful_results) * 0.02  # Rough API cost estimate

print(f"\nShopping List Summary:")
print(f"Analyzed: {len(successful_results)}/{len(shopping_list)} items")
print(f"Total calories: {total_calories:,.0f}")
print("Estimated API cost: $" + f"{total_cost_estimate:.2f}")

šŸ—ļø Real-World Examples

Recipe App Integration

import avocavo_nutrition as av
from typing import List, Dict, Optional

class RecipeNutritionCalculator:
    """Calculate nutrition for recipes in your app"""
    
    def __init__(self):
        # Initialize with OAuth login
        if not av.is_logged_in():
            av.login()
    
    def calculate_recipe_nutrition(self, 
                                 ingredients: List[str], 
                                 servings: int = 1,
                                 recipe_name: str = None) -> Dict:
        """Calculate comprehensive nutrition for a recipe"""
        
        try:
            recipe = av.analyze_recipe(ingredients, servings, name=recipe_name)
            
            if recipe.success:
                per_serving = recipe.nutrition.per_serving
                total = recipe.nutrition.total
                
                return {
                    'success': True,
                    'recipe_name': recipe_name,
                    'servings': servings,
                    'per_serving': {
                        'calories': per_serving.calories,
                        'protein': per_serving.protein,
                        'carbs': per_serving.carbs,
                        'fat': per_serving.fat,
                        'fiber': per_serving.fiber,
                        'sodium': per_serving.sodium
                    },
                    'total': {
                        'calories': total.calories,
                        'protein': total.protein,
                        'carbs': total.carbs,
                        'fat': total.fat
                    },
                    'ingredient_analysis': [
                        {
                            'ingredient': ing.original,
                            'calories': ing.nutrition.calories if ing.success else 0,
                            'usda_match': ing.usda_match.description if ing.success else None,
                            'success': ing.success
                        }
                        for ing in recipe.ingredients
                    ],
                    'usda_match_rate': f"{recipe.successful_matches}/{len(recipe.ingredients)}",
                    'processing_time_ms': recipe.processing_time_ms
                }
            else:
                return {'success': False, 'error': recipe.error}
                
        except Exception as e:
            return {'success': False, 'error': str(e)}

# Usage in your app
calculator = RecipeNutritionCalculator()

# Calculate nutrition for user's recipe
user_recipe = [
    "2 cups whole wheat flour",
    "1 cup Greek yogurt", 
    "2 large eggs",
    "1/4 cup honey",
    "1 tsp vanilla extract",
    "1 tsp baking soda"
]

nutrition_data = calculator.calculate_recipe_nutrition(
    ingredients=user_recipe,
    servings=12,
    recipe_name="Healthy Muffins"
)

if nutrition_data['success']:
    print(f"Recipe: {nutrition_data['recipe_name']}")
    print(f"Per muffin: {nutrition_data['per_serving']['calories']} calories")
    print(f"USDA matches: {nutrition_data['usda_match_rate']}")
    
    # Store in your database
    # save_recipe_nutrition(recipe_id, nutrition_data)
else:
    print(f"Error: {nutrition_data['error']}")

Fitness Tracker Integration

import avocavo_nutrition as av
from datetime import datetime, date
from typing import List, Dict

class FitnessNutritionTracker:
    """Track daily nutrition from food entries"""
    
    def __init__(self):
        if not av.is_logged_in():
            av.login()
    
    def track_daily_nutrition(self, food_entries: List[Dict]) -> Dict:
        """
        Track nutrition from daily food entries
        
        Args:
            food_entries: List of {"food": "1 cup rice", "meal": "lunch", "time": "12:30"}
        """
        
        # Extract just the food descriptions for batch processing
        foods = [entry["food"] for entry in food_entries]
        
        # Use batch processing for efficiency
        batch_result = av.analyze_batch(foods)
        
        # Initialize daily totals
        daily_totals = {
            'calories': 0, 'protein': 0, 'carbs': 0, 'fat': 0,
            'fiber': 0, 'sodium': 0, 'sugar': 0
        }
        
        # Group by meal
        meals = {'breakfast': [], 'lunch': [], 'dinner': [], 'snacks': []}
        
        # Process results
        for i, result in enumerate(batch_result.results):
            if result.success:
                nutrition = result.nutrition
                entry = food_entries[i]
                
                # Add to daily totals
                daily_totals['calories'] += nutrition.calories
                daily_totals['protein'] += nutrition.protein
                daily_totals['carbs'] += nutrition.carbs
                daily_totals['fat'] += nutrition.fat
                daily_totals['fiber'] += nutrition.fiber
                daily_totals['sodium'] += nutrition.sodium
                daily_totals['sugar'] += nutrition.sugar
                
                # Group by meal
                meal = entry.get('meal', 'snacks')
                meals[meal].append({
                    'food': entry['food'],
                    'time': entry.get('time'),
                    'calories': nutrition.calories,
                    'protein': nutrition.protein,
                    'carbs': nutrition.carbs,
                    'fat': nutrition.fat
                })
        
        # Calculate macro percentages
        total_cals = daily_totals['calories']
        if total_cals > 0:
            macro_percentages = {
                'protein_percent': (daily_totals['protein'] * 4 / total_cals) * 100,
                'carbs_percent': (daily_totals['carbs'] * 4 / total_cals) * 100,
                'fat_percent': (daily_totals['fat'] * 9 / total_cals) * 100
            }
        else:
            macro_percentages = {'protein_percent': 0, 'carbs_percent': 0, 'fat_percent': 0}
        
        return {
            'date': date.today().isoformat(),
            'daily_totals': daily_totals,
            'macro_percentages': macro_percentages,
            'meals': meals,
            'foods_analyzed': len([r for r in batch_result.results if r.success]),
            'total_foods': len(food_entries),
            'success_rate': batch_result.success_rate
        }
    
    def get_nutrition_goals_progress(self, daily_nutrition: Dict, user_goals: Dict) -> Dict:
        """Compare daily nutrition against user goals"""
        
        progress = {}
        for nutrient, consumed in daily_nutrition['daily_totals'].items():
            if nutrient in user_goals:
                goal = user_goals[nutrient]
                progress[nutrient] = {
                    'consumed': consumed,
                    'goal': goal,
                    'percent_of_goal': (consumed / goal * 100) if goal > 0 else 0,
                    'remaining': max(0, goal - consumed)
                }
        
        return progress

# Usage example
tracker = FitnessNutritionTracker()

# User's daily food log
todays_foods = [
    {"food": "1 cup oatmeal with banana", "meal": "breakfast", "time": "7:30"},
    {"food": "1 tbsp almond butter", "meal": "breakfast", "time": "7:30"},
    {"food": "6 oz grilled chicken breast", "meal": "lunch", "time": "12:00"},
    {"food": "2 cups mixed salad", "meal": "lunch", "time": "12:00"},
    {"food": "2 tbsp olive oil dressing", "meal": "lunch", "time": "12:00"},
    {"food": "1 medium apple", "meal": "snacks", "time": "15:30"},
    {"food": "8 oz salmon fillet", "meal": "dinner", "time": "19:00"},
    {"food": "1 cup steamed broccoli", "meal": "dinner", "time": "19:00"},
    {"food": "1/2 cup brown rice", "meal": "dinner", "time": "19:00"}
]

# Track daily nutrition
daily_nutrition = tracker.track_daily_nutrition(todays_foods)

print(f"Daily Nutrition Summary for {daily_nutrition['date']}:")
print(f"Total Calories: {daily_nutrition['daily_totals']['calories']:.0f}")
print(f"Protein: {daily_nutrition['daily_totals']['protein']:.1f}g ({daily_nutrition['macro_percentages']['protein_percent']:.1f}%)")
print(f"Carbs: {daily_nutrition['daily_totals']['carbs']:.1f}g ({daily_nutrition['macro_percentages']['carbs_percent']:.1f}%)")
print(f"Fat: {daily_nutrition['daily_totals']['fat']:.1f}g ({daily_nutrition['macro_percentages']['fat_percent']:.1f}%)")

# Check against goals
user_goals = {
    'calories': 2000,
    'protein': 150,  # grams
    'carbs': 250,    # grams  
    'fat': 67        # grams
}

progress = tracker.get_nutrition_goals_progress(daily_nutrition, user_goals)
print(f"\nGoal Progress:")
for nutrient, data in progress.items():
    print(f"{nutrient.title()}: {data['consumed']:.1f}/{data['goal']} ({data['percent_of_goal']:.1f}%)")

Restaurant Menu Analysis

import avocavo_nutrition as av
import json
from typing import List, Dict

class RestaurantMenuAnalyzer:
    """Analyze nutrition for restaurant menu items"""
    
    def __init__(self):
        if not av.is_logged_in():
            av.login()
    
    def analyze_menu_item(self, 
                         item_name: str, 
                         ingredients: List[str],
                         serving_size: str = "1 serving") -> Dict:
        """Analyze a single menu item"""
        
        try:
            # Use batch processing for efficiency
            batch_result = av.analyze_batch(ingredients)
            
            # Calculate totals
            total_nutrition = {
                'calories': 0, 'protein': 0, 'carbs': 0, 'fat': 0,
                'fiber': 0, 'sodium': 0, 'saturated_fat': 0
            }
            
            ingredient_details = []
            
            for result in batch_result.results:
                if result.success:
                    n = result.nutrition
                    
                    # Add to totals
                    total_nutrition['calories'] += n.calories
                    total_nutrition['protein'] += n.protein
                    total_nutrition['carbs'] += n.carbs
                    total_nutrition['fat'] += n.fat
                    total_nutrition['fiber'] += n.fiber
                    total_nutrition['sodium'] += n.sodium
                    total_nutrition['saturated_fat'] += getattr(n, 'saturated_fat', 0)
                    
                    ingredient_details.append({
                        'ingredient': result.ingredient,
                        'calories': n.calories,
                        'usda_description': result.usda_match.description if hasattr(result, 'usda_match') else None
                    })
                else:
                    ingredient_details.append({
                        'ingredient': result.ingredient,
                        'error': result.error,
                        'calories': 0
                    })
            
            # Calculate nutrition facts panel values (based on FDA requirements)
            nutrition_facts = {
                'serving_size': serving_size,
                'calories': round(total_nutrition['calories']),
                'total_fat': round(total_nutrition['fat'], 1),
                'saturated_fat': round(total_nutrition['saturated_fat'], 1),
                'sodium': round(total_nutrition['sodium']),
                'total_carbs': round(total_nutrition['carbs'], 1),
                'dietary_fiber': round(total_nutrition['fiber'], 1),
                'protein': round(total_nutrition['protein'], 1),
                
                # Daily Value percentages (based on 2000 calorie diet)
                'fat_dv': round((total_nutrition['fat'] / 65) * 100),
                'saturated_fat_dv': round((total_nutrition['saturated_fat'] / 20) * 100),
                'sodium_dv': round((total_nutrition['sodium'] / 2300) * 100),
                'carbs_dv': round((total_nutrition['carbs'] / 300) * 100),
                'fiber_dv': round((total_nutrition['fiber'] / 25) * 100),
                'protein_dv': round((total_nutrition['protein'] / 50) * 100)
            }
            
            return {
                'success': True,
                'item_name': item_name,
                'nutrition_facts': nutrition_facts,
                'ingredient_analysis': ingredient_details,
                'success_rate': batch_result.success_rate,
                'total_ingredients': len(ingredients),
                'successful_matches': len([r for r in batch_result.results if r.success])
            }
            
        except Exception as e:
            return {
                'success': False,
                'item_name': item_name,
                'error': str(e)
            }
    
    def analyze_full_menu(self, menu_items: Dict[str, List[str]]) -> Dict:
        """Analyze an entire menu"""
        
        menu_analysis = {}
        
        for item_name, ingredients in menu_items.items():
            print(f"Analyzing: {item_name}...")
            analysis = self.analyze_menu_item(item_name, ingredients)
            menu_analysis[item_name] = analysis
        
        # Generate menu summary
        successful_items = [item for item in menu_analysis.values() if item['success']]
        
        if successful_items:
            avg_calories = sum(item['nutrition_facts']['calories'] for item in successful_items) / len(successful_items)
            high_sodium_items = [item['item_name'] for item in successful_items 
                               if item['nutrition_facts']['sodium_dv'] > 20]  # >20% DV
            
            summary = {
                'total_items_analyzed': len(menu_items),
                'successful_analyses': len(successful_items),
                'average_calories': round(avg_calories),
                'high_sodium_items': high_sodium_items,
                'analysis_timestamp': datetime.now().isoformat()
            }
        else:
            summary = {'error': 'No items could be analyzed successfully'}
        
        return {
            'menu_summary': summary,
            'item_analyses': menu_analysis
        }

# Usage example
analyzer = RestaurantMenuAnalyzer()

# Sample restaurant menu items
menu_items = {
    "Classic Burger": [
        "1 beef patty 6 oz",
        "1 hamburger bun",
        "2 slices cheddar cheese",
        "2 leaves lettuce",
        "2 slices tomato",
        "1 tbsp mayonnaise"
    ],
    "Caesar Salad": [
        "4 cups romaine lettuce",
        "2 tbsp caesar dressing",
        "1/4 cup parmesan cheese",
        "1/2 cup croutons",
        "6 oz grilled chicken breast"
    ],
    "Margherita Pizza": [
        "1 pizza dough 12 inch",
        "1/2 cup tomato sauce",
        "8 oz fresh mozzarella",
        "10 fresh basil leaves",
        "2 tbsp olive oil"
    ]
}

# Analyze the menu
menu_analysis = analyzer.analyze_full_menu(menu_items)

# Display results
print("\n=== MENU NUTRITION ANALYSIS ===")
print(f"Items analyzed: {menu_analysis['menu_summary']['successful_analyses']}/{menu_analysis['menu_summary']['total_items_analyzed']}")
print(f"Average calories: {menu_analysis['menu_summary']['average_calories']}")

if menu_analysis['menu_summary']['high_sodium_items']:
    print(f"High sodium items: {', '.join(menu_analysis['menu_summary']['high_sodium_items'])}")

print("\n=== INDIVIDUAL ITEMS ===")
for item_name, analysis in menu_analysis['item_analyses'].items():
    if analysis['success']:
        nf = analysis['nutrition_facts']
        print(f"\n{item_name}:")
        print(f"  Calories: {nf['calories']}")
        print(f"  Fat: {nf['total_fat']}g ({nf['fat_dv']}% DV)")
        print(f"  Sodium: {nf['sodium']}mg ({nf['sodium_dv']}% DV)")
        print(f"  Protein: {nf['protein']}g")
        print(f"  USDA matches: {analysis['successful_matches']}/{analysis['total_ingredients']}")
    else:
        print(f"\n{item_name}: Analysis failed - {analysis['error']}")

# Save results to file
with open('menu_nutrition_analysis.json', 'w') as f:
    json.dump(menu_analysis, f, indent=2)
    
print(f"\nDetailed analysis saved to menu_nutrition_analysis.json")

šŸ› ļø Error Handling

Exception Types

from avocavo_nutrition import (
    ApiError, 
    RateLimitError, 
    AuthenticationError,
    ValidationError,
    NetworkError
)
import avocavo_nutrition as av

def robust_nutrition_analysis(ingredient: str):
    """Nutrition analysis with comprehensive error handling"""
    
    try:
        result = av.analyze_ingredient(ingredient)
        
        if result.success:
            print(f"āœ… {ingredient}")
            print(f"   Calories: {result.nutrition.calories}")
            print(f"   USDA: {result.usda_match.description}")
            print(f"   Verify: {result.verification_url}")
            return result
        else:
            print(f"āŒ {ingredient}: {result.error}")
            return None
            
    except AuthenticationError as e:
        print(f"šŸ” Authentication failed: {e.message}")
        print("šŸ’” Try: av.login() or check your API key")
        return None
        
    except RateLimitError as e:
        print(f"ā±ļø  Rate limit exceeded: {e.message}")
        print(f"   Current usage: {e.usage}/{e.limit}")
        print(f"   Resets at: {e.reset_time}")
        print("šŸ’” Consider upgrading your plan or waiting")
        return None
        
    except ValidationError as e:
        print(f"šŸ“ Invalid input: {e.message}")
        print("šŸ’” Check ingredient format: '1 cup rice' not just 'rice'")
        return None
        
    except NetworkError as e:
        print(f"🌐 Network error: {e.message}")
        print("šŸ’” Check internet connection and try again")
        return None
        
    except ApiError as e:
        print(f"🚨 API error: {e.message}")
        print(f"   Status code: {e.status_code}")
        print("šŸ’” Contact support if this persists")
        return None
        
    except Exception as e:
        print(f"ā— Unexpected error: {str(e)}")
        print("šŸ’” Please report this issue")
        return None

# Usage
ingredients = [
    "1 cup brown rice",
    "invalid ingredient format",
    "2 tbsp olive oil",
    "",  # Empty string
    "1 cup imaginary food that doesn't exist"
]

successful_analyses = []
for ingredient in ingredients:
    if ingredient.strip():  # Skip empty strings
        result = robust_nutrition_analysis(ingredient)
        if result:
            successful_analyses.append(result)

print(f"\nSuccessfully analyzed: {len(successful_analyses)}/{len([i for i in ingredients if i.strip()])} ingredients")

Retry Logic and Timeouts

import time
import avocavo_nutrition as av
from avocavo_nutrition import NetworkError, RateLimitError

def analyze_with_retry(ingredient: str, max_retries: int = 3, backoff_factor: float = 1.0):
    """Analyze ingredient with exponential backoff retry logic"""
    
    for attempt in range(max_retries):
        try:
            result = av.analyze_ingredient(ingredient)
            return result
            
        except RateLimitError as e:
            if attempt == max_retries - 1:
                raise  # Re-raise on final attempt
            
            # Wait for rate limit reset or exponential backoff
            wait_time = min(e.retry_after or (backoff_factor * (2 ** attempt)), 60)
            print(f"Rate limited. Waiting {wait_time:.1f}s before retry {attempt + 1}/{max_retries}")
            time.sleep(wait_time)
            
        except NetworkError as e:
            if attempt == max_retries - 1:
                raise
            
            wait_time = backoff_factor * (2 ** attempt)
            print(f"Network error. Retrying in {wait_time:.1f}s... ({attempt + 1}/{max_retries})")
            time.sleep(wait_time)
    
    raise Exception(f"Failed after {max_retries} attempts")

# Usage with timeout configuration
from avocavo_nutrition import NutritionAPI

# Configure client with custom timeout
client = NutritionAPI(
    api_key="your_api_key",
    timeout=30,  # 30 second timeout
    max_retries=3
)

# Analyze with retry logic
try:
    result = analyze_with_retry("1 cup quinoa", max_retries=3)
    if result.success:
        print(f"Success: {result.nutrition.calories} calories")
except Exception as e:
    print(f"Final failure: {e}")

🚨 Best Practices

  • • Always check result.success before accessing nutrition data
  • • Implement retry logic for network errors
  • • Respect rate limits and implement backoff
  • • Log errors for monitoring and debugging
  • • Validate ingredient format before API calls
  • • Use batch processing to minimize API calls

šŸ” Complete Response Fields

✨ Enhanced in v1.7.3+

The Python SDK now returns all the same fields as the raw API, including caching details, parsing information, and performance metrics for complete transparency.

IngredientResult Fields

result = av.analyze_ingredient("1 cup cooked brown rice")

# Core Properties
result.success                    # bool: True if analysis succeeded
result.ingredient                 # str: Original ingredient text
result.nutrition                  # Nutrition: Complete nutrition data
result.usda_match                 # USDAMatch: USDA verification info
result.verification_url           # str: Direct USDA verification link

# Performance & System Data (NEW in v1.7.3+)
result.from_cache                 # bool: True if served from cache
result.cache_type                 # str: "redis" | "supabase" | None
result.processing_time_ms         # float: Processing time in milliseconds
result.method_used                # str: "llm_driven_search" | "sql_exact" | "fuzzy_match"

# Parsing Details (NEW in v1.7.3+)
result.estimated_grams            # float: Estimated grams for ingredient
result.ingredient_name            # str: Parsed ingredient name
result.error                      # str: Error message if success=False

RecipeResult Fields

recipe = av.analyze_recipe(ingredients, servings=4)

# Core Properties
recipe.success                    # bool: True if analysis succeeded
recipe.recipe                     # dict: Original recipe info
recipe.nutrition                  # RecipeNutrition: Complete nutrition breakdown

# Recipe Performance (NEW in v1.7.3+)
recipe.usda_matches               # int: Number of USDA-verifiable ingredients  
recipe.processing_time_ms         # float: Total processing time (sum of ingredients)
# Note: All data is USDA-verifiable via included FDC IDs and verification URLs

# Nutrition Breakdown
recipe.nutrition.total            # Nutrition: Total recipe nutrition
recipe.nutrition.per_serving      # Nutrition: Per-serving nutrition
recipe.nutrition.ingredients      # List[RecipeIngredient]: Individual ingredients

# Individual Ingredient Details
for ingredient in recipe.nutrition.ingredients:
    ingredient.ingredient         # str: Ingredient text
    ingredient.nutrition          # Nutrition: Individual nutrition data
    ingredient.usda_match         # USDAMatch: USDA verification
    ingredient.verification_url   # str: USDA verification link (NEW)
    ingredient.success            # bool: Analysis success for this ingredient

šŸ“š API Reference

Core Functions

FunctionDescriptionReturns
av.analyze_ingredient(ingredient)Analyze single ingredientIngredientResult
av.analyze_recipe(ingredients, servings)Analyze complete recipeRecipeResult
av.analyze_batch(ingredients)Batch analyze multiple ingredientsBatchResult
av.get_account_usage()Check API usage and limitsAccountUsage

Authentication Functions

FunctionDescriptionExample
av.login(provider="google")OAuth login (opens browser)av.login("github")
av.is_logged_in()Check if logged inif av.is_logged_in():
av.get_current_user()Get current user infouser = av.get_current_user()
av.logout()Logout and clear credentialsav.logout()

Data Models

# IngredientResult
class IngredientResult:
    success: bool
    ingredient: str
    nutrition: NutritionData
    usda_match: USDAMatch
    verification_url: str
    error: str | None
    from_cache: bool
    processing_time_ms: float

# NutritionData  
class NutritionData:
    calories: float
    protein: float          # grams
    carbs: float           # grams
    fat: float             # grams
    fiber: float           # grams
    sugar: float           # grams
    sodium: float          # milligrams
    calcium: float         # milligrams
    iron: float            # milligrams
    saturated_fat: float   # grams
    cholesterol: float     # milligrams
    
# USDAMatch
class USDAMatch:
    fdc_id: int
    description: str
    data_type: str         # "Foundation", "SR Legacy", etc.
    food_category: str
    
# RecipeResult
class RecipeResult:
    success: bool
    ingredients: List[IngredientResult]
    nutrition: RecipeNutrition
    servings: int
    successful_matches: int
    processing_time_ms: float
    
# RecipeNutrition
class RecipeNutrition:
    total: NutritionData       # Total recipe nutrition
    per_serving: NutritionData # Per serving nutrition
    
# BatchResult
class BatchResult:
    results: List[IngredientResult]
    success_rate: float
    total_processing_time_ms: float
    successful_matches: int
    
# AccountUsage
class AccountUsage:
    plan_name: str
    usage: UsageData
    
class UsageData:
    current_month: int
    monthly_limit: int
    remaining: int
    reset_date: str

Need Help?

We're here to help you integrate our Python SDK successfully into your application.