Files
comfy-web/generate_examples.py
drjones 55bea5757c Comfy Apps: 12-workflow image-gen web GUI + payment frontend
- Flask frontend + serialized GPU worker + BTCPay invoice/webhook
- 12 example images rendered from the real ComfyUI workflows
- fix: ipadapter workflow uses modern IPAdapter node (was broken IPAdapterApply)
- helper scripts: generate/optimize examples
- README with deploy recipe
2026-08-27 20:37:11 -07:00

161 lines
6.1 KiB
Python

#!/usr/bin/env python3
"""
Generate one example image per Comfy App workflow and save to static/examples/.
Uses the real comfy_apps functions + comfy_workflows_lib builders against nightmare.
"""
import os, sys, shutil, time, json
from PIL import Image, ImageFilter, ImageDraw, ImageOps
sys.path.insert(0, os.path.expanduser("~/auto-publisher/core"))
import comfy_apps as CA
import comfy_workflows_lib as CL
BASE = os.path.expanduser("~/comfy-web")
EXAMPLES = os.path.join(BASE, "static", "examples")
os.makedirs(EXAMPLES, exist_ok=True)
def upload(local, name):
CL.upload_image(local, name=name)
print(f" uploaded {name}")
def save_result(app, local_path):
if not local_path or not os.path.exists(local_path):
print(f" [{app}] NO RESULT")
return False
ext = os.path.splitext(local_path)[1] or ".png"
dest = os.path.join(EXAMPLES, app + ext)
shutil.copy(local_path, dest)
print(f" [{app}] -> {dest} ({os.path.getsize(dest)//1024} KB)")
return True
def gen(app, fn, **params):
print(f"[{app}] building workflow...")
wf = fn(**params)
pid, err = CL.submit(wf)
if err:
print(f"[{app}] SUBMIT ERROR: {json.dumps(err)[:300]}")
return None
print(f"[{app}] pid={pid}, rendering...")
paths = CL.fetch_result(pid, timeout=900)
if not paths:
print(f"[{app}] TIMEOUT/FAILED")
return None
save_result(app, paths[0])
return paths[0]
# ---------------------------------------------------------------------------
# free GPU first
# ---------------------------------------------------------------------------
print("freeing GPU (unload ollama, apply comfy OC)...")
CL.free_gpu()
time.sleep(2)
results = {}
# 1. Text-to-image bases
print("\n=== BASE T2I ===")
results["logo"] = gen("logo", CA.app_logo,
prompt="minimalist geometric logo mark of a phoenix rising from flames, gold metallic on deep black, symmetrical vector emblem, clean lines, no text",
steps=8)
results["hero"] = gen("hero", CA.app_hero,
prompt="epic cinematic fantasy landscape, floating islands with waterfalls at golden sunset, volumetric god rays, dramatic clouds, ultra detailed",
steps=20)
results["article"] = gen("article", CA.app_article,
prompt="photorealistic over-the-shoulder shot of a barista pouring latte art in a sunlit cafe, shallow depth of field, morning light, editorial photography",
steps=8)
results["portrait"] = gen("portrait", CA.app_portrait,
prompt="professional studio portrait of a woman in her 30s, soft window light, warm tones, sharp focus, 85mm, head and shoulders",
steps=8)
# upload base images to ComfyUI input/ for the derived apps
print("\n=== UPLOADING BASES ===")
names = {}
for app, p in results.items():
if p and os.path.exists(p):
n = f"base_{app}.png"
upload(p, n)
names[app] = n
# make a low-res version of the portrait for upscale/restore_face demo
lowres_path = None
if results.get("portrait"):
im = Image.open(results["portrait"]).convert("RGB")
im = im.resize((192, 256), Image.LANCZOS)
lowres_path = os.path.join(BASE, "uploads", "base_lowres.png")
im.save(lowres_path)
upload(lowres_path, "base_lowres.png")
print(" created low-res portrait (192x256) for upscale demo")
# make an inpaint mask (white blob on black) for the article image
mask_path = os.path.join(BASE, "uploads", "inpaint_mask.png")
if results.get("article"):
a = Image.open(results["article"])
m = Image.new("L", a.size, 0)
d = ImageDraw.Draw(m)
w, h = a.size
d.ellipse([w*0.35, h*0.25, w*0.75, h*0.75], fill=255)
m.save(mask_path)
upload(mask_path, "inpaint_mask.png")
print(" created inpaint mask")
# make a canny-ish control image from the article
control_path = os.path.join(BASE, "uploads", "control_canny.png")
if results.get("article"):
a = Image.open(results["article"]).convert("L")
e = a.filter(ImageFilter.FIND_EDGES)
e = ImageOps.autocontrast(e)
e.save(control_path)
upload(control_path, "control_canny.png")
print(" created control edge image")
# 2. Derived apps
print("\n=== DERIVED ===")
if names.get("hero"):
results["banner"] = gen("banner", CA.app_banner,
image_name=names["hero"], prompt="epic cinematic fantasy landscape, floating islands, golden sunset, seamless extension",
left=192, right=192, steps=25)
if names.get("portrait"):
results["outpaint"] = gen("outpaint", CA.app_outpaint,
image_name=names["portrait"], prompt="extend the studio backdrop with soft bokeh lights, seamless",
left=96, right=96, top=64, bottom=64, steps=25)
if names.get("article") and os.path.exists(mask_path):
results["inpaint"] = gen("inpaint", CA.app_inpaint,
image_name=names["article"], mask_name="inpaint_mask.png",
prompt="a glowing golden espresso machine with steam", steps=20, denoise=0.7)
if lowres_path:
results["upscale"] = gen("upscale", CA.app_upscale,
image_name="base_lowres.png", upscaler="4x-UltraSharp.pth")
results["restore_face"] = gen("restore_face", CA.app_restore_face,
image_name="base_lowres.png", upscaler="RealESRGAN_x4.pth")
if names.get("hero"):
results["ipadapter"] = gen("ipadapter", CA.app_ipadapter,
style_image=names["hero"],
prompt="a cozy cottage by a lake at sunset, same painterly style", steps=20, cfg=7.0)
if os.path.exists(control_path):
results["controlnet"] = gen("controlnet", CA.app_controlnet,
prompt="a detailed illustration of a barista in a cafe, line art", control_image="control_canny.png",
control_type="canny", steps=20, cfg=7.0)
if names.get("portrait"):
try:
results["face_swap"] = gen("face_swap", CA.app_face_swap,
face_image=names["portrait"],
prompt="a samurai warrior in full ornate armor, studio lighting, dramatic", steps=20)
except Exception as e:
print(f"[face_swap] ERROR: {e}")
# restore GPU
print("\nrestoring GPU (ollama OC profile)...")
CL.restore_gpu()
# summary
print("\n=== SUMMARY ===")
for app, p in results.items():
status = "OK" if (p and os.path.exists(p)) else "MISSING"
print(f" {app:14s} {status}")