Sumith0102's picture
download
raw
7.23 kB
"""Personalized text-to-image website. Requires Sumith's hosted model weights."""
import os
import secrets
import threading
from pathlib import Path
import spaces
import gradio as gr
from prompts import make_prompt, STYLES
_pipeline = None
_lock = threading.Lock()
def load_pipeline():
global _pipeline
if _pipeline is not None:
return _pipeline
import torch
from diffusers import StableDiffusionPipeline, DDIMScheduler
from huggingface_hub import hf_hub_download
local_path = os.getenv("MODEL_PATH", "")
repo = os.getenv("MODEL_REPO_ID", "Sumith0102/PersonalisedAiAvatarGenerator")
if local_path:
path = Path(local_path)
elif repo:
path = Path(hf_hub_download(
repo_id=repo,
filename=os.getenv("MODEL_FILENAME", "model.ckpt"),
token=os.getenv("HF_TOKEN") or None,
))
else:
raise gr.Error("The owner is connecting the personalized model. Please try again later.")
if path.suffix == ".ckpt":
from convert_checkpoint import convert
import hashlib
import tempfile
cache_key = hashlib.sha256(str(path.resolve()).encode()).hexdigest()[:20]
safe_path = Path(tempfile.gettempdir()) / f"sumith-{cache_key}.safetensors"
if not safe_path.exists():
convert(path, safe_path)
path = safe_path
elif path.suffix != ".safetensors":
raise gr.Error("The configured model format is not supported.")
pipeline = StableDiffusionPipeline.from_single_file(
str(path),
config=os.getenv("BASE_MODEL_ID", "stable-diffusion-v1-5/stable-diffusion-v1-5"),
torch_dtype=torch.float16,
token=os.getenv("HF_TOKEN") or None,
load_safety_checker=True,
)
pipeline.scheduler = DDIMScheduler.from_config(pipeline.scheduler.config)
pipeline.enable_attention_slicing()
pipeline.enable_vae_slicing()
pipeline.to("cuda")
_pipeline = pipeline
return pipeline
@spaces.GPU(duration=60)
def generate(scene, style, seed, steps, progress=gr.Progress()):
import torch
try:
prompt = make_prompt(scene, style)
except ValueError as exc:
raise gr.Error(str(exc)) from None
if seed is None:
raise gr.Error("Enter a seed, or use -1 for a random image.")
if isinstance(seed, bool) or int(seed) != seed or not -1 <= seed <= 2147483647:
raise gr.Error("Choose a whole-number seed from 0 to 2147483647, or -1 for random.")
seed = secrets.randbelow(2147483648) if seed == -1 else int(seed)
steps = int(steps)
if not 15 <= steps <= 35:
raise gr.Error("Use between 15 and 35 generation steps.")
with _lock:
try:
progress(0.05, desc="Loading the personalized model")
pipe = load_pipeline()
device = "cuda"
rng = torch.Generator(device=device).manual_seed(seed)
def step_callback(pipeline, index, timestep, kwargs):
progress(0.1 + 0.85 * (index + 1) / steps, desc="Creating your portrait")
return kwargs
with torch.inference_mode():
result = pipe(
prompt=prompt,
negative_prompt="blurry, low resolution, distorted face, duplicate person, watermark, text",
height=512, width=512, guidance_scale=7.5,
num_inference_steps=steps, generator=rng,
callback_on_step_end=step_callback,
)
if result.nsfw_content_detected and any(result.nsfw_content_detected):
raise gr.Error("This image could not be displayed. Please try another scene.")
return result.images[0], f"Seed: {seed} · 512 × 512 · AI-generated image"
except gr.Error:
raise
except Exception as exc:
# Do not return upstream paths, tokens, prompts, or credentials to visitors.
print("Generation failed:", type(exc).__name__, flush=True)
raise gr.Error("Generation is unavailable right now. Please try again later.") from None
CSS = """
.gradio-container {max-width: 1240px !important; margin: auto; background: #f5f7fc;}
#studio-header {padding: 28px 0 14px; border-bottom: 1px solid #cdd5e6; margin-bottom: 22px;}
#studio-header h1 {font-size: clamp(30px, 4vw, 48px); letter-spacing: -1.5px; color: #182448;}
#studio-header p {font-size: 16px; color: #475777;}
#generate {background: #304ffe; color: white; border: 0; min-height: 52px; font-size: 17px;}
#portrait {min-height: 460px; background: #e9eef9; border-radius: 18px;}
#footer {font-size: 14px; color: #566581; margin-top: 20px;}
"""
with gr.Blocks(title="Sumith Portrait Studio",
analytics_enabled=False, delete_cache=(3600, 3600)) as demo:
gr.Markdown("# Sumith Portrait Studio\nDescribe a scene. Create an AI portrait of Sumith.", elem_id="studio-header")
with gr.Row():
with gr.Column(scale=5):
scene = gr.Textbox(label="Your scene", lines=5, max_lines=8,
placeholder="Standing beside a lake in the Canadian mountains at sunrise")
style = gr.Radio(list(STYLES), value="Natural", label="Look")
with gr.Accordion("Fine-tune the result", open=False):
seed = gr.Number(value=-1, precision=0, label="Seed · -1 for a new variation")
steps = gr.Slider(15, 35, value=24, step=1, label="Generation steps")
submit = gr.Button("Create portrait", variant="primary", elem_id="generate")
gr.Examples([
["Walking through Old Montréal on a sunny afternoon", "Natural"],
["In a tailored navy suit, soft studio lighting, professional headshot", "Studio"],
["An explorer beside a mountain lake at sunrise", "Cinematic"],
], inputs=[scene, style], label="Try a scene", cache_examples=False)
with gr.Column(scale=6):
portrait = gr.Image(label="Your portrait", type="pil", interactive=False,
buttons=["download"], elem_id="portrait")
details = gr.Markdown("Your generated portrait will appear here.")
gr.Markdown(
"Built by Sumith Reddy · DreamBooth / Stable Diffusion 1.5 \n"
"Images are AI-generated and may vary in likeness. Prompts and results are processed by the hosting service. "
"The app keeps temporary output files for up to about two hours. \n"
"[Back to portfolio](https://thanu-sumith.github.io/sumith-portfolio/)", elem_id="footer")
submit.click(generate, inputs=[scene, style, seed, steps], outputs=[portrait, details],
concurrency_limit=1, api_name="generate_portrait")
# Prepare the model before ZeroGPU forks a worker. Its CUDA emulation supports
# model placement at startup; real GPU computation happens only in generate().
if __name__ == "__main__":
load_pipeline()
demo.queue(max_size=4, default_concurrency_limit=1).launch(
css=CSS, theme=gr.themes.Soft(primary_hue="indigo", neutral_hue="slate"),
server_name="0.0.0.0", server_port=int(os.getenv("PORT", "7860")),
show_error=False, max_file_size="1mb",
)

Xet Storage Details

Size:
7.23 kB
·
Xet hash:
b366e34e2a74bd8fe4294f6a939f5eaf5944a09607c190452f50ad238d7b95e2

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.