m3hrdadfi commited on
Commit
5849dd5
β€’
1 Parent(s): 9dcef67

Add GenFood into generated recipe

Browse files
app.py CHANGED
@@ -9,78 +9,149 @@ from PIL import (
9
  ImageFont,
10
  ImageDraw
11
  )
 
12
 
13
- import numpy as np
14
- from datetime import datetime
15
- import glob
16
  import re
17
  import random
18
  import textwrap
19
  from examples import EXAMPLES
 
20
  import meta
21
  from utils import (
22
  remote_css,
23
  local_css,
24
- load_image,
 
 
25
  pure_comma_separation
26
  )
27
 
28
- # np.random.seed(42)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
 
31
  class TextGeneration:
32
  def __init__(self):
33
- self.debug = False
34
- self.dummy_output = {
35
- 'directions': [
36
- "for the dough",
37
- "in a small bowl, combine the warm water and yeast.",
38
- "let it sit for 5 minutes.",
39
- "add the flour, salt, and olive oil.",
40
- "mix well and knead until the dough is smooth and elastic.",
41
- "cover the dough with a damp towel and let it rise for about 1 hour.",
42
- "for the filling",
43
- "heat a large skillet over medium high heat.",
44
- "cook the beef and onion until the beef is browned and the onion is translucent. browned and the onion is translucent.",
45
- "drain off any excess grease.",
46
- "stir in the pepper and salt and black pepper to taste.",
47
- "remove from the heat and set aside.",
48
- "preheat the oven to 425 degrees f.",
49
- "roll out the dough on a lightly floured surface into a 12 inch circle.",
50
- "spread the beef mixture over the dough, leaving a 1 inch border.",
51
- "top with the feta, parsley, and lemon juice.",
52
- "bake for 20 minutes or until the crust is golden brown.",
53
- "cut into wedges and serve.",
54
- ],
55
- 'ingredients': [
56
- '1 potato',
57
- '1 slice cheese 1 slice cheese',
58
- '1 potato 1 slice cheese 1 slice cheese',
59
- '1 slice cheese'
60
- '1 potato',
61
- '1 slice cheese',
62
- '1 slice cheese',
63
- '1 potato',
64
- '1 slice cheese'
65
- '1 potato',
66
- '1 slice cheese',
67
- ],
68
- 'title': 'Cheese Potatoes with Some other items'
69
- }
70
  self.tokenizer = None
71
  self.generator = None
 
 
 
72
  self.task = "text2text-generation"
73
  self.model_name_or_path = "flax-community/t5-recipe-generation"
74
- self.frames = list(glob.glob("asset/images/frames/*.jpg"))
 
 
 
 
 
 
 
75
  self.fonts = {
76
- "title": ImageFont.truetype("asset/fonts/Poppins-Bold.ttf", 90),
77
  "sub_title": ImageFont.truetype("asset/fonts/Poppins-Medium.ttf", 30),
78
- "body_bold": ImageFont.truetype("asset/fonts/Montserrat-Bold.ttf", 50),
79
- "body": ImageFont.truetype("asset/fonts/Montserrat-Regular.ttf", 30),
80
 
81
  }
82
- self.list_division = 5
83
- self.point = "β€’"
84
  set_seed(42)
85
 
86
  def _skip_special_tokens_and_prettify(self, text):
@@ -109,81 +180,43 @@ class TextGeneration:
109
 
110
  return data
111
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  def load(self):
 
113
  if not self.debug:
114
- self.tokenizer = AutoTokenizer.from_pretrained(self.model_name_or_path)
115
- self.generator = pipeline(self.task, model=self.model_name_or_path, tokenizer=self.model_name_or_path)
116
-
117
- def prepare_frame(self, recipe, frame):
118
- im_editable = ImageDraw.Draw(frame)
119
- # Info
120
- im_editable.text(
121
- (1570, 180),
122
- datetime.now().strftime("%Y-%m-%d %H:%M"),
123
- (61, 61, 70),
124
- font=self.fonts["sub_title"],
125
- )
126
- im_editable.text(
127
- (1570, 170 + 70),
128
- "By " + recipe["by"],
129
- (61, 61, 70),
130
- font=self.fonts["sub_title"],
131
  )
