Files
admin ae32e650ce feat(backend): wire exclude_recipe_ids, verify MealPlan votes schema, add image generation service
- api/meal_plans.py: /regenerate now passes exclude_recipe_ids into generate_meal_plan
- planner/generate.py: filter recipe_dicts by exclude_recipe_ids set
- image_generation.py: OpenAI gpt-image-1 client with prompt building, b64_json handling
- main.py: StaticFiles mount at /static for generated images
- admin.py: POST /api/admin/trigger-images endpoint for batch generation
- scripts/generate_images.py: CLI for batch image generation
- docker-compose.yml + nginx: volume mounts for static/images persistence
- Verify MealPlanItem.votes ↔ MealPlanVote relationship is correct; no model bug exists
2026-05-24 19:31:26 -07:00

63 lines
2.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""Batch-generate recipe images using OpenAI DALL-E 3.
Usage:
python scripts/generate_images.py --limit 10 --missing-only
python scripts/generate_images.py --recipe-id <uuid>
"""
from __future__ import annotations
import argparse
import os
import sys
from pathlib import Path
# Ensure imports resolve regardless of cwd.
_ = sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from app.database import get_db as _get_db
from app.services.image_generation import generate_images_batch
def main() -> int:
parser = argparse.ArgumentParser(description="Generate recipe images via DALL-E 3")
parser.add_argument("--limit", type=int, default=10, help="Max recipes to process")
parser.add_argument("--missing-only", action="store_true", default=True, help="Only recipes without images")
parser.add_argument("--force", action="store_true", default=False, help="Overwrite existing images")
parser.add_argument("--recipe-id", type=str, default=None, help="Generate for a single recipe")
args = parser.parse_args()
# FastAPI DB dependency is a generator; consume it.
# Ensure project-root .env is discoverable before importing config.
project_root = Path(__file__).resolve().parent.parent.parent
os.environ.setdefault("DATABASE_URL", os.environ.get("DATABASE_URL", ""))
os.environ.setdefault("AI_IMAGE_ENABLED", os.environ.get("AI_IMAGE_ENABLED", "true"))
os.environ.setdefault("AI_IMAGE_API_KEY", os.environ.get("AI_IMAGE_API_KEY", ""))
os.environ.setdefault("OPENAI_API_KEY", os.environ.get("OPENAI_API_KEY", ""))
db_gen = _get_db()
db = next(db_gen)
recipe_ids = [args.recipe_id] if args.recipe_id else None
result = generate_images_batch(
db,
recipe_ids=recipe_ids,
missing_only=args.missing_only,
force=args.force,
limit=args.limit,
)
print(f"Total: {result['total']}")
print(f"Succeeded: {result['succeeded']}")
print(f"Failed: {result['failed']}")
print(f"Skipped: {result['skipped']}")
for rid, info in result["results"].items():
print(f" {rid}: {info['status']} {info['url'] or '—'}")
return 0
if __name__ == "__main__":
raise SystemExit(main())