haybale-models 0.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- haybale_models/OVERVIEW.md +30 -0
- haybale_models/QUICKREF.md +27 -0
- haybale_models/__init__.py +44 -0
- haybale_models/consumer.py +115 -0
- haybale_models/describe.py +111 -0
- haybale_models/docs/haybale-models.editor.ModelsEditor.md +35 -0
- haybale_models/docs/haybale-models.farmhand.fetch.md +23 -0
- haybale_models/docs/haybale-models.farmhand.list.md +28 -0
- haybale_models/docs/haybale-models.farmhand.needs.md +24 -0
- haybale_models/docs/haybale-models.node.ResolveModelNode.md +33 -0
- haybale_models/docs/haybale-models.panel.ModelsSettingsPanel.md +14 -0
- haybale_models/docs/haybale-models.setting.ModelsSettings.md +9 -0
- haybale_models/docs/haybale-models.state.ModelsState.md +9 -0
- haybale_models/docs/haybale-models.type.MODEL_REF.md +19 -0
- haybale_models/docs/haybale-models.widget.ModelRefWidget.md +53 -0
- haybale_models/download.py +675 -0
- haybale_models/editors/__init__.py +0 -0
- haybale_models/editors/assisted_dialog.py +180 -0
- haybale_models/editors/models_editor.py +1399 -0
- haybale_models/farmhands/__init__.py +0 -0
- haybale_models/farmhands/model_tools.py +225 -0
- haybale_models/filters.py +78 -0
- haybale_models/haybale.toml +13 -0
- haybale_models/hf.py +386 -0
- haybale_models/keys.py +10 -0
- haybale_models/matcher.py +50 -0
- haybale_models/needs.py +565 -0
- haybale_models/nodes/__init__.py +0 -0
- haybale_models/nodes/resolve_model.py +66 -0
- haybale_models/panels/__init__.py +1 -0
- haybale_models/panels/models_settings_panel.py +32 -0
- haybale_models/pool.py +113 -0
- haybale_models/py.typed +0 -0
- haybale_models/receive.py +150 -0
- haybale_models/resolver.py +418 -0
- haybale_models/settings/__init__.py +0 -0
- haybale_models/settings/models_settings.py +17 -0
- haybale_models/signals.py +18 -0
- haybale_models/sources/__init__.py +48 -0
- haybale_models/sources/base.py +195 -0
- haybale_models/sources/caches.py +124 -0
- haybale_models/sources/folder.py +143 -0
- haybale_models/sources/hf.py +110 -0
- haybale_models/sources/https.py +132 -0
- haybale_models/sources/registry.py +97 -0
- haybale_models/state/__init__.py +0 -0
- haybale_models/state/models_state.py +179 -0
- haybale_models/status.py +48 -0
- haybale_models/store/__init__.py +1 -0
- haybale_models/store/index.py +302 -0
- haybale_models/store/layout.py +118 -0
- haybale_models/store/records.py +125 -0
- haybale_models/types/__init__.py +0 -0
- haybale_models/types/model_ref.py +74 -0
- haybale_models/upload_route.py +176 -0
- haybale_models/value/__init__.py +5 -0
- haybale_models/value/model_ref.py +83 -0
- haybale_models/widgets/__init__.py +0 -0
- haybale_models/widgets/model_ref_widget.py +657 -0
- haybale_models-0.3.1.dist-info/METADATA +11 -0
- haybale_models-0.3.1.dist-info/RECORD +63 -0
- haybale_models-0.3.1.dist-info/WHEEL +4 -0
- haybale_models-0.3.1.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Models
|
|
2
|
+
|
|
3
|
+
Model references, local model store, downloads and graph needs-list
|
|
4
|
+
|
|
5
|
+
## Nodes
|
|
6
|
+
### Models
|
|
7
|
+
- **Resolve Model** — Gives the file of a model on this machine, with its sha256 and size
|
|
8
|
+
|
|
9
|
+
## Types
|
|
10
|
+
- **Model** — A model, named by a catalog entry or by a file (url and sha256). Resolve Model turns it into a path on disk.
|
|
11
|
+
|
|
12
|
+
## Widgets
|
|
13
|
+
- **ModelRefWidget** — Pick a model
|
|
14
|
+
|
|
15
|
+
## Settings
|
|
16
|
+
- **Models** — Model download behaviour
|
|
17
|
+
|
|
18
|
+
## Farmhands
|
|
19
|
+
- **Fetch models** — Queue downloads: everything an open graph needs, or catalog entries by key (admin).
|
|
20
|
+
- **List models** — Catalog entries with per-variant status, indexed local files and download jobs.
|
|
21
|
+
- **Models a graph needs** — The models an open graph references and does not have locally.
|
|
22
|
+
|
|
23
|
+
## States
|
|
24
|
+
- **Models** — Model volumes, file index, download queue and the pool of loaded models
|
|
25
|
+
|
|
26
|
+
## Panels
|
|
27
|
+
- **Models** — Model download behaviour: how many files download in parallel.
|
|
28
|
+
|
|
29
|
+
## Editors
|
|
30
|
+
- **Models** — Model files on this machine and where they come from
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# haybale-models — component index (v0.3.1)
|
|
2
|
+
|
|
3
|
+
## node
|
|
4
|
+
- `haybale-models:node:ResolveModelNode` — Resolve Model — Gives the file of a model on this machine, with its sha256 and size _tags: model, resolve, file, path, weights, catalog, sha256_
|
|
5
|
+
|
|
6
|
+
## type
|
|
7
|
+
- `haybale-models:type:MODEL_REF` — Model — A model, named by a catalog entry or by a file (url and sha256). Resolve Model turns it into a path on disk.
|
|
8
|
+
|
|
9
|
+
## widget
|
|
10
|
+
- `haybale-models:widget:ModelRefWidget` — ModelRefWidget — Pick a model
|
|
11
|
+
|
|
12
|
+
## setting
|
|
13
|
+
- `haybale-models:setting:ModelsSettings` — Models — Model download behaviour
|
|
14
|
+
|
|
15
|
+
## farmhand
|
|
16
|
+
- `haybale-models:farmhand:fetch` — Fetch models — Queue downloads: everything an open graph needs, or catalog entries by key (admin).
|
|
17
|
+
- `haybale-models:farmhand:list` — List models — Catalog entries with per-variant status, indexed local files and download jobs.
|
|
18
|
+
- `haybale-models:farmhand:needs` — Models a graph needs — The models an open graph references and does not have locally.
|
|
19
|
+
|
|
20
|
+
## state
|
|
21
|
+
- `haybale-models:state:ModelsState` — Models — Model volumes, file index, download queue and the pool of loaded models
|
|
22
|
+
|
|
23
|
+
## panel
|
|
24
|
+
- `haybale-models:panel:ModelsSettingsPanel` — Models — Model download behaviour: how many files download in parallel.
|
|
25
|
+
|
|
26
|
+
## editor
|
|
27
|
+
- `haybale-models:editor:ModelsEditor` — Models — Model files on this machine and where they come from
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Haybale-Models: model references, local model store, downloads and needs-list.
|
|
2
|
+
|
|
3
|
+
Component folders (registered in ``register_components``):
|
|
4
|
+
- ``state``: ``ModelsState`` with the two model volumes.
|
|
5
|
+
- ``settings``, ``types``, ``widgets``, ``nodes``, ``editors``, ``farmhands``, ``panels``.
|
|
6
|
+
|
|
7
|
+
Never imports ``torch``: variant choice comes from the consuming node's settings.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
from haywire.core.farmhand import FarmhandRegistry
|
|
13
|
+
from haywire.core.library.base import BaseLibrary
|
|
14
|
+
from haywire.core.library.decorator import library
|
|
15
|
+
from haywire.core.node.registry import NodeRegistry
|
|
16
|
+
from haywire.core.settings.registry import SettingsRegistry
|
|
17
|
+
from haywire.core.state import LibraryStateRegistry
|
|
18
|
+
from haywire.core.types.registry import TypeRegistry
|
|
19
|
+
from haywire.ui.editor.registry import EditorTypeRegistry
|
|
20
|
+
from haywire.ui.panel.registry import PanelRegistry
|
|
21
|
+
from haywire.ui.widget.registry import WidgetRegistry
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@library(
|
|
25
|
+
file_watcher=True,
|
|
26
|
+
)
|
|
27
|
+
class Library(BaseLibrary):
|
|
28
|
+
"""Models library — model references, store and downloads."""
|
|
29
|
+
|
|
30
|
+
def register_components(self):
|
|
31
|
+
"""Register the component folders with their registries."""
|
|
32
|
+
base_path = Path(__file__).parent
|
|
33
|
+
|
|
34
|
+
self.add_folder_to_registry(folder_path=str(base_path / "state"), registry_cls=LibraryStateRegistry)
|
|
35
|
+
self.add_folder_to_registry(folder_path=str(base_path / "settings"), registry_cls=SettingsRegistry)
|
|
36
|
+
self.add_folder_to_registry(folder_path=str(base_path / "types"), registry_cls=TypeRegistry)
|
|
37
|
+
self.add_folder_to_registry(folder_path=str(base_path / "widgets"), registry_cls=WidgetRegistry)
|
|
38
|
+
self.add_folder_to_registry(folder_path=str(base_path / "nodes"), registry_cls=NodeRegistry)
|
|
39
|
+
self.add_folder_to_registry(folder_path=str(base_path / "editors"), registry_cls=EditorTypeRegistry)
|
|
40
|
+
self.add_folder_to_registry(folder_path=str(base_path / "farmhands"), registry_cls=FarmhandRegistry)
|
|
41
|
+
self.add_folder_to_registry(folder_path=str(base_path / "panels"), registry_cls=PanelRegistry)
|
|
42
|
+
|
|
43
|
+
def validate(self) -> bool:
|
|
44
|
+
return True
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""Helpers for node authors: resolve a MODEL_REF port and hold its loaded model per run."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable, Hashable
|
|
6
|
+
from typing import TYPE_CHECKING, TypeVar
|
|
7
|
+
|
|
8
|
+
from haywire.core.di.context import get_library_state_container
|
|
9
|
+
from haywire.core.node.node_warning import NodeWarning
|
|
10
|
+
|
|
11
|
+
from haybale_models.matcher import Preference
|
|
12
|
+
from haybale_models.resolver import ModelMissing, ResolvedModel, resolve
|
|
13
|
+
from haybale_models.state.models_state import ModelsState
|
|
14
|
+
from haybale_models.value.model_ref import ModelRef
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from haywire.core.node.base import BaseNode
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"KIND",
|
|
21
|
+
"MISSING_WARNING",
|
|
22
|
+
"ModelMissing",
|
|
23
|
+
"acquire_port",
|
|
24
|
+
"models_state",
|
|
25
|
+
"preference_for",
|
|
26
|
+
"release_node",
|
|
27
|
+
"resolve_port",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
T = TypeVar("T")
|
|
31
|
+
|
|
32
|
+
KIND = "model"
|
|
33
|
+
MISSING_WARNING = NodeWarning(message="Model missing — Show in Models", source_version=None, kind=KIND)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def models_state() -> ModelsState:
|
|
37
|
+
"""The app-wide :class:`ModelsState`.
|
|
38
|
+
|
|
39
|
+
Raises:
|
|
40
|
+
RuntimeError: If haybale-models is not enabled.
|
|
41
|
+
"""
|
|
42
|
+
state = get_library_state_container().get(ModelsState)
|
|
43
|
+
if state is None:
|
|
44
|
+
raise RuntimeError("haybale-models is not enabled")
|
|
45
|
+
return state
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def preference_for(node: BaseNode, port_id: str) -> Preference:
|
|
49
|
+
"""The variant preference for *port_id*.
|
|
50
|
+
|
|
51
|
+
The node's ``model_preference(port_id)`` if it defines one, else the port's ``prefer``
|
|
52
|
+
property, else ``[{}]``.
|
|
53
|
+
"""
|
|
54
|
+
hook = getattr(node, "model_preference", None)
|
|
55
|
+
if callable(hook):
|
|
56
|
+
return hook(port_id) # type: ignore[no-any-return]
|
|
57
|
+
prefer = node.ports[port_id].widget_config.get("properties", {}).get("prefer")
|
|
58
|
+
return list(prefer) if prefer else [{}]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def resolve_port(node: BaseNode, port_id: str) -> ResolvedModel:
|
|
62
|
+
"""Resolve the model on *port_id* and set the node's ``"model"`` warnings.
|
|
63
|
+
|
|
64
|
+
All ``MODEL_REF`` ports of one node share a single ``"model"`` warning list, so with
|
|
65
|
+
several ports the last call wins. Key the list per port when a two-port consumer lands.
|
|
66
|
+
|
|
67
|
+
Raises:
|
|
68
|
+
ModelMissing: If no local file matches the reference.
|
|
69
|
+
"""
|
|
70
|
+
state = models_state()
|
|
71
|
+
value = node.ports[port_id].get_value()
|
|
72
|
+
ref = value if isinstance(value, ModelRef) else ModelRef.from_dict(value or {})
|
|
73
|
+
try:
|
|
74
|
+
resolved = resolve(
|
|
75
|
+
ref,
|
|
76
|
+
preference_for(node, port_id),
|
|
77
|
+
catalog=state.catalog,
|
|
78
|
+
index=state.index,
|
|
79
|
+
sources=state.sources,
|
|
80
|
+
)
|
|
81
|
+
except ModelMissing:
|
|
82
|
+
node.wrapper.replace_warnings(KIND, [] if ref.is_empty else [MISSING_WARNING])
|
|
83
|
+
raise
|
|
84
|
+
node.wrapper.replace_warnings(KIND, _warnings(resolved))
|
|
85
|
+
return resolved
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _warnings(resolved: ResolvedModel) -> list[NodeWarning]:
|
|
89
|
+
messages: list[str] = []
|
|
90
|
+
if resolved.better_unfetched is not None:
|
|
91
|
+
variant = resolved.better_unfetched.variant_name()
|
|
92
|
+
messages.append(f"Preferred variant {variant} is not downloaded — Show in Models")
|
|
93
|
+
if resolved.ref.is_file and not resolved.ref.sha256:
|
|
94
|
+
messages.append("Not pinned — use the pin on the card")
|
|
95
|
+
return [NodeWarning(message=m, source_version=None, kind=KIND) for m in messages]
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def acquire_port(
|
|
99
|
+
node: BaseNode,
|
|
100
|
+
port_id: str,
|
|
101
|
+
*,
|
|
102
|
+
variant_key: Hashable,
|
|
103
|
+
load: Callable[[ResolvedModel], T],
|
|
104
|
+
release: Callable[[T], None],
|
|
105
|
+
) -> T:
|
|
106
|
+
"""Resolve *port_id* and hold its loaded model for *node*; nodes share one load per key."""
|
|
107
|
+
resolved = resolve_port(node, port_id)
|
|
108
|
+
return models_state().pool.acquire(
|
|
109
|
+
(resolved.key, variant_key), node, load=lambda: load(resolved), release=release
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def release_node(node: BaseNode) -> None:
|
|
114
|
+
"""Drop *node*'s holds. Call from ``on_shutdown`` and, as a backstop, ``on_teardown``."""
|
|
115
|
+
models_state().pool.release(node)
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""What a catalog entry is, in words: a one-line summary, a plain-text description, and search text.
|
|
2
|
+
|
|
3
|
+
Used wherever a person chooses between models (the model picker, the Models editor),
|
|
4
|
+
so both describe an entry the same way.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import re
|
|
10
|
+
from typing import TYPE_CHECKING
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from haywire.core.catalog import CatalogEntry
|
|
14
|
+
|
|
15
|
+
from haybale_models.filters import COMMERCIAL, NON_COMMERCIAL
|
|
16
|
+
|
|
17
|
+
_NOT_NON_COMMERCIAL = re.compile(r"(?<!non-)commercial")
|
|
18
|
+
|
|
19
|
+
__all__ = ["entry_description", "entry_search_text", "entry_summary", "search_matches"]
|
|
20
|
+
|
|
21
|
+
#: Tags shown in a summary line; the rest are counted (``+2``).
|
|
22
|
+
SUMMARY_TAGS = 4
|
|
23
|
+
|
|
24
|
+
#: Longest description shown in a tip, in characters; longer text ends in ``…``.
|
|
25
|
+
DESCRIPTION_LIMIT = 400
|
|
26
|
+
|
|
27
|
+
_LINK = re.compile(r"\[([^\]]+)\]\([^)]*\)")
|
|
28
|
+
_MARKUP = re.compile(r"[*_`#>]+")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def entry_summary(entry: CatalogEntry, *, scale: bool = True) -> str:
|
|
32
|
+
"""Return what tells *entry* apart at a glance, such as ``4x · ESRGAN · anime, photo +2``.
|
|
33
|
+
|
|
34
|
+
Scale, architecture and the first tags, each left out when the entry has none.
|
|
35
|
+
``scale=False`` leaves the scale out, for a place that already shows it.
|
|
36
|
+
"""
|
|
37
|
+
parts: list[str] = []
|
|
38
|
+
if scale and entry.scale:
|
|
39
|
+
parts.append(f"{entry.scale}x")
|
|
40
|
+
if entry.architecture:
|
|
41
|
+
parts.append(entry.architecture)
|
|
42
|
+
if entry.tags:
|
|
43
|
+
shown = ", ".join(entry.tags[:SUMMARY_TAGS])
|
|
44
|
+
rest = len(entry.tags) - SUMMARY_TAGS
|
|
45
|
+
parts.append(f"{shown} +{rest}" if rest > 0 else shown)
|
|
46
|
+
return " · ".join(parts)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def entry_description(entry: CatalogEntry) -> str:
|
|
50
|
+
"""Return *entry*'s description as plain text for a tip, with purpose, author and licence below.
|
|
51
|
+
|
|
52
|
+
Markdown links keep their text, other markup is dropped, and a description longer
|
|
53
|
+
than ``DESCRIPTION_LIMIT`` characters is cut at a word and ends in ``…``.
|
|
54
|
+
"""
|
|
55
|
+
text = _plain(entry.description)
|
|
56
|
+
if len(text) > DESCRIPTION_LIMIT:
|
|
57
|
+
text = text[:DESCRIPTION_LIMIT].rsplit(" ", 1)[0] + " …"
|
|
58
|
+
facts = []
|
|
59
|
+
if entry.purpose:
|
|
60
|
+
facts.append("Purpose: " + ", ".join(entry.purpose))
|
|
61
|
+
if entry.author:
|
|
62
|
+
facts.append("By " + entry.author)
|
|
63
|
+
if licence := entry_licence_text(entry):
|
|
64
|
+
facts.append("Licence: " + licence)
|
|
65
|
+
return "\n".join(part for part in (text, " · ".join(facts)) if part)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def entry_licence_text(entry: CatalogEntry) -> str:
|
|
69
|
+
"""Return *entry*'s licence, followed by ``non-commercial`` unless its author states otherwise.
|
|
70
|
+
|
|
71
|
+
Empty for a commercial entry without a licence.
|
|
72
|
+
"""
|
|
73
|
+
parts = [entry.license, "" if entry.commercial else NON_COMMERCIAL]
|
|
74
|
+
return " · ".join(part for part in parts if part)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def entry_search_text(entry: CatalogEntry) -> str:
|
|
78
|
+
"""Return the lower-case text a search over *entry* matches; see :func:`search_matches`.
|
|
79
|
+
|
|
80
|
+
Its name, scale (``4x``), architecture, purpose, tags, licence, commercial use and description.
|
|
81
|
+
"""
|
|
82
|
+
words = [
|
|
83
|
+
entry.name,
|
|
84
|
+
f"{entry.scale}x" if entry.scale else "",
|
|
85
|
+
entry.architecture,
|
|
86
|
+
*entry.purpose,
|
|
87
|
+
*entry.tags,
|
|
88
|
+
entry.license,
|
|
89
|
+
COMMERCIAL if entry.commercial else NON_COMMERCIAL,
|
|
90
|
+
_plain(entry.description),
|
|
91
|
+
]
|
|
92
|
+
return " ".join(w for w in words if w).lower()
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def search_matches(query: str, text: str) -> bool:
|
|
96
|
+
"""Return whether every word of *query* appears somewhere in *text*, ignoring case.
|
|
97
|
+
|
|
98
|
+
A word may be part of a longer one, in any order. An empty query matches everything. The word
|
|
99
|
+
``commercial`` does not match ``non-commercial``.
|
|
100
|
+
"""
|
|
101
|
+
text = text.lower()
|
|
102
|
+
return all(
|
|
103
|
+
_NOT_NON_COMMERCIAL.search(text) if word == COMMERCIAL else word in text
|
|
104
|
+
for word in query.lower().split()
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _plain(markdown: str) -> str:
|
|
109
|
+
text = _LINK.sub(r"\1", markdown or "")
|
|
110
|
+
text = _MARKUP.sub("", text)
|
|
111
|
+
return " ".join(text.split())
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Models
|
|
2
|
+
|
|
3
|
+
`haybale-models:editor:ModelsEditor` · kind: editor
|
|
4
|
+
|
|
5
|
+
Model files on this machine and where they come from
|
|
6
|
+
|
|
7
|
+
## Details
|
|
8
|
+
|
|
9
|
+
- **default_slot**: `action`
|
|
10
|
+
- **opens**: `OpenBehavior.REQUIRED`
|
|
11
|
+
- **order**: `100`
|
|
12
|
+
|
|
13
|
+
## Notes
|
|
14
|
+
|
|
15
|
+
Lists the model catalog, the files in the Models volume and the Hugging Face files in use.
|
|
16
|
+
|
|
17
|
+
The **Filters** icon in the header opens the filter section. Its **Show:** row picks the sections
|
|
18
|
+
(**Catalog**, **Models**, **Huggingface**). Its search toggle opens a field that narrows every
|
|
19
|
+
section: each word must appear, in any order, and scale, licence and `commercial` count too. Its
|
|
20
|
+
**+** adds a filter on library, purpose, tags, architecture, scale, commercial use or status, which
|
|
21
|
+
narrows the catalog. Closing it switches them all off, so a closed section always means the full
|
|
22
|
+
list, and reopening it brings them back.
|
|
23
|
+
The **Needed** section is always shown: per open graph, the models it lacks; **Fetch all**
|
|
24
|
+
downloads them. Each section header counts what the section lists; hover it for the whole
|
|
25
|
+
volume's size.
|
|
26
|
+
|
|
27
|
+
A catalog row reads `non-commercial` unless its author states the model may be used commercially.
|
|
28
|
+
Each catalog resource shows its status: `local`, `HF cache`, `downloading`, `failed` or
|
|
29
|
+
`not downloaded`. **Models** lists the files in the Models volume that no catalog entry
|
|
30
|
+
occupies. **Huggingface** lists the cached files that catalog entries or open graphs use,
|
|
31
|
+
and what uses each; the Volumes editor shows where the cache lives. Download, Cancel and
|
|
32
|
+
Remove need admin access; a removal names the open graphs that use the file and the bytes
|
|
33
|
+
it frees. Cancel is offered only while a download can still be stopped: a Hugging Face
|
|
34
|
+
download, once started, runs to the end. Opening the editor and **Rescan** index the Models
|
|
35
|
+
volume on a background thread.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Fetch models
|
|
2
|
+
|
|
3
|
+
`haybale-models:farmhand:fetch` · kind: farmhand
|
|
4
|
+
|
|
5
|
+
Queue downloads: everything an open graph needs, or catalog entries by key (admin).
|
|
6
|
+
|
|
7
|
+
## Agent Instructions
|
|
8
|
+
|
|
9
|
+
Queues the downloads and returns their job ids; progress is in models_list jobs. Pass binding_id to fetch everything that graph needs, or keys=[<catalog key>, ...] to fetch the preferred variant of each entry. Needs admin access.
|
|
10
|
+
|
|
11
|
+
## Details
|
|
12
|
+
|
|
13
|
+
- **input_schema**: `{'type': 'object', 'properties': {'binding_id': {'type': 'string', 'default': None}, 'keys': {'type': 'array', 'items': {'type': 'string'}, 'default': None}}, 'required': []}`
|
|
14
|
+
- **annotations**: `{'read_only_hint': False, 'destructive_hint': False, 'idempotent_hint': False, 'open_world_hint': True}`
|
|
15
|
+
|
|
16
|
+
## Notes
|
|
17
|
+
|
|
18
|
+
Queues downloads of missing models. Needs ADMIN access.
|
|
19
|
+
|
|
20
|
+
Pass `binding_id` to fetch everything that open graph needs, or `keys` to fetch the
|
|
21
|
+
preferred variant of each catalog entry. Returns the job ids at once; the files
|
|
22
|
+
arrive in the background, so call `models_list` to follow the jobs. Downloads use
|
|
23
|
+
network and disk: call it only when the user wants the models.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# List models
|
|
2
|
+
|
|
3
|
+
`haybale-models:farmhand:list` · kind: farmhand
|
|
4
|
+
|
|
5
|
+
Catalog entries with per-variant status, indexed local files and download jobs.
|
|
6
|
+
|
|
7
|
+
## Agent Instructions
|
|
8
|
+
|
|
9
|
+
Lists the model catalog (every entry with each variant's size and status: local, HF cache, queued, downloading N %, failed, not downloaded), the files indexed in the models volume, and the download jobs. detail=true adds license, commercial and description to catalog rows.
|
|
10
|
+
|
|
11
|
+
## Details
|
|
12
|
+
|
|
13
|
+
- **input_schema**: `{'type': 'object', 'properties': {'detail': {'type': 'boolean', 'default': False}}, 'required': []}`
|
|
14
|
+
- **annotations**: `{'read_only_hint': True, 'destructive_hint': False, 'idempotent_hint': False, 'open_world_hint': False}`
|
|
15
|
+
|
|
16
|
+
## Notes
|
|
17
|
+
|
|
18
|
+
Lists the model catalog, the local model files and the download jobs.
|
|
19
|
+
|
|
20
|
+
Returns every catalog entry with its variants (size and status: local, HF cache,
|
|
21
|
+
queued, downloading, failed or not downloaded), every file indexed in the models
|
|
22
|
+
volume, and every download job with its progress. Call it first, to learn the
|
|
23
|
+
catalog keys that `models_fetch` takes and to follow a download. Pass
|
|
24
|
+
`detail=true` to add license, commercial (whether the author states the model may be used
|
|
25
|
+
commercially) and description to the catalog rows.
|
|
26
|
+
|
|
27
|
+
A failed job with `assisted` true can be finished by the user: they get the file from one of its
|
|
28
|
+
`page_urls` and hand it over with Download in browser in the Models editor.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Models a graph needs
|
|
2
|
+
|
|
3
|
+
`haybale-models:farmhand:needs` · kind: farmhand
|
|
4
|
+
|
|
5
|
+
The models an open graph references and does not have locally.
|
|
6
|
+
|
|
7
|
+
## Agent Instructions
|
|
8
|
+
|
|
9
|
+
Returns the missing models of an open graph, interiors included: label, size (null when unknown) and the node_ids that ask for it. Get binding_id from haystack_list_graphs.
|
|
10
|
+
|
|
11
|
+
## Details
|
|
12
|
+
|
|
13
|
+
- **input_schema**: `{'type': 'object', 'properties': {'binding_id': {'type': 'string'}}, 'required': ['binding_id']}`
|
|
14
|
+
- **annotations**: `{'read_only_hint': True, 'destructive_hint': False, 'idempotent_hint': False, 'open_world_hint': False}`
|
|
15
|
+
|
|
16
|
+
## Notes
|
|
17
|
+
|
|
18
|
+
Lists the models an open graph needs and this machine does not have.
|
|
19
|
+
|
|
20
|
+
Returns, for the graph under `binding_id`, each missing model with its label, size
|
|
21
|
+
(`null` when unknown) and the ids of the nodes that ask for it, interiors of
|
|
22
|
+
subgraphs and macros included, plus the known total in bytes. Call it before
|
|
23
|
+
starting a graph, or to decide what `models_fetch` should download. Get
|
|
24
|
+
`binding_id` from `haystack_list_graphs`.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Resolve Model
|
|
2
|
+
|
|
3
|
+
`haybale-models:node:ResolveModelNode` · kind: node
|
|
4
|
+
|
|
5
|
+
Gives the file of a model on this machine, with its sha256 and size
|
|
6
|
+
|
|
7
|
+
## Ports
|
|
8
|
+
|
|
9
|
+
| id | direction | type | description |
|
|
10
|
+
|---|---|---|---|
|
|
11
|
+
| `model` | inlet | `haybale-models:type:MODEL_REF` | Model to look up |
|
|
12
|
+
| `path` | outlet | `haywire-core:type:FILE_PATH` | The model's file on this machine |
|
|
13
|
+
| `sha256` | outlet | `haywire-core:type:STRING` | The file's sha256 checksum |
|
|
14
|
+
| `size` | outlet | `haywire-core:type:INT` | The file's size in bytes |
|
|
15
|
+
|
|
16
|
+
## Notes
|
|
17
|
+
|
|
18
|
+
Gives the file of a model on this machine, with its sha256 and size.
|
|
19
|
+
|
|
20
|
+
Pick the model on the card: a catalog entry, or a file by its address
|
|
21
|
+
(`hf://` or `https://`) or from the Models or Hugging Face cache folder.
|
|
22
|
+
Nothing is downloaded here: a model that is not on this machine is an
|
|
23
|
+
error until it is fetched in the Models editor.
|
|
24
|
+
|
|
25
|
+
- `Path`: the file, as a path inside the `Models` or `Hugging Face cache`
|
|
26
|
+
volume. For a model made of several files, or a whole-repo `hf://`
|
|
27
|
+
address, the folder holding them.
|
|
28
|
+
- `sha256`: the file's digest, empty when it is not known yet.
|
|
29
|
+
- `Size`: the size in bytes, of all files together for a model made of
|
|
30
|
+
several files.
|
|
31
|
+
|
|
32
|
+
For a catalog entry with several variants, the first one on disk in the
|
|
33
|
+
port's preferred order is used.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Models
|
|
2
|
+
|
|
3
|
+
`haybale-models:panel:ModelsSettingsPanel` · kind: panel
|
|
4
|
+
|
|
5
|
+
Model download behaviour: how many files download in parallel.
|
|
6
|
+
|
|
7
|
+
## Details
|
|
8
|
+
|
|
9
|
+
- **surface**: `barns`
|
|
10
|
+
- **order**: `10`
|
|
11
|
+
|
|
12
|
+
## Notes
|
|
13
|
+
|
|
14
|
+
Model download behaviour: how many files download in parallel.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Model
|
|
2
|
+
|
|
3
|
+
`haybale-models:type:MODEL_REF` · kind: type
|
|
4
|
+
|
|
5
|
+
A model, named by a catalog entry or by a file (url and sha256). Resolve Model turns it into a path on disk.
|
|
6
|
+
|
|
7
|
+
## Details
|
|
8
|
+
|
|
9
|
+
- **wire_type**: `haywire-core:wire:DataWire`
|
|
10
|
+
- **default**: `{'value': {}}`
|
|
11
|
+
- **widget_key**: `haybale-models:widget:ModelRefWidget`
|
|
12
|
+
- **color**: `#b07ad9`
|
|
13
|
+
|
|
14
|
+
## Notes
|
|
15
|
+
|
|
16
|
+
A model, named by a catalog entry or by a file.
|
|
17
|
+
|
|
18
|
+
The port's `filter` narrows the picker by catalog field; `prefer` is an ordered
|
|
19
|
+
list of tag sets used to pick a variant.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# ModelRefWidget
|
|
2
|
+
|
|
3
|
+
`haybale-models:widget:ModelRefWidget` · kind: widget
|
|
4
|
+
|
|
5
|
+
Pick a model
|
|
6
|
+
|
|
7
|
+
## Details
|
|
8
|
+
|
|
9
|
+
- **min_width**: `220`
|
|
10
|
+
|
|
11
|
+
## Notes
|
|
12
|
+
|
|
13
|
+
Pick the model a node uses.
|
|
14
|
+
|
|
15
|
+
The card shows one line: a state icon, the model's name and an edit button.
|
|
16
|
+
|
|
17
|
+
- Green icon: the model is on this machine.
|
|
18
|
+
- Amber `online_prediction` icon: an address that is not pinned yet; the pin
|
|
19
|
+
button next to it records the digest of the file on this machine.
|
|
20
|
+
- Amber icon: the model is not on this machine; fetch it in the Models editor.
|
|
21
|
+
- Red icon: no model chosen.
|
|
22
|
+
|
|
23
|
+
Hover the name for the details. The edit button opens the picker, with the
|
|
24
|
+
choice at the top and four tabs:
|
|
25
|
+
|
|
26
|
+
- **Catalog**: the catalog entries this port accepts. A catalog entry follows
|
|
27
|
+
the catalog: each machine uses the variant that suits it best.
|
|
28
|
+
- **Models Volume**: a file in the Models volume, named by its sha256: one you
|
|
29
|
+
put there or fetched by address. Catalog variants are in the Catalog tab.
|
|
30
|
+
- **Hugging Face**: a model file in the Hugging Face cache, named by its `hf://`
|
|
31
|
+
address and its sha256, so it works offline.
|
|
32
|
+
- **Address**: an `hf://` or `https://` address. An `hf://` address is pinned when
|
|
33
|
+
the Hub answers; an `https://` address once the file is on this machine.
|
|
34
|
+
|
|
35
|
+
**Use** stores the choice (pinned when its digest is known), **Cancel** drops it.
|
|
36
|
+
The picker never downloads: missing models are fetched in the Models editor.
|
|
37
|
+
|
|
38
|
+
Options (in `properties`):
|
|
39
|
+
|
|
40
|
+
- `filter`: catalog field to allowed values, such as `{"architecture": ["esrgan"]}`;
|
|
41
|
+
only matching entries are listed.
|
|
42
|
+
- `unavailable`: when set, the edit button is unavailable and this text is its
|
|
43
|
+
tooltip, for a node that cannot take a model yet. A node that learns later which
|
|
44
|
+
models fit sets `filter` and drops `unavailable` by rebuilding the port in `rejig`.
|
|
45
|
+
- `catalog_only`: when true, only catalog entries can be chosen: the other tabs are not shown,
|
|
46
|
+
for a node that needs what a catalog entry says about the model. A value already saved stays
|
|
47
|
+
shown until it is replaced.
|
|
48
|
+
- `prefer`: ordered list of tag sets for choosing a variant, such as
|
|
49
|
+
`[{"precision": "fp16"}, {}]`.
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
MODEL_REF.as_inlet("model", widget_config={"properties": {"filter": {"scale": [4]}}})
|
|
53
|
+
```
|