132
- # Title
133
- im_editable.text(
134
- (400, 650),
135
- textwrap.fill(recipe["title"], 30),
136
- (61, 61, 70),
137
- font=self.fonts["title"],
138
- )
139
- # Ingredients
140
- im_editable.text(
141
- (100, 1000),
142
- "Ingredients",
143
- (61, 61, 70),
144
- font=self.fonts["body_bold"],
145
- )
146
- ingredients = recipe["ingredients"]
147
- ingredients = [textwrap.fill(item, 30).replace("\n", "\n ") for item in ingredients]
148
-
149
- im_editable.text(
150
- (100, 1080),
151
- "\n".join([f"{self.point} {item}" for item in ingredients]),
152
- (61, 61, 70),
153
- font=self.fonts["body"],
154
- )
155
- # Directions
156
- im_editable.text(
157
- (700, 1000),
158
- "Directions",
159
- (61, 61, 70),
160
- font=self.fonts["body_bold"],
161
- )
162
- directions = recipe["directions"]
163
- directions = [textwrap.fill(item, 80).replace("\n", "\n ") for item in directions]
164
- im_editable.text(
165
- (700, 1080),
166
- "\n".join([f"{i + 1}. {item}" for i, item in enumerate(directions)]).strip(),
167
- (61, 61, 70),
168
- font=self.fonts["body"],
169
- )
170
- # directions_col1 = [textwrap.fill(item, 30).replace("\n", "\n ") for item in directions[:self.list_division]]
171
- # directions_col2 = [textwrap.fill(item, 30).replace("\n", "\n ") for item in directions[self.list_division:]]
172
- # im_editable.text(
173
- # (700, 1130),
174
- # "\n".join([f"{i + 1}. {item}" for i, item in enumerate(directions_col1)]).strip(),
175
- # (61, 61, 70),
176
- # font=self.fonts["body"],
177
- # )
178
- # im_editable.text(
179
- # (1300, 1130),
180
- # "\n".join([f"{i + 1 + self.list_division}. {item}" for i, item in enumerate(directions_col2)]).strip(),
181
- # (61, 61, 70),
182
- # font=self.fonts["body"],
183
- # )
184
  return frame
185
 
186
  def generate(self, items, generation_kwargs):
 
 
187
  if not self.debug:
188
  generation_kwargs["num_return_sequences"] = 1
189
  # generation_kwargs["return_full_text"] = False
@@ -196,13 +229,25 @@ class TextGeneration:
196
  )[0]["generated_token_ids"]
197
  recipe = self.tokenizer.decode(generated_ids, skip_special_tokens=False)
198
  recipe = self._skip_special_tokens_and_prettify(recipe)
199
- return recipe
200
 
201
- return self.dummy_output
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
 
203
- def generate_frame(self, recipe, frame_path):
204
- frame = load_image(frame_path)
205
- return self.prepare_frame(recipe, frame)
206
 
207
 
208
  @st.cache(allow_output_mutation=True)
@@ -240,17 +285,17 @@ def main():
240
  initial_sidebar_state="expanded"
241
  )
242
  generator = load_text_generator()
243
- if hasattr(st, "session_state"):
244
- if 'get_random_frame' not in st.session_state:
245
- st.session_state.get_random_frame = generator.frames[0]
246
- else:
247
- get_random_frame = generator.frames[0]
248
 
249
  local_css("asset/css/style.css")
250
 
251
- col1, col2 = st.beta_columns([5, 3])
252
  with col2:
253
- st.image(load_image("asset/images/chef-transformer-transparent.png"), width=300)
254
  st.markdown(meta.SIDEBAR_INFO, unsafe_allow_html=True)
255
 
256
  with st.beta_expander("Where did this story start?"):
@@ -288,10 +333,10 @@ def main():
288
  unsafe_allow_html=True
289
  )
290
  if recipe_button:
291
- if hasattr(st, "session_state"):
292
- st.session_state.get_random_frame = generator.frames[random.randint(0, len(generator.frames)) - 1]
293
- else:
294
- get_random_frame = generator.frames[random.randint(0, len(generator.frames)) - 1]
295
 
296
  entered_items.markdown("**Generate recipe for:** " + items)
297
  with st.spinner("Generating recipe..."):
@@ -306,6 +351,9 @@ def main():
306
  generated_recipe = generator.generate(items, gen_kw)
307
 
308
  title = generated_recipe["title"]
 
 
 
