Update app.py
Browse files
app.py
CHANGED
@@ -17,7 +17,7 @@ except KeyError:
|
|
17 |
raise ValueError("Please set the GEMINI_API_KEY environment variable.")
|
18 |
client = genai.Client(api_key=api_key)
|
19 |
|
20 |
-
# Define safety settings to disable all filters
|
21 |
SAFETY_SETTINGS = [
|
22 |
types.SafetySetting(
|
23 |
category=types.HarmCategory.HARM_CATEGORY_HARASSMENT,
|
@@ -184,6 +184,11 @@ def generate_item(user_input, ideas, generate_video=False, max_retries=3):
|
|
184 |
total_attempts += 1
|
185 |
|
186 |
# Step 1: Generate an image (retry up to max_retries times)
|
|
|
|
|
|
|
|
|
|
|
187 |
for image_attempt in range(max_retries):
|
188 |
selected_idea = random.choice(ideas)
|
189 |
prompt = f"""
|
@@ -225,8 +230,7 @@ def generate_item(user_input, ideas, generate_video=False, max_retries=3):
|
|
225 |
prompt=image_prompt,
|
226 |
config=types.GenerateImagesConfig(
|
227 |
aspect_ratio="9:16",
|
228 |
-
number_of_images=1
|
229 |
-
safety_settings=SAFETY_SETTINGS
|
230 |
)
|
231 |
)
|
232 |
if imagen.generated_images and len(imagen.generated_images) > 0:
|
@@ -244,8 +248,9 @@ def generate_item(user_input, ideas, generate_video=False, max_retries=3):
|
|
244 |
else:
|
245 |
print(f"Image generation failed (image attempt {image_attempt + 1}, total attempt {total_attempts}): No images returned")
|
246 |
if image_attempt == max_retries - 1:
|
247 |
-
# Last image attempt in this cycle
|
248 |
if total_attempts == max_total_attempts:
|
|
|
249 |
image = Image.new('RGB', (360, 640), color='gray')
|
250 |
buffered = BytesIO()
|
251 |
image.save(buffered, format="PNG")
|
@@ -256,8 +261,8 @@ def generate_item(user_input, ideas, generate_video=False, max_retries=3):
|
|
256 |
'video_base64': None,
|
257 |
'ideas': ideas
|
258 |
}
|
259 |
-
# Otherwise,
|
260 |
-
|
261 |
except Exception as e:
|
262 |
print(f"Error generating image (image attempt {image_attempt + 1}, total attempt {total_attempts}): {e}")
|
263 |
if image_attempt == max_retries - 1:
|
@@ -274,12 +279,15 @@ def generate_item(user_input, ideas, generate_video=False, max_retries=3):
|
|
274 |
'video_base64': None,
|
275 |
'ideas': ideas
|
276 |
}
|
277 |
-
# Otherwise,
|
278 |
-
|
279 |
|
280 |
# Step 2: Generate video if enabled (with retries using the same image)
|
281 |
-
if generate_video:
|
282 |
max_video_retries_per_image = 2 # Try video generation twice per image
|
|
|
|
|
|
|
283 |
for video_attempt in range(max_video_retries_per_image):
|
284 |
try:
|
285 |
# Base video prompt
|
@@ -297,7 +305,7 @@ def generate_item(user_input, ideas, generate_video=False, max_retries=3):
|
|
297 |
Use a static close-up shot of the subject in a realistic style.
|
298 |
"""
|
299 |
|
300 |
-
print(f"Attempting video generation (video attempt {video_attempt + 1}, total attempt {total_attempts}): {video_prompt}")
|
301 |
operation = client.models.generate_videos(
|
302 |
model="veo-2.0-generate-001",
|
303 |
prompt=video_prompt,
|
@@ -306,8 +314,7 @@ def generate_item(user_input, ideas, generate_video=False, max_retries=3):
|
|
306 |
aspect_ratio="9:16",
|
307 |
number_of_videos=1,
|
308 |
duration_seconds=8,
|
309 |
-
negative_prompt="blurry, low quality, text, letters"
|
310 |
-
safety_settings=SAFETY_SETTINGS
|
311 |
)
|
312 |
)
|
313 |
# Wait for video to generate
|
@@ -361,6 +368,7 @@ def generate_item(user_input, ideas, generate_video=False, max_retries=3):
|
|
361 |
video_bytes = video_buffer.getvalue()
|
362 |
# Encode the video bytes as base64
|
363 |
video_base64 = base64.b64encode(video_bytes).decode()
|
|
|
364 |
# Successfully generated video, return the result
|
365 |
return {
|
366 |
'text': text,
|
@@ -371,29 +379,128 @@ def generate_item(user_input, ideas, generate_video=False, max_retries=3):
|
|
371 |
else:
|
372 |
raise ValueError("No video was generated")
|
373 |
except Exception as e:
|
374 |
-
print(f"Error generating video (video attempt {video_attempt + 1}, total attempt {total_attempts}): {e}")
|
375 |
if video_attempt == max_video_retries_per_image - 1:
|
376 |
-
|
377 |
-
|
378 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
379 |
return {
|
380 |
'text': text,
|
381 |
'image_base64': img_str,
|
382 |
'video_base64': video_base64,
|
383 |
'ideas': ideas
|
384 |
}
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
389 |
|
390 |
-
# If video generation is not enabled or
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
|
|
|
|
397 |
|
398 |
# If max total attempts reached without success, use a gray placeholder image
|
399 |
print("Max total attempts reached without successful image generation. Using placeholder.")
|
|
|
17 |
raise ValueError("Please set the GEMINI_API_KEY environment variable.")
|
18 |
client = genai.Client(api_key=api_key)
|
19 |
|
20 |
+
# Define safety settings to disable all filters for content generation
|
21 |
SAFETY_SETTINGS = [
|
22 |
types.SafetySetting(
|
23 |
category=types.HarmCategory.HARM_CATEGORY_HARASSMENT,
|
|
|
184 |
total_attempts += 1
|
185 |
|
186 |
# Step 1: Generate an image (retry up to max_retries times)
|
187 |
+
generated_image = None # Initialize to None
|
188 |
+
text = None
|
189 |
+
img_str = None
|
190 |
+
image_prompt = None
|
191 |
+
|
192 |
for image_attempt in range(max_retries):
|
193 |
selected_idea = random.choice(ideas)
|
194 |
prompt = f"""
|
|
|
230 |
prompt=image_prompt,
|
231 |
config=types.GenerateImagesConfig(
|
232 |
aspect_ratio="9:16",
|
233 |
+
number_of_images=1
|
|
|
234 |
)
|
235 |
)
|
236 |
if imagen.generated_images and len(imagen.generated_images) > 0:
|
|
|
248 |
else:
|
249 |
print(f"Image generation failed (image attempt {image_attempt + 1}, total attempt {total_attempts}): No images returned")
|
250 |
if image_attempt == max_retries - 1:
|
251 |
+
# Last image attempt in this cycle
|
252 |
if total_attempts == max_total_attempts:
|
253 |
+
# Max total attempts reached, use a gray placeholder
|
254 |
image = Image.new('RGB', (360, 640), color='gray')
|
255 |
buffered = BytesIO()
|
256 |
image.save(buffered, format="PNG")
|
|
|
261 |
'video_base64': None,
|
262 |
'ideas': ideas
|
263 |
}
|
264 |
+
# Otherwise, continue to next cycle
|
265 |
+
break # Exit inner loop to retry with new idea
|
266 |
except Exception as e:
|
267 |
print(f"Error generating image (image attempt {image_attempt + 1}, total attempt {total_attempts}): {e}")
|
268 |
if image_attempt == max_retries - 1:
|
|
|
279 |
'video_base64': None,
|
280 |
'ideas': ideas
|
281 |
}
|
282 |
+
# Otherwise, continue to next cycle
|
283 |
+
break # Exit inner loop to retry with new idea
|
284 |
|
285 |
# Step 2: Generate video if enabled (with retries using the same image)
|
286 |
+
if generate_video and generated_image is not None:
|
287 |
max_video_retries_per_image = 2 # Try video generation twice per image
|
288 |
+
video_generated = False
|
289 |
+
|
290 |
+
# First, try image-to-video generation
|
291 |
for video_attempt in range(max_video_retries_per_image):
|
292 |
try:
|
293 |
# Base video prompt
|
|
|
305 |
Use a static close-up shot of the subject in a realistic style.
|
306 |
"""
|
307 |
|
308 |
+
print(f"Attempting image-to-video generation (video attempt {video_attempt + 1}, total attempt {total_attempts}): {video_prompt}")
|
309 |
operation = client.models.generate_videos(
|
310 |
model="veo-2.0-generate-001",
|
311 |
prompt=video_prompt,
|
|
|
314 |
aspect_ratio="9:16",
|
315 |
number_of_videos=1,
|
316 |
duration_seconds=8,
|
317 |
+
negative_prompt="blurry, low quality, text, letters"
|
|
|
318 |
)
|
319 |
)
|
320 |
# Wait for video to generate
|
|
|
368 |
video_bytes = video_buffer.getvalue()
|
369 |
# Encode the video bytes as base64
|
370 |
video_base64 = base64.b64encode(video_bytes).decode()
|
371 |
+
video_generated = True
|
372 |
# Successfully generated video, return the result
|
373 |
return {
|
374 |
'text': text,
|
|
|
379 |
else:
|
380 |
raise ValueError("No video was generated")
|
381 |
except Exception as e:
|
382 |
+
print(f"Error generating video (image-to-video attempt {video_attempt + 1}, total attempt {total_attempts}): {e}")
|
383 |
if video_attempt == max_video_retries_per_image - 1:
|
384 |
+
print("Image-to-video generation failed after all attempts. Falling back to text-to-video generation.")
|
385 |
+
break
|
386 |
+
continue # Retry image-to-video generation with a modified prompt
|
387 |
+
|
388 |
+
# If image-to-video generation failed, try text-to-video generation
|
389 |
+
if not video_generated:
|
390 |
+
for video_attempt in range(max_video_retries_per_image):
|
391 |
+
try:
|
392 |
+
# Use the same video prompt but without the image
|
393 |
+
video_prompt_base = f"""
|
394 |
+
The user concept is "{user_input}". Based on this and the scene: {image_prompt}, create a video.
|
395 |
+
Use a close-up shot with a slow dolly shot circling around the subject,
|
396 |
+
using shallow focus on the main subject to emphasize details, in a realistic style with cinematic lighting.
|
397 |
+
"""
|
398 |
+
if video_attempt == 0:
|
399 |
+
video_prompt = video_prompt_base
|
400 |
+
else:
|
401 |
+
video_prompt = f"""
|
402 |
+
The user concept is "{user_input}". Based on this and a simplified scene: {image_prompt}, create a video.
|
403 |
+
Use a static close-up shot of the subject in a realistic style.
|
404 |
+
"""
|
405 |
+
|
406 |
+
print(f"Attempting text-to-video generation (video attempt {video_attempt + 1}, total attempt {total_attempts}): {video_prompt}")
|
407 |
+
operation = client.models.generate_videos(
|
408 |
+
model="veo-2.0-generate-001",
|
409 |
+
prompt=video_prompt,
|
410 |
+
config=types.GenerateVideosConfig(
|
411 |
+
aspect_ratio="9:16",
|
412 |
+
number_of_videos=1,
|
413 |
+
duration_seconds=8,
|
414 |
+
negative_prompt="blurry, low quality, text, letters"
|
415 |
+
)
|
416 |
+
)
|
417 |
+
# Wait for video to generate
|
418 |
+
while not operation.done:
|
419 |
+
time.sleep(20)
|
420 |
+
operation = client.operations.get(operation)
|
421 |
+
|
422 |
+
# Log detailed information about the operation
|
423 |
+
print(f"Video generation operation completed: {operation}")
|
424 |
+
print(f"Operation done: {operation.done}")
|
425 |
+
print(f"Operation error: {operation.error}")
|
426 |
+
if operation.error:
|
427 |
+
print(f"Operation error message: {operation.error.message}")
|
428 |
+
if hasattr(operation.error, 'code'):
|
429 |
+
print(f"Operation error code: {operation.error.code}")
|
430 |
+
if hasattr(operation.error, 'details'):
|
431 |
+
print(f"Operation error details: {operation.error.details}")
|
432 |
+
print(f"Operation response: {operation.response}")
|
433 |
+
if operation.response:
|
434 |
+
print(f"Operation response has generated_videos: {hasattr(operation.response, 'generated_videos')}")
|
435 |
+
if hasattr(operation.response, 'generated_videos'):
|
436 |
+
print(f"Generated videos: {operation.response.generated_videos}")
|
437 |
+
else:
|
438 |
+
print("No generated_videos attribute in response")
|
439 |
+
|
440 |
+
# Enhanced error handling for video generation response
|
441 |
+
if operation.error:
|
442 |
+
raise ValueError(f"Video generation operation failed with error: {operation.error.message}")
|
443 |
+
if operation.response is None:
|
444 |
+
raise ValueError("Video generation operation failed: No response")
|
445 |
+
if not hasattr(operation.response, 'generated_videos') or operation.response.generated_videos is None:
|
446 |
+
raise ValueError("Video generation operation failed: No generated_videos in response")
|
447 |
+
|
448 |
+
# Process the single generated video
|
449 |
+
if len(operation.response.generated_videos) > 0:
|
450 |
+
video = operation.response.generated_videos[0]
|
451 |
+
if video is None or not hasattr(video, 'video'):
|
452 |
+
raise ValueError("Video is invalid or missing video data")
|
453 |
+
fname = 'text_to_video.mp4'
|
454 |
+
print(f"Generated video: {fname}")
|
455 |
+
# Download the video and get the raw bytes
|
456 |
+
video_data = client.files.download(file=video.video)
|
457 |
+
# Ensure video_data is in bytes
|
458 |
+
if isinstance(video_data, bytes):
|
459 |
+
video_bytes = video_data
|
460 |
+
else:
|
461 |
+
# If video_data is a file-like object, read the bytes
|
462 |
+
video_buffer = BytesIO()
|
463 |
+
for chunk in video_data:
|
464 |
+
video_buffer.write(chunk)
|
465 |
+
video_bytes = video_buffer.getvalue()
|
466 |
+
# Encode the video bytes as base64
|
467 |
+
video_base64 = base64.b64encode(video_bytes).decode()
|
468 |
+
video_generated = True
|
469 |
+
# Successfully generated video, return the result
|
470 |
return {
|
471 |
'text': text,
|
472 |
'image_base64': img_str,
|
473 |
'video_base64': video_base64,
|
474 |
'ideas': ideas
|
475 |
}
|
476 |
+
else:
|
477 |
+
raise ValueError("No video was generated")
|
478 |
+
except Exception as e:
|
479 |
+
print(f"Error generating video (text-to-video attempt {video_attempt + 1}, total attempt {total_attempts}): {e}")
|
480 |
+
if video_attempt == max_video_retries_per_image - 1:
|
481 |
+
if total_attempts == max_total_attempts:
|
482 |
+
print("Max total attempts reached. Proceeding without video.")
|
483 |
+
video_base64 = None
|
484 |
+
return {
|
485 |
+
'text': text,
|
486 |
+
'image_base64': img_str,
|
487 |
+
'video_base64': video_base64,
|
488 |
+
'ideas': ideas
|
489 |
+
}
|
490 |
+
# Both image-to-video and text-to-video failed, break to outer loop to try a new image
|
491 |
+
print(f"Text-to-video generation failed after {max_video_retries_per_image} attempts. Selecting a new idea and generating a new image.")
|
492 |
+
break
|
493 |
+
continue # Retry text-to-video generation with a modified prompt
|
494 |
|
495 |
+
# If video generation is not enabled or image generation failed, return the result
|
496 |
+
if img_str is not None:
|
497 |
+
return {
|
498 |
+
'text': text,
|
499 |
+
'image_base64': img_str,
|
500 |
+
'video_base64': video_base64,
|
501 |
+
'ideas': ideas
|
502 |
+
}
|
503 |
+
# If img_str is None, continue to next cycle or fall back if max attempts reached
|
504 |
|
505 |
# If max total attempts reached without success, use a gray placeholder image
|
506 |
print("Max total attempts reached without successful image generation. Using placeholder.")
|