Versatile_Art / app.py
faiz0983's picture
Create app.py
4db75e4 verified
import os
import torch
import random
# Removed google.colab import for deployment
from diffusers import StableDiffusionPipeline
import gradio as gr
# ---------------------------------------------------------
# 1. SETUP & HARDWARE DETECTION (Auto-Switching)
# ---------------------------------------------------------
# This allows it to run on Free CPU (Slow) or Paid GPU (Fast) automatically.
if torch.cuda.is_available():
device = "cuda"
dtype = torch.float16
print("πŸš€ Running on GPU (Fast Mode)")
else:
device = "cpu"
dtype = torch.float32
print("🐒 Running on CPU (Slow Compatibility Mode)")
print(f"⏳ Loading DreamShaper V44 on {device}...")
pipe = StableDiffusionPipeline.from_pretrained(
"Lykon/dreamshaper-8",
torch_dtype=dtype,
use_safetensors=True
)
pipe.to(device)
if device == "cuda":
pipe.enable_attention_slicing()
# Disable Safety Checker to save memory/speed
pipe.safety_checker = None
pipe.requires_safety_checker = False
# ---------------------------------------------------------
# 2. LOGICAL CONTENT ENGINE
# ---------------------------------------------------------
THEMES = {
"Cyberpunk": {
"subjects": ["A young cyberpunk hacker", "A futuristic android", "A rogue cyborg mercenary", "A holographic AI avatar"],
"outfits": ["wearing a glowing neon jacket", "wearing a transparent plastic raincoat", "wearing high-tech tactical armor"],
"locations": ["in a rain-soaked neon city", "inside a server room with green lasers", "in a grimy futuristic alleyway", "on a rooftop overlooking flying cars"]
},
"Fantasy": {
"subjects": ["A high elf princess", "A rugged dwarf warrior", "A mysterious forest druid", "A dark necromancer"],
"outfits": ["wearing intricate silver plate armor", "wearing a hooded velvet cloak", "wearing robes embroidered with gold"],
"locations": ["deep in a bioluminescent forest", "inside a grand castle throne room", "standing on a cliff overlooking a dragon valley", "in a magical crystal cave"]
},
"Modern/Urban": {
"subjects": ["A stylish university student", "A lo-fi hip hop girl", "A weary detective", "A graffiti artist"],
"outfits": ["wearing an oversized streetwear hoodie", "wearing a vintage denim jacket", "wearing a cozy knitted sweater"],
"locations": ["sitting in a cozy cafe with warm lighting", "standing on a subway platform", "walking through a rainy Tokyo street", "in a messy bedroom full of posters"]
},
"Historical": {
"subjects": ["A traditional samurai", "A victorian gothic lady", "A viking shieldmaiden", "A 1920s jazz singer"],
"outfits": ["wearing a floral kimono with a katana", "wearing a black lace victorian dress", "wearing fur-lined leather armor"],
"locations": ["standing in a cherry blossom garden", "inside a foggy london street", "on the deck of a wooden ship", "in a workshop full of brass clocks"]
}
}
ACTIONS = [
"looking at the camera", "holding a weapon", "reading a book",
"drinking coffee", "adjusting hair", "standing confidently"
]
ATMOSPHERES = [
"at sunset", "during a storm", "under a starry sky", "in the morning mist",
"with dramatic shadows", "bathed in moonlight", "during golden hour"
]
def get_logical_prompt(subject_mode):
theme_name = random.choice(list(THEMES.keys()))
data = THEMES[theme_name]
l = random.choice(data["locations"])
if subject_mode == "Scenery Only":
clean_loc = l.replace("standing ", "").replace("sitting ", "").replace("walking ", "")
atmos = random.choice(ATMOSPHERES)
return f"{clean_loc}, {atmos}"
else:
s = random.choice(data["subjects"])
o = random.choice(data["outfits"])
a = random.choice(ACTIONS)
return f"{s} {o}, {a}, {l}"
def on_subject_change(mode):
new_text = ""
if mode == "Scenery Only":
new_shape = "Landscape"
else:
new_shape = "Portrait"
return new_text, new_shape
def live_style_manager(user_text, selected_style, subject_mode):
if not user_text: return ""
cleaned = user_text
if selected_style == "Anime (2D)":
cleaned = cleaned.replace(", detailed iris", "").replace("detailed iris", "")
cleaned = cleaned.replace(", realistic eyes", "").replace("realistic eyes", "")
cleaned = cleaned.replace(", skin texture", "").replace("skin texture", "")
elif selected_style == "Realistic":
if subject_mode == "Character" and "detailed iris" not in cleaned:
cleaned += ", detailed iris"
return cleaned
def smart_enhance(user_text, selected_style, subject_mode):
if not user_text: return "masterpiece"
base = user_text + ", high quality, sharp lines, masterpiece, 8k resolution"
if subject_mode == "Character":
if "perfect eyes" not in base:
base += ", perfect eyes, symmetrical eyes"
if selected_style != "Anime (2D)" and "detailed iris" not in base:
base += ", detailed iris"
elif subject_mode == "Scenery Only":
base += ", detailed background, atmospheric, cinematic composition, wide angle"
return base
def apply_style(prompt, preset):
if preset == "Anime (2D)":
clean_prompt = prompt.replace("detailed iris", "").replace("realistic eyes", "")
suffix = ", anime style, studio ghibli, cel shading, flat color, vector art, 2d, vibrant colors, simple shading"
neg = "3d, realistic, photorealistic, oil painting, render, octane, unreal engine, clay, blender, shading, shadows, detailed iris"
return clean_prompt + suffix, neg
else:
suffix = ", photograph, 8k, raw photo, realistic texture, ray tracing, dslr, cinematic lighting, film grain"
neg = "anime, cartoon, drawing, painting, illustration, 2d, sketch, flat color"
return prompt + suffix, neg
MASTER_NEGATIVE = "blurry, low quality, bad anatomy, ugly, distorted, watermark, text, signature"
FACE_NEGATIVE = ", strabismus, crossed eyes, cross-eyed, uneven eyes, lazy eye, asymmetric eyes, bad eyes, open mouth, missing teeth, disfigured, extra fingers, missing limbs"
SCENERY_NEGATIVE = ", woman, man, person, people, human, face, portrait, character, girl, boy, body, skin, eyes, limbs"
def detect_face_request(prompt):
triggers = ["face", "portrait", "eyes", "mouth", "closeup", "close up", "woman", "man", "girl", "boy", "character", "selfie"]
return any(trigger in prompt.lower() for trigger in triggers)
def generate(prompt, aspect_ratio, style_preset, subject_mode, mode, cust_steps, cust_guidance, cust_seed):
final_prompt, style_negative = apply_style(prompt, style_preset)
if aspect_ratio == "Portrait": w, h = 512, 768
elif aspect_ratio == "Landscape": w, h = 768, 512
else: w, h = 512, 768
if mode == "Custom (Expert)":
steps = int(cust_steps)
guidance = float(cust_guidance)
seed = random.randint(0, 2147483647) if cust_seed == -1 else int(cust_seed)
final_negative = MASTER_NEGATIVE + style_negative
if subject_mode == "Scenery Only":
final_negative += SCENERY_NEGATIVE
info_prefix = "πŸ”§ Custom"
else:
base_neg = MASTER_NEGATIVE + style_negative
if subject_mode == "Scenery Only":
steps = 28
guidance = 7.5
final_negative = base_neg + SCENERY_NEGATIVE
info_prefix = "🌍 Scenery Mode"
else:
is_portrait = detect_face_request(prompt)
if is_portrait:
steps = 35
guidance = 6.5
final_negative = base_neg + FACE_NEGATIVE
info_prefix = "πŸ€– Auto-Face"
else:
steps = 28
guidance = 7.5
final_negative = base_neg
info_prefix = "✈️ Auto-Creative"
if style_preset == "Anime (2D)":
guidance = 7.0
info_prefix += " (Anime)"
seed = random.randint(0, 2147483647)
# Use 'device' variable determined at startup
generator = torch.Generator(device).manual_seed(seed)
image = pipe(
prompt=final_prompt,
negative_prompt=final_negative,
num_inference_steps=steps,
guidance_scale=guidance,
width=w,
height=h,
generator=generator
).images[0]
return image, f"{info_prefix} | {w}x{h} | Steps: {steps} | G: {guidance} | Seed: {seed}"
with gr.Blocks(theme=gr.themes.Soft()) as app:
gr.Markdown("# πŸš€ DreamShaper V44 (Hosted)")
with gr.Row():
with gr.Column():
txt = gr.Textbox(label="Prompt", placeholder="Type here or click 'Logical Idea'...", lines=4)
subject_mode = gr.Radio(["Character", "Scenery Only"], value="Character", label="1. Subject Type")
style_preset = gr.Radio(["Realistic", "Anime (2D)"], value="Realistic", label="2. Style Preset")
with gr.Row():
random_btn = gr.Button("🧠 Logical Idea", variant="primary")
refine_btn = gr.Button("✨ Enhance Text", variant="secondary")
shape = gr.Radio(["Portrait", "Landscape"], value="Portrait", label="Shape")
mode = gr.Radio(["Random (Auto-Pilot)", "Custom (Expert)"], value="Random (Auto-Pilot)", label="Mode")
with gr.Group(visible=False) as custom_box:
cust_steps = gr.Slider(10, 60, value=30, label="Steps")
cust_guidance = gr.Slider(1.0, 15.0, value=7.0, label="Guidance")
cust_seed = gr.Number(value=-1, label="Seed")
btn = gr.Button("Generate 🎨", variant="primary")
with gr.Column():
out_img = gr.Image(label="Result")
out_info = gr.Textbox(label="Settings Used", interactive=False)
random_btn.click(get_logical_prompt, [subject_mode], [txt])
refine_btn.click(smart_enhance, [txt, style_preset, subject_mode], [txt])
style_preset.change(live_style_manager, [txt, style_preset, subject_mode], [txt])
subject_mode.change(on_subject_change, inputs=[subject_mode], outputs=[txt, shape])
def toggle(val): return gr.update(visible=(val == "Custom (Expert)"))
mode.change(toggle, mode, custom_box)
btn.click(generate, [txt, shape, style_preset, subject_mode, mode, cust_steps, cust_guidance, cust_seed], [out_img, out_info])
app.launch()