ecoChef / meal_planner.py
tejasashinde's picture
Added project
d9d1fcf
import os
from openai import OpenAI
import json
def call_llm(prompt, api_key):
try:
client = OpenAI(
base_url="https://api.studio.nebius.com/v1/",
api_key=api_key
)
response = client.chat.completions.create(
model="meta-llama/Llama-3.3-70B-Instruct",
max_tokens=1024,
temperature=0.6,
top_p=0.9,
extra_body={"top_k": 50},
messages=[
{
"role": "system",
"content": """You are an eco-conscious recipe planner. Use the provided ingredient data to minimize food waste and carbon footprint.
### Instructions:
1. Provide json values with the following keys for given data:
• Ingredient (Qty: if specified)
• Expiry / Shelf Life (use 'X days left' if available, else 'Unknown')
• Spoilage Risk (high, medium, low — assume only if missing)
• Carbon Footprint (kg CO₂e/kg — assume only if missing)
- Only assume values **if the field is null or missing**, and **only if the ingredient is a known food item**.
- When assuming missing values, refer to other similar ingredients in the data as examples for expected format and typical values.
- Fields eligible for assumption (only under above condition):
• spoilage → risk
• carbon → estimated_kg_CO2e_per_kg
• parsed → days_left
- Use all other values exactly as provided without change.
2. Summary of carbon footprint based on provided ingredients in friendly tone.
3. Provide new 2-3 simple recipe ideas (bulleted or numbered) for ingredients focusing more on high risk to reduce food spoilage. Keep recipes simple, using common household ingredients and easy steps. Give everything as JSON format.
4. Present your answer in clear sections as below:
(a) Json ingredients table with all data.
(b) Carbon footprint overview and impact of ingredients present in json data.
(c) Suggested meals to reduce food spoilage: i. recipe name, ii. ingredients, iii. preparation steps
(d) Alternative ingredients to reduce carbon emissions from your fridge/pantry (if possible). Also, If possible suggest ingredient substitutions reasons (e.g. high carbon footprint).
(e) End with single sentence why and how your recomendation reduces food wastage and also helps user carbon emissions. give appropriate examples with slight pun (like might save trips to some destination)"""
},
{
"role": "user",
"content": prompt # ← Inject user-provided ingredient data here
}
]
)
parsed_json = json.loads(response.to_json())
# Extract the 'content' safely
try:
content = parsed_json["choices"][0]["message"]["content"]
except (KeyError, IndexError) as e:
content = None
print("Failed to get content from LLM:", e)
return content
except Exception as e:
return [f"Error generating recipes: {str(e)}"]
# === LLM-powered meal planner ===
def generate_meal_plan(parsed_items, spoilage, carbon, parsed, api_key):
if not parsed_items:
return [{"note": "No ingredients found to suggest recipes."}]
parsed_names = [item.get("name", "").lower() for item in parsed_items]
spoilage_dict = {item["name"].lower(): item["risk"].lower() for item in spoilage}
carbon_dict = {
item["name"].lower(): item.get("estimated_kg_CO2e_per_kg", "unknown")
for item in carbon
}
# Categorize by spoilage risk
high_risk = [name for name in parsed_names if spoilage_dict.get(name) == "high"]
medium_risk = [name for name in parsed_names if spoilage_dict.get(name) == "medium"]
low_risk = [name for name in parsed_names if spoilage_dict.get(name) == "low"]
# Construct note with carbon footprint
def format_item(name, risk_level):
co2e = carbon_dict.get(name, "unknown")
return f"- {name.title()} (Risk: {risk_level.title()}, CO₂e: {co2e} kg/kg)"
note_lines = ["Suggesting recipes based on spoilage risk:"]
for name in high_risk:
note_lines.append(format_item(name, "high"))
for name in medium_risk:
note_lines.append(format_item(name, "medium"))
for name in low_risk:
note_lines.append(format_item(name, "low"))
if not high_risk and not medium_risk:
note_lines.append("- No items at spoilage risk. Showing general ideas.")
# Format CO2 label with risk
def co2_label(name):
co2 = carbon_dict.get(name, "unknown")
return f"{name} (CO₂e: {co2} kg/kg)"
# Add detailed ingredient info from 'parsed'
parsed_ingredient_info = "Ingredient details:\n"
for item in parsed:
name = item.get("name", "unknown").strip().lower()
qty = item.get("quantity", "unknown")
expiry = item.get("expiry_date", "unknown")
days_left = item.get("days_left")
parsed_ingredient_info += (
f"- {name.title()}: Quantity = {qty}, "
f"Expiry Date = {expiry}, Days Left = {days_left}\n"
)
# Construct prompt with all context
prompt = (
"You are an eco-conscious recipe planner. Use the provided ingredient data to minimize food waste and carbon footprint.\n\n"
"### Data for processing is as follows:\n"
"- Spoilage info:\n"
f"{json.dumps(spoilage, indent=2)}\n\n"
"- Carbon footprint info:\n"
f"{json.dumps(carbon, indent=2)}\n\n"
"- Parsed ingredient details:\n"
f"{json.dumps(parsed, indent=2)}\n\n"
)
recipes = call_llm(prompt, api_key)
note_lines = ["Suggesting recipes based on spoilage risk and carbon footprint:"]
for name in high_risk:
cf = carbon_dict.get(name, "N/A")
note_lines.append(f"- {name.title()} (Risk: High, CO₂e: {cf} kg/kg)")
for name in medium_risk:
cf = carbon_dict.get(name, "N/A")
note_lines.append(f"- {name.title()} (Risk: Medium, CO₂e: {cf} kg/kg)")
if not high_risk and not medium_risk:
note_lines.append("- No items at spoilage risk. Showing general ideas.")
return [
{"note": "\n".join(note_lines)},
{"recipes": recipes}
]