codelion commited on
Commit
7215045
·
verified ·
1 Parent(s): d0a3276

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +127 -41
app.py CHANGED
@@ -8,6 +8,7 @@ import os
8
  import json
9
  import random
10
  import urllib.parse
 
11
 
12
  # Initialize the Google Generative AI client with the API key from environment variables
13
  try:
@@ -74,18 +75,21 @@ def generate_ideas(tag):
74
  f"An action-packed {tag} scene with dynamic colors"
75
  ]
76
 
77
- def generate_item(tag, ideas, max_retries=3):
78
  """
79
- Generate a single feed item using one of the ideas, retrying if image generation fails.
80
 
81
  Args:
82
  tag (str): The tag to base the content on.
83
  ideas (list): List of ideas to choose from.
 
84
  max_retries (int): Maximum number of retries if image generation fails.
85
 
86
  Returns:
87
- dict: A dictionary with 'text' (str), 'image_base64' (str), and 'ideas' (list).
88
  """
 
 
89
  for attempt in range(max_retries):
90
  selected_idea = random.choice(ideas)
91
  prompt = f"""
@@ -119,26 +123,61 @@ def generate_item(tag, ideas, max_retries=3):
119
 
120
  # Attempt to generate the image
121
  try:
122
- # Pass parameters directly or adjust based on the correct API schema
123
- image_response = client.models.generate_images(
124
  model='imagen-3.0-generate-002',
125
  prompt=image_prompt,
126
- number_of_images=1, # Pass directly instead of in config
127
- aspect_ratio="9:16",
128
- person_generation="DONT_ALLOW"
 
129
  )
130
- if image_response.generated_images and len(image_response.generated_images) > 0:
131
- generated_image = image_response.generated_images[0]
132
  image = Image.open(BytesIO(generated_image.image.image_bytes))
133
  # Ensure the image matches the desired aspect ratio (9:16 = 0.5625)
134
  target_width = 360
135
  target_height = int(target_width / 9 * 16) # 9:16 aspect ratio
136
  image = image.resize((target_width, target_height), Image.LANCZOS)
137
- # Successfully generated an image, proceed
138
  buffered = BytesIO()
139
  image.save(buffered, format="PNG")
140
  img_str = base64.b64encode(buffered.getvalue()).decode()
141
- return {'text': text, 'image_base64': img_str, 'ideas': ideas}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
  else:
143
  print(f"Image generation failed (attempt {attempt + 1}): No images returned")
144
  if attempt == max_retries - 1:
@@ -147,7 +186,12 @@ def generate_item(tag, ideas, max_retries=3):
147
  buffered = BytesIO()
148
  image.save(buffered, format="PNG")
149
  img_str = base64.b64encode(buffered.getvalue()).decode()
150
- return {'text': text, 'image_base64': img_str, 'ideas': ideas}
 
 
 
 
 
151
  # Retry with new ideas
152
  ideas = generate_ideas(tag)
153
  continue
@@ -159,17 +203,23 @@ def generate_item(tag, ideas, max_retries=3):
159
  buffered = BytesIO()
160
  image.save(buffered, format="PNG")
161
  img_str = base64.b64encode(buffered.getvalue()).decode()
162
- return {'text': text, 'image_base64': img_str, 'ideas': ideas}
 
 
 
 
 
163
  # Retry with new ideas
164
  ideas = generate_ideas(tag)
165
  continue
166
 
167
- def start_feed(tag, current_index, feed_items):
168
  """
169
  Start or update the feed based on the tag.
170
 
171
  Args:
172
  tag (str): The tag to generate content for.
 
173
  current_index (int): The current item index.
174
  feed_items (list): The current list of feed items.
175
 
@@ -186,10 +236,14 @@ def start_feed(tag, current_index, feed_items):
186
 
187
  try:
188
  ideas = generate_ideas(tag)
189
- item = generate_item(tag, ideas)
190
  feed_items = [item]
191
  current_index = 0
192
- share_links = generate_share_links(item['image_base64'], item['text'])
 
 
 
 
193
  except Exception as e:
194
  print(f"Error in start_feed: {e}")
195
  feed_items = []
