File size: 10,096 Bytes
f757d1a 13d3d93 8aad262 8344664 a910f40 f757d1a 80ea744 2576f99 80ea744 d81763e b5d91cd 8344664 1c04bb5 8344664 2576f99 1c04bb5 2576f99 1c04bb5 2576f99 8344664 1e5434c 1c04bb5 1e5434c 1c04bb5 1e5434c f757d1a 1e5434c f757d1a 1e5434c 2576f99 1e5434c 2576f99 1c04bb5 2576f99 1c04bb5 2576f99 1e5434c 80ea744 1e5434c 8344664 1e5434c 97aee12 1e5434c 1c04bb5 1e5434c 04e72d8 1e5434c 04e72d8 1e5434c 04e72d8 1e5434c 04e72d8 1e5434c 04e72d8 1e5434c 04e72d8 2f3f67d 4ae2592 2576f99 f757d1a 97aee12 f757d1a b5d91cd 13d3d93 d81763e 2576f99 1c04bb5 13d3d93 d81763e 8344664 d81763e 8344664 d81763e 8344664 d81763e 1c04bb5 f757d1a 97aee12 1c04bb5 8344664 1e5434c 1c04bb5 8344664 1c04bb5 8344664 1e5434c 1c04bb5 9b37648 8344664 9b37648 1c04bb5 9b37648 1e5434c 9b37648 1c04bb5 97aee12 f757d1a 1c04bb5 1e5434c 97aee12 f757d1a 1e5434c 97aee12 1c04bb5 97aee12 1e5434c f757d1a 1e5434c f757d1a 1e5434c 8be9cc8 1e5434c f757d1a 1c04bb5 97aee12 5401ee1 97aee12 5401ee1 97aee12 1e5434c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
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) |