nbroad HF staff commited on
Commit
e2d34bf
1 Parent(s): 37e608c

cosmetic changes

Browse files
Files changed (3) hide show
  1. app.py +137 -96
  2. examples.py +1 -0
  3. meta.py +2 -2
app.py CHANGED
@@ -1,63 +1,53 @@
1
  import streamlit as st
 
2
 
3
  import torch
4
  from transformers import pipeline, set_seed
5
  from transformers import AutoTokenizer
6
 
7
- from PIL import (
8
- Image,
9
- ImageFont,
10
- ImageDraw
11
- )
12
 
13
  import re
14
  import textwrap
15
  from examples import EXAMPLES
16
  import meta
17
- from utils import (
18
- remote_css,
19
- local_css,
20
- load_image,
21
- pure_comma_separation
22
- )
23
 
24
 
25
  class TextGeneration:
26
  def __init__(self):
27
- self.debug = False
28
  self.dummy_output = {
29
- 'directions': [
30
- 'peel the potato and slice thinly.',
31
- 'place in a microwave safe dish.',
32
- 'cover with plastic wrap and microwave on high for 5 minutes.',
33
- 'remove from the microwave and sprinkle with cheese.',
34
- 'return to the microwave for 1 minute or until cheese is melted.',
35
- 'return to the microwave for 1 minute or until cheese is melted. return to the microwave for 1 minute or until cheese is melted.'
36
- 'return to the microwave for 1 minute or until cheese is melted.',
37
- 'return to the microwave for 1 minute or until cheese is melted.',
38
- 'return to the microwave for 1 minute or until cheese is melted.',
39
  ],
40
- 'ingredients': [
41
- '1 potato',
42
- '1 slice cheese',
43
- '1 potato',
44
- '1 slice cheese'
45
- '1 potato',
46
- '1 slice cheese',
47
- '1 slice cheese',
48
- '1 potato',
49
- '1 slice cheese'
50
- '1 potato',
51
- '1 slice cheese',
52
  ],
53
- 'title': 'Cheese Potatoes with Some other items'
54
  }
55
  self.tokenizer = None
56
  self.generator = None
57
  self.task = "text2text-generation"
58
  self.model_name_or_path = "flax-community/t5-recipe-generation"
59
  self.list_division = 5
60
- self.point = "-"
61
  self.h1_font = ImageFont.truetype("asset/fonts/PT_Serif/PTSerif-Bold.ttf", 75)
62
  self.h2_font = ImageFont.truetype("asset/fonts/PT_Serif/PTSerif-Bold.ttf", 50)
63
  self.p_font = ImageFont.truetype("asset/fonts/PT_Serif/PTSerif-Regular.ttf", 30)
@@ -70,7 +60,7 @@ class TextGeneration:
70
  text = re.sub(
71
  recipe_map_pattern,
72
  lambda m: recipe_maps[m.group()],
73
- re.sub("|".join(self.tokenizer.all_special_tokens), "", text)
74
  )
75
 
76
  data = {"title": "", "ingredients": [], "directions": []}
@@ -78,12 +68,20 @@ class TextGeneration:
78
  section = section.strip()
79
  if section.startswith("title:"):
80
  data["title"] = " ".join(
81
- [w.strip().capitalize() for w in section.replace("title:", "").strip().split() if w.strip()]
 
 
 
 
82
  )
83
  elif section.startswith("ingredients:"):
84
- data["ingredients"] = [s.strip() for s in section.replace("ingredients:", "").split('--')]
 
 
85
  elif section.startswith("directions:"):
86
- data["directions"] = [s.strip() for s in section.replace("directions:", "").split('--')]
 
 
87
  else:
88
  pass
89
 
@@ -92,7 +90,11 @@ class TextGeneration:
92
  def load(self):
93
  if not self.debug:
94
  self.tokenizer = AutoTokenizer.from_pretrained(self.model_name_or_path)
95
- self.generator = pipeline(self.task, model=self.model_name_or_path, tokenizer=self.model_name_or_path)
 
 
 
 
96
 
97
  def prepare_frame(self, recipe, frame):
98
  im_editable = ImageDraw.Draw(frame)
@@ -114,12 +116,16 @@ class TextGeneration:
114
  )
115
  hs = hs + 80
