Skip to content

Instantly share code, notes, and snippets.

@Miyamura80
Created March 13, 2025 13:40
Show Gist options
  • Save Miyamura80/e1eda9bb0a3c237b852c81fe766639ca to your computer and use it in GitHub Desktop.
Save Miyamura80/e1eda9bb0a3c237b852c81fe766639ca to your computer and use it in GitHub Desktop.
from google import genai
from google.genai import types
from PIL import Image
from io import BytesIO
import os
import subprocess
import tempfile
from global_config import global_config
from loguru import logger as log
# TODO: Use your own key
GEMINI_API_KEY = ""
# Setup logging
setup_logging()
client = genai.Client(api_key=GEMINI_API_KEY)
contents = "Create an animation by generating multiple frames, showing a seed growing into a plant and then blooming into a flower, in a pixel art style"
log.info(f"Sending request to Gemini with prompt: {contents}")
response = client.models.generate_content(
model="models/gemini-2.0-flash-exp",
contents=contents,
config=types.GenerateContentConfig(response_modalities=['Text', 'Image'])
)
# Create a temporary directory to store the frames
with tempfile.TemporaryDirectory() as temp_dir:
log.info(f"Created temporary directory at {temp_dir}")
frame_paths = []
frame_count = 0
# Process and save each part
log.info(f"Number of candidates: {len(response.candidates)}")
if response.candidates:
log.info(f"Number of parts in first candidate: {len(response.candidates[0].content.parts)}")
for part_index, part in enumerate(response.candidates[0].content.parts):
log.info(f"Processing part {part_index+1}")
if part.text is not None:
log.info(f"Text content: {part.text[:100]}...")
print(part.text)
elif part.inline_data is not None:
# Save the image to a temporary file
frame_path = os.path.join(temp_dir, f"frame_{frame_count:03d}.png")
image = Image.open(BytesIO(part.inline_data.data))
image.save(frame_path)
frame_paths.append(frame_path)
frame_count += 1
log.info(f"Saved frame {frame_count} to {frame_path}")
else:
log.warning(f"Part {part_index+1} has neither text nor inline_data")
else:
log.error("No candidates returned in the response")
# If we have frames, create a GIF using ffmpeg
if frame_paths:
log.info(f"Found {len(frame_paths)} frames to process")
output_path = os.path.abspath("animation.gif")
log.info(f"Will save animation to {output_path}")
# List all files in the temp directory to verify
log.info(f"Files in temp directory: {os.listdir(temp_dir)}")
# Build ffmpeg command
ffmpeg_cmd = [
"ffmpeg",
"-y", # Overwrite output file if it exists
"-framerate", "2", # 2 frames per second
"-pattern_type", "glob",
"-i", f"{temp_dir}/frame_*.png",
"-vf", "scale=512:-1:flags=lanczos", # Resize while maintaining aspect ratio
output_path
]
try:
cmd_str = ' '.join(ffmpeg_cmd)
log.info(f"Running ffmpeg command: {cmd_str}")
# Run ffmpeg and capture output
result = subprocess.run(
ffmpeg_cmd,
check=True,
capture_output=True,
text=True
)
log.info(f"ffmpeg stdout: {result.stdout}")
log.info(f"ffmpeg stderr: {result.stderr}")
if os.path.exists(output_path):
log.info(f"Animation successfully saved to {output_path}")
file_size = os.path.getsize(output_path)
log.info(f"File size: {file_size} bytes")
# Open the resulting GIF
Image.open(output_path).show()
else:
log.error(f"Output file {output_path} was not created")
except subprocess.CalledProcessError as e:
log.error(f"Failed to create GIF: {e}")
log.error(f"ffmpeg stdout: {e.stdout}")
log.error(f"ffmpeg stderr: {e.stderr}")
except Exception as e:
log.error(f"Unexpected error: {str(e)}")
else:
log.warning("No frames were generated, cannot create animation")
log.info("Script completed")
@GBurgardt
Copy link

It only generates text. Do I need to enable something in my API Key in the Google Console?

@Miyamura80
Copy link
Author

Ah sorry better refer to my newer one: https://x.com/Eito_Miyamura/status/1900190111565836455

@Miyamura80
Copy link
Author

This one little bit unstable

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment