OmPrakashSingh1704 commited on
Commit
c4a397e
1 Parent(s): 101017e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +286 -245
app.py CHANGED
@@ -26,13 +26,9 @@ with open('vectors.pkl', 'rb') as file:
26
  with open('items_dict.pkl', 'rb') as file:
27
  items_dict = pd.DataFrame.from_dict(pickle.load(file))
28
 
 
29
  mode = st.toggle(label="MART")
30
 
31
- # Utility functions
32
- def preprocess_text(text):
33
- text = re.sub(r'[^a-zA-Z\s]', '', text)
34
- text = re.sub(r'\s+', ' ', text).strip()
35
- return text.lower()
36
 
37
  def get_recommendations(user_description, count_vectorizer, count_matrix):
38
  user_description = preprocess_text(user_description)
@@ -41,88 +37,13 @@ def get_recommendations(user_description, count_vectorizer, count_matrix):
41
  similar_indices = cosine_similarities.argsort()[::-1]
42
  return similar_indices
43
 
44
- def create_detailed_prompt(user_direction, exclusions, serving_size, difficulty):
45
- prompt_template = {
46
- "Quick & Easy": (
47
- "Provide a 'Quick and Easy' recipe for {user_direction} that excludes {exclusions} and has a serving size of {serving_size}. "
48
- "It should require as few ingredients as possible and should be ready in as little time as possible. "
49
- "The steps should be simple, and the ingredients should be commonly found in a household pantry. "
50
- "Provide a detailed ingredient list and step-by-step guide that explains the instructions to prepare in detail."
51
- ),
52
- "Intermediate": (
53
- "Provide a classic recipe for {user_direction} that excludes {exclusions} and has a serving size of {serving_size}. "
54
- "The recipe should offer a bit of a cooking challenge but should not require professional skills. "
55
- "The recipe should feature traditional ingredients and techniques that are authentic to its cuisine. "
56
- "Provide a detailed ingredient list and step-by-step guide that explains the instructions to prepare in detail."
57
- ),
58
- "Professional": (
59
- "Provide an advanced recipe for {user_direction} that excludes {exclusions} and has a serving size of {serving_size}. "
60
- "The recipe should push the boundaries of culinary arts, integrating unique ingredients, advanced cooking techniques, and innovative presentations. "
61
- "The recipe should be able to be served at a high-end restaurant or would impress at a gourmet food competition. "
62
- "Provide a detailed ingredient list and step-by-step guide that explains the instructions to prepare in detail."
63
- )
64
- }
65
- return prompt_template[difficulty].format(
66
- user_direction=user_direction,
67
- exclusions=exclusions,
68
- serving_size=serving_size
69
- )
70
-
71
- def generate_recipe(user_inputs):
72
- with st.spinner('Building the perfect recipe...'):
73
- prompt = create_detailed_prompt(user_inputs['user_direction'], user_inputs['exclusions'],
74
- user_inputs['serving_size'], user_inputs['difficulty'])
75
- functions = [
76
- {
77
- "name": "provide_recipe",
78
- "description": "Provides a detailed recipe strictly adhering to the user input/specifications, especially ingredient exclusions and the recipe difficulty",
79
- "parameters": {
80
- "type": "object",
81
- "properties": {
82
- "name": {"type": "string", "description": "A creative name for the recipe"},
83
- "description": {"type": "string", "description": "a brief one-sentence description of the provided recipe"},
84
- "ingredients": {
85
- "type": "array",
86
- "items": {
87
- "type": "object",
88
- "properties": {"name": {"type": "string", "description": "Quantity and name of the ingredient"}}
89
- }
90
- },
91
- "instructions": {
92
- "type": "array",
93
- "items": {
94
- "type": "object",
95
- "properties": {
96
- "step_number": {"type": "number", "description": "The sequence number of this step"},
97
- "instruction": {"type": "string", "description": "Detailed description of what to do in this step"}
98
- }
99
- }
100
- }
101
- },
102
- "required": ["name", "description", "ingredients", "instructions"]
103
- }
104
- }
105
- ]
106
-
107
- generate_kwargs = dict(
108
- temperature=0.9,
109
- max_new_tokens=10000,
110
- top_p=0.9,
111
- repetition_penalty=1.0,
112
- do_sample=True,
113
- )
114
-
115
- prompt += f"\nPlease format the output in JSON. The JSON should include fields for 'name', 'description', 'ingredients', and 'instructions', with each field structured as described below.\n\n{json.dumps(functions)}"
116
-
117
- response = client.text_generation(prompt, **generate_kwargs)
118
- st.session_state.recipe = response
119
- st.session_state.recipe_saved = False
120
 
