zcbot/scripts/test_gpt_image_manual.py

101 lines
4.2 KiB
Python

"""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())