116
  ingredients = recipe["ingredients"]
117
- ingredients_col1 = [textwrap.fill(item, 30) for item in ingredients[:self.list_division]]
118
- ingredients_col2 = [textwrap.fill(item, 30) for item in ingredients[self.list_division:]]
 
 
 
 
119
 
120
  im_editable.text(
121
  (ws + 10, hs),
122
- "\n".join([f"- {item}" for item in ingredients_col1]),
123
  (61, 61, 70),
124
  font=self.p_font,
125
  )
@@ -138,10 +144,13 @@ class TextGeneration:
138
  font=self.h2_font,
139
  )
140
  hs = hs + 80
141
- directions = [textwrap.fill(item, 70).replace("\n", "\n ") for item in recipe["directions"]]
 
 
 
142
  im_editable.text(
143
  (ws + 10, hs),
144
- "\n".join([f"{self.point} {item}" for item in directions]),
145
  (61, 61, 70),
146
  font=self.p_font,
147
  )
@@ -155,10 +164,9 @@ class TextGeneration:
155
  generation_kwargs["return_tensors"] = True
156
  generation_kwargs["return_text"] = False
157
 
158
- generated_ids = self.generator(
159
- items,
160
- **generation_kwargs,
161
- )[0]["generated_token_ids"]
162
  recipe = self.tokenizer.decode(generated_ids, skip_special_tokens=False)
163
  recipe = self._skip_special_tokens_and_prettify(recipe)
164
  return recipe
@@ -184,7 +192,7 @@ chef_top = {
184
  "do_sample": True,
185
  "top_k": 60,
186
  "top_p": 0.95,
187
- "num_return_sequences": 1
188
  }
189
  chef_beam = {
190
  "max_length": 512,
@@ -193,80 +201,108 @@ chef_beam = {
193
  "early_stopping": True,
194
  "num_beams": 5,
195
  "length_penalty": 1.5,
196
- "num_return_sequences": 1
197
  }
198
 
199
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  def main():
201
  st.set_page_config(
202
  page_title="Chef Transformer",
203
  page_icon="🍲",
204
  layout="wide",
205
- initial_sidebar_state="expanded"
206
  )
207
  generator = load_text_generator()
208
  local_css("asset/css/style.css")
209
 
210
- st.sidebar.image(load_image("asset/images/chef-transformer-transparent.png"), width=310)
211
- st.sidebar.title("Welcome to our lovely restaurant, what can I do for you?")
212
- chef = st.sidebar.selectbox("Choose your chef", index=0, options=["Chef Scheherazade", "Chef Giovanni"])
213
- is_text = st.sidebar.selectbox(
214
- label='Recipe',
 
 
 
 
215
  options=(True, False),
216
- help="Will generate your recipe as a text post",
 
217
  )
218
- is_frame = st.sidebar.selectbox(
219
- label='Recipe for Instagram?',
220
  options=(True, False),
221
- help="Will generate your recipe as an Instagram post",
 
222
  )
223
 
224
  st.markdown(meta.HEADER_INFO)
225
- prompts = list(EXAMPLES.keys()) + ["Custom"]
226
- prompt = st.selectbox('Examples', prompts, index=len(prompts) - 1)
227
 
228
- if prompt == "Custom":
229
- prompt_box = ""
 
 
 
 
 
 
 
 
 
230
  else:
231
- prompt_box = EXAMPLES[prompt]
232
-
233
- items = st.text_input(
234
- 'Add custom ingredients here (separated by `,`): ',
235
- pure_comma_separation(prompt_box, return_list=False),
236
- key="custom_keywords",
237
- max_chars=1000)
238
- items = pure_comma_separation(items, return_list=False)
239
  entered_items = st.empty()
240
 
241
- if st.button('Get Recipe!'):
242
- entered_items.markdown("**Generate recipe for:** " + items)
 
 
 
243
  with st.spinner("Generating recipe..."):
244
 
245
  if isinstance(items, str) and len(items) > 1:
246
  gen_kw = chef_top if chef == "Chef Scheherazade" else chef_beam
247
  generated_recipe = generator.generate(items, gen_kw)
248
 
249
- if is_text:
 
 
 
 
 
250
  title = generated_recipe["title"]
251
  ingredients = generated_recipe["ingredients"]
252
- directions = [textwrap.fill(item, 70).replace("\n", "\n ") for item in
253
- generated_recipe["directions"]]
254
- st.markdown(
255
- " ".join([
256
- f"<h2>{title}</h2>",
257
- "<h3>Ingredient</h3>",
258
- "<ul class='ingredients-list'>",
259
- " ".join([f'<li>{item}</li>' for item in ingredients]),
260
- "</ul>",
261
- "<h3>Direction</h3>",
262
- "<ul class='ingredients-list'>",
263
- " ".join([f'<li>{item}</li>' for item in directions]),
264
- "</ul>",
265
- ]),
266
- unsafe_allow_html=True
267
  )
268
-
269
- if is_frame:
 
 
 
 
 
270
  recipe_post = generator.generate_frame(generated_recipe)
271
 
272
  col1, col2, col3 = st.beta_columns([1, 6, 1])
@@ -279,14 +315,19 @@ def main():
279
  # width=500,
280
  caption="Your recipe",
281
  use_column_width="auto",
282
- output_format="PNG"
283
  )
