# app.py import os from dotenv import load_dotenv from google import genai import gradio as gr # Load environment variables (local .env or HF Secrets) load_dotenv() # Initialize Gemini client (will read GEMINI_API_KEY from environment) client = genai.Client() MODEL = "gemini-2.5-flash" # quickstart example uses gemini-2.5-flash; change to gemini-2.5-flash-pro if you have access # --- Utilities --- def calculate_calorie_requirements(age, gender, weight, height, fitness_goal): try: age = float(age); weight = float(weight); height = float(height) except Exception: return 0 if gender == "Male": bmr = 10 * weight + 6.25 * height - 5 * age + 5 else: bmr = 10 * weight + 6.25 * height - 5 * age - 161 if fitness_goal == "Weight Loss": return int(bmr * 1.2) if fitness_goal == "Weight Gain": return int(bmr * 1.5) return int(bmr * 1.375) AYURVEDA_PROMPT = """ You are an expert in modern medicine and Ayurveda. Create a concise personalized weekly diet & exercise plan for {name}, a {age}-year-old {gender} with BMI {bmi} ({health_status}). Fitness Goal: {fitness_goal} Daily Calories: {daily_calories} kcal Diet Preference: {dietary_preference} Food Allergies: {food_allergies} Local Cuisine: {local_cuisine} Month: {month} Return short bullets for each weekday (Mon..Sun). """ REGULAR_PROMPT = """ You are a health expert. Create a concise personalized weekly diet & exercise plan for {name}, a {age}-year-old {gender} with BMI {bmi} ({health_status}). Fitness Goal: {fitness_goal} Daily Calories: {daily_calories} kcal Diet Preference: {dietary_preference} Food Allergies: {food_allergies} Local Cuisine: {local_cuisine} Month: {month} Return short bullets for each weekday (Mon..Sun). """ def call_gemini(prompt_text, model_name=MODEL): """ Calls client.models.generate_content exactly as in the official quickstart: client.models.generate_content(model=..., contents=...) Returns the best available text representation (response.text or fallbacks). """ try: # Per quickstart: use `contents=` (can be a string or structured contents) response = client.models.generate_content(model=model_name, contents=prompt_text) except Exception as e: return f"Error calling Gemini API: {e}" # Preferred accessor per docs/examples if hasattr(response, "text") and response.text: return response.text # Fallbacks for various SDK response shapes: # - candidates -> content -> parts -> text try: cand = getattr(response, "candidates", None) if cand: first = cand[0] # dict-like candidate with nested content->parts if isinstance(first, dict): content = first.get("content") or {} parts = content.get("parts") or [] if parts: texts = [] for p in parts: if isinstance(p, dict) and p.get("text"): texts.append(p.get("text")) elif isinstance(p, str): texts.append(p) if texts: return "\n".join(texts) # if candidate object has .content.parts style try: parts = first.get("content", {}).get("parts", []) except Exception: parts = [] if parts: out = [] for p in parts: t = p.get("text") if isinstance(p, dict) else str(p) out.append(t) return "\n".join(out) except Exception: pass # Last resort: try response.output or stringified response try: if hasattr(response, "output"): return str(response.output) except Exception: pass return str(response) def generate_plan(name, age, weight, height, gender, fitness_goal, dietary_preference, food_allergies, local_cuisine, month, include_ayurveda): # validate numeric values try: age_f = float(age); weight_f = float(weight); height_f = float(height) except Exception: return "Please enter valid numeric values for age, weight, and height." bmi = round(weight_f / (height_f / 100) ** 2, 2) health_status = "Underweight" if bmi < 18.5 else "Normal weight" if bmi <= 24.9 else "Overweight" daily_calories = calculate_calorie_requirements(age_f, gender, weight_f, height_f, fitness_goal) metrics = { "name": name or "User", "age": int(age_f), "gender": gender, "bmi": bmi, "health_status": health_status, "fitness_goal": fitness_goal, "dietary_preference": dietary_preference, "food_allergies": food_allergies or "None", "daily_calories": daily_calories, "local_cuisine": local_cuisine or "Local", "month": month or "" } prompt_template = AYURVEDA_PROMPT if include_ayurveda else REGULAR_PROMPT prompt = prompt_template.format(**metrics) text = call_gemini(prompt, model_name=MODEL) header = f"BMI: {bmi} ({health_status})\nEstimated calories/day: {daily_calories} kcal\n\n" return header + text # --- Gradio UI --- with gr.Blocks(title="AI Health Advisor") as demo: gr.Markdown("# 🩺 AI-Based Personalized Weekly Diet & Exercise Planner (Gemini quickstart style)") with gr.Row(): with gr.Column(): name_in = gr.Textbox(label="Name") age_in = gr.Number(label="Age", value=25) weight_in = gr.Number(label="Weight (kg)", value=70) height_in = gr.Number(label="Height (cm)", value=170) gender_in = gr.Dropdown(label="Gender", choices=["Male", "Female", "Other"], value="Male") goal_in = gr.Dropdown(label="Fitness Goal", choices=["Weight Loss", "Weight Gain", "Maintenance"], value="Maintenance") diet_in = gr.Dropdown(label="Diet Preference", choices=["Vegetarian", "Vegan", "Keto", "Halal", "None"], value="None") allergy_in = gr.Textbox(label="Food Allergies") cuisine_in = gr.Textbox(label="Local Cuisine") month_in = gr.Dropdown(label="Month", choices=[ "January","February","March","April","May","June","July","August","September","October","November","December" ], value="October") ayurveda_in = gr.Checkbox(label="Include Ayurvedic Insights", value=True) btn = gr.Button("Generate Plan") with gr.Column(): output = gr.Textbox(label="Generated Plan", lines=25) btn.click( generate_plan, inputs=[name_in, age_in, weight_in, height_in, gender_in, goal_in, diet_in, allergy_in, cuisine_in, month_in, ayurveda_in], outputs=output ) if __name__ == "__main__": demo.launch(server_name="0.0.0.0", share=False)