121
  def show_recipe(recipe):
122
  with st.spinner("HANG TIGHT, RECIPE INCOMING..."):
123
- name_and_dis = f'# {recipe["name"]}\n\n{recipe["description"]}\n\n'
 
124
  ingredients = '## Ingredients:\n'
125
- instructions = '## Instructions:\n'
126
  for instruction in recipe["instructions"]:
127
  instructions += f"{instruction['step_number']}. {instruction['instruction']}\n"
128
 
@@ -133,191 +54,311 @@ def show_recipe(recipe):
133
  cont.write(ingredients)
134
  for j, i in enumerate(recipe["ingredients"]):
135
  cont.selectbox(i['name'],
136
- options=items_dict.iloc[get_recommendations(i['name'], cv, vectors)]["PRODUCT_NAME"].values,
137
- key=f"selectbox_{j}_{i['name']}{random.random()*100}")
 
138
  with col02:
139
  cont = st.container(border=True, height=500)
140
  cont.write(instructions)
141
 
142
- def clear_inputs():
143
- st.session_state.user_direction = None
144
- st.session_state.exclusions = None
145
- st.session_state.serving_size = 2
146
- st.session_state.selected_difficulty = "Quick & Easy"
147
- st.session_state.recipe = None
148
-
149
- def create_safe_filename(recipe_name):
150
- safe_name = recipe_name.lower().replace(" ", "_")
151
- safe_name = re.sub(r"[^a-zA-Z0-9_]", "", safe_name)
152
- safe_name = safe_name[:50] if len(safe_name) > 50 else safe_name
153
- unique_token = secrets.token_hex(8)
154
- return f"{unique_token}_{safe_name}"
155
-
156
- def save_recipe():
157
- with st.spinner('WAIT SAVING YOUR DISH...'):
158
- filename = create_safe_filename(recipe["name"])
159
- os.makedirs('data', exist_ok=True)
160
- with open(f'./data/{filename}.pkl', 'wb') as f:
161
- pickle.dump(recipe, f)
162
- st.session_state.recipe_saved = True
163
-
164
- def load_saved_recipes_from_pickle(directory_path):
165
- os.makedirs('data', exist_ok=True)
166
- recipes = []
167
- for filename in os.listdir(directory_path):
168
- if filename.endswith('.pkl'):
169
- with open(os.path.join(directory_path, filename), 'rb') as file:
170
- recipe = pickle.load(file)
171
- recipes.append(recipe)
172
- return recipes
173
-
174
- # Main UI logic
175
- if not mode:
176
- if 'current_tab' not in st.session_state:
177
- st.session_state.current_tab = 'COOK'
178
 
 
 
 
179
  cook, saved = st.tabs(['COOK', 'SAVED'])
 
 
180
 
181
- if cook:
182
- st.session_state.current_tab = 'COOK'
183
- if saved:
184
- st.session_state.current_tab = 'SAVED'
185
 
186
- if st.session_state.current_tab == 'COOK':
187
- with cook:
188
- client = InferenceClient("mistralai/Mixtral-8x7B-Instruct-v0.1")
189
 
190
- if 'recipe' not in st.session_state:
191
- st.session_state.recipe = None
192
 
193
- if 'recipe_saved' not in st.session_state:
194
- st.session_state.recipe_saved = None
195
 
196
- if 'user_direction' not in st.session_state:
197
- st.session_state.user_direction = None
198
 
199
- if 'serving_size' not in st.session_state:
200
- st.session_state.serving_size = 2
201
 
