sd-turbo-cpu / app.py
Quantish1's picture
Use mount_gradio_app + uvicorn (avoid launch self-check gradio_client bug)
8bafb1b verified
Raw
History Blame Contribute Delete
3.78 kB
import os
import subprocess
import time
import urllib.request
import zipfile
import gradio as gr
import uvicorn
from fastapi import FastAPI
from huggingface_hub import hf_hub_download
# --- Config -----------------------------------------------------------------
SD_TAG = "master-709-92a3b73"
SD_ZIP = "sd-master-92a3b73-bin-Linux-Ubuntu-24.04-x86_64.zip"
SD_URL = f"https://github.com/leejet/stable-diffusion.cpp/releases/download/{SD_TAG}/{SD_ZIP}"
MODEL_REPO = "Green-Sky/SD-Turbo-GGUF"
MODEL_FILE = "sd_turbo-f16-q8_0.gguf"
N_THREADS = int(os.environ.get("N_THREADS", "2"))
WORK = os.path.abspath("runtime")
os.makedirs(WORK, exist_ok=True)
def log(*a):
print("[startup]", *a, flush=True)
# --- Fetch sd.cpp binary ----------------------------------------------------
def fetch_sd():
sd_dir = os.path.join(WORK, "sdcpp")
if not os.path.isdir(sd_dir):
zip_path = os.path.join(WORK, "sd.zip")
log("downloading stable-diffusion.cpp ...")
urllib.request.urlretrieve(SD_URL, zip_path)
with zipfile.ZipFile(zip_path) as z:
z.extractall(sd_dir)
sd_bin = os.path.join(sd_dir, "sd-cli")
os.chmod(sd_bin, 0o755)
return sd_dir, sd_bin
log("fetching binary + model ...")
SD_DIR, SD_BIN = fetch_sd()
MODEL_PATH = hf_hub_download(repo_id=MODEL_REPO, filename=MODEL_FILE)
log("ready.")
def generate(prompt, negative, steps, width, height, seed):
if not prompt or not prompt.strip():
raise gr.Error("Введите prompt")
out = os.path.join(WORK, "out.png")
if os.path.exists(out):
os.remove(out)
env = dict(os.environ)
env["LD_LIBRARY_PATH"] = SD_DIR + ":" + env.get("LD_LIBRARY_PATH", "")
cmd = [
SD_BIN,
"-m", MODEL_PATH,
"-p", prompt,
"-n", negative or "",
"--cfg-scale", "1.0", # turbo models: cfg ~1
"--steps", str(int(steps)),
"--sampling-method", "euler",
"-W", str(int(width)),
"-H", str(int(height)),
"-s", str(int(seed)),
"-t", str(N_THREADS),
"-o", out,
]
t0 = time.time()
r = subprocess.run(cmd, env=env, capture_output=True, text=True, timeout=1200)
dt = time.time() - t0
if not os.path.exists(out):
tail = (r.stderr or r.stdout or "no output")[-800:]
raise gr.Error(f"Генерация не удалась:\n{tail}")
return out, f"{dt:.1f}s · steps={int(steps)} · {int(width)}x{int(height)} · seed={int(seed)}"
demo = gr.Interface(
fn=generate,
inputs=[
gr.Textbox(label="Prompt", value="a cute cat astronaut floating in space, digital art, highly detailed"),
gr.Textbox(label="Negative prompt", value="blurry, low quality, deformed"),
gr.Slider(1, 8, value=3, step=1, label="Steps (turbo: 1-4 достаточно)"),
gr.Slider(256, 768, value=512, step=64, label="Width"),
gr.Slider(256, 768, value=512, step=64, label="Height"),
gr.Number(value=42, label="Seed", precision=0),
],
outputs=[
gr.Image(label="Результат", type="filepath"),
gr.Textbox(label="Инфо / тайминг"),
],
title="SD-Turbo — CPU text→image (stable-diffusion.cpp)",
description=(
"SD-Turbo на CPU Basic (2 vCPU). 512px, few-step (1-4 шага). "
"Одна картинка ~30-90 с — наберитесь терпения, это CPU."
),
allow_flagging="never",
)
# Use mount_gradio_app + uvicorn (avoids demo.launch() self-check which crashes
# on gradio_client 1.3.0 get_api_info bug under Python 3.12).
demo.queue(max_size=4)
fastapi_app = FastAPI()
app = gr.mount_gradio_app(fastapi_app, demo, path="/")
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=7860)