309
  ingredients = generated_recipe["ingredients"]
310
  directions = [textwrap.fill(item, 70).replace("\n", "\n ") for item in
311
  generated_recipe["directions"]]
@@ -315,15 +363,17 @@ def main():
315
 
316
  with r1:
317
  # st.write(st.session_state.get_random_frame)
318
- if hasattr(st, "session_state"):
319
- recipe_post = generator.generate_frame(generated_recipe, st.session_state.get_random_frame)
320
- else:
321
- recipe_post = generator.generate_frame(generated_recipe, get_random_frame)
 
 
322
 
323
  st.image(
324
  recipe_post,
325
  # width=500,
326
- caption="Click πŸ”Ž to enlarge",
327
  use_column_width="auto",
328
  output_format="PNG"
329
  )
@@ -332,7 +382,11 @@ def main():
332
  st.markdown(
333
  " ".join([
334
  "<div class='r-text-recipe'>",
 
 
335
  f"<h2>{title}</h2>",
 
 
336
  "<h3>Ingredients</h3>",
337
  "<ul class='ingredients-list'>",
338
  " ".join([f'<li>{item}</li>' for item in ingredients]),
 
9
  ImageFont,
10
  ImageDraw
11
  )
12
+ import requests
13
 
14
+ import os
 
 
15
  import re
16
  import random
17
  import textwrap
18
  from examples import EXAMPLES
19
+ import dummy
20
  import meta
21
  from utils import (
22
  remote_css,
23
  local_css,
24
+ load_image_from_url,
25
+ load_image_from_local,
26
+ image_to_base64,
27
  pure_comma_separation
28
  )
29
 
30
+
31
+ def generate_cook_image(query, app_id, app_key):
32
+ api_url = f"https://api.edamam.com/api/recipes/v2?type=public&q={query}&app_id={app_id}&app_key={app_key}&field=image"
33
+
34
+ try:
35
+ r = requests.get(api_url)
36
+ if r.status_code != 200:
37
+ return None
38
+
39
+ rj = r.json()
40
+ if "hits" not in rj or not len(rj["hits"]) > 0:
41
+ return None
42
+
43
+ data = rj["hits"]
44
+ data = data[random.randint(0, min(4, len(data) - 1))] if len(data) > 1 else data[0]
45
+
46
+ if "recipe" not in data or "image" not in data["recipe"]:
47
+ return None
48
+
49
+ image = data["recipe"]["image"]
50
+ return image
51
+ except Exception as e:
52
+ return None
53
+
54
+
55
+ def generate_food_with_logo_image(bg_path, logo_path, food_url, no_food="asset/frame/no_food.png"):
56
+ bg = Image.open(bg_path)
57
+ width, height = bg.size
58
+
59
+ logo = Image.open(logo_path)
60
+ logo_width, logo_height, logo_ratio, logo_rb, logo_mb = logo.size + (3, -20, 45)
61
+ logo_width, logo_height = (logo_width // logo_ratio, logo_height // logo_ratio)
62
+ logo = logo.resize((logo_width, logo_height))
63
+
64
+ food = load_image_from_url(food_url, rgba_mode=True, default_image=no_food)
65
+
66
+ food_width, food_height = (300, 300)
67
+ food = food.resize((food_width, food_height))
68
+
69
+ bg.paste(food, (0, 0), food)
70
+ bg.paste(logo, (width - logo_width - logo_rb, height - logo_height - logo_mb), logo)
71
+
72
+ return bg
73
+
74
+
75
+ def generate_recipe_image(
76
+ recipe_data,
77
+ bg_path,
78
+ food_logo_ia,
79
+ fonts,
80
+ bg_color="#ffffff"
81
+ ):
82
+ bg = Image.open(bg_path)
83
+ bg.paste(food_logo_ia, (50, 50), food_logo_ia)
84
+ bg_color = Image.new("RGBA", bg.size, bg_color)
85
+ bg_color.paste(bg, mask=bg)
86
+
87
+ im_editable = ImageDraw.Draw(bg_color)
88
+ im_editable.text(
89
+ (418, 30),
90
+ textwrap.fill(recipe_data["title"], 15).replace(" \n", "\n"),
91
+ (61, 61, 70),
92
+ font=fonts["title"],
93
+ )
94
+
95
+ im_editable.text(
96
+ (100, 450),
97
+ "Ingredients",
98
+ (61, 61, 70),
99
+ font=fonts["body_bold"],
100
+ )
101
+ ingredients = recipe_data["ingredients"]
102
+ ingredients = [textwrap.fill(item, 30).replace("\n", "\n ") for item in ingredients]
103
+
104
+ im_editable.text(
105
+ (50, 520),
106
+ "\n".join([f"- {item}" for item in ingredients]),
107
+ (61, 61, 70),
108
+ font=fonts["body"],
109
+ )
110
+
111
+ im_editable.text(
112
+ (700, 450),
113
+ "Directions",
114
+ (61, 61, 70),
115
+ font=fonts["body_bold"],
116
+ )
117
+
118
+ directions = recipe_data["directions"]
119
+ directions = [textwrap.fill(item, 70).replace("\n", "\n ") for item in directions]
120
+ im_editable.text(
121
+ (430, 520),
122
+ "\n".join([f"{i + 1}. {item}" for i, item in enumerate(directions)]).strip(),
123
+ (61, 61, 70),
124
+ font=fonts["body"],
125
+ )
126
+ return bg_color
127
 
128
 
129
  class TextGeneration:
130
  def __init__(self):
131
+ self.debug = True
132
+ self.dummy_outputs = dummy.recipes
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  self.tokenizer = None
134
  self.generator = None
135
+ self.api_ids = []
136
+ self.api_keys = []
137
+ self.api_test = 2
138
  self.task = "text2text-generation"
139
  self.model_name_or_path = "flax-community/t5-recipe-generation"
140
+ self.color_frame = "#ffffff"
141
+ self.main_frame = "asset/frame/recipe-bg.png"
142
+ self.no_food = "asset/frame/no_food.png"
143
+ self.logo_frame = "asset/frame/logo.png"
144
+ self.chef_frames = {
145
+ "scheherazade": "asset/frame/food-image-logo-bg-s.png",
146
+ "giovanni": "asset/frame/food-image-logo-bg-g.png",
147
+ }
148
  self.fonts = {
149
+ "title": ImageFont.truetype("asset/fonts/Poppins-Bold.ttf", 70),
150
  "sub_title": ImageFont.truetype("asset/fonts/Poppins-Medium.ttf", 30),
151
+ "body_bold": ImageFont.truetype("asset/fonts/Montserrat-Bold.ttf", 22),
152
+ "body": ImageFont.truetype("asset/fonts/Montserrat-Regular.ttf", 18),
153
 
154
  }
 
 
155
  set_seed(42)
156
 
157
  def _skip_special_tokens_and_prettify(self, text):
 
180
 
181
  return data
182
 
183
+ def load_pipeline(self):
184
+ self.tokenizer = AutoTokenizer.from_pretrained(self.model_name_or_path)
185
+ self.generator = pipeline(self.task, model=self.model_name_or_path, tokenizer=self.model_name_or_path)
186
+
187
+ def load_api(self):
188
+ app_ids = os.getenv("EDAMAM_APP_ID")
189
+ app_ids = app_ids.split(",") if app_ids else []
190
+ app_keys = os.getenv("EDAMAM_APP_KEY")
191
+ app_keys = app_keys.split(",") if app_keys else []
192
+
193
+ if len(app_ids) != len(app_keys):
194
+ self.api_ids = []
195
+ self.api_keys = []
196
+
197
+ self.api_ids = app_ids
198
+ self.api_keys = app_keys
199
+
200
  def load(self):
201
+ self.load_api()
202
  if not self.debug:
203
+ self.load_pipeline()
204
+
205
+ def prepare_frame(self, recipe, chef_name):
206
+ frame_path = self.chef_frames[chef_name.lower()]
207
+ food_logo = generate_food_with_logo_image(frame_path, self.logo_frame, recipe["image"])
208
+ frame = generate_recipe_image(
209
+ recipe,
210
+ self.main_frame,
211
+ food_logo,
212
+ self.fonts,
213
+ bg_color="#ffffff"
 
 
 
 
 
 
214
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  return frame
216
 
217
  def generate(self, items, generation_kwargs):
218
+ recipe = self.dummy_outputs[random.randint(0, len(self.dummy_outputs) - 1)]
219
+
220
  if not self.debug:
221
  generation_kwargs["num_return_sequences"] = 1
222
  # generation_kwargs["return_full_text"] = False
 
229
  )[0]["generated_token_ids"]
230
  recipe = self.tokenizer.decode(generated_ids, skip_special_tokens=False)
231
  recipe = self._skip_special_tokens_and_prettify(recipe)
 
232
 
233
+ if self.api_ids and self.api_keys and len(self.api_ids) == len(self.api_keys):
234
+ test = 0
235
+ for i in range(len(self.api_keys)):
236
+ if test > self.api_test:
237
+ recipe["image"] = None
238
+ break
239
+ image = generate_cook_image(recipe["title"].lower(), self.api_ids[i], self.api_keys[i])
240
+ test += 1
241
+ if image:
242
+ recipe["image"] = image
243
+ break
244
+ else:
245
+ recipe["image"] = None
246
+
247
+ return recipe
248
 
249
+ def generate_frame(self, recipe, chef_name):
250
+ return self.prepare_frame(recipe, chef_name)
 
251
 
252
 
253
  @st.cache(allow_output_mutation=True)
 
285
  initial_sidebar_state="expanded"
286
  )
287
  generator = load_text_generator()
288
+ # if hasattr(st, "session_state"):
289
+ # if 'get_random_frame' not in st.session_state:
290
+ # st.session_state.get_random_frame = generator.frames[0]
291
+ # else:
292
+ # get_random_frame = generator.frames[0]
293
 
294
  local_css("asset/css/style.css")
295
 
296
+ col1, col2 = st.beta_columns([4, 3])
297
  with col2:
298
+ st.image(load_image_from_local("asset/images/chef-transformer-transparent.png"), width=300)
299
  st.markdown(meta.SIDEBAR_INFO, unsafe_allow_html=True)
300
 
301
  with st.beta_expander("Where did this story start?"):
 
333
  unsafe_allow_html=True
334
  )
335
  if recipe_button:
336
+ # if hasattr(st, "session_state"):
337
+ # st.session_state.get_random_frame = generator.frames[random.randint(0, len(generator.frames)) - 1]
338
+ # else:
339
+ # get_random_frame = generator.frames[random.randint(0, len(generator.frames)) - 1]
340
 
341
  entered_items.markdown("**Generate recipe for:** " + items)
342
  with st.spinner("Generating recipe..."):
 
351
  generated_recipe = generator.generate(items, gen_kw)
352
 
353
  title = generated_recipe["title"]
354
+ food_image = generated_recipe["image"]
355
+ food_image = load_image_from_url(food_image, rgba_mode=True, default_image=generator.no_food)
356
+ food_image = image_to_base64(food_image)
357
  ingredients = generated_recipe["ingredients"]
358
  directions = [textwrap.fill(item, 70).replace("\n", "\n ") for item in
359
  generated_recipe["directions"]]
 
363
 
364
  with r1:
365
  # st.write(st.session_state.get_random_frame)
366
+ # if hasattr(st, "session_state"):
367
+ # recipe_post = generator.generate_frame(generated_recipe, st.session_state.get_random_frame)
368
+ # else:
369
+ # recipe_post = generator.generate_frame(generated_recipe, get_random_frame)
370
+
371
+ recipe_post = generator.generate_frame(generated_recipe, chef.split()[-1])
372
 
373
  st.image(
374
  recipe_post,
375
  # width=500,
376
+ caption="Save image and share on your social media",
377
  use_column_width="auto",
378
  output_format="PNG"
379
  )
 
382
  st.markdown(
383
  " ".join([
384
  "<div class='r-text-recipe'>",
385
+ "<div class='food-title'>",
386
+ f"<img src='{food_image}' />",
387
  f"<h2>{title}</h2>",
388
+ "</div>",
389
+ '<div class="divider"><div class="divider-mask"></div></div>',
390
  "<h3>Ingredients</h3>",
391
  "<ul class='ingredients-list'>",
392
  " ".join([f'<li>{item}</li>' for item in ingredients]),
asset/css/style.css CHANGED
@@ -35,14 +35,46 @@ body {
35
  text-decoration: underline;
36
  }
37
 
 
 
 
 
 
38
  .r-text-recipe {
39
  padding-left: 30px;
40
  margin-left: 10px;
41
  border-left: 1px dashed #eee;
42
  }
43
- .r-text-recipe > h2 {
44
- margin-top: 0;
45
- padding-top: 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  }
47
  .ingredients-list {
48
  columns: 2;
 
35
  text-decoration: underline;
36
  }
37
 
38
+ .story-box {
39
+ overflow-y: scroll;
40
+ max-height: 300px;
41
+ }
42
+
43
  .r-text-recipe {
44
  padding-left: 30px;
45
  margin-left: 10px;
46
  border-left: 1px dashed #eee;
47
  }
48
+
49
+ .divider {
50
+ margin: 5px auto;
51
+ width: 400px;
52
+ max-width: 100%;
53
+ position:relative;
54
+ }
55
+
56
+ .divider-mask {
57
+ overflow: hidden;
58
+ height: 20px;
59
+ }
60
+
61
+ .divider-mask:after {
62
+ content: '';
63
+ display: block;
64
+ margin: 0 auto;
65
+ width: 170px;
66
+ height: 0px;
67
+ border-bottom: 2px solid #e9a726;
68
+ border-radius: 10px;
69
+ }
70
+
71
+ .r-text-recipe .food-title {
72
+ text-align: center;
73
+ }
74
+ .r-text-recipe .food-title img {
75
+ max-width: 120px;
76
+ }
77
+ .r-text-recipe .food-title h2 {
78
  }
79
  .ingredients-list {
80
  columns: 2;
asset/frame/export/food-image-logo.png ADDED
asset/frame/food-image-logo-background.png ADDED
asset/frame/food-image-logo-bg-g.png ADDED
asset/frame/food-image-logo-bg-s.png ADDED
asset/frame/food.jpg ADDED
asset/frame/logo.png ADDED
asset/frame/no_food.png ADDED
asset/frame/recipe-bg.png ADDED
dummy.py ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ recipes = [
2
+ {
3
+ 'directions': [
4
+ "preheat oven to 350.",
5
+ "grease a 13 x 9 x 2 inch baking pan.",
6
+ "place 1 sheet of the dough on a work surface.",
7
+ "brush with melted butter.",
8
+ "top with another sheet of dough and brush with butter. repeat with 3 more sheets of dough, brushing each sheet with butter between each layer.",
9
+ "combine walnuts and cinnamon in a small bowl.",
10
+ "sprinkle half of the walnut mixture over the dough.",
11
+ "repeat with the remaining dough and walnut mixture.",
12
+ "starting at the long side, roll up the dough into a log.",
13
+ "cut the log into 1 inch slices.",
14
+ "arrange the slices, cut side down, in the prepared baking dish.",
15
+ "bake until golden brown, about 30 minutes.",
16
+ "meanwhile, bring water and honey to a boil.",
17
+ "remove from heat and stir in chocolate until melted.",
18
+ "pour over the cooled strudel.",
19
+ "serve warm or at room temperature.",
20
+ "makes 12 servings.",
21
+ ],
22
+ 'ingredients': [
23
+ "1 lb. phyllo dough, thawed",
24
+ "1 c. unsalted butter, melted",
25
+ "2 c chopped walnuts",
26
+ "1/2 tsp. cinnamon",
27
+ "1 1/2 c water",
28
+ "3/4 c honey",
29
+ "1/4 c melted chocolate",
30
+ ],
31
+ 'title': 'Baklava'
32
+ },
33
+ {
34
+ 'directions': [
35
+ "in a large skillet, heat oil to 375.",
36
+ "season chops on both sides with salt and pepper.",
37
+ "dredge chops in flour, shaking off excess.",
38
+ "dip chops into eggs, then coat with breadcrumbs.",
39
+ "fry chops until golden brown, about 3 minutes per side.",
40
+ "transfer to a platter and keep warm.",
41
+ "pour off all but 1 tablespoon of fat from skillet.",
42
+ "add gravy and cook over medium heat, stirring occasionally, until thickened, about 5 minutes.",
43
+ "spoon gravy over chops and sprinkle with parsley.",
44
+ "makes 4 servings.",
45
+ ],
46
+ 'ingredients': [
47
+ "1 lb beef, cubed",
48
+ "2 tablespoons oil",
49
+ "1 large onion, chopped",
50
+ "2 medium tomatoes, peeled and chopped",
51
+ "1 teaspoon turmeric powder",
52
+ "2 limes, juice of",
53
+ "1 cup water",
54
+ "salt",
55
+ "pepper",
56
+ "1 15 ounce can red beans, drained and rinsed",
57
+ "1 tablespoon dried herb",
58
+ ],
59
+ 'title': 'Beef And Red Beans'
60
+ },
61
+ {
62
+ 'directions': [
63
+ "heat the oil in a large saucepan.",
64
+ "add the onion and saute until golden brown.",
65
+ "stir in the tomatoes, turmeric powder, lime juice, water, salt and pepper.",
66
+ "bring to a boil.",
67
+ "reduce the heat and simmer for 10 minutes.",
68
+ "mix in the beef and beans.",
69
+ "cover and cook over low heat for 30 minutes or until the beef is tender.",
70
+ "garnish with the dried herbs.",
71
+ ],
72
+ 'ingredients': [
73
+ "oil for frying",
74
+ "4 6 oz. boneless pork loin chops",
75
+ "salt",
76
+ "pepper",
77
+ "1/2 c. flour",
78
+ "2 eggs, lightly beaten",
79
+ "2 tbsp. dry breadcrumbs",
80
+ "gravy",
81
+ "chopped parsley",
82
+ ],
83
+ 'title': 'Breaded Pork Chops With Gravy'
84
+ }
85
+ ]
meta.py CHANGED
@@ -15,26 +15,40 @@ Chef Giovanni. Scheherazade is known for being more creative whereas Giovanni is
15
  """.strip()
16
  PROMPT_BOX = "Add custom ingredients here (separated by `,`): "
17
  STORY = """
18
- Hello everyone πŸ‘‹, I am **Chef Transformer**, the owner of this restaurant. I was made by a group of [NLP Engineers](
19
- https://huggingface.co/flax-community/t5-recipe-generation#team-members) to train my two prodigy recipe creators: **Chef Scheherazade** and **Chef Giovanni**. Both of my students participated in my rigorous culinary program, [T5 fine-tune training](https://huggingface.co/flax-community/t5-recipe-generation), to learn how to prepare exquisite cuisines from a wide variety of ingredients.
20
- I've never been more proud of my students -- both can produce exceptional dishes but I regard Scheherazade as being *creative* while Giovanni is *meticulous*. If you give each of them the same ingredients, they'll usually come up with something different.
21
- At the start of the program the chefs read cookbooks containing thousands of recipes of varying difficulties and from cultures all over the world. The NLP engineers helped guide the learning process so that the chefs could actually learn which ingredients work well together rather than just memorize recipes.
 
 
 
 
 
 
22
  I trained my chefs by asking them to generate a title, a list of ingredients (including amounts!), and a list of directions after giving them just a simple list of food items.
23
- ```text
 
 
24
  [Input]
25
  {food items*: separated by comma}
26
 
27
  [Targets]
28
- title: {TITLE} <section>
29
- ingredients: {INGREDIENTS: separated by <sep>} <section>
30
  directions: {DIRECTIONS: separated by <sep>}.
31
- ```
32
-
33
- *In the cookbooks (a.k.a [dataset](https://huggingface.co/datasets/recipe_nlg)), the food items were referred to as
34
- NER.*
35
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
- In the span of a week, my chefs went from spitting out nonsense to creating masterpieces. Their learning rate was exceptionally high and each batch of recipes was better than the last. In their final exam, they achieved [high scores](
38
- https://huggingface.co/flax-community/t5-recipe-generation#evaluation) πŸ’― in a standardized industry test and established this restaurant 🍲. Please tell your friends and family about us! We create each recipe with a smile on our faces πŸ€—
39
- Everyone at the restaurant is grateful for the generous support of Hugging Face and Google for hosting Flax Community week.
40
  """.strip()
 
15
  """.strip()
16
  PROMPT_BOX = "Add custom ingredients here (separated by `,`): "
17
  STORY = """
18
+ <div class="story-box">
19
+ <p>
20
+ Hello everyone πŸ‘‹, I am <strong>Chef Transformer</strong>,
21
+ the owner of this restaurant. I was made by a group of <a href="https://huggingface.co/flax-community/t5-recipe-generation#team-members">NLP Engineers</a> to train my two prodigy recipe creators: <strong>Chef Scheherazade</strong> and <strong>Chef Giovanni</strong>.
22
+ Both of my students participated in my rigorous culinary program, <a href="https://huggingface.co/flax-community/t5-recipe-generation">T5 fine-tune training</a>,
23
+ to learn how to prepare exquisite cuisines from a wide variety of ingredients.
24
+ I've never been more proud of my students -- both can produce exceptional dishes but I regard Scheherazade as being <em>creative</em> while Giovanni is <em>meticulous</em>.
25
+ If you give each of them the same ingredients, they'll usually come up with something different. <br /><br />
26
+ At the start of the program the chefs read cookbooks containing thousands of recipes of varying difficulties and from cultures all over the world.
27
+ The NLP engineers helped guide the learning process so that the chefs could actually learn which ingredients work well together rather than just memorize recipes.
28
  I trained my chefs by asking them to generate a title, a list of ingredients (including amounts!), and a list of directions after giving them just a simple list of food items.
29
+ </p>
30
+
31
+ <pre>
32
  [Input]
33
  {food items*: separated by comma}
34
 
35
  [Targets]
36
+ title: {TITLE} <section>
37
+ ingredients: {INGREDIENTS: separated by <sep>} <section>
38
  directions: {DIRECTIONS: separated by <sep>}.
39
+ </pre>
 
 
 
40
 
41
+ <p>
42
+ <em>In the cookbooks (a.k.a <a href="https://huggingface.co/datasets/recipe_nlg">dataset</a>), the food items were referred to as NER. </em>
43
+ </p>
44
+ <p>
45
+ In the span of a week, my chefs went from spitting out nonsense to creating masterpieces.
46
+ Their learning rate was exceptionally high and each batch of recipes was better than the last. <br />
47
+ In their final exam, they achieved <a href="https://huggingface.co/flax-community/t5-recipe-generation#evaluation">high scores</a> πŸ’― in a
48
+ standardized industry test and established this restaurant 🍲. Please tell your friends and family about us!
49
+ We create each recipe with a smile on our faces πŸ€— Everyone at the restaurant is grateful for the generous support of
50
+ HuggingFace and Google for hosting Flax Community week.
51
+ </p>
52
 
53
+ </div>
 
 
54
  """.strip()
requirements.txt CHANGED
@@ -1,4 +1,5 @@
1
  streamlit==0.84.1
2
  transformers
3
  torch
4
- Pillow
 
 
1
  streamlit==0.84.1
2
  transformers
3
  torch
4
+ Pillow
5
+ requests
utils.py CHANGED
@@ -1,15 +1,44 @@
1
  import streamlit as st
2
  import json
3
  from PIL import Image
 
 
 
4
 
5
 
6
- def load_image(image_path, image_resize=None):
7
  image = Image.open(image_path)
 
8
  if isinstance(image_resize, tuple):
9
- image.resize(image_resize)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  return image
11
 
12
 
 
 
 
 
 
 
 
13
  def load_text(text_path):
14
  text = ''
15
  with open(text_path) as f:
 
1
  import streamlit as st
2
  import json
3
  from PIL import Image
4
+ from io import BytesIO
5
+ import base64
6
+ import requests
7
 
8
 
9
+ def load_image_from_local(image_path, image_resize=None):
10
  image = Image.open(image_path)
11
+
12
  if isinstance(image_resize, tuple):
13
+ image = image.resize(image_resize)
14
+ return image
15
+
16
+
17
+ def load_image_from_url(image_url, rgba_mode=False, image_resize=None, default_image=None):
18
+ try:
19
+ image = Image.open(requests.get(image_url, stream=True).raw)
20
+
21
+ if rgba_mode:
22
+ image = image.convert("RGBA")
23
+
24
+ if isinstance(image_resize, tuple):
25
+ image = image.resize(image_resize)
26
+
27
+ except Exception as e:
28
+ image = None
29
+ if default_image:
30
+ image = load_image_from_local(default_image, image_resize=image_resize)
31
+
32
  return image
33
 
34
 
35
+ def image_to_base64(image_array):
36
+ buffered = BytesIO()
37
+ image_array.save(buffered, format="PNG")
38
+ image_b64 = base64.b64encode(buffered.getvalue()).decode("utf-8")
39
+ return f"data:image/png;base64, {image_b64}"
40
+
41
+
42
  def load_text(text_path):
43
  text = ''
44
  with open(text_path) as f: