MinakshiKaushik commited on
Commit
8d4ed8d
·
verified ·
1 Parent(s): cd05d4b

Upload 10 files

Browse files
Files changed (11) hide show
  1. .gitattributes +1 -0
  2. .gitignore +6 -0
  3. NLP_code.py +42 -0
  4. README.md +10 -14
  5. app.py +115 -0
  6. background.png +3 -0
  7. llm_module.py +38 -0
  8. requirements.txt +7 -0
  9. team.txt +5 -0
  10. yolo_detect.py +23 -0
  11. yolov8n.pt +3 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ background.png filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ __pycache__/
2
+ venv/
3
+ .env
4
+ uploads/
5
+ *.pyc
6
+ .DS_Store
NLP_code.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import nltk
2
+ from nltk.corpus import stopwords, wordnet as wn
3
+ from nltk.stem import WordNetLemmatizer
4
+ import re
5
+
6
+ # Download required NLTK resources
7
+ nltk.download('punkt')
8
+ nltk.download('punkt_tab')
9
+ nltk.download('wordnet')
10
+ nltk.download('stopwords')
11
+
12
+ # Whitelist of common food items
13
+ FOOD_WHITELIST = {
14
+ 'apple', 'banana', 'orange', 'milk', 'bread', 'butter', 'cheese', 'egg', 'carrot',
15
+ 'broccoli', 'onion', 'potato', 'tomato', 'rice', 'pasta', 'chicken', 'fish', 'meat',
16
+ 'pizza', 'cake', 'cucumber', 'corn', 'lettuce', 'mushroom', 'yogurt', 'flour',
17
+ 'spinach', 'garlic', 'pepper', 'beans', 'peas', 'chili', 'tomatoes'
18
+ }
19
+
20
+ # WordNet-based check for food-related nouns
21
+ def is_food_word(word):
22
+ for syn in wn.synsets(word, pos=wn.NOUN):
23
+ if 'food' in syn.lexname():
24
+ return True
25
+ return False
26
+
27
+ # Preprocessing YOLO-detected ingredient labels
28
+ def preprocess_ingredients(yolo_output):
29
+ raw_ingredients = [item['class'] for item in yolo_output]
30
+ lemmatizer = WordNetLemmatizer()
31
+ stop_words = set(stopwords.words('english'))
32
+ cleaned = []
33
+
34
+ for ingredient in raw_ingredients:
35
+ ingredient = re.sub(r'[^a-zA-Z\s]', '', ingredient.lower())
36
+ tokens = nltk.word_tokenize(ingredient)
37
+ tokens = [lemmatizer.lemmatize(t) for t in tokens if t not in stop_words]
38
+ for token in tokens:
39
+ if token in FOOD_WHITELIST or is_food_word(token):
40
+ cleaned.append(token)
41
+
42
+ return list(set(cleaned))
README.md CHANGED
@@ -1,14 +1,10 @@
1
- ---
2
- title: Recipe Oracle
3
- emoji: 📚
4
- colorFrom: yellow
5
- colorTo: purple
6
- sdk: gradio
7
- sdk_version: 5.35.0
8
- app_file: app.py
9
- pinned: false
10
- license: mit
11
- short_description: Generate recipes from ingredients (Image Detection).
12
- ---
13
-
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
+ # 🍽️ The Recipe Oracle
2
+ Upload your fridge photo or ingredients to get smart Indian recipe suggestions with the help of YOLOv8, NLP, and Gemini LLM.
3
+
4
+
5
+ ## 🧠 Tech Stack
6
+
7
+ - **Frontend**: Streamlit
8
+ - **Computer Vision**: YOLOv8 (Ultralytics)
9
+ - **NLP**: Ingredient filtering using WordNet
10
+ - **LLM**: Google Gemini Flash API
 
 
 
 
app.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from PIL import Image
3
+ from NLP_code import preprocess_ingredients
4
+ from yolo_detect import detect_objects
5
+ from llm_module import generate_dish_options, generate_recipe
6
+ import os
7
+ from dotenv import load_dotenv
8
+ import base64
9
+
10
+ # Load Gemini API key from secrets.env
11
+ load_dotenv("secrets.env")
12
+
13
+ # Background image setup
14
+ def set_background(image_file):
15
+ with open(image_file, "rb") as f:
16
+ data = f.read()
17
+ encoded = base64.b64encode(data).decode()
18
+ css = f"""
19
+ <style>
20
+ [data-testid="stAppViewContainer"] {{
21
+ background-image: linear-gradient(rgba(255, 255, 255, 0.75), rgba(255, 255, 255, 0.75)),
22
+ url("data:image/png;base64,{encoded}");
23
+ background-size: cover;
24
+ background-position: center;
25
+ background-attachment: fixed;
26
+ }}
27
+ </style>
28
+ """
29
+ st.markdown(css, unsafe_allow_html=True)
30
+
31
+ # Apply background image
32
+ set_background("background.png")
33
+
34
+ # Page setup
35
+ st.set_page_config(page_title="The Recipe Oracle", layout="wide")
36
+
37
+ # Add custom Google font
38
+ st.markdown('<link href="https://fonts.googleapis.com/css2?family=Chewy&display=swap" rel="stylesheet">', unsafe_allow_html=True)
39
+
40
+ # Heading + subtitle
41
+ st.markdown("<h1 style='text-align: center; color: orange;'>🔮 The Recipe Oracle</h1>", unsafe_allow_html=True)
42
+ st.markdown("""
43
+ <p style='text-align: center; font-family: "Chewy", cursive; font-size: 20px;'>
44
+ Your AI-powered kitchen companion
45
+ </p>
46
+ """, unsafe_allow_html=True)
47
+ st.markdown("---")
48
+
49
+ # Upload image
50
+ uploaded_file = st.file_uploader("Upload a food image (optional)", type=["jpg", "jpeg", "png"])
51
+
52
+ # Manual ingredients input
53
+ manual_input = st.text_input("Add ingredients (comma-separated)")
54
+ manual_ingredients = [i.strip().lower() for i in manual_input.split(',') if i.strip()]
55
+
56
+ # Allow dish suggestion from manual input
57
+ if manual_ingredients and "ingredients" not in st.session_state:
58
+ st.session_state.ingredients = manual_ingredients
59
+
60
+ # Show uploaded image and save it
61
+ if uploaded_file:
62
+ st.image(uploaded_file, caption="Uploaded Image", use_container_width=True)
63
+ with open("uploads/image.jpg", "wb") as f:
64
+ f.write(uploaded_file.read())
65
+
66
+
67
+ # Run YOLO + NLP filtering
68
+ if st.button("🔍 Detect Ingredients") and uploaded_file:
69
+ raw_detected = detect_objects("uploads/image.jpg")
70
+ ingredients = preprocess_ingredients(raw_detected)
71
+ all_ingredients = list(set(ingredients + manual_ingredients))
72
+ st.session_state.ingredients = all_ingredients
73
+ st.success(f"Ingredients: {', '.join(all_ingredients)}")
74
+
75
+ # Generate dish suggestions
76
+ if "ingredients" in st.session_state and st.button("✨ Suggest Dishes"):
77
+ dishes = generate_dish_options(st.session_state.ingredients)
78
+ st.session_state.dishes = dishes
79
+
80
+ # Show recipe
81
+ if "dishes" in st.session_state:
82
+ # Style for radio button labels (dish list)
83
+ st.markdown("""
84
+ <style>
85
+ div[role="radiogroup"] label {
86
+ color: #000000 !important;
87
+ font-family: 'Segoe UI', sans-serif;
88
+ font-size: 18px;
89
+ }
90
+ </style>
91
+ """, unsafe_allow_html=True)
92
+
93
+ dish_titles = [d['title'] for d in st.session_state.dishes]
94
+ selected = st.radio("Pick a dish to cook:", dish_titles)
95
+
96
+ if st.button("📜 Show Recipe"):
97
+ recipe = generate_recipe(selected)
98
+
99
+ if recipe["title"] == "Error":
100
+ st.warning("⚠️ Gemini API is temporarily unavailable. Please wait a minute and try again.")
101
+ else:
102
+ # 🍽️ Recipe title styling
103
+ st.markdown(f"""
104
+ <h3 style='color:#000000; font-family:"Trebuchet MS", sans-serif;'>
105
+ 🍽️ {recipe['title']}
106
+ </h3>
107
+ """, unsafe_allow_html=True)
108
+
109
+ # 📄 Recipe steps styling
110
+ for step in recipe['steps']:
111
+ st.markdown(f"""
112
+ <p style='color:#000000; font-size:1.1rem; font-family:"Segoe UI", sans-serif; margin-bottom:0.5rem;'>
113
+ • {step}
114
+ </p>
115
+ """, unsafe_allow_html=True)
background.png ADDED

