diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index e69de29..0000000 diff --git a/smart_pantry_manager/data/clean_data b/smart_pantry_manager/data/clean_data.py similarity index 100% rename from smart_pantry_manager/data/clean_data rename to smart_pantry_manager/data/clean_data.py diff --git a/smart_pantry_manager/data/pantry_data.xlsx b/smart_pantry_manager/data/pantry_data.xlsx deleted file mode 100644 index 317f359..0000000 Binary files a/smart_pantry_manager/data/pantry_data.xlsx and /dev/null differ diff --git a/smart_pantry_manager/data/pantry_omnia.xlsx b/smart_pantry_manager/data/pantry_omnia.xlsx deleted file mode 100644 index c5b3b23..0000000 Binary files a/smart_pantry_manager/data/pantry_omnia.xlsx and /dev/null differ diff --git a/smart_pantry_manager/data/user_data/pantry_azozomer743@gmail.com.xlsx b/smart_pantry_manager/data/user_data/pantry_azozomer743@gmail.com.xlsx new file mode 100644 index 0000000..09a996d Binary files /dev/null and b/smart_pantry_manager/data/user_data/pantry_azozomer743@gmail.com.xlsx differ diff --git a/smart_pantry_manager/pages/recommended_recipes.py b/smart_pantry_manager/pages/1- recommended_recipes.py similarity index 98% rename from smart_pantry_manager/pages/recommended_recipes.py rename to smart_pantry_manager/pages/1- recommended_recipes.py index c1f9de4..0fbe22e 100644 --- a/smart_pantry_manager/pages/recommended_recipes.py +++ b/smart_pantry_manager/pages/1- recommended_recipes.py @@ -24,7 +24,10 @@ username = st.session_state["username"] USER_FILE = os.path.join( - "smart_pantry_manager", "data", f"pantry_{username.replace(' ', '_').lower()}.xlsx" + "smart_pantry_manager", + "data", + "user_data", + f"pantry_{username.replace(' ', '_').lower()}.xlsx", ) # ---------- Load pantry ---------- diff --git a/smart_pantry_manager/pages/all_recipes.py b/smart_pantry_manager/pages/2- all_recipes.py similarity index 88% rename from smart_pantry_manager/pages/all_recipes.py rename to smart_pantry_manager/pages/2- all_recipes.py index 3e34ff2..b7e12bd 100644 --- a/smart_pantry_manager/pages/all_recipes.py +++ b/smart_pantry_manager/pages/2- all_recipes.py @@ -48,6 +48,16 @@ def load_recipes(): st.info("No recipes found.") st.stop() +# ---------- Search Recipes ---------- +search_query = st.text_input("๐Ÿ” Search recipes by title:", "") +if search_query: + # Filter recipes where the title contains the typed text (case-insensitive) + recipes = recipes[recipes["Title"].str.contains(search_query, case=False, na=False)] + +if recipes.empty: + st.info("No recipes match your search.") + st.stop() + # ---------- Parse Ingredients ---------- def parse_ingredients(ingredients_str): diff --git a/smart_pantry_manager/requirements.txt b/smart_pantry_manager/requirements.txt index 09aa0c5..5d7b81b 100644 --- a/smart_pantry_manager/requirements.txt +++ b/smart_pantry_manager/requirements.txt @@ -1,4 +1,3 @@ pandas streamlit openpyxl -sqlite3 diff --git a/smart_pantry_manager/smart_pantry.py b/smart_pantry_manager/smart_pantry.py index 21ffdf6..c0d3129 100644 --- a/smart_pantry_manager/smart_pantry.py +++ b/smart_pantry_manager/smart_pantry.py @@ -1,16 +1,16 @@ -# spell-checker: disable """ smart_pantry.py Smart Pantry Web App (Home Page Only) Features: -- Personal pantry for each user (saved to Excel) -- Add, edit, and track products with expiry alerts -- Quantity + unit input (numeric or count) -- Small loading animation when saving -- Optional intro/demo video +- Personal pantry for each user, stored in Excel +- Add, edit, and track products with automatic expiry alerts +- Support for numeric quantities and units (e.g., g, kg, ml, count) +- Visual indicators for soon-to-expire and expired items +- Optional loading animation when saving +- Optional demo video to guide new users -Date: 29/10/2025 +Date: 27/11/2025 """ import os @@ -20,6 +20,26 @@ import pandas as pd import streamlit as st + +# ----- Styling Functions ----- +def style_expired(expired_products_df): + return expired_products_df.style.set_properties( + **{ + "background-color": "#EB4343", # Light Red + "color": "black", + } + ) + + +def style_expiring_soon(expiring_products_df): + return expiring_products_df.style.set_properties( + **{ + "background-color": "#F5DB76", # Light Yellow + "color": "black", + } + ) + + # ---------- Page Setup ---------- st.set_page_config(page_title="Smart Pantry Manager", page_icon="๐Ÿงบ", layout="centered") @@ -37,22 +57,23 @@ st.session_state["username"] = username # Create user-specific file path -os.makedirs("smart_pantry_manager/data", exist_ok=True) -USER_FILE = os.path.join( - "smart_pantry_manager", "data", f"pantry_{username.replace(' ', '_').lower()}.xlsx" -) +os.makedirs("smart_pantry_manager/data/user_data", exist_ok=True) +USER_FILE = f"smart_pantry_manager/data/user_data/pantry_{username.replace(' ', '_').lower()}.xlsx" # ---------- Load Pantry ---------- @st.cache_data def load_pantry(file_path): - """Load pantry data or create empty DataFrame.""" + """Load pantry data for a specific user or create empty table.""" try: df = pd.read_excel(file_path) df["Expiry Date"] = pd.to_datetime(df["Expiry Date"], errors="coerce") df["Days Left"] = (df["Expiry Date"] - datetime.now()).dt.days - df = df[df["Days Left"] >= 0].reset_index(drop=True) + + # Remove expired items automatically + # df = df[df["Days Left"] >= 0].reset_index(drop=True) return df + except FileNotFoundError: return pd.DataFrame( columns=[ @@ -66,12 +87,17 @@ def load_pantry(file_path): ) -data = load_pantry(USER_FILE) +pantry_df = load_pantry(USER_FILE) + +# Store in session_state +if "pantry_data" not in st.session_state: + st.session_state["pantry_data"] = pantry_df # ---------- Add New Product ---------- st.header("โž• Add a New Product") -product = st.text_input("Product name:") -category = st.selectbox( + +product_name = st.text_input("Product name:") +product_category = st.selectbox( "Category:", [ "Uncategorized", @@ -89,57 +115,135 @@ def load_pantry(file_path): "Frozen Foods", "Canned Goods", "Spices & Seasonings", + "Milks & Alternatives", "Drinks", ], ) -quantity = st.number_input("Quantity (numeric or count):", min_value=0.0, step=0.1) -unit = st.selectbox("Unit:", ["count", "g", "kg", "ml", "L", "cup", "tbsp", "tsp"]) -expiry = st.date_input("Expiry date:") +product_quantity = st.number_input( + "Quantity (numeric or count):", min_value=0.0, step=0.1 +) +product_unit = st.selectbox( + "Unit:", ["count", "g", "kg", "ml", "L", "cup", "tbsp", "tsp"] +) +expiry_date = st.date_input("Expiry date:") if st.button("๐Ÿ’พ Save product"): - if product: + if product_name: with st.spinner("๐Ÿ’พ Saving product... please wait..."): - time.sleep(1) + time.sleep(2) today = datetime.now().date() - days_left = (expiry - today).days - new_row = { - "Product": product, - "Category": category, - "Quantity": quantity, - "Unit": unit, - "Expiry Date": expiry, + days_left = (expiry_date - today).days + new_product = { + "Product": product_name, + "Category": product_category, + "Quantity": product_quantity, + "Unit": product_unit, + "Expiry Date": expiry_date, "Days Left": days_left, } - data = pd.concat([data, pd.DataFrame([new_row])], ignore_index=True) - data.to_excel(USER_FILE, index=False) + pantry_df = st.session_state["pantry_data"] + pantry_df = pd.concat( + [pantry_df, pd.DataFrame([new_product])], ignore_index=True + ) + + # Sort by Days Left + pantry_df = pantry_df.sort_values( + by="Days Left", ascending=True + ).reset_index(drop=True) + pantry_df.to_excel(USER_FILE, index=False) + st.session_state["pantry_data"] = pantry_df st.cache_data.clear() - st.success(f"โœ… {product} added successfully!") + st.success(f"โœ… {product_name} added successfully!") else: st.warning("Please enter a product name.") # ---------- Update Days Left ---------- -if not data.empty: - data["Expiry Date"] = pd.to_datetime(data["Expiry Date"], errors="coerce") +if not st.session_state["pantry_data"].empty: + pantry_df = st.session_state["pantry_data"] + pantry_df["Expiry Date"] = pd.to_datetime(pantry_df["Expiry Date"], errors="coerce") today = pd.Timestamp(datetime.now().date()) - data["Days Left"] = (data["Expiry Date"] - today).dt.days + pantry_df["Days Left"] = (pantry_df["Expiry Date"] - today).dt.days + st.session_state["pantry_data"] = pantry_df # ---------- Alerts ---------- -st.header("โš ๏ธ Expiry Alerts") -if not data.empty: - expired = data[data["Days Left"] < 0] - expiring_soon = data[(data["Days Left"] >= 0) & (data["Days Left"] <= 3)] - if not expired.empty: - st.error("โŒ Some products have expired:") - st.table(expired[["Product", "Expiry Date", "Days Left"]]) - if not expiring_soon.empty: - st.warning("โฐ Some products are expiring soon:") - st.table(expiring_soon[["Product", "Expiry Date", "Days Left"]]) +st.markdown("### โš ๏ธ Expiry Alerts") + +current_df = st.session_state["pantry_data"] # renamed + +if not current_df.empty: + expired_items = current_df[current_df["Days Left"] < 0].copy() # renamed + expired_items = expired_items.sort_values(by="Days Left") + expiring_items = current_df[ + (current_df["Days Left"] >= 0) & (current_df["Days Left"] <= 3) + ].copy() # renamed + + # ---------- Expired Products ---------- + if not expired_items.empty: + with st.expander("โŒ Expired Products (Click to view)", expanded=True): + st.dataframe( + style_expired(expired_items[["Product", "Expiry Date", "Days Left"]]), + use_container_width=True, + ) + col1, col2 = st.columns([2, 1]) + if col2.button("๐Ÿ—‘๏ธ Delete ALL expired"): + current_df = current_df[current_df["Days Left"] >= 0] + st.session_state["pantry_data"] = current_df + current_df.to_excel(USER_FILE, index=False) + + st.success("All expired products deleted!") + + # ---------- Expiring Soon ---------- + if not expiring_items.empty: + with st.expander("โฐ Expiring Soon (Within 3 days)", expanded=True): + st.dataframe( + style_expiring_soon( + expiring_items[["Product", "Expiry Date", "Days Left"]] + ), + use_container_width=True, + ) + + # ---------- Manage Section ---------- + st.markdown("---") + st.markdown("### ๐Ÿ›  Manage Products") + + colA, colB = st.columns([2, 3]) + selected_item = colA.selectbox("Choose a product:", current_df["Product"].unique()) + + if selected_item: + item_row = current_df[current_df["Product"] == selected_item].iloc[0] + colB.markdown(f"**Current:** {item_row['Quantity']} {item_row['Unit']}") + + new_quantity = colB.number_input( + "New quantity:", + min_value=0.0, + max_value=float(item_row["Quantity"]), + value=float(item_row["Quantity"]), + step=0.1, + ) + + col1, col2 = st.columns([1, 1]) + if col1.button("โœ”๏ธ Update Quantity"): + current_df.loc[current_df["Product"] == selected_item, "Quantity"] = ( + new_quantity + ) + st.session_state["pantry_data"] = current_df + current_df.to_excel(USER_FILE, index=False) + st.success("Quantity updated!") + + if col2.button("๐Ÿ—‘๏ธ Delete Product"): + current_df = current_df[current_df["Product"] != selected_item] + st.session_state["pantry_data"] = current_df + current_df.to_excel(USER_FILE, index=False) + st.success(f"{selected_item} deleted!") + +st.markdown("---") # ---------- Pantry Table ---------- st.header("๐Ÿ“ฆ Your Pantry Items") def color_days(val): + """Color based on days left.""" if val < 0: color = "#ff4d4d" elif val <= 3: @@ -149,15 +253,21 @@ def color_days(val): return f"background-color: {color}; color: black;" -if not data.empty: - # Sort by Days Left ascending - data_sorted = data.sort_values("Days Left").reset_index(drop=True) - styled_data = data_sorted.style.applymap(color_days, subset=["Days Left"]) +if not pantry_df.empty: + display_data = pantry_df.sort_values(by="Days Left", ascending=True) + styled_data = display_data.reset_index(drop=True).style.applymap( + color_days, subset=["Days Left"] + ) st.dataframe(styled_data, use_container_width=True) else: st.info("Your pantry is empty. Add your first product above!") # ---------- Manual Save ---------- if st.button("๐Ÿ”„ Save Changes"): - data.to_excel(USER_FILE, index=False) - st.success("Pantry data saved successfully!") + if not pantry_df.empty: + pantry_df_sorted = pantry_df.sort_values(by="Days Left", ascending=True) + pantry_df_sorted.to_excel(USER_FILE, index=False) + st.session_state["pantry_data"] = pantry_df_sorted + st.success("Pantry data saved successfully (sorted by expiry)!") + else: + st.info("No items to save.") diff --git a/the_app/data/pantry_omnia.xlsx b/the_app/data/pantry_omnia.xlsx deleted file mode 100644 index d5664c2..0000000 Binary files a/the_app/data/pantry_omnia.xlsx and /dev/null differ