AgentChef / app.py
ParthBhuptani's picture
Update app.py
c1285f8 verified
raw
history blame
5.5 kB
import gradio as gr
import requests
import os
from fpdf import FPDF
import uuid
import re
import matplotlib.pyplot as plt
import tempfile
# Load your Nebius API key and Folder ID from environment variables
NEBIUS_API_KEY = os.getenv("NEBIUS_API_KEY") or "YOUR_NEBIUS_API_KEY"
FOLDER_ID = os.getenv("FOLDER_ID") or "YOUR_FOLDER_ID"
def generate_meal(preferences, ingredients, time):
prompt = f"""
You're a smart kitchen agent.
Given:
- Dietary preferences: {preferences}
- Ingredients available: {ingredients}
- Time available: {time} minutes
Tasks:
1. Suggest one meal idea
2. Provide step-by-step recipe instructions
3. List missing ingredients (Shopping List)
4. Estimate nutrition (calories, protein, carbs, fat)
Output in this format:
Meal Name: ...
Steps:
1. ...
2. ...
Shopping List:
- ...
Nutrition:
- Calories: ... kcal
- Protein: ... g
- Carbs: ... g
- Fat: ... g
"""
headers = {
"Authorization": f"Api-Key {NEBIUS_API_KEY}",
"Content-Type": "application/json"
}
data = {
"modelUri": f"gpt://{FOLDER_ID}/yandexgpt-lite",
"completionOptions": {"stream": False, "temperature": 0.7, "maxTokens": 700},
"messages": [{"role": "user", "text": prompt.strip()}]
}
response = requests.post(
"https://llm.api.cloud.yandex.net/foundationModels/v1/completion",
headers=headers, json=data
)
try:
text = response.json()["result"]["alternatives"][0]["message"]["text"]
except Exception as e:
return f"❌ Error: Could not fetch recipe. {e}"
return text
def extract_nutrition(recipe_text):
# More robust pattern allowing newlines and flexible spacing
pattern = (
r"Calories:\s*([\d\.]+)\s*kcal.*?"
r"Protein:\s*([\d\.]+)\s*g.*?"
r"Carbs:\s*([\d\.]+)\s*g.*?"
r"Fat:\s*([\d\.]+)\s*g"
)
match = re.search(pattern, recipe_text.replace("\n", " "))
if match:
calories, protein, carbs, fat = map(float, match.groups())
return {"Calories": calories, "Protein": protein, "Carbs": carbs, "Fat": fat}
return None
def plot_nutrition_chart(nutrition):
fig, ax = plt.subplots()
nutrients = list(nutrition.keys())
values = list(nutrition.values())
colors = ['#ff9999','#66b3ff','#99ff99','#ffcc99']
ax.pie(values, labels=nutrients, autopct='%1.1f%%', startangle=140, colors=colors)
ax.axis('equal')
plt.tight_layout()
temp_file = tempfile.NamedTemporaryFile(suffix=".png", delete=False)
plt.savefig(temp_file.name)
plt.close(fig)
return temp_file.name
def handle_generate(preferences, ingredients, time):
recipe = generate_meal(preferences, ingredients, time)
nutrition = extract_nutrition(recipe)
chart_path = None
if nutrition:
chart_path = plot_nutrition_chart(nutrition)
return recipe, chart_path
def save_pdf(recipe_text):
pdf = FPDF()
pdf.add_page()
pdf.set_font("Arial", size=12)
for line in recipe_text.split('\n'):
pdf.multi_cell(0, 10, line)
temp_file = tempfile.NamedTemporaryFile(suffix=".pdf", delete=False)
pdf.output(temp_file.name)
return temp_file.name
# Optional: placeholder function for speech-to-text (you can replace with real STT)
def dummy_speech_to_text(audio):
# This just returns a fixed string for demo. Replace with actual STT model call if you want.
if audio is None:
return ""
return "tomato, onion, garlic"
with gr.Blocks(css="""
body { background-color: #111; color: #eee; font-family: 'Segoe UI', sans-serif; }
.gradio-container { max-width: 900px; margin: auto; }
.input-label { font-weight: 600; margin-bottom: 5px; }
.footer { font-size: 0.8rem; color: #666; padding: 10px; text-align: center; }
@media (max-width: 600px) {
.gradio-container { padding: 10px; }
}
""") as demo:
gr.Markdown("# 👨‍🍳 AgentChef: AI Recipe Planner & Smart Kitchen Assistant")
with gr.Row():
with gr.Column(scale=1, min_width=200):
preferences = gr.Textbox(label="🥗 Dietary Preferences", placeholder="e.g. vegetarian, keto")
ingredients = gr.Textbox(label="🧂 Ingredients You Have", placeholder="e.g. rice, tomato, onion", lines=3)
mic = gr.Audio(type="filepath", label="🎤 Speak Ingredients")
transcribed = gr.Textbox(label="📝 Transcribed Ingredients (from mic)", interactive=False)
mic.change(dummy_speech_to_text, inputs=mic, outputs=transcribed)
# Add a button to copy transcribed text to ingredients textbox if needed
copy_btn = gr.Button("Copy Transcription to Ingredients")
copy_btn.click(lambda txt: txt, inputs=transcribed, outputs=ingredients)
time = gr.Slider(5, 60, value=20, step=5, label="⏱️ Time Available (minutes)")
generate_btn = gr.Button("🍽️ Generate Recipe")
with gr.Column(scale=1, min_width=300):
recipe_output = gr.Textbox(label="📝 Recipe Output", lines=15, interactive=False)
nutrition_chart = gr.Image(label="📊 Nutrition Breakdown", interactive=False)
pdf_btn = gr.Button("📄 Export as PDF")
generate_btn.click(handle_generate,
inputs=[preferences, ingredients, time],
outputs=[recipe_output, nutrition_chart])
pdf_btn.click(save_pdf, inputs=[recipe_output], outputs=gr.File(label="📥 Download Recipe PDF"))
demo.launch()