#!/usr/bin/env python
import argparse
import asyncio
import json
import sys
from typing import Iterable
from server.main import generate_topdown_asset, generate_with_viewpoint
def _parse_csv(value: str) -> list[str]:
return [v.strip() for v in value.split(",") if v.strip()]
def _print_result(title: str, payload: dict) -> None:
print(f"=== {title} ===")
print(f"Success: {payload.get('success')}")
if payload.get("success"):
if payload.get("file_path"):
print(f"File: {payload.get('file_path')}")
if payload.get("depth_map_path"):
print(f"Depth map: {payload.get('depth_map_path')}")
if payload.get("view_type"):
print(f"View: {payload.get('view_type')}")
if payload.get("control_strength") is not None:
print(f"Control strength: {payload.get('control_strength')}")
if payload.get("hash"):
print(f"Hash: {payload.get('hash')}")
else:
print(f"Error: {payload.get('error')}")
if payload.get("hint"):
print(f"Hint: {payload.get('hint')}")
print()
def _iter_views(views: str) -> Iterable[str]:
for v in _parse_csv(views):
if v in {"topdown", "side", "front", "3/4"}:
yield v
else:
yield v
async def _run_prop(args: argparse.Namespace) -> None:
result = await generate_with_viewpoint(
prompt=args.prompt_prop,
view_type="topdown",
shape=args.prop_shape,
preset=args.preset_prop,
controlnet_model=args.controlnet_model,
control_strength=args.strength,
width=args.size,
height=args.size,
seed=args.seed,
save_to_file=args.save
)
payload = json.loads(result)
_print_result("Test: Top-down Prop (ControlNet Depth)", payload)
async def _run_character(args: argparse.Namespace) -> None:
result = await generate_topdown_asset(
prompt=args.prompt_character,
asset_type="character",
size=args.size,
control_strength=args.strength,
seed=args.seed,
save_to_file=args.save
)
payload = json.loads(result)
_print_result("Test: Top-down Character (generate_topdown_asset)", payload)
async def _run_multi(args: argparse.Namespace) -> None:
views = list(_iter_views(args.views))
if not views:
return
print("=== Test: Multi-view (same object) ===")
for view in views:
print(f"Generating view: {view}")
result = await generate_with_viewpoint(
prompt=args.prompt_multiview,
view_type=view,
shape=args.multiview_shape,
preset=args.preset_multiview if view != "topdown" else args.preset_prop,
controlnet_model=args.controlnet_model,
control_strength=args.strength,
width=args.size,
height=args.size,
seed=args.seed,
save_to_file=args.save
)
payload = json.loads(result)
if payload.get("success"):
print(f" OK -> {payload.get('file_path', '(no file_path)')}")
else:
print(f" FAIL -> {payload.get('error')}")
print()
async def main() -> int:
parser = argparse.ArgumentParser(description="ControlNet integration tests (ComfyAI-MCP-GameAssets)")
parser.add_argument("--tests", default="prop", help="Comma list: prop,character,multi (default: prop)")
parser.add_argument("--size", type=int, default=512, help="Requested output size (will render at preset size then downscale)")
parser.add_argument("--seed", type=int, default=42)
parser.add_argument("--save", action="store_true", help="Save outputs to OUTPUT_DIR (recommended)")
parser.add_argument("--controlnet-model", default="diffusers_xl_depth_full.safetensors")
parser.add_argument("--strength", type=float, default=0.90)
parser.add_argument("--prompt-prop", default="a wooden barrel with metal bands, clean silhouette")
parser.add_argument("--preset-prop", default="topdown_prop")
parser.add_argument("--prop-shape", default="box", help="flat/sphere/cylinder/box")
parser.add_argument("--prompt-character", default="a knight in blue armor with sword and shield")
parser.add_argument("--prompt-multiview", default="a treasure chest with golden lock")
parser.add_argument("--preset-multiview", default="prop")
parser.add_argument("--multiview-shape", default="box")
parser.add_argument("--views", default="topdown,side")
args = parser.parse_args()
selected = set(_parse_csv(args.tests))
if not selected:
selected = {"prop"}
if args.save is False:
# Default to saving; prevents huge base64 in console and makes review easier.
args.save = True
try:
if "prop" in selected:
await _run_prop(args)
if "character" in selected:
await _run_character(args)
if "multi" in selected:
await _run_multi(args)
return 0
except KeyboardInterrupt:
print("Interrupted.")
return 130
if __name__ == "__main__":
raise SystemExit(asyncio.run(main()))