File size: 4,379 Bytes
db59f73
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6fe13ea
 
 
 
db59f73
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6fe13ea
db59f73
6fe13ea
db59f73
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
"""
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()