Spaces:
Runtime error
Runtime error
Download app.py from whosouravsharma/diffusiondb-sd15-lora-inference: direct link, hf CLI and curl.
- Browser
- Download file 6.19 kB
-
https://huggingface.co/spaces/whosouravsharma/diffusiondb-sd15-lora-inference/resolve/main/app.py
- Command line
-
hf download hf://spaces/whosouravsharma/diffusiondb-sd15-lora-inference/app.py
-
curl -L -o app.py https://huggingface.co/spaces/whosouravsharma/diffusiondb-sd15-lora-inference/resolve/main/app.py
6.19 kB
| """Inference backend for the DiffusionDB SD 1.5 LoRA. | |
| A Gradio app whose only job is to expose generation as an API. The UI Space | |
| (spaces/whosouravsharma/diffusiondb-sd15-lora) calls it with gradio_client; | |
| the minimal interface here is also usable directly for debugging. | |
| This is the Space that needs the GPU. Weights are pulled from the model repo | |
| at first request, not baked into the image. | |
| """ | |
| import os | |
| import gradio as gr | |
| from src.pipeline import LORA_CHECKPOINT, LORA_REPO, ModelRunner, pick_device | |
| from src.tracing import ( | |
| TRACING_ACTIVE, | |
| configure_logging, | |
| continue_trace, | |
| logger, | |
| ) | |
| configure_logging() | |
| # Loaded on first request rather than at import, so the Space becomes | |
| # reachable immediately and a slow weight download cannot kill startup. | |
| _runner = None | |
| def get_runner() -> ModelRunner: | |
| global _runner | |
| if _runner is None: | |
| _runner = ModelRunner() | |
| return _runner | |
| def model_is_warm() -> bool: | |
| return _runner is not None | |
| # Status strings for the visible UI. The cold path is genuinely slow -- the | |
| # container has to wake, then torch/diffusers import, then ~9 s of weight | |
| # loading before a single step runs -- so say so rather than showing a | |
| # spinner that looks indistinguishable from a hang. | |
| STATUS_IDLE = "Ready." | |
| STATUS_COLD = ( | |
| "⏳ **Starting server…** waking the GPU and loading the model. " | |
| "The first image takes around 40 seconds; later ones take a few." | |
| ) | |
| STATUS_WARM = "⏳ **Generating…**" | |
| def status_on_click() -> str: | |
| """Fires the instant the button is pressed, before the GPU job queues.""" | |
| return STATUS_WARM if model_is_warm() else STATUS_COLD | |
| def status_on_load() -> str: | |
| """Fires when someone opens the page.""" | |
| if model_is_warm(): | |
| return STATUS_IDLE | |
| return ( | |
| "Model not loaded yet — the first generation also starts the server " | |
| "and takes around 40 seconds." | |
| ) | |
| def generate(prompt, negative_prompt, steps, guidance, lora_scale, seed, | |
| request: gr.Request = None): | |
| """One image per call. Returns (image, seed_used). | |
| Deliberately single-image: gradio_client handles a plain Image return | |
| far more predictably than a Gallery, and the UI can call again for more. | |
| `request` is supplied by Gradio from the type annotation and is not a UI | |
| input, so the published /generate signature stays at six arguments. It | |
| exists only to pick up the caller's trace headers. | |
| """ | |
| try: | |
| # When the UI Space sent trace headers this run becomes a child of | |
| # its run, so one LangSmith trace covers UI and backend -- and the | |
| # visitor's location, carried in baggage, lands on this run too. | |
| with continue_trace(request): | |
| result = get_runner().generate( | |
| prompt=prompt, | |
| negative_prompt=negative_prompt, | |
| steps=int(steps), | |
| guidance=float(guidance), | |
| lora_scale=float(lora_scale), | |
| seed=None if int(seed) < 0 else int(seed), | |
| count=1, | |
| ) | |
| except ValueError as error: | |
| raise gr.Error(str(error)) | |
| except Exception as error: | |
| # The gr.Error string is all the caller sees; without this the | |
| # traceback is lost and the Space logs show nothing useful. | |
| logger.exception("request failed") | |
| raise gr.Error(f"Generation failed: {error}") | |
| return result.images[0], result.seed | |
| with gr.Blocks(title="DiffusionDB SD 1.5 LoRA — inference API") as demo: | |
| gr.Markdown( | |
| f"## Inference API\n" | |
| f"Backend for [`diffusiondb-sd15-lora`]" | |
| f"(https://huggingface.co/spaces/whosouravsharma/diffusiondb-sd15-lora).\n\n" | |
| f"Model `{LORA_REPO}` @ `{LORA_CHECKPOINT}` · device `{pick_device()}` · " | |
| f"tracing `{'on' if TRACING_ACTIVE else 'off'}`\n\n" | |
| f"Call it with `gradio_client`:\n" | |
| f"```python\n" | |
| f"from gradio_client import Client\n" | |
| f"c = Client('whosouravsharma/diffusiondb-sd15-lora-inference')\n" | |
| f"image, seed = c.predict('a steampunk owl', '', 25, 7.5, 1.0, 42,\n" | |
| f" api_name='/generate')\n" | |
| f"```" | |
| ) | |
| with gr.Row(): | |
| with gr.Column(): | |
| prompt = gr.Textbox(label="prompt", lines=2) | |
| negative = gr.Textbox(label="negative_prompt", lines=1) | |
| steps = gr.Number(value=25, label="steps", precision=0) | |
| guidance = gr.Number(value=7.5, label="guidance") | |
| lora_scale = gr.Number(value=1.0, label="lora_scale") | |
| seed = gr.Number(value=-1, label="seed", precision=0) | |
| run = gr.Button("Generate", variant="primary") | |
| with gr.Column(): | |
| # Initial value assumes cold, because at import time it always | |
| # is; demo.load corrects it to "Ready." on a warm server. The | |
| # reverse default would flash a false "Ready." at every cold | |
| # visitor before the load event lands. | |
| status = gr.Markdown(status_on_load()) | |
| image = gr.Image(label="image", type="pil") | |
| used_seed = gr.Number(label="seed_used", interactive=False) | |
| # Two independent listeners on the same button. The cosmetic one uses | |
| # queue=False so it paints immediately instead of waiting behind the GPU | |
| # job it is announcing. The API contract of /generate is untouched: same | |
| # six inputs, same two outputs, so gradio_client callers are unaffected. | |
| # api_name=False keeps these cosmetic events out of the published API, | |
| # so gradio_client sees /generate and nothing else. | |
| run.click(status_on_click, outputs=status, queue=False, api_name=False) | |
| generate_event = run.click( | |
| generate, | |
| inputs=[prompt, negative, steps, guidance, lora_scale, seed], | |
| outputs=[image, used_seed], | |
| api_name="generate", | |
| ) | |
| generate_event.then( | |
| lambda: STATUS_IDLE, outputs=status, queue=False, api_name=False | |
| ) | |
| demo.load(status_on_load, outputs=status, api_name=False) | |
| if __name__ == "__main__": | |
| demo.queue(max_size=12).launch( | |
| server_name="0.0.0.0", | |
| server_port=int(os.environ.get("PORT", 7860)), | |
| ) | |