Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
92 lines
4.7 KiB
Python
92 lines
4.7 KiB
Python
"""The default pipeline, as data.
|
|
|
|
Every slot here can be pointed at a different node or taken out entirely, and
|
|
that is only true because this is a list rather than a function. v4's equivalent
|
|
was a `CORE` dict inside the builder, so "remove this node" had nothing to
|
|
delete and "use a different node" had nothing to change -- the pipeline was code,
|
|
and code is not a thing a user can edit.
|
|
|
|
The rule for what belongs here: enough to generate with nothing else wired. A
|
|
run with no overrides at all has to produce a picture, because that is what makes
|
|
the UI an override layer rather than a requirement.
|
|
|
|
Nothing about these slots is privileged. Core does not know this list exists; it
|
|
is handed one and builds it.
|
|
|
|
`roles` is how a slot puts one of its inputs on the app's own surface: the
|
|
prompt is a slot input like any other, and typing it into a box beside the
|
|
picture rather than digging for the node it belongs to is the whole difference
|
|
between a pipeline and an app. The name is a mount point, so a role naming a
|
|
place this shell does not offer is simply not shown.
|
|
|
|
`group` is the pipeline's own idea of how it reads to a person -- the cards the
|
|
app shows are these names, in the order they first appear. It travels on the
|
|
slot rather than living in the app, so a pipeline that replaced every slot keeps
|
|
its own arrangement, and a group is created by a slot claiming a name nobody
|
|
used yet rather than by registering it anywhere.
|
|
"""
|
|
|
|
ID = "pipeline"
|
|
TITLE = "Pipeline"
|
|
STAGE = "load"
|
|
CATEGORY = "system"
|
|
STATUS = "proven"
|
|
|
|
# Slot ids are stable: they are how an override says which slot it means, and
|
|
# they end up as node ids in the queued prompt.
|
|
DEFAULT = [
|
|
{"id": "model", "group": "Loaders", "node": "FunPackDiffusionModelLoader", "inputs": {
|
|
"weight_dtype": "default", "compute_dtype": "default", "attention": "default"}},
|
|
{"id": "clip", "group": "Loaders", "node": "FunPackCLIPLoader", "inputs": {"type": "stable_diffusion"}},
|
|
{"id": "vae", "group": "Loaders", "node": "FunPackVAELoader", "inputs": {"dtype": "bfloat16"}},
|
|
|
|
{"id": "positive", "group": "Preparation", "node": "CLIPTextEncode",
|
|
"roles": [{"at": "generation.prompt", "input": "text", "label": "Prompt"}],
|
|
"inputs": {"clip": ["clip", 0], "text": ""}},
|
|
{"id": "negative", "group": "Preparation", "node": "CLIPTextEncode",
|
|
# A project-level field, not a per-run one: most FunPack pipelines run at
|
|
# CFG 1, where a negative prompt does nothing, so it does not belong beside
|
|
# the prompt every Generate reads.
|
|
"roles": [{"at": "project.negative", "input": "text", "label": "Negative prompt"}],
|
|
"inputs": {"clip": ["clip", 0], "text": ""}},
|
|
|
|
{"id": "latent", "group": "Preparation", "node": "FunPackEmptyLatent",
|
|
"roles": [{"at": "project.video", "input": "width", "label": "Width"},
|
|
{"at": "project.video", "input": "height", "label": "Height"},
|
|
{"at": "project.video", "input": "length", "label": "Length", "drives": "frames"}],
|
|
"inputs": {
|
|
"model": ["model", 0], "width": 512, "height": 512, "length": 1, "batch_size": 1}},
|
|
|
|
{"id": "settings", "group": "Preparation", "node": "FunPackModifierSettings", "inputs": {"settings": "{}"}},
|
|
{"id": "modifiers", "group": "Preparation", "node": "FunPackLoadModifiers", "inputs": {
|
|
"model": ["model", 0], "settings": ["settings", 0]}},
|
|
|
|
{"id": "sampler", "group": "Sampling", "node": "FunPackSampler",
|
|
# The three dials that get reached for constantly. v4 buried them several
|
|
# clicks deep in Engine Settings; here they are on the main window because
|
|
# the slot says they belong there.
|
|
"roles": [{"at": "generation.sampling", "input": "steps", "label": "Steps"},
|
|
{"at": "generation.sampling", "input": "sampler_name", "label": "Sampler"},
|
|
{"at": "generation.sampling", "input": "scheduler", "label": "Scheduler"},
|
|
{"at": "generation.seed", "input": "seed", "label": "Seed"}],
|
|
"inputs": {
|
|
"model": ["modifiers", 0], "positive": ["positive", 0], "negative": ["negative", 0],
|
|
"latent": ["latent", 0], "settings": ["settings", 0],
|
|
"seed": 0, "steps": 20, "cfg": 7.0,
|
|
"sampler_name": "euler", "scheduler": "normal", "denoise": 1.0}},
|
|
|
|
{"id": "decode", "group": "Render", "node": "FunPackDecode", "inputs": {
|
|
"samples": ["sampler", 0], "vae": ["vae", 0], "model": ["model", 0]}},
|
|
|
|
{"id": "save", "group": "Render", "node": "SaveImage", "inputs": {
|
|
"images": ["decode", 0], "filename_prefix": "FunPack"}},
|
|
]
|
|
|
|
|
|
def default():
|
|
"""A fresh copy: a caller that edits the pipeline must not edit everyone's."""
|
|
return [dict(slot, inputs=dict(slot.get("inputs") or {})) for slot in DEFAULT]
|
|
|
|
|
|
PROVIDES = {"default_pipeline": default}
|