284
 
285
  with col3:
286
  st.write("")
 
 
 
 
 
287
  else:
288
  entered_items.markdown("Enter your items...")
289
 
290
 
291
- if __name__ == '__main__':
292
  main()
1
  import streamlit as st
2
+ import streamlit.components.v1 as components
3
 
4
  import torch
5
  from transformers import pipeline, set_seed
6
  from transformers import AutoTokenizer
7
 
8
+ from PIL import Image, ImageFont, ImageDraw
 
 
 
 
9
 
10
  import re
11
  import textwrap
12
  from examples import EXAMPLES
13
  import meta
14
+ from utils import remote_css, local_css, load_image, pure_comma_separation
 
 
 
 
 
15
 
16
 
17
  class TextGeneration:
18
  def __init__(self):
19
+ self.debug = True
20
  self.dummy_output = {
21
+ "directions": [
22
+ "peel the potato and slice thinly.",
23
+ "place in a microwave safe dish.",
24
+ "cover with plastic wrap and microwave on high for 5 minutes.",
25
+ "remove from the microwave and sprinkle with cheese.",
26
+ "return to the microwave for 1 minute or until cheese is melted.",
27
+ "return to the microwave for 1 minute or until cheese is melted. return to the microwave for 1 minute or until cheese is melted."
28
+ "return to the microwave for 1 minute or until cheese is melted.",
29
+ "return to the microwave for 1 minute or until cheese is melted.",
30
+ "return to the microwave for 1 minute or until cheese is melted.",
31
  ],
32
+ "ingredients": [
33
+ "1 potato",
34
+ "1 slice cheese",
35
+ "1 potato",
36
+ "1 slice cheese" "1 potato",
37
+ "1 slice cheese",
38
+ "1 slice cheese",
39
+ "1 potato",
40
+ "1 slice cheese" "1 potato",
41
+ "1 slice cheese",
 
 
42
  ],
43
+ "title": "Cheese Potatoes with Some other items",
44
  }
45
  self.tokenizer = None
46
  self.generator = None
47
  self.task = "text2text-generation"
48
  self.model_name_or_path = "flax-community/t5-recipe-generation"
49
  self.list_division = 5
50
+ self.point = ""
51
  self.h1_font = ImageFont.truetype("asset/fonts/PT_Serif/PTSerif-Bold.ttf", 75)
52
  self.h2_font = ImageFont.truetype("asset/fonts/PT_Serif/PTSerif-Bold.ttf", 50)
53
  self.p_font = ImageFont.truetype("asset/fonts/PT_Serif/PTSerif-Regular.ttf", 30)
60
  text = re.sub(
61
  recipe_map_pattern,
62
  lambda m: recipe_maps[m.group()],
63
+ re.sub("|".join(self.tokenizer.all_special_tokens), "", text),
64
  )
65
 
66
  data = {"title": "", "ingredients": [], "directions": []}
68
  section = section.strip()
69
  if section.startswith("title:"):
70
  data["title"] = " ".join(
71
+ [
72
+ w.strip().capitalize()
73
+ for w in section.replace("title:", "").strip().split()
74
+ if w.strip()
75
+ ]
76
  )
77
  elif section.startswith("ingredients:"):