@@ -220,12 +274,13 @@ def start_feed(tag, current_index, feed_items):
220
  html_content = generate_html(feed_items, False, current_index, tag, is_loading)
221
  return tag, current_index, feed_items, html_content, share_links, is_loading
222
 
223
- def load_next(tag, current_index, feed_items):
224
  """
225
  Load the next item in the feed.
226
 
227
  Args:
228
  tag (str): The tag to generate content for.
 
229
  current_index (int): The current item index.
230
  feed_items (list): The current list of feed items.
231
 
@@ -241,10 +296,14 @@ def load_next(tag, current_index, feed_items):
241
  current_index += 1
242
  else:
243
  ideas = feed_items[-1]['ideas'] if feed_items else generate_ideas(tag)
244
- new_item = generate_item(tag, ideas)
245
  feed_items.append(new_item)
246
  current_index = len(feed_items) - 1
247
- share_links = generate_share_links(feed_items[current_index]['image_base64'], feed_items[current_index]['text'])
 
 
 
 
248
  except Exception as e:
249
  print(f"Error in load_next: {e}")
250
  html_content = """
@@ -272,12 +331,13 @@ def load_next(tag, current_index, feed_items):
272
  html_content = generate_html(feed_items, False, current_index, tag, is_loading)
273
  return tag, current_index, feed_items, html_content, share_links, is_loading
274
 
275
- def load_previous(tag, current_index, feed_items):
276
  """
277
  Load the previous item in the feed.
278
 
279
  Args:
280
  tag (str): The tag to generate content for.
 
281
  current_index (int): The current item index.
282
  feed_items (list): The current list of feed items.
283
 
@@ -287,16 +347,21 @@ def load_previous(tag, current_index, feed_items):
287
  if current_index > 0:
288
  current_index -= 1
289
  html_content = generate_html(feed_items, False, current_index, tag, False)
290
- share_links = generate_share_links(feed_items[current_index]['image_base64'], feed_items[current_index]['text'])
 
 
 
 
291
  return tag, current_index, feed_items, html_content, share_links, False
292
 
293
- def generate_share_links(image_base64, caption):
294
  """
295
- Generate share links for social media platforms with a download link.
296
 
297
  Args:
298
  image_base64 (str): The base64-encoded image data.
299
- caption (str): The caption to share with the image.
 
300
 
301
  Returns:
302
  str: HTML string with share links and download instructions.
@@ -304,8 +369,33 @@ def generate_share_links(image_base64, caption):
304
  image_data_url = f"data:image/png;base64,{image_base64}"
305
  encoded_caption = urllib.parse.quote(caption)
306
 
307
- # Generate share links with instructions to download the image
308
- share_links = """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
309
  <div style="
310
  display: flex;
311
  flex-direction: column;
@@ -315,14 +405,7 @@ def generate_share_links(image_base64, caption):
315
  color: white;
316
  font-family: Arial, sans-serif;
317
  ">
318
- <p style="text-align: center;">To share, download the image and upload it to your platform:</p>
319
- <a href="{image_url}" download="feed_item.png" style="
320
- background-color: #4CAF50;
321
- color: white;
322
- padding: 5px 10px;
323
- border-radius: 5px;
324
- text-decoration: none;
325
- ">Download Image</a>
326
  <div style="
327
  display: flex;
328
  flex-wrap: wrap;
@@ -367,8 +450,7 @@ def generate_share_links(image_base64, caption):
367
  ">Share on Pinterest</a>
368
  </div>
369
  </div>
370
- """.format(image_url=image_data_url, caption=encoded_caption)
371
-
372
  return share_links
373
 
374
  def generate_html(feed_items, scroll_to_latest=False, current_index=0, tag="", is_loading=False):
