sakshamlakhera commited on
Commit
085c988
Β·
1 Parent(s): 04cc6b0

home page combined

Browse files
Files changed (2) hide show
  1. Home.py +162 -21
  2. src/streamlit_app.py +0 -40
Home.py CHANGED
@@ -1,22 +1,163 @@
1
  import streamlit as st
2
- from utils.layout import set_custom_page_config, render_header
3
-
4
- with open("assets/css/styles.css") as f:
5
- st.markdown(f"<style>{f.read()}</style>", unsafe_allow_html=True)
6
-
7
- set_custom_page_config()
8
- render_header()
9
-
10
- st.markdown("""
11
- <div class="about-box">
12
- This tool leverages AI to assist in:<br>
13
- - Classifying images of vegetables and fruits.<br>
14
- - Detecting their variations (cut, whole, sliced).<br>
15
- - Recommending recipes based on natural language input.<br>
16
- </div>
17
-
18
- ### Use the left sidebar to navigate between:
19
- - Task A: Classification - upload an image of a vegetable or fruit to classify it.
20
- - Task B: Variation Detection - upload an image of a vegetable or fruit to detect its variation.
21
- - NLP Recipe Recommendation - enter a search query to recommend a recipe.
22
- """, unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
+ from PIL import Image
3
+ from model.classifier import get_model, predict
4
+ from model.search_script import search_for_recipes
5
+ import streamlit.components.v1 as components
6
+ import time
7
+ import base64
8
+
9
+ from utils.layout import render_layout
10
+
11
+ @st.cache_resource
12
+ def load_model():
13
+ return get_model()
14
+
15
+ def classification_and_recommendation_page():
16
+ st.markdown("## πŸ–ΌοΈ Task A: Image Classification + 🍽️ Recipe Recommendation")
17
+
18
+ st.markdown("""
19
+ <div class="about-box">
20
+ Upload one or more food images. This module classifies each image into
21
+ <b>Onion, Pear, Strawberry, or Tomato</b> using EfficientNet-B0, and then recommends recipes
22
+ based on the combined classification results.
23
+ </div>
24
+ """, unsafe_allow_html=True)
25
+
26
+ model = load_model()
27
+
28
+ # --- Upload and classify ---
29
+ uploaded_files = st.file_uploader("πŸ“€ Upload images (JPG/PNG)", type=["jpg", "jpeg", "png"], accept_multiple_files=True)
30
+
31
+ if "uploaded_images" not in st.session_state:
32
+ st.session_state.uploaded_images = []
33
+ if "image_tags" not in st.session_state:
34
+ st.session_state.image_tags = {}
35
+
36
+ if uploaded_files:
37
+ for img_file in uploaded_files:
38
+ if img_file.name not in [img.name for img in st.session_state.uploaded_images]:
39
+ img = Image.open(img_file).convert("RGB")
40
+ label, _ = predict(img, model)
41
+ st.session_state.uploaded_images.append(img_file)
42
+ st.session_state.image_tags[img_file.name] = label
43
+
44
+ # --- Show grid of classified images ---
45
+ if st.session_state.uploaded_images:
46
+ html = """
47
+ <style>
48
+ .image-grid { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 10px; }
49
+ .image-card {
50
+ width: 140px; height: 180px;
51
+ border: 1px solid #ccc; border-radius: 10px;
52
+ overflow: hidden; text-align: center;
53
+ font-size: 13px; position: relative;
54
+ background: #fdfdfd; box-shadow: 0 1px 4px rgba(0,0,0,0.08);
55
+ }
56
+ .image-card img {
57
+ max-width: 100%; max-height: 110px;
58
+ object-fit: contain; margin-top: 5px;
59
+ }
60
+ .remove-btn {
61
+ position: absolute; top: 2px; right: 6px;
62
+ color: #d33; background: #fff;
63
+ border: none; cursor: pointer; font-size: 16px;
64
+ }
65
+ </style>
66
+ <div class="image-grid">
67
+ """
68
+
69
+ for img in st.session_state.uploaded_images:
70
+ label = st.session_state.image_tags.get(img.name, "unknown")
71
+ img_b64 = base64.b64encode(img.getvalue()).decode()
72
+ html += f"""
73
+ <div class="image-card">
74
+ <img src="data:image/png;base64,{img_b64}" />
75
+ <div><b>{label.upper()}</b></div>
76
+ <div style="color:gray; font-size:11px;">{img.name}</div>
77
+ </div>
78
+ """
79
+
80
+ html += "</div>"
81
+ grid_rows = ((len(st.session_state.uploaded_images) - 1) // 5 + 1)
82
+ components.html(html, height=200 * grid_rows + 20, scrolling=True)
83
+
84
+ # --- Recipe Search ---
85
+ st.markdown("---")
86
+ st.markdown("## πŸ” Recipe Recommendation")
87
+
88
+ if 'search_system' not in st.session_state:
89
+ with st.spinner("Initializing recipe search system"):
90
+ st.session_state.search_system = search_for_recipes()
91
+
92
+ search_system = st.session_state.search_system
93
+
94
+ if not search_system.is_ready:
95
+ st.error("System not ready. Please check data files and try again.")
96
+ return
97
+
98
+ unique_tags = list(set(st.session_state.image_tags.values()))
99
+ default_query = " ".join(unique_tags)
100
+
101
+ query = st.text_input(
102
+ "Search for recipes:",
103
+ value=default_query,
104
+ placeholder="e.g., 'onion tomato pasta', 'strawberry dessert', etc."
105
+ )
106
+
107
+ col1, col2 = st.columns(2)
108
+ with col1:
109
+ num_results = st.slider("Number of results", 1, 15, 5)
110
+ with col2:
111
+ min_rating = st.slider("Minimum rating", 1.0, 5.0, 3.0, 0.1)
112
+
113
+ if st.button("πŸ” Search Recipes") and query:
114
+ with st.spinner(f"Searching for '{query}'..."):
115
+ results = search_system.search_recipes(query, num_results, min_rating)
116
+
117
+ if results:
118
+ st.markdown(f"### Top {len(results)} recipe recommendations for: *'{query}'*")
119
+ st.markdown("<hr>", unsafe_allow_html=True)
120
+
121
+ for i, recipe in enumerate(results, 1):
122
+ steps_html = "".join([f"<li>{step.strip().capitalize()}</li>" for step in recipe.get("steps", [])])
123
+ description = recipe.get("description", "").strip().capitalize()
124
+
125
+ html_code = f"""
126
+ <div style="margin: 8px 0; padding: 8px; border-radius: 12px; background-color: #fdfdfd;
127
+ box-shadow: 0 2px 8px rgba(0,0,0,0.06); font-family: Arial, sans-serif;
128
+ border: 1px solid #e0e0e0;">
129
+ <div style="font-size: 18px; font-weight: bold; color: #333; margin-bottom: 8px;">
130
+ {i}. {recipe['name']}
131
+ </div>
132
+ <div style="margin: 4px 0 12px 0; font-size: 14px; color: #555;">
133
+ <b>{recipe['minutes']} min</b> &nbsp;&nbsp;|&nbsp;&nbsp;
134
+ <b>{recipe['n_steps']} steps</b> &nbsp;&nbsp;|&nbsp;&nbsp;
135
+ <b>{recipe['avg_rating']:.1f}/5.0</b>
136
+ <span style="font-size: 12px; color: #999;">({recipe['num_ratings']} ratings)</span>
137
+ </div>
138
+ <div style="margin-bottom: 8px; font-size: 14px;">
139
+ <b>Match Score:</b>
140
+ <span style="color: #007acc; font-weight: bold;">{recipe['similarity_score']:.1%}</span>
141
+ <span style="font-size: 12px; color: #888;">(query match)</span>
142
+ </div>
143
+ <div style="margin-bottom: 8px;">
144
+ <b>Tags:</b><br>
145
+ <div style="margin-top: 8px;">
146
+ {" ".join([f"<span style='background:#eee;padding:4px 8px;border-radius:6px;margin:2px;display:inline-block;font-size:12px'>{tag}</span>" for tag in recipe['tags']])}
147
+ </div>
148
+ </div>
149
+ <div style="margin-bottom: 8px;">
150
+ <b>Ingredients:</b><br>
151
+ <span style="font-size: 13px; color: #444; display: block;">
152
+ {', '.join(recipe['ingredients'][:8])}{'...' if len(recipe['ingredients']) > 8 else ''}
153
+ </span>
154
+ </div>
155
+ {f"<div style='margin-top: 10px; font-size: 13px; color: #333;'><b>Description:</b><br><span>{description}</span></div>" if description else ""}
156
+ {f"<div style='margin-top: 10px; font-size: 13px;'><b>Steps:</b><ol style='margin: 6px 0 0 18px; padding: 0;'>{steps_html}</ol></div>" if steps_html else ""}
157
+ </div>
158
+ """
159
+ components.html(html_code, height=340, scrolling=True)
160
+ else:
161
+ st.warning(f"No recipes found for '{query}' with a minimum rating of {min_rating}/5.0.")
162
+
163
+ render_layout(classification_and_recommendation_page)
src/streamlit_app.py DELETED
@@ -1,40 +0,0 @@
1
- import altair as alt
2
- import numpy as np
3
- import pandas as pd
4
- import streamlit as st
5
-
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))