From 5c80e65d58a92d2666d01376235907d7a2c939e2 Mon Sep 17 00:00:00 2001 From: type-two Date: Fri, 24 Jul 2026 18:14:21 +1000 Subject: [PATCH] Salvage the SD lane: patch MODELBEAST, add the SD backend, fix the assets filter at source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The LoRA bench concluded the SD1.5 lane was invalid for garments. That was true of the CHECKPOINT, not the lane: Hyper_Realism_1.2 was the only one the farm could reach and it is a person-photoreal merge that framed every garment as worn-and-cropped no matter how hard you negative-prompted. Given four non-person checkpoints, the lane works — and now beats flux. MODELBEAST patches (John's explicit blessing; flux_local deliberately untouched because a parallel session owned it and had already deployed LoRA + Z-Image support there): · comfyui_sd now STACKS LoRAs. It hard-coded a single LoraLoader, so style+texture together was impossible; `lora` now takes a list, each entry optionally `name=0.6`, chained. · comfyui_sd gains ControlNet (loader + ApplyAdvanced + staged control image). The payoff for a wardrobe is recolouring one garment into N colourways that share a byte-identical silhouette, so a single cut-out alpha is reusable across every variant. · Per-node preflight widened to LoRAs and ControlNets, and the arch-mismatch warning now fires per LoRA. A wrong-base LoRA is a SILENT no-op, so everything fails loudly instead. · Deployed to all three nodes that run comfyui_sd (m3ultra, ultra=m1, m4pro=m4), each backed up. · GET /api/assets now honours ?parent_job=. It declared no such parameter, so FastAPI silently dropped it and every caller got the whole table — 2,578 rows for a bogus id. Callers that took rows[0] were right only by accident of newest-first ordering. Verified: bogus -> 0 rows, real -> only its own. Restarted the queue in a zero-active-jobs window. · Copied 4 non-person checkpoints ultra -> m3ultra over the fast LAN (12.6 GB). wardrobegod: · `sd` backend on /api/gen, defaulting to juggernautXL_ragnarok, with checkpoint/lora/negative passthrough. Measured on one prompt+seed: a full isolated flat-lay where Hyper_Realism crops a worn garment. · flat3d template gains 'no hanger, no coat hanger' — a wire hanger appeared in most SD product shots and keys into the cutout as if it were garment. doll2d already had the clause. Verified end-to-end: 7/7 salvage cells ran (including a 2-LoRA stack, previously impossible), and a Coogi knit generated through wardrobegod's own /api/gen came back isolated on white with legible raised-knit texture. Co-Authored-By: Claude Opus 4.8 --- server.py | 35 +++++++++++++++++++++++++++++++++-- web/index.html | 1 + 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/server.py b/server.py index 78fd90e..bf4e2cb 100644 --- a/server.py +++ b/server.py @@ -116,9 +116,11 @@ def doll_catalogue(): # keying cleanly (7/7 flood seeds) on both a dark solid and a busy multicolour knit, so # white is the default and green is the escape hatch, not the other way round. TEMPLATES = { + # 'no hanger, no coat hanger' is not padding: without it a wire hanger showed up in most + # SD product shots (and some flux ones), and a hanger keys into the cutout as garment. 'flat3d': ('product photo of a single {phrase} laid flat on a plain white background, front view, ' - 'no mannequin, no person, no text, soft even lighting, 1990s Australian op-shop garment, ' - 'slightly worn'), + 'no mannequin, no person, no hanger, no coat hanger, no text, soft even lighting, ' + '1990s Australian op-shop garment, slightly worn'), 'doll2d': ('paper doll clothing item for a dress-up game, {phrase}, {year} australia, {view}, ' 'floating centered on a plain pure white background, painterly stylized 3d game ' 'illustration, full item visible, no body, no person, no mannequin, no hanger, ' @@ -133,6 +135,15 @@ DOLL_PROMPT = TEMPLATES['doll2d_green'] # back-compat alias FLAT_PROMPT = TEMPLATES['flat3d'] +# The SD lane's default. Hyper_Realism was the only checkpoint the farm could reach and it is a +# person-photoreal merge — it framed every garment as worn-and-cropped no matter how hard you +# negative-prompted. juggernautXL is a product/material specialist; measured on the same +# prompt+seed it returns a clean isolated flat-lay. +SD_CKPT = os.environ.get('WG_SD_CKPT', 'juggernautXL_ragnarok.safetensors') +SD_NEG = ('person, human, body, model, mannequin, face, hands, legs, worn by someone, ' + 'hanger, coat hanger, (worst quality, low quality:1.4), blurry, watermark, text') + + def gen_seed(phrase, variant=0): """Reproducible seed from the phrase — reroll by bumping `variant`. @@ -596,6 +607,26 @@ class H(BaseHTTPRequestHandler): with open(tgt, 'wb') as f: f.write(base64.b64decode(out['result']['image'])) return tgt + if backend == 'sd': + # SDXL via ComfyUI. juggernautXL is a product/material specialist and beats + # the SD1.5 default outright: measured side by side on the same prompt+seed it + # gives a full isolated flat-lay, where Hyper_Realism frames the garment as + # worn and crops it at the edge. `lora` may be a list — the operator chains them. + JOBS[jid]['note'] = 'comfyui_sd ' + body.get('checkpoint', SD_CKPT) + params = {'prompt': style, 'negative': body.get('negative', SD_NEG), + 'checkpoint': body.get('checkpoint', SD_CKPT), + 'steps': int(body.get('steps') or 25), 'cfg': float(body.get('cfg', 7.0)), + 'width': wide, 'height': wide, 'seed': seed} + if body.get('lora'): + params['lora'] = body['lora'] + params['lora_weight'] = body.get('lora_weight', 0.8) + j = mb_req('/api/jobs', {'operator': 'comfyui_sd', 'params': params}) + gid = j.get('id') or j.get('job_id') + mb_wait(gid, jid, timeout=900) + outs = mb_outputs(gid) + if not outs: + raise RuntimeError('no image came back') + return mb_download(outs[0], tgt) JOBS[jid]['note'] = 'flux_local klein-4b' j = mb_req('/api/jobs', {'operator': 'flux_local', 'params': {'prompt': style, 'model': 'flux2-klein-4b', diff --git a/web/index.html b/web/index.html index f436b0e..6356dee 100644 --- a/web/index.html +++ b/web/index.html @@ -177,6 +177,7 @@