| import base64 |
| import io |
| import torch |
| import spaces |
| from PIL import Image |
| from diffusers import StableDiffusionXLControlNetPipeline, ControlNetModel |
|
|
| _pipe = None |
|
|
|
|
| def _load_pipeline(): |
| global _pipe |
| if _pipe is not None: |
| return _pipe |
|
|
| print("Loading ControlNet...") |
| controlnet = ControlNetModel.from_pretrained( |
| "xinsir/controlnet-scribble-sdxl-1.0", |
| torch_dtype=torch.float16, |
| ) |
|
|
| print("Loading SDXL...") |
| _pipe = StableDiffusionXLControlNetPipeline.from_pretrained( |
| "stabilityai/stable-diffusion-xl-base-1.0", |
| controlnet=controlnet, |
| torch_dtype=torch.float16, |
| variant="fp16", |
| use_safetensors=True, |
| ).to("cuda") |
|
|
| _pipe.enable_attention_slicing() |
| _pipe.enable_vae_slicing() |
|
|
| print("Pipeline ready.") |
| return _pipe |
|
|
|
|
| def _b64_to_pil(b64: str) -> Image.Image: |
| |
| if "," in b64: |
| b64 = b64.split(",", 1)[1] |
| return Image.open(io.BytesIO(base64.b64decode(b64))).convert("RGB") |
|
|
|
|
| def _pil_to_b64(img: Image.Image) -> str: |
| buf = io.BytesIO() |
| img.save(buf, format="PNG") |
| return base64.b64encode(buf.getvalue()).decode() |
|
|
|
|
| @spaces.GPU(duration=120) |
| def generate(sketch_b64: str, description: str, strength: float = 0.7) -> str: |
| pipe = _load_pipeline() |
|
|
| sketch = _b64_to_pil(sketch_b64).resize((1024, 1024)) |
|
|
| negative_prompt = ( |
| "ugly, blurry, low quality, distorted, deformed, watermark, text, signature" |
| ) |
|
|
| result = pipe( |
| prompt=description, |
| negative_prompt=negative_prompt, |
| image=sketch, |
| controlnet_conditioning_scale=strength, |
| num_inference_steps=30, |
| guidance_scale=7.5, |
| height=1024, |
| width=1024, |
| ).images[0] |
|
|
| return _pil_to_b64(result) |
|
|