codelion commited on
Commit
1aca0b8
·
verified ·
1 Parent(s): 2a952b2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +116 -67
app.py CHANGED
@@ -98,7 +98,7 @@ def generate_ideas(user_input):
98
 
99
  def generate_item(user_input, ideas, generate_video=False, max_retries=3):
100
  """
101
- Generate a single feed item (image and optionally video) using one of the ideas.
102
 
103
  Args:
104
  user_input (str): The user's input concept or idea.
@@ -107,9 +107,9 @@ def generate_item(user_input, ideas, generate_video=False, max_retries=3):
107
  max_retries (int): Maximum number of retries if image generation fails.
108
 
109
  Returns:
110
- dict: A dictionary with 'text' (str), 'image_base64' (str), 'video_base64_list' (list of str), and 'ideas' (list).
111
  """
112
- video_base64_list = []
113
 
114
  for attempt in range(max_retries):
115
  selected_idea = random.choice(ideas)
@@ -149,7 +149,7 @@ def generate_item(user_input, ideas, generate_video=False, max_retries=3):
149
  prompt=image_prompt,
150
  config=types.GenerateImagesConfig(
151
  aspect_ratio="9:16",
152
- number_of_images=1
153
  )
154
  )
155
  if imagen.generated_images and len(imagen.generated_images) > 0:
@@ -164,7 +164,7 @@ def generate_item(user_input, ideas, generate_video=False, max_retries=3):
164
  image.save(buffered, format="PNG")
165
  img_str = base64.b64encode(buffered.getvalue()).decode()
166
 
167
- # Generate video if enabled
168
  if generate_video:
169
  try:
170
  # Enhance the image prompt for video generation
@@ -179,12 +179,12 @@ def generate_item(user_input, ideas, generate_video=False, max_retries=3):
179
  image=generated_image.image,
180
  config=types.GenerateVideosConfig(
181
  aspect_ratio="9:16",
182
- number_of_videos=2,
183
  duration_seconds=8,
184
  negative_prompt="blurry, low quality, text, letters"
185
  )
186
  )
187
- # Wait for videos to generate
188
  while not operation.done:
189
  time.sleep(20)
190
  operation = client.operations.get(operation)
@@ -197,11 +197,12 @@ def generate_item(user_input, ideas, generate_video=False, max_retries=3):
197
  if not hasattr(operation.response, 'generated_videos') or operation.response.generated_videos is None:
198
  raise ValueError("Video generation operation failed: No generated_videos in response")
199
 
200
- # Iterate over generated videos
201
- for n, video in enumerate(operation.response.generated_videos, start=1):
 
202
  if video is None or not hasattr(video, 'video'):
203
- raise ValueError(f"Video {n} is invalid or missing video data")
204
- fname = f'with_image_input{n}.mp4'
205
  print(f"Generated video: {fname}")
206
  # Download the video and get the raw bytes
207
  video_data = client.files.download(file=video.video)
@@ -216,15 +217,16 @@ def generate_item(user_input, ideas, generate_video=False, max_retries=3):
216
  video_bytes = video_buffer.getvalue()
217
  # Encode the video bytes as base64
218
  video_base64 = base64.b64encode(video_bytes).decode()
219
- video_base64_list.append(video_base64)
 
220
  except Exception as e:
221
  print(f"Error generating video: {e}")
222
- video_base64_list = [] # Proceed without video if generation fails
223
 
224
  return {
225
  'text': text,
226
  'image_base64': img_str,
227
- 'video_base64_list': video_base64_list,
228
  'ideas': ideas
229
  }
230
  else:
@@ -238,7 +240,7 @@ def generate_item(user_input, ideas, generate_video=False, max_retries=3):
238
  return {
239
  'text': text,
240
  'image_base64': img_str,
241
- 'video_base64_list': [],
242
  'ideas': ideas
243
  }
244
  # Retry with new ideas
@@ -255,7 +257,7 @@ def generate_item(user_input, ideas, generate_video=False, max_retries=3):
255
  return {
256
  'text': text,
257
  'image_base64': img_str,
258
- 'video_base64_list': [],
259
  'ideas': ideas
260
  }
261
  # Retry with new ideas
@@ -290,7 +292,7 @@ def start_feed(user_input, generate_video, current_index, feed_items):
290
  current_index = 0
291
  share_links = generate_share_links(
292
  item['image_base64'],
293
- item['video_base64_list'],
294
  item['text']
295
  )
296
  except Exception as e:
