Track deploy, social, and Reaper scripts
Scripts already referenced from CLAUDE.md but never committed: deploy_searxng.sh (which stands up the SearXNG instance Devon's web_search depends on), post_milestone.py, generate_milestone_images.py, make_x_launch_assets.py, schedule_x_launch.py, download_music.py, and the Reaper bleep-selection script. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate 1000 downloads milestone images using Nano Banana 2 (Gemini Flash Image)."""
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from google import genai
|
||||
from google.genai import types
|
||||
|
||||
# Load .env manually
|
||||
env_path = Path(__file__).parent / ".env"
|
||||
if env_path.exists():
|
||||
for line in env_path.read_text().splitlines():
|
||||
line = line.strip()
|
||||
if line and not line.startswith("#") and "=" in line:
|
||||
key, _, value = line.partition("=")
|
||||
os.environ.setdefault(key.strip(), value.strip())
|
||||
|
||||
client = genai.Client(api_key=os.getenv("GOOGLE_API_KEY"))
|
||||
MODEL = "gemini-3.1-flash-image-preview"
|
||||
OUTPUT_DIR = Path("social_posts/1000_milestone")
|
||||
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
||||
def generate_image(prompt: str, filename: str, aspect_ratio: str = "1:1"):
|
||||
print(f"Generating {filename}...")
|
||||
response = client.models.generate_content(
|
||||
model=MODEL,
|
||||
contents=[prompt],
|
||||
config=types.GenerateContentConfig(
|
||||
response_modalities=["TEXT", "IMAGE"],
|
||||
image_config=types.ImageConfig(
|
||||
aspect_ratio=aspect_ratio,
|
||||
image_size="2K",
|
||||
),
|
||||
),
|
||||
)
|
||||
for part in response.parts:
|
||||
if part.inline_data is not None:
|
||||
image = part.as_image()
|
||||
path = OUTPUT_DIR / filename
|
||||
image.save(str(path))
|
||||
print(f" Saved: {path}")
|
||||
return
|
||||
print(f" WARNING: No image generated for {filename}")
|
||||
|
||||
|
||||
STYLE_BASE = (
|
||||
"Professional podcast promotional graphic. Dark navy/black background with subtle "
|
||||
"warm amber and gold accent lighting, evoking a late-night radio studio atmosphere. "
|
||||
"Clean modern typography. No photorealistic people. Subtle microphone and radio wave "
|
||||
"design elements. Polished, minimal, high contrast."
|
||||
)
|
||||
|
||||
images = [
|
||||
{
|
||||
"filename": "main_milestone_square.png",
|
||||
"aspect_ratio": "1:1",
|
||||
"prompt": (
|
||||
f"{STYLE_BASE} "
|
||||
"Large bold glowing text '1,000' as the hero element in the center, with "
|
||||
"'DOWNLOADS' directly below it in a thinner font. Below that in smaller text: "
|
||||
"'27 episodes · 200+ callers · 1 month'. "
|
||||
"At the top: 'LUKE AT THE ROOST' in elegant lettering. "
|
||||
"Subtle golden microphone icon above the title. "
|
||||
"At the bottom: 'lukeattheroost.com' in small clean text. "
|
||||
"The overall feel is celebratory but classy, like a late-night milestone announcement."
|
||||
),
|
||||
},
|
||||
{
|
||||
"filename": "main_milestone_twitter.png",
|
||||
"aspect_ratio": "16:9",
|
||||
"prompt": (
|
||||
f"{STYLE_BASE} "
|
||||
"Wide banner format. Left side has 'LUKE AT THE ROOST' title with a subtle "
|
||||
"microphone graphic. Right side has large bold glowing '1,000 DOWNLOADS' text "
|
||||
"with '27 episodes · 200+ callers · 1 month' below. "
|
||||
"Warm amber glow connecting the two sides. "
|
||||
"Bottom right corner: 'lukeattheroost.com'. "
|
||||
"Designed as a Twitter/X post image."
|
||||
),
|
||||
},
|
||||
{
|
||||
"filename": "carousel_1_downloads.png",
|
||||
"aspect_ratio": "1:1",
|
||||
"prompt": (
|
||||
f"{STYLE_BASE} "
|
||||
"Instagram carousel slide 1. Giant bold text '1,000' taking up most of the frame, "
|
||||
"with 'DOWNLOADS' below. Subtle radio wave ripples emanating from the numbers. "
|
||||
"'LUKE AT THE ROOST' at the top in small elegant text. "
|
||||
"Small '1/5' page indicator dots at the bottom."
|
||||
),
|
||||
},
|
||||
{
|
||||
"filename": "carousel_2_episodes.png",
|
||||
"aspect_ratio": "1:1",
|
||||
"prompt": (
|
||||
f"{STYLE_BASE} "
|
||||
"Instagram carousel slide 2. Large bold text '27' in the center with "
|
||||
"'EPISODES' below. A subtle audio waveform timeline graphic running horizontally "
|
||||
"behind the number. 'LUKE AT THE ROOST' at the top in small elegant text. "
|
||||
"Small '2/5' page indicator dots at the bottom."
|
||||
),
|
||||
},
|
||||
{
|
||||
"filename": "carousel_3_callers.png",
|
||||
"aspect_ratio": "1:1",
|
||||
"prompt": (
|
||||
f"{STYLE_BASE} "
|
||||
"Instagram carousel slide 3. Large bold text '200+' in the center with "
|
||||
"'CALLERS' below. Subtle vintage telephone handset icon above the number. "
|
||||
"'LUKE AT THE ROOST' at the top in small elegant text. "
|
||||
"Small '3/5' page indicator dots at the bottom."
|
||||
),
|
||||
},
|
||||
{
|
||||
"filename": "carousel_4_regulars.png",
|
||||
"aspect_ratio": "1:1",
|
||||
"prompt": (
|
||||
f"{STYLE_BASE} "
|
||||
"Instagram carousel slide 4. Large bold text '13' in the center with "
|
||||
"'RETURNING REGULARS' below. Subtle connected dots/nodes graphic suggesting "
|
||||
"a network of recurring characters. "
|
||||
"'LUKE AT THE ROOST' at the top in small elegant text. "
|
||||
"Small '4/5' page indicator dots at the bottom."
|
||||
),
|
||||
},
|
||||
{
|
||||
"filename": "carousel_5_thankyou.png",
|
||||
"aspect_ratio": "1:1",
|
||||
"prompt": (
|
||||
f"{STYLE_BASE} "
|
||||
"Instagram carousel slide 5. Warm, heartfelt tone. Large elegant text "
|
||||
"'THANK YOU' in the center with a soft golden glow. Below: "
|
||||
"'lukeattheroost.com' and '208-439-LUKE' in clean small text. "
|
||||
"'LUKE AT THE ROOST' at the top in small elegant text. "
|
||||
"Small '5/5' page indicator dots at the bottom. "
|
||||
"Slightly warmer color temperature than the other slides to feel like a closing moment."
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
if __name__ == "__main__":
|
||||
for img in images:
|
||||
try:
|
||||
generate_image(img["prompt"], img["filename"], img["aspect_ratio"])
|
||||
except Exception as e:
|
||||
print(f" ERROR generating {img['filename']}: {e}")
|
||||
print(f"\nDone! Images saved to {OUTPUT_DIR}/")
|
||||
Reference in New Issue
Block a user