Spaces:
Running on Zero
Running on Zero
| import os, io, base64 | |
| import spaces | |
| import torch | |
| import gradio as gr | |
| from PIL import Image | |
| from huggingface_hub import hf_hub_download | |
| from diffusers import StableDiffusionXLPipeline | |
| from transformers import CLIPVisionModelWithProjection, CLIPImageProcessor | |
| from msdiffusion.models.projection import Resampler | |
| from msdiffusion.models.model import MSAdapter | |
| from msdiffusion.utils import get_phrase_idx, get_eot_idx | |
| BASE = "stabilityai/stable-diffusion-xl-base-1.0" | |
| IMG_ENC = "laion/CLIP-ViT-bigG-14-laion2B-39B-b160k" | |
| NUM_TOKENS = 16 | |
| DTYPE = torch.float16 | |
| print("loading SDXL…") | |
| pipe = StableDiffusionXLPipeline.from_pretrained(BASE, torch_dtype=DTYPE, add_watermarker=False) | |
| print("loading CLIP image encoder…") | |
| image_encoder = CLIPVisionModelWithProjection.from_pretrained(IMG_ENC, torch_dtype=DTYPE) | |
| image_processor = CLIPImageProcessor() | |
| print("building resampler + MSAdapter…") | |
| image_proj_model = Resampler( | |
| dim=1280, depth=4, dim_head=64, heads=20, num_queries=NUM_TOKENS, | |
| embedding_dim=image_encoder.config.hidden_size, | |
| output_dim=pipe.unet.config.cross_attention_dim, ff_mult=4, | |
| latent_init_mode="grounding", | |
| phrase_embeddings_dim=pipe.text_encoder.config.projection_dim, | |
| ).to(dtype=DTYPE) | |
| ms_ckpt = hf_hub_download("doge1516/MS-Diffusion", "ms_adapter.bin") | |
| ms_model = MSAdapter(pipe.unet, image_proj_model, ckpt_path=ms_ckpt, device="cpu", num_tokens=NUM_TOKENS) | |
| ms_model.to(dtype=DTYPE) | |
| print("models ready (CPU); GPU attaches per-call.") | |
| def _b64_to_pil(s): | |
| if not s: | |
| return None | |
| if "," in s and s.strip().startswith("data:"): | |
| s = s.split(",", 1)[1] | |
| return Image.open(io.BytesIO(base64.b64decode(s))).convert("RGB").resize((512, 512)) | |
| def _phrase_idxes(phrases, prompt): | |
| res, cnt = [], {} | |
| for ph in phrases: | |
| k = cnt.get(ph, 0); cnt[ph] = k + 1 | |
| res.append(get_phrase_idx(pipe.tokenizer, ph, prompt, num=k)[0]) | |
| return res | |
| def generate(prompt, img1_b64, img2_b64, phrase1, phrase2, box1, box2, scale, seed, steps): | |
| dev = "cuda" | |
| pipe.to(dev); image_encoder.to(dev, dtype=DTYPE); ms_model.to(dev, dtype=DTYPE) | |
| ms_model.device = dev # generate() places tensors on self.device; must match cuda | |
| subs, phrases, boxes = [], [], [] | |
| for b64, ph, bx in ((img1_b64, phrase1, box1), (img2_b64, phrase2, box2)): | |
| im = _b64_to_pil(b64) | |
| if im is None: | |
| continue | |
| subs.append(im); phrases.append(ph.strip()) | |
| boxes.append([float(x) for x in bx.split(",")]) | |
| if not subs: | |
| return "" | |
| phrase_idxes = [_phrase_idxes(phrases, prompt)] | |
| eot_idxes = [[get_eot_idx(pipe.tokenizer, prompt)] * len(phrases)] | |
| images = ms_model.generate( | |
| pipe=pipe, pil_images=[subs], num_samples=1, | |
| num_inference_steps=int(steps), seed=int(seed), prompt=[prompt], scale=float(scale), | |
| image_encoder=image_encoder, image_processor=image_processor, boxes=[boxes], | |
| image_proj_type="resampler", image_encoder_type="clip", | |
| phrases=[phrases], drop_grounding_tokens=[0], | |
| phrase_idxes=phrase_idxes, eot_idxes=eot_idxes, | |
| height=1024, width=1024, mask_threshold=0.5, start_step=5, | |
| ) | |
| buf = io.BytesIO(); images[0].save(buf, "PNG") | |
| return base64.b64encode(buf.getvalue()).decode() | |
| demo = gr.Interface( | |
| fn=generate, | |
| inputs=[ | |
| gr.Textbox(label="prompt"), | |
| gr.Textbox(label="img1_b64"), gr.Textbox(label="img2_b64"), | |
| gr.Textbox(label="phrase1", value="a man"), gr.Textbox(label="phrase2", value="a man"), | |
| gr.Textbox(label="box1", value="0.0,0.25,0.45,0.95"), | |
| gr.Textbox(label="box2", value="0.55,0.25,1.0,0.95"), | |
| gr.Number(value=0.6, label="scale"), gr.Number(value=42, label="seed"), | |
| gr.Number(value=30, label="steps"), | |
| ], | |
| outputs=gr.Textbox(label="result_b64"), | |
| title="MS-Diffusion — layout-guided multi-subject (base64 API)", | |
| ) | |
| demo.queue(max_size=6).launch(server_name="0.0.0.0", server_port=7860) | |