#!/usr/bin/env python
import argparse
import asyncio
import base64
import json
from pathlib import Path
from server.main import generate_character_animations
def _parse_csv(value: str) -> list[str]:
return [v.strip() for v in value.split(",") if v.strip()]
def _image_file_to_b64(path: Path) -> str:
data = path.read_bytes()
return base64.b64encode(data).decode("utf-8")
async def main() -> int:
parser = argparse.ArgumentParser(description="Img2Img character animation test")
parser.add_argument("--ref", required=True, help="Path to reference PNG/JPG")
parser.add_argument("--description", default="a knight in blue armor")
parser.add_argument("--poses", default="idle,walking,attacking", help="Comma-separated list of poses")
parser.add_argument("--denoise", type=float, default=0.35)
parser.add_argument("--seed", type=int, default=42)
parser.add_argument("--preset", default="character")
parser.add_argument("--pose-denoise-boost", type=float, default=0.25)
parser.add_argument("--save", action="store_true", help="Save outputs to OUTPUT_DIR")
args = parser.parse_args()
ref_path = Path(args.ref)
if not ref_path.exists():
raise FileNotFoundError(str(ref_path))
if args.save is False:
args.save = True
reference_image_base64 = _image_file_to_b64(ref_path)
try:
result = await generate_character_animations(
reference_image_base64=reference_image_base64,
description=args.description,
poses=_parse_csv(args.poses),
denoise=args.denoise,
seed=args.seed,
preset=args.preset,
pose_denoise_boost=args.pose_denoise_boost,
save_to_file=args.save
)
except KeyboardInterrupt:
print("Interrupted.")
return 130
payload = json.loads(result)
print(f"Success: {payload.get('success')}")
if not payload.get("success"):
print(f"Error: {payload.get('error')}")
return 1
print(f"Description: {payload.get('description')}")
print(f"Count: {payload.get('count')}")
animations = payload.get("animations", [])
for a in animations:
pose = a.get("pose")
file_path = a.get("file_path")
h = a.get("hash")
print(f"- pose={pose} file={file_path} hash={h}")
return 0
if __name__ == "__main__":
raise SystemExit(asyncio.run(main()))