@@ -542,7 +624,7 @@ with gr.Blocks(
542
  css="""
543
  body { background-color: #000; color: #fff; font-family: Arial, sans-serif; }
544
  .gradio-container { max-width: 400px; margin: 0 auto; padding: 10px; }
545
- input, select, button { border-radius: 5px; background-color: #222; color: #fff; border: 1px solid #444; }
546
  button { background-color: #ff2d55; border: none; }
547
  button:hover { background-color: #e0264b; }
548
  .gr-button { width: 100%; margin-top: 10px; }
@@ -566,6 +648,10 @@ with gr.Blocks(
566
  placeholder="e.g., sushi adventure, neon tech",
567
  submit_btn=False
568
  )
 
 
 
 
569
  magic_button = gr.Button("✨ Generate Next Item", elem_classes="gr-button")
570
 
571
  # Output display
@@ -576,14 +662,14 @@ with gr.Blocks(
576
  # Handle Enter keypress in the concept input
577
  tag_input.submit(
578
  fn=start_feed,
579
- inputs=[tag_input, current_index, feed_items],
580
  outputs=[current_tag, current_index, feed_items, feed_html, share_html, is_loading]
581
  )
582
 
583
  # Handle magic button click to generate next item
584
  magic_button.click(
585
  fn=load_next,
586
- inputs=[current_tag, current_index, feed_items],
587
  outputs=[current_tag, current_index, feed_items, feed_html, share_html, is_loading]
588
  )
589
 
@@ -593,7 +679,7 @@ with gr.Blocks(
593
  # Handle click to go to previous item
594
  previous_button.click(
595
  fn=load_previous,
596
- inputs=[current_tag, current_index, feed_items],
597
  outputs=[current_tag, current_index, feed_items, feed_html, share_html, is_loading]
598
  )
599
 
 
8
  import json
9
  import random
10
  import urllib.parse
11
+ import time
12
 
13
  # Initialize the Google Generative AI client with the API key from environment variables
14
  try:
 
75
  f"An action-packed {tag} scene with dynamic colors"
76
  ]
77
 
78
+ def generate_item(tag, ideas, generate_video=False, max_retries=3):
79
  """
80
+ Generate a single feed item (image and optionally video) using one of the ideas.
81
 
82
  Args:
83
  tag (str): The tag to base the content on.
84
  ideas (list): List of ideas to choose from.
85
+ generate_video (bool): Whether to generate a video from the image.
86
  max_retries (int): Maximum number of retries if image generation fails.
87
 
88
  Returns:
89
+ dict: A dictionary with 'text' (str), 'image_base64' (str), 'video_base64_list' (list of str), and 'ideas' (list).
90
  """
91
+ video_base64_list = []
92
+
93
  for attempt in range(max_retries):
94
  selected_idea = random.choice(ideas)
95
  prompt = f"""
 
123
 
124
  # Attempt to generate the image
125
  try:
126
+ imagen = client.models.generate_images(
 
127
  model='imagen-3.0-generate-002',
128
  prompt=image_prompt,
129
+ config=types.GenerateImagesConfig(
130
+ aspect_ratio="9:16",
131
+ number_of_images=1
132
+ )
133
  )
134
+ if imagen.generated_images and len(imagen.generated_images) > 0:
135
+ generated_image = imagen.generated_images[0]
136
  image = Image.open(BytesIO(generated_image.image.image_bytes))
137
  # Ensure the image matches the desired aspect ratio (9:16 = 0.5625)
138
  target_width = 360
139
  target_height = int(target_width / 9 * 16) # 9:16 aspect ratio
140
  image = image.resize((target_width, target_height), Image.LANCZOS)
141
+ # Convert image to base64
142
  buffered = BytesIO()
143
  image.save(buffered, format="PNG")
144
  img_str = base64.b64encode(buffered.getvalue()).decode()
145
+
146
+ # Generate video if enabled
147
+ if generate_video:
148
+ try:
149
+ operation = client.models.generate_videos(
150
+ model="veo-2.0-generate-001",
151
+ prompt=image_prompt,
152
+ image=generated_image.image,
153
+ config=types.GenerateVideosConfig(
154
+ aspect_ratio="9:16",
155
+ number_of_videos=2
156
+ )
157
+ )
158
+ # Wait for videos to generate
159
+ while not operation.done:
160
+ time.sleep(20)
161
+ operation = client.operations.get(operation)
162
+
163
+ for n, video in enumerate(operation.response.generated_videos):
164
+ fname = f'with_image_input{n}.mp4'
165
+ print(f"Generated video: {fname}")
166
+ client.files.download(file=video.video)
167
+ video_buffer = BytesIO()
168
+ video.video.save(video_buffer)
169
+ video_base64 = base64.b64encode(video_buffer.getvalue()).decode()
170
+ video_base64_list.append(video_base64)
171
+ except Exception as e:
172
+ print(f"Error generating video: {e}")
173
+ video_base64_list = [] # Proceed without video if generation fails
174
+
175
+ return {
176
+ 'text': text,
177
+ 'image_base64': img_str,
178
+ 'video_base64_list': video_base64_list,
179
+ 'ideas': ideas
180
+ }
181
  else:
182
  print(f"Image generation failed (attempt {attempt + 1}): No images returned")
183
  if attempt == max_retries - 1:
 
186
  buffered = BytesIO()
187
  image.save(buffered, format="PNG")
188
  img_str = base64.b64encode(buffered.getvalue()).decode()
189
+ return {
190
+ 'text': text,
191
+ 'image_base64': img_str,
192
+ 'video_base64_list': [],
193
+ 'ideas': ideas
194
+ }
195
  # Retry with new ideas
196
  ideas = generate_ideas(tag)
197
  continue
 
203
  buffered = BytesIO()
204
  image.save(buffered, format="PNG")
205
  img_str = base64.b64encode(buffered.getvalue()).decode()
206
+ return {
207
+ 'text': text,
208
+ 'image_base64': img_str,
209
+ 'video_base64_list': [],
210
+ 'ideas': ideas
211
+ }
212
  # Retry with new ideas
213
  ideas = generate_ideas(tag)
214
  continue
215
 
216
+ def start_feed(tag, generate_video, current_index, feed_items):
217
  """
218
  Start or update the feed based on the tag.
219
 
220
  Args:
221
  tag (str): The tag to generate content for.
222
+ generate_video (bool): Whether to generate a video.
223
  current_index (int): The current item index.
224
  feed_items (list): The current list of feed items.
225
 
 
236
 
237
  try:
238
  ideas = generate_ideas(tag)
239
+ item = generate_item(tag, ideas, generate_video=generate_video)
240
  feed_items = [item]
241
  current_index = 0
242
+ share_links = generate_share_links(
243
+ item['image_base64'],
244
+ item['video_base64_list'],
245
+ item['text']
246
+ )
247
  except Exception as e:
248
  print(f"Error in start_feed: {e}")
249
  feed_items = []
 
274
  html_content = generate_html(feed_items, False, current_index, tag, is_loading)
275
  return tag, current_index, feed_items, html_content, share_links, is_loading
276
 
277
+ def load_next(tag, generate_video, current_index, feed_items):
278
  """
279
  Load the next item in the feed.
280
 
281
  Args:
282
  tag (str): The tag to generate content for.
283
+ generate_video (bool): Whether to generate a video.
284
  current_index (int): The current item index.
285
  feed_items (list): The current list of feed items.
286
 
 
296
  current_index += 1
297
  else:
298
  ideas = feed_items[-1]['ideas'] if feed_items else generate_ideas(tag)
299
+ new_item = generate_item(tag, ideas, generate_video=generate_video)
300
  feed_items.append(new_item)
301
  current_index = len(feed_items) - 1
302
+ share_links = generate_share_links(
303
+ feed_items[current_index]['image_base64'],
304
+ IRfeed_items[current_index]['video_base64_list'],
305
+ feed_items[current_index]['text']
306
+ )
307
  except Exception as e:
308
  print(f"Error in load_next: {e}")
309
  html_content = """
 
331
  html_content = generate_html(feed_items, False, current_index, tag, is_loading)
332
  return tag, current_index, feed_items, html_content, share_links, is_loading
333
 
334
+ def load_previous(tag, generate_video, current_index, feed_items):
335
  """
336
  Load the previous item in the feed.
337
 
338
  Args:
339
  tag (str): The tag to generate content for.
340
+ generate_video (bool): Whether to generate a video (not used here).
341
  current_index (int): The current item index.
342
  feed_items (list): The current list of feed items.
343
 
 
347
  if current_index > 0:
348
  current_index -= 1
349
  html_content = generate_html(feed_items, False, current_index, tag, False)
350
+ share_links = generate_share_links(
351
+ feed_items[current_index]['image_base64'],
352
+ feed_items[current_index]['video_base64_list'],
353
+ feed_items[current_index]['text']
354
+ )
355
  return tag, current_index, feed_items, html_content, share_links, False
356
 
357
+ def generate_share_links(image_base64, video_base64_list, caption):
358
  """
359
+ Generate share links for social media platforms with download links for image and video.
360
 
361
  Args:
362
  image_base64 (str): The base64-encoded image data.
363
+ video_base64_list (list): List of base64-encoded video data.
364
+ caption (str): The caption to share.
365
 
366
  Returns:
367
  str: HTML string with share links and download instructions.
 
369
  image_data_url = f"data:image/png;base64,{image_base64}"
370
  encoded_caption = urllib.parse.quote(caption)
371
 
372
+ # Generate download links for image and videos
373
+ download_links = f"""
374
+ <p style="text-align: center;">Download and attach the image/video to share:</p>
375
+ <a href="{image_data_url}" download="feed_item.png" style="
376
+ background-color: #4CAF50;
377
+ color: white;
378
+ padding: 5px 10px;
379
+ border-radius: 5px;
380
+ text-decoration: none;
381
+ margin: 5px;
382
+ ">Download Image</a>
383
+ """
384
+ for i, video_base64 in enumerate(video_base64_list):
385
+ video_data_url = f"data:video/mp4;base64,{video_base64}"
386
+ download_links += f"""
387
+ <a href="{video_data_url}" download="feed_video_{i}.mp4" style="
388
+ background-color: #4CAF50;
389
+ color: white;
390
+ padding: 5px 10px;
391
+ border-radius: 5px;
392
+ text-decoration: none;
393
+ margin: 5px;
394
+ ">Download Video {i+1}</a>
395
+ """
396
+
397
+ # Generate share links using only the caption
398
+ share_links = f"""
399
  <div style="
400
  display: flex;
401
  flex-direction: column;
 
405
  color: white;
406
  font-family: Arial, sans-serif;
407
  ">
408
+ {download_links}
 
 
 
 
 
 
 
409
  <div style="
410
  display: flex;
411
  flex-wrap: wrap;
 
450
  ">Share on Pinterest</a>
451
  </div>
452
  </div>
453
+ """
 
454
  return share_links
455
 
456
  def generate_html(feed_items, scroll_to_latest=False, current_index=0, tag="", is_loading=False):
 
624
  css="""
625
  body { background-color: #000; color: #fff; font-family: Arial, sans-serif; }
626
  .gradio-container { max-width: 400px; margin: 0 auto; padding: 10px; }
627
+ input, select, button, .gr-checkbox { border-radius: 5px; background-color: #222; color: #fff; border: 1px solid #444; }
628
  button { background-color: #ff2d55; border: none; }
629
  button:hover { background-color: #e0264b; }
630
  .gr-button { width: 100%; margin-top: 10px; }
 
648
  placeholder="e.g., sushi adventure, neon tech",
649
  submit_btn=False
650
  )
651
+ generate_video_checkbox = gr.Checkbox(
652
+ label="Generate Video (may take longer)",
653
+ value=False
654
+ )
655
  magic_button = gr.Button("✨ Generate Next Item", elem_classes="gr-button")
656
 
657
  # Output display
 
662
  # Handle Enter keypress in the concept input
663
  tag_input.submit(
664
  fn=start_feed,
665
+ inputs=[tag_input, generate_video_checkbox, current_index, feed_items],
666
  outputs=[current_tag, current_index, feed_items, feed_html, share_html, is_loading]
667
  )
668
 
669
  # Handle magic button click to generate next item
670
  magic_button.click(
671
  fn=load_next,
672
+ inputs=[current_tag, generate_video_checkbox, current_index, feed_items],
673
  outputs=[current_tag, current_index, feed_items, feed_html, share_html, is_loading]
674
  )
675
 
 
679
  # Handle click to go to previous item
680
  previous_button.click(
681
  fn=load_previous,
682
+ inputs=[current_tag, generate_video_checkbox, current_index, feed_items],
683
  outputs=[current_tag, current_index, feed_items, feed_html, share_html, is_loading]
684
  )
685