@@ -307,7 +309,7 @@ def start_feed(user_input, generate_video, current_index, feed_items):
307
  margin: 0 auto;
308
  background-color: #000;
309
  height: 640px;
310
- border: 1px solid #333;
311
  border-radius: 10px;
312
  color: white;
313
  font-family: Arial, sans-serif;
@@ -350,7 +352,7 @@ def load_next(user_input, generate_video, current_index, feed_items):
350
  current_index = len(feed_items) - 1
351
  share_links = generate_share_links(
352
  feed_items[current_index]['image_base64'],
353
- feed_items[current_index]['video_base64_list'],
354
  feed_items[current_index]['text']
355
  )
356
  except Exception as e:
@@ -398,18 +400,18 @@ def load_previous(user_input, generate_video, current_index, feed_items):
398
  html_content = generate_html(feed_items, False, current_index, user_input, False)
399
  share_links = generate_share_links(
400
  feed_items[current_index]['image_base64'],
401
- feed_items[current_index]['video_base64_list'],
402
  feed_items[current_index]['text']
403
  )
404
  return user_input, current_index, feed_items, html_content, share_links, False
405
 
406
- def generate_share_links(image_base64, video_base64_list, caption):
407
  """
408
  Generate share links for social media platforms with download links for image and video.
409
 
410
  Args:
411
  image_base64 (str): The base64-encoded image data.
412
- video_base64_list (list): List of base64-encoded video data.
413
  caption (str): The caption to share.
414
 
415
  Returns:
@@ -418,89 +420,136 @@ def generate_share_links(image_base64, video_base64_list, caption):
418
  image_data_url = f"data:image/png;base64,{image_base64}"
419
  encoded_caption = urllib.parse.quote(caption)
420
 
421
- # Generate download links for image and videos
422
  download_links = f"""
423
- <p style="text-align: center;">Download and attach the image/video to share:</p>
424
- <a href="{image_data_url}" download="feed_item.png" style="
425
- background-color: #4CAF50;
426
- color: white;
427
- padding: 5px 10px;
428
- border-radius: 5px;
429
- text-decoration: none;
430
- margin: 5px;
431
- ">Download Image</a>
 
 
 
432
  """
433
- for i, video_base64 in enumerate(video_base64_list):
434
  video_data_url = f"data:video/mp4;base64,{video_base64}"
435
  download_links += f"""
436
- <a href="{video_data_url}" download="feed_video_{i}.mp4" style="
437
  background-color: #4CAF50;
438
  color: white;
439
- padding: 5px 10px;
440
  border-radius: 5px;
441
  text-decoration: none;
442
- margin: 5px;
443
- ">Download Video {i+1}</a>
 
 
444
  """
 
445
 
446
- # Generate share links using only the caption
447
- share_links = f"""
448
- <div style="
449
- display: flex;
450
- flex-direction: column;
451
- align-items: center;
452
- gap: 10px;
453
- margin-top: 10px;
454
- color: white;
455
- font-family: Arial, sans-serif;
456
- ">
457
- {download_links}
458
  <div style="
459
  display: flex;
460
  flex-wrap: wrap;
461
  justify-content: center;
462
- gap: 10px;
463
- margin-top: 10px;
464
  ">
465
  <a href="https://www.tiktok.com/upload?caption={caption}" target="_blank" style="
466
  background-color: #00f2ea;
467
  color: #000;
468
- padding: 5px 10px;
469
  border-radius: 5px;
470
  text-decoration: none;
471
- ">Share on TikTok</a>
 
 
 
472
  <a href="https://www.instagram.com/?caption={caption}" target="_blank" style="
473
  background-color: #e1306c;
474
  color: white;
475
- padding: 5px 10px;
476
  border-radius: 5px;
477
  text-decoration: none;
478
- ">Share on Instagram</a>
 
 
 
479
  <a href="https://www.facebook.com/sharer/sharer.php?quote={caption}" target="_blank" style="
480
  background-color: #4267b2;
481
  color: white;
482
- padding: 5px 10px;
483
  border-radius: 5px;
484
  text-decoration: none;
485
- ">Share on Facebook</a>
 
 
 
486
  <a href="https://twitter.com/intent/tweet?text={caption}" target="_blank" style="
487
  background-color: #1da1f2;
488
  color: white;
489
- padding: 5px 10px;
490
  border-radius: 5px;
491
  text-decoration: none;
492
- ">Share on X</a>
 
 
 