202
- if 'selected_difficulty' not in st.session_state:
203
- st.session_state.selected_difficulty = "Quick & Easy"
204
 
205
- if 'exclusions' not in st.session_state:
206
- st.session_state.exclusions = None
 
 
 
207
 
208
- st.title("Let's get cooking")
209
- col1, col2 = st.columns(2)
210
- with col1:
211
- st.session_state.user_direction = st.text_area(
212
- "What do you want to cook? Describe anything - a dish, cuisine, event, or vibe.",
213
- value=st.session_state.user_direction,
214
- placeholder="quick snack, asian style bowl with either noodles or rice, something italian",
 
 
 
 
 
 
 
 
215
  )
216
- with col2:
217
- st.session_state.serving_size = st.number_input(
218
- "How many servings would you like to cook?",
219
- min_value=1,
220
- max_value=100,
221
- value=st.session_state.serving_size,
222
- step=1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
  )
224
 
225
- difficulty_dictionary = {
226
- "Quick & Easy": {
227
- "description": "Easy recipes with straightforward instructions. Ideal for beginners or those seeking quick and simple cooking.",
228
- },
229
- "Intermediate": {
230
- "description": "Recipes with some intricate steps that invite a little challenge. Perfect for regular cooks wanting to expand their repertoire with new ingredients and techniques.",
231
- },
232
- "Professional": {
233
- "description": "Complex recipes that demand a high level of skill and precision. Suited for seasoned cooks aspiring to professional-level sophistication and creativity.",
234
- }
235
- }
 
 
236
 
237
- st.session_state.selected_difficulty = st.radio(
238
- "Choose a difficulty level for your recipe.",
239
- list(difficulty_dictionary.keys()),
240
- index=list(difficulty_dictionary.keys()).index(st.session_state.selected_difficulty),
241
- format_func=lambda x: f"{x}: {difficulty_dictionary[x]['description']}"
242
- )
243
 
244
- st.session_state.exclusions = st.text_area(
245
- "Any ingredients you want to exclude?",
246
- value=st.session_state.exclusions,
247
- placeholder="gluten, dairy, nuts, cilantro",
 
 
 
 
 
 
 
 
 
 
 
248
  )
249
 
