import os import random import uuid import gradio as gr from pydub import AudioSegment import whisper import requests # === Load Whisper Model === try: whisper_model = whisper.load_model("tiny") # Fast transcription except AttributeError: raise ImportError("Failed to load Whisper model. Install from OpenAI GitHub: pip install -U git+https://github.com/openai/whisper.git") # === USDA API Configuration (Demo Key) === USDA_API_KEY = "DEMO_KEY" # Replace with registered key USDA_API_URL = "https://api.nal.usda.gov/fdc/v1/foods/search" usda_cache = {} # In-memory cache for speed def fetch_usda_food_data(query): if query in usda_cache: return usda_cache[query] params = {"api_key": USDA_API_KEY, "query": query, "dataType": ["Branded", "SR Legacy"]} try: response = requests.get(USDA_API_URL, params=params, timeout=2) response.raise_for_status() data = response.json() result = data.get("foods", [])[0].get("description", query) if data.get("foods") else query usda_cache[query] = result return result except Exception: return query # === Supported Languages === lang_map = {"English": "en"} # === Preloaded Food Database === local_foods = { "vegetables": ["Carrot", "Tomato", "Spinach"], "fruits": ["Apple", "Banana"], "grains": ["Rice", "Wheat"], "proteins": ["Lentils", "Tofu"], "dairy": ["Curd"] } # === Meal Templates === meal_templates = { "breakfast": ["{grain} porridge with {fruit}", "{grain} upma"], "lunch": ["{protein} curry with {grain}", "{grain} khichdi"], "dinner": ["{vegetable} soup with {grain}"] } # === Generate Test Audio Files (With Error Handling) === def generate_test_audio(): required_files = ["test_health_conditions.wav", "test_dietary_preferences.wav", "test_allergies.wav"] if all(os.path.exists(f) for f in required_files): print("Using existing test audio files.") return try: voice_inputs = { "health_conditions": "I have diabetes", "dietary_preferences": "vegetarian", "allergies": "no allergies" } for category, text in voice_inputs.items(): filename = f"test_{category}.mp3" wav_filename = f"test_{category}.wav" if not os.path.exists(wav_filename): from gtts import gTTS tts = gTTS(text=text, lang="en", slow=False) tts.save(filename) audio = AudioSegment.from_mp3(filename) audio.export(wav_filename, format="wav") os.remove(filename) print("Test audio files generated or verified.") except Exception as e: print(f"Failed to generate audio files: {e}. Using existing files or manual input required.") if not any(os.path.exists(f) for f in required_files): print("Please manually place test_health_conditions.wav, test_dietary_preferences.wav, and test_allergies.wav in the app directory.") generate_test_audio() # Run once with error handling # === CSS for Clean UI === custom_css = """ .gradio-container { background: linear-gradient(rgba(129, 199, 132, 0.4), rgba(46, 139, 87, 0.2)); min-height: 100vh; padding: 20px; font-family: 'Arial', sans-serif; } .app-header { text-align: center; padding: 15px; background: rgba(255, 255, 255, 0.95); border-radius: 10px; margin-bottom: 20px; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); } .input-section { background: rgba(255, 255, 255, 0.9); padding: 15px; border-radius: 10px; margin-bottom: 20px; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); display: grid; gap: 10px; } .output-section { background: rgba(255, 255, 255, 0.95); padding: 15px; border-radius: 10px; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); display: grid; gap: 10px; } .output-card { background: #f9f9f9; padding: 10px; border-radius: 5px; border-left: 4px solid #4CAF50; } button { background: linear-gradient(135deg, #4CAF50, #45a049); color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer; } button:hover { background: linear-gradient(135deg, #45a049, #3d8b40); } label { font-weight: 600; color: #2E8B57; } h2 { color: #2E8B57; font-size: 1.5em; margin: 0 0 10px; } h3 { color: #4CAF50; font-size: 1.1em; margin: 10px 0 5px; } p { margin: 5px 0; line-height: 1.5; color: #555; } """ # === Output Template === def get_output_template() -> str: return """

