Spaces:
Sleeping
Sleeping
dark_mode (#3)
Browse files- add dark mode, fix issues (cb0d4a7fae13462c7ab9cfb937e1bf1015d71d5d)
- add dark mode (9a0e3d5ed4353a65ad59b278f196dbe56a229cee)
- adding report template (156d6a00a946f0db59e7996316778b9ab2f3d48c)
- Delete_Later_report.txt +49 -1
- assets/css/styles.css +38 -4
- model/search_script.py +4 -4
- pages/3_Recipe_Recommendation.py +14 -15
Delete_Later_report.txt
CHANGED
@@ -1 +1,49 @@
|
|
1 |
-
Report section:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Report section:
|
2 |
+
Title Page
|
3 |
+
β’ Title: Term Project
|
4 |
+
β’ Authors: Saksham Lakhera and Ahmed Zaher
|
5 |
+
β’ Course: CSE 555 β Introduction to Pattern Recognition
|
6 |
+
β’ Date: July 20 2025
|
7 |
+
Abstract
|
8 |
+
βββ’ One concise paragraph summarizing the problem, method, key results, and significance
|
9 |
+
Keywords (optional)
|
10 |
+
βββ’ 4 β 6 technical terms that index your paper (e.g., βpattern recognition, machine learning, CNN, EEGβ)
|
11 |
+
Introduction
|
12 |
+
βββ’ Problem statement and motivation
|
13 |
+
βββ’ Objectives and contributions
|
14 |
+
βββ’ Outline of the paper
|
15 |
+
Background / Related Work
|
16 |
+
βββ’ Survey of prior methods and the state of the art
|
17 |
+
βββ’ Clear positioning of your approach relative to existing literature
|
18 |
+
Dataset and Pre-processing
|
19 |
+
βββ’ Data source(s), collection or selection criteria
|
20 |
+
βββ’ Cleaning, normalization, augmentation, class balancing, etc.
|
21 |
+
Methodology
|
22 |
+
βββ’ Theoretical foundations and algorithms used
|
23 |
+
βββ’ Model architecture, feature extraction, hyper-parameters
|
24 |
+
βββ’ Assumptions and justifications
|
25 |
+
Experimental Setup
|
26 |
+
βββ’ Hardware / software environment
|
27 |
+
βββ’ Train / validation / test split, cross-validation strategy
|
28 |
+
βββ’ Evaluation metrics (accuracy, F1-score, ROC-AUC, etc.)
|
29 |
+
Results
|
30 |
+
βββ’ Quantitative tables and charts
|
31 |
+
βββ’ Qualitative examples (e.g., confusion matrix, sample outputs)
|
32 |
+
βββ’ Statistical significance tests where applicable
|
33 |
+
Discussion
|
34 |
+
ββ β’ Interpretation of results (why methods worked or failed)
|
35 |
+
ββ β’ Comparison with baselines or published benchmarks
|
36 |
+
ββ β’ Limitations of your study
|
37 |
+
Conclusion
|
38 |
+
ββ β’ Recap of contributions and findings
|
39 |
+
ββ β’ Practical implications
|
40 |
+
Future Work
|
41 |
+
ββ β’ Concrete next steps or open problems
|
42 |
+
Acknowledgments (if appropriate)
|
43 |
+
ββ β’ Funding sources, collaborators, data providers
|
44 |
+
References
|
45 |
+
ββ β’ Properly formatted bibliography (IEEE, APA, etc.)
|
46 |
+
Appendices (optional)
|
47 |
+
ββ β’ Supplementary proofs, additional graphs, extensive tables, code snippets
|
48 |
+
|
49 |
+
|
assets/css/styles.css
CHANGED
@@ -1,5 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
body {
|
2 |
font-family: 'Segoe UI', sans-serif;
|
|
|
|
|
3 |
}
|
4 |
|
5 |
.block-container {
|
@@ -22,21 +44,22 @@ body {
|
|
22 |
}
|
23 |
|
24 |
.home-card {
|
25 |
-
background:
|
26 |
border-radius: 12px;
|
27 |
padding: 2rem;
|
28 |
-
box-shadow: 0 8px 20px
|
29 |
max-width: 600px;
|
30 |
text-align: center;
|
31 |
}
|
32 |
|
33 |
.about-box {
|
34 |
-
background-color:
|
35 |
-
border-left: 5px solid
|
36 |
padding: 1rem;
|
37 |
margin-bottom: 1.5rem;
|
38 |
border-radius: 6px;
|
39 |
font-size: 0.95rem;
|
|
|
40 |
}
|
41 |
|
42 |
img {
|
@@ -55,3 +78,14 @@ p, li { font-size: 1rem; }
|
|
55 |
|
56 |
/* Sidebar tweaks */
|
57 |
.css-1lcbmhc { padding-top: 2rem; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
:root {
|
2 |
+
--bg-primary: #ffffff;
|
3 |
+
--bg-secondary: #f1f3f6;
|
4 |
+
--text-primary: #000000;
|
5 |
+
--text-secondary: #333333;
|
6 |
+
--border-color: #4a90e2;
|
7 |
+
--shadow-color: rgba(0, 0, 0, 0.1);
|
8 |
+
|
9 |
+
}
|
10 |
+
|
11 |
+
/* Dark mode */
|
12 |
+
[data-theme="dark"] {
|
13 |
+
--bg-primary: #1e1e1e;
|
14 |
+
--bg-secondary: #2d2d2d;
|
15 |
+
--text-primary: #ffffff;
|
16 |
+
--text-secondary: #e0e0e0;
|
17 |
+
--border-color: #6bb6ff;
|
18 |
+
--shadow-color: rgba(0, 0, 0, 0.3);
|
19 |
+
}
|
20 |
+
|
21 |
body {
|
22 |
font-family: 'Segoe UI', sans-serif;
|
23 |
+
background-color: var(--bg-primary);
|
24 |
+
color: var(--text-primary);
|
25 |
}
|
26 |
|
27 |
.block-container {
|
|
|
44 |
}
|
45 |
|
46 |
.home-card {
|
47 |
+
background: var(--bg-primary);
|
48 |
border-radius: 12px;
|
49 |
padding: 2rem;
|
50 |
+
box-shadow: 0 8px 20px var(--shadow-color);
|
51 |
max-width: 600px;
|
52 |
text-align: center;
|
53 |
}
|
54 |
|
55 |
.about-box {
|
56 |
+
background-color: var(--bg-secondary);
|
57 |
+
border-left: 5px solid var(--border-color);
|
58 |
padding: 1rem;
|
59 |
margin-bottom: 1.5rem;
|
60 |
border-radius: 6px;
|
61 |
font-size: 0.95rem;
|
62 |
+
color: var(--text-secondary);
|
63 |
}
|
64 |
|
65 |
img {
|
|
|
78 |
|
79 |
/* Sidebar tweaks */
|
80 |
.css-1lcbmhc { padding-top: 2rem; }
|
81 |
+
|
82 |
+
@media (prefers-color-scheme: dark) {
|
83 |
+
:root {
|
84 |
+
--bg-primary: #1e1e1e;
|
85 |
+
--bg-secondary: #2d2d2d;
|
86 |
+
--text-primary: #ffffff;
|
87 |
+
--text-secondary: #e0e0e0;
|
88 |
+
--border-color: #6bb6ff;
|
89 |
+
--shadow-color: rgba(0, 0, 0, 0.3);
|
90 |
+
}
|
91 |
+
}
|
model/search_script.py
CHANGED
@@ -145,7 +145,7 @@ class RecipeSearchSystem:
|
|
145 |
recipe = self.recipes_df.iloc[recipe_index]
|
146 |
recipe_id = recipe['id']
|
147 |
|
148 |
-
|
149 |
|
150 |
#if the recipe has no ratings we will assume it is a bad recipe to choose and set the ratio to 1.0
|
151 |
if recipe_id in self.recipe_stats:
|
@@ -156,7 +156,7 @@ class RecipeSearchSystem:
|
|
156 |
recipe_scores.append({
|
157 |
'recipe_index': recipe_index,
|
158 |
'recipe_id': recipe_id,
|
159 |
-
'
|
160 |
'avg_rating': avg_rating
|
161 |
})
|
162 |
|
@@ -179,7 +179,7 @@ class RecipeSearchSystem:
|
|
179 |
'minutes': int(recipe['minutes']),
|
180 |
'n_steps': int(recipe['n_steps']),
|
181 |
'description': recipe.get('description', ''),
|
182 |
-
'
|
183 |
'avg_rating': float(avg_rating),
|
184 |
'num_ratings': int(num_ratings),
|
185 |
'unique_users': int(unique_users)
|
@@ -202,7 +202,7 @@ class RecipeSearchSystem:
|
|
202 |
recipe_scores = self.rank_recipes_by_similarity_and_rating(similarities, filtered_recipe_indices)
|
203 |
|
204 |
# Sort by semantic similarity, then by average rating
|
205 |
-
recipe_scores.sort(key=lambda x: (x['
|
206 |
|
207 |
# Get top results
|
208 |
top_results = recipe_scores[:top_k]
|
|
|
145 |
recipe = self.recipes_df.iloc[recipe_index]
|
146 |
recipe_id = recipe['id']
|
147 |
|
148 |
+
similarity_score = similarities[recipe_index]
|
149 |
|
150 |
#if the recipe has no ratings we will assume it is a bad recipe to choose and set the ratio to 1.0
|
151 |
if recipe_id in self.recipe_stats:
|
|
|
156 |
recipe_scores.append({
|
157 |
'recipe_index': recipe_index,
|
158 |
'recipe_id': recipe_id,
|
159 |
+
'similarity_score': similarity_score,
|
160 |
'avg_rating': avg_rating
|
161 |
})
|
162 |
|
|
|
179 |
'minutes': int(recipe['minutes']),
|
180 |
'n_steps': int(recipe['n_steps']),
|
181 |
'description': recipe.get('description', ''),
|
182 |
+
'similarity_score': float(scores_info['similarity_score']),
|
183 |
'avg_rating': float(avg_rating),
|
184 |
'num_ratings': int(num_ratings),
|
185 |
'unique_users': int(unique_users)
|
|
|
202 |
recipe_scores = self.rank_recipes_by_similarity_and_rating(similarities, filtered_recipe_indices)
|
203 |
|
204 |
# Sort by semantic similarity, then by average rating
|
205 |
+
recipe_scores.sort(key=lambda x: (x['similarity_score'], x['avg_rating']), reverse=True)
|
206 |
|
207 |
# Get top results
|
208 |
top_results = recipe_scores[:top_k]
|
pages/3_Recipe_Recommendation.py
CHANGED
@@ -6,7 +6,7 @@ import streamlit.components.v1 as components
|
|
6 |
|
7 |
def recipe_search_page():
|
8 |
st.markdown("""
|
9 |
-
##
|
10 |
<div class="about-box">
|
11 |
This module uses a custom-trained BERT model to semantically search recipes
|
12 |
based on your query, ingredients, and tags.
|
@@ -14,18 +14,18 @@ def recipe_search_page():
|
|
14 |
""", unsafe_allow_html=True)
|
15 |
|
16 |
if 'search_system' not in st.session_state:
|
17 |
-
with st.spinner("
|
18 |
st.session_state.search_system = search_for_recipes()
|
19 |
|
20 |
search_system = st.session_state.search_system
|
21 |
|
22 |
if not search_system.is_ready:
|
23 |
-
st.error("
|
24 |
return
|
25 |
|
26 |
query = st.text_input(
|
27 |
"Search for recipes:",
|
28 |
-
placeholder="e.g., 'chicken pasta', 'vegetarian salad', 'chocolate dessert'"
|
29 |
)
|
30 |
|
31 |
col1, col2 = st.columns(2)
|
@@ -42,8 +42,7 @@ def recipe_search_page():
|
|
42 |
elapsed = time.time() - start
|
43 |
|
44 |
if results:
|
45 |
-
st.markdown(f"###
|
46 |
-
st.markdown("<sub>π Sorted by best match using semantic search and popularity</sub>", unsafe_allow_html=True)
|
47 |
st.markdown("<hr>", unsafe_allow_html=True)
|
48 |
|
49 |
for i, recipe in enumerate(results, 1):
|
@@ -52,39 +51,39 @@ def recipe_search_page():
|
|
52 |
|
53 |
html_code = f"""
|
54 |
<div style="margin-bottom: 24px; padding: 16px; border-radius: 12px; background-color: #fdfdfd; box-shadow: 0 2px 8px rgba(0,0,0,0.06); font-family: Arial, sans-serif;">
|
55 |
-
<div style="font-size: 18px; font-weight: bold; color: #333;"
|
56 |
|
57 |
<div style="margin: 4px 0 8px 0; font-size: 14px; color: #555;">
|
58 |
-
|
59 |
<span style="font-size: 12px; color: #999;">({recipe['num_ratings']} ratings)</span>
|
60 |
</div>
|
61 |
|
62 |
<div style="margin-bottom: 6px; font-size: 14px;">
|
63 |
-
<b
|
64 |
<span style="font-size: 12px; color: #888;">(query match)</span><br>
|
65 |
-
<b
|
66 |
<span style="font-size: 12px; color: #888;">(match + popularity)</span>
|
67 |
</div>
|
68 |
|
69 |
<div style="margin-bottom: 6px;">
|
70 |
-
<b
|
71 |
{" ".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']])}
|
72 |
</div>
|
73 |
|
74 |
<div style="margin-bottom: 6px;">
|
75 |
-
<b
|
76 |
<span style="font-size: 13px; color: #444;">{', '.join(recipe['ingredients'][:8])}
|
77 |
{'...' if len(recipe['ingredients']) > 8 else ''}</span>
|
78 |
</div>
|
79 |
|
80 |
-
{"<div style='margin-top: 10px; font-size: 13px; color: #333;'><b
|
81 |
|
82 |
-
{"<div style='margin-top: 10px; font-size: 13px;'><b
|
83 |
</div>
|
84 |
"""
|
85 |
components.html(html_code, height=360 + len(recipe.get("steps", [])) * 20)
|
86 |
|
87 |
else:
|
88 |
-
st.warning(f"
|
89 |
|
90 |
render_layout(recipe_search_page)
|
|
|
6 |
|
7 |
def recipe_search_page():
|
8 |
st.markdown("""
|
9 |
+
## Advanced Recipe Recommendation
|
10 |
<div class="about-box">
|
11 |
This module uses a custom-trained BERT model to semantically search recipes
|
12 |
based on your query, ingredients, and tags.
|
|
|
14 |
""", unsafe_allow_html=True)
|
15 |
|
16 |
if 'search_system' not in st.session_state:
|
17 |
+
with st.spinner("Initializing recipe search system"):
|
18 |
st.session_state.search_system = search_for_recipes()
|
19 |
|
20 |
search_system = st.session_state.search_system
|
21 |
|
22 |
if not search_system.is_ready:
|
23 |
+
st.error("System not ready. Please check data files and try again.")
|
24 |
return
|
25 |
|
26 |
query = st.text_input(
|
27 |
"Search for recipes:",
|
28 |
+
placeholder="e.g., 'chicken pasta', 'vegetarian salad', 'chocolate dessert', 'quick easy "
|
29 |
)
|
30 |
|
31 |
col1, col2 = st.columns(2)
|
|
|
42 |
elapsed = time.time() - start
|
43 |
|
44 |
if results:
|
45 |
+
st.markdown(f"### Top {len(results)} recipe recommendations for: *'{query}'*")
|
|
|
46 |
st.markdown("<hr>", unsafe_allow_html=True)
|
47 |
|
48 |
for i, recipe in enumerate(results, 1):
|
|
|
51 |
|
52 |
html_code = f"""
|
53 |
<div style="margin-bottom: 24px; padding: 16px; border-radius: 12px; background-color: #fdfdfd; box-shadow: 0 2px 8px rgba(0,0,0,0.06); font-family: Arial, sans-serif;">
|
54 |
+
<div style="font-size: 18px; font-weight: bold; color: #333;"> {i}. {recipe['name']}</div>
|
55 |
|
56 |
<div style="margin: 4px 0 8px 0; font-size: 14px; color: #555;">
|
57 |
+
<b>{recipe['minutes']} min</b> | <b>{recipe['n_steps']} steps</b> | <b>{recipe['avg_rating']:.1f}/5.0</b>
|
58 |
<span style="font-size: 12px; color: #999;">({recipe['num_ratings']} ratings)</span>
|
59 |
</div>
|
60 |
|
61 |
<div style="margin-bottom: 6px; font-size: 14px;">
|
62 |
+
<b>Match Score:</b> <span style="color: #007acc; font-weight: bold;">{recipe['similarity_score']:.1%}</span>
|
63 |
<span style="font-size: 12px; color: #888;">(query match)</span><br>
|
64 |
+
<b>Overall Score:</b> <span style="color: green; font-weight: bold;">{recipe['combined_score']:.1%}</span>
|
65 |
<span style="font-size: 12px; color: #888;">(match + popularity)</span>
|
66 |
</div>
|
67 |
|
68 |
<div style="margin-bottom: 6px;">
|
69 |
+
<b>Tags:</b><br>
|
70 |
{" ".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']])}
|
71 |
</div>
|
72 |
|
73 |
<div style="margin-bottom: 6px;">
|
74 |
+
<b>Ingredients:</b><br>
|
75 |
<span style="font-size: 13px; color: #444;">{', '.join(recipe['ingredients'][:8])}
|
76 |
{'...' if len(recipe['ingredients']) > 8 else ''}</span>
|
77 |
</div>
|
78 |
|
79 |
+
{"<div style='margin-top: 10px; font-size: 13px; color: #333;'><b>Description:</b><br>" + description + "</div>" if description else ""}
|
80 |
|
81 |
+
{"<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 ""}
|
82 |
</div>
|
83 |
"""
|
84 |
components.html(html_code, height=360 + len(recipe.get("steps", [])) * 20)
|
85 |
|
86 |
else:
|
87 |
+
st.warning(f"No recipes found for '{query}' with a minimum rating of {min_rating}/5.0.")
|
88 |
|
89 |
render_layout(recipe_search_page)
|