78
+ data["ingredients"] = [
79
+ s.strip() for s in section.replace("ingredients:", "").split("--")
80
+ ]
81
  elif section.startswith("directions:"):
82
+ data["directions"] = [
83
+ s.strip() for s in section.replace("directions:", "").split("--")
84
+ ]
85
  else:
86
  pass
87
 
90
  def load(self):
91
  if not self.debug:
92
  self.tokenizer = AutoTokenizer.from_pretrained(self.model_name_or_path)
93
+ self.generator = pipeline(
94
+ self.task,
95
+ model=self.model_name_or_path,
96
+ tokenizer=self.model_name_or_path,
97
+ )
98
 
99
  def prepare_frame(self, recipe, frame):
100
  im_editable = ImageDraw.Draw(frame)
116
  )
117
  hs = hs + 80
118
  ingredients = recipe["ingredients"]
119
+ ingredients_col1 = [
120
+ textwrap.fill(item, 30) for item in ingredients[: self.list_division]
121
+ ]
122
+ ingredients_col2 = [
123
+ textwrap.fill(item, 30) for item in ingredients[self.list_division :]
124
+ ]
125
 
126
  im_editable.text(
127
  (ws + 10, hs),
128
+ "\n".join([f"{self.point} {item}" for item in ingredients_col1]),
129
  (61, 61, 70),
130
  font=self.p_font,
131
  )
144
  font=self.h2_font,
145
  )
146
  hs = hs + 80
147
+ directions = [
148
+ textwrap.fill(item, 70).replace("\n", "\n ")
149
+ for item in recipe["directions"]
150
+ ]
151
  im_editable.text(
152
  (ws + 10, hs),
153
+ "\n".join([f"{num}. {d}" for num, d in enumerate(directions, start=1)]),
154
  (61, 61, 70),
155
  font=self.p_font,
156
  )
164
  generation_kwargs["return_tensors"] = True
165
  generation_kwargs["return_text"] = False
166
 
167
+ generated_ids = self.generator(items, **generation_kwargs,)[
168
+ 0
169
+ ]["generated_token_ids"]
 
170
  recipe = self.tokenizer.decode(generated_ids, skip_special_tokens=False)
171
  recipe = self._skip_special_tokens_and_prettify(recipe)
172
  return recipe
192
  "do_sample": True,
193
  "top_k": 60,
194
  "top_p": 0.95,
195
+ "num_return_sequences": 1,
196
  }
197
  chef_beam = {
198
  "max_length": 512,
201
  "early_stopping": True,
202
  "num_beams": 5,
203
  "length_penalty": 1.5,
204
+ "num_return_sequences": 1,
205
  }
206
 
207
 
208
+ def true_false_format_func(choose_yes):
209
+ if choose_yes:
210
+ return "Yes"
211
+ return "No"
212
+
213
+
214
+ def examples_custom_format_func(use_examples):
215
+ if use_examples:
216
+ return "Examples"
217
+ return "Custom ingredients"
218
+
219
+
220
  def main():
221
  st.set_page_config(
222
  page_title="Chef Transformer",
223
  page_icon="🍲",
224
  layout="wide",
225
+ initial_sidebar_state="expanded",
226
  )
227
  generator = load_text_generator()
228
  local_css("asset/css/style.css")
229
 
230
+ st.sidebar.image(
231
+ load_image("asset/images/chef-transformer-transparent.png"), width=310
232
+ )
233
+ st.sidebar.title("Welcome to our lovely restaurant, how may I serve you?")
234
+ chef = st.sidebar.selectbox(
235
+ "Choose your chef", index=0, options=["Chef Scheherazade", "Chef Giovanni"]
236
+ )
237
+ recipe_as_text = st.sidebar.radio(
238
+ label="Show Recipe Text",
239
  options=(True, False),
240
+ help="A text version of the generated recipe will be displayed (can copy-paste)",
241
+ format_func=true_false_format_func,
242
  )
243
+ recipe_as_image = st.sidebar.radio(
244
+ label="Show Recipe Image",
245
  options=(True, False),
246
+ help="An image of the generated recipe will be displayed (useful for social media)",
247
+ format_func=true_false_format_func,
248
  )
249
 
250
  st.markdown(meta.HEADER_INFO)
 
 
251
 