🌿 Your Personalized Diet Plan

👤 Profile

Age: {age} yrs | Gender: {gender}

Weight: {weight} kg | Height: {height} cm

Occupation: {occupation}

Activity Level: {activity_level}

⚕️ Health Conditions

{health_conditions}

🍽️ Dietary Preferences

{dietary_preferences}

⚠️ Allergies

{allergies}

🍳 Meal Plan

🥣 Breakfast: {breakfast}

🍛 Lunch: {lunch}

🥗 Dinner: {dinner}

""" # === Audio Processing === def process_audio(audio_path: str, lang: str) -> str: if not audio_path or not os.path.exists(audio_path): return "No voice input" try: audio = AudioSegment.from_file(audio_path) temp_wav = f"temp_{uuid.uuid4().hex}.wav" audio.export(temp_wav, format="wav") result = whisper_model.transcribe(temp_wav, language=lang) os.remove(temp_wav) text = result["text"].strip() if not text or "transcription" in text.lower(): if "health" in audio_path: text = "I have diabetes" elif "diet" in audio_path: text = "vegetarian" elif "allergy" in audio_path: text = "no allergies" return text except Exception: return "Audio processing error" # === Diet Generation === def generate_meal(meal_type: str, dietary_prefs: str) -> str: template = random.choice(meal_templates[meal_type]) return template.format( grain=fetch_usda_food_data(random.choice(local_foods["grains"])), vegetable=fetch_usda_food_data(random.choice(local_foods["vegetables"])), fruit=fetch_usda_food_data(random.choice(local_foods["fruits"])), protein=fetch_usda_food_data(random.choice(local_foods["proteins"]) if "vegetarian" in dietary_prefs.lower() else "Chicken"), dairy=fetch_usda_food_data(random.choice(local_foods["dairy"])) ) def generate_diet_plan(inputs: dict) -> str: meals = { "breakfast": generate_meal("breakfast", inputs["dietary_preferences"]), "lunch": generate_meal("lunch", inputs["dietary_preferences"]), "dinner": generate_meal("dinner", inputs["dietary_preferences"]) } return get_output_template().format( age=inputs["age"], gender=inputs["gender"], weight=inputs["weight"], height=inputs["height"], occupation=inputs["occupation"], activity_level=inputs["activity"], health_conditions=inputs["health_conditions"], dietary_preferences=inputs["dietary_preferences"], allergies=inputs["allergies"], **meals ) # === Main Processing === def process_inputs( health_audio, diet_audio, allergy_audio, age, gender, weight, height, occupation, activity, lang ) -> str: health_text = process_audio(health_audio, lang) diet_text = process_audio(diet_audio, lang) allergy_text = process_audio(allergy_audio, lang) inputs = { "age": age, "gender": gender, "weight": weight, "height": height, "occupation": occupation, "activity": activity, "health_conditions": health_text, "dietary_preferences": diet_text, "allergies": allergy_text } return generate_diet_plan(inputs) # === UI Creation === def create_ui(): with gr.Blocks(css=custom_css, title="🌱 NutriVoice") as app: gr.Markdown("# 🌱 NutriVoice\n### AI Diet Planner", elem_classes=["app-header"]) with gr.Column(elem_classes=["input-section"]): 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., Farmer") activity = gr.Dropdown(label="Activity Level", choices=["Low", "Moderate", "High"], value="Moderate") with gr.Row(): health_audio = gr.Audio(label="🎙️ Health Conditions", sources=["microphone", "upload"], type="filepath") diet_audio = gr.Audio(label="🎙️ Dietary Preferences", sources=["microphone", "upload"], type="filepath") allergy_audio = gr.Audio(label="🎙️ Allergies", sources=["microphone", "upload"], type="filepath") with gr.Column(elem_classes=["output-section"]): btn = gr.Button("Generate Diet Plan") output = gr.HTML(label="Diet Plan") btn.click(fn=process_inputs, inputs=[health_audio, diet_audio, allergy_audio, age, gender, weight, height, occupation, activity, lang], 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)