@@ -354,10 +354,91 @@ def hooks() -> None:
354354 )
355355
356356
357+ def _check_gemini_key () -> bool :
358+ """Check if GEMINI_API_KEY is available in .env or environment."""
359+ import os
360+
361+ if os .environ .get ("GEMINI_API_KEY" ):
362+ return True
363+ env_path = PROJECT_ROOT / ".env"
364+ if env_path .exists ():
365+ for line in env_path .read_text ().splitlines ():
366+ line = line .strip ()
367+ if line .startswith ("GEMINI_API_KEY=" ) and not line .startswith ("#" ):
368+ value = line .split ("=" , 1 )[1 ].strip ()
369+ return _has_real_value (value )
370+ return False
371+
372+
373+ def _run_media_generation (choice : str , project_name : str , theme : str ) -> list [str ]:
374+ """Run the selected media generation and return list of generated file paths."""
375+ import asyncio
376+
377+ from init .generate_banner import generate_banner as gen_banner
378+ from init .generate_logo import generate_logo as gen_logo
379+
380+ generated_files : list [str ] = []
381+
382+ if choice in ("Banner only" , "Both" ):
383+ with console .status ("[yellow]Generating banner...[/yellow]" ):
384+ asyncio .run (gen_banner (title = project_name , theme = theme ))
385+ banner_path = PROJECT_ROOT / "media" / "banner.png"
386+ generated_files .append (str (banner_path ))
387+ rprint (f"[green]✓[/green] Banner saved to { banner_path } " )
388+
389+ if choice in ("Logo only" , "Both" ):
390+ with console .status ("[yellow]Generating logo...[/yellow]" ):
391+ asyncio .run (gen_logo (project_name = project_name , theme = theme ))
392+ logo_dir = PROJECT_ROOT / "docs" / "public"
393+ for name in (
394+ "logo-light.png" ,
395+ "logo-dark.png" ,
396+ "icon-light.png" ,
397+ "icon-dark.png" ,
398+ "favicon.ico" ,
399+ ):
400+ generated_files .append (str (logo_dir / name ))
401+ rprint (f"[green]✓[/green] Logo assets saved to { logo_dir } " )
402+
403+ return generated_files
404+
405+
357406@app .command ()
358407def media () -> None :
359408 """Step 5: Generate banner and logo assets."""
360- rprint ("[yellow]Step 5 (media) not yet implemented.[/yellow]" )
409+ if not _check_gemini_key ():
410+ rprint ("[yellow]⚠ GEMINI_API_KEY is not configured.[/yellow]" )
411+ skip = questionary .confirm ("Skip media generation?" , default = True ).ask ()
412+ if skip is None :
413+ raise typer .Abort ()
414+ if skip :
415+ rprint ("[yellow]Media generation skipped.[/yellow]" )
416+ return
417+
418+ project_name = _read_pyproject_name ()
419+
420+ theme = questionary .text (
421+ "Describe the visual theme/style for your project assets:" ,
422+ default = "modern, clean, minimalist tech aesthetic" ,
423+ ).ask ()
424+ if theme is None :
425+ raise typer .Abort ()
426+
427+ choice = questionary .select (
428+ "What would you like to generate?" ,
429+ choices = ["Banner only" , "Logo only" , "Both" , "Skip" ],
430+ ).ask ()
431+ if choice is None :
432+ raise typer .Abort ()
433+
434+ if choice == "Skip" :
435+ rprint ("[yellow]Media generation skipped.[/yellow]" )
436+ return
437+
438+ generated_files = _run_media_generation (choice , project_name , theme )
439+ rprint ("\n [green]Generated files:[/green]" )
440+ for f in generated_files :
441+ rprint (f" { f } " )
361442
362443
363444if __name__ == "__main__" :
0 commit comments