250
- fancy_exclusions = ""
251
- if st.session_state.selected_difficulty == "Professional":
252
- exclude_fancy = st.checkbox(
253
- "Exclude cliche professional ingredients? (gold leaf, truffle, edible flowers, microgreens)",
254
- value=True)
255
- if exclude_fancy:
256
- fancy_exclusions = "gold leaf, truffle, edible flowers, microgreens, gold dust"
257
-
258
- user_inputs = {
259
- "user_direction": st.session_state.user_direction,
260
- "exclusions": f"{st.session_state.exclusions}, {fancy_exclusions}".strip(", "),
261
- "serving_size": st.session_state.serving_size,
262
- "difficulty": st.session_state.selected_difficulty
263
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
264
 
265
- button_cols_submit = st.columns([1, 1, 4])
266
- with button_cols_submit[0]:
267
- st.button(label='Submit', on_click=generate_recipe, kwargs=dict(user_inputs=user_inputs), type="primary",
268
- use_container_width=True)
269
- with button_cols_submit[1]:
270
- st.button(label='Reset', on_click=clear_inputs, type="secondary", use_container_width=True)
271
- with button_cols_submit[2]:
272
- st.empty()
273
 
274
- if st.session_state.recipe is not None:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275
  st.divider()
276
- recipe = json.loads(st.session_state.recipe)
277
- if not st.session_state.recipe_saved:
278
- show_recipe(recipe)
279
- recipe['timestamp'] = str(datetime.datetime.now())
280
- disable_button = st.session_state.recipe_saved
281
-
282
- button_cols_save = st.columns([1, 1, 4])
283
- with button_cols_save[0]:
284
- st.button("Save Recipe", on_click=save_recipe, disabled=disable_button, type="primary")
285
- with button_cols_save[1]:
286
- st.empty()
287
- with button_cols_save[2]:
288
- st.empty()
289
-
290
- if st.session_state.recipe_saved:
291
- st.success("Recipe Saved!")
292
-
293
- elif st.session_state.current_tab == 'SAVED':
294
- with saved:
295
- st.title("Saved Recipes")
296
- with st.spinner('LOADING YOUR RECIPE...'):
297
- directory_path = 'data'
298
- recipes = load_saved_recipes_from_pickle(directory_path)
299
-
300
- cols = st.columns([4, 1])
301
- with cols[1]:
302
- user_sort = st.selectbox("Sort", ('Recent', 'Oldest', 'A-Z', 'Z-A', 'Random'))
303
- if user_sort == 'Recent':
304
- recipes.sort(key=lambda x: x['timestamp'], reverse=True)
305
- elif user_sort == 'Oldest':
306
- recipes.sort(key=lambda x: x['timestamp'])
307
- elif user_sort == 'A-Z':
308
- recipes.sort(key=lambda x: x['name'])
309
- elif user_sort == 'Z-A':
310
- recipes.sort(key=lambda x: x['name'], reverse=True)
311
- elif user_sort == 'Random':
312
- random.shuffle(recipes)
313
- with cols[0]:
314
- user_search = st.selectbox("Search Recipes", [""] + [recipe['name'] for recipe in recipes])
315
- st.write("") # just some space
316
-
317
- if user_search:
318
- st.divider()
319
- filtered_recipes = [recipe for recipe in recipes if recipe['name'] == user_search]
320
- if filtered_recipes:
321
- show_recipe(filtered_recipes[0])
322
- else:
323
- st.write("No recipe found.")
 
26
  with open('items_dict.pkl', 'rb') as file:
27
  items_dict = pd.DataFrame.from_dict(pickle.load(file))
28
 
29
+
30
  mode = st.toggle(label="MART")
31
 
 
 
 
 
 
32
 
33
  def get_recommendations(user_description, count_vectorizer, count_matrix):
34
  user_description = preprocess_text(user_description)
 
37
  similar_indices = cosine_similarities.argsort()[::-1]
38
  return similar_indices
39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
  def show_recipe(recipe):
42
  with st.spinner("HANG TIGHT, RECIPE INCOMING..."):
43
+ name_and_dis = f'# {recipe["name"]}\n\n'
44
+ name_and_dis += f'{recipe["description"]}\n\n'
45
  ingredients = '## Ingredients:\n'
46
+ instructions = '\n## Instructions:\n'
47
  for instruction in recipe["instructions"]:
48
  instructions += f"{instruction['step_number']}. {instruction['instruction']}\n"
49
 
 
54
  cont.write(ingredients)
55
  for j, i in enumerate(recipe["ingredients"]):
56
  cont.selectbox(i['name'],
57
+ options=items_dict.iloc[get_recommendations(i['name'], cv, vectors)][
58
+ "PRODUCT_NAME"].values,
59
+ key=f"selectbox_{j}_{i['name']}{random.random() * 100}")
60
  with col02:
61
  cont = st.container(border=True, height=500)
62
  cont.write(instructions)
63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
+ # Initialize the inference client for the Mixtral model
66
+
67
+ if not mode:
68
  cook, saved = st.tabs(['COOK', 'SAVED'])
69
+ with cook:
70
+ client = InferenceClient("mistralai/Mixtral-8x7B-Instruct-v0.1")
71
 
72
+ if 'recipe' not in st.session_state:
73
+ st.session_state.recipe = None
 
 
74
 
75
+ if 'recipe_saved' not in st.session_state:
76
+ st.session_state.recipe_saved = None
 
77
 
78
+ if 'user_direction' not in st.session_state:
79
+ st.session_state.user_direction = None
80
 
81
+ if 'serving_size' not in st.session_state:
82
+ st.session_state.serving_size = 2
83
 
84
+ if 'selected_difficulty' not in st.session_state:
85
+ st.session_state.selected_difficulty = "Quick & Easy"
86
 
87
+ if 'exclusions' not in st.session_state:
88
+ st.session_state.exclusions = None
89
 
 
 
90
 
91
+ def preprocess_text(text):
92
+ # Remove non-alphabet characters and extra spaces
93
+ text = re.sub(r'[^a-zA-Z\s]', '', text)
94
+ text = re.sub(r'\s+', ' ', text).strip()
95
+ return text.lower()
96
 
97
+
98
+ def create_detailed_prompt(user_direction, exclusions, serving_size, difficulty):
99
+ if difficulty == "Quick & Easy":
100
+ prompt = (
101
+ f"Provide a 'Quick and Easy' recipe for {user_direction} that excludes {exclusions} and has a serving size of {serving_size}. "
102
+ f"It should require as few ingredients as possible and should be ready in as little time as possible. "
103
+ f"The steps should be simple, and the ingredients should be commonly found in a household pantry. "
104
+ f"Provide a detailed ingredient list and step-by-step guide that explains the instructions to prepare in detail."
105
+ )
106
+ elif difficulty == "Intermediate":
107
+ prompt = (
108
+ f"Provide a classic recipe for {user_direction} that excludes {exclusions} and has a serving size of {serving_size}. "
109
+ f"The recipe should offer a bit of a cooking challenge but should not require professional skills. "
110
+ f"The recipe should feature traditional ingredients and techniques that are authentic to its cuisine. "
111
+ f"Provide a detailed ingredient list and step-by-step guide that explains the instructions to prepare in detail."
112
  )
113
+ elif difficulty == "Professional":
114
+ prompt = (
115
+ f"Provide an advanced recipe for {user_direction} that excludes {exclusions} and has a serving size of {serving_size}. "
116
+ f"The recipe should push the boundaries of culinary arts, integrating unique ingredients, advanced cooking techniques, and innovative presentations. "
117
+ f"The recipe should be able to be served at a high-end restaurant or would impress at a gourmet food competition. "
118
+ f"Provide a detailed ingredient list and step-by-step guide that explains the instructions to prepare in detail."
119
+ )
120
+ return prompt
121
+
122
+
123
+ def generate_recipe(user_inputs):
124
+ with st.spinner('Building the perfect recipe...'):
125
+ prompt = create_detailed_prompt(user_inputs['user_direction'], user_inputs['exclusions'],
126
+ user_inputs['serving_size'], user_inputs['difficulty'])
127
+
128
+ functions = [
129
+ {
130
+ "name": "provide_recipe",
131
+ "description": "Provides a detailed recipe strictly adhering to the user input/specifications, especially ingredient exclusions and the recipe difficulty",
132
+ "parameters": {
133
+ "type": "object",
134
+ "properties": {
135
+ "name": {
136
+ "type": "string",
137
+ "description": "A creative name for the recipe"
138
+ },
139
+ "description": {
140
+ "type": "string",
141
+ "description": "a brief one-sentence description of the provided recipe"
142
+ },
143
+ "ingredients": {
144
+ "type": "array",
145
+ "items": {
146
+ "type": "object",
147
+ "properties": {
148
+ "name": {
149
+ "type": "string",
150
+ "description": "Quantity and name of the ingredient"
151
+ }
152
+ }
153
+ }
154
+ },
155
+ "instructions": {
156
+ "type": "array",
157
+ "items": {
158
+ "type": "object",
159
+ "properties": {
160
+ "step_number": {
161
+ "type": "number",
162
+ "description": "The sequence number of this step"
163
+ },
164
+ "instruction": {
165
+ "type": "string",
166
+ "description": "Detailed description of what to do in this step"
167
+ }
168
+ }
169
+ }
170
+ }
171
+ },
172
+ "required": [
173
+ "name",
174
+ "description",
175
+ "ingredients",
176
+ "instructions"
177
+ ],
178
+ },
179
+ }
180
+ ]
181
+
182
+ generate_kwargs = dict(
183
+ temperature=0.9,
184
+ max_new_tokens=10000,
185
+ top_p=0.9,
186
+ repetition_penalty=1.0,
187
+ do_sample=True,
188
  )
189
 
190
+ prompt += f"\nPlease format the output in JSON. The JSON should include fields for 'name', 'description', 'ingredients', and 'instructions', with each field structured as described below.\n\n{json.dumps(functions)}"
191
+
192
+ response = client.text_generation(prompt, **generate_kwargs)
193
+ st.session_state.recipe = response
194
+ st.session_state.recipe_saved = False
195
+
196
+
197
+ def clear_inputs():
198
+ st.session_state.user_direction = None
199
+ st.session_state.exclusions = None
200
+ st.session_state.serving_size = 2
201
+ st.session_state.selected_difficulty = "Quick & Easy"
202
+ st.session_state.recipe = None
203
 
 
 
 
 
 
 
204
 
205
+ st.title("Let's get cooking")
206
+ col1, col2 = st.columns(2)
207
+ with col1:
208
+ st.session_state.user_direction = st.text_area(
209
+ "What do you want to cook? Describe anything - a dish, cuisine, event, or vibe.",
210
+ value=st.session_state.user_direction,
211
+ placeholder="quick snack, asian style bowl with either noodles or rice, something italian",
212
+ )
213
+ with col2:
214
+ st.session_state.serving_size = st.number_input(
215
+ "How many servings would you like to cook?",
216
+ min_value=1,
217
+ max_value=100,
218
+ value=st.session_state.serving_size,
219
+ step=1
220
  )
221
 
222
+ difficulty_dictionary = {
223
+ "Quick & Easy": {
224
+ "description": "Easy recipes with straightforward instructions. Ideal for beginners or those seeking quick and simple cooking.",
225
+ },
226
+ "Intermediate": {
227
+ "description": "Recipes with some intricate steps that invite a little challenge. Perfect for regular cooks wanting to expand their repertoire with new ingredients and techniques.",
228
+ },
229
+ "Professional": {
230
+ "description": "Complex recipes that demand a high level of skill and precision. Suited for seasoned cooks aspiring to professional-level sophistication and creativity.",
 
 
 
 
231
  }
232
+ }
233
+
234
+ st.session_state.selected_difficulty = st.radio(
235
+ "Choose a difficulty level for your recipe.",
236
+ [
237
+ list(difficulty_dictionary.keys())[0],
238
+ list(difficulty_dictionary.keys())[1],
239
+ list(difficulty_dictionary.keys())[2]
240
+ ],
241
+ captions=[
242
+ difficulty_dictionary["Quick & Easy"]["description"],
243
+ difficulty_dictionary["Intermediate"]["description"],
244
+ difficulty_dictionary["Professional"]["description"]
245
+ ],
246
+ index=list(difficulty_dictionary).index(st.session_state.selected_difficulty)
247
+ )
248
 
249
+ st.session_state.exclusions = st.text_area(
250
+ "Any ingredients you want to exclude?",
251
+ value=st.session_state.exclusions,
252
+ placeholder="gluten, dairy, nuts, cilantro",
253
+ )
 
 
 
254
 
255
+ fancy_exclusions = ""
256
+
257
+ if st.session_state.selected_difficulty == "Professional":
258
+ exclude_fancy = st.checkbox(
259
+ "Exclude cliche professional ingredients? (gold leaf, truffle, edible flowers, microgreens)",
260
+ value=True)
261
+ if exclude_fancy:
262
+ fancy_exclusions = "gold leaf, truffle, edible flowers, microgreens, gold dust"
263
+
264
+ user_inputs = {
265
+ "user_direction": st.session_state.user_direction,
266
+ "exclusions": f"{st.session_state.exclusions}, {fancy_exclusions}".strip(", "),
267
+ "serving_size": st.session_state.serving_size,
268
+ "difficulty": st.session_state.selected_difficulty
269
+ }
270
+
271
+ button_cols_submit = st.columns([1, 1, 4])
272
+ with button_cols_submit[0]:
273
+ st.button(label='Submit', on_click=generate_recipe, kwargs=dict(user_inputs=user_inputs), type="primary",
274
+ use_container_width=True)
275
+ with button_cols_submit[1]:
276
+ st.button(label='Reset', on_click=clear_inputs, type="secondary", use_container_width=True)
277
+ with button_cols_submit[2]:
278
+ st.empty()
279
+
280
+
281
+ def create_safe_filename(recipe_name):
282
+ # format and generate random URL-safe text string
283
+ safe_name = recipe_name.lower()
284
+ safe_name = safe_name.replace(" ", "_")
285
+ safe_name = re.sub(r"[^a-zA-Z0-9_]", "", safe_name)
286
+ safe_name = (safe_name[:50]) if len(safe_name) > 50 else safe_name
287
+ unique_token = secrets.token_hex(8)
288
+ safe_filename = f"{unique_token}_{safe_name}"
289
+ return safe_filename
290
+
291
+
292
+ def save_recipe():
293
+ with st.spinner('WAIT SAVING YOUR DISH...'):
294
+ filename = create_safe_filename(recipe["name"])
295
+ os.makedirs('data', exist_ok=True)
296
+ with open(f'./data/{filename}.pkl', 'wb') as f:
297
+ pickle.dump(recipe, f)
298
+ st.session_state.recipe_saved = True
299
+
300
+
301
+ if st.session_state.recipe is not None:
302
+ st.divider()
303
+ print(st.session_state.recipe)
304
+ recipe = json.loads(st.session_state.recipe)
305
+ show_recipe(recipe)
306
+ recipe['timestamp'] = str(datetime.datetime.now())
307
+ if st.session_state.recipe_saved == True:
308
+ disable_button = True
309
+ else:
310
+ disable_button = False
311
+ button_cols_save = st.columns([1, 1, 4])
312
+ with button_cols_save[0]:
313
+ st.button("Save Recipe", on_click=save_recipe, disabled=disable_button, type="primary")
314
+ with button_cols_save[1]:
315
+ st.empty()
316
+ with button_cols_save[2]:
317
+ st.empty()
318
+ if st.session_state.recipe_saved == True:
319
+ st.success("Recipe Saved!")
320
+ with saved:
321
+ st.title("Saved Recipes")
322
+ with st.spinner('LOADING YOUR RECIPE...'):
323
+ def load_saved_recipes_from_pickle(directory_path):
324
+ os.makedirs('data', exist_ok=True)
325
+ recipes = []
326
+ # Iterate through all files in the directory
327
+ for filename in os.listdir(directory_path):
328
+ if filename.endswith('.pkl'):
329
+ file_path = os.path.join(directory_path, filename)
330
+ with open(file_path, 'rb') as file:
331
+ recipe = pickle.load(file)
332
+ recipes.append(recipe)
333
+ return recipes
334
+
335
+
336
+ # get all saved files
337
+ directory_path = 'data'
338
+ recipes = load_saved_recipes_from_pickle(directory_path)
339
+ print(recipes)
340
+
341
+ cols = st.columns([4, 1])
342
+ with cols[1]:
343
+ user_sort = st.selectbox("Sort", ('Recent', 'Oldest', 'A-Z', 'Z-A', 'Random'))
344
+ if user_sort == 'Recent':
345
+ recipes.sort(key=lambda x: x['timestamp'], reverse=True)
346
+ elif user_sort == 'Oldest':
347
+ recipes.sort(key=lambda x: x['timestamp'])
348
+ elif user_sort == 'A-Z':
349
+ recipes.sort(key=lambda x: x['name'])
350
+ elif user_sort == 'Z-A':
351
+ recipes.sort(key=lambda x: x['name'], reverse=True)
352
+ elif user_sort == 'Random':
353
+ recipes.sort(key=lambda x: x['file'])
354
+ with cols[0]:
355
+ user_search = st.selectbox("Search Recipes", [""] + [recipe['name'] for recipe in recipes])
356
+ st.write("") # just some space
357
+
358
+ if user_search != "":
359
  st.divider()
360
+ filtered_recipes = [recipe for recipe in recipes if recipe['name'] == user_search]
361
+ if filtered_recipes:
362
+ show_recipe(filtered_recipes[0])
363
+ else:
364
+ st.write("No recipe found.")