"""Manual staging smoke check for a real ComfyUI server. This script is intentionally opt-in. It never runs from pytest/CI by default and does not include customer images, S3 calls, or real image generation. """ from __future__ import annotations import os import sys import urllib.error import urllib.request from io import BytesIO from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parents[1])) from PIL import Image from app.core.config import settings from app.services.comfyui_client import ( AIErrorCode, ComfyUIUnavailable, FaceSwapRequest, FakeComfyUIClient, build_face_only_payload, ) def _enabled() -> bool: return os.getenv("ENABLE_STAGING_COMFYUI_SMOKE", "").lower() == "true" def _dummy_png() -> bytes: buf = BytesIO() Image.new("RGB", (512, 512), (180, 180, 180)).save(buf, format="PNG") return buf.getvalue() def _check_reachable(base_url: str, timeout: int) -> None: url = f"{base_url.rstrip('/')}/system_stats" req = urllib.request.Request(url, headers={"User-Agent": "leechard-staging-smoke"}) with urllib.request.urlopen(req, timeout=timeout) as resp: # noqa: S310 if resp.status >= 400: raise ComfyUIUnavailable(f"ComfyUI returned HTTP {resp.status}") def main() -> int: if not _enabled(): print("SKIP: set ENABLE_STAGING_COMFYUI_SMOKE=true to contact ComfyUI.") return 0 if settings.ai_provider != "comfyui": print("SKIP: AI_PROVIDER must be comfyui for staging ComfyUI smoke.") return 0 if not settings.comfyui_require_server: print("SKIP: COMFYUI_REQUIRE_SERVER must be true for real server smoke.") return 0 if not settings.comfyui_base_url: print("SKIP: COMFYUI_BASE_URL is not configured.") return 0 req = FaceSwapRequest( image_bytes=_dummy_png(), mime="image/png", face_boxes=[(192, 160, 128, 128)], model_identity_id="virtual_default", ) payload = build_face_only_payload(req) mask = payload["mask"] print("OK: face-only payload generated.") print(f"workflow_name={payload['workflow_name']}") print(f"mode={payload['mode']}") print(f"edit_region={payload['edit_region']}") print(f"denoise_outside_mask={payload['denoise_outside_mask']}") print( "mask=" f"erode:{mask['face_mask_erode_px']} " f"inset:{mask['mask_inset_px']} " f"hairline:{mask['hairline_protection_px']}" ) fake = FakeComfyUIClient() for simulate, expected in ( ("timeout", AIErrorCode.COMFYUI_TIMEOUT.value), ("unavailable", AIErrorCode.COMFYUI_UNAVAILABLE.value), ): try: fake.face_only_transform( FaceSwapRequest( image_bytes=req.image_bytes, mime=req.mime, face_boxes=req.face_boxes, simulate=simulate, ) ) except Exception as exc: # noqa: BLE001 code = getattr(exc, "code", None) if code != expected: print(f"FAIL: simulate={simulate} returned error_code={code}") return 1 print(f"OK: simulate={simulate} returned error_code={code}") try: _check_reachable(settings.comfyui_base_url, settings.comfyui_timeout_seconds) except urllib.error.URLError as exc: print(f"FAIL: ComfyUI is not reachable: {exc.reason}") return 1 except TimeoutError: print("FAIL: ComfyUI reachability check timed out.") return 1 except Exception as exc: # noqa: BLE001 print(f"FAIL: ComfyUI reachability check failed: {exc}") return 1 print("OK: ComfyUI base URL is reachable.") print("NOTE: real image generation is intentionally not executed by this smoke.") return 0 if __name__ == "__main__": sys.exit(main())