diff --git a/tools/sprite-generation/server.py b/tools/sprite-generation/server.py index 07e184f0..bb70aac2 100644 --- a/tools/sprite-generation/server.py +++ b/tools/sprite-generation/server.py @@ -41,6 +41,10 @@ class RejectRequest(BaseModel): dimension_id: int | None = None +class RejectVariantRequest(BaseModel): + reason: str | None = None + + class RegenerateRequest(BaseModel): prompt: str | None = None dimension_id: int | None = None @@ -58,6 +62,13 @@ class PipelineRunRequest(BaseModel): rescore: bool = False +class PinSeedRequest(BaseModel): + seed: int + category: str + entity_id: str = "" + variant_id: int | None = None + + class GenerateRequest(BaseModel): category: str | None = None sprite_id: str | None = None @@ -156,8 +167,8 @@ def create_app( return registry.get_scores(variant_id) @app.post("/api/variants/{variant_id:int}/reject") - def reject_variant(variant_id: int) -> dict: - registry.reject_variant(variant_id) + def reject_variant(variant_id: int, body: RejectVariantRequest = RejectVariantRequest()) -> dict: + registry.reject_variant(variant_id, body.reason) return {"status": "rejected", "variant_id": variant_id} @app.post("/api/sprites/{sprite_id:path}/regenerate") @@ -210,7 +221,7 @@ def create_app( if proc is not None and proc.poll() is None: return {"status": "already_running", "pid": proc.pid} - cmd = [sys.executable, str(TOOL_DIR / "tools" / "advance.py")] + cmd = [sys.executable, "-u", str(TOOL_DIR / "tools" / "advance.py")] if body.scorers: cmd += ["--scorers"] + body.scorers if body.rescore: @@ -278,6 +289,14 @@ def create_app( ) -> list[dict]: return registry.get_review_variants(limit=limit) + @app.get("/api/terrain-grid") + def terrain_grid( + elevation: Annotated[str, Query(pattern=r"^(lowland|highland|alpine)$")] = "lowland", + ) -> dict: + """Biome grid cells for one elevation tier, with best variant per cell.""" + cells = registry.get_terrain_grid(elevation) + return {"cells": cells} + @app.get("/api/theater") def theater_variants( mode: Annotated[str, Query(pattern=r"^(all|review)$")] = "all", @@ -329,10 +348,39 @@ def create_app( def get_runs() -> list[dict]: return registry.get_runs() + # ── Analytics + Seed pool ───────────────────────────────────────────── + + @app.get("/api/analytics/quality") + def quality_analytics( + category: Annotated[str | None, Query()] = None, + scorer: Annotated[str | None, Query()] = None, + ) -> dict: + """Quality dimension averages and gate failure rates across scored variants.""" + return registry.get_quality_analytics(category=category, scorer=scorer) + + @app.get("/api/seeds") + def list_seeds( + category: Annotated[str | None, Query()] = None, + limit: Annotated[int, Query(ge=1, le=200)] = 50, + ) -> list[dict]: + """Top seeds from the pool for a category.""" + return registry.get_seed_pool_report(category=category, limit=limit) + + @app.post("/api/seeds/pin") + def pin_seed(body: PinSeedRequest) -> dict: + """Manually pin a seed to the pool with max quality (user override).""" + registry.pin_seed( + seed=body.seed, + category=body.category, + entity_id=body.entity_id, + variant_id=body.variant_id, + ) + return {"status": "pinned", "seed": body.seed, "category": body.category} + # ── Generation trigger ──────────────────────────────────────────────── @app.post("/api/generate") - def trigger_generate(body: GenerateRequest) -> dict: + async def trigger_generate(body: GenerateRequest) -> dict: from engine.generator import SpriteGenerator config = json.loads((TOOL_DIR / "sprite-config.json").read_text()) @@ -350,7 +398,7 @@ def create_app( return {"submitted": 0, "message": "No sprites in 'needed' status"} sprite_ids = [s["id"] for s in sprites] - submitted = gen.generate_sprites( + submitted = await gen.submit_batch( sprite_ids=sprite_ids, variants_per=body.variants, priority=body.priority, diff --git a/tools/sprite-generation/spritegen.db b/tools/sprite-generation/spritegen.db index f5efd1c5..261ff0da 100644 Binary files a/tools/sprite-generation/spritegen.db and b/tools/sprite-generation/spritegen.db differ diff --git a/tools/sprite-generation/spritegen.db-shm b/tools/sprite-generation/spritegen.db-shm index 2e84b5a4..4a838637 100644 Binary files a/tools/sprite-generation/spritegen.db-shm and b/tools/sprite-generation/spritegen.db-shm differ diff --git a/tools/sprite-generation/spritegen.db-wal b/tools/sprite-generation/spritegen.db-wal index 220a5576..9c5d5006 100644 Binary files a/tools/sprite-generation/spritegen.db-wal and b/tools/sprite-generation/spritegen.db-wal differ