Workflow1111 / app.py
ysharma's picture
ysharma HF Staff
Workflow1111 β€” Automatic1111-style diffusion studio on gr.Workflow
6fe13ea verified
Raw
History Blame Contribute Delete
4.38 kB
"""
Workflow1111 Β· a Diffusion Studio built entirely from `gr.Workflow`
==================================================================
An Automatic1111-shaped image studio expressed as **one canvas graph** instead
of a tabbed UI β€” 64 nodes across 10 pipelines, every one of them runnable on
its own.
python apps/05_workflow1111/app.py
What's on the canvas
--------------------
1 txt2img prompt/style builders β†’ FLUX.1-schnell β†’ post-processing
with the real control surface: negative prompt, steps,
CFG, seed, and size presets
2 Hires fix the txt2img result re-rendered through FLUX.1-Kontext
3 img2img upload an image, edit it by instruction
4 Prompt magic an LLM writes a prompt from a rough idea
5 Interrogate recover a prompt from an image (VLM) + classify it (ViT)
6 Detect & mask DETR boxes β†’ annotated preview β†’ inpainting mask
7 Prompt matrix four variants rendered in parallel into an X/Y grid
8 Extras local upscale, AuraSR Γ—4, background removal
9 Annotators Canny / line art / sketch / luma-depth previews
10 PNG Info read generation parameters back out of a file
Why it is shaped like this
--------------------------
`gr.Workflow` raises if constructed inside a `gr.Blocks` context, so an app
like this genuinely cannot be tabs β€” the graph *is* the UI. Each output
("subject") is independently runnable and is also published as an API endpoint,
which is the closest analogue to A1111's tabs.
Four design rules came out of probing gradio 6.22 / huggingface_hub 1.26
directly, and the app depends on all four (details in `nodes.py` and README):
β€’ A `model` node's ports get rewritten to the endpoint's canonical schema the
moment a browser loads the graph β€” and the file is saved back that way. So
anything needing a richer control surface than the schema (`txt2img`,
`chat_llm`, `interrogate`) is an `fn` node calling `InferenceClient`
itself. `build_workflow.py` refuses to build if a `model` node's ports
ever diverge from its schema again.
β€’ `fn` nodes emit images as ``{"path": <file>, "url": <data: URI>}``. The
REST endpoint's `gr.Image` component needs a real file (a bare ``data:``
URI is read as a *filename*); the canvas and a chained `model` node need
the URI. Both keys, one value.
β€’ A `model` image output is never wired straight into another `model`'s image
port; `prep_image` sits between them (gradio would otherwise hand the
provider an unresolvable ``/gradio_api/file=`` path).
β€’ `space` nodes only ever take an *uploaded* image.
19 of the 26 `fn` nodes are pure local Pillow/numpy β€” no token, no quota, no
network β€” so most of the app keeps working even when a provider is having a bad
day. 13 nodes in total leave the machine.
Setup
-----
hf auth login # or: set HF_TOKEN=hf_xxx
pip install -r apps/05_workflow1111/requirements.txt
Tests (no network, ~2s): python apps/05_workflow1111/test_nodes.py
Live pipelines (hits HF): python apps/05_workflow1111/test_pipelines.py
REST endpoints: python apps/05_workflow1111/test_api.py
Regenerate the graph: python apps/05_workflow1111/build_workflow.py
Deploy to a Space: python apps/05_workflow1111/deploy_space.py --push
"""
import os
import sys
import gradio as gr
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import nodes # noqa: E402
HERE = os.path.dirname(os.path.abspath(__file__))
WORKFLOW = os.path.join(HERE, "workflow.json")
if not os.path.exists(WORKFLOW):
raise SystemExit(
f"{WORKFLOW} is missing.\n"
"Generate it with: python apps/05_workflow1111/build_workflow.py"
)
demo = gr.Workflow(WORKFLOW, bind=nodes.BIND)
if __name__ == "__main__":
from huggingface_hub import get_token
if not (get_token() or os.environ.get("HF_TOKEN")):
print(
"\n ⚠ No Hugging Face token found.\n"
" The 19 local `fn` nodes (post-processing, annotators, masks,\n"
" contact sheet, PNG info) work regardless, but every `model`\n"
" and `space` node will fail until you run `hf auth login`,\n"
" set HF_TOKEN, or sign in from inside the app.\n"
)
demo.launch()