Files
AIGame/Tools/generate_battlefield_designs.py

112 lines
4.1 KiB
Python

"""Generate battlefield concept boards with the project image generation flow.
This script delegates image creation to ``Tools/gpt_image_generate.py`` with
the project-standard ``gpt-image-2.5`` model. It deliberately does not draw
placeholder diagrams with PIL. Use ``--dry-run`` to inspect requests without
calling the remote service.
"""
from __future__ import annotations
import argparse
import json
import subprocess
import sys
import time
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
OUT = ROOT / "Doc/Design/Scene/Battlefield"
PROMPT_FILE = OUT / "battlefield_design_prompts.json"
IMAGE_TOOL = ROOT / "Tools/gpt_image_generate.py"
def load_prompts() -> dict:
return json.loads(PROMPT_FILE.read_text(encoding="utf-8-sig"))
def mark_generated(design_id: str, output: Path, status_file: Path) -> None:
manifest_path = OUT / "battlefield_scene_manifest.json"
if not manifest_path.is_file():
return
manifest = json.loads(manifest_path.read_text(encoding="utf-8-sig"))
for option in manifest.get("designOptions", []):
if option.get("id") == design_id:
option.setdefault("generation", {}).update(
{
"tool": "Tools/gpt_image_generate.py",
"model": "gpt-image-2.5",
"status": "generated",
"output": str(output.relative_to(ROOT)).replace("\\", "/"),
"statusFile": str(status_file.relative_to(ROOT)).replace("\\", "/"),
"generatedAtUtc": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
}
)
if manifest.get("requestedDesign") == design_id:
manifest["selectedDesign"] = design_id
manifest.setdefault("designGeneration", {}).update(
{
"tool": "Tools/generate_battlefield_designs.py",
"imageTool": "Tools/gpt_image_generate.py",
"model": "gpt-image-2.5",
"status": "generated",
"generatedAtUtc": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
"note": "已生成并覆盖总览图。",
}
)
manifest_path.write_text(json.dumps(manifest, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
def main() -> int:
parser = argparse.ArgumentParser(
description="Use gpt-image-2.5 to generate the three battlefield design boards."
)
parser.add_argument("--design", choices=["A", "B", "C", "all"], default="all")
parser.add_argument("--dry-run", action="store_true", help="print requests without calling the image API")
parser.add_argument("--quality", default="auto", choices=["auto", "low", "medium", "high"])
args = parser.parse_args()
data = load_prompts()
selected = data["designs"] if args.design == "all" else [next(x for x in data["designs"] if x["id"] == args.design)]
OUT.mkdir(parents=True, exist_ok=True)
for item in selected:
output = OUT / item["file"]
callback = OUT / f"{output.stem}_gpt_image_status.json"
command = [
sys.executable,
str(IMAGE_TOOL),
"--prompt",
item["prompt"],
"--model",
"gpt-image-2.5",
"--aspect-ratio",
"1024x1024",
"--quality",
args.quality,
"--output",
str(output),
"--callback-file",
str(callback),
"--result-only",
]
print(f"[{item['id']}] {item['name']}")
print(" ".join(json.dumps(part, ensure_ascii=False) for part in command))
if args.dry_run:
continue
try:
subprocess.run(command, cwd=ROOT, check=True)
except subprocess.CalledProcessError as exc:
print(
"image generation failed; configure GRSAI_API_KEY or "
"GPT_IMAGE_API_KEY and rerun this command",
file=sys.stderr,
)
return exc.returncode or 1
mark_generated(item["id"], output, callback)
print(f"saved: {output}")
return 0
if __name__ == "__main__":
raise SystemExit(main())