import os import logging from typing import Dict, List, Optional from PIL import Image from transformers import ViTFeatureExtractor, ViTForImageClassification import requests import gradio as gr # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) class NutritionAnalyzer: """Main class handling food recognition and nutrition analysis""" def __init__(self): self.model_name = "google/vit-base-patch16-224" self.feature_extractor = None self.model = None self.api_key = os.getenv('NUTRITION_API_KEY', 'Your API Key') def initialize_models(self): """Initialize vision transformer model and feature extractor""" try: self.feature_extractor = ViTFeatureExtractor.from_pretrained(self.model_name) self.model = ViTForImageClassification.from_pretrained(self.model_name) logger.info("Models initialized successfully") except Exception as e: logger.error(f"Model initialization failed: {str(e)}") raise def identify_food(self, image_path: str) -> str: """Identify food item from image using Vision Transformer Args: image_path: Path to the input image file Returns: str: Detected food item name """ try: image = Image.open(image_path) inputs = self.feature_extractor(images=image, return_tensors="pt") outputs = self.model(**inputs) return self.model.config.id2label[outputs.logits.argmax(-1).item()].split(',')[0] except Exception as e: logger.error(f"Food identification error: {str(e)}") raise class NutritionAPIHandler: """Handles nutrition data retrieval from API""" BASE_URL = "https://api.api-ninjas.com/v1/nutrition" def __init__(self, api_key: str): self.api_key = api_key self.session = requests.Session() self.session.headers.update({'X-Api-Key': self.api_key}) def get_nutrition_data(self, food_name: str) -> Optional[Dict]: """Fetch nutrition data from API Args: food_name: Name of food item to query Returns: Optional[Dict]: Nutrition data or None if error occurs """ try: response = self.session.get(self.BASE_URL, params={'query': food_name}) response.raise_for_status() return response.json()[0] if response.json() else None except Exception as e: logger.error(f"API Error: {str(e)}") return None class NutritionFormatter: """Formats nutrition data into visual representations""" @staticmethod def create_nutrition_table(data: Dict) -> str: """Generate HTML table with nutrition facts Args: data: Dictionary containing nutrition data Returns: str: Formatted HTML table """ if not data: return "
No nutrition data available
" return f"""| Nutrient | Amount | Daily Value% |
|---|
Error processing request. Please try again.
" def _handle_output(self, food_item: str, data: Optional[Dict]) -> str: if not data: return f"No nutrition data found for {food_item}
" return NutritionFormatter.create_nutrition_table(data) # Initialize and run Gradio app if __name__ == "__main__": app = NutritionAnalyzerApp() css = """ .nutrition-container { max-width: 600px; margin: 20px auto; } .macros { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin: 20px 0; } .macro { padding: 15px; border-radius: 8px; text-align: center; } .calories { background: #ffd70033; } .protein { background: #00ff0033; } .carbs { background: #0000ff33; } .fat { background: #ff000033; } .value { font-size: 1.5em; font-weight: bold; } table { width: 100%; margin-top: 20px; } th, td { padding: 10px; text-align: left; } .error { color: red; font-weight: bold; } """ # Update the Gradio interface section in the __main__ block: with gr.Blocks(css=css) as demo: gr.Markdown("# 🍎 AI Nutrition Analyzer") with gr.Row(): with gr.Column(): image_input = gr.Image(type="filepath", label="Upload Food Image") submit_btn = gr.Button("Analyze Nutrition") with gr.Column(): output = gr.HTML(label="Nutrition Analysis") submit_btn.click( fn=app.analyze_image, inputs=image_input, outputs=output ) demo.launch()