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.
Files changed (63) hide show
  1. haybale_models/OVERVIEW.md +30 -0
  2. haybale_models/QUICKREF.md +27 -0
  3. haybale_models/__init__.py +44 -0
  4. haybale_models/consumer.py +115 -0
  5. haybale_models/describe.py +111 -0
  6. haybale_models/docs/haybale-models.editor.ModelsEditor.md +35 -0
  7. haybale_models/docs/haybale-models.farmhand.fetch.md +23 -0
  8. haybale_models/docs/haybale-models.farmhand.list.md +28 -0
  9. haybale_models/docs/haybale-models.farmhand.needs.md +24 -0
  10. haybale_models/docs/haybale-models.node.ResolveModelNode.md +33 -0
  11. haybale_models/docs/haybale-models.panel.ModelsSettingsPanel.md +14 -0
  12. haybale_models/docs/haybale-models.setting.ModelsSettings.md +9 -0
  13. haybale_models/docs/haybale-models.state.ModelsState.md +9 -0
  14. haybale_models/docs/haybale-models.type.MODEL_REF.md +19 -0
  15. haybale_models/docs/haybale-models.widget.ModelRefWidget.md +53 -0
  16. haybale_models/download.py +675 -0
  17. haybale_models/editors/__init__.py +0 -0
  18. haybale_models/editors/assisted_dialog.py +180 -0
  19. haybale_models/editors/models_editor.py +1399 -0
  20. haybale_models/farmhands/__init__.py +0 -0
  21. haybale_models/farmhands/model_tools.py +225 -0
  22. haybale_models/filters.py +78 -0
  23. haybale_models/haybale.toml +13 -0
  24. haybale_models/hf.py +386 -0
  25. haybale_models/keys.py +10 -0
  26. haybale_models/matcher.py +50 -0
  27. haybale_models/needs.py +565 -0
  28. haybale_models/nodes/__init__.py +0 -0
  29. haybale_models/nodes/resolve_model.py +66 -0
  30. haybale_models/panels/__init__.py +1 -0
  31. haybale_models/panels/models_settings_panel.py +32 -0
  32. haybale_models/pool.py +113 -0
  33. haybale_models/py.typed +0 -0
  34. haybale_models/receive.py +150 -0
  35. haybale_models/resolver.py +418 -0
  36. haybale_models/settings/__init__.py +0 -0
  37. haybale_models/settings/models_settings.py +17 -0
  38. haybale_models/signals.py +18 -0
  39. haybale_models/sources/__init__.py +48 -0
  40. haybale_models/sources/base.py +195 -0
  41. haybale_models/sources/caches.py +124 -0
  42. haybale_models/sources/folder.py +143 -0
  43. haybale_models/sources/hf.py +110 -0
  44. haybale_models/sources/https.py +132 -0
  45. haybale_models/sources/registry.py +97 -0
  46. haybale_models/state/__init__.py +0 -0
  47. haybale_models/state/models_state.py +179 -0
  48. haybale_models/status.py +48 -0
  49. haybale_models/store/__init__.py +1 -0
  50. haybale_models/store/index.py +302 -0
  51. haybale_models/store/layout.py +118 -0
  52. haybale_models/store/records.py +125 -0
  53. haybale_models/types/__init__.py +0 -0
  54. haybale_models/types/model_ref.py +74 -0
  55. haybale_models/upload_route.py +176 -0
  56. haybale_models/value/__init__.py +5 -0
  57. haybale_models/value/model_ref.py +83 -0
  58. haybale_models/widgets/__init__.py +0 -0
  59. haybale_models/widgets/model_ref_widget.py +657 -0
  60. haybale_models-0.3.1.dist-info/METADATA +11 -0
  61. haybale_models-0.3.1.dist-info/RECORD +63 -0
  62. haybale_models-0.3.1.dist-info/WHEEL +4 -0
  63. 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,9 @@
1
+ # Models
2
+
3
+ `haybale-models:setting:ModelsSettings` · kind: setting
4
+
5
+ Model download behaviour
6
+
7
+ ## Notes
8
+
9
+ Settings for the model download queue.
@@ -0,0 +1,9 @@
1
+ # Models
2
+
3
+ `haybale-models:state:ModelsState` · kind: state
4
+
5
+ Model volumes, file index, download queue and the pool of loaded models
6
+
7
+ ## Notes
8
+
9
+ Owns the model volumes, the file index and the pool of loaded models.
@@ -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
+ ```