Skip to content

Commit f2ebe4c

Browse files
authored
Add Custom Ingredient Selection (#20)
--- Add Custom Ingredient Selection --- <!-- make this PR easy to find: - assign and add reviewers - add any helpful labels - connect it to a milestone (if necessary) - link it with an issue (if necessary) --> <!-- A clear and concise description of what the Pull Request is about. --> ## General Checks - [ ] the branch is up to date with `main` - [ ] the code works when pulled and run locally - [ ] All CI checks pass (or at least discussed) - [ ] all conflicts are resolved (if any) - [ ] PR has a descriptive title - [ ] PR has appropriate labels and milestones for easy identification - [ ] PR it is assigned to the owner - [ ] reviewers are assigned - [ ] the PR contributes only one focused change - [ ] It is in the appropriate column in the project board (if necessary) - [ ] has short and clear description - [ ] is linked to an issue (if it is related) - [ ] feedback is addressed (if any and if it is appropriate feedback.) ## Markdown <!-- markdown-specific checks --> - [ ] the markdown source is formatted - [ ] spelling and grammar is correct in all text - [ ] The markdown looks correct when you preview the file - [ ] all links and images work
2 parents 1e18b60 + ce74e62 commit f2ebe4c

File tree

7 files changed

+388
-186
lines changed

7 files changed

+388
-186
lines changed
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# spell-checker: disable
2+
"""
3+
Clean recipe CSV and create SQLite DB with diet type.
4+
"""
5+
6+
import re
7+
import sqlite3
8+
9+
import pandas as pd
10+
11+
# Load CSV
12+
df = pd.read_csv("smart_pantry_manager/data/Recipe_Dataset.csv")
13+
14+
# Forbidden (haram) ingredients
15+
haram_keywords = [
16+
"pork",
17+
"ham",
18+
"bacon",
19+
"prosciutto",
20+
"pancetta",
21+
"sausage",
22+
"wine",
23+
"beer",
24+
"bourbon",
25+
"rum",
26+
"whisky",
27+
"vodka",
28+
"tequila",
29+
"cognac",
30+
"brandy",
31+
"liqueur",
32+
"alcohol",
33+
"champagne",
34+
"sake",
35+
"sherry",
36+
"gin",
37+
]
38+
39+
# Meat ingredients
40+
meat_keywords = [
41+
"chicken",
42+
"beef",
43+
"lamb",
44+
"turkey",
45+
"fish",
46+
"shrimp",
47+
"salmon",
48+
"tuna",
49+
"meat",
50+
"steak",
51+
"duck",
52+
"anchovy",
53+
"crab",
54+
"lobster",
55+
"clam",
56+
"oyster",
57+
"scallop",
58+
"mussel",
59+
"squid",
60+
"sausage",
61+
]
62+
63+
# Animal products (vegetarian)
64+
animal_product_keywords = [
65+
"egg",
66+
"milk",
67+
"cheese",
68+
"butter",
69+
"cream",
70+
"yogurt",
71+
"ghee",
72+
"honey",
73+
"mayonnaise",
74+
"whey",
75+
"casein",
76+
"gelatin",
77+
]
78+
79+
80+
# Check haram
81+
def contains_haram(ingredient_text):
82+
if pd.isna(ingredient_text):
83+
return False
84+
text = ingredient_text.lower()
85+
for kw in haram_keywords:
86+
if re.search(rf"\b{kw}\b", text):
87+
return True
88+
return False
89+
90+
91+
# Classify diet type
92+
def classify_diet_type(ingredient_text):
93+
if pd.isna(ingredient_text):
94+
return "Unknown"
95+
text = ingredient_text.lower()
96+
for kw in meat_keywords:
97+
if re.search(rf"\b{kw}\b", text):
98+
return "Non-Vegetarian"
99+
for kw in animal_product_keywords:
100+
if re.search(rf"\b{kw}\b", text):
101+
return "Vegetarian"
102+
return "Vegan"
103+
104+
105+
# Filter haram
106+
df["contains_haram"] = df["Ingredients"].apply(contains_haram)
107+
df_clean = df[~df["contains_haram"]].copy()
108+
df_clean["Diet_Type"] = df_clean["Ingredients"].apply(classify_diet_type)
109+
df_clean.drop("contains_haram", axis=1, inplace=True)
110+
111+
# SQLite DB
112+
conn = sqlite3.connect("smart_pantry_manager/data/cleaned_data.sqlite")
113+
114+
# Tables for each diet type
115+
for diet in ["Vegan", "Vegetarian", "Non-Vegetarian"]:
116+
diet_df = df_clean[df_clean["Diet_Type"] == diet].copy()
117+
diet_df.to_sql(
118+
diet.lower().replace("-", "_") + "_recipes",
119+
conn,
120+
if_exists="replace",
121+
index=False,
122+
)
123+
124+
# Combined table
125+
df_clean.to_sql("all_recipes", conn, if_exists="replace", index=False)
126+
127+
conn.close()
128+
print("✅ SQLite DB created with all_recipes and diet tables.")
45.8 MB
Binary file not shown.
5.18 KB
Binary file not shown.
Lines changed: 66 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,87 @@
11
# spell-checker: disable
22
"""
3-
All Recipes Page for Smart Pantry Application (SQLite version)
3+
All Recipes Page
4+
Shows all recipes and diet type from cleaned_data.sqlite
45
"""
56

7+
import ast
8+
import os
69
import sqlite3
10+
711
import pandas as pd
812
import streamlit as st
913

1014
st.set_page_config(page_title="All Recipes", page_icon="📜", layout="wide")
11-
1215
st.title("📜 All Recipes")
13-
st.caption("Browse all available recipes in the Smart Pantry system.")
16+
st.caption("Browse all recipes with diet type from Smart Pantry DB.")
17+
18+
DB_PATH = os.path.join("smart_pantry_manager", "data", "cleaned_data.sqlite")
1419

1520

16-
# ---------- Load recipes from SQLite ----------
21+
# ---------- Load Recipes ----------
1722
@st.cache_data
1823
def load_recipes():
19-
"""
20-
Load recipes from the SQLite database and normalize column names.
21-
Returns a DataFrame with columns: Recipe, Ingredients, Instructions
22-
"""
23-
db_path = "the_app/data/Recipe_Dataset.sqlite"
24-
25-
# Connect to SQLite database
26-
conn = sqlite3.connect(db_path)
27-
28-
# Load the table "recipes"
29-
df = pd.read_sql_query("SELECT * FROM recipes", conn)
30-
24+
if not os.path.exists(DB_PATH):
25+
st.error("❌ Recipes database not found.")
26+
return pd.DataFrame(
27+
columns=["Title", "Ingredients", "Instructions", "Diet_Type"]
28+
)
29+
conn = sqlite3.connect(DB_PATH)
30+
try:
31+
df = pd.read_sql("SELECT * FROM all_recipes", conn)
32+
except Exception as e:
33+
st.error(f"Error loading recipes: {e}")
34+
conn.close()
35+
return pd.DataFrame(
36+
columns=["Title", "Ingredients", "Instructions", "Diet_Type"]
37+
)
3138
conn.close()
32-
33-
# Normalize column names
34-
df.columns = [c.strip().lower() for c in df.columns]
35-
36-
# Rename columns if they exist
37-
rename_map = {
38-
"title": "Recipe",
39-
"cleaned_ingredients": "Ingredients",
40-
"instruction": "Instructions",
41-
"instructions": "Instructions",
42-
}
43-
df.rename(
44-
columns={k: v for k, v in rename_map.items() if k in df.columns}, inplace=True
45-
)
46-
47-
# Keep only required columns
48-
required_cols = ["Recipe", "Ingredients", "Instructions"]
49-
df = df[[col for col in required_cols if col in df.columns]]
50-
39+
# Ensure required columns exist
40+
for col in ["Title", "Ingredients", "Instructions", "Diet_Type"]:
41+
if col not in df.columns:
42+
df[col] = ""
5143
return df
5244

5345

5446
recipes = load_recipes()
55-
56-
# ---------- Display recipes ----------
5747
if recipes.empty:
5848
st.info("No recipes found.")
59-
else:
60-
search = st.text_input("🔍 Search for a recipe:")
61-
filtered = (
62-
recipes[recipes["Recipe"].str.contains(search, case=False, na=False)]
63-
if search
64-
else recipes
65-
)
66-
67-
for _, row in filtered.iterrows():
68-
with st.expander(row["Recipe"]):
69-
st.markdown(f"**🧂 Ingredients:** {row['Ingredients']}")
70-
st.markdown(f"**👩‍🍳 Instructions:** {row['Instructions']}")
49+
st.stop()
50+
51+
52+
# ---------- Parse Ingredients ----------
53+
def parse_ingredients(ingredients_str):
54+
if pd.isna(ingredients_str):
55+
return []
56+
try:
57+
if ingredients_str.startswith("[") and ingredients_str.endswith("]"):
58+
parsed = ast.literal_eval(ingredients_str)
59+
return [str(x).strip() for x in parsed if str(x).strip()]
60+
elif "," in ingredients_str:
61+
return [x.strip() for x in ingredients_str.split(",") if x.strip()]
62+
else:
63+
return [ingredients_str]
64+
except Exception:
65+
return [ingredients_str]
66+
67+
68+
# ---------- Display Recipes ----------
69+
for _, row in recipes.iterrows():
70+
title = str(row.get("Title", "Unnamed Recipe"))
71+
diet = str(row.get("Diet_Type", "Unknown"))
72+
with st.expander(f"📖 {title}{diet}"):
73+
col1, col2 = st.columns([1, 2])
74+
with col1:
75+
st.markdown(f"**Diet Type:** {diet}")
76+
with col2:
77+
st.markdown("**🧂 Ingredients:**")
78+
# Parse ingredients safely
79+
ing_list = parse_ingredients(row.get("Ingredients", ""))
80+
if ing_list:
81+
for ing in ing_list:
82+
st.write(f"• {ing}")
83+
else:
84+
st.write("No ingredient data available.")
85+
st.markdown("**👩‍🍳 Instructions:**")
86+
# Show full instructions
87+
st.write(str(row.get("Instructions", "No instructions available.")))

0 commit comments

Comments
 (0)