MaheshP98's picture
Update app.py
2576f99 verified
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 """
<div class="output-section">
<h2>🌿 Your Personalized Diet Plan</h2>
<div class="output-card">
<h3>πŸ‘€ Profile</h3>
<p><strong>Age:</strong> {age} yrs | <strong>Gender:</strong> {gender}</p>
<p><strong>Weight:</strong> {weight} kg | <strong>Height:</strong> {height} cm</p>
<p><strong>Occupation:</strong> {occupation}</p>
<p><strong>Activity Level:</strong> {activity_level}</p>
</div>
<div class="output-card">
<h3>βš•οΈ Health Conditions</h3>
<p>{health_conditions}</p>
</div>
<div class="output-card">
<h3>🍽️ Dietary Preferences</h3>
<p>{dietary_preferences}</p>
</div>
<div class="output-card">
<h3>⚠️ Allergies</h3>
<p>{allergies}</p>
</div>
<div class="output-card">
<h3>🍳 Meal Plan</h3>
<p><strong>πŸ₯£ Breakfast:</strong> {breakfast}</p>
<p><strong>πŸ› Lunch:</strong> {lunch}</p>
<p><strong>πŸ₯— Dinner:</strong> {dinner}</p>
</div>
</div>
"""
# === 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)