493
  <a href="https://pinterest.com/pin/create/button/?description={caption}" target="_blank" style="
494
  background-color: #bd081c;
495
  color: white;
496
- padding: 5px 10px;
497
  border-radius: 5px;
498
  text-decoration: none;
499
- ">Share on Pinterest</a>
 
 
 
500
  </div>
501
- </div>
502
  """
503
- return share_links
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
504
 
505
  def generate_html(feed_items, scroll_to_latest=False, current_index=0, user_input="", is_loading=False):
506
  """
@@ -508,7 +557,7 @@ def generate_html(feed_items, scroll_to_latest=False, current_index=0, user_inpu
508
  Displays a video if available, otherwise falls back to the image.
509
 
510
  Args:
511
- feed_items (list): List of dictionaries containing 'text', 'image_base64', and 'video_base64_list'.
512
  scroll_to_latest (bool): Whether to auto-scroll to the latest item (not used here).
513
  current_index (int): The index of the item to display.
514
  user_input (str): The user's input concept or idea for loading messages.
@@ -606,8 +655,8 @@ def generate_html(feed_items, scroll_to_latest=False, current_index=0, user_inpu
606
  """
607
 
608
  item = feed_items[current_index]
609
- # Check if there are videos to display; if so, show the first video
610
- if item['video_base64_list']:
611
  media_element = f"""
612
  <video id="feed-video" controls style="
613
  width: 100%;
@@ -618,7 +667,7 @@ def generate_html(feed_items, scroll_to_latest=False, current_index=0, user_inpu
618
  left: 0;
619
  z-index: 1;
620
  ">
621
- <source src="data:video/mp4;base64,{item['video_base64_list'][0]}" type="video/mp4">
622
  Your browser does not support the video tag.
623
  </video>
624
  """
 
98
 
99
  def generate_item(user_input, ideas, generate_video=False, max_retries=3):
100
  """
101
+ Generate a single feed item (image and optionally one video) using one of the ideas.
102
 
103
  Args:
104
  user_input (str): The user's input concept or idea.
 
107
  max_retries (int): Maximum number of retries if image generation fails.
108
 
109
  Returns:
110
+ dict: A dictionary with 'text' (str), 'image_base64' (str), 'video_base64' (str or None), and 'ideas' (list).
111
  """
112
+ video_base64 = None # Changed from a list to a single value (string or None)
113
 
114
  for attempt in range(max_retries):
115
  selected_idea = random.choice(ideas)
 
149
  prompt=image_prompt,
150
  config=types.GenerateImagesConfig(
151
  aspect_ratio="9:16",
152
+ number_of_images=1 # Already set to 1 image
153
  )
154
  )
155
  if imagen.generated_images and len(imagen.generated_images) > 0:
 
164
  image.save(buffered, format="PNG")
165
  img_str = base64.b64encode(buffered.getvalue()).decode()
166
 
167
+ # Generate video if enabled (only 1 video)
168
  if generate_video:
169
  try:
170
  # Enhance the image prompt for video generation
 
179
  image=generated_image.image,
180
  config=types.GenerateVideosConfig(
181
  aspect_ratio="9:16",
182
+ number_of_videos=1, # Changed to 1 video
183
  duration_seconds=8,
184
  negative_prompt="blurry, low quality, text, letters"
185
  )
186
  )
187
+ # Wait for video to generate
188
  while not operation.done:
189
  time.sleep(20)
190
  operation = client.operations.get(operation)
 
197
  if not hasattr(operation.response, 'generated_videos') or operation.response.generated_videos is None:
198
  raise ValueError("Video generation operation failed: No generated_videos in response")
199
 
200
+ # Process the single generated video
201
+ if len(operation.response.generated_videos) > 0:
202
+ video = operation.response.generated_videos[0]
203
  if video is None or not hasattr(video, 'video'):
204
+ raise ValueError("Video is invalid or missing video data")
205
+ fname = 'with_image_input.mp4' # Removed numbering since only 1 video
206
  print(f"Generated video: {fname}")
207
  # Download the video and get the raw bytes
208
  video_data = client.files.download(file=video.video)
 
217
  video_bytes = video_buffer.getvalue()
218
  # Encode the video bytes as base64
219
  video_base64 = base64.b64encode(video_bytes).decode()
220
+ else:
221
+ raise ValueError("No video was generated")
222
  except Exception as e:
223
  print(f"Error generating video: {e}")
224
+ video_base64 = None # Proceed without video if generation fails
225
 
226
  return {
227
  'text': text,
228
  'image_base64': img_str,
229
+ 'video_base64': video_base64, # Now a single string or None
230
  'ideas': ideas
231
  }
232
  else:
 
240
  return {
241
  'text': text,
242
  'image_base64': img_str,
243
+ 'video_base64': None,
244
  'ideas': ideas
245
  }
246
  # Retry with new ideas
 
257
  return {
258
  'text': text,
259
  'image_base64': img_str,
260
+ 'video_base64': None,
261
  'ideas': ideas
262
  }
263
  # Retry with new ideas
 
292
  current_index = 0
293
  share_links = generate_share_links(
294
  item['image_base64'],
295
+ item['video_base64'],
296
  item['text']
297
  )
298
  except Exception as e:
 
309
  margin: 0 auto;
310
  background-color: #000;
311
  height: 640px;
312
+ border: 1px solidBundled #333;
313
  border-radius: 10px;
314
  color: white;
315
  font-family: Arial, sans-serif;
 
352
  current_index = len(feed_items) - 1
353
  share_links = generate_share_links(
354
  feed_items[current_index]['image_base64'],
355
+ feed_items[current_index]['video_base64'],
356
  feed_items[current_index]['text']
357
  )
358
  except Exception as e:
 
400
  html_content = generate_html(feed_items, False, current_index, user_input, False)
401
  share_links = generate_share_links(
402
  feed_items[current_index]['image_base64'],
403
+ feed_items[current_index]['video_base64'],
404
  feed_items[current_index]['text']
405
  )
406
  return user_input, current_index, feed_items, html_content, share_links, False
407
 
408
+ def generate_share_links(image_base64, video_base64, caption):
409
  """
410
  Generate share links for social media platforms with download links for image and video.
411
 
412
  Args:
413
  image_base64 (str): The base64-encoded image data.
414
+ video_base64 (str or None): The base64-encoded video data (single video).
415
  caption (str): The caption to share.
416
 
417
  Returns:
 
420
  image_data_url = f"data:image/png;base64,{image_base64}"
421
  encoded_caption = urllib.parse.quote(caption)
422
 
423
+ # Generate download links for image and video (if available)
424
  download_links = f"""
425
+ <p style="text-align: center; margin-bottom: 10px;">Download the media to share:</p>
426
+ <div style="display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-bottom: 15px;">
427
+ <a href="{image_data_url}" download="feed_item.png" style="
428
+ background-color: #4CAF50;
429
+ color: white;
430
+ padding: 8px 16px;
431
+ border-radius: 5px;
432
+ text-decoration: none;
433
+ font-size: 14px;
434
+ font-weight: bold;
435
+ transition: background-color 0.3s;
436
+ " onmouseover="this.style.backgroundColor='#45a049'" onmouseout="this.style.backgroundColor='#4CAF50'">Download Image</a>
437
  """
438
+ if video_base64: # Only include video download link if a video exists
439
  video_data_url = f"data:video/mp4;base64,{video_base64}"
440
  download_links += f"""
441
+ <a href="{video_data_url}" download="feed_video.mp4" style="
442
  background-color: #4CAF50;
443
  color: white;
444
+ padding: 8px 16px;
445
  border-radius: 5px;
446
  text-decoration: none;
447
+ font-size: 14px;
448
+ font-weight: bold;
449
+ transition: background-color 0.3s;
450
+ " onmouseover="this.style.backgroundColor='#45a049'" onmouseout="this.style.backgroundColor='#4CAF50'">Download Video</a>
451
  """
452
+ download_links += "</div>"
453
 
454
+ # Generate share links for social media platforms
455
+ share_links = """
 
 
 
 
 
 
 
 
 
 
456
  <div style="
457
  display: flex;
458
  flex-wrap: wrap;
459
  justify-content: center;
460
+ gap: 8px;
461
+ margin-bottom: 15px;
462
  ">
463
  <a href="https://www.tiktok.com/upload?caption={caption}" target="_blank" style="
464
  background-color: #00f2ea;
465
  color: #000;
466
+ padding: 8px 16px;
467
  border-radius: 5px;
468
  text-decoration: none;
469
+ font-size: 14px;
470
+ font-weight: bold;
471
+ transition: background-color 0.3s;
472
+ " onmouseover="this.style.backgroundColor='#00d9d1'" onmouseout="this.style.backgroundColor='#00f2ea'">Share on TikTok</a>
473
  <a href="https://www.instagram.com/?caption={caption}" target="_blank" style="
474
  background-color: #e1306c;
475
  color: white;
476
+ padding: 8px 16px;
477
  border-radius: 5px;
478
  text-decoration: none;
479
+ font-size: 14px;
480
+ font-weight: bold;
481
+ transition: background-color 0.3s;
482
+ " onmouseover="this.style.backgroundColor='#c72b5e'" onmouseout="this.style.backgroundColor='#e1306c'">Share on Instagram</a>
483
  <a href="https://www.facebook.com/sharer/sharer.php?quote={caption}" target="_blank" style="
484
  background-color: #4267b2;
485
  color: white;
486
+ padding: 8px 16px;
487
  border-radius: 5px;
488
  text-decoration: none;
489
+ font-size: 14px;
490
+ font-weight: bold;
491
+ transition: background-color 0.3s;
492
+ " onmouseover="this.style.backgroundColor='#395a9d'" onmouseout="this.style.backgroundColor='#4267b2'">Share on Facebook</a>
493
  <a href="https://twitter.com/intent/tweet?text={caption}" target="_blank" style="
494
  background-color: #1da1f2;
495
  color: white;
496
+ padding: 8px 16px;
497
  border-radius: 5px;
498
  text-decoration: none;
499
+ font-size: 14px;
500
+ font-weight: bold;
501
+ transition: background-color 0.3s;
502
+ " onmouseover="this.style.backgroundColor='#1a91da'" onmouseout="this.style.backgroundColor='#1da1f2'">Share on X</a>
503
  <a href="https://pinterest.com/pin/create/button/?description={caption}" target="_blank" style="
504
  background-color: #bd081c;
505
  color: white;
506
+ padding: 8px 16px;
507
  border-radius: 5px;
508
  text-decoration: none;
509
+ font-size: 14px;
510
+ font-weight: bold;
511
+ transition: background-color 0.3s;
512
+ " onmouseover="this.style.backgroundColor='#a30718'" onmouseout="this.style.backgroundColor='#bd081c'">Share on Pinterest</a>
513
  </div>
 
514
  """
515
+
516
+ # Add YouTube Shorts share button if a video is available
517
+ youtube_share = ""
518
+ if video_base64: # Only show YouTube Shorts share button if a video is generated
519
+ youtube_share = f"""
520
+ <div style="
521
+ display: flex;
522
+ justify-content: center;
523
+ margin-top: 10px;
524
+ ">
525
+ <a href="https://www.youtube.com/upload?description={caption}" target="_blank" style="
526
+ background-color: #ff0000;
527
+ color: white;
528
+ padding: 8px 16px;
529
+ border-radius: 5px;
530
+ text-decoration: none;
531
+ font-size: 14px;
532
+ font-weight: bold;
533
+ transition: background-color 0.3s;
534
+ " onmouseover="this.style.backgroundColor='#e60000'" onmouseout="this.style.backgroundColor='#ff0000'">Share to YouTube as a Short</a>
535
+ </div>
536
+ """
537
+
538
+ return f"""
539
+ <div style="
540
+ display: flex;
541
+ flex-direction: column;
542
+ align-items: center;
543
+ gap: 10px;
544
+ margin-top: 10px;
545
+ color: white;
546
+ font-family: Arial, sans-serif;
547
+ ">
548
+ {download_links}
549
+ {share_links}
550
+ {youtube_share}
551
+ </div>
552
+ """.format(caption=encoded_caption)
553
 
554
  def generate_html(feed_items, scroll_to_latest=False, current_index=0, user_input="", is_loading=False):
555
  """
 
557
  Displays a video if available, otherwise falls back to the image.
558
 
559
  Args:
560
+ feed_items (list): List of dictionaries containing 'text', 'image_base64', and 'video_base64'.
561
  scroll_to_latest (bool): Whether to auto-scroll to the latest item (not used here).
562
  current_index (int): The index of the item to display.
563
  user_input (str): The user's input concept or idea for loading messages.
 
655
  """
656
 
657
  item = feed_items[current_index]
658
+ # Check if there is a video to display
659
+ if item['video_base64']:
660
  media_element = f"""
661
  <video id="feed-video" controls style="
662
  width: 100%;
 
667
  left: 0;
668
  z-index: 1;
669
  ">
670
+ <source src="data:video/mp4;base64,{item['video_base64']}" type="video/mp4">
671
  Your browser does not support the video tag.
672
  </video>
673
  """