Spaces:
Sleeping
Sleeping
import gradio as gr | |
import requests | |
import os | |
from fpdf import FPDF | |
import uuid | |
import re | |
import matplotlib.pyplot as plt | |
# 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): | |
pattern = r"Calories:\s*([\d\.]+)\s*kcal.*Protein:\s*([\d\.]+)g.*Carbs:\s*([\d\.]+)g.*Fat:\s*([\d\.]+)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() | |
filename = f"/tmp/nutrition_{uuid.uuid4().hex}.png" | |
plt.savefig(filename) | |
plt.close(fig) | |
return filename | |
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) | |
filename = f"/tmp/AgentChef_Recipe_{uuid.uuid4().hex}.pdf" | |
pdf.output(filename) | |
return filename | |
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.Microphone(label="🎤 Speak Ingredients") | |
mic.stream(lambda audio: audio if audio else "", inputs=None, 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) | |
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() | |