"""gpt_image 第二图像后端手工验证(host 模式,真实调网关,烧 1 张图额度)。 用法(.env 在仓库根, 含 UNIFYLLM_API_KEY): .venv/Scripts/python.exe scripts/test_gpt_image_manual.py [--dry] --dry: 只验证配置装配 / variant 选择 / prompt 块,不真调 API。 输出一律 ASCII(Windows 控制台 GBK)。 """ import os import sys import tempfile import uuid from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT)) env_file = ROOT / ".env" if env_file.exists(): for line in env_file.read_text(encoding="utf-8").splitlines(): line = line.strip() if line and not line.startswith("#") and "=" in line: k, v = line.split("=", 1) os.environ.setdefault(k.strip(), v.strip().strip('"').strip("'")) def main() -> int: dry = "--dry" in sys.argv fails = 0 from core.ark_client import ArkConfig from core.agent_builder import _choose_image_variant, _media_tools_block gw = ArkConfig.load(ROOT / "config" / "media" / "unifyllm.yaml") ark = ArkConfig.load() print(f"[info] ark_cfg={'set' if ark else 'None'} gw_cfg={'set' if gw else 'None'}") if gw is None: print("[FAIL] unifyllm.yaml 未装配(UNIFYLLM_API_KEY 缺失?)") return 1 # variant 选择:显式 gpt_image / 显式 seedream_5 / 空 fallback cases = [ ("gpt_image", "unifyllm", "gpt_image"), ("seedream_5", "doubao" if ark else "unifyllm", "seedream_5" if ark else "gpt_image"), ("", "doubao" if ark else "unifyllm", "seedream_5" if ark else "gpt_image"), ("nonsense", "doubao" if ark else "unifyllm", "seedream_5" if ark else "gpt_image"), ] for variant, want_prov, want_key in cases: prov, key, cfg, pcfg = _choose_image_variant(ark, gw, variant) ok = prov == want_prov and key == want_key and cfg is not None and pcfg is not None print(f"[{'OK' if ok else 'FAIL'}] choose({variant!r}) -> {prov}.{key}") fails += 0 if ok else 1 # prompt 媒体段拼装 blk = _media_tools_block(ark is not None, "gpt_image") ok = "`gpt_image`" in blk and "`seedream`" not in blk.split("\n")[0] and "reference_images" not in blk.split("- `gpt_image`")[1].split("- `")[0] print(f"[{'OK' if ok else 'FAIL'}] media block(gpt_image) mentions gpt_image, no i2i params") fails += 0 if ok else 1 blk2 = _media_tools_block(ark is not None, "seedream") ok = ("- `seedream`" in blk2) and ("- `gpt_image`" not in blk2) print(f"[{'OK' if ok else 'FAIL'}] media block(seedream) unchanged shape") fails += 0 if ok else 1 blk3 = _media_tools_block(False, "") ok = blk3 == "" print(f"[{'OK' if ok else 'FAIL'}] media block(none) empty") fails += 0 if ok else 1 if dry: return 1 if fails else 0 # 真实调用:临时 working_dir,不限额(daily_limit=0),无 DB(record 失败仅打印) from tools.gpt_image import GptImageTool prov, key, cfg, pcfg = _choose_image_variant(ark, gw, "gpt_image") with tempfile.TemporaryDirectory() as td: wd = Path(td) / "wd" wd.mkdir() tool = GptImageTool( gw_cfg=pcfg, image_variant_cfg=cfg, variant_key=key, working_dir=wd, task_id=uuid.uuid4(), user_id=uuid.uuid4(), base_dir=Path(td), user_root=Path(td), daily_limit=0, ) result = tool.execute(prompt="A minimalist flat-design icon of a cement mixer truck, orange and grey") first = result.split("\n")[0] print(f"[info] result first line: {first}") pngs = list(wd.glob("figures/*.png")) metas = list(wd.glob("figures/*.meta.json")) ok = result.startswith("[gpt_image]") and len(pngs) == 1 and len(metas) == 1 and pngs[0].stat().st_size > 10000 print(f"[{'OK' if ok else 'FAIL'}] png saved: {pngs[0].name if pngs else 'NONE'} " f"({pngs[0].stat().st_size if pngs else 0} bytes), meta: {len(metas)}") fails += 0 if ok else 1 ok = "saved: " in result and "prompt=" in result print(f"[{'OK' if ok else 'FAIL'}] banner protocol lines present") fails += 0 if ok else 1 print(f"[{'OK' if not fails else 'FAIL'}] total fails={fails}") return 1 if fails else 0 if __name__ == "__main__": sys.exit(main())