Spaces:
Build error
Build error
| import os | |
| import io | |
| import uuid | |
| import random | |
| import json | |
| from dataclasses import dataclass | |
| from typing import Dict, List, Optional, Tuple | |
| import numpy as np | |
| import pandas as pd | |
| import gradio as gr | |
| from pydub import AudioSegment | |
| import logging | |
| import whisper | |
| from dotenv import load_dotenv | |
| # Load environment variables from .env file | |
| load_dotenv() | |
| logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') | |
| logger = logging.getLogger(__name__) | |
| # ============ FAST, OFFLINE ASR (OpenAI Whisper local) ============ | |
| USE_ASR = True | |
| WHISPER_MODEL_NAME = os.getenv("WHISPER_MODEL", "base") # Options: "tiny"|"base"|"small"|"medium" | |
| if USE_ASR: | |
| try: | |
| _whisper_model = whisper.load_model(WHISPER_MODEL_NAME) | |
| logger.info(f"Whisper model {WHISPER_MODEL_NAME} loaded successfully.") | |
| except Exception as e: | |
| logger.error(f"Failed to load Whisper model: {str(e)}") | |
| raise | |
| # ======================= LANGUAGES ================================ | |
| lang_map = { | |
| "English": "en", | |
| "Hindi": "hi", | |
| "Telugu": "te", | |
| "Spanish": "es", | |
| "Tamil": "ta", | |
| "Kannada": "kn", | |
| "Bengali": "bn", | |
| } | |
| # =================== TRANSLATION TEMPLATES ======================== | |
| def get_output_template(lang: str) -> str: | |
| templates = { | |
| "English": ( | |
| "<div style='font-family: \"Open Sans\", sans-serif; background: #f8f9fa; padding: 20px; border-radius: 15px; " | |
| "box-shadow: 0 6px 12px rgba(0,0,0,0.1); max-width: 900px; margin: 0 auto;'>" | |
| "<h2 style='color: #28a745; text-align: center; margin-bottom: 20px; font-size: 28px;'>🌾 Your Personalized Weekly Diet Plan</h2>" | |
| "<div style='background: #ffffff; padding: 15px; border-radius: 10px; margin-bottom: 15px; border-left: 5px solid #17a2b8;'>" | |
| "<h3 style='color: #17a2b8; margin-bottom: 10px; font-size: 20px;'>👤 Your Profile</h3>" | |
| "<p style='margin: 5px 0; font-size: 16px;'><strong>Age:</strong> {age} years</p>" | |
| "<p style='margin: 5px 0; font-size: 16px;'><strong>Gender:</strong> {gender}</p>" | |
| "<p style='margin: 5px 0; font-size: 16px;'><strong>Height:</strong> {height} cm</p>" | |
| "<p style='margin: 5px 0; font-size: 16px;'><strong>Weight:</strong> {weight} kg</p>" | |
| "<p style='margin: 5px 0; font-size: 16px;'><strong>Occupation:</strong> {occupation}</p>" | |
| "<p style='margin: 5px 0; font-size: 16px;'><strong>Activity Level:</strong> {activity_level}</p>" | |
| "<p style='margin: 5px 0; font-size: 16px;'><strong>Goal:</strong> {goal}</p>" | |
| "<p style='margin: 5px 0; font-size: 16px;'><strong>BMI:</strong> {bmi:.1f}</p>" | |
| "</div>" | |
| "<div style='background: #ffffff; padding: 15px; border-radius: 10px; margin-bottom: 15px; border-left: 5px solid #dc3545;'>" | |
| "<h3 style='color: #dc3545; margin-bottom: 10px; font-size: 20px;'>⚕️ Health Conditions</h3>" | |
| "<p style='margin: 5px 0; font-size: 16px;'>{health_conditions}</p>" | |
| "</div>" | |
| "<div style='background: #ffffff; padding: 15px; border-radius: 10px; margin-bottom: 15px; border-left: 5px solid #ffc107;'>" | |
| "<h3 style='color: #ffc107; margin-bottom: 10px; font-size: 20px;'>🍽️ Dietary Preferences</h3>" | |
| "<p style='margin: 5px 0; font-size: 16px;'>{dietary_preferences}</p>" | |
| "</div>" | |
| "<div style='background: #ffffff; padding: 15px; border-radius: 10px; margin-bottom: 15px; border-left: 5px solid #fd7e14;'>" | |
| "<h3 style='color: #fd7e14; margin-bottom: 10px; font-size: 20px;'>⚠️ Allergies</h3>" | |
| "<p style='margin: 5px 0; font-size: 16px;'>{allergies}</p>" | |
| "</div>" | |
| "<div style='background: #ffffff; padding: 15px; border-radius: 10px; margin-bottom: 15px; border-left: 5px solid #6f42c1;'>" | |
| "<h3 style='color: #6f42c1; margin-bottom: 10px; font-size: 20px;'>💰 Budget</h3>" | |
| "<p style='margin: 5px 0; font-size: 16px;'>₹{budget} per day</p>" | |
| "</div>" | |
| "<div style='background: #ffffff; padding: 15px; border-radius: 10px; margin-top: 20px; border-left: 5px solid #28a745;'>" | |
| "<h3 style='color: #28a745; margin-bottom: 10px; font-size: 20px;'>📋 Your Weekly Meal Plan</h3>" | |
| "{formatted_plan}" | |
| "</div>" | |
| "<div style='text-align: center; margin-top: 20px; font-size: 14px; color: #6c757d;'>" | |
| "Note: This plan is for informational purposes. Consult a nutritionist for personalized advice." | |
| "</div>" | |
| "</div>" | |
| ), | |
| "Hindi": ( | |
| "<div style='font-family: \"Open Sans\", sans-serif; background: #f8f9fa; padding: 20px; border-radius: 15px; " | |
| "box-shadow: 0 6px 12px rgba(0,0,0,0.1); max-width: 900px; margin: 0 auto;'>" | |
| "<h2 style='color: #28a745; text-align: center; margin-bottom: 20px; font-size: 28px;'>🌾 आपकी व्यक्तिगत साप्ताहिक आहार योजना</h2>" | |
| "<div style='background: #ffffff; padding: 15px; border-radius: 10px; margin-bottom: 15px; border-left: 5px solid #17a2b8;'>" | |
| "<h3 style='color: #17a2b8; margin-bottom: 10px; font-size: 20px;'>👤 आपकी प्रोफ़ाइल</h3>" | |
| "<p style='margin: 5px 0; font-size: 16px;'><strong>आयु:</strong> {age} वर्ष</p>" | |
| "<p style='margin: 5px 0; font-size: 16px;'><strong>लिंग:</strong> {gender}</p>" | |
| "<p style='margin: 5px 0; font-size: 16px;'><strong>ऊँचाई:</strong> {height} सेमी</p>" | |
| "<p style='margin: 5px 0; font-size: 16px;'><strong>वज़न:</strong> {weight} किग्रा</p>" | |
| "<p style='margin: 5px 0; font-size: 16px;'><strong>पेशा:</strong> {occupation}</p>" | |
| "<p style='margin: 5px 0; font-size: 16px;'><strong>गतिविधि स्तर:</strong> {activity_level}</p>" | |
| "<p style='margin: 5px 0; font-size: 16px;'><strong>लक्ष्य:</strong> {goal}</p>" | |
| "<p style='margin: 5px 0; font-size: 16px;'><strong>बीएमआई:</strong> {bmi:.1f}</p>" | |
| "</div>" | |
| "<div style='background: #ffffff; padding: 15px; border-radius: 10px; margin-bottom: 15px; border-left: 5px solid #dc3545;'>" | |
| "<h3 style='color: #dc3545; margin-bottom: 10px; font-size: 20px;'>⚕️ स्वास्थ्य स्थितियाँ</h3>" | |
| "<p style='margin: 5px 0; font-size: 16px;'>{health_conditions}</p>" | |
| "</div>" | |
| "<div style='background: #ffffff; padding: 15px; border-radius: 10px; margin-bottom: 15px; border-left: 5px solid #ffc107;'>" | |
| "<h3 style='color: #ffc107; margin-bottom: 10px; font-size: 20px;'>🍽️ पसंद</h3>" | |
| "<p style='margin: 5px 0; font-size: 16px;'>{dietary_preferences}</p>" | |
| "</div>" | |
| "<div style='background: #ffffff; padding: 15px; border-radius: 10px; margin-bottom: 15px; border-left: 5px solid #fd7e14;'>" | |
| "<h3 style='color: #fd7e14; margin-bottom: 10px; font-size: 20px;'>⚠️ एलर्जी</h3>" | |
| "<p style='margin: 5px 0; font-size: 16px;'>{allergies}</p>" | |
| "</div>" | |
| "<div style='background: #ffffff; padding: 15px; border-radius: 10px; margin-bottom: 15px; border-left: 5px solid #6f42c1;'>" | |
| "<h3 style='color: #6f42c1; margin-bottom: 10px; font-size: 20px;'>💰 बजट</h3>" | |
| "<p style='margin: 5px 0; font-size: 16px;'>₹{budget} प्रति दिन</p>" | |
| "</div>" | |
| "<div style='background: #ffffff; padding: 15px; border-radius: 10px; margin-top: 20px; border-left: 5px solid #28a745;'>" | |
| "<h3 style='color: #28a745; margin-bottom: 10px; font-size: 20px;'>📋 आपकी साप्ताहिक भोजन योजना</h3>" | |
| "{formatted_plan}" | |
| "</div>" | |
| "<div style='text-align: center; margin-top: 20px; font-size: 14px; color: #6c757d;'>" | |
| "नोट: यह योजना सूचनात्मक उद्देश्यों के लिए है। व्यक्तिगत सलाह के लिए पोषण विशेषज्ञ से परामर्श करें।" | |
| "</div>" | |
| "</div>" | |
| ), | |
| } | |
| return templates.get(lang, templates["English"]) | |
| # ================== LOCAL FOOD DATABASE =========================== | |
| FOODS = { | |
| "grains": [ | |
| {"name": "rice", "kcal": 130, "protein": 2.7, "carbs": 28, "fat": 0.3, "price_per_100g": 5}, | |
| {"name": "wheat", "kcal": 340, "protein": 12, "carbs": 71, "fat": 1.5, "price_per_100g": 6}, | |
| {"name": "millet", "kcal": 378, "protein": 11, "carbs": 73, "fat": 4.2, "price_per_100g": 7}, | |
| {"name": "barley", "kcal": 354, "protein": 12, "carbs": 73, "fat": 2.3, "price_per_100g": 8}, | |
| {"name": "quinoa", "kcal": 120, "protein": 4.1, "carbs": 21, "fat": 1.9, "price_per_100g": 15}, | |
| {"name": "oats", "kcal": 389, "protein": 13, "carbs": 66, "fat": 7, "price_per_100g": 12}, | |
| {"name": "brown rice", "kcal": 123, "protein": 2.7, "carbs": 25, "fat": 1, "price_per_100g": 10}, | |
| ], | |
| "fruits": [ | |
| {"name": "apple", "kcal": 52, "protein": 0.3, "carbs": 14, "fat": 0.2, "price_per_100g": 15}, | |
| {"name": "banana", "kcal": 89, "protein": 1.1, "carbs": 23, "fat": 0.3, "price_per_100g": 10}, | |
| {"name": "orange", "kcal": 47, "protein": 0.9, "carbs": 12, "fat": 0.1, "price_per_100g": 12}, | |
| {"name": "papaya", "kcal": 43, "protein": 0.5, "carbs": 11, "fat": 0.3, "price_per_100g": 8}, | |
| {"name": "guava", "kcal": 68, "protein": 2.6, "carbs": 14, "fat": 0.9, "price_per_100g": 10}, | |
| {"name": "mango", "kcal": 60, "protein": 0.8, "carbs": 15, "fat": 0.4, "price_per_100g": 20}, | |
| {"name": "grapes", "kcal": 69, "protein": 0.7, "carbs": 18, "fat": 0.2, "price_per_100g": 25}, | |
| ], | |
| "vegetables": [ | |
| {"name": "carrot", "kcal": 41, "protein": 0.9, "carbs": 10, "fat": 0.2, "price_per_100g": 5}, | |
| {"name": "tomato", "kcal": 18, "protein": 0.9, "carbs": 3.9, "fat": 0.2, "price_per_100g": 4}, | |
| {"name": "spinach", "kcal": 23, "protein": 2.9, "carbs": 3.6, "fat": 0.4, "price_per_100g": 6}, | |
| {"name": "onion", "kcal": 40, "protein": 1.1, "carbs": 9, "fat": 0.1, "price_per_100g": 3}, | |
| {"name": "beetroot", "kcal": 43, "protein": 1.6, "carbs": 10, "fat": 0.2, "price_per_100g": 5}, | |
| {"name": "bitter gourd", "kcal": 17, "protein": 1, "carbs": 3.7, "fat": 0.2, "price_per_100g": 4}, | |
| {"name": "bottle gourd", "kcal": 14, "protein": 0.6, "carbs": 3.4, "fat": 0.1, "price_per_100g": 3}, | |
| {"name": "cucumber", "kcal": 15, "protein": 0.7, "carbs": 3.6, "fat": 0.1, "price_per_100g": 2}, | |
| {"name": "broccoli", "kcal": 34, "protein": 3, "carbs": 7, "fat": 0.4, "price_per_100g": 10}, | |
| ], | |
| "proteins": [ | |
| {"name": "lentils", "kcal": 116, "protein": 9, "carbs": 20, "fat": 0.4, "price_per_100g": 8}, | |
| {"name": "eggs", "kcal": 155, "protein": 13, "carbs": 1.1, "fat": 11, "price_per_100g": 15}, | |
| {"name": "chicken", "kcal": 239, "protein": 27, "carbs": 0, "fat": 14, "price_per_100g": 25}, | |
| {"name": "tofu", "kcal": 76, "protein": 8, "carbs": 1.9, "fat": 4.8, "price_per_100g": 12}, | |
| {"name": "fish", "kcal": 206, "protein": 22, "carbs": 0, "fat": 12, "price_per_100g": 30}, | |
| {"name": "chickpeas", "kcal": 164, "protein": 9, "carbs": 27, "fat": 2.6, "price_per_100g": 10}, | |
| {"name": "paneer", "kcal": 265, "protein": 18, "carbs": 1.2, "fat": 20, "price_per_100g": 20}, | |
| ], | |
| "dairy": [ | |
| {"name": "milk", "kcal": 42, "protein": 3.4, "carbs": 5, "fat": 1, "price_per_100g": 6}, | |
| {"name": "curd", "kcal": 98, "protein": 11, "carbs": 3.4, "fat": 4.3, "price_per_100g": 8}, | |
| {"name": "buttermilk", "kcal": 40, "protein": 3.3, "carbs": 4.8, "fat": 0.9, "price_per_100g": 5}, | |
| {"name": "paneer", "kcal": 265, "protein": 18, "carbs": 1.2, "fat": 20, "price_per_100g": 20}, | |
| {"name": "cheese", "kcal": 403, "protein": 23, "carbs": 0.3, "fat": 33, "price_per_100g": 30}, | |
| {"name": "yogurt", "kcal": 61, "protein": 10, "carbs": 3.6, "fat": 0.4, "price_per_100g": 10}, | |
| ], | |
| "spices": [ | |
| {"name": "turmeric", "kcal": 312, "protein": 9.7, "carbs": 67, "fat": 3.3, "price_per_100g": 15}, | |
| {"name": "cumin", "kcal": 375, "protein": 18, "carbs": 44, "fat": 22, "price_per_100g": 20}, | |
| {"name": "coriander", "kcal": 298, "protein": 12, "carbs": 55, "fat": 17, "price_per_100g": 18}, | |
| {"name": "fennel", "kcal": 345, "protein": 16, "carbs": 52, "fat": 15, "price_per_100g": 22}, | |
| {"name": "cardamom", "kcal": 311, "protein": 11, "carbs": 68, "fat": 7, "price_per_100g": 25}, | |
| {"name": "cinnamon", "kcal": 247, "protein": 4, "carbs": 80, "fat": 1.2, "price_per_100g": 30}, | |
| ], | |
| } | |
| # ======================= ACTIVITY LEVELS ========================== | |
| ACTIVITY_LEVELS = ["Low", "Moderate", "High", "Very High"] | |
| # ========================= GOALS ================================== | |
| GOALS = ["Lose Weight", "Maintain Weight", "Gain Weight", "Build Muscle"] | |
| # =================== GENERATION FUNCTIONS ========================= | |
| class Meal: | |
| name: str | |
| kcal: float | |
| protein: float | |
| carbs: float | |
| fat: float | |
| cost: float | |
| def generate_meal(food_type: str, num_foods: int = 2, budget: int = 200) -> Meal: | |
| """Generate a meal by randomly selecting foods within budget constraints.""" | |
| available_foods = [f for f in FOODS[food_type] if f["price_per_100g"] * 100 <= budget] | |
| if not available_foods: | |
| available_foods = FOODS[food_type] # Fallback if budget too low | |
| foods = random.choices(available_foods, k=num_foods) | |
| kcal = sum(f["kcal"] for f in foods) / len(foods) | |
| protein = sum(f["protein"] for f in foods) / len(foods) | |
| carbs = sum(f["carbs"] for f in foods) / len(foods) | |
| fat = sum(f["fat"] for f in foods) / len(foods) | |
| cost = sum(f["price_per_100g"] for f in foods) / len(foods) | |
| names = ", ".join(f["name"].capitalize() for f in foods) | |
| return Meal(names, kcal, protein, carbs, fat, cost) | |
| def generate_daily_meals(lang: str, budget: int) -> Dict[str, Meal]: | |
| """Generate meals for a day based on budget.""" | |
| breakfast = generate_meal("grains", num_foods=2, budget=budget) | |
| lunch = generate_meal("proteins", num_foods=2, budget=budget) | |
| dinner = generate_meal("vegetables", num_foods=2, budget=budget) | |
| snack = generate_meal("fruits", num_foods=1, budget=budget // 2) # Half budget for snack | |
| return { | |
| "breakfast": breakfast, | |
| "lunch": lunch, | |
| "dinner": dinner, | |
| "snack": snack, | |
| } | |
| def generate_weekly_plan(lang: str, budget: int) -> Dict[str, Dict[str, Meal]]: | |
| """Generate a full weekly meal plan.""" | |
| plan = {} | |
| for day in range(7): | |
| day_name = f"Day {day + 1} ({['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'][day]})" | |
| plan[day_name] = generate_daily_meals(lang, budget) | |
| return plan | |
| # =================== TRANSCRIPTION FUNCTION ======================= | |
| def transcribe_audio(audio_path: str, lang: str) -> str: | |
| """Transcribe audio input using Whisper model.""" | |
| if not audio_path or not os.path.exists(audio_path): | |
| return "❌ No audio file found. Please upload or record audio." | |
| try: | |
| temp_wav = f"temp_{uuid.uuid4().hex}.wav" | |
| audio = AudioSegment.from_file(audio_path) | |
| audio = audio.set_frame_rate(16000).set_channels(1) | |
| audio.export(temp_wav, format="wav") | |
| result = _whisper_model.transcribe(temp_wav, language=lang_map.get(lang, "en")) | |
| os.remove(temp_wav) | |
| text = result.get("text", "").strip() | |
| return text if text else "❌ Could not understand the speech. Please try again." | |
| except Exception as e: | |
| logger.error(f"Transcription error: {str(e)}") | |
| return "❌ Transcription failed due to an error." | |
| # =================== DIET PLAN GENERATION ======================== | |
| def generate_diet_plan( | |
| lang: str, age: int, gender: str, height: float, weight: float, | |
| occupation: str, activity_level: str, goal: str, budget: int, | |
| health_conditions_typed: str, dietary_preferences_typed: str, allergies_typed: str, | |
| health_conditions_audio: Optional[str], dietary_preferences_audio: Optional[str], allergies_audio: Optional[str], | |
| feedback: Optional[str] = None | |
| ) -> str: | |
| """Generate a personalized diet plan with validation and feedback.""" | |
| # Input validation | |
| if not (1 <= age <= 120): | |
| return "<p style='color: red; font-family: \"Open Sans\", sans-serif;'>Error: Age must be between 1 and 120 years.</p>" | |
| if not (30 <= weight <= 200): | |
| return "<p style='color: red; font-family: \"Open Sans\", sans-serif;'>Error: Weight must be between 30 and 200 kg.</p>" | |
| if not (100 <= height <= 250): | |
| return "<p style='color: red; font-family: \"Open Sans\", sans-serif;'>Error: Height must be between 100 and 250 cm.</p>" | |
| if not (100 <= budget <= 1000): | |
| return "<p style='color: red; font-family: \"Open Sans\", sans-serif;'>Error: Budget must be between ₹100 and ₹1000.</p>" | |
| # Process audio or typed input | |
| health_conditions = transcribe_audio(health_conditions_audio, lang) if health_conditions_audio else health_conditions_typed or "None" | |
| dietary_preferences = transcribe_audio(dietary_preferences_audio, lang) if dietary_preferences_audio else dietary_preferences_typed or "None" | |
| allergies = transcribe_audio(allergies_audio, lang) if allergies_audio else allergies_typed or "None" | |
| # Generate plan | |
| plan = generate_weekly_plan(lang, budget) | |
| template = get_output_template(lang) | |
| formatted_plan = "\n".join( | |
| f"<div style='margin-bottom: 15px;'><strong>{day}</strong><br>" | |
| f"🌞 Breakfast: {meals['breakfast'].name} ({meals['breakfast'].kcal:.0f} kcal, ₹{meals['breakfast'].cost:.0f})<br>" | |
| f"🍲 Lunch: {meals['lunch'].name} ({meals['lunch'].kcal:.0f} kcal, ₹{meals['lunch'].cost:.0f})<br>" | |
| f"🍽️ Dinner: {meals['dinner'].name} ({meals['dinner'].kcal:.0f} kcal, ₹{meals['dinner'].cost:.0f})<br>" | |
| f"🍎 Snack: {meals['snack'].name} ({meals['snack'].kcal:.0f} kcal, ₹{meals['snack'].cost:.0f})<br>" | |
| f"</div>" for day, meals in plan.items() | |
| ) | |
| bmi = weight / (height / 100) ** 2 | |
| # Log feedback if provided | |
| if feedback: | |
| logger.info(f"User feedback: {feedback}") | |
| return template.format( | |
| age=age, gender=gender, height=height, weight=weight, occupation=occupation, | |
| activity_level=activity_level, goal=goal, health_conditions=health_conditions, | |
| dietary_preferences=dietary_preferences, allergies=allergies, budget=budget, bmi=bmi, | |
| formatted_plan=formatted_plan | |
| ) | |
| # =================== GRADIO UI =================================== | |
| def create_ui() -> gr.Blocks: | |
| with gr.Blocks(theme=gr.themes.Soft()) as app: | |
| gr.Markdown("# Personalized Diet Plan Generator (Offline, Multilingual)") | |
| lang = gr.Dropdown(label="Language", choices=list(lang_map.keys()), value="English") | |
| with gr.Row(): | |
| age = gr.Number(label="Age", value=30, minimum=1, maximum=120) | |
| gender = gr.Radio(label="Gender", choices=["Male", "Female", "Other"], value="Other") | |
| with gr.Row(): | |
| weight = gr.Number(label="Weight (kg)", value=65, minimum=30, maximum=200) | |
| height = gr.Number(label="Height (cm)", value=170, minimum=100, maximum=250) | |
| occupation = gr.Textbox(label="Occupation", placeholder="e.g. Teacher, Engineer") | |
| activity = gr.Dropdown(label="Activity Level", choices=ACTIVITY_LEVELS, value="Moderate") | |
| goal = gr.Dropdown(label="Goal", choices=GOALS, value="Maintain") | |
| budget = gr.Slider(label="Daily Budget (₹)", minimum=100, maximum=1000, step=50, value=200) | |
| health_typed = gr.Textbox(label="Health conditions (Typed)", placeholder="e.g. Diabetes, high cholesterol") | |
| dietary_typed = gr.Textbox(label="Dietary preferences (Typed)", placeholder="e.g. Veg, Non-Veg, High Protein") | |
| allergies_typed = gr.Textbox(label="Allergies (Typed, comma-separated)", placeholder="e.g. Peanut, Milk") | |
| gr.Markdown("Optional: Type or Speak your health info, preferences, and allergies.") | |
| with gr.Row(): | |
| health_audio = gr.Audio(label="Speak Health Conditions (optional)", source="microphone", type="filepath") | |
| dietary_audio = gr.Audio(label="Speak Dietary Preferences (optional)", source="microphone", type="filepath") | |
| allergy_audio = gr.Audio(label="Speak Allergies (optional)", source="microphone", type="filepath") | |
| feedback = gr.Textbox(label="Feedback (Optional)", placeholder="Share your thoughts on the plan...") | |
| submit = gr.Button("Generate Diet Plan") | |
| output = gr.HTML(label="Your Personalized Diet Plan") | |
| submit.click( | |
| fn=generate_diet_plan, | |
| inputs=[lang, age, gender, height, weight, occupation, activity, goal, budget, health_typed, dietary_typed, allergies_typed, health_audio, dietary_audio, allergy_audio, feedback], | |
| outputs=output | |
| ) | |
| return app | |
| # === Run the App === | |
| if __name__ == "__main__": | |
| app = create_ui() | |
| app.launch(server_name="0.0.0.0", server_port=7860, share=True) |