252
+ use_examples = st.radio(
253
+ label="Choose from predefined examples or use custom ingredients",
254
+ options=[True, False],
255
+ format_func=examples_custom_format_func,
256
+ )
257
+
258
+ input_container = st.empty()
259
+
260
+ if use_examples:
261
+ example_name = input_container.selectbox("Examples", EXAMPLES.keys())
262
+ items = pure_comma_separation(EXAMPLES[example_name], return_list=False)
263
  else:
264
+ example_name = None
265
+ items = input_container.text_input(
266
+ "Add custom ingredients here (separated by `,`): ",
267
+ key="custom_keywords",
268
+ max_chars=1000,
269
+ )
 
 
270
  entered_items = st.empty()
271
 
272
+ if st.button("Generate Recipe!"):
273
+ # if st.button("Generate Recipe!") or len(items):
274
+ entered_items.markdown(
275
+ "**Generating recipe using the following ingredients:** " + items
276
+ )
277
  with st.spinner("Generating recipe..."):
278
 
279
  if isinstance(items, str) and len(items) > 1:
280
  gen_kw = chef_top if chef == "Chef Scheherazade" else chef_beam
281
  generated_recipe = generator.generate(items, gen_kw)
282
 
283
+ if recipe_as_text:
284
+
285
+ st.markdown(
286
+ '<div>To copy the recipe to your clipboard, hover the mouse in the top-right corner of the section below and then click the button that looks like this: <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg> </div>',
287
+ unsafe_allow_html=True,
288
+ )
289
  title = generated_recipe["title"]
290
  ingredients = generated_recipe["ingredients"]
291
+ directions = [
292
+ textwrap.fill(item, 100).replace("\n", "\n ")
293
+ for item in generated_recipe["directions"]
294
+ ]
295
+ ingredients = "\n• ".join(ingredients)
296
+ directions = "\n".join(
297
+ [f"{n}. {d}" for n, d in enumerate(directions, start=1)]
 
 
 
 
 
 
 
 
298
  )
299
+ st.code(
300
+ f"""
301
+ {title}\n\n\nIngredients\n\n• {ingredients}\n\nDirections\n\n{directions}
302
+ """.strip(),
303
+ language="text",
304
+ )
305
+ if recipe_as_image:
306
  recipe_post = generator.generate_frame(generated_recipe)
307
 
308
  col1, col2, col3 = st.beta_columns([1, 6, 1])
315
  # width=500,
316
  caption="Your recipe",
317
  use_column_width="auto",
318
+ output_format="PNG",
319
  )
320
 
321
  with col3:
322
  st.write("")
323
+
324
+ if not recipe_as_text and not recipe_as_image:
325
+ st.write(
326
+ "Please select 'Yes' for either 'Show Recipe Text' or 'Show Recipe Image' in the left sidebar."
327
+ )
328
  else:
329
  entered_items.markdown("Enter your items...")
330
 
331
 
332
+ if __name__ == "__main__":
333
  main()
examples.py CHANGED
@@ -1,3 +1,4 @@
1
  EXAMPLES = {
2
  "Chocolate Baklava": "phyllo dough, unsalted butter, walnuts, cinnamon, water, honey, melted chocolate",
 
3
  }
1
  EXAMPLES = {
2
  "Chocolate Baklava": "phyllo dough, unsalted butter, walnuts, cinnamon, water, honey, melted chocolate",
3
+ "Meatballs in Tomato Sauce": "eggs, durum, olive oil, oregano, tomatoes, parmesan, ground beef",
4
  }
meta.py CHANGED
@@ -1,8 +1,8 @@
1
  HEADER_INFO = """
2
  # Chef Transformer 🍲
3
 
4
- This demo uses [T5 trained on RecipeNLG](https://huggingface.co/flax-community/t5-recipe-generation)
5
- to generate recipe from a given set of ingredients
6
  """.strip()
7
  SIDEBAR_INFO = """
8
  # Configuration
1
  HEADER_INFO = """
2
  # Chef Transformer 🍲
3
 
4
+ This demo uses [T5 trained on the RecipeNLG dataset](https://huggingface.co/flax-community/t5-recipe-generation)
5
+ to generate recipes from a given set of ingredients
6
  """.strip()
7
  SIDEBAR_INFO = """
8
  # Configuration