| import importlib |
| import random |
|
|
| |
| spaces = None |
| try: |
| spaces = importlib.import_module("spaces") |
| HAS_SPACES = True |
| except ImportError: |
| HAS_SPACES = False |
|
|
| import gradio as gr |
| import torch |
|
|
| |
| try: |
| from transformers.models.qwen3_vl.modeling_qwen3_vl import ( |
| Qwen3VLTextRotaryEmbedding, |
| ) |
|
|
| old_init = Qwen3VLTextRotaryEmbedding.__init__ |
|
|
| def patched_init(self, config, *args, **kwargs): |
| if getattr(config, "rope_scaling", None) is None: |
| config.rope_scaling = { |
| "mrope_section": [24, 20, 20], |
| "rope_type": "default", |
| } |
| old_init(self, config, *args, **kwargs) |
|
|
| Qwen3VLTextRotaryEmbedding.__init__ = patched_init |
| print("Successfully patched Qwen3VLTextRotaryEmbedding.__init__") |
| except Exception as patch_err: |
| print(f"Skipping transformers patch: {patch_err}") |
|
|
| |
| try: |
| import gradio_client.utils as gr_utils |
|
|
| old_json_schema = gr_utils._json_schema_to_python_type |
|
|
| def patched_json_schema(schema, *args, **kwargs): |
| if isinstance(schema, bool): |
| return "Any" |
| return old_json_schema(schema, *args, **kwargs) |
|
|
| gr_utils._json_schema_to_python_type = patched_json_schema |
| print("Successfully patched gradio_client._json_schema_to_python_type") |
| except Exception as patch_err: |
| print(f"Skipping gradio_client patch: {patch_err}") |
|
|
| from diffusers import Krea2Pipeline |
|
|
| |
| |
| device = "cuda" if torch.cuda.is_available() else "cpu" |
| dtype = torch.bfloat16 if device == "cuda" else torch.float32 |
|
|
| print(f"Loading Krea-2-Turbo model. Device: {device}, Dtype: {dtype}") |
|
|
| |
| from transformers import Qwen2TokenizerFast |
|
|
| tokenizer = Qwen2TokenizerFast.from_pretrained( |
| "krea/Krea-2-Turbo", subfolder="tokenizer", extra_special_tokens={} |
| ) |
|
|
| |
| |
| pipe = Krea2Pipeline.from_pretrained( |
| "krea/Krea-2-Turbo", tokenizer=tokenizer, torch_dtype=dtype, use_safetensors=True |
| ).to(device) |
|
|
| |
| |
| custom_css = """ |
| @import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap'); |
| |
| :root, |
| html, |
| body, |
| .gradio-container, |
| .gradio-container.dark { |
| color-scheme: light !important; |
| --body-background-fill: #f8fafc !important; |
| --body-text-color: #0f172a !important; |
| --block-background-fill: rgba(255, 255, 255, 0.86) !important; |
| --block-border-color: rgba(148, 163, 184, 0.28) !important; |
| --input-background-fill: #ffffff !important; |
| --input-border-color: #cbd5e1 !important; |
| --input-placeholder-color: #94a3b8 !important; |
| --neutral-50: #f8fafc !important; |
| --neutral-100: #f1f5f9 !important; |
| --neutral-200: #e2e8f0 !important; |
| --neutral-700: #334155 !important; |
| --neutral-800: #1e293b !important; |
| --neutral-900: #0f172a !important; |
| } |
| |
| body, .gradio-container, .gradio-container.dark { |
| font-family: 'Outfit', sans-serif !important; |
| background: |
| radial-gradient(circle at top left, rgba(216, 180, 254, 0.46), transparent 32%), |
| radial-gradient(circle at top right, rgba(147, 197, 253, 0.38), transparent 34%), |
| linear-gradient(135deg, #ffffff 0%, #f8fafc 45%, #eef2ff 100%) !important; |
| color: #0f172a !important; |
| } |
| |
| /* App container centering */ |
| .app-container { |
| max-width: 1200px !important; |
| margin: 0 auto !important; |
| padding: 20px !important; |
| } |
| |
| /* Main header card */ |
| .header { |
| text-align: center; |
| margin-bottom: 2.5rem; |
| padding: 2.5rem; |
| background: rgba(255, 255, 255, 0.78); |
| backdrop-filter: blur(18px); |
| border: 1px solid rgba(148, 163, 184, 0.28); |
| border-radius: 24px; |
| box-shadow: 0 18px 50px rgba(99, 102, 241, 0.14); |
| } |
| |
| .header h1 { |
| font-size: 3.2rem !important; |
| font-weight: 800 !important; |
| background: linear-gradient(90deg, #c026d3, #7c3aed, #2563eb); |
| -webkit-background-clip: text !important; |
| -webkit-text-fill-color: transparent !important; |
| margin-bottom: 0.5rem !important; |
| letter-spacing: -0.02em; |
| text-shadow: 0 10px 30px rgba(124, 58, 237, 0.16); |
| } |
| |
| .header p { |
| font-size: 1.1rem !important; |
| color: #475569 !important; |
| max-width: 600px; |
| margin: 0 auto !important; |
| line-height: 1.6; |
| } |
| |
| /* Custom panels */ |
| .glass-panel { |
| background: rgba(255, 255, 255, 0.84) !important; |
| backdrop-filter: blur(16px) !important; |
| border: 1px solid rgba(148, 163, 184, 0.26) !important; |
| border-radius: 20px !important; |
| box-shadow: 0 14px 38px rgba(15, 23, 42, 0.08) !important; |
| padding: 1.5rem !important; |
| transition: border-color 0.3s ease, box-shadow 0.3s ease !important; |
| } |
| |
| .glass-panel:hover { |
| border-color: rgba(124, 58, 237, 0.34) !important; |
| box-shadow: 0 18px 45px rgba(124, 58, 237, 0.14) !important; |
| } |
| |
| /* Call-to-action generate button */ |
| .btn-generate { |
| background: linear-gradient(135deg, #d946ef 0%, #8b5cf6 50%, #6366f1 100%) !important; |
| color: white !important; |
| border: none !important; |
| border-radius: 12px !important; |
| font-weight: 700 !important; |
| text-transform: uppercase !important; |
| letter-spacing: 0.05em !important; |
| padding: 12px 24px !important; |
| transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important; |
| box-shadow: 0 8px 22px rgba(139, 92, 246, 0.32) !important; |
| } |
| |
| .btn-generate:hover { |
| transform: translateY(-2px) !important; |
| box-shadow: 0 12px 28px rgba(139, 92, 246, 0.44) !important; |
| } |
| |
| .btn-generate:active { |
| transform: translateY(1px) !important; |
| } |
| |
| /* Styled inputs and select elements */ |
| .gradio-container input, |
| .gradio-container textarea, |
| .gradio-container select, |
| .gradio-container.dark input, |
| .gradio-container.dark textarea, |
| .gradio-container.dark select { |
| background-color: #ffffff !important; |
| border: 1px solid #cbd5e1 !important; |
| color: #0f172a !important; |
| border-radius: 12px !important; |
| padding: 10px 14px !important; |
| font-size: 0.95rem !important; |
| transition: all 0.2s ease !important; |
| } |
| |
| .gradio-container input:focus, |
| .gradio-container textarea:focus, |
| .gradio-container select:focus { |
| border-color: #8b5cf6 !important; |
| box-shadow: 0 0 0 2px rgba(139, 92, 246, 0.22) !important; |
| } |
| |
| .gradio-container label, |
| .gradio-container .prose, |
| .gradio-container .markdown, |
| .gradio-container.dark label, |
| .gradio-container.dark .prose, |
| .gradio-container.dark .markdown { |
| color: #1e293b !important; |
| } |
| |
| /* Custom License badge styling */ |
| .badge-license { |
| display: inline-block; |
| padding: 5px 12px; |
| border-radius: 100px; |
| background: rgba(139, 92, 246, 0.12); |
| color: #7c3aed; |
| font-size: 0.825rem; |
| font-weight: 600; |
| border: 1px solid rgba(139, 92, 246, 0.22); |
| margin-top: 1rem; |
| } |
| """ |
|
|
|
|
| def infer(prompt, style, aspect_ratio, steps, guidance_scale, seed): |
| |
| style_prompts = { |
| "None": "{prompt}", |
| "Cinematic": "{prompt}, cinematic shot, 35mm lens, depth of field, anamorphic flare, professional lighting, photorealistic, 8k", |
| "Photorealistic": "{prompt}, photorealistic, ultra-detailed, 8k resolution, highly detailed, dramatic lighting, sharp focus", |
| "Digital Art": "{prompt}, digital painting, concept art, sharp focus, vibrant colors, detailed, artstation trending", |
| "Fantasy / Mythic": "{prompt}, high fantasy, magical, ethereal, concept art, mystical lighting, detailed, epic composition", |
| "Cyberpunk": "{prompt}, cyberpunk aesthetic, neon lights, futuristic city, highly detailed, dark synthwave style, raytracing", |
| "Anime / Manga": "{prompt}, anime style, colorful, studio ghibli, detailed background, vibrant, aesthetic key visual, 4k", |
| "Vintage Film": "{prompt}, vintage photograph, film grain, muted colors, nostalgic, warm lighting, old photo style", |
| } |
|
|
| formatted_prompt = style_prompts.get(style, "{prompt}").format(prompt=prompt) |
|
|
| |
| aspect_ratios = { |
| "1:1 Square (1024x1024)": (1024, 1024), |
| "9:16 Vertical (768x1360)": (768, 1360), |
| "16:9 Landscape (1360x768)": (1360, 768), |
| "4:3 Portrait (896x1152)": (896, 1152), |
| "3:4 Landscape (1152x896)": (1152, 896), |
| } |
| width, height = aspect_ratios.get(aspect_ratio, (1024, 1024)) |
|
|
| |
| if seed == -1 or seed is None: |
| seed = random.randint(0, 2**32 - 1) |
| else: |
| seed = int(seed) |
|
|
| generator = torch.Generator(device=device).manual_seed(seed) |
|
|
| |
| |
| image = pipe( |
| prompt=formatted_prompt, |
| width=width, |
| height=height, |
| num_inference_steps=int(steps), |
| guidance_scale=float(guidance_scale), |
| generator=generator, |
| ).images[0] |
|
|
| return image, seed |
|
|
|
|
| |
| if HAS_SPACES and spaces is not None: |
| generate_fn = getattr(spaces, "GPU")(duration=35)(infer) |
| else: |
| generate_fn = infer |
|
|
| |
| theme = gr.themes.Default(primary_hue="purple", secondary_hue="indigo") |
|
|
| with gr.Blocks() as demo: |
| with gr.Column(elem_classes="app-container"): |
| gr.HTML(""" |
| <div class="header"> |
| <h1>⚡ Kreatin</h1> |
| <p>Create polished images fast with a clean prompt studio powered by Krea 2 Turbo, Krea's distilled 12B parameter Diffusion Transformer optimized for 8-step generation.</p> |
| <span class="badge-license">Powered by Krea 2 Turbo • Krea 2 Community License</span> |
| </div> |
| """) |
|
|
| with gr.Row(): |
| with gr.Column(scale=5): |
| with gr.Group(elem_classes="glass-panel"): |
| prompt = gr.Textbox( |
| label="Prompt", |
| placeholder="Describe the image you want to create...", |
| lines=3, |
| elem_id="prompt-input", |
| ) |
|
|
| with gr.Row(): |
| style = gr.Dropdown( |
| label="Style Preset", |
| choices=[ |
| "None", |
| "Cinematic", |
| "Photorealistic", |
| "Digital Art", |
| "Fantasy / Mythic", |
| "Cyberpunk", |
| "Anime / Manga", |
| "Vintage Film", |
| ], |
| value="None", |
| ) |
|
|
| aspect_ratio = gr.Dropdown( |
| label="Aspect Ratio", |
| choices=[ |
| "1:1 Square (1024x1024)", |
| "9:16 Vertical (768x1360)", |
| "16:9 Landscape (1360x768)", |
| "4:3 Portrait (896x1152)", |
| "3:4 Landscape (1152x896)", |
| ], |
| value="1:1 Square (1024x1024)", |
| ) |
|
|
| generate_btn = gr.Button( |
| "Generate Image", elem_classes="btn-generate" |
| ) |
|
|
| with gr.Accordion( |
| "Advanced Settings", open=False, elem_classes="glass-panel" |
| ): |
| with gr.Row(): |
| steps = gr.Slider( |
| label="Inference Steps", |
| minimum=1, |
| maximum=25, |
| step=1, |
| value=8, |
| info="Turbo is optimized for 8 steps.", |
| ) |
|
|
| guidance_scale = gr.Slider( |
| label="Guidance Scale (CFG)", |
| minimum=0.0, |
| maximum=10.0, |
| step=0.1, |
| value=0.0, |
| info="Turbo model works best with 0.0 guidance scale.", |
| ) |
|
|
| seed = gr.Number( |
| label="Seed (-1 for random)", value=-1, precision=0 |
| ) |
|
|
| with gr.Column(scale=5): |
| with gr.Group(elem_classes="glass-panel"): |
| output_image = gr.Image( |
| label="Generated Output", |
| type="pil", |
| interactive=False, |
| ) |
|
|
| with gr.Row(): |
| used_seed = gr.Number( |
| label="Used Seed", interactive=False, precision=0 |
| ) |
|
|
| |
| generate_btn.click( |
| fn=generate_fn, |
| inputs=[prompt, style, aspect_ratio, steps, guidance_scale, seed], |
| outputs=[output_image, used_seed], |
| ) |
|
|
| |
| prompt.submit( |
| fn=generate_fn, |
| inputs=[prompt, style, aspect_ratio, steps, guidance_scale, seed], |
| outputs=[output_image, used_seed], |
| ) |
|
|
| gr.HTML("<br>") |
|
|
| |
| gr.Examples( |
| examples=[ |
| [ |
| "A stunning close-up portrait of a majestic lion with glowing cyan eyes, digital art, highly detailed", |
| "Digital Art", |
| "1:1 Square (1024x1024)", |
| 8, |
| 0.0, |
| 42, |
| ], |
| [ |
| "A futuristic cyberpunk street at night, neon reflections in the puddles, rain, cinematic lighting, 8k", |
| "Cyberpunk", |
| "16:9 Landscape (1360x768)", |
| 8, |
| 0.0, |
| 1337, |
| ], |
| [ |
| "An enchanted cottage in the middle of a mystical forest, fireflies, high fantasy, warm volumetric light", |
| "Fantasy / Mythic", |
| "4:3 Portrait (896x1152)", |
| 8, |
| 0.0, |
| 999, |
| ], |
| [ |
| "A high-fashion editorial photo of a model in a vibrant flowing dress, architectural backdrop, cinematic lighting", |
| "Photorealistic", |
| "9:16 Vertical (768x1360)", |
| 8, |
| 0.0, |
| 777, |
| ], |
| [ |
| "Retro 90s anime style screenshot of a pilot in a spaceship cockpit looking at the stars", |
| "Anime / Manga", |
| "16:9 Landscape (1360x768)", |
| 8, |
| 0.0, |
| 12345, |
| ], |
| ], |
| inputs=[prompt, style, aspect_ratio, steps, guidance_scale, seed], |
| outputs=[output_image, used_seed], |
| fn=generate_fn, |
| cache_examples=False, |
| ) |
|
|
| if __name__ == "__main__": |
| demo.queue().launch(css=custom_css, theme=theme) |
|
|