Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Comprehensive AI design skill providing design intelligence across platforms with 161 reasoning rules.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
scripts/cip/generate.py
1#!/usr/bin/env python32# -*- coding: utf-8 -*-3"""4CIP Design Generator - Generate corporate identity mockups using Gemini Nano Banana56Uses Gemini's native image generation (Nano Banana Flash/Pro) for high-quality mockups.7Supports text-and-image-to-image generation for using actual brand logos.89- gemini-2.5-flash-image: Fast generation, cost-effective (default)10- gemini-3-pro-image-preview: Pro quality, 4K text rendering1112Image Editing (text-and-image-to-image):13When --logo is provided, the script uses Gemini's image editing capability14to incorporate the actual logo into CIP mockups instead of generating one.15"""1617import argparse18import json19import os20import sys21from pathlib import Path22from datetime import datetime2324# Add parent directory for imports25sys.path.insert(0, str(Path(__file__).parent))26from core import search, get_cip_brief2728# Model options29MODELS = {30"flash": "gemini-2.5-flash-image", # Nano Banana Flash - fast, default31"pro": "gemini-3-pro-image-preview" # Nano Banana Pro - quality, 4K text32}33DEFAULT_MODEL = "flash"343536def load_logo_image(logo_path):37"""Load logo image using PIL for Gemini image editing"""38try:39from PIL import Image40except ImportError:41print("Error: pillow package not installed.")42print("Install with: pip install pillow")43return None4445logo_path = Path(logo_path)46if not logo_path.exists():47print(f"Error: Logo file not found: {logo_path}")48return None4950try:51img = Image.open(logo_path)52# Convert to RGB if necessary (Gemini works best with RGB)53if img.mode in ('RGBA', 'P'):54# Create white background for transparent images55background = Image.new('RGB', img.size, (255, 255, 255))56if img.mode == 'RGBA':57background.paste(img, mask=img.split()[3]) # Use alpha channel as mask58else:59background.paste(img)60img = background61elif img.mode != 'RGB':62img = img.convert('RGB')63return img64except Exception as e:65print(f"Error loading logo: {e}")66return None6768# Load environment variables69def load_env():70"""Load environment variables from .env files"""71env_paths = [72Path(__file__).parent.parent.parent / ".env",73Path.home() / ".claude" / "skills" / ".env",74Path.home() / ".claude" / ".env"75]76for env_path in env_paths:77if env_path.exists():78with open(env_path) as f:79for line in f:80line = line.strip()81if line and not line.startswith("#") and "=" in line:82key, value = line.split("=", 1)83if key not in os.environ:84os.environ[key] = value.strip('"\'')8586load_env()878889def build_cip_prompt(deliverable, brand_name, style=None, industry=None, mockup=None, use_logo_image=False):90"""Build an optimized prompt for CIP mockup generation9192Args:93deliverable: Type of deliverable (business card, letterhead, etc.)94brand_name: Name of the brand95style: Design style preference96industry: Industry for style recommendations97mockup: Mockup context override98use_logo_image: If True, prompt is optimized for image editing with logo99"""100101# Get deliverable details102deliverable_info = search(deliverable, "deliverable", 1)103deliverable_data = deliverable_info.get("results", [{}])[0] if deliverable_info.get("results") else {}104105# Get style details106style_info = search(style or "corporate minimal", "style", 1) if style else {}107style_data = style_info.get("results", [{}])[0] if style_info.get("results") else {}108109# Get industry details110industry_info = search(industry or "technology", "industry", 1) if industry else {}111industry_data = industry_info.get("results", [{}])[0] if industry_info.get("results") else {}112113# Get mockup context114mockup_context = deliverable_data.get("Mockup Context", "clean professional")115if mockup:116mockup_info = search(mockup, "mockup", 1)117if mockup_info.get("results"):118mockup_data = mockup_info["results"][0]119mockup_context = mockup_data.get("Scene Description", mockup_context)120121# Build prompt components122deliverable_name = deliverable_data.get("Deliverable", deliverable)123description = deliverable_data.get("Description", "")124dimensions = deliverable_data.get("Dimensions", "")125logo_placement = deliverable_data.get("Logo Placement", "center")126127style_name = style_data.get("Style Name", style or "corporate")128primary_colors = style_data.get("Primary Colors", industry_data.get("Primary Colors", "#0F172A #FFFFFF"))129typography = style_data.get("Typography", industry_data.get("Typography", "clean sans-serif"))130materials = style_data.get("Materials", "premium quality")131finishes = style_data.get("Finishes", "professional")132133mood = style_data.get("Mood", industry_data.get("Mood", "professional"))134135# Construct the prompt - different for image editing vs pure generation136if use_logo_image:137# Image editing prompt: instructs to USE the provided logo image138prompt_parts = [139f"Create a professional corporate identity mockup photograph of a {deliverable_name}",140f"Use the EXACT logo from the provided image - do NOT modify or recreate the logo",141f"The logo MUST appear exactly as shown in the input image",142f"Place the logo on the {deliverable_name} at: {logo_placement}",143f"Brand name: '{brand_name}'",144f"{description}" if description else "",145f"Design style: {style_name}",146f"Color scheme matching the logo colors",147f"Materials: {materials} with {finishes} finish",148f"Setting: {mockup_context}",149f"Mood: {mood}",150"Photorealistic product photography",151"Soft natural lighting, professional studio quality",152"8K resolution, sharp details"153]154else:155# Pure text-to-image prompt156prompt_parts = [157f"Professional corporate identity mockup photograph",158f"showing {deliverable_name} for brand '{brand_name}'",159f"{description}" if description else "",160f"{style_name} design style",161f"using colors {primary_colors}",162f"{typography} typography",163f"logo placement: {logo_placement}",164f"{materials} materials with {finishes} finish",165f"{mockup_context} setting",166f"{mood} mood",167"photorealistic product photography",168"soft natural lighting",169"high quality professional shot",170"8k resolution detailed"171]172173prompt = ", ".join([p for p in prompt_parts if p])174175return {176"prompt": prompt,177"deliverable": deliverable_name,178"style": style_name,179"brand": brand_name,180"colors": primary_colors,181"mockup_context": mockup_context,182"logo_placement": logo_placement183}184185186def generate_with_nano_banana(prompt_data, output_dir=None, model_key="flash", aspect_ratio="1:1", logo_image=None):187"""Generate image using Gemini Nano Banana (native image generation)188189Supports two modes:1901. Text-to-image: Pure prompt-based generation (logo_image=None)1912. Image editing: Text-and-image-to-image using provided logo (logo_image=PIL.Image)192193Models:194- flash: gemini-2.5-flash-image (fast, cost-effective) - DEFAULT195- pro: gemini-3-pro-image-preview (quality, 4K text rendering)196197Args:198prompt_data: Dict with prompt, deliverable, brand, etc.199output_dir: Output directory for generated images200model_key: 'flash' or 'pro'201aspect_ratio: Output aspect ratio (1:1, 16:9, etc.)202logo_image: PIL.Image object of the brand logo for image editing mode203"""204try:205from google import genai206from google.genai import types207except ImportError:208print("Error: google-genai package not installed.")209print("Install with: pip install google-genai")210return None211212api_key = os.environ.get("GEMINI_API_KEY") or os.environ.get("GOOGLE_API_KEY")213if not api_key:214print("Error: GEMINI_API_KEY or GOOGLE_API_KEY not set")215return None216217client = genai.Client(api_key=api_key)218219prompt = prompt_data["prompt"]220model_name = MODELS.get(model_key, MODELS[DEFAULT_MODEL])221222# Determine mode223mode = "image-editing" if logo_image else "text-to-image"224225print(f"\n🎨 Generating CIP mockup...")226print(f" Mode: {mode}")227print(f" Deliverable: {prompt_data['deliverable']}")228print(f" Brand: {prompt_data['brand']}")229print(f" Style: {prompt_data['style']}")230print(f" Model: {model_name}")231print(f" Context: {prompt_data['mockup_context']}")232if logo_image:233print(f" Logo: Using provided image ({logo_image.size[0]}x{logo_image.size[1]})")234235try:236# Build contents: either just prompt or [prompt, image] for image editing237if logo_image:238# Image editing mode: pass both prompt and logo image239contents = [prompt, logo_image]240else:241# Text-to-image mode: just the prompt242contents = prompt243244# Use generate_content with response_modalities=['IMAGE'] for Nano Banana245response = client.models.generate_content(246model=model_name,247contents=contents,248config=types.GenerateContentConfig(249response_modalities=['IMAGE'], # Uppercase required250image_config=types.ImageConfig(251aspect_ratio=aspect_ratio252)253)254)255256# Extract image from response257if response.candidates and response.candidates[0].content.parts:258for part in response.candidates[0].content.parts:259if hasattr(part, 'inline_data') and part.inline_data:260# Save image261output_dir = output_dir or Path.cwd()262output_dir = Path(output_dir)263output_dir.mkdir(parents=True, exist_ok=True)264265timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")266brand_slug = prompt_data["brand"].lower().replace(" ", "-")267deliverable_slug = prompt_data["deliverable"].lower().replace(" ", "-")268filename = f"{brand_slug}-{deliverable_slug}-{timestamp}.png"269filepath = output_dir / filename270271image_data = part.inline_data.data272with open(filepath, "wb") as f:273f.write(image_data)274275print(f"\n✅ Generated: {filepath}")276return str(filepath)277278print("No image generated in response")279return None280281except Exception as e:282print(f"Error generating image: {e}")283return None284285286def generate_cip_set(brand_name, industry, style=None, deliverables=None, output_dir=None, model_key="flash", logo_path=None, aspect_ratio="1:1"):287"""Generate a complete CIP set for a brand288289Args:290brand_name: Brand name to generate for291industry: Industry type for style recommendations292style: Optional specific style override293deliverables: List of deliverables to generate (default: core set)294output_dir: Output directory for images295model_key: 'flash' (fast) or 'pro' (quality)296logo_path: Path to brand logo image for image editing mode297aspect_ratio: Output aspect ratio298"""299300# Load logo image if provided301logo_image = None302if logo_path:303logo_image = load_logo_image(logo_path)304if not logo_image:305print("Warning: Could not load logo, falling back to text-to-image mode")306307# Get CIP brief for the brand308brief = get_cip_brief(brand_name, industry, style)309310# Default deliverables if not specified311if not deliverables:312deliverables = ["business card", "letterhead", "office signage", "vehicle", "polo shirt"]313314results = []315for deliverable in deliverables:316prompt_data = build_cip_prompt(317deliverable=deliverable,318brand_name=brand_name,319style=brief.get("style", {}).get("Style Name"),320industry=industry,321use_logo_image=(logo_image is not None)322)323324filepath = generate_with_nano_banana(325prompt_data,326output_dir,327model_key=model_key,328aspect_ratio=aspect_ratio,329logo_image=logo_image330)331if filepath:332results.append({333"deliverable": deliverable,334"filepath": filepath,335"prompt": prompt_data["prompt"]336})337338return results339340341def check_logo_required(brand_name, skip_prompt=False):342"""Check if logo is required and suggest logo-design skill if not provided343344Returns:345str: 'continue' to proceed without logo, 'generate' to use logo-design skill, 'exit' to abort346"""347if skip_prompt:348return 'continue'349350print(f"\n⚠️ No logo image provided for '{brand_name}'")351print(" Without a logo, AI will generate its own interpretation of the brand logo.")352print("")353print(" Options:")354print(" 1. Continue without logo (AI-generated logo interpretation)")355print(" 2. Generate a logo first using 'logo-design' skill")356print(" 3. Exit and provide a logo path with --logo")357print("")358359try:360choice = input(" Enter choice [1/2/3] (default: 1): ").strip()361if choice == '2':362return 'generate'363elif choice == '3':364return 'exit'365return 'continue'366except (EOFError, KeyboardInterrupt):367return 'continue'368369370def main():371parser = argparse.ArgumentParser(372description="Generate CIP mockups using Gemini Nano Banana",373formatter_class=argparse.RawDescriptionHelpFormatter,374epilog="""375Examples:376# Generate with brand logo (RECOMMENDED)377python generate.py --brand "TopGroup" --logo /path/to/logo.png --deliverable "business card"378379# Generate CIP set with logo380python generate.py --brand "TopGroup" --logo /path/to/logo.png --industry "consulting" --set381382# Generate without logo (AI interprets brand)383python generate.py --brand "TechFlow" --deliverable "business card" --no-logo-prompt384385# Generate with Pro model (higher quality, 4K text)386python generate.py --brand "TechFlow" --logo logo.png --deliverable "business card" --model pro387388# Specify output directory and aspect ratio389python generate.py --brand "MyBrand" --logo logo.png --deliverable "vehicle" --output ./mockups --ratio 16:9390391Models:392flash (default): gemini-2.5-flash-image - Fast, cost-effective393pro: gemini-3-pro-image-preview - Quality, 4K text rendering394395Image Editing Mode:396When --logo is provided, uses Gemini's text-and-image-to-image capability397to incorporate your ACTUAL logo into the CIP mockups.398"""399)400401parser.add_argument("--brand", "-b", required=True, help="Brand name")402parser.add_argument("--logo", "-l", help="Path to brand logo image (enables image editing mode)")403parser.add_argument("--deliverable", "-d", help="Single deliverable to generate")404parser.add_argument("--deliverables", help="Comma-separated list of deliverables")405parser.add_argument("--industry", "-i", default="technology", help="Industry type")406parser.add_argument("--style", "-s", help="Design style")407parser.add_argument("--mockup", "-m", help="Mockup context")408parser.add_argument("--set", action="store_true", help="Generate full CIP set")409parser.add_argument("--output", "-o", help="Output directory")410parser.add_argument("--model", default="flash", choices=["flash", "pro"], help="Model: flash (fast) or pro (quality)")411parser.add_argument("--ratio", default="1:1", help="Aspect ratio (1:1, 16:9, 4:3, etc.)")412parser.add_argument("--prompt-only", action="store_true", help="Only show prompt, don't generate")413parser.add_argument("--json", "-j", action="store_true", help="Output as JSON")414parser.add_argument("--no-logo-prompt", action="store_true", help="Skip logo prompt, proceed without logo")415416args = parser.parse_args()417418# Check if logo is provided, prompt user if not419logo_image = None420if args.logo:421logo_image = load_logo_image(args.logo)422if not logo_image:423print("Error: Could not load logo image")424sys.exit(1)425elif not args.prompt_only:426# No logo provided - ask user what to do427action = check_logo_required(args.brand, skip_prompt=args.no_logo_prompt)428if action == 'generate':429print("\n💡 To generate a logo, use the logo-design skill:")430print(f" python ~/.claude/skills/design/scripts/logo/generate.py --brand \"{args.brand}\" --industry \"{args.industry}\"")431print("\n Then re-run this command with --logo <generated_logo.png>")432sys.exit(0)433elif action == 'exit':434print("\n Provide logo with: --logo /path/to/your/logo.png")435sys.exit(0)436# else: continue without logo437438use_logo = logo_image is not None439440if args.set or args.deliverables:441# Generate multiple deliverables442deliverables = args.deliverables.split(",") if args.deliverables else None443444if args.prompt_only:445results = []446deliverables = deliverables or ["business card", "letterhead", "office signage", "vehicle", "polo shirt"]447for d in deliverables:448prompt_data = build_cip_prompt(d, args.brand, args.style, args.industry, args.mockup, use_logo_image=use_logo)449results.append(prompt_data)450if args.json:451print(json.dumps(results, indent=2))452else:453for r in results:454print(f"\n{r['deliverable']}:\n{r['prompt']}\n")455else:456results = generate_cip_set(457args.brand, args.industry, args.style, deliverables, args.output,458model_key=args.model, logo_path=args.logo, aspect_ratio=args.ratio459)460if args.json:461print(json.dumps(results, indent=2))462else:463print(f"\n✅ Generated {len(results)} CIP mockups")464else:465# Generate single deliverable466deliverable = args.deliverable or "business card"467prompt_data = build_cip_prompt(deliverable, args.brand, args.style, args.industry, args.mockup, use_logo_image=use_logo)468469if args.prompt_only:470if args.json:471print(json.dumps(prompt_data, indent=2))472else:473print(f"\nPrompt:\n{prompt_data['prompt']}")474else:475filepath = generate_with_nano_banana(476prompt_data, args.output, model_key=args.model,477aspect_ratio=args.ratio, logo_image=logo_image478)479if args.json:480print(json.dumps({"filepath": filepath, **prompt_data}, indent=2))481482483if __name__ == "__main__":484main()485