Spaces:
Sleeping
Sleeping
| import os | |
| import gradio as gr | |
| import numpy as np | |
| from PIL import Image, ImageOps | |
| import torch | |
| from diffusers import StableDiffusionImg2ImgPipeline, EulerAncestralDiscreteScheduler | |
| # ----------------------------- | |
| # CPU performance knobs | |
| # ----------------------------- | |
| os.environ["OMP_NUM_THREADS"] = "2" | |
| os.environ["MKL_NUM_THREADS"] = "2" | |
| try: | |
| torch.set_num_threads(2) | |
| except Exception: | |
| pass | |
| torch.set_grad_enabled(False) | |
| device = "cpu" | |
| dtype = torch.float32 | |
| MODEL_ID = "runwayml/stable-diffusion-v1-5" | |
| pipe = StableDiffusionImg2ImgPipeline.from_pretrained( | |
| MODEL_ID, | |
| torch_dtype=dtype, | |
| safety_checker=None, | |
| requires_safety_checker=False, | |
| ) | |
| pipe.scheduler = EulerAncestralDiscreteScheduler.from_config(pipe.scheduler.config) | |
| pipe = pipe.to(device) | |
| # Make diffusers quieter / slightly faster | |
| pipe.set_progress_bar_config(disable=True) | |
| # Helpful on CPU | |
| try: | |
| pipe.enable_attention_slicing() | |
| except Exception: | |
| pass | |
| # VAE optimizations (often helps) | |
| try: | |
| pipe.enable_vae_slicing() | |
| except Exception: | |
| pass | |
| try: | |
| pipe.enable_vae_tiling() | |
| except Exception: | |
| pass | |
| # ----------------------------- | |
| # Image utils | |
| # ----------------------------- | |
| def _to_pil(img_np): | |
| if img_np is None: | |
| return None | |
| if isinstance(img_np, Image.Image): | |
| return img_np.convert("RGB") | |
| arr = np.asarray(img_np) | |
| if arr.dtype != np.uint8: | |
| arr = np.clip(arr, 0, 255).astype(np.uint8) | |
| if arr.ndim == 3 and arr.shape[2] == 4: | |
| arr = arr[:, :, :3] | |
| return Image.fromarray(arr).convert("RGB") | |
| def _center_square(pil_img: Image.Image, out_size=512): | |
| w, h = pil_img.size | |
| s = min(w, h) | |
| left = (w - s) // 2 | |
| top = (h - s) // 2 | |
| pil_img = pil_img.crop((left, top, left + s, top + s)) | |
| pil_img = pil_img.resize((out_size, out_size), Image.LANCZOS) | |
| return pil_img | |
| def _blend_parents(dad_pil, mom_pil, out_size=512): | |
| dad = _center_square(dad_pil, out_size) | |
| mom = _center_square(mom_pil, out_size) | |
| blended = Image.blend(dad, mom, alpha=0.5) | |
| blended = ImageOps.autocontrast(blended, cutoff=1) | |
| return blended | |
| # ----------------------------- | |
| # Generation | |
| # ----------------------------- | |
| def generate_cartoon_kid( | |
| dad_np, | |
| mom_np, | |
| age, | |
| style_strength, | |
| steps, | |
| guidance_scale, | |
| seed, | |
| extra_prompt, | |
| negative_prompt | |
| ): | |
| dad = _to_pil(dad_np) | |
| mom = _to_pil(mom_np) | |
| if dad is None or mom is None: | |
| raise gr.Error("ارفع صورتين: الأب + الأم.") | |
| init = _blend_parents(dad, mom, out_size=512) | |
| # ✅ Faster on CPU: 256 instead of 384 | |
| init_small = init.resize((256, 256), Image.LANCZOS) | |
| base_prompt = ( | |
| "cute 3d animated child portrait, pixar-like style, " | |
| "soft studio lighting, smooth skin, big friendly eyes, " | |
| "high quality, centered face, clean background" | |
| ) | |
| age = int(age) | |
| if age <= 7: | |
| age_prompt = f"a {age}-year-old kid, very cute, youthful" | |
| elif age <= 12: | |
| age_prompt = f"a {age}-year-old pre-teen kid, youthful" | |
| else: | |
| age_prompt = f"a {age}-year-old teen, youthful" | |
| prompt = f"{base_prompt}, {age_prompt}" | |
| if extra_prompt and extra_prompt.strip(): | |
| prompt = f"{prompt}, {extra_prompt.strip()}" | |
| if seed is None or int(seed) < 0: | |
| seed = np.random.randint(0, 2**31 - 1) | |
| gen = torch.Generator(device=device).manual_seed(int(seed)) | |
| strength = float(style_strength) | |
| # ✅ Inference mode saves overhead | |
| with torch.inference_mode(): | |
| out = pipe( | |
| prompt=prompt, | |
| negative_prompt=negative_prompt, | |
| image=init_small, | |
| strength=strength, | |
| num_inference_steps=int(steps), | |
| guidance_scale=float(guidance_scale), | |
| generator=gen, | |
| ).images[0] | |
| out = out.resize((512, 512), Image.LANCZOS) | |
| return init, out, int(seed), prompt | |
| # ----------------------------- | |
| # UI (same) | |
| # ----------------------------- | |
| with gr.Blocks() as demo: | |
| gr.Markdown("# 👶 Kid Generator — Cartoon (CPU)\nFaster CPU settings (256px + fewer steps).") | |
| with gr.Row(): | |
| dad_in = gr.Image(type="numpy", label="Father") | |
| mom_in = gr.Image(type="numpy", label="Mother") | |
| with gr.Row(): | |
| age = gr.Slider(4, 15, value=11, step=1, label="Age") | |
| style_strength = gr.Slider(0.45, 0.85, value=0.65, step=0.01, label="Cartoon Strength") | |
| with gr.Row(): | |
| # ✅ recommend smaller steps default | |
| steps = gr.Slider(6, 20, value=10, step=1, label="Steps (CPU faster)") | |
| guidance_scale = gr.Slider(3, 8, value=5.5, step=0.1, label="Guidance Scale") | |
| seed = gr.Number(value=-1, precision=0, label="Seed (-1 random)") | |
| extra_prompt = gr.Textbox(label="Extra Prompt (optional)", placeholder="smiling, curly hair, freckles") | |
| negative_prompt = gr.Textbox( | |
| label="Negative Prompt", | |
| value="realistic photo, ugly, deformed, blurry, low quality, watermark, text, scary, old, wrinkles" | |
| ) | |
| btn = gr.Button("Generate Cartoon Kid", variant="primary") | |
| with gr.Row(): | |
| init_out = gr.Image(label="Blended Parents (Init)") | |
| out_img = gr.Image(label="Cartoon Kid Result") | |
| used_seed = gr.Number(label="Used Seed", precision=0) | |
| used_prompt = gr.Textbox(label="Used Prompt") | |
| btn.click( | |
| fn=generate_cartoon_kid, | |
| inputs=[dad_in, mom_in, age, style_strength, steps, guidance_scale, seed, extra_prompt, negative_prompt], | |
| outputs=[init_out, out_img, used_seed, used_prompt], | |
| ) | |
| demo.launch() | |