Git LFS Details

  • SHA256: 9b7a7b6a6f87f5d08fed716c2d8e504b1276e429da9d32882e95caae7a7cc161
  • Pointer size: 131 Bytes
  • Size of remote file: 853 kB
llm_module.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from dotenv import load_dotenv
3
+ import google.generativeai as genai
4
+
5
+ load_dotenv("secrets.env")
6
+ genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
7
+
8
+ chat = genai.GenerativeModel("gemini-1.5-flash").start_chat()
9
+
10
+ def generate_dish_options(ingredients):
11
+ ingredient_str = ", ".join(ingredients)
12
+ prompt = f"I have {ingredient_str}. Suggest some Indian dishes using some of these ingredients (just names, no recipes)."
13
+
14
+ try:
15
+ response = chat.send_message(prompt)
16
+ dishes = response.text.strip().split("\n")
17
+ return [{"title": dish.strip("1234567890. ").strip()} for dish in dishes if dish.strip()]
18
+ except Exception as e:
19
+ print("❌ Gemini API error (dish generation):", e)
20
+ return [{"title": "⚠️ Unable to fetch dish options. Please try again shortly."}]
21
+
22
+ def generate_recipe(dish_name):
23
+ prompt = f"Give me a detailed recipe for {dish_name}"
24
+
25
+ try:
26
+ response = chat.send_message(prompt)
27
+ steps = response.text.strip().split("\n")
28
+ return {
29
+ "title": dish_name,
30
+ "steps": [step.strip("1234567890. ").strip() for step in steps if step.strip()]
31
+ }
32
+ except Exception as e:
33
+ print("❌ Gemini API error (recipe generation):", e)
34
+ return {
35
+ "title": "Error",
36
+ "steps": ["⚠️ Unable to fetch recipe at the moment. Please wait and try again."]
37
+ }
38
+
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ streamlit
2
+ Pillow
3
+ nltk
4
+ torch
5
+ python-dotenv
6
+ google-generativeai
7
+ ultralytics
team.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ ## 👩‍💻 Team
2
+ - Gourika – Frontend
3
+ - Sachita – YOLOv5
4
+ - Lipi – Gemini LLM
5
+ - Minakshi – NLP Filtering
yolo_detect.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from ultralytics import YOLO
2
+
3
+ # Load YOLOv8 model
4
+ model = YOLO("yolov8n.pt")
5
+
6
+ def detect_objects(image_path):
7
+ """
8
+ Uses YOLOv8 to detect objects in an image.
9
+ Returns a list of dictionaries with 'class' and 'confidence' keys.
10
+ """
11
+ results = model(image_path)
12
+ detected_items = []
13
+
14
+ for box in results[0].boxes:
15
+ class_id = int(box.cls[0].item())
16
+ class_name = results[0].names[class_id]
17
+ confidence = float(box.conf[0].item())
18
+ detected_items.append({
19
+ "class": class_name,
20
+ "confidence": confidence
21
+ })
22
+
23
+ return detected_items
yolov8n.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f59b3d833e2ff32e194b5bb8e08d211dc7c5bdf144b90d2c8412c47ccfc83b36
3
+ size 6549796