OmPrakashSingh1704 commited on
Commit
8576e15
1 Parent(s): e45413d

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +230 -0
app.py ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from transformers import AutoModelForCausalLM, AutoTokenizer
3
+ import torch, re, json
4
+ from datetime import datetime
5
+
6
+ device = "cuda" # the device to load the model onto
7
+
8
+ # Load model and tokenizer
9
+ model = AutoModelForCausalLM.from_pretrained(
10
+ "Qwen/Qwen1.5-0.5B-Chat",
11
+ torch_dtype="auto",
12
+ device_map="auto",
13
+ ).to(device)
14
+ tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen1.5-0.5B-Chat")
15
+
16
+ if 'recipe' not in st.session_state:
17
+ st.session_state.recipe = None
18
+
19
+ if 'recipe_saved' not in st.session_state:
20
+ st.session_state.recipe_saved = None
21
+
22
+ if 'user_direction' not in st.session_state:
23
+ st.session_state.user_direction = None
24
+
25
+ if 'serving_size' not in st.session_state:
26
+ st.session_state.serving_size = 2
27
+
28
+ if 'selected_difficulty' not in st.session_state:
29
+ st.session_state.selected_difficulty = "Quick & Easy"
30
+
31
+ if 'exclusions' not in st.session_state:
32
+ st.session_state.exclusions = None
33
+
34
+ def create_detailed_prompt(user_direction, exclusions, serving_size, difficulty):
35
+ if difficulty == "Quick & Easy":
36
+ prompt = (
37
+ f"Provide a 'Quick and Easy' recipe for {user_direction} that excludes {exclusions} and has a serving size of {serving_size}. "
38
+ f"It should require as few ingredients as possible and should be ready in as little time as possible. "
39
+ f"The steps should be simple, and the ingredients should be commonly found in a household pantry. "
40
+ f"Provide a detailed ingredient list and step-by-step guide that explains the instructions to prepare in detail."
41
+ )
42
+ elif difficulty == "Intermediate":
43
+ prompt = (
44
+ f"Provide a classic recipe for {user_direction} that excludes {exclusions} and has a serving size of {serving_size}. "
45
+ f"The recipe should offer a bit of a cooking challenge but should not require professional skills. "
46
+ f"The recipe should feature traditional ingredients and techniques that are authentic to its cuisine. "
47
+ f"Provide a detailed ingredient list and step-by-step guide that explains the instructions to prepare in detail."
48
+ )
49
+ elif difficulty == "Professional":
50
+ prompt = (
51
+ f"Provide a advanced recipe for {user_direction} that excludes {exclusions} and has a serving size of {serving_size}. "
52
+ f"The recipe should push the boundaries of culinary arts, integrating unique ingredients, advanced cooking techniques, and innovative presentations. "
53
+ f"The recipe should be able to be served at a high-end restaurant or would impress at a gourmet food competition. "
54
+ f"Provide a detailed ingredient list and step-by-step guide that explains the instructions to prepare in detail."
55
+ )
56
+ return prompt
57
+
58
+ def generate_recipe(user_inputs):
59
+ with st.spinner('Building the perfect recipe...'):
60
+ functions = [
61
+ {
62
+ "name": "provide_recipe",
63
+ "description": "Provides a detailed recipe strictly adhering to the user input/specifications, especially ingredient exclusions and the recipe difficulty",
64
+ "parameters": {
65
+ "type": "object",
66
+ "properties": {
67
+ "name": {
68
+ "type": "string",
69
+ "description": "A creative name for the recipe"
70
+ },
71
+ "description": {
72
+ "type": "string",
73
+ "description": "a brief one-sentence description of the provided recipe"
74
+ },
75
+ "ingredients": {
76
+ "type": "array",
77
+ "items": {
78
+ "type": "object",
79
+ "properties": {
80
+ "name": {
81
+ "type": "string",
82
+ "description": "Quantity and name of the ingredient"
83
+ }
84
+ }
85
+ }
86
+ },
87
+ "instructions": {
88
+ "type": "array",
89
+ "items": {
90
+ "type": "object",
91
+ "properties": {
92
+ "step_number": {
93
+ "type": "number",
94
+ "description": "The sequence number of this step"
95
+ },
96
+ "instruction": {
97
+ "type": "string",
98
+ "description": "Detailed description of what to do in this step"
99
+ }
100
+ }
101
+ }
102
+ }
103
+ },
104
+ "required": [
105
+ "name",
106
+ "description",
107
+ "ingredients",
108
+ "instructions"
109
+ ],
110
+ },
111
+ }
112
+ ]
113
+ prompt = create_detailed_prompt(user_inputs['user_direction'], user_inputs['exclusions'], user_inputs['serving_size'], user_inputs['difficulty'])
114
+ messages = [{"role": "user", "content": prompt}]
115
+ text = tokenizer.apply_chat_template(
116
+ messages,
117
+ tokenize=False,
118
+ add_generation_prompt=True,
119
+ tools=functions
120
+ )
121
+
122
+ # Tokenize and move to the correct device
123
+ model_inputs = tokenizer([text], return_tensors="pt").to(device)
124
+ torch.cuda.empty_cache()
125
+ with torch.no_grad():
126
+ generated_ids = model.generate(
127
+ model_inputs.input_ids,
128
+ max_new_tokens=64 # Reduced value for memory management
129
+ )
130
+
131
+ generated_ids = [
132
+ output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
133
+ ]
134
+
135
+ st.session_state.recipe = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
136
+ st.session_state.recipe_saved = False
137
+
138
+ def clear_inputs():
139
+ st.session_state.user_direction = None
140
+ st.session_state.exclusions = None
141
+ st.session_state.serving_size = 2
142
+ st.session_state.selected_difficulty = "Quick & Easy"
143
+
144
+ st.title("Let's get cooking")
145
+ st.session_state.user_direction = st.text_area(
146
+ "What do you want to cook? Describe anything - a dish, cuisine, event, or vibe.",
147
+ value = st.session_state.user_direction,
148
+ placeholder="quick snack, asian style bowl with either noodles or rice, something italian",
149
+ )
150
+
151
+ st.session_state.serving_size = st.number_input(
152
+ "How many servings would you like to cook?",
153
+ min_value=1,
154
+ max_value=100,
155
+ value=st.session_state.serving_size,
156
+ step=1
157
+ )
158
+
159
+ difficulty_dictionary = {
160
+ "Quick & Easy": {
161
+ "description": "Easy recipes with straightforward instructions. Ideal for beginners or those seeking quick and simple cooking.",
162
+ },
163
+ "Intermediate": {
164
+ "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.",
165
+ },
166
+ "Professional": {
167
+ "description": "Complex recipes that demand a high level of skill and precision. Suited for seasoned cooks aspiring to professional-level sophistication and creativity.",
168
+ }
169
+ }
170
+
171
+ st.session_state.selected_difficulty = st.radio(
172
+ "Choose a difficulty level for your recipe.",
173
+ [
174
+ list(difficulty_dictionary.keys())[0],
175
+ list(difficulty_dictionary.keys())[1],
176
+ list(difficulty_dictionary.keys())[2]
177
+ ],
178
+ captions = [
179
+ difficulty_dictionary["Quick & Easy"]["description"],
180
+ difficulty_dictionary["Intermediate"]["description"],
181
+ difficulty_dictionary["Professional"]["description"]
182
+ ],
183
+ index=list(difficulty_dictionary).index(st.session_state.selected_difficulty)
184
+ )
185
+
186
+ st.session_state.exclusions = st.text_area(
187
+ "Any ingredients you want to exclude?",
188
+ value = st.session_state.exclusions,
189
+ placeholder="gluten, dairy, nuts, cilantro",
190
+ )
191
+
192
+ fancy_exclusions =""
193
+
194
+ if st.session_state.selected_difficulty == "Professional":
195
+ exclude_fancy = st.checkbox(
196
+ "Exclude cliche professional ingredients? (gold leaf, truffle, edible flowers, microgreens)",
197
+ value=True)
198
+ fancy_exclusions = "gold leaf, truffle, edible flowers, microgreens, gold dust"
199
+
200
+
201
+ user_inputs = {
202
+ "user_direction" : st.session_state.user_direction,
203
+ "exclusions": f"{st.session_state.exclusions}, {fancy_exclusions}",
204
+ "serving_size": st.session_state.serving_size,
205
+ "difficulty": st.session_state.selected_difficulty
206
+ }
207
+ button_cols_submit = st.columns([1, 1, 4])
208
+ with button_cols_submit[0]:
209
+ st.button(label='Submit', on_click=generate_recipe, kwargs=dict(user_inputs=user_inputs), type="primary", use_container_width=True)
210
+ with button_cols_submit[1]:
211
+ st.button(label='Reset', on_click=clear_inputs, type="secondary", use_container_width=True)
212
+ with button_cols_submit[2]:
213
+ st.empty()
214
+
215
+ if st.session_state.recipe is not None:
216
+ st.divider()
217
+ recipe = json.loads(st.session_state.recipe)
218
+ recipe_md = ''
219
+ recipe_md += f'# {recipe["name"]} \n\n'
220
+ recipe_md += f'{recipe["description"]} \n\n'
221
+ recipe_md += '## Ingredients: \n'
222
+ for ingredient in recipe['ingredients']:
223
+ recipe_md += f"- {ingredient['name']} \n"
224
+ recipe_md += '\n## Instructions:\n'
225
+ for instruction in recipe['instructions']:
226
+ recipe_md += f"{instruction['step_number']}. {instruction['instruction']} \n"
227
+ recipe['md'] = recipe_md
228
+ recipe['timestamp'] = str(datetime.now())
229
+ st.markdown(recipe_md)
230
+ st.write("")