Compare commits
48 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b50ab153f9 | ||
|
|
072db3bea6 | ||
|
|
a6deca6d9a | ||
|
|
41c30e92e7 | ||
|
|
f579a740dd | ||
|
|
d37272532c | ||
|
|
12da6ef581 | ||
|
|
29d4384a75 | ||
|
|
c5be423d6b | ||
|
|
b4d3652d88 | ||
|
|
5715be2ca9 | ||
|
|
0d4d9222c6 | ||
|
|
afc85cdeb6 | ||
|
|
acc152b674 | ||
|
|
b07258cef2 | ||
|
|
31e54b7052 | ||
|
|
8c0bae50c3 | ||
|
|
530412cb9d | ||
|
|
61c8c70c6e | ||
|
|
d0399f4343 | ||
|
|
e2919d38b4 | ||
|
|
93c8607d51 | ||
|
|
b3d6ae15b3 | ||
|
|
2e21122aab | ||
|
|
1cd6cd6080 | ||
|
|
d7b4bf21a2 | ||
|
|
042a905c37 | ||
|
|
019c7029ea | ||
|
|
8773ccf74d | ||
|
|
1d5d6586f3 | ||
|
|
35740259de | ||
|
|
ab888e1e0b | ||
|
|
d9f0fcdb0c | ||
|
|
b124256817 | ||
|
|
af4b7c91be | ||
|
|
e57d2282d1 | ||
|
|
4027466c80 | ||
|
|
095d867147 | ||
|
|
caeb27c3a5 | ||
|
|
3d06e1c555 | ||
|
|
43a74c0de1 | ||
|
|
af93c8d1ee | ||
|
|
832e3f5ca3 | ||
|
|
079eccc92a | ||
|
|
b6951768c4 | ||
|
|
fca304debf | ||
|
|
14880e6dba | ||
|
|
f1059b0b82 |
@@ -293,6 +293,8 @@ Use `--tls-keyfile key.pem --tls-certfile cert.pem` to enable TLS/SSL, the app w
|
|||||||
|
|
||||||
## Support and dev channel
|
## Support and dev channel
|
||||||
|
|
||||||
|
[Discord](https://comfy.org/discord): Try the #help or #feedback channels.
|
||||||
|
|
||||||
[Matrix space: #comfyui_space:matrix.org](https://app.element.io/#/room/%23comfyui_space%3Amatrix.org) (it's like discord but open source).
|
[Matrix space: #comfyui_space:matrix.org](https://app.element.io/#/room/%23comfyui_space%3Amatrix.org) (it's like discord but open source).
|
||||||
|
|
||||||
See also: [https://www.comfy.org/](https://www.comfy.org/)
|
See also: [https://www.comfy.org/](https://www.comfy.org/)
|
||||||
@@ -309,7 +311,7 @@ For any bugs, issues, or feature requests related to the frontend, please use th
|
|||||||
|
|
||||||
The new frontend is now the default for ComfyUI. However, please note:
|
The new frontend is now the default for ComfyUI. However, please note:
|
||||||
|
|
||||||
1. The frontend in the main ComfyUI repository is updated weekly.
|
1. The frontend in the main ComfyUI repository is updated fortnightly.
|
||||||
2. Daily releases are available in the separate frontend repository.
|
2. Daily releases are available in the separate frontend repository.
|
||||||
|
|
||||||
To use the most up-to-date frontend version:
|
To use the most up-to-date frontend version:
|
||||||
@@ -326,7 +328,7 @@ To use the most up-to-date frontend version:
|
|||||||
--front-end-version Comfy-Org/ComfyUI_frontend@1.2.2
|
--front-end-version Comfy-Org/ComfyUI_frontend@1.2.2
|
||||||
```
|
```
|
||||||
|
|
||||||
This approach allows you to easily switch between the stable weekly release and the cutting-edge daily updates, or even specific versions for testing purposes.
|
This approach allows you to easily switch between the stable fortnightly release and the cutting-edge daily updates, or even specific versions for testing purposes.
|
||||||
|
|
||||||
### Accessing the Legacy Frontend
|
### Accessing the Legacy Frontend
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from folder_paths import models_dir, user_directory, output_directory, folder_names_and_paths
|
from folder_paths import folder_names_and_paths, get_directory_by_type
|
||||||
from api_server.services.file_service import FileService
|
|
||||||
from api_server.services.terminal_service import TerminalService
|
from api_server.services.terminal_service import TerminalService
|
||||||
import app.logger
|
import app.logger
|
||||||
|
import os
|
||||||
|
|
||||||
class InternalRoutes:
|
class InternalRoutes:
|
||||||
'''
|
'''
|
||||||
@@ -15,26 +15,10 @@ class InternalRoutes:
|
|||||||
def __init__(self, prompt_server):
|
def __init__(self, prompt_server):
|
||||||
self.routes: web.RouteTableDef = web.RouteTableDef()
|
self.routes: web.RouteTableDef = web.RouteTableDef()
|
||||||
self._app: Optional[web.Application] = None
|
self._app: Optional[web.Application] = None
|
||||||
self.file_service = FileService({
|
|
||||||
"models": models_dir,
|
|
||||||
"user": user_directory,
|
|
||||||
"output": output_directory
|
|
||||||
})
|
|
||||||
self.prompt_server = prompt_server
|
self.prompt_server = prompt_server
|
||||||
self.terminal_service = TerminalService(prompt_server)
|
self.terminal_service = TerminalService(prompt_server)
|
||||||
|
|
||||||
def setup_routes(self):
|
def setup_routes(self):
|
||||||
@self.routes.get('/files')
|
|
||||||
async def list_files(request):
|
|
||||||
directory_key = request.query.get('directory', '')
|
|
||||||
try:
|
|
||||||
file_list = self.file_service.list_files(directory_key)
|
|
||||||
return web.json_response({"files": file_list})
|
|
||||||
except ValueError as e:
|
|
||||||
return web.json_response({"error": str(e)}, status=400)
|
|
||||||
except Exception as e:
|
|
||||||
return web.json_response({"error": str(e)}, status=500)
|
|
||||||
|
|
||||||
@self.routes.get('/logs')
|
@self.routes.get('/logs')
|
||||||
async def get_logs(request):
|
async def get_logs(request):
|
||||||
return web.json_response("".join([(l["t"] + " - " + l["m"]) for l in app.logger.get_logs()]))
|
return web.json_response("".join([(l["t"] + " - " + l["m"]) for l in app.logger.get_logs()]))
|
||||||
@@ -67,6 +51,20 @@ class InternalRoutes:
|
|||||||
response[key] = folder_names_and_paths[key][0]
|
response[key] = folder_names_and_paths[key][0]
|
||||||
return web.json_response(response)
|
return web.json_response(response)
|
||||||
|
|
||||||
|
@self.routes.get('/files/{directory_type}')
|
||||||
|
async def get_files(request: web.Request) -> web.Response:
|
||||||
|
directory_type = request.match_info['directory_type']
|
||||||
|
if directory_type not in ("output", "input", "temp"):
|
||||||
|
return web.json_response({"error": "Invalid directory type"}, status=400)
|
||||||
|
|
||||||
|
directory = get_directory_by_type(directory_type)
|
||||||
|
sorted_files = sorted(
|
||||||
|
(entry for entry in os.scandir(directory) if entry.is_file()),
|
||||||
|
key=lambda entry: -entry.stat().st_mtime
|
||||||
|
)
|
||||||
|
return web.json_response([entry.name for entry in sorted_files], status=200)
|
||||||
|
|
||||||
|
|
||||||
def get_app(self):
|
def get_app(self):
|
||||||
if self._app is None:
|
if self._app is None:
|
||||||
self._app = web.Application()
|
self._app = web.Application()
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
from typing import Dict, List, Optional
|
|
||||||
from api_server.utils.file_operations import FileSystemOperations, FileSystemItem
|
|
||||||
|
|
||||||
class FileService:
|
|
||||||
def __init__(self, allowed_directories: Dict[str, str], file_system_ops: Optional[FileSystemOperations] = None):
|
|
||||||
self.allowed_directories: Dict[str, str] = allowed_directories
|
|
||||||
self.file_system_ops: FileSystemOperations = file_system_ops or FileSystemOperations()
|
|
||||||
|
|
||||||
def list_files(self, directory_key: str) -> List[FileSystemItem]:
|
|
||||||
if directory_key not in self.allowed_directories:
|
|
||||||
raise ValueError("Invalid directory key")
|
|
||||||
directory_path: str = self.allowed_directories[directory_key]
|
|
||||||
return self.file_system_ops.walk_directory(directory_path)
|
|
||||||
@@ -179,7 +179,7 @@ parser.add_argument(
|
|||||||
|
|
||||||
parser.add_argument("--user-directory", type=is_valid_directory, default=None, help="Set the ComfyUI user directory with an absolute path. Overrides --base-directory.")
|
parser.add_argument("--user-directory", type=is_valid_directory, default=None, help="Set the ComfyUI user directory with an absolute path. Overrides --base-directory.")
|
||||||
|
|
||||||
parser.add_argument("--disable-compres-response-body", action="store_true", help="Disable compressing response body.")
|
parser.add_argument("--enable-compress-response-body", action="store_true", help="Enable compressing response body.")
|
||||||
|
|
||||||
if comfy.options.args_parsing:
|
if comfy.options.args_parsing:
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
@@ -191,3 +191,6 @@ if args.windows_standalone_build:
|
|||||||
|
|
||||||
if args.disable_auto_launch:
|
if args.disable_auto_launch:
|
||||||
args.auto_launch = False
|
args.auto_launch = False
|
||||||
|
|
||||||
|
if args.force_fp16:
|
||||||
|
args.fp16_unet = True
|
||||||
|
|||||||
@@ -104,7 +104,8 @@ class CLIPTextModel_(torch.nn.Module):
|
|||||||
mask = 1.0 - attention_mask.to(x.dtype).reshape((attention_mask.shape[0], 1, -1, attention_mask.shape[-1])).expand(attention_mask.shape[0], 1, attention_mask.shape[-1], attention_mask.shape[-1])
|
mask = 1.0 - attention_mask.to(x.dtype).reshape((attention_mask.shape[0], 1, -1, attention_mask.shape[-1])).expand(attention_mask.shape[0], 1, attention_mask.shape[-1], attention_mask.shape[-1])
|
||||||
mask = mask.masked_fill(mask.to(torch.bool), -torch.finfo(x.dtype).max)
|
mask = mask.masked_fill(mask.to(torch.bool), -torch.finfo(x.dtype).max)
|
||||||
|
|
||||||
causal_mask = torch.empty(x.shape[1], x.shape[1], dtype=x.dtype, device=x.device).fill_(-torch.finfo(x.dtype).max).triu_(1)
|
causal_mask = torch.full((x.shape[1], x.shape[1]), -torch.finfo(x.dtype).max, dtype=x.dtype, device=x.device).triu_(1)
|
||||||
|
|
||||||
if mask is not None:
|
if mask is not None:
|
||||||
mask += causal_mask
|
mask += causal_mask
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -66,13 +66,26 @@ class IO(StrEnum):
|
|||||||
b = frozenset(value.split(","))
|
b = frozenset(value.split(","))
|
||||||
return not (b.issubset(a) or a.issubset(b))
|
return not (b.issubset(a) or a.issubset(b))
|
||||||
|
|
||||||
|
class RemoteInputOptions(TypedDict):
|
||||||
|
route: str
|
||||||
|
"""The route to the remote source."""
|
||||||
|
refresh_button: bool
|
||||||
|
"""Specifies whether to show a refresh button in the UI below the widget."""
|
||||||
|
control_after_refresh: Literal["first", "last"]
|
||||||
|
"""Specifies the control after the refresh button is clicked. If "first", the first item will be automatically selected, and so on."""
|
||||||
|
timeout: int
|
||||||
|
"""The maximum amount of time to wait for a response from the remote source in milliseconds."""
|
||||||
|
max_retries: int
|
||||||
|
"""The maximum number of retries before aborting the request."""
|
||||||
|
refresh: int
|
||||||
|
"""The TTL of the remote input's value in milliseconds. Specifies the interval at which the remote input's value is refreshed."""
|
||||||
|
|
||||||
class InputTypeOptions(TypedDict):
|
class InputTypeOptions(TypedDict):
|
||||||
"""Provides type hinting for the return type of the INPUT_TYPES node function.
|
"""Provides type hinting for the return type of the INPUT_TYPES node function.
|
||||||
|
|
||||||
Due to IDE limitations with unions, for now all options are available for all types (e.g. `label_on` is hinted even when the type is not `IO.BOOLEAN`).
|
Due to IDE limitations with unions, for now all options are available for all types (e.g. `label_on` is hinted even when the type is not `IO.BOOLEAN`).
|
||||||
|
|
||||||
Comfy Docs: https://docs.comfy.org/essentials/custom_node_datatypes
|
Comfy Docs: https://docs.comfy.org/custom-nodes/backend/datatypes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
default: bool | str | float | int | list | tuple
|
default: bool | str | float | int | list | tuple
|
||||||
@@ -113,6 +126,14 @@ class InputTypeOptions(TypedDict):
|
|||||||
# defaultVal: str
|
# defaultVal: str
|
||||||
dynamicPrompts: bool
|
dynamicPrompts: bool
|
||||||
"""Causes the front-end to evaluate dynamic prompts (``STRING``)"""
|
"""Causes the front-end to evaluate dynamic prompts (``STRING``)"""
|
||||||
|
# class InputTypeCombo(InputTypeOptions):
|
||||||
|
image_upload: bool
|
||||||
|
"""Specifies whether the input should have an image upload button and image preview attached to it. Requires that the input's name is `image`."""
|
||||||
|
image_folder: Literal["input", "output", "temp"]
|
||||||
|
"""Specifies which folder to get preview images from if the input has the ``image_upload`` flag.
|
||||||
|
"""
|
||||||
|
remote: RemoteInputOptions
|
||||||
|
"""Specifies the configuration for a remote input."""
|
||||||
|
|
||||||
|
|
||||||
class HiddenInputTypeDict(TypedDict):
|
class HiddenInputTypeDict(TypedDict):
|
||||||
@@ -133,7 +154,7 @@ class HiddenInputTypeDict(TypedDict):
|
|||||||
class InputTypeDict(TypedDict):
|
class InputTypeDict(TypedDict):
|
||||||
"""Provides type hinting for node INPUT_TYPES.
|
"""Provides type hinting for node INPUT_TYPES.
|
||||||
|
|
||||||
Comfy Docs: https://docs.comfy.org/essentials/custom_node_more_on_inputs
|
Comfy Docs: https://docs.comfy.org/custom-nodes/backend/more_on_inputs
|
||||||
"""
|
"""
|
||||||
|
|
||||||
required: dict[str, tuple[IO, InputTypeOptions]]
|
required: dict[str, tuple[IO, InputTypeOptions]]
|
||||||
@@ -143,14 +164,14 @@ class InputTypeDict(TypedDict):
|
|||||||
hidden: HiddenInputTypeDict
|
hidden: HiddenInputTypeDict
|
||||||
"""Offers advanced functionality and server-client communication.
|
"""Offers advanced functionality and server-client communication.
|
||||||
|
|
||||||
Comfy Docs: https://docs.comfy.org/essentials/custom_node_more_on_inputs#hidden-inputs
|
Comfy Docs: https://docs.comfy.org/custom-nodes/backend/more_on_inputs#hidden-inputs
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class ComfyNodeABC(ABC):
|
class ComfyNodeABC(ABC):
|
||||||
"""Abstract base class for Comfy nodes. Includes the names and expected types of attributes.
|
"""Abstract base class for Comfy nodes. Includes the names and expected types of attributes.
|
||||||
|
|
||||||
Comfy Docs: https://docs.comfy.org/essentials/custom_node_server_overview
|
Comfy Docs: https://docs.comfy.org/custom-nodes/backend/server_overview
|
||||||
"""
|
"""
|
||||||
|
|
||||||
DESCRIPTION: str
|
DESCRIPTION: str
|
||||||
@@ -167,7 +188,7 @@ class ComfyNodeABC(ABC):
|
|||||||
CATEGORY: str
|
CATEGORY: str
|
||||||
"""The category of the node, as per the "Add Node" menu.
|
"""The category of the node, as per the "Add Node" menu.
|
||||||
|
|
||||||
Comfy Docs: https://docs.comfy.org/essentials/custom_node_server_overview#category
|
Comfy Docs: https://docs.comfy.org/custom-nodes/backend/server_overview#category
|
||||||
"""
|
"""
|
||||||
EXPERIMENTAL: bool
|
EXPERIMENTAL: bool
|
||||||
"""Flags a node as experimental, informing users that it may change or not work as expected."""
|
"""Flags a node as experimental, informing users that it may change or not work as expected."""
|
||||||
@@ -181,9 +202,9 @@ class ComfyNodeABC(ABC):
|
|||||||
|
|
||||||
* Must include the ``required`` key, which describes all inputs that must be connected for the node to execute.
|
* Must include the ``required`` key, which describes all inputs that must be connected for the node to execute.
|
||||||
* The ``optional`` key can be added to describe inputs which do not need to be connected.
|
* The ``optional`` key can be added to describe inputs which do not need to be connected.
|
||||||
* The ``hidden`` key offers some advanced functionality. More info at: https://docs.comfy.org/essentials/custom_node_more_on_inputs#hidden-inputs
|
* The ``hidden`` key offers some advanced functionality. More info at: https://docs.comfy.org/custom-nodes/backend/more_on_inputs#hidden-inputs
|
||||||
|
|
||||||
Comfy Docs: https://docs.comfy.org/essentials/custom_node_server_overview#input-types
|
Comfy Docs: https://docs.comfy.org/custom-nodes/backend/server_overview#input-types
|
||||||
"""
|
"""
|
||||||
return {"required": {}}
|
return {"required": {}}
|
||||||
|
|
||||||
@@ -198,7 +219,7 @@ class ComfyNodeABC(ABC):
|
|||||||
|
|
||||||
By default, a node is not considered an output. Set ``OUTPUT_NODE = True`` to specify that it is.
|
By default, a node is not considered an output. Set ``OUTPUT_NODE = True`` to specify that it is.
|
||||||
|
|
||||||
Comfy Docs: https://docs.comfy.org/essentials/custom_node_server_overview#output-node
|
Comfy Docs: https://docs.comfy.org/custom-nodes/backend/server_overview#output-node
|
||||||
"""
|
"""
|
||||||
INPUT_IS_LIST: bool
|
INPUT_IS_LIST: bool
|
||||||
"""A flag indicating if this node implements the additional code necessary to deal with OUTPUT_IS_LIST nodes.
|
"""A flag indicating if this node implements the additional code necessary to deal with OUTPUT_IS_LIST nodes.
|
||||||
@@ -209,7 +230,7 @@ class ComfyNodeABC(ABC):
|
|||||||
|
|
||||||
A node can also override the default input behaviour and receive the whole list in a single call. This is done by setting a class attribute `INPUT_IS_LIST` to ``True``.
|
A node can also override the default input behaviour and receive the whole list in a single call. This is done by setting a class attribute `INPUT_IS_LIST` to ``True``.
|
||||||
|
|
||||||
Comfy Docs: https://docs.comfy.org/essentials/custom_node_lists#list-processing
|
Comfy Docs: https://docs.comfy.org/custom-nodes/backend/lists#list-processing
|
||||||
"""
|
"""
|
||||||
OUTPUT_IS_LIST: tuple[bool]
|
OUTPUT_IS_LIST: tuple[bool]
|
||||||
"""A tuple indicating which node outputs are lists, but will be connected to nodes that expect individual items.
|
"""A tuple indicating which node outputs are lists, but will be connected to nodes that expect individual items.
|
||||||
@@ -227,7 +248,7 @@ class ComfyNodeABC(ABC):
|
|||||||
the node should provide a class attribute `OUTPUT_IS_LIST`, which is a ``tuple[bool]``, of the same length as `RETURN_TYPES`,
|
the node should provide a class attribute `OUTPUT_IS_LIST`, which is a ``tuple[bool]``, of the same length as `RETURN_TYPES`,
|
||||||
specifying which outputs which should be so treated.
|
specifying which outputs which should be so treated.
|
||||||
|
|
||||||
Comfy Docs: https://docs.comfy.org/essentials/custom_node_lists#list-processing
|
Comfy Docs: https://docs.comfy.org/custom-nodes/backend/lists#list-processing
|
||||||
"""
|
"""
|
||||||
|
|
||||||
RETURN_TYPES: tuple[IO]
|
RETURN_TYPES: tuple[IO]
|
||||||
@@ -237,19 +258,19 @@ class ComfyNodeABC(ABC):
|
|||||||
|
|
||||||
RETURN_TYPES = (IO.INT, "INT", "CUSTOM_TYPE")
|
RETURN_TYPES = (IO.INT, "INT", "CUSTOM_TYPE")
|
||||||
|
|
||||||
Comfy Docs: https://docs.comfy.org/essentials/custom_node_server_overview#return-types
|
Comfy Docs: https://docs.comfy.org/custom-nodes/backend/server_overview#return-types
|
||||||
"""
|
"""
|
||||||
RETURN_NAMES: tuple[str]
|
RETURN_NAMES: tuple[str]
|
||||||
"""The output slot names for each item in `RETURN_TYPES`, e.g. ``RETURN_NAMES = ("count", "filter_string")``
|
"""The output slot names for each item in `RETURN_TYPES`, e.g. ``RETURN_NAMES = ("count", "filter_string")``
|
||||||
|
|
||||||
Comfy Docs: https://docs.comfy.org/essentials/custom_node_server_overview#return-names
|
Comfy Docs: https://docs.comfy.org/custom-nodes/backend/server_overview#return-names
|
||||||
"""
|
"""
|
||||||
OUTPUT_TOOLTIPS: tuple[str]
|
OUTPUT_TOOLTIPS: tuple[str]
|
||||||
"""A tuple of strings to use as tooltips for node outputs, one for each item in `RETURN_TYPES`."""
|
"""A tuple of strings to use as tooltips for node outputs, one for each item in `RETURN_TYPES`."""
|
||||||
FUNCTION: str
|
FUNCTION: str
|
||||||
"""The name of the function to execute as a literal string, e.g. `FUNCTION = "execute"`
|
"""The name of the function to execute as a literal string, e.g. `FUNCTION = "execute"`
|
||||||
|
|
||||||
Comfy Docs: https://docs.comfy.org/essentials/custom_node_server_overview#function
|
Comfy Docs: https://docs.comfy.org/custom-nodes/backend/server_overview#function
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -267,7 +288,7 @@ class CheckLazyMixin:
|
|||||||
Params should match the nodes execution ``FUNCTION`` (self, and all inputs by name).
|
Params should match the nodes execution ``FUNCTION`` (self, and all inputs by name).
|
||||||
Will be executed repeatedly until it returns an empty list, or all requested items were already evaluated (and sent as params).
|
Will be executed repeatedly until it returns an empty list, or all requested items were already evaluated (and sent as params).
|
||||||
|
|
||||||
Comfy Docs: https://docs.comfy.org/essentials/custom_node_lazy_evaluation#defining-check-lazy-status
|
Comfy Docs: https://docs.comfy.org/custom-nodes/backend/lazy_evaluation#defining-check-lazy-status
|
||||||
"""
|
"""
|
||||||
|
|
||||||
need = [name for name in kwargs if kwargs[name] is None]
|
need = [name for name in kwargs if kwargs[name] is None]
|
||||||
|
|||||||
@@ -1267,7 +1267,7 @@ def sample_dpmpp_2m_cfg_pp(model, x, sigmas, extra_args=None, callback=None, dis
|
|||||||
return x
|
return x
|
||||||
|
|
||||||
@torch.no_grad()
|
@torch.no_grad()
|
||||||
def res_multistep(model, x, sigmas, extra_args=None, callback=None, disable=None, s_churn=0., s_tmin=0., s_tmax=float('inf'), s_noise=1., noise_sampler=None, cfg_pp=False):
|
def res_multistep(model, x, sigmas, extra_args=None, callback=None, disable=None, s_noise=1., noise_sampler=None, eta=1., cfg_pp=False):
|
||||||
extra_args = {} if extra_args is None else extra_args
|
extra_args = {} if extra_args is None else extra_args
|
||||||
seed = extra_args.get("seed", None)
|
seed = extra_args.get("seed", None)
|
||||||
noise_sampler = default_noise_sampler(x, seed=seed) if noise_sampler is None else noise_sampler
|
noise_sampler = default_noise_sampler(x, seed=seed) if noise_sampler is None else noise_sampler
|
||||||
@@ -1289,53 +1289,60 @@ def res_multistep(model, x, sigmas, extra_args=None, callback=None, disable=None
|
|||||||
extra_args["model_options"] = comfy.model_patcher.set_model_options_post_cfg_function(model_options, post_cfg_function, disable_cfg1_optimization=True)
|
extra_args["model_options"] = comfy.model_patcher.set_model_options_post_cfg_function(model_options, post_cfg_function, disable_cfg1_optimization=True)
|
||||||
|
|
||||||
for i in trange(len(sigmas) - 1, disable=disable):
|
for i in trange(len(sigmas) - 1, disable=disable):
|
||||||
if s_churn > 0:
|
denoised = model(x, sigmas[i] * s_in, **extra_args)
|
||||||
gamma = min(s_churn / (len(sigmas) - 1), 2**0.5 - 1) if s_tmin <= sigmas[i] <= s_tmax else 0.0
|
sigma_down, sigma_up = get_ancestral_step(sigmas[i], sigmas[i + 1], eta=eta)
|
||||||
sigma_hat = sigmas[i] * (gamma + 1)
|
|
||||||
else:
|
|
||||||
gamma = 0
|
|
||||||
sigma_hat = sigmas[i]
|
|
||||||
|
|
||||||
if gamma > 0:
|
|
||||||
eps = torch.randn_like(x) * s_noise
|
|
||||||
x = x + eps * (sigma_hat**2 - sigmas[i] ** 2) ** 0.5
|
|
||||||
denoised = model(x, sigma_hat * s_in, **extra_args)
|
|
||||||
if callback is not None:
|
if callback is not None:
|
||||||
callback({"x": x, "i": i, "sigma": sigmas[i], "sigma_hat": sigma_hat, "denoised": denoised})
|
callback({"x": x, "i": i, "sigma": sigmas[i], "sigma_hat": sigmas[i], "denoised": denoised})
|
||||||
if sigmas[i + 1] == 0 or old_denoised is None:
|
if sigma_down == 0 or old_denoised is None:
|
||||||
# Euler method
|
# Euler method
|
||||||
if cfg_pp:
|
if cfg_pp:
|
||||||
d = to_d(x, sigma_hat, uncond_denoised)
|
d = to_d(x, sigmas[i], uncond_denoised)
|
||||||
x = denoised + d * sigmas[i + 1]
|
x = denoised + d * sigma_down
|
||||||
else:
|
else:
|
||||||
d = to_d(x, sigma_hat, denoised)
|
d = to_d(x, sigmas[i], denoised)
|
||||||
dt = sigmas[i + 1] - sigma_hat
|
dt = sigma_down - sigmas[i]
|
||||||
x = x + d * dt
|
x = x + d * dt
|
||||||
else:
|
else:
|
||||||
# Second order multistep method in https://arxiv.org/pdf/2308.02157
|
# Second order multistep method in https://arxiv.org/pdf/2308.02157
|
||||||
t, t_next, t_prev = t_fn(sigmas[i]), t_fn(sigmas[i + 1]), t_fn(sigmas[i - 1])
|
t, t_next, t_prev = t_fn(sigmas[i]), t_fn(sigma_down), t_fn(sigmas[i - 1])
|
||||||
h = t_next - t
|
h = t_next - t
|
||||||
c2 = (t_prev - t) / h
|
c2 = (t_prev - t) / h
|
||||||
|
|
||||||
phi1_val, phi2_val = phi1_fn(-h), phi2_fn(-h)
|
phi1_val, phi2_val = phi1_fn(-h), phi2_fn(-h)
|
||||||
b1 = torch.nan_to_num(phi1_val - 1.0 / c2 * phi2_val, nan=0.0)
|
b1 = torch.nan_to_num(phi1_val - phi2_val / c2, nan=0.0)
|
||||||
b2 = torch.nan_to_num(1.0 / c2 * phi2_val, nan=0.0)
|
b2 = torch.nan_to_num(phi2_val / c2, nan=0.0)
|
||||||
|
|
||||||
if cfg_pp:
|
if cfg_pp:
|
||||||
x = x + (denoised - uncond_denoised)
|
x = x + (denoised - uncond_denoised)
|
||||||
|
x = sigma_fn(h) * x + h * (b1 * uncond_denoised + b2 * old_denoised)
|
||||||
|
else:
|
||||||
|
x = sigma_fn(h) * x + h * (b1 * denoised + b2 * old_denoised)
|
||||||
|
|
||||||
x = (sigma_fn(t_next) / sigma_fn(t)) * x + h * (b1 * denoised + b2 * old_denoised)
|
# Noise addition
|
||||||
|
if sigmas[i + 1] > 0:
|
||||||
|
x = x + noise_sampler(sigmas[i], sigmas[i + 1]) * s_noise * sigma_up
|
||||||
|
|
||||||
old_denoised = denoised
|
if cfg_pp:
|
||||||
|
old_denoised = uncond_denoised
|
||||||
|
else:
|
||||||
|
old_denoised = denoised
|
||||||
return x
|
return x
|
||||||
|
|
||||||
@torch.no_grad()
|
@torch.no_grad()
|
||||||
def sample_res_multistep(model, x, sigmas, extra_args=None, callback=None, disable=None, s_churn=0., s_tmin=0., s_tmax=float('inf'), s_noise=1., noise_sampler=None):
|
def sample_res_multistep(model, x, sigmas, extra_args=None, callback=None, disable=None, s_noise=1., noise_sampler=None):
|
||||||
return res_multistep(model, x, sigmas, extra_args=extra_args, callback=callback, disable=disable, s_churn=s_churn, s_tmin=s_tmin, s_tmax=s_tmax, s_noise=s_noise, noise_sampler=noise_sampler, cfg_pp=False)
|
return res_multistep(model, x, sigmas, extra_args=extra_args, callback=callback, disable=disable, s_noise=s_noise, noise_sampler=noise_sampler, eta=0., cfg_pp=False)
|
||||||
|
|
||||||
@torch.no_grad()
|
@torch.no_grad()
|
||||||
def sample_res_multistep_cfg_pp(model, x, sigmas, extra_args=None, callback=None, disable=None, s_churn=0., s_tmin=0., s_tmax=float('inf'), s_noise=1., noise_sampler=None):
|
def sample_res_multistep_cfg_pp(model, x, sigmas, extra_args=None, callback=None, disable=None, s_noise=1., noise_sampler=None):
|
||||||
return res_multistep(model, x, sigmas, extra_args=extra_args, callback=callback, disable=disable, s_churn=s_churn, s_tmin=s_tmin, s_tmax=s_tmax, s_noise=s_noise, noise_sampler=noise_sampler, cfg_pp=True)
|
return res_multistep(model, x, sigmas, extra_args=extra_args, callback=callback, disable=disable, s_noise=s_noise, noise_sampler=noise_sampler, eta=0., cfg_pp=True)
|
||||||
|
|
||||||
|
@torch.no_grad()
|
||||||
|
def sample_res_multistep_ancestral(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None):
|
||||||
|
return res_multistep(model, x, sigmas, extra_args=extra_args, callback=callback, disable=disable, s_noise=s_noise, noise_sampler=noise_sampler, eta=eta, cfg_pp=False)
|
||||||
|
|
||||||
|
@torch.no_grad()
|
||||||
|
def sample_res_multistep_ancestral_cfg_pp(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None):
|
||||||
|
return res_multistep(model, x, sigmas, extra_args=extra_args, callback=callback, disable=disable, s_noise=s_noise, noise_sampler=noise_sampler, eta=eta, cfg_pp=True)
|
||||||
|
|
||||||
@torch.no_grad()
|
@torch.no_grad()
|
||||||
def sample_gradient_estimation(model, x, sigmas, extra_args=None, callback=None, disable=None, ge_gamma=2.):
|
def sample_gradient_estimation(model, x, sigmas, extra_args=None, callback=None, disable=None, ge_gamma=2.):
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ def attention(q: Tensor, k: Tensor, v: Tensor, pe: Tensor, mask=None) -> Tensor:
|
|||||||
|
|
||||||
def rope(pos: Tensor, dim: int, theta: int) -> Tensor:
|
def rope(pos: Tensor, dim: int, theta: int) -> Tensor:
|
||||||
assert dim % 2 == 0
|
assert dim % 2 == 0
|
||||||
if comfy.model_management.is_device_mps(pos.device) or comfy.model_management.is_intel_xpu():
|
if comfy.model_management.is_device_mps(pos.device) or comfy.model_management.is_intel_xpu() or comfy.model_management.is_directml_enabled():
|
||||||
device = torch.device("cpu")
|
device = torch.device("cpu")
|
||||||
else:
|
else:
|
||||||
device = pos.device
|
device = pos.device
|
||||||
|
|||||||
@@ -310,7 +310,7 @@ class HunyuanVideo(nn.Module):
|
|||||||
shape[i] = shape[i] // self.patch_size[i]
|
shape[i] = shape[i] // self.patch_size[i]
|
||||||
img = img.reshape([img.shape[0]] + shape + [self.out_channels] + self.patch_size)
|
img = img.reshape([img.shape[0]] + shape + [self.out_channels] + self.patch_size)
|
||||||
img = img.permute(0, 4, 1, 5, 2, 6, 3, 7)
|
img = img.permute(0, 4, 1, 5, 2, 6, 3, 7)
|
||||||
img = img.reshape(initial_shape)
|
img = img.reshape(initial_shape[0], self.out_channels, initial_shape[2], initial_shape[3], initial_shape[4])
|
||||||
return img
|
return img
|
||||||
|
|
||||||
def forward(self, x, timestep, context, y, guidance=None, attention_mask=None, control=None, transformer_options={}, **kwargs):
|
def forward(self, x, timestep, context, y, guidance=None, attention_mask=None, control=None, transformer_options={}, **kwargs):
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from typing import List, Optional, Tuple
|
|||||||
import torch
|
import torch
|
||||||
import torch.nn as nn
|
import torch.nn as nn
|
||||||
import torch.nn.functional as F
|
import torch.nn.functional as F
|
||||||
|
import comfy.ldm.common_dit
|
||||||
|
|
||||||
from comfy.ldm.modules.diffusionmodules.mmdit import TimestepEmbedder, RMSNorm
|
from comfy.ldm.modules.diffusionmodules.mmdit import TimestepEmbedder, RMSNorm
|
||||||
from comfy.ldm.modules.attention import optimized_attention_masked
|
from comfy.ldm.modules.attention import optimized_attention_masked
|
||||||
@@ -352,25 +353,6 @@ class FinalLayer(nn.Module):
|
|||||||
return x
|
return x
|
||||||
|
|
||||||
|
|
||||||
class RopeEmbedder:
|
|
||||||
def __init__(
|
|
||||||
self, theta: float = 10000.0, axes_dims: List[int] = (16, 56, 56), axes_lens: List[int] = (1, 512, 512)
|
|
||||||
):
|
|
||||||
super().__init__()
|
|
||||||
self.theta = theta
|
|
||||||
self.axes_dims = axes_dims
|
|
||||||
self.axes_lens = axes_lens
|
|
||||||
self.freqs_cis = NextDiT.precompute_freqs_cis(self.axes_dims, self.axes_lens, theta=self.theta)
|
|
||||||
|
|
||||||
def __call__(self, ids: torch.Tensor):
|
|
||||||
self.freqs_cis = [freqs_cis.to(ids.device) for freqs_cis in self.freqs_cis]
|
|
||||||
result = []
|
|
||||||
for i in range(len(self.axes_dims)):
|
|
||||||
index = ids[:, :, i:i+1].repeat(1, 1, self.freqs_cis[i].shape[-1]).to(torch.int64)
|
|
||||||
result.append(torch.gather(self.freqs_cis[i].unsqueeze(0).repeat(index.shape[0], 1, 1), dim=1, index=index))
|
|
||||||
return torch.cat(result, dim=-1)
|
|
||||||
|
|
||||||
|
|
||||||
class NextDiT(nn.Module):
|
class NextDiT(nn.Module):
|
||||||
"""
|
"""
|
||||||
Diffusion model with a Transformer backbone.
|
Diffusion model with a Transformer backbone.
|
||||||
@@ -481,7 +463,6 @@ class NextDiT(nn.Module):
|
|||||||
assert (dim // n_heads) == sum(axes_dims)
|
assert (dim // n_heads) == sum(axes_dims)
|
||||||
self.axes_dims = axes_dims
|
self.axes_dims = axes_dims
|
||||||
self.axes_lens = axes_lens
|
self.axes_lens = axes_lens
|
||||||
# self.rope_embedder = RopeEmbedder(axes_dims=axes_dims, axes_lens=axes_lens)
|
|
||||||
self.rope_embedder = EmbedND(dim=dim // n_heads, theta=10000.0, axes_dim=axes_dims)
|
self.rope_embedder = EmbedND(dim=dim // n_heads, theta=10000.0, axes_dim=axes_dims)
|
||||||
self.dim = dim
|
self.dim = dim
|
||||||
self.n_heads = n_heads
|
self.n_heads = n_heads
|
||||||
@@ -609,12 +590,13 @@ class NextDiT(nn.Module):
|
|||||||
|
|
||||||
return padded_full_embed, mask, img_sizes, l_effective_cap_len, freqs_cis
|
return padded_full_embed, mask, img_sizes, l_effective_cap_len, freqs_cis
|
||||||
|
|
||||||
|
|
||||||
# def forward(self, x, t, cap_feats, cap_mask):
|
# def forward(self, x, t, cap_feats, cap_mask):
|
||||||
def forward(self, x, timesteps, context, num_tokens, attention_mask=None, **kwargs):
|
def forward(self, x, timesteps, context, num_tokens, attention_mask=None, **kwargs):
|
||||||
t = 1.0 - timesteps
|
t = 1.0 - timesteps
|
||||||
cap_feats = context
|
cap_feats = context
|
||||||
cap_mask = attention_mask
|
cap_mask = attention_mask
|
||||||
|
bs, c, h, w = x.shape
|
||||||
|
x = comfy.ldm.common_dit.pad_to_patch_size(x, (self.patch_size, self.patch_size))
|
||||||
"""
|
"""
|
||||||
Forward pass of NextDiT.
|
Forward pass of NextDiT.
|
||||||
t: (N,) tensor of diffusion timesteps
|
t: (N,) tensor of diffusion timesteps
|
||||||
@@ -634,41 +616,7 @@ class NextDiT(nn.Module):
|
|||||||
x = layer(x, mask, freqs_cis, adaln_input)
|
x = layer(x, mask, freqs_cis, adaln_input)
|
||||||
|
|
||||||
x = self.final_layer(x, adaln_input)
|
x = self.final_layer(x, adaln_input)
|
||||||
x = self.unpatchify(x, img_size, cap_size, return_tensor=x_is_tensor)
|
x = self.unpatchify(x, img_size, cap_size, return_tensor=x_is_tensor)[:,:,:h,:w]
|
||||||
|
|
||||||
return -x
|
return -x
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def precompute_freqs_cis(
|
|
||||||
dim: List[int],
|
|
||||||
end: List[int],
|
|
||||||
theta: float = 10000.0,
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
Precompute the frequency tensor for complex exponentials (cis) with
|
|
||||||
given dimensions.
|
|
||||||
|
|
||||||
This function calculates a frequency tensor with complex exponentials
|
|
||||||
using the given dimension 'dim' and the end index 'end'. The 'theta'
|
|
||||||
parameter scales the frequencies. The returned tensor contains complex
|
|
||||||
values in complex64 data type.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
dim (list): Dimension of the frequency tensor.
|
|
||||||
end (list): End index for precomputing frequencies.
|
|
||||||
theta (float, optional): Scaling factor for frequency computation.
|
|
||||||
Defaults to 10000.0.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
torch.Tensor: Precomputed frequency tensor with complex
|
|
||||||
exponentials.
|
|
||||||
"""
|
|
||||||
freqs_cis = []
|
|
||||||
for i, (d, e) in enumerate(zip(dim, end)):
|
|
||||||
freqs = 1.0 / (theta ** (torch.arange(0, d, 2, dtype=torch.float64, device="cpu") / d))
|
|
||||||
timestep = torch.arange(e, device=freqs.device, dtype=torch.float64)
|
|
||||||
freqs = torch.outer(timestep, freqs).float()
|
|
||||||
freqs_cis_i = torch.polar(torch.ones_like(freqs), freqs).to(torch.complex64) # complex64
|
|
||||||
freqs_cis.append(freqs_cis_i)
|
|
||||||
|
|
||||||
return freqs_cis
|
|
||||||
|
|||||||
@@ -297,7 +297,7 @@ def vae_attention():
|
|||||||
if model_management.xformers_enabled_vae():
|
if model_management.xformers_enabled_vae():
|
||||||
logging.info("Using xformers attention in VAE")
|
logging.info("Using xformers attention in VAE")
|
||||||
return xformers_attention
|
return xformers_attention
|
||||||
elif model_management.pytorch_attention_enabled():
|
elif model_management.pytorch_attention_enabled_vae():
|
||||||
logging.info("Using pytorch attention in VAE")
|
logging.info("Using pytorch attention in VAE")
|
||||||
return pytorch_attention
|
return pytorch_attention
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -166,9 +166,6 @@ class BaseModel(torch.nn.Module):
|
|||||||
def get_dtype(self):
|
def get_dtype(self):
|
||||||
return self.diffusion_model.dtype
|
return self.diffusion_model.dtype
|
||||||
|
|
||||||
def is_adm(self):
|
|
||||||
return self.adm_channels > 0
|
|
||||||
|
|
||||||
def encode_adm(self, **kwargs):
|
def encode_adm(self, **kwargs):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -874,6 +871,15 @@ class HunyuanVideo(BaseModel):
|
|||||||
if cross_attn is not None:
|
if cross_attn is not None:
|
||||||
out['c_crossattn'] = comfy.conds.CONDRegular(cross_attn)
|
out['c_crossattn'] = comfy.conds.CONDRegular(cross_attn)
|
||||||
|
|
||||||
|
image = kwargs.get("concat_latent_image", None)
|
||||||
|
noise = kwargs.get("noise", None)
|
||||||
|
|
||||||
|
if image is not None:
|
||||||
|
padding_shape = (noise.shape[0], 16, noise.shape[2] - 1, noise.shape[3], noise.shape[4])
|
||||||
|
latent_padding = torch.zeros(padding_shape, device=noise.device, dtype=noise.dtype)
|
||||||
|
image_latents = torch.cat([image.to(noise), latent_padding], dim=2)
|
||||||
|
out['c_concat'] = comfy.conds.CONDNoiseShape(self.process_latent_in(image_latents))
|
||||||
|
|
||||||
guidance = kwargs.get("guidance", 6.0)
|
guidance = kwargs.get("guidance", 6.0)
|
||||||
if guidance is not None:
|
if guidance is not None:
|
||||||
out['guidance'] = comfy.conds.CONDRegular(torch.FloatTensor([guidance]))
|
out['guidance'] = comfy.conds.CONDRegular(torch.FloatTensor([guidance]))
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ def detect_unet_config(state_dict, key_prefix):
|
|||||||
if '{}txt_in.individual_token_refiner.blocks.0.norm1.weight'.format(key_prefix) in state_dict_keys: #Hunyuan Video
|
if '{}txt_in.individual_token_refiner.blocks.0.norm1.weight'.format(key_prefix) in state_dict_keys: #Hunyuan Video
|
||||||
dit_config = {}
|
dit_config = {}
|
||||||
dit_config["image_model"] = "hunyuan_video"
|
dit_config["image_model"] = "hunyuan_video"
|
||||||
dit_config["in_channels"] = 16
|
dit_config["in_channels"] = state_dict['{}img_in.proj.weight'.format(key_prefix)].shape[1] #SkyReels img2video has 32 input channels
|
||||||
dit_config["patch_size"] = [1, 2, 2]
|
dit_config["patch_size"] = [1, 2, 2]
|
||||||
dit_config["out_channels"] = 16
|
dit_config["out_channels"] = 16
|
||||||
dit_config["vec_in_dim"] = 768
|
dit_config["vec_in_dim"] = 768
|
||||||
|
|||||||
@@ -50,7 +50,9 @@ xpu_available = False
|
|||||||
torch_version = ""
|
torch_version = ""
|
||||||
try:
|
try:
|
||||||
torch_version = torch.version.__version__
|
torch_version = torch.version.__version__
|
||||||
xpu_available = (int(torch_version[0]) < 2 or (int(torch_version[0]) == 2 and int(torch_version[2]) <= 4)) and torch.xpu.is_available()
|
temp = torch_version.split(".")
|
||||||
|
torch_version_numeric = (int(temp[0]), int(temp[1]))
|
||||||
|
xpu_available = (torch_version_numeric[0] < 2 or (torch_version_numeric[0] == 2 and torch_version_numeric[1] <= 4)) and torch.xpu.is_available()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -218,7 +220,7 @@ def is_amd():
|
|||||||
|
|
||||||
MIN_WEIGHT_MEMORY_RATIO = 0.4
|
MIN_WEIGHT_MEMORY_RATIO = 0.4
|
||||||
if is_nvidia():
|
if is_nvidia():
|
||||||
MIN_WEIGHT_MEMORY_RATIO = 0.1
|
MIN_WEIGHT_MEMORY_RATIO = 0.0
|
||||||
|
|
||||||
ENABLE_PYTORCH_ATTENTION = False
|
ENABLE_PYTORCH_ATTENTION = False
|
||||||
if args.use_pytorch_cross_attention:
|
if args.use_pytorch_cross_attention:
|
||||||
@@ -227,7 +229,7 @@ if args.use_pytorch_cross_attention:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if is_nvidia():
|
if is_nvidia():
|
||||||
if int(torch_version[0]) >= 2:
|
if torch_version_numeric[0] >= 2:
|
||||||
if ENABLE_PYTORCH_ATTENTION == False and args.use_split_cross_attention == False and args.use_quad_cross_attention == False:
|
if ENABLE_PYTORCH_ATTENTION == False and args.use_split_cross_attention == False and args.use_quad_cross_attention == False:
|
||||||
ENABLE_PYTORCH_ATTENTION = True
|
ENABLE_PYTORCH_ATTENTION = True
|
||||||
if is_intel_xpu() or is_ascend_npu():
|
if is_intel_xpu() or is_ascend_npu():
|
||||||
@@ -236,13 +238,32 @@ try:
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
if is_amd():
|
||||||
|
arch = torch.cuda.get_device_properties(get_torch_device()).gcnArchName
|
||||||
|
logging.info("AMD arch: {}".format(arch))
|
||||||
|
if args.use_split_cross_attention == False and args.use_quad_cross_attention == False:
|
||||||
|
if torch_version_numeric[0] >= 2 and torch_version_numeric[1] >= 7: # works on 2.6 but doesn't actually seem to improve much
|
||||||
|
if any((a in arch) for a in ["gfx1100", "gfx1101"]): # TODO: more arches
|
||||||
|
ENABLE_PYTORCH_ATTENTION = True
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
if ENABLE_PYTORCH_ATTENTION:
|
if ENABLE_PYTORCH_ATTENTION:
|
||||||
torch.backends.cuda.enable_math_sdp(True)
|
torch.backends.cuda.enable_math_sdp(True)
|
||||||
torch.backends.cuda.enable_flash_sdp(True)
|
torch.backends.cuda.enable_flash_sdp(True)
|
||||||
torch.backends.cuda.enable_mem_efficient_sdp(True)
|
torch.backends.cuda.enable_mem_efficient_sdp(True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if int(torch_version[0]) == 2 and int(torch_version[2]) >= 5:
|
if is_nvidia() and args.fast:
|
||||||
|
torch.backends.cuda.matmul.allow_fp16_accumulation = True
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
if torch_version_numeric[0] == 2 and torch_version_numeric[1] >= 5:
|
||||||
torch.backends.cuda.allow_fp16_bf16_reduction_math_sdp(True)
|
torch.backends.cuda.allow_fp16_bf16_reduction_math_sdp(True)
|
||||||
except:
|
except:
|
||||||
logging.warning("Warning, could not set allow_fp16_bf16_reduction_math_sdp")
|
logging.warning("Warning, could not set allow_fp16_bf16_reduction_math_sdp")
|
||||||
@@ -256,15 +277,10 @@ elif args.highvram or args.gpu_only:
|
|||||||
vram_state = VRAMState.HIGH_VRAM
|
vram_state = VRAMState.HIGH_VRAM
|
||||||
|
|
||||||
FORCE_FP32 = False
|
FORCE_FP32 = False
|
||||||
FORCE_FP16 = False
|
|
||||||
if args.force_fp32:
|
if args.force_fp32:
|
||||||
logging.info("Forcing FP32, if this improves things please report it.")
|
logging.info("Forcing FP32, if this improves things please report it.")
|
||||||
FORCE_FP32 = True
|
FORCE_FP32 = True
|
||||||
|
|
||||||
if args.force_fp16:
|
|
||||||
logging.info("Forcing FP16.")
|
|
||||||
FORCE_FP16 = True
|
|
||||||
|
|
||||||
if lowvram_available:
|
if lowvram_available:
|
||||||
if set_vram_to in (VRAMState.LOW_VRAM, VRAMState.NO_VRAM):
|
if set_vram_to in (VRAMState.LOW_VRAM, VRAMState.NO_VRAM):
|
||||||
vram_state = set_vram_to
|
vram_state = set_vram_to
|
||||||
@@ -898,6 +914,11 @@ def pytorch_attention_enabled():
|
|||||||
global ENABLE_PYTORCH_ATTENTION
|
global ENABLE_PYTORCH_ATTENTION
|
||||||
return ENABLE_PYTORCH_ATTENTION
|
return ENABLE_PYTORCH_ATTENTION
|
||||||
|
|
||||||
|
def pytorch_attention_enabled_vae():
|
||||||
|
if is_amd():
|
||||||
|
return False # enabling pytorch attention on AMD currently causes crash when doing high res
|
||||||
|
return pytorch_attention_enabled()
|
||||||
|
|
||||||
def pytorch_attention_flash_attention():
|
def pytorch_attention_flash_attention():
|
||||||
global ENABLE_PYTORCH_ATTENTION
|
global ENABLE_PYTORCH_ATTENTION
|
||||||
if ENABLE_PYTORCH_ATTENTION:
|
if ENABLE_PYTORCH_ATTENTION:
|
||||||
@@ -908,6 +929,8 @@ def pytorch_attention_flash_attention():
|
|||||||
return True
|
return True
|
||||||
if is_ascend_npu():
|
if is_ascend_npu():
|
||||||
return True
|
return True
|
||||||
|
if is_amd():
|
||||||
|
return True #if you have pytorch attention enabled on AMD it probably supports at least mem efficient attention
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def mac_version():
|
def mac_version():
|
||||||
@@ -920,7 +943,7 @@ def force_upcast_attention_dtype():
|
|||||||
upcast = args.force_upcast_attention
|
upcast = args.force_upcast_attention
|
||||||
|
|
||||||
macos_version = mac_version()
|
macos_version = mac_version()
|
||||||
if macos_version is not None and ((14, 5) <= macos_version <= (15, 2)): # black image bug on recent versions of macOS
|
if macos_version is not None and ((14, 5) <= macos_version < (16,)): # black image bug on recent versions of macOS
|
||||||
upcast = True
|
upcast = True
|
||||||
|
|
||||||
if upcast:
|
if upcast:
|
||||||
@@ -990,21 +1013,26 @@ def is_device_mps(device):
|
|||||||
def is_device_cuda(device):
|
def is_device_cuda(device):
|
||||||
return is_device_type(device, 'cuda')
|
return is_device_type(device, 'cuda')
|
||||||
|
|
||||||
def should_use_fp16(device=None, model_params=0, prioritize_performance=True, manual_cast=False):
|
def is_directml_enabled():
|
||||||
global directml_enabled
|
global directml_enabled
|
||||||
|
if directml_enabled:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def should_use_fp16(device=None, model_params=0, prioritize_performance=True, manual_cast=False):
|
||||||
if device is not None:
|
if device is not None:
|
||||||
if is_device_cpu(device):
|
if is_device_cpu(device):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if FORCE_FP16:
|
if args.force_fp16:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if FORCE_FP32:
|
if FORCE_FP32:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if directml_enabled:
|
if is_directml_enabled():
|
||||||
return False
|
return True
|
||||||
|
|
||||||
if (device is not None and is_device_mps(device)) or mps_mode():
|
if (device is not None and is_device_mps(device)) or mps_mode():
|
||||||
return True
|
return True
|
||||||
@@ -1075,13 +1103,23 @@ def should_use_bf16(device=None, model_params=0, prioritize_performance=True, ma
|
|||||||
if is_intel_xpu():
|
if is_intel_xpu():
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
if is_ascend_npu():
|
||||||
|
return True
|
||||||
|
|
||||||
|
if is_amd():
|
||||||
|
arch = torch.cuda.get_device_properties(device).gcnArchName
|
||||||
|
if any((a in arch) for a in ["gfx1030", "gfx1031", "gfx1010", "gfx1011", "gfx1012", "gfx906", "gfx900", "gfx803"]): # RDNA2 and older don't support bf16
|
||||||
|
if manual_cast:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
props = torch.cuda.get_device_properties(device)
|
props = torch.cuda.get_device_properties(device)
|
||||||
if props.major >= 8:
|
if props.major >= 8:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
bf16_works = torch.cuda.is_bf16_supported()
|
bf16_works = torch.cuda.is_bf16_supported()
|
||||||
|
|
||||||
if bf16_works or manual_cast:
|
if bf16_works and manual_cast:
|
||||||
free_model_memory = maximum_vram_for_weights(device)
|
free_model_memory = maximum_vram_for_weights(device)
|
||||||
if (not prioritize_performance) or model_params * 4 > free_model_memory:
|
if (not prioritize_performance) or model_params * 4 > free_model_memory:
|
||||||
return True
|
return True
|
||||||
@@ -1100,11 +1138,11 @@ def supports_fp8_compute(device=None):
|
|||||||
if props.minor < 9:
|
if props.minor < 9:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if int(torch_version[0]) < 2 or (int(torch_version[0]) == 2 and int(torch_version[2]) < 3):
|
if torch_version_numeric[0] < 2 or (torch_version_numeric[0] == 2 and torch_version_numeric[1] < 3):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if WINDOWS:
|
if WINDOWS:
|
||||||
if (int(torch_version[0]) == 2 and int(torch_version[2]) < 4):
|
if (torch_version_numeric[0] == 2 and torch_version_numeric[1] < 4):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -96,8 +96,28 @@ def wipe_lowvram_weight(m):
|
|||||||
if hasattr(m, "prev_comfy_cast_weights"):
|
if hasattr(m, "prev_comfy_cast_weights"):
|
||||||
m.comfy_cast_weights = m.prev_comfy_cast_weights
|
m.comfy_cast_weights = m.prev_comfy_cast_weights
|
||||||
del m.prev_comfy_cast_weights
|
del m.prev_comfy_cast_weights
|
||||||
m.weight_function = None
|
|
||||||
m.bias_function = None
|
if hasattr(m, "weight_function"):
|
||||||
|
m.weight_function = []
|
||||||
|
|
||||||
|
if hasattr(m, "bias_function"):
|
||||||
|
m.bias_function = []
|
||||||
|
|
||||||
|
def move_weight_functions(m, device):
|
||||||
|
if device is None:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
memory = 0
|
||||||
|
if hasattr(m, "weight_function"):
|
||||||
|
for f in m.weight_function:
|
||||||
|
if hasattr(f, "move_to"):
|
||||||
|
memory += f.move_to(device=device)
|
||||||
|
|
||||||
|
if hasattr(m, "bias_function"):
|
||||||
|
for f in m.bias_function:
|
||||||
|
if hasattr(f, "move_to"):
|
||||||
|
memory += f.move_to(device=device)
|
||||||
|
return memory
|
||||||
|
|
||||||
class LowVramPatch:
|
class LowVramPatch:
|
||||||
def __init__(self, key, patches):
|
def __init__(self, key, patches):
|
||||||
@@ -192,11 +212,13 @@ class ModelPatcher:
|
|||||||
self.backup = {}
|
self.backup = {}
|
||||||
self.object_patches = {}
|
self.object_patches = {}
|
||||||
self.object_patches_backup = {}
|
self.object_patches_backup = {}
|
||||||
|
self.weight_wrapper_patches = {}
|
||||||
self.model_options = {"transformer_options":{}}
|
self.model_options = {"transformer_options":{}}
|
||||||
self.model_size()
|
self.model_size()
|
||||||
self.load_device = load_device
|
self.load_device = load_device
|
||||||
self.offload_device = offload_device
|
self.offload_device = offload_device
|
||||||
self.weight_inplace_update = weight_inplace_update
|
self.weight_inplace_update = weight_inplace_update
|
||||||
|
self.force_cast_weights = False
|
||||||
self.patches_uuid = uuid.uuid4()
|
self.patches_uuid = uuid.uuid4()
|
||||||
self.parent = None
|
self.parent = None
|
||||||
|
|
||||||
@@ -250,11 +272,14 @@ class ModelPatcher:
|
|||||||
n.patches_uuid = self.patches_uuid
|
n.patches_uuid = self.patches_uuid
|
||||||
|
|
||||||
n.object_patches = self.object_patches.copy()
|
n.object_patches = self.object_patches.copy()
|
||||||
|
n.weight_wrapper_patches = self.weight_wrapper_patches.copy()
|
||||||
n.model_options = copy.deepcopy(self.model_options)
|
n.model_options = copy.deepcopy(self.model_options)
|
||||||
n.backup = self.backup
|
n.backup = self.backup
|
||||||
n.object_patches_backup = self.object_patches_backup
|
n.object_patches_backup = self.object_patches_backup
|
||||||
n.parent = self
|
n.parent = self
|
||||||
|
|
||||||
|
n.force_cast_weights = self.force_cast_weights
|
||||||
|
|
||||||
# attachments
|
# attachments
|
||||||
n.attachments = {}
|
n.attachments = {}
|
||||||
for k in self.attachments:
|
for k in self.attachments:
|
||||||
@@ -402,6 +427,16 @@ class ModelPatcher:
|
|||||||
def add_object_patch(self, name, obj):
|
def add_object_patch(self, name, obj):
|
||||||
self.object_patches[name] = obj
|
self.object_patches[name] = obj
|
||||||
|
|
||||||
|
def set_model_compute_dtype(self, dtype):
|
||||||
|
self.add_object_patch("manual_cast_dtype", dtype)
|
||||||
|
if dtype is not None:
|
||||||
|
self.force_cast_weights = True
|
||||||
|
self.patches_uuid = uuid.uuid4() #TODO: optimize by preventing a full model reload for this
|
||||||
|
|
||||||
|
def add_weight_wrapper(self, name, function):
|
||||||
|
self.weight_wrapper_patches[name] = self.weight_wrapper_patches.get(name, []) + [function]
|
||||||
|
self.patches_uuid = uuid.uuid4()
|
||||||
|
|
||||||
def get_model_object(self, name: str) -> torch.nn.Module:
|
def get_model_object(self, name: str) -> torch.nn.Module:
|
||||||
"""Retrieves a nested attribute from an object using dot notation considering
|
"""Retrieves a nested attribute from an object using dot notation considering
|
||||||
object patches.
|
object patches.
|
||||||
@@ -566,6 +601,9 @@ class ModelPatcher:
|
|||||||
|
|
||||||
lowvram_weight = False
|
lowvram_weight = False
|
||||||
|
|
||||||
|
weight_key = "{}.weight".format(n)
|
||||||
|
bias_key = "{}.bias".format(n)
|
||||||
|
|
||||||
if not full_load and hasattr(m, "comfy_cast_weights"):
|
if not full_load and hasattr(m, "comfy_cast_weights"):
|
||||||
if mem_counter + module_mem >= lowvram_model_memory:
|
if mem_counter + module_mem >= lowvram_model_memory:
|
||||||
lowvram_weight = True
|
lowvram_weight = True
|
||||||
@@ -573,34 +611,46 @@ class ModelPatcher:
|
|||||||
if hasattr(m, "prev_comfy_cast_weights"): #Already lowvramed
|
if hasattr(m, "prev_comfy_cast_weights"): #Already lowvramed
|
||||||
continue
|
continue
|
||||||
|
|
||||||
weight_key = "{}.weight".format(n)
|
cast_weight = self.force_cast_weights
|
||||||
bias_key = "{}.bias".format(n)
|
|
||||||
|
|
||||||
if lowvram_weight:
|
if lowvram_weight:
|
||||||
|
if hasattr(m, "comfy_cast_weights"):
|
||||||
|
m.weight_function = []
|
||||||
|
m.bias_function = []
|
||||||
|
|
||||||
if weight_key in self.patches:
|
if weight_key in self.patches:
|
||||||
if force_patch_weights:
|
if force_patch_weights:
|
||||||
self.patch_weight_to_device(weight_key)
|
self.patch_weight_to_device(weight_key)
|
||||||
else:
|
else:
|
||||||
m.weight_function = LowVramPatch(weight_key, self.patches)
|
m.weight_function = [LowVramPatch(weight_key, self.patches)]
|
||||||
patch_counter += 1
|
patch_counter += 1
|
||||||
if bias_key in self.patches:
|
if bias_key in self.patches:
|
||||||
if force_patch_weights:
|
if force_patch_weights:
|
||||||
self.patch_weight_to_device(bias_key)
|
self.patch_weight_to_device(bias_key)
|
||||||
else:
|
else:
|
||||||
m.bias_function = LowVramPatch(bias_key, self.patches)
|
m.bias_function = [LowVramPatch(bias_key, self.patches)]
|
||||||
patch_counter += 1
|
patch_counter += 1
|
||||||
|
|
||||||
m.prev_comfy_cast_weights = m.comfy_cast_weights
|
cast_weight = True
|
||||||
m.comfy_cast_weights = True
|
|
||||||
else:
|
else:
|
||||||
if hasattr(m, "comfy_cast_weights"):
|
if hasattr(m, "comfy_cast_weights"):
|
||||||
if m.comfy_cast_weights:
|
wipe_lowvram_weight(m)
|
||||||
wipe_lowvram_weight(m)
|
|
||||||
|
|
||||||
if full_load or mem_counter + module_mem < lowvram_model_memory:
|
if full_load or mem_counter + module_mem < lowvram_model_memory:
|
||||||
mem_counter += module_mem
|
mem_counter += module_mem
|
||||||
load_completely.append((module_mem, n, m, params))
|
load_completely.append((module_mem, n, m, params))
|
||||||
|
|
||||||
|
if cast_weight:
|
||||||
|
m.prev_comfy_cast_weights = m.comfy_cast_weights
|
||||||
|
m.comfy_cast_weights = True
|
||||||
|
|
||||||
|
if weight_key in self.weight_wrapper_patches:
|
||||||
|
m.weight_function.extend(self.weight_wrapper_patches[weight_key])
|
||||||
|
|
||||||
|
if bias_key in self.weight_wrapper_patches:
|
||||||
|
m.bias_function.extend(self.weight_wrapper_patches[bias_key])
|
||||||
|
|
||||||
|
mem_counter += move_weight_functions(m, device_to)
|
||||||
|
|
||||||
load_completely.sort(reverse=True)
|
load_completely.sort(reverse=True)
|
||||||
for x in load_completely:
|
for x in load_completely:
|
||||||
n = x[1]
|
n = x[1]
|
||||||
@@ -662,6 +712,7 @@ class ModelPatcher:
|
|||||||
self.unpatch_hooks()
|
self.unpatch_hooks()
|
||||||
if self.model.model_lowvram:
|
if self.model.model_lowvram:
|
||||||
for m in self.model.modules():
|
for m in self.model.modules():
|
||||||
|
move_weight_functions(m, device_to)
|
||||||
wipe_lowvram_weight(m)
|
wipe_lowvram_weight(m)
|
||||||
|
|
||||||
self.model.model_lowvram = False
|
self.model.model_lowvram = False
|
||||||
@@ -728,15 +779,19 @@ class ModelPatcher:
|
|||||||
weight_key = "{}.weight".format(n)
|
weight_key = "{}.weight".format(n)
|
||||||
bias_key = "{}.bias".format(n)
|
bias_key = "{}.bias".format(n)
|
||||||
if move_weight:
|
if move_weight:
|
||||||
|
cast_weight = self.force_cast_weights
|
||||||
m.to(device_to)
|
m.to(device_to)
|
||||||
|
module_mem += move_weight_functions(m, device_to)
|
||||||
if lowvram_possible:
|
if lowvram_possible:
|
||||||
if weight_key in self.patches:
|
if weight_key in self.patches:
|
||||||
m.weight_function = LowVramPatch(weight_key, self.patches)
|
m.weight_function.append(LowVramPatch(weight_key, self.patches))
|
||||||
patch_counter += 1
|
patch_counter += 1
|
||||||
if bias_key in self.patches:
|
if bias_key in self.patches:
|
||||||
m.bias_function = LowVramPatch(bias_key, self.patches)
|
m.bias_function.append(LowVramPatch(bias_key, self.patches))
|
||||||
patch_counter += 1
|
patch_counter += 1
|
||||||
|
cast_weight = True
|
||||||
|
|
||||||
|
if cast_weight:
|
||||||
m.prev_comfy_cast_weights = m.comfy_cast_weights
|
m.prev_comfy_cast_weights = m.comfy_cast_weights
|
||||||
m.comfy_cast_weights = True
|
m.comfy_cast_weights = True
|
||||||
m.comfy_patched_weights = False
|
m.comfy_patched_weights = False
|
||||||
|
|||||||
33
comfy/ops.py
33
comfy/ops.py
@@ -38,21 +38,23 @@ def cast_bias_weight(s, input=None, dtype=None, device=None, bias_dtype=None):
|
|||||||
bias = None
|
bias = None
|
||||||
non_blocking = comfy.model_management.device_supports_non_blocking(device)
|
non_blocking = comfy.model_management.device_supports_non_blocking(device)
|
||||||
if s.bias is not None:
|
if s.bias is not None:
|
||||||
has_function = s.bias_function is not None
|
has_function = len(s.bias_function) > 0
|
||||||
bias = comfy.model_management.cast_to(s.bias, bias_dtype, device, non_blocking=non_blocking, copy=has_function)
|
bias = comfy.model_management.cast_to(s.bias, bias_dtype, device, non_blocking=non_blocking, copy=has_function)
|
||||||
if has_function:
|
if has_function:
|
||||||
bias = s.bias_function(bias)
|
for f in s.bias_function:
|
||||||
|
bias = f(bias)
|
||||||
|
|
||||||
has_function = s.weight_function is not None
|
has_function = len(s.weight_function) > 0
|
||||||
weight = comfy.model_management.cast_to(s.weight, dtype, device, non_blocking=non_blocking, copy=has_function)
|
weight = comfy.model_management.cast_to(s.weight, dtype, device, non_blocking=non_blocking, copy=has_function)
|
||||||
if has_function:
|
if has_function:
|
||||||
weight = s.weight_function(weight)
|
for f in s.weight_function:
|
||||||
|
weight = f(weight)
|
||||||
return weight, bias
|
return weight, bias
|
||||||
|
|
||||||
class CastWeightBiasOp:
|
class CastWeightBiasOp:
|
||||||
comfy_cast_weights = False
|
comfy_cast_weights = False
|
||||||
weight_function = None
|
weight_function = []
|
||||||
bias_function = None
|
bias_function = []
|
||||||
|
|
||||||
class disable_weight_init:
|
class disable_weight_init:
|
||||||
class Linear(torch.nn.Linear, CastWeightBiasOp):
|
class Linear(torch.nn.Linear, CastWeightBiasOp):
|
||||||
@@ -64,7 +66,7 @@ class disable_weight_init:
|
|||||||
return torch.nn.functional.linear(input, weight, bias)
|
return torch.nn.functional.linear(input, weight, bias)
|
||||||
|
|
||||||
def forward(self, *args, **kwargs):
|
def forward(self, *args, **kwargs):
|
||||||
if self.comfy_cast_weights:
|
if self.comfy_cast_weights or len(self.weight_function) > 0 or len(self.bias_function) > 0:
|
||||||
return self.forward_comfy_cast_weights(*args, **kwargs)
|
return self.forward_comfy_cast_weights(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
return super().forward(*args, **kwargs)
|
return super().forward(*args, **kwargs)
|
||||||
@@ -78,7 +80,7 @@ class disable_weight_init:
|
|||||||
return self._conv_forward(input, weight, bias)
|
return self._conv_forward(input, weight, bias)
|
||||||
|
|
||||||
def forward(self, *args, **kwargs):
|
def forward(self, *args, **kwargs):
|
||||||
if self.comfy_cast_weights:
|
if self.comfy_cast_weights or len(self.weight_function) > 0 or len(self.bias_function) > 0:
|
||||||
return self.forward_comfy_cast_weights(*args, **kwargs)
|
return self.forward_comfy_cast_weights(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
return super().forward(*args, **kwargs)
|
return super().forward(*args, **kwargs)
|
||||||
@@ -92,7 +94,7 @@ class disable_weight_init:
|
|||||||
return self._conv_forward(input, weight, bias)
|
return self._conv_forward(input, weight, bias)
|
||||||
|
|
||||||
def forward(self, *args, **kwargs):
|
def forward(self, *args, **kwargs):
|
||||||
if self.comfy_cast_weights:
|
if self.comfy_cast_weights or len(self.weight_function) > 0 or len(self.bias_function) > 0:
|
||||||
return self.forward_comfy_cast_weights(*args, **kwargs)
|
return self.forward_comfy_cast_weights(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
return super().forward(*args, **kwargs)
|
return super().forward(*args, **kwargs)
|
||||||
@@ -106,7 +108,7 @@ class disable_weight_init:
|
|||||||
return self._conv_forward(input, weight, bias)
|
return self._conv_forward(input, weight, bias)
|
||||||
|
|
||||||
def forward(self, *args, **kwargs):
|
def forward(self, *args, **kwargs):
|
||||||
if self.comfy_cast_weights:
|
if self.comfy_cast_weights or len(self.weight_function) > 0 or len(self.bias_function) > 0:
|
||||||
return self.forward_comfy_cast_weights(*args, **kwargs)
|
return self.forward_comfy_cast_weights(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
return super().forward(*args, **kwargs)
|
return super().forward(*args, **kwargs)
|
||||||
@@ -120,12 +122,11 @@ class disable_weight_init:
|
|||||||
return torch.nn.functional.group_norm(input, self.num_groups, weight, bias, self.eps)
|
return torch.nn.functional.group_norm(input, self.num_groups, weight, bias, self.eps)
|
||||||
|
|
||||||
def forward(self, *args, **kwargs):
|
def forward(self, *args, **kwargs):
|
||||||
if self.comfy_cast_weights:
|
if self.comfy_cast_weights or len(self.weight_function) > 0 or len(self.bias_function) > 0:
|
||||||
return self.forward_comfy_cast_weights(*args, **kwargs)
|
return self.forward_comfy_cast_weights(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
return super().forward(*args, **kwargs)
|
return super().forward(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class LayerNorm(torch.nn.LayerNorm, CastWeightBiasOp):
|
class LayerNorm(torch.nn.LayerNorm, CastWeightBiasOp):
|
||||||
def reset_parameters(self):
|
def reset_parameters(self):
|
||||||
return None
|
return None
|
||||||
@@ -139,7 +140,7 @@ class disable_weight_init:
|
|||||||
return torch.nn.functional.layer_norm(input, self.normalized_shape, weight, bias, self.eps)
|
return torch.nn.functional.layer_norm(input, self.normalized_shape, weight, bias, self.eps)
|
||||||
|
|
||||||
def forward(self, *args, **kwargs):
|
def forward(self, *args, **kwargs):
|
||||||
if self.comfy_cast_weights:
|
if self.comfy_cast_weights or len(self.weight_function) > 0 or len(self.bias_function) > 0:
|
||||||
return self.forward_comfy_cast_weights(*args, **kwargs)
|
return self.forward_comfy_cast_weights(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
return super().forward(*args, **kwargs)
|
return super().forward(*args, **kwargs)
|
||||||
@@ -160,7 +161,7 @@ class disable_weight_init:
|
|||||||
output_padding, self.groups, self.dilation)
|
output_padding, self.groups, self.dilation)
|
||||||
|
|
||||||
def forward(self, *args, **kwargs):
|
def forward(self, *args, **kwargs):
|
||||||
if self.comfy_cast_weights:
|
if self.comfy_cast_weights or len(self.weight_function) > 0 or len(self.bias_function) > 0:
|
||||||
return self.forward_comfy_cast_weights(*args, **kwargs)
|
return self.forward_comfy_cast_weights(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
return super().forward(*args, **kwargs)
|
return super().forward(*args, **kwargs)
|
||||||
@@ -181,7 +182,7 @@ class disable_weight_init:
|
|||||||
output_padding, self.groups, self.dilation)
|
output_padding, self.groups, self.dilation)
|
||||||
|
|
||||||
def forward(self, *args, **kwargs):
|
def forward(self, *args, **kwargs):
|
||||||
if self.comfy_cast_weights:
|
if self.comfy_cast_weights or len(self.weight_function) > 0 or len(self.bias_function) > 0:
|
||||||
return self.forward_comfy_cast_weights(*args, **kwargs)
|
return self.forward_comfy_cast_weights(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
return super().forward(*args, **kwargs)
|
return super().forward(*args, **kwargs)
|
||||||
@@ -199,7 +200,7 @@ class disable_weight_init:
|
|||||||
return torch.nn.functional.embedding(input, weight, self.padding_idx, self.max_norm, self.norm_type, self.scale_grad_by_freq, self.sparse).to(dtype=output_dtype)
|
return torch.nn.functional.embedding(input, weight, self.padding_idx, self.max_norm, self.norm_type, self.scale_grad_by_freq, self.sparse).to(dtype=output_dtype)
|
||||||
|
|
||||||
def forward(self, *args, **kwargs):
|
def forward(self, *args, **kwargs):
|
||||||
if self.comfy_cast_weights:
|
if self.comfy_cast_weights or len(self.weight_function) > 0 or len(self.bias_function) > 0:
|
||||||
return self.forward_comfy_cast_weights(*args, **kwargs)
|
return self.forward_comfy_cast_weights(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
if "out_dtype" in kwargs:
|
if "out_dtype" in kwargs:
|
||||||
|
|||||||
@@ -686,7 +686,8 @@ class Sampler:
|
|||||||
KSAMPLER_NAMES = ["euler", "euler_cfg_pp", "euler_ancestral", "euler_ancestral_cfg_pp", "heun", "heunpp2","dpm_2", "dpm_2_ancestral",
|
KSAMPLER_NAMES = ["euler", "euler_cfg_pp", "euler_ancestral", "euler_ancestral_cfg_pp", "heun", "heunpp2","dpm_2", "dpm_2_ancestral",
|
||||||
"lms", "dpm_fast", "dpm_adaptive", "dpmpp_2s_ancestral", "dpmpp_2s_ancestral_cfg_pp", "dpmpp_sde", "dpmpp_sde_gpu",
|
"lms", "dpm_fast", "dpm_adaptive", "dpmpp_2s_ancestral", "dpmpp_2s_ancestral_cfg_pp", "dpmpp_sde", "dpmpp_sde_gpu",
|
||||||
"dpmpp_2m", "dpmpp_2m_cfg_pp", "dpmpp_2m_sde", "dpmpp_2m_sde_gpu", "dpmpp_3m_sde", "dpmpp_3m_sde_gpu", "ddpm", "lcm",
|
"dpmpp_2m", "dpmpp_2m_cfg_pp", "dpmpp_2m_sde", "dpmpp_2m_sde_gpu", "dpmpp_3m_sde", "dpmpp_3m_sde_gpu", "ddpm", "lcm",
|
||||||
"ipndm", "ipndm_v", "deis", "res_multistep", "res_multistep_cfg_pp", "gradient_estimation"]
|
"ipndm", "ipndm_v", "deis", "res_multistep", "res_multistep_cfg_pp", "res_multistep_ancestral", "res_multistep_ancestral_cfg_pp",
|
||||||
|
"gradient_estimation"]
|
||||||
|
|
||||||
class KSAMPLER(Sampler):
|
class KSAMPLER(Sampler):
|
||||||
def __init__(self, sampler_function, extra_options={}, inpaint_options={}):
|
def __init__(self, sampler_function, extra_options={}, inpaint_options={}):
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ def load_torch_file(ckpt, safe_load=False, device=None):
|
|||||||
if "HeaderTooLarge" in message:
|
if "HeaderTooLarge" in message:
|
||||||
raise ValueError("{}\n\nFile path: {}\n\nThe safetensors file is corrupt or invalid. Make sure this is actually a safetensors file and not a ckpt or pt or other filetype.".format(message, ckpt))
|
raise ValueError("{}\n\nFile path: {}\n\nThe safetensors file is corrupt or invalid. Make sure this is actually a safetensors file and not a ckpt or pt or other filetype.".format(message, ckpt))
|
||||||
if "MetadataIncompleteBuffer" in message:
|
if "MetadataIncompleteBuffer" in message:
|
||||||
raise ValueError("{}\n\nFile path: {}\n\nThe safetensors file is incomplete. Check the file size and make sure you have copied/downloaded it correctly.".format(message, ckpt))
|
raise ValueError("{}\n\nFile path: {}\n\nThe safetensors file is corrupt/incomplete. Check the file size and make sure you have copied/downloaded it correctly.".format(message, ckpt))
|
||||||
raise e
|
raise e
|
||||||
else:
|
else:
|
||||||
if safe_load or ALWAYS_SAFE_LOAD:
|
if safe_load or ALWAYS_SAFE_LOAD:
|
||||||
|
|||||||
@@ -20,9 +20,7 @@ class Load3D():
|
|||||||
"width": ("INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}),
|
"width": ("INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}),
|
||||||
"height": ("INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}),
|
"height": ("INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}),
|
||||||
"material": (["original", "normal", "wireframe", "depth"],),
|
"material": (["original", "normal", "wireframe", "depth"],),
|
||||||
"light_intensity": ("INT", {"default": 10, "min": 1, "max": 20, "step": 1}),
|
|
||||||
"up_direction": (["original", "-x", "+x", "-y", "+y", "-z", "+z"],),
|
"up_direction": (["original", "-x", "+x", "-y", "+y", "-z", "+z"],),
|
||||||
"fov": ("INT", {"default": 75, "min": 10, "max": 150, "step": 1}),
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
RETURN_TYPES = ("IMAGE", "MASK", "STRING")
|
RETURN_TYPES = ("IMAGE", "MASK", "STRING")
|
||||||
@@ -34,22 +32,14 @@ class Load3D():
|
|||||||
CATEGORY = "3d"
|
CATEGORY = "3d"
|
||||||
|
|
||||||
def process(self, model_file, image, **kwargs):
|
def process(self, model_file, image, **kwargs):
|
||||||
if isinstance(image, dict):
|
image_path = folder_paths.get_annotated_filepath(image['image'])
|
||||||
image_path = folder_paths.get_annotated_filepath(image['image'])
|
mask_path = folder_paths.get_annotated_filepath(image['mask'])
|
||||||
mask_path = folder_paths.get_annotated_filepath(image['mask'])
|
|
||||||
|
|
||||||
load_image_node = nodes.LoadImage()
|
load_image_node = nodes.LoadImage()
|
||||||
output_image, ignore_mask = load_image_node.load_image(image=image_path)
|
output_image, ignore_mask = load_image_node.load_image(image=image_path)
|
||||||
ignore_image, output_mask = load_image_node.load_image(image=mask_path)
|
ignore_image, output_mask = load_image_node.load_image(image=mask_path)
|
||||||
|
|
||||||
return output_image, output_mask, model_file,
|
return output_image, output_mask, model_file,
|
||||||
else:
|
|
||||||
# to avoid the format is not dict which will happen the FE code is not compatibility to core,
|
|
||||||
# we need to this to double-check, it can be removed after merged FE into the core
|
|
||||||
image_path = folder_paths.get_annotated_filepath(image)
|
|
||||||
load_image_node = nodes.LoadImage()
|
|
||||||
output_image, output_mask = load_image_node.load_image(image=image_path)
|
|
||||||
return output_image, output_mask, model_file,
|
|
||||||
|
|
||||||
class Load3DAnimation():
|
class Load3DAnimation():
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -66,9 +56,7 @@ class Load3DAnimation():
|
|||||||
"width": ("INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}),
|
"width": ("INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}),
|
||||||
"height": ("INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}),
|
"height": ("INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}),
|
||||||
"material": (["original", "normal", "wireframe", "depth"],),
|
"material": (["original", "normal", "wireframe", "depth"],),
|
||||||
"light_intensity": ("INT", {"default": 10, "min": 1, "max": 20, "step": 1}),
|
|
||||||
"up_direction": (["original", "-x", "+x", "-y", "+y", "-z", "+z"],),
|
"up_direction": (["original", "-x", "+x", "-y", "+y", "-z", "+z"],),
|
||||||
"fov": ("INT", {"default": 75, "min": 10, "max": 150, "step": 1}),
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
RETURN_TYPES = ("IMAGE", "MASK", "STRING")
|
RETURN_TYPES = ("IMAGE", "MASK", "STRING")
|
||||||
@@ -80,20 +68,14 @@ class Load3DAnimation():
|
|||||||
CATEGORY = "3d"
|
CATEGORY = "3d"
|
||||||
|
|
||||||
def process(self, model_file, image, **kwargs):
|
def process(self, model_file, image, **kwargs):
|
||||||
if isinstance(image, dict):
|
image_path = folder_paths.get_annotated_filepath(image['image'])
|
||||||
image_path = folder_paths.get_annotated_filepath(image['image'])
|
mask_path = folder_paths.get_annotated_filepath(image['mask'])
|
||||||
mask_path = folder_paths.get_annotated_filepath(image['mask'])
|
|
||||||
|
|
||||||
load_image_node = nodes.LoadImage()
|
load_image_node = nodes.LoadImage()
|
||||||
output_image, ignore_mask = load_image_node.load_image(image=image_path)
|
output_image, ignore_mask = load_image_node.load_image(image=image_path)
|
||||||
ignore_image, output_mask = load_image_node.load_image(image=mask_path)
|
ignore_image, output_mask = load_image_node.load_image(image=mask_path)
|
||||||
|
|
||||||
return output_image, output_mask, model_file,
|
return output_image, output_mask, model_file,
|
||||||
else:
|
|
||||||
image_path = folder_paths.get_annotated_filepath(image)
|
|
||||||
load_image_node = nodes.LoadImage()
|
|
||||||
output_image, output_mask = load_image_node.load_image(image=image_path)
|
|
||||||
return output_image, output_mask, model_file,
|
|
||||||
|
|
||||||
class Preview3D():
|
class Preview3D():
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -101,9 +83,7 @@ class Preview3D():
|
|||||||
return {"required": {
|
return {"required": {
|
||||||
"model_file": ("STRING", {"default": "", "multiline": False}),
|
"model_file": ("STRING", {"default": "", "multiline": False}),
|
||||||
"material": (["original", "normal", "wireframe", "depth"],),
|
"material": (["original", "normal", "wireframe", "depth"],),
|
||||||
"light_intensity": ("INT", {"default": 10, "min": 1, "max": 20, "step": 1}),
|
|
||||||
"up_direction": (["original", "-x", "+x", "-y", "+y", "-z", "+z"],),
|
"up_direction": (["original", "-x", "+x", "-y", "+y", "-z", "+z"],),
|
||||||
"fov": ("INT", {"default": 75, "min": 10, "max": 150, "step": 1}),
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
OUTPUT_NODE = True
|
OUTPUT_NODE = True
|
||||||
@@ -123,9 +103,7 @@ class Preview3DAnimation():
|
|||||||
return {"required": {
|
return {"required": {
|
||||||
"model_file": ("STRING", {"default": "", "multiline": False}),
|
"model_file": ("STRING", {"default": "", "multiline": False}),
|
||||||
"material": (["original", "normal", "wireframe", "depth"],),
|
"material": (["original", "normal", "wireframe", "depth"],),
|
||||||
"light_intensity": ("INT", {"default": 10, "min": 1, "max": 20, "step": 1}),
|
|
||||||
"up_direction": (["original", "-x", "+x", "-y", "+y", "-z", "+z"],),
|
"up_direction": (["original", "-x", "+x", "-y", "+y", "-z", "+z"],),
|
||||||
"fov": ("INT", {"default": 75, "min": 10, "max": 150, "step": 1}),
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
OUTPUT_NODE = True
|
OUTPUT_NODE = True
|
||||||
|
|||||||
104
comfy_extras/nodes_lumina2.py
Normal file
104
comfy_extras/nodes_lumina2.py
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
from comfy.comfy_types import IO, ComfyNodeABC, InputTypeDict
|
||||||
|
import torch
|
||||||
|
|
||||||
|
|
||||||
|
class RenormCFG:
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s):
|
||||||
|
return {"required": { "model": ("MODEL",),
|
||||||
|
"cfg_trunc": ("FLOAT", {"default": 100, "min": 0.0, "max": 100.0, "step": 0.01}),
|
||||||
|
"renorm_cfg": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}),
|
||||||
|
}}
|
||||||
|
RETURN_TYPES = ("MODEL",)
|
||||||
|
FUNCTION = "patch"
|
||||||
|
|
||||||
|
CATEGORY = "advanced/model"
|
||||||
|
|
||||||
|
def patch(self, model, cfg_trunc, renorm_cfg):
|
||||||
|
def renorm_cfg_func(args):
|
||||||
|
cond_denoised = args["cond_denoised"]
|
||||||
|
uncond_denoised = args["uncond_denoised"]
|
||||||
|
cond_scale = args["cond_scale"]
|
||||||
|
timestep = args["timestep"]
|
||||||
|
x_orig = args["input"]
|
||||||
|
in_channels = model.model.diffusion_model.in_channels
|
||||||
|
|
||||||
|
if timestep[0] < cfg_trunc:
|
||||||
|
cond_eps, uncond_eps = cond_denoised[:, :in_channels], uncond_denoised[:, :in_channels]
|
||||||
|
cond_rest, _ = cond_denoised[:, in_channels:], uncond_denoised[:, in_channels:]
|
||||||
|
half_eps = uncond_eps + cond_scale * (cond_eps - uncond_eps)
|
||||||
|
half_rest = cond_rest
|
||||||
|
|
||||||
|
if float(renorm_cfg) > 0.0:
|
||||||
|
ori_pos_norm = torch.linalg.vector_norm(cond_eps
|
||||||
|
, dim=tuple(range(1, len(cond_eps.shape))), keepdim=True
|
||||||
|
)
|
||||||
|
max_new_norm = ori_pos_norm * float(renorm_cfg)
|
||||||
|
new_pos_norm = torch.linalg.vector_norm(
|
||||||
|
half_eps, dim=tuple(range(1, len(half_eps.shape))), keepdim=True
|
||||||
|
)
|
||||||
|
if new_pos_norm >= max_new_norm:
|
||||||
|
half_eps = half_eps * (max_new_norm / new_pos_norm)
|
||||||
|
else:
|
||||||
|
cond_eps, uncond_eps = cond_denoised[:, :in_channels], uncond_denoised[:, :in_channels]
|
||||||
|
cond_rest, _ = cond_denoised[:, in_channels:], uncond_denoised[:, in_channels:]
|
||||||
|
half_eps = cond_eps
|
||||||
|
half_rest = cond_rest
|
||||||
|
|
||||||
|
cfg_result = torch.cat([half_eps, half_rest], dim=1)
|
||||||
|
|
||||||
|
# cfg_result = uncond_denoised + (cond_denoised - uncond_denoised) * cond_scale
|
||||||
|
|
||||||
|
return x_orig - cfg_result
|
||||||
|
|
||||||
|
m = model.clone()
|
||||||
|
m.set_model_sampler_cfg_function(renorm_cfg_func)
|
||||||
|
return (m, )
|
||||||
|
|
||||||
|
|
||||||
|
class CLIPTextEncodeLumina2(ComfyNodeABC):
|
||||||
|
SYSTEM_PROMPT = {
|
||||||
|
"superior": "You are an assistant designed to generate superior images with the superior "\
|
||||||
|
"degree of image-text alignment based on textual prompts or user prompts.",
|
||||||
|
"alignment": "You are an assistant designed to generate high-quality images with the "\
|
||||||
|
"highest degree of image-text alignment based on textual prompts."
|
||||||
|
}
|
||||||
|
SYSTEM_PROMPT_TIP = "Lumina2 provide two types of system prompts:" \
|
||||||
|
"Superior: You are an assistant designed to generate superior images with the superior "\
|
||||||
|
"degree of image-text alignment based on textual prompts or user prompts. "\
|
||||||
|
"Alignment: You are an assistant designed to generate high-quality images with the highest "\
|
||||||
|
"degree of image-text alignment based on textual prompts."
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s) -> InputTypeDict:
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"system_prompt": (list(CLIPTextEncodeLumina2.SYSTEM_PROMPT.keys()), {"tooltip": CLIPTextEncodeLumina2.SYSTEM_PROMPT_TIP}),
|
||||||
|
"user_prompt": (IO.STRING, {"multiline": True, "dynamicPrompts": True, "tooltip": "The text to be encoded."}),
|
||||||
|
"clip": (IO.CLIP, {"tooltip": "The CLIP model used for encoding the text."})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RETURN_TYPES = (IO.CONDITIONING,)
|
||||||
|
OUTPUT_TOOLTIPS = ("A conditioning containing the embedded text used to guide the diffusion model.",)
|
||||||
|
FUNCTION = "encode"
|
||||||
|
|
||||||
|
CATEGORY = "conditioning"
|
||||||
|
DESCRIPTION = "Encodes a system prompt and a user prompt using a CLIP model into an embedding that can be used to guide the diffusion model towards generating specific images."
|
||||||
|
|
||||||
|
def encode(self, clip, user_prompt, system_prompt):
|
||||||
|
if clip is None:
|
||||||
|
raise RuntimeError("ERROR: clip input is invalid: None\n\nIf the clip is from a checkpoint loader node your checkpoint does not contain a valid clip or text encoder model.")
|
||||||
|
system_prompt = CLIPTextEncodeLumina2.SYSTEM_PROMPT[system_prompt]
|
||||||
|
prompt = f'{system_prompt} <Prompt Start> {user_prompt}'
|
||||||
|
tokens = clip.tokenize(prompt)
|
||||||
|
return (clip.encode_from_tokens_scheduled(tokens), )
|
||||||
|
|
||||||
|
|
||||||
|
NODE_CLASS_MAPPINGS = {
|
||||||
|
"CLIPTextEncodeLumina2": CLIPTextEncodeLumina2,
|
||||||
|
"RenormCFG": RenormCFG
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||||
|
"CLIPTextEncodeLumina2": "CLIP Text Encode for Lumina2",
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@ import comfy.model_sampling
|
|||||||
import comfy.latent_formats
|
import comfy.latent_formats
|
||||||
import nodes
|
import nodes
|
||||||
import torch
|
import torch
|
||||||
|
import node_helpers
|
||||||
|
|
||||||
|
|
||||||
class LCM(comfy.model_sampling.EPS):
|
class LCM(comfy.model_sampling.EPS):
|
||||||
def calculate_denoised(self, sigma, model_output, model_input):
|
def calculate_denoised(self, sigma, model_output, model_input):
|
||||||
@@ -294,6 +296,24 @@ class RescaleCFG:
|
|||||||
m.set_model_sampler_cfg_function(rescale_cfg)
|
m.set_model_sampler_cfg_function(rescale_cfg)
|
||||||
return (m, )
|
return (m, )
|
||||||
|
|
||||||
|
class ModelComputeDtype:
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s):
|
||||||
|
return {"required": { "model": ("MODEL",),
|
||||||
|
"dtype": (["default", "fp32", "fp16", "bf16"],),
|
||||||
|
}}
|
||||||
|
|
||||||
|
RETURN_TYPES = ("MODEL",)
|
||||||
|
FUNCTION = "patch"
|
||||||
|
|
||||||
|
CATEGORY = "advanced/debug/model"
|
||||||
|
|
||||||
|
def patch(self, model, dtype):
|
||||||
|
m = model.clone()
|
||||||
|
m.set_model_compute_dtype(node_helpers.string_to_torch_dtype(dtype))
|
||||||
|
return (m, )
|
||||||
|
|
||||||
|
|
||||||
NODE_CLASS_MAPPINGS = {
|
NODE_CLASS_MAPPINGS = {
|
||||||
"ModelSamplingDiscrete": ModelSamplingDiscrete,
|
"ModelSamplingDiscrete": ModelSamplingDiscrete,
|
||||||
"ModelSamplingContinuousEDM": ModelSamplingContinuousEDM,
|
"ModelSamplingContinuousEDM": ModelSamplingContinuousEDM,
|
||||||
@@ -303,4 +323,5 @@ NODE_CLASS_MAPPINGS = {
|
|||||||
"ModelSamplingAuraFlow": ModelSamplingAuraFlow,
|
"ModelSamplingAuraFlow": ModelSamplingAuraFlow,
|
||||||
"ModelSamplingFlux": ModelSamplingFlux,
|
"ModelSamplingFlux": ModelSamplingFlux,
|
||||||
"RescaleCFG": RescaleCFG,
|
"RescaleCFG": RescaleCFG,
|
||||||
|
"ModelComputeDtype": ModelComputeDtype,
|
||||||
}
|
}
|
||||||
|
|||||||
75
comfy_extras/nodes_video.py
Normal file
75
comfy_extras/nodes_video.py
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import os
|
||||||
|
import av
|
||||||
|
import torch
|
||||||
|
import folder_paths
|
||||||
|
import json
|
||||||
|
from fractions import Fraction
|
||||||
|
|
||||||
|
|
||||||
|
class SaveWEBM:
|
||||||
|
def __init__(self):
|
||||||
|
self.output_dir = folder_paths.get_output_directory()
|
||||||
|
self.type = "output"
|
||||||
|
self.prefix_append = ""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s):
|
||||||
|
return {"required":
|
||||||
|
{"images": ("IMAGE", ),
|
||||||
|
"filename_prefix": ("STRING", {"default": "ComfyUI"}),
|
||||||
|
"codec": (["vp9", "av1"],),
|
||||||
|
"fps": ("FLOAT", {"default": 24.0, "min": 0.01, "max": 1000.0, "step": 0.01}),
|
||||||
|
"crf": ("FLOAT", {"default": 32.0, "min": 0, "max": 63.0, "step": 1, "tooltip": "Higher crf means lower quality with a smaller file size, lower crf means higher quality higher filesize."}),
|
||||||
|
},
|
||||||
|
"hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"},
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_TYPES = ()
|
||||||
|
FUNCTION = "save_images"
|
||||||
|
|
||||||
|
OUTPUT_NODE = True
|
||||||
|
|
||||||
|
CATEGORY = "image/video"
|
||||||
|
|
||||||
|
EXPERIMENTAL = True
|
||||||
|
|
||||||
|
def save_images(self, images, codec, fps, filename_prefix, crf, prompt=None, extra_pnginfo=None):
|
||||||
|
filename_prefix += self.prefix_append
|
||||||
|
full_output_folder, filename, counter, subfolder, filename_prefix = folder_paths.get_save_image_path(filename_prefix, self.output_dir, images[0].shape[1], images[0].shape[0])
|
||||||
|
|
||||||
|
file = f"{filename}_{counter:05}_.webm"
|
||||||
|
container = av.open(os.path.join(full_output_folder, file), mode="w")
|
||||||
|
|
||||||
|
if prompt is not None:
|
||||||
|
container.metadata["prompt"] = json.dumps(prompt)
|
||||||
|
|
||||||
|
if extra_pnginfo is not None:
|
||||||
|
for x in extra_pnginfo:
|
||||||
|
container.metadata[x] = json.dumps(extra_pnginfo[x])
|
||||||
|
|
||||||
|
codec_map = {"vp9": "libvpx-vp9", "av1": "libaom-av1"}
|
||||||
|
stream = container.add_stream(codec_map[codec], rate=Fraction(round(fps * 1000), 1000))
|
||||||
|
stream.width = images.shape[-2]
|
||||||
|
stream.height = images.shape[-3]
|
||||||
|
stream.pix_fmt = "yuv420p"
|
||||||
|
stream.bit_rate = 0
|
||||||
|
stream.options = {'crf': str(crf)}
|
||||||
|
|
||||||
|
for frame in images:
|
||||||
|
frame = av.VideoFrame.from_ndarray(torch.clamp(frame[..., :3] * 255, min=0, max=255).to(device=torch.device("cpu"), dtype=torch.uint8).numpy(), format="rgb24")
|
||||||
|
for packet in stream.encode(frame):
|
||||||
|
container.mux(packet)
|
||||||
|
container.close()
|
||||||
|
|
||||||
|
results = [{
|
||||||
|
"filename": file,
|
||||||
|
"subfolder": subfolder,
|
||||||
|
"type": self.type
|
||||||
|
}]
|
||||||
|
|
||||||
|
return {"ui": {"images": results, "animated": (True,)}} # TODO: frontend side
|
||||||
|
|
||||||
|
|
||||||
|
NODE_CLASS_MAPPINGS = {
|
||||||
|
"SaveWEBM": SaveWEBM,
|
||||||
|
}
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
# This file is automatically generated by the build process when version is
|
# This file is automatically generated by the build process when version is
|
||||||
# updated in pyproject.toml.
|
# updated in pyproject.toml.
|
||||||
__version__ = "0.3.14"
|
__version__ = "0.3.15"
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
|
import torch
|
||||||
|
|
||||||
from comfy.cli_args import args
|
from comfy.cli_args import args
|
||||||
|
|
||||||
@@ -35,3 +36,11 @@ def hasher():
|
|||||||
"sha512": hashlib.sha512
|
"sha512": hashlib.sha512
|
||||||
}
|
}
|
||||||
return hashfuncs[args.default_hashing_function]
|
return hashfuncs[args.default_hashing_function]
|
||||||
|
|
||||||
|
def string_to_torch_dtype(string):
|
||||||
|
if string == "fp32":
|
||||||
|
return torch.float32
|
||||||
|
if string == "fp16":
|
||||||
|
return torch.float16
|
||||||
|
if string == "bf16":
|
||||||
|
return torch.bfloat16
|
||||||
|
|||||||
41
nodes.py
41
nodes.py
@@ -924,7 +924,7 @@ class CLIPLoader:
|
|||||||
|
|
||||||
CATEGORY = "advanced/loaders"
|
CATEGORY = "advanced/loaders"
|
||||||
|
|
||||||
DESCRIPTION = "[Recipes]\n\nstable_diffusion: clip-l\nstable_cascade: clip-g\nsd3: t5 / clip-g / clip-l\nstable_audio: t5\nmochi: t5\ncosmos: old t5 xxl"
|
DESCRIPTION = "[Recipes]\n\nstable_diffusion: clip-l\nstable_cascade: clip-g\nsd3: t5 / clip-g / clip-l\nstable_audio: t5\nmochi: t5\ncosmos: old t5 xxl\nlumina2: gemma 2 2B"
|
||||||
|
|
||||||
def load_clip(self, clip_name, type="stable_diffusion", device="default"):
|
def load_clip(self, clip_name, type="stable_diffusion", device="default"):
|
||||||
if type == "stable_cascade":
|
if type == "stable_cascade":
|
||||||
@@ -1064,10 +1064,11 @@ class StyleModelApply:
|
|||||||
for t in conditioning:
|
for t in conditioning:
|
||||||
(txt, keys) = t
|
(txt, keys) = t
|
||||||
keys = keys.copy()
|
keys = keys.copy()
|
||||||
if strength_type == "attn_bias" and strength != 1.0:
|
# even if the strength is 1.0 (i.e, no change), if there's already a mask, we have to add to it
|
||||||
|
if "attention_mask" in keys or (strength_type == "attn_bias" and strength != 1.0):
|
||||||
# math.log raises an error if the argument is zero
|
# math.log raises an error if the argument is zero
|
||||||
# torch.log returns -inf, which is what we want
|
# torch.log returns -inf, which is what we want
|
||||||
attn_bias = torch.log(torch.Tensor([strength]))
|
attn_bias = torch.log(torch.Tensor([strength if strength_type == "attn_bias" else 1.0]))
|
||||||
# get the size of the mask image
|
# get the size of the mask image
|
||||||
mask_ref_size = keys.get("attention_mask_img_shape", (1, 1))
|
mask_ref_size = keys.get("attention_mask_img_shape", (1, 1))
|
||||||
n_ref = mask_ref_size[0] * mask_ref_size[1]
|
n_ref = mask_ref_size[0] * mask_ref_size[1]
|
||||||
@@ -1762,6 +1763,36 @@ class LoadImageMask:
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class LoadImageOutput(LoadImage):
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s):
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"image": ("COMBO", {
|
||||||
|
"image_upload": True,
|
||||||
|
"image_folder": "output",
|
||||||
|
"remote": {
|
||||||
|
"route": "/internal/files/output",
|
||||||
|
"refresh_button": True,
|
||||||
|
"control_after_refresh": "first",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DESCRIPTION = "Load an image from the output folder. When the refresh button is clicked, the node will update the image list and automatically select the first image, allowing for easy iteration."
|
||||||
|
EXPERIMENTAL = True
|
||||||
|
FUNCTION = "load_image_output"
|
||||||
|
|
||||||
|
def load_image_output(self, image):
|
||||||
|
return self.load_image(f"{image} [output]")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def VALIDATE_INPUTS(s, image):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class ImageScale:
|
class ImageScale:
|
||||||
upscale_methods = ["nearest-exact", "bilinear", "area", "bicubic", "lanczos"]
|
upscale_methods = ["nearest-exact", "bilinear", "area", "bicubic", "lanczos"]
|
||||||
crop_methods = ["disabled", "center"]
|
crop_methods = ["disabled", "center"]
|
||||||
@@ -1948,6 +1979,7 @@ NODE_CLASS_MAPPINGS = {
|
|||||||
"PreviewImage": PreviewImage,
|
"PreviewImage": PreviewImage,
|
||||||
"LoadImage": LoadImage,
|
"LoadImage": LoadImage,
|
||||||
"LoadImageMask": LoadImageMask,
|
"LoadImageMask": LoadImageMask,
|
||||||
|
"LoadImageOutput": LoadImageOutput,
|
||||||
"ImageScale": ImageScale,
|
"ImageScale": ImageScale,
|
||||||
"ImageScaleBy": ImageScaleBy,
|
"ImageScaleBy": ImageScaleBy,
|
||||||
"ImageInvert": ImageInvert,
|
"ImageInvert": ImageInvert,
|
||||||
@@ -2048,6 +2080,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
|||||||
"PreviewImage": "Preview Image",
|
"PreviewImage": "Preview Image",
|
||||||
"LoadImage": "Load Image",
|
"LoadImage": "Load Image",
|
||||||
"LoadImageMask": "Load Image (as Mask)",
|
"LoadImageMask": "Load Image (as Mask)",
|
||||||
|
"LoadImageOutput": "Load Image (from Outputs)",
|
||||||
"ImageScale": "Upscale Image",
|
"ImageScale": "Upscale Image",
|
||||||
"ImageScaleBy": "Upscale Image By",
|
"ImageScaleBy": "Upscale Image By",
|
||||||
"ImageUpscaleWithModel": "Upscale Image (using Model)",
|
"ImageUpscaleWithModel": "Upscale Image (using Model)",
|
||||||
@@ -2232,6 +2265,8 @@ def init_builtin_extra_nodes():
|
|||||||
"nodes_hooks.py",
|
"nodes_hooks.py",
|
||||||
"nodes_load_3d.py",
|
"nodes_load_3d.py",
|
||||||
"nodes_cosmos.py",
|
"nodes_cosmos.py",
|
||||||
|
"nodes_video.py",
|
||||||
|
"nodes_lumina2.py",
|
||||||
]
|
]
|
||||||
|
|
||||||
import_failed = []
|
import_failed = []
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "ComfyUI"
|
name = "ComfyUI"
|
||||||
version = "0.3.14"
|
version = "0.3.15"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = { file = "LICENSE" }
|
license = { file = "LICENSE" }
|
||||||
requires-python = ">=3.9"
|
requires-python = ">=3.9"
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ transformers>=4.28.1
|
|||||||
tokenizers>=0.13.3
|
tokenizers>=0.13.3
|
||||||
sentencepiece
|
sentencepiece
|
||||||
safetensors>=0.4.2
|
safetensors>=0.4.2
|
||||||
aiohttp
|
aiohttp>=3.11.8
|
||||||
|
yarl>=1.18.0
|
||||||
pyyaml
|
pyyaml
|
||||||
Pillow
|
Pillow
|
||||||
scipy
|
scipy
|
||||||
@@ -19,3 +20,4 @@ psutil
|
|||||||
kornia>=0.7.1
|
kornia>=0.7.1
|
||||||
spandrel
|
spandrel
|
||||||
soundfile
|
soundfile
|
||||||
|
av
|
||||||
|
|||||||
10
server.py
10
server.py
@@ -57,8 +57,6 @@ async def cache_control(request: web.Request, handler):
|
|||||||
async def compress_body(request: web.Request, handler):
|
async def compress_body(request: web.Request, handler):
|
||||||
accept_encoding = request.headers.get("Accept-Encoding", "")
|
accept_encoding = request.headers.get("Accept-Encoding", "")
|
||||||
response: web.Response = await handler(request)
|
response: web.Response = await handler(request)
|
||||||
if args.disable_compres_response_body:
|
|
||||||
return response
|
|
||||||
if not isinstance(response, web.Response):
|
if not isinstance(response, web.Response):
|
||||||
return response
|
return response
|
||||||
if response.content_type not in ["application/json", "text/plain"]:
|
if response.content_type not in ["application/json", "text/plain"]:
|
||||||
@@ -152,7 +150,8 @@ class PromptServer():
|
|||||||
PromptServer.instance = self
|
PromptServer.instance = self
|
||||||
|
|
||||||
mimetypes.init()
|
mimetypes.init()
|
||||||
mimetypes.types_map['.js'] = 'application/javascript; charset=utf-8'
|
mimetypes.add_type('application/javascript; charset=utf-8', '.js')
|
||||||
|
mimetypes.add_type('image/webp', '.webp')
|
||||||
|
|
||||||
self.user_manager = UserManager()
|
self.user_manager = UserManager()
|
||||||
self.model_file_manager = ModelFileManager()
|
self.model_file_manager = ModelFileManager()
|
||||||
@@ -165,7 +164,10 @@ class PromptServer():
|
|||||||
self.client_session:Optional[aiohttp.ClientSession] = None
|
self.client_session:Optional[aiohttp.ClientSession] = None
|
||||||
self.number = 0
|
self.number = 0
|
||||||
|
|
||||||
middlewares = [cache_control, compress_body]
|
middlewares = [cache_control]
|
||||||
|
if args.enable_compress_response_body:
|
||||||
|
middlewares.append(compress_body)
|
||||||
|
|
||||||
if args.enable_cors_header:
|
if args.enable_cors_header:
|
||||||
middlewares.append(create_cors_middleware(args.enable_cors_header))
|
middlewares.append(create_cors_middleware(args.enable_cors_header))
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -1,115 +0,0 @@
|
|||||||
import pytest
|
|
||||||
from aiohttp import web
|
|
||||||
from unittest.mock import MagicMock, patch
|
|
||||||
from api_server.routes.internal.internal_routes import InternalRoutes
|
|
||||||
from api_server.services.file_service import FileService
|
|
||||||
from folder_paths import models_dir, user_directory, output_directory
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def internal_routes():
|
|
||||||
return InternalRoutes(None)
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def aiohttp_client_factory(aiohttp_client, internal_routes):
|
|
||||||
async def _get_client():
|
|
||||||
app = internal_routes.get_app()
|
|
||||||
return await aiohttp_client(app)
|
|
||||||
return _get_client
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
|
||||||
async def test_list_files_valid_directory(aiohttp_client_factory, internal_routes):
|
|
||||||
mock_file_list = [
|
|
||||||
{"name": "file1.txt", "path": "file1.txt", "type": "file", "size": 100},
|
|
||||||
{"name": "dir1", "path": "dir1", "type": "directory"}
|
|
||||||
]
|
|
||||||
internal_routes.file_service.list_files = MagicMock(return_value=mock_file_list)
|
|
||||||
client = await aiohttp_client_factory()
|
|
||||||
resp = await client.get('/files?directory=models')
|
|
||||||
assert resp.status == 200
|
|
||||||
data = await resp.json()
|
|
||||||
assert 'files' in data
|
|
||||||
assert len(data['files']) == 2
|
|
||||||
assert data['files'] == mock_file_list
|
|
||||||
|
|
||||||
# Check other valid directories
|
|
||||||
resp = await client.get('/files?directory=user')
|
|
||||||
assert resp.status == 200
|
|
||||||
resp = await client.get('/files?directory=output')
|
|
||||||
assert resp.status == 200
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
|
||||||
async def test_list_files_invalid_directory(aiohttp_client_factory, internal_routes):
|
|
||||||
internal_routes.file_service.list_files = MagicMock(side_effect=ValueError("Invalid directory key"))
|
|
||||||
client = await aiohttp_client_factory()
|
|
||||||
resp = await client.get('/files?directory=invalid')
|
|
||||||
assert resp.status == 400
|
|
||||||
data = await resp.json()
|
|
||||||
assert 'error' in data
|
|
||||||
assert data['error'] == "Invalid directory key"
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
|
||||||
async def test_list_files_exception(aiohttp_client_factory, internal_routes):
|
|
||||||
internal_routes.file_service.list_files = MagicMock(side_effect=Exception("Unexpected error"))
|
|
||||||
client = await aiohttp_client_factory()
|
|
||||||
resp = await client.get('/files?directory=models')
|
|
||||||
assert resp.status == 500
|
|
||||||
data = await resp.json()
|
|
||||||
assert 'error' in data
|
|
||||||
assert data['error'] == "Unexpected error"
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
|
||||||
async def test_list_files_no_directory_param(aiohttp_client_factory, internal_routes):
|
|
||||||
mock_file_list = []
|
|
||||||
internal_routes.file_service.list_files = MagicMock(return_value=mock_file_list)
|
|
||||||
client = await aiohttp_client_factory()
|
|
||||||
resp = await client.get('/files')
|
|
||||||
assert resp.status == 200
|
|
||||||
data = await resp.json()
|
|
||||||
assert 'files' in data
|
|
||||||
assert len(data['files']) == 0
|
|
||||||
|
|
||||||
def test_setup_routes(internal_routes):
|
|
||||||
internal_routes.setup_routes()
|
|
||||||
routes = internal_routes.routes
|
|
||||||
assert any(route.method == 'GET' and str(route.path) == '/files' for route in routes)
|
|
||||||
|
|
||||||
def test_get_app(internal_routes):
|
|
||||||
app = internal_routes.get_app()
|
|
||||||
assert isinstance(app, web.Application)
|
|
||||||
assert internal_routes._app is not None
|
|
||||||
|
|
||||||
def test_get_app_reuse(internal_routes):
|
|
||||||
app1 = internal_routes.get_app()
|
|
||||||
app2 = internal_routes.get_app()
|
|
||||||
assert app1 is app2
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
|
||||||
async def test_routes_added_to_app(aiohttp_client_factory, internal_routes):
|
|
||||||
client = await aiohttp_client_factory()
|
|
||||||
try:
|
|
||||||
resp = await client.get('/files')
|
|
||||||
print(f"Response received: status {resp.status}") # noqa: T201
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Exception occurred during GET request: {e}") # noqa: T201
|
|
||||||
raise
|
|
||||||
|
|
||||||
assert resp.status != 404, "Route /files does not exist"
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
|
||||||
async def test_file_service_initialization():
|
|
||||||
with patch('api_server.routes.internal.internal_routes.FileService') as MockFileService:
|
|
||||||
# Create a mock instance
|
|
||||||
mock_file_service_instance = MagicMock(spec=FileService)
|
|
||||||
MockFileService.return_value = mock_file_service_instance
|
|
||||||
internal_routes = InternalRoutes(None)
|
|
||||||
|
|
||||||
# Check if FileService was initialized with the correct parameters
|
|
||||||
MockFileService.assert_called_once_with({
|
|
||||||
"models": models_dir,
|
|
||||||
"user": user_directory,
|
|
||||||
"output": output_directory
|
|
||||||
})
|
|
||||||
|
|
||||||
# Verify that the file_service attribute of InternalRoutes is set
|
|
||||||
assert internal_routes.file_service == mock_file_service_instance
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
import pytest
|
|
||||||
from unittest.mock import MagicMock
|
|
||||||
from api_server.services.file_service import FileService
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def mock_file_system_ops():
|
|
||||||
return MagicMock()
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def file_service(mock_file_system_ops):
|
|
||||||
allowed_directories = {
|
|
||||||
"models": "/path/to/models",
|
|
||||||
"user": "/path/to/user",
|
|
||||||
"output": "/path/to/output"
|
|
||||||
}
|
|
||||||
return FileService(allowed_directories, file_system_ops=mock_file_system_ops)
|
|
||||||
|
|
||||||
def test_list_files_valid_directory(file_service, mock_file_system_ops):
|
|
||||||
mock_file_system_ops.walk_directory.return_value = [
|
|
||||||
{"name": "file1.txt", "path": "file1.txt", "type": "file", "size": 100},
|
|
||||||
{"name": "dir1", "path": "dir1", "type": "directory"}
|
|
||||||
]
|
|
||||||
|
|
||||||
result = file_service.list_files("models")
|
|
||||||
|
|
||||||
assert len(result) == 2
|
|
||||||
assert result[0]["name"] == "file1.txt"
|
|
||||||
assert result[1]["name"] == "dir1"
|
|
||||||
mock_file_system_ops.walk_directory.assert_called_once_with("/path/to/models")
|
|
||||||
|
|
||||||
def test_list_files_invalid_directory(file_service):
|
|
||||||
# Does not support walking directories outside of the allowed directories
|
|
||||||
with pytest.raises(ValueError, match="Invalid directory key"):
|
|
||||||
file_service.list_files("invalid_key")
|
|
||||||
|
|
||||||
def test_list_files_empty_directory(file_service, mock_file_system_ops):
|
|
||||||
mock_file_system_ops.walk_directory.return_value = []
|
|
||||||
|
|
||||||
result = file_service.list_files("models")
|
|
||||||
|
|
||||||
assert len(result) == 0
|
|
||||||
mock_file_system_ops.walk_directory.assert_called_once_with("/path/to/models")
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("directory_key", ["models", "user", "output"])
|
|
||||||
def test_list_files_all_allowed_directories(file_service, mock_file_system_ops, directory_key):
|
|
||||||
mock_file_system_ops.walk_directory.return_value = [
|
|
||||||
{"name": f"file_{directory_key}.txt", "path": f"file_{directory_key}.txt", "type": "file", "size": 100}
|
|
||||||
]
|
|
||||||
|
|
||||||
result = file_service.list_files(directory_key)
|
|
||||||
|
|
||||||
assert len(result) == 1
|
|
||||||
assert result[0]["name"] == f"file_{directory_key}.txt"
|
|
||||||
mock_file_system_ops.walk_directory.assert_called_once_with(f"/path/to/{directory_key}")
|
|
||||||
@@ -114,7 +114,7 @@ def test_load_extra_model_paths_expands_userpath(
|
|||||||
mock_yaml_safe_load.assert_called_once()
|
mock_yaml_safe_load.assert_called_once()
|
||||||
|
|
||||||
# Check if open was called with the correct file path
|
# Check if open was called with the correct file path
|
||||||
mock_file.assert_called_once_with(dummy_yaml_file_name, 'r')
|
mock_file.assert_called_once_with(dummy_yaml_file_name, 'r', encoding='utf-8')
|
||||||
|
|
||||||
|
|
||||||
@patch('builtins.open', new_callable=mock_open)
|
@patch('builtins.open', new_callable=mock_open)
|
||||||
@@ -145,7 +145,7 @@ def test_load_extra_model_paths_expands_appdata(
|
|||||||
else:
|
else:
|
||||||
expected_base_path = '/Users/TestUser/AppData/Roaming/ComfyUI'
|
expected_base_path = '/Users/TestUser/AppData/Roaming/ComfyUI'
|
||||||
expected_calls = [
|
expected_calls = [
|
||||||
('checkpoints', os.path.join(expected_base_path, 'models/checkpoints'), False),
|
('checkpoints', os.path.normpath(os.path.join(expected_base_path, 'models/checkpoints')), False),
|
||||||
]
|
]
|
||||||
|
|
||||||
assert mock_add_model_folder_path.call_count == len(expected_calls)
|
assert mock_add_model_folder_path.call_count == len(expected_calls)
|
||||||
@@ -197,8 +197,8 @@ def test_load_extra_path_config_relative_base_path(
|
|||||||
|
|
||||||
load_extra_path_config(dummy_yaml_name)
|
load_extra_path_config(dummy_yaml_name)
|
||||||
|
|
||||||
expected_checkpoints = os.path.abspath(os.path.join(str(tmp_path), sub_folder, "checkpoints"))
|
expected_checkpoints = os.path.abspath(os.path.join(str(tmp_path), "my_rel_base", "checkpoints"))
|
||||||
expected_some_value = os.path.abspath(os.path.join(str(tmp_path), sub_folder, "some_value"))
|
expected_some_value = os.path.abspath(os.path.join(str(tmp_path), "my_rel_base", "some_value"))
|
||||||
|
|
||||||
actual_paths = folder_paths.folder_names_and_paths["checkpoints"][0]
|
actual_paths = folder_paths.folder_names_and_paths["checkpoints"][0]
|
||||||
assert len(actual_paths) == 1, "Should have one path added for 'checkpoints'."
|
assert len(actual_paths) == 1, "Should have one path added for 'checkpoints'."
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import folder_paths
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
def load_extra_path_config(yaml_path):
|
def load_extra_path_config(yaml_path):
|
||||||
with open(yaml_path, 'r') as stream:
|
with open(yaml_path, 'r', encoding='utf-8') as stream:
|
||||||
config = yaml.safe_load(stream)
|
config = yaml.safe_load(stream)
|
||||||
yaml_dir = os.path.dirname(os.path.abspath(yaml_path))
|
yaml_dir = os.path.dirname(os.path.abspath(yaml_path))
|
||||||
for c in config:
|
for c in config:
|
||||||
@@ -29,5 +29,6 @@ def load_extra_path_config(yaml_path):
|
|||||||
full_path = os.path.join(base_path, full_path)
|
full_path = os.path.join(base_path, full_path)
|
||||||
elif not os.path.isabs(full_path):
|
elif not os.path.isabs(full_path):
|
||||||
full_path = os.path.abspath(os.path.join(yaml_dir, y))
|
full_path = os.path.abspath(os.path.join(yaml_dir, y))
|
||||||
logging.info("Adding extra search path {} {}".format(x, full_path))
|
normalized_path = os.path.normpath(full_path)
|
||||||
folder_paths.add_model_folder_path(x, full_path, is_default)
|
logging.info("Adding extra search path {} {}".format(x, normalized_path))
|
||||||
|
folder_paths.add_model_folder_path(x, normalized_path, is_default)
|
||||||
|
|||||||
6
web/assets/BaseViewTemplate-v6omkdXg.js → web/assets/BaseViewTemplate-BTbuZf5t.js
generated
vendored
6
web/assets/BaseViewTemplate-v6omkdXg.js → web/assets/BaseViewTemplate-BTbuZf5t.js
generated
vendored
@@ -1,4 +1,4 @@
|
|||||||
import { d as defineComponent, U as ref, p as onMounted, b4 as isElectron, W as nextTick, b5 as electronAPI, o as openBlock, f as createElementBlock, i as withDirectives, v as vShow, j as unref, b6 as isNativeWindow, m as createBaseVNode, A as renderSlot, ai as normalizeClass } from "./index-4Hb32CNk.js";
|
import { d as defineComponent, T as ref, p as onMounted, b8 as isElectron, V as nextTick, b9 as electronAPI, o as openBlock, f as createElementBlock, i as withDirectives, v as vShow, j as unref, ba as isNativeWindow, m as createBaseVNode, A as renderSlot, aj as normalizeClass } from "./index-Bv0b06LE.js";
|
||||||
const _hoisted_1 = { class: "flex-grow w-full flex items-center justify-center overflow-auto" };
|
const _hoisted_1 = { class: "flex-grow w-full flex items-center justify-center overflow-auto" };
|
||||||
const _sfc_main = /* @__PURE__ */ defineComponent({
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
||||||
__name: "BaseViewTemplate",
|
__name: "BaseViewTemplate",
|
||||||
@@ -27,7 +27,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|||||||
});
|
});
|
||||||
return (_ctx, _cache) => {
|
return (_ctx, _cache) => {
|
||||||
return openBlock(), createElementBlock("div", {
|
return openBlock(), createElementBlock("div", {
|
||||||
class: normalizeClass(["font-sans w-screen h-screen flex flex-col pointer-events-auto", [
|
class: normalizeClass(["font-sans w-screen h-screen flex flex-col", [
|
||||||
props.dark ? "text-neutral-300 bg-neutral-900 dark-theme" : "text-neutral-900 bg-neutral-300"
|
props.dark ? "text-neutral-300 bg-neutral-900 dark-theme" : "text-neutral-900 bg-neutral-300"
|
||||||
]])
|
]])
|
||||||
}, [
|
}, [
|
||||||
@@ -48,4 +48,4 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|||||||
export {
|
export {
|
||||||
_sfc_main as _
|
_sfc_main as _
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=BaseViewTemplate-v6omkdXg.js.map
|
//# sourceMappingURL=BaseViewTemplate-BTbuZf5t.js.map
|
||||||
19
web/assets/DesktopStartView-D9r53Bue.js
generated
vendored
Normal file
19
web/assets/DesktopStartView-D9r53Bue.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { d as defineComponent, o as openBlock, y as createBlock, z as withCtx, k as createVNode, j as unref, bE as script } from "./index-Bv0b06LE.js";
|
||||||
|
import { _ as _sfc_main$1 } from "./BaseViewTemplate-BTbuZf5t.js";
|
||||||
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
||||||
|
__name: "DesktopStartView",
|
||||||
|
setup(__props) {
|
||||||
|
return (_ctx, _cache) => {
|
||||||
|
return openBlock(), createBlock(_sfc_main$1, { dark: "" }, {
|
||||||
|
default: withCtx(() => [
|
||||||
|
createVNode(unref(script), { class: "m-8 w-48 h-48" })
|
||||||
|
]),
|
||||||
|
_: 1
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
export {
|
||||||
|
_sfc_main as default
|
||||||
|
};
|
||||||
|
//# sourceMappingURL=DesktopStartView-D9r53Bue.js.map
|
||||||
22
web/assets/DesktopStartView-coDnSXEF.js
generated
vendored
22
web/assets/DesktopStartView-coDnSXEF.js
generated
vendored
@@ -1,22 +0,0 @@
|
|||||||
import { d as defineComponent, o as openBlock, y as createBlock, z as withCtx, m as createBaseVNode, k as createVNode, j as unref, bz as script } from "./index-4Hb32CNk.js";
|
|
||||||
import { _ as _sfc_main$1 } from "./BaseViewTemplate-v6omkdXg.js";
|
|
||||||
const _hoisted_1 = { class: "max-w-screen-sm w-screen p-8" };
|
|
||||||
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
||||||
__name: "DesktopStartView",
|
|
||||||
setup(__props) {
|
|
||||||
return (_ctx, _cache) => {
|
|
||||||
return openBlock(), createBlock(_sfc_main$1, { dark: "" }, {
|
|
||||||
default: withCtx(() => [
|
|
||||||
createBaseVNode("div", _hoisted_1, [
|
|
||||||
createVNode(unref(script), { mode: "indeterminate" })
|
|
||||||
])
|
|
||||||
]),
|
|
||||||
_: 1
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
export {
|
|
||||||
_sfc_main as default
|
|
||||||
};
|
|
||||||
//# sourceMappingURL=DesktopStartView-coDnSXEF.js.map
|
|
||||||
58
web/assets/DesktopUpdateView-C-R0415K.js
generated
vendored
Normal file
58
web/assets/DesktopUpdateView-C-R0415K.js
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
var __defProp = Object.defineProperty;
|
||||||
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
||||||
|
import { d as defineComponent, T as ref, d8 as onUnmounted, o as openBlock, y as createBlock, z as withCtx, m as createBaseVNode, E as toDisplayString, j as unref, bg as t, k as createVNode, bE as script, l as script$1, b9 as electronAPI, _ as _export_sfc } from "./index-Bv0b06LE.js";
|
||||||
|
import { s as script$2 } from "./index-A_bXPJCN.js";
|
||||||
|
import { _ as _sfc_main$1 } from "./TerminalOutputDrawer-CKr7Br7O.js";
|
||||||
|
import { _ as _sfc_main$2 } from "./BaseViewTemplate-BTbuZf5t.js";
|
||||||
|
const _hoisted_1 = { class: "h-screen w-screen grid items-center justify-around overflow-y-auto" };
|
||||||
|
const _hoisted_2 = { class: "relative m-8 text-center" };
|
||||||
|
const _hoisted_3 = { class: "download-bg pi-download text-4xl font-bold" };
|
||||||
|
const _hoisted_4 = { class: "m-8" };
|
||||||
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
||||||
|
__name: "DesktopUpdateView",
|
||||||
|
setup(__props) {
|
||||||
|
const electron = electronAPI();
|
||||||
|
const terminalVisible = ref(false);
|
||||||
|
const toggleConsoleDrawer = /* @__PURE__ */ __name(() => {
|
||||||
|
terminalVisible.value = !terminalVisible.value;
|
||||||
|
}, "toggleConsoleDrawer");
|
||||||
|
onUnmounted(() => electron.Validation.dispose());
|
||||||
|
return (_ctx, _cache) => {
|
||||||
|
return openBlock(), createBlock(_sfc_main$2, { dark: "" }, {
|
||||||
|
default: withCtx(() => [
|
||||||
|
createBaseVNode("div", _hoisted_1, [
|
||||||
|
createBaseVNode("div", _hoisted_2, [
|
||||||
|
createBaseVNode("h1", _hoisted_3, toDisplayString(unref(t)("desktopUpdate.title")), 1),
|
||||||
|
createBaseVNode("div", _hoisted_4, [
|
||||||
|
createBaseVNode("span", null, toDisplayString(unref(t)("desktopUpdate.description")), 1)
|
||||||
|
]),
|
||||||
|
createVNode(unref(script), { class: "m-8 w-48 h-48" }),
|
||||||
|
createVNode(unref(script$1), {
|
||||||
|
style: { "transform": "translateX(-50%)" },
|
||||||
|
class: "fixed bottom-0 left-1/2 my-8",
|
||||||
|
label: unref(t)("maintenance.consoleLogs"),
|
||||||
|
icon: "pi pi-desktop",
|
||||||
|
"icon-pos": "left",
|
||||||
|
severity: "secondary",
|
||||||
|
onClick: toggleConsoleDrawer
|
||||||
|
}, null, 8, ["label"]),
|
||||||
|
createVNode(_sfc_main$1, {
|
||||||
|
modelValue: terminalVisible.value,
|
||||||
|
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => terminalVisible.value = $event),
|
||||||
|
header: unref(t)("g.terminal"),
|
||||||
|
"default-message": unref(t)("desktopUpdate.terminalDefaultMessage")
|
||||||
|
}, null, 8, ["modelValue", "header", "default-message"])
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
createVNode(unref(script$2))
|
||||||
|
]),
|
||||||
|
_: 1
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const DesktopUpdateView = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-8d77828d"]]);
|
||||||
|
export {
|
||||||
|
DesktopUpdateView as default
|
||||||
|
};
|
||||||
|
//# sourceMappingURL=DesktopUpdateView-C-R0415K.js.map
|
||||||
20
web/assets/DesktopUpdateView-CxchaIvw.css
generated
vendored
Normal file
20
web/assets/DesktopUpdateView-CxchaIvw.css
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
.download-bg[data-v-8d77828d]::before {
|
||||||
|
position: absolute;
|
||||||
|
margin: 0px;
|
||||||
|
color: var(--p-text-muted-color);
|
||||||
|
font-family: 'primeicons';
|
||||||
|
top: -2rem;
|
||||||
|
right: 2rem;
|
||||||
|
speak: none;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: normal;
|
||||||
|
font-variant: normal;
|
||||||
|
text-transform: none;
|
||||||
|
line-height: 1;
|
||||||
|
display: inline-block;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
opacity: 0.02;
|
||||||
|
font-size: min(14rem, 90vw);
|
||||||
|
z-index: 0
|
||||||
|
}
|
||||||
6
web/assets/DownloadGitView-3STu4yxt.js → web/assets/DownloadGitView-PWqK5ke4.js
generated
vendored
6
web/assets/DownloadGitView-3STu4yxt.js → web/assets/DownloadGitView-PWqK5ke4.js
generated
vendored
@@ -1,7 +1,7 @@
|
|||||||
var __defProp = Object.defineProperty;
|
var __defProp = Object.defineProperty;
|
||||||
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
||||||
import { d as defineComponent, o as openBlock, y as createBlock, z as withCtx, m as createBaseVNode, E as toDisplayString, k as createVNode, j as unref, l as script, be as useRouter } from "./index-4Hb32CNk.js";
|
import { d as defineComponent, o as openBlock, y as createBlock, z as withCtx, m as createBaseVNode, E as toDisplayString, k as createVNode, j as unref, l as script, bi as useRouter } from "./index-Bv0b06LE.js";
|
||||||
import { _ as _sfc_main$1 } from "./BaseViewTemplate-v6omkdXg.js";
|
import { _ as _sfc_main$1 } from "./BaseViewTemplate-BTbuZf5t.js";
|
||||||
const _hoisted_1 = { class: "max-w-screen-sm flex flex-col gap-8 p-8 bg-[url('/assets/images/Git-Logo-White.svg')] bg-no-repeat bg-right-top bg-origin-padding" };
|
const _hoisted_1 = { class: "max-w-screen-sm flex flex-col gap-8 p-8 bg-[url('/assets/images/Git-Logo-White.svg')] bg-no-repeat bg-right-top bg-origin-padding" };
|
||||||
const _hoisted_2 = { class: "mt-24 text-4xl font-bold text-red-500" };
|
const _hoisted_2 = { class: "mt-24 text-4xl font-bold text-red-500" };
|
||||||
const _hoisted_3 = { class: "space-y-4" };
|
const _hoisted_3 = { class: "space-y-4" };
|
||||||
@@ -55,4 +55,4 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|||||||
export {
|
export {
|
||||||
_sfc_main as default
|
_sfc_main as default
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=DownloadGitView-3STu4yxt.js.map
|
//# sourceMappingURL=DownloadGitView-PWqK5ke4.js.map
|
||||||
8
web/assets/ExtensionPanel-GE0aOkbr.js → web/assets/ExtensionPanel-Ba57xrmg.js
generated
vendored
8
web/assets/ExtensionPanel-GE0aOkbr.js → web/assets/ExtensionPanel-Ba57xrmg.js
generated
vendored
@@ -1,8 +1,8 @@
|
|||||||
var __defProp = Object.defineProperty;
|
var __defProp = Object.defineProperty;
|
||||||
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
||||||
import { d as defineComponent, U as ref, dl as FilterMatchMode, dr as useExtensionStore, a as useSettingStore, p as onMounted, c as computed, o as openBlock, y as createBlock, z as withCtx, k as createVNode, dm as SearchBox, j as unref, bj as script, m as createBaseVNode, f as createElementBlock, D as renderList, E as toDisplayString, a7 as createTextVNode, F as Fragment, l as script$1, B as createCommentVNode, a4 as script$3, ax as script$4, bn as script$5, dn as _sfc_main$1 } from "./index-4Hb32CNk.js";
|
import { d as defineComponent, T as ref, dx as FilterMatchMode, dC as useExtensionStore, a as useSettingStore, p as onMounted, c as computed, o as openBlock, y as createBlock, z as withCtx, k as createVNode, dy as SearchBox, j as unref, bn as script, m as createBaseVNode, f as createElementBlock, D as renderList, E as toDisplayString, a8 as createTextVNode, F as Fragment, l as script$1, B as createCommentVNode, a5 as script$3, ay as script$4, br as script$5, dz as _sfc_main$1 } from "./index-Bv0b06LE.js";
|
||||||
import { g as script$2, h as script$6 } from "./index-nJubvliG.js";
|
import { g as script$2, h as script$6 } from "./index-CgMyWf7n.js";
|
||||||
import "./index-D6zf5KAf.js";
|
import "./index-Dzu9WL4p.js";
|
||||||
const _hoisted_1 = { class: "flex justify-end" };
|
const _hoisted_1 = { class: "flex justify-end" };
|
||||||
const _sfc_main = /* @__PURE__ */ defineComponent({
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
||||||
__name: "ExtensionPanel",
|
__name: "ExtensionPanel",
|
||||||
@@ -179,4 +179,4 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|||||||
export {
|
export {
|
||||||
_sfc_main as default
|
_sfc_main as default
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=ExtensionPanel-GE0aOkbr.js.map
|
//# sourceMappingURL=ExtensionPanel-Ba57xrmg.js.map
|
||||||
2127
web/assets/GraphView-CUSGEqGS.js → web/assets/GraphView-B_UDZi95.js
generated
vendored
2127
web/assets/GraphView-CUSGEqGS.js → web/assets/GraphView-B_UDZi95.js
generated
vendored
File diff suppressed because it is too large
Load Diff
123
web/assets/GraphView-CVCdiww1.css → web/assets/GraphView-Bo28XDd0.css
generated
vendored
123
web/assets/GraphView-CVCdiww1.css → web/assets/GraphView-Bo28XDd0.css
generated
vendored
@@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
.comfy-menu-hamburger[data-v-7ed57d1a] {
|
.comfy-menu-hamburger[data-v-82120b51] {
|
||||||
pointer-events: auto;
|
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -41,19 +40,19 @@
|
|||||||
z-index: 999;
|
z-index: 999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-buttongroup-vertical[data-v-cb8f9a1a] {
|
.p-buttongroup-vertical[data-v-27a9500c] {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
border-radius: var(--p-button-border-radius);
|
border-radius: var(--p-button-border-radius);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 1px solid var(--p-panel-border-color);
|
border: 1px solid var(--p-panel-border-color);
|
||||||
}
|
}
|
||||||
.p-buttongroup-vertical .p-button[data-v-cb8f9a1a] {
|
.p-buttongroup-vertical .p-button[data-v-27a9500c] {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.node-tooltip[data-v-46859edf] {
|
.node-tooltip[data-v-f03142eb] {
|
||||||
background: var(--comfy-input-bg);
|
background: var(--comfy-input-bg);
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
box-shadow: 0 0 5px rgba(0, 0, 0, 0.4);
|
box-shadow: 0 0 5px rgba(0, 0, 0, 0.4);
|
||||||
@@ -133,13 +132,11 @@
|
|||||||
border-right: 4px solid var(--p-button-text-primary-color);
|
border-right: 4px solid var(--p-button-text-primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-tool-bar-container[data-v-33cac83a] {
|
.side-tool-bar-container[data-v-04875455] {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
pointer-events: auto;
|
|
||||||
|
|
||||||
width: var(--sidebar-width);
|
width: var(--sidebar-width);
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
@@ -150,16 +147,16 @@
|
|||||||
--sidebar-width: 4rem;
|
--sidebar-width: 4rem;
|
||||||
--sidebar-icon-size: 1.5rem;
|
--sidebar-icon-size: 1.5rem;
|
||||||
}
|
}
|
||||||
.side-tool-bar-container.small-sidebar[data-v-33cac83a] {
|
.side-tool-bar-container.small-sidebar[data-v-04875455] {
|
||||||
--sidebar-width: 2.5rem;
|
--sidebar-width: 2.5rem;
|
||||||
--sidebar-icon-size: 1rem;
|
--sidebar-icon-size: 1rem;
|
||||||
}
|
}
|
||||||
.side-tool-bar-end[data-v-33cac83a] {
|
.side-tool-bar-end[data-v-04875455] {
|
||||||
align-self: flex-end;
|
align-self: flex-end;
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-indicator[data-v-8d011a31] {
|
.status-indicator[data-v-fd6ae3af] {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
@@ -221,7 +218,7 @@
|
|||||||
border-radius: 0px
|
border-radius: 0px
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-v-38831d8e] .workflow-tabs {
|
[data-v-6ab68035] .workflow-tabs {
|
||||||
background-color: var(--comfy-menu-bg);
|
background-color: var(--comfy-menu-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,31 +232,36 @@
|
|||||||
border-bottom-right-radius: 0;
|
border-bottom-right-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.actionbar[data-v-915e5456] {
|
.actionbar[data-v-ebd56d51] {
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
}
|
}
|
||||||
.actionbar.is-docked[data-v-915e5456] {
|
.actionbar.is-docked[data-v-ebd56d51] {
|
||||||
position: static;
|
position: static;
|
||||||
border-style: none;
|
border-style: none;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
}
|
}
|
||||||
.actionbar.is-dragging[data-v-915e5456] {
|
.actionbar.is-dragging[data-v-ebd56d51] {
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
-moz-user-select: none;
|
-moz-user-select: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
[data-v-915e5456] .p-panel-content {
|
[data-v-ebd56d51] .p-panel-content {
|
||||||
padding: 0.25rem;
|
padding: 0.25rem;
|
||||||
}
|
}
|
||||||
.is-docked[data-v-915e5456] .p-panel-content {
|
.is-docked[data-v-ebd56d51] .p-panel-content {
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
}
|
}
|
||||||
[data-v-915e5456] .p-panel-header {
|
[data-v-ebd56d51] .p-panel-header {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
.drag-handle[data-v-ebd56d51] {
|
||||||
|
height: -moz-max-content;
|
||||||
|
height: max-content;
|
||||||
|
width: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
.top-menubar[data-v-56df69d2] .p-menubar-item-link svg {
|
.top-menubar[data-v-56df69d2] .p-menubar-item-link svg {
|
||||||
display: none;
|
display: none;
|
||||||
@@ -275,7 +277,7 @@
|
|||||||
border-style: solid;
|
border-style: solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comfyui-menu[data-v-929e7543] {
|
.comfyui-menu[data-v-68d3b5b9] {
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: var(--comfy-topbar-height);
|
height: var(--comfy-topbar-height);
|
||||||
background: var(--comfy-menu-bg);
|
background: var(--comfy-menu-bg);
|
||||||
@@ -288,19 +290,94 @@
|
|||||||
order: 0;
|
order: 0;
|
||||||
grid-column: 1/-1;
|
grid-column: 1/-1;
|
||||||
}
|
}
|
||||||
.comfyui-menu.dropzone[data-v-929e7543] {
|
.comfyui-menu.dropzone[data-v-68d3b5b9] {
|
||||||
background: var(--p-highlight-background);
|
background: var(--p-highlight-background);
|
||||||
}
|
}
|
||||||
.comfyui-menu.dropzone-active[data-v-929e7543] {
|
.comfyui-menu.dropzone-active[data-v-68d3b5b9] {
|
||||||
background: var(--p-highlight-background-focus);
|
background: var(--p-highlight-background-focus);
|
||||||
}
|
}
|
||||||
[data-v-929e7543] .p-menubar-item-label {
|
[data-v-68d3b5b9] .p-menubar-item-label {
|
||||||
line-height: revert;
|
line-height: revert;
|
||||||
}
|
}
|
||||||
.comfyui-logo[data-v-929e7543] {
|
.comfyui-logo[data-v-68d3b5b9] {
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
-moz-user-select: none;
|
-moz-user-select: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comfyui-body[data-v-e89d9273] {
|
||||||
|
grid-template-columns: auto 1fr auto;
|
||||||
|
grid-template-rows: auto 1fr auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
+------------------+------------------+------------------+
|
||||||
|
| |
|
||||||
|
| .comfyui-body- |
|
||||||
|
| top |
|
||||||
|
| (spans all cols) |
|
||||||
|
| |
|
||||||
|
+------------------+------------------+------------------+
|
||||||
|
| | | |
|
||||||
|
| .comfyui-body- | #graph-canvas | .comfyui-body- |
|
||||||
|
| left | | right |
|
||||||
|
| | | |
|
||||||
|
| | | |
|
||||||
|
+------------------+------------------+------------------+
|
||||||
|
| |
|
||||||
|
| .comfyui-body- |
|
||||||
|
| bottom |
|
||||||
|
| (spans all cols) |
|
||||||
|
| |
|
||||||
|
+------------------+------------------+------------------+
|
||||||
|
*/
|
||||||
|
.comfyui-body-top[data-v-e89d9273] {
|
||||||
|
order: -5;
|
||||||
|
/* Span across all columns */
|
||||||
|
grid-column: 1/-1;
|
||||||
|
/* Position at the first row */
|
||||||
|
grid-row: 1;
|
||||||
|
/* Top menu bar dropdown needs to be above of graph canvas splitter overlay which is z-index: 999 */
|
||||||
|
/* Top menu bar z-index needs to be higher than bottom menu bar z-index as by default
|
||||||
|
pysssss's image feed is located at body-bottom, and it can overlap with the queue button, which
|
||||||
|
is located in body-top. */
|
||||||
|
z-index: 1001;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.comfyui-body-left[data-v-e89d9273] {
|
||||||
|
order: -4;
|
||||||
|
/* Position in the first column */
|
||||||
|
grid-column: 1;
|
||||||
|
/* Position below the top element */
|
||||||
|
grid-row: 2;
|
||||||
|
z-index: 10;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.graph-canvas-container[data-v-e89d9273] {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
order: -3;
|
||||||
|
grid-column: 2;
|
||||||
|
grid-row: 2;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.comfyui-body-right[data-v-e89d9273] {
|
||||||
|
order: -2;
|
||||||
|
z-index: 10;
|
||||||
|
grid-column: 3;
|
||||||
|
grid-row: 2;
|
||||||
|
}
|
||||||
|
.comfyui-body-bottom[data-v-e89d9273] {
|
||||||
|
order: 4;
|
||||||
|
/* Span across all columns */
|
||||||
|
grid-column: 1/-1;
|
||||||
|
grid-row: 3;
|
||||||
|
/* Bottom menu bar dropdown needs to be above of graph canvas splitter overlay which is z-index: 999 */
|
||||||
|
z-index: 1000;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
52
web/assets/InstallView-DTDlVr0Z.js → web/assets/InstallView-DW9xwU_F.js
generated
vendored
52
web/assets/InstallView-DTDlVr0Z.js → web/assets/InstallView-DW9xwU_F.js
generated
vendored
@@ -1,9 +1,9 @@
|
|||||||
var __defProp = Object.defineProperty;
|
var __defProp = Object.defineProperty;
|
||||||
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
||||||
import { d as defineComponent, U as ref, bm as useModel, o as openBlock, f as createElementBlock, m as createBaseVNode, E as toDisplayString, k as createVNode, j as unref, bn as script, bh as script$1, ar as withModifiers, z as withCtx, ab as script$2, K as useI18n, c as computed, ai as normalizeClass, B as createCommentVNode, a4 as script$3, a7 as createTextVNode, b5 as electronAPI, _ as _export_sfc, p as onMounted, r as resolveDirective, bg as script$4, i as withDirectives, bo as script$5, bp as script$6, l as script$7, y as createBlock, bj as script$8, bq as MigrationItems, w as watchEffect, F as Fragment, D as renderList, br as script$9, bs as mergeModels, bt as ValidationState, Y as normalizeI18nKey, O as watch, bu as checkMirrorReachable, bv as _sfc_main$7, bw as mergeValidationStates, bc as t, a$ as script$a, bx as CUDA_TORCH_URL, by as NIGHTLY_CPU_TORCH_URL, be as useRouter, ag as toRaw } from "./index-4Hb32CNk.js";
|
import { d as defineComponent, T as ref, bq as useModel, o as openBlock, f as createElementBlock, m as createBaseVNode, E as toDisplayString, k as createVNode, j as unref, br as script, bl as script$1, as as withModifiers, z as withCtx, ac as script$2, I as useI18n, c as computed, aj as normalizeClass, B as createCommentVNode, a5 as script$3, a8 as createTextVNode, b9 as electronAPI, _ as _export_sfc, p as onMounted, r as resolveDirective, bk as script$4, i as withDirectives, bs as script$5, bt as script$6, l as script$7, y as createBlock, bn as script$8, bu as MigrationItems, w as watchEffect, F as Fragment, D as renderList, bv as script$9, bw as mergeModels, bx as ValidationState, X as normalizeI18nKey, N as watch, by as checkMirrorReachable, bz as _sfc_main$7, bA as isInChina, bB as mergeValidationStates, bg as t, b3 as script$a, bC as CUDA_TORCH_URL, bD as NIGHTLY_CPU_TORCH_URL, bi as useRouter, ah as toRaw } from "./index-Bv0b06LE.js";
|
||||||
import { s as script$b, a as script$c, b as script$d, c as script$e, d as script$f } from "./index-hkkV7N7e.js";
|
import { s as script$b, a as script$c, b as script$d, c as script$e, d as script$f } from "./index-SeIZOWJp.js";
|
||||||
import { P as PYTHON_MIRROR, a as PYPI_MIRROR } from "./uvMirrors-B-HKMf6X.js";
|
import { P as PYTHON_MIRROR, a as PYPI_MIRROR } from "./uvMirrors-B-HKMf6X.js";
|
||||||
import { _ as _sfc_main$8 } from "./BaseViewTemplate-v6omkdXg.js";
|
import { _ as _sfc_main$8 } from "./BaseViewTemplate-BTbuZf5t.js";
|
||||||
const _hoisted_1$5 = { class: "flex flex-col gap-6 w-[600px]" };
|
const _hoisted_1$5 = { class: "flex flex-col gap-6 w-[600px]" };
|
||||||
const _hoisted_2$5 = { class: "flex flex-col gap-4" };
|
const _hoisted_2$5 = { class: "flex flex-col gap-4" };
|
||||||
const _hoisted_3$5 = { class: "text-2xl font-semibold text-neutral-100" };
|
const _hoisted_3$5 = { class: "text-2xl font-semibold text-neutral-100" };
|
||||||
@@ -314,6 +314,7 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
|
|||||||
const pathExists = ref(false);
|
const pathExists = ref(false);
|
||||||
const appData = ref("");
|
const appData = ref("");
|
||||||
const appPath = ref("");
|
const appPath = ref("");
|
||||||
|
const inputTouched = ref(false);
|
||||||
const electron = electronAPI();
|
const electron = electronAPI();
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const paths = await electron.getSystemPaths();
|
const paths = await electron.getSystemPaths();
|
||||||
@@ -355,6 +356,13 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
|
|||||||
pathError.value = t2("install.failedToSelectDirectory");
|
pathError.value = t2("install.failedToSelectDirectory");
|
||||||
}
|
}
|
||||||
}, "browsePath");
|
}, "browsePath");
|
||||||
|
const onFocus = /* @__PURE__ */ __name(() => {
|
||||||
|
if (!inputTouched.value) {
|
||||||
|
inputTouched.value = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
validatePath(installPath.value);
|
||||||
|
}, "onFocus");
|
||||||
return (_ctx, _cache) => {
|
return (_ctx, _cache) => {
|
||||||
const _directive_tooltip = resolveDirective("tooltip");
|
const _directive_tooltip = resolveDirective("tooltip");
|
||||||
return openBlock(), createElementBlock("div", _hoisted_1$3, [
|
return openBlock(), createElementBlock("div", _hoisted_1$3, [
|
||||||
@@ -370,10 +378,16 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
|
|||||||
_cache[0] || (_cache[0] = ($event) => installPath.value = $event),
|
_cache[0] || (_cache[0] = ($event) => installPath.value = $event),
|
||||||
validatePath
|
validatePath
|
||||||
],
|
],
|
||||||
class: normalizeClass(["w-full", { "p-invalid": pathError.value }])
|
class: normalizeClass(["w-full", { "p-invalid": pathError.value }]),
|
||||||
|
onFocus
|
||||||
}, null, 8, ["modelValue", "class"]),
|
}, null, 8, ["modelValue", "class"]),
|
||||||
withDirectives(createVNode(unref(script$5), { class: "pi pi-info-circle" }, null, 512), [
|
withDirectives(createVNode(unref(script$5), { class: "pi pi-info-circle" }, null, 512), [
|
||||||
[_directive_tooltip, _ctx.$t("install.installLocationTooltip")]
|
[
|
||||||
|
_directive_tooltip,
|
||||||
|
_ctx.$t("install.installLocationTooltip"),
|
||||||
|
void 0,
|
||||||
|
{ top: true }
|
||||||
|
]
|
||||||
])
|
])
|
||||||
]),
|
]),
|
||||||
_: 1
|
_: 1
|
||||||
@@ -595,13 +609,12 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
return (_ctx, _cache) => {
|
return (_ctx, _cache) => {
|
||||||
const _component_UrlInput = _sfc_main$7;
|
|
||||||
return openBlock(), createElementBlock("div", _hoisted_1$1, [
|
return openBlock(), createElementBlock("div", _hoisted_1$1, [
|
||||||
createBaseVNode("div", _hoisted_2$1, [
|
createBaseVNode("div", _hoisted_2$1, [
|
||||||
createBaseVNode("h3", _hoisted_3$1, toDisplayString(_ctx.$t(`settings.${normalizedSettingId.value}.name`)), 1),
|
createBaseVNode("h3", _hoisted_3$1, toDisplayString(_ctx.$t(`settings.${normalizedSettingId.value}.name`)), 1),
|
||||||
createBaseVNode("p", _hoisted_4$1, toDisplayString(_ctx.$t(`settings.${normalizedSettingId.value}.tooltip`)), 1)
|
createBaseVNode("p", _hoisted_4$1, toDisplayString(_ctx.$t(`settings.${normalizedSettingId.value}.tooltip`)), 1)
|
||||||
]),
|
]),
|
||||||
createVNode(_component_UrlInput, {
|
createVNode(_sfc_main$7, {
|
||||||
modelValue: modelValue.value,
|
modelValue: modelValue.value,
|
||||||
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => modelValue.value = $event),
|
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => modelValue.value = $event),
|
||||||
"validate-url-fn": /* @__PURE__ */ __name((mirror) => unref(checkMirrorReachable)(mirror + (_ctx.item.validationPathSuffix ?? "")), "validate-url-fn"),
|
"validate-url-fn": /* @__PURE__ */ __name((mirror) => unref(checkMirrorReachable)(mirror + (_ctx.item.validationPathSuffix ?? "")), "validate-url-fn"),
|
||||||
@@ -653,11 +666,24 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}, "getTorchMirrorItem");
|
}, "getTorchMirrorItem");
|
||||||
const mirrors = computed(() => [
|
const userIsInChina = ref(false);
|
||||||
[PYTHON_MIRROR, pythonMirror],
|
onMounted(async () => {
|
||||||
[PYPI_MIRROR, pypiMirror],
|
userIsInChina.value = await isInChina();
|
||||||
[getTorchMirrorItem(__props.device), torchMirror]
|
});
|
||||||
]);
|
const useFallbackMirror = /* @__PURE__ */ __name((mirror) => ({
|
||||||
|
...mirror,
|
||||||
|
mirror: mirror.fallbackMirror
|
||||||
|
}), "useFallbackMirror");
|
||||||
|
const mirrors = computed(
|
||||||
|
() => [
|
||||||
|
[PYTHON_MIRROR, pythonMirror],
|
||||||
|
[PYPI_MIRROR, pypiMirror],
|
||||||
|
[getTorchMirrorItem(__props.device), torchMirror]
|
||||||
|
].map(([item, modelValue]) => [
|
||||||
|
userIsInChina.value ? useFallbackMirror(item) : item,
|
||||||
|
modelValue
|
||||||
|
])
|
||||||
|
);
|
||||||
const validationStates = ref(
|
const validationStates = ref(
|
||||||
mirrors.value.map(() => ValidationState.IDLE)
|
mirrors.value.map(() => ValidationState.IDLE)
|
||||||
);
|
);
|
||||||
@@ -942,4 +968,4 @@ const InstallView = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-
|
|||||||
export {
|
export {
|
||||||
InstallView as default
|
InstallView as default
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=InstallView-DTDlVr0Z.js.map
|
//# sourceMappingURL=InstallView-DW9xwU_F.js.map
|
||||||
8
web/assets/KeybindingPanel-CDYVPYDp.css
generated
vendored
Normal file
8
web/assets/KeybindingPanel-CDYVPYDp.css
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
[data-v-8454e24f] .p-datatable-tbody > tr > td {
|
||||||
|
padding: 0.25rem;
|
||||||
|
min-height: 2rem
|
||||||
|
}
|
||||||
|
[data-v-8454e24f] .p-datatable-row-selected .actions,[data-v-8454e24f] .p-datatable-selectable-row:hover .actions {
|
||||||
|
visibility: visible
|
||||||
|
}
|
||||||
8
web/assets/KeybindingPanel-DvrUYZ4S.css
generated
vendored
8
web/assets/KeybindingPanel-DvrUYZ4S.css
generated
vendored
@@ -1,8 +0,0 @@
|
|||||||
|
|
||||||
[data-v-2554ab36] .p-datatable-tbody > tr > td {
|
|
||||||
padding: 0.25rem;
|
|
||||||
min-height: 2rem
|
|
||||||
}
|
|
||||||
[data-v-2554ab36] .p-datatable-row-selected .actions,[data-v-2554ab36] .p-datatable-selectable-row:hover .actions {
|
|
||||||
visibility: visible
|
|
||||||
}
|
|
||||||
26
web/assets/KeybindingPanel-C0Nt6GXU.js → web/assets/KeybindingPanel-oavhFdkz.js
generated
vendored
26
web/assets/KeybindingPanel-C0Nt6GXU.js → web/assets/KeybindingPanel-oavhFdkz.js
generated
vendored
@@ -1,9 +1,9 @@
|
|||||||
var __defProp = Object.defineProperty;
|
var __defProp = Object.defineProperty;
|
||||||
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
||||||
import { d as defineComponent, c as computed, o as openBlock, f as createElementBlock, F as Fragment, D as renderList, k as createVNode, z as withCtx, a7 as createTextVNode, E as toDisplayString, j as unref, a4 as script, B as createCommentVNode, U as ref, dl as FilterMatchMode, an as useKeybindingStore, L as useCommandStore, K as useI18n, Y as normalizeI18nKey, w as watchEffect, aR as useToast, r as resolveDirective, y as createBlock, dm as SearchBox, m as createBaseVNode, l as script$2, bg as script$4, ar as withModifiers, bj as script$5, ab as script$6, i as withDirectives, dn as _sfc_main$2, dp as KeyComboImpl, dq as KeybindingImpl, _ as _export_sfc } from "./index-4Hb32CNk.js";
|
import { d as defineComponent, c as computed, o as openBlock, f as createElementBlock, F as Fragment, D as renderList, k as createVNode, z as withCtx, a8 as createTextVNode, E as toDisplayString, j as unref, a5 as script, B as createCommentVNode, T as ref, dx as FilterMatchMode, ao as useKeybindingStore, J as useCommandStore, I as useI18n, X as normalizeI18nKey, w as watchEffect, aV as useToast, r as resolveDirective, y as createBlock, dy as SearchBox, m as createBaseVNode, l as script$2, bk as script$4, as as withModifiers, bn as script$5, ac as script$6, i as withDirectives, dz as _sfc_main$2, dA as KeyComboImpl, dB as KeybindingImpl, _ as _export_sfc } from "./index-Bv0b06LE.js";
|
||||||
import { g as script$1, h as script$3 } from "./index-nJubvliG.js";
|
import { g as script$1, h as script$3 } from "./index-CgMyWf7n.js";
|
||||||
import { u as useKeybindingService } from "./keybindingService-BTNdTpfl.js";
|
import { u as useKeybindingService } from "./keybindingService-DyjX-nxF.js";
|
||||||
import "./index-D6zf5KAf.js";
|
import "./index-Dzu9WL4p.js";
|
||||||
const _hoisted_1$1 = {
|
const _hoisted_1$1 = {
|
||||||
key: 0,
|
key: 0,
|
||||||
class: "px-2"
|
class: "px-2"
|
||||||
@@ -96,6 +96,16 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|||||||
}
|
}
|
||||||
__name(removeKeybinding, "removeKeybinding");
|
__name(removeKeybinding, "removeKeybinding");
|
||||||
function captureKeybinding(event) {
|
function captureKeybinding(event) {
|
||||||
|
if (!event.shiftKey && !event.altKey && !event.ctrlKey && !event.metaKey) {
|
||||||
|
switch (event.key) {
|
||||||
|
case "Escape":
|
||||||
|
cancelEdit();
|
||||||
|
return;
|
||||||
|
case "Enter":
|
||||||
|
saveKeybinding();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
const keyCombo = KeyComboImpl.fromEvent(event);
|
const keyCombo = KeyComboImpl.fromEvent(event);
|
||||||
newBindingKeyCombo.value = keyCombo;
|
newBindingKeyCombo.value = keyCombo;
|
||||||
}
|
}
|
||||||
@@ -151,7 +161,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|||||||
value: commandsData.value,
|
value: commandsData.value,
|
||||||
selection: selectedCommandData.value,
|
selection: selectedCommandData.value,
|
||||||
"onUpdate:selection": _cache[1] || (_cache[1] = ($event) => selectedCommandData.value = $event),
|
"onUpdate:selection": _cache[1] || (_cache[1] = ($event) => selectedCommandData.value = $event),
|
||||||
"global-filter-fields": ["id"],
|
"global-filter-fields": ["id", "label"],
|
||||||
filters: filters.value,
|
filters: filters.value,
|
||||||
selectionMode: "single",
|
selectionMode: "single",
|
||||||
stripedRows: "",
|
stripedRows: "",
|
||||||
@@ -216,7 +226,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|||||||
visible: editDialogVisible.value,
|
visible: editDialogVisible.value,
|
||||||
"onUpdate:visible": _cache[2] || (_cache[2] = ($event) => editDialogVisible.value = $event),
|
"onUpdate:visible": _cache[2] || (_cache[2] = ($event) => editDialogVisible.value = $event),
|
||||||
modal: "",
|
modal: "",
|
||||||
header: currentEditingCommand.value?.id,
|
header: currentEditingCommand.value?.label,
|
||||||
onHide: cancelEdit
|
onHide: cancelEdit
|
||||||
}, {
|
}, {
|
||||||
footer: withCtx(() => [
|
footer: withCtx(() => [
|
||||||
@@ -275,8 +285,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const KeybindingPanel = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-2554ab36"]]);
|
const KeybindingPanel = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-8454e24f"]]);
|
||||||
export {
|
export {
|
||||||
KeybindingPanel as default
|
KeybindingPanel as default
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=KeybindingPanel-C0Nt6GXU.js.map
|
//# sourceMappingURL=KeybindingPanel-oavhFdkz.js.map
|
||||||
1426
web/assets/MaintenanceView-B5Gl0Rrl.js → web/assets/MaintenanceView-Bh8OZpgl.js
generated
vendored
1426
web/assets/MaintenanceView-B5Gl0Rrl.js → web/assets/MaintenanceView-Bh8OZpgl.js
generated
vendored
File diff suppressed because one or more lines are too long
4
web/assets/MaintenanceView-Bj5_Vr6o.css → web/assets/MaintenanceView-DEJCj8SR.css
generated
vendored
4
web/assets/MaintenanceView-Bj5_Vr6o.css → web/assets/MaintenanceView-DEJCj8SR.css
generated
vendored
@@ -63,10 +63,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-v-74b78f7d] .p-tag {
|
[data-v-dd50a7dd] .p-tag {
|
||||||
--p-tag-gap: 0.375rem;
|
--p-tag-gap: 0.375rem;
|
||||||
}
|
}
|
||||||
.backspan[data-v-74b78f7d]::before {
|
.backspan[data-v-dd50a7dd]::before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
color: var(--p-text-muted-color);
|
color: var(--p-text-muted-color);
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
var __defProp = Object.defineProperty;
|
var __defProp = Object.defineProperty;
|
||||||
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
||||||
import { d as defineComponent, K as useI18n, U as ref, p as onMounted, o as openBlock, y as createBlock, z as withCtx, m as createBaseVNode, E as toDisplayString, k as createVNode, j as unref, a4 as script, a$ as script$1, l as script$2, b5 as electronAPI, _ as _export_sfc } from "./index-4Hb32CNk.js";
|
import { d as defineComponent, I as useI18n, T as ref, p as onMounted, o as openBlock, y as createBlock, z as withCtx, m as createBaseVNode, E as toDisplayString, k as createVNode, j as unref, a5 as script, b3 as script$1, l as script$2, b9 as electronAPI, _ as _export_sfc } from "./index-Bv0b06LE.js";
|
||||||
import { _ as _sfc_main$1 } from "./BaseViewTemplate-v6omkdXg.js";
|
import { _ as _sfc_main$1 } from "./BaseViewTemplate-BTbuZf5t.js";
|
||||||
const _hoisted_1 = { class: "comfy-installer grow flex flex-col gap-4 text-neutral-300 max-w-110" };
|
const _hoisted_1 = { class: "comfy-installer grow flex flex-col gap-4 text-neutral-300 max-w-110" };
|
||||||
const _hoisted_2 = { class: "text-2xl font-semibold text-neutral-100" };
|
const _hoisted_2 = { class: "text-2xl font-semibold text-neutral-100" };
|
||||||
const _hoisted_3 = { class: "m-1 text-neutral-300" };
|
const _hoisted_3 = { class: "m-1 text-neutral-300" };
|
||||||
@@ -71,4 +71,4 @@ const ManualConfigurationView = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scop
|
|||||||
export {
|
export {
|
||||||
ManualConfigurationView as default
|
ManualConfigurationView as default
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=ManualConfigurationView-DueOvLuK.js.map
|
//# sourceMappingURL=ManualConfigurationView-DTLyJ3VG.js.map
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
var __defProp = Object.defineProperty;
|
var __defProp = Object.defineProperty;
|
||||||
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
||||||
import { _ as _sfc_main$1 } from "./BaseViewTemplate-v6omkdXg.js";
|
import { _ as _sfc_main$1 } from "./BaseViewTemplate-BTbuZf5t.js";
|
||||||
import { d as defineComponent, aR as useToast, K as useI18n, U as ref, be as useRouter, o as openBlock, y as createBlock, z as withCtx, m as createBaseVNode, E as toDisplayString, a7 as createTextVNode, k as createVNode, j as unref, bn as script, l as script$1, b5 as electronAPI } from "./index-4Hb32CNk.js";
|
import { d as defineComponent, aV as useToast, I as useI18n, T as ref, bi as useRouter, o as openBlock, y as createBlock, z as withCtx, m as createBaseVNode, E as toDisplayString, a8 as createTextVNode, k as createVNode, j as unref, br as script, l as script$1, b9 as electronAPI } from "./index-Bv0b06LE.js";
|
||||||
const _hoisted_1 = { class: "h-full p-8 2xl:p-16 flex flex-col items-center justify-center" };
|
const _hoisted_1 = { class: "h-full p-8 2xl:p-16 flex flex-col items-center justify-center" };
|
||||||
const _hoisted_2 = { class: "bg-neutral-800 rounded-lg shadow-lg p-6 w-full max-w-[600px] flex flex-col gap-6" };
|
const _hoisted_2 = { class: "bg-neutral-800 rounded-lg shadow-lg p-6 w-full max-w-[600px] flex flex-col gap-6" };
|
||||||
const _hoisted_3 = { class: "text-3xl font-semibold text-neutral-100" };
|
const _hoisted_3 = { class: "text-3xl font-semibold text-neutral-100" };
|
||||||
@@ -83,4 +83,4 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|||||||
export {
|
export {
|
||||||
_sfc_main as default
|
_sfc_main as default
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=MetricsConsentView-DTQYUF4Z.js.map
|
//# sourceMappingURL=MetricsConsentView-C80fk2cl.js.map
|
||||||
6
web/assets/NotSupportedView-PDDrAb9U.js → web/assets/NotSupportedView-B78ZVR9Z.js
generated
vendored
6
web/assets/NotSupportedView-PDDrAb9U.js → web/assets/NotSupportedView-B78ZVR9Z.js
generated
vendored
@@ -1,7 +1,7 @@
|
|||||||
var __defProp = Object.defineProperty;
|
var __defProp = Object.defineProperty;
|
||||||
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
||||||
import { d as defineComponent, be as useRouter, r as resolveDirective, o as openBlock, y as createBlock, z as withCtx, m as createBaseVNode, E as toDisplayString, k as createVNode, j as unref, l as script, i as withDirectives, _ as _export_sfc } from "./index-4Hb32CNk.js";
|
import { d as defineComponent, bi as useRouter, r as resolveDirective, o as openBlock, y as createBlock, z as withCtx, m as createBaseVNode, E as toDisplayString, k as createVNode, j as unref, l as script, i as withDirectives, _ as _export_sfc } from "./index-Bv0b06LE.js";
|
||||||
import { _ as _sfc_main$1 } from "./BaseViewTemplate-v6omkdXg.js";
|
import { _ as _sfc_main$1 } from "./BaseViewTemplate-BTbuZf5t.js";
|
||||||
const _imports_0 = "" + new URL("images/sad_girl.png", import.meta.url).href;
|
const _imports_0 = "" + new URL("images/sad_girl.png", import.meta.url).href;
|
||||||
const _hoisted_1 = { class: "sad-container" };
|
const _hoisted_1 = { class: "sad-container" };
|
||||||
const _hoisted_2 = { class: "no-drag sad-text flex items-center" };
|
const _hoisted_2 = { class: "no-drag sad-text flex items-center" };
|
||||||
@@ -83,4 +83,4 @@ const NotSupportedView = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "
|
|||||||
export {
|
export {
|
||||||
NotSupportedView as default
|
NotSupportedView as default
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=NotSupportedView-PDDrAb9U.js.map
|
//# sourceMappingURL=NotSupportedView-B78ZVR9Z.js.map
|
||||||
6
web/assets/ServerConfigPanel-DnGhsuUV.js → web/assets/ServerConfigPanel-BYrt6wyr.js
generated
vendored
6
web/assets/ServerConfigPanel-DnGhsuUV.js → web/assets/ServerConfigPanel-BYrt6wyr.js
generated
vendored
@@ -1,7 +1,7 @@
|
|||||||
var __defProp = Object.defineProperty;
|
var __defProp = Object.defineProperty;
|
||||||
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
||||||
import { o as openBlock, f as createElementBlock, m as createBaseVNode, H as markRaw, d as defineComponent, a as useSettingStore, ae as storeToRefs, O as watch, dy as useCopyToClipboard, K as useI18n, y as createBlock, z as withCtx, j as unref, bj as script, E as toDisplayString, D as renderList, F as Fragment, k as createVNode, l as script$1, B as createCommentVNode, bh as script$2, dz as FormItem, dn as _sfc_main$1, b5 as electronAPI } from "./index-4Hb32CNk.js";
|
import { o as openBlock, f as createElementBlock, m as createBaseVNode, H as markRaw, d as defineComponent, a as useSettingStore, af as storeToRefs, N as watch, dJ as useCopyToClipboard, I as useI18n, y as createBlock, z as withCtx, j as unref, bn as script, E as toDisplayString, D as renderList, F as Fragment, k as createVNode, l as script$1, B as createCommentVNode, bl as script$2, dK as FormItem, dz as _sfc_main$1, b9 as electronAPI } from "./index-Bv0b06LE.js";
|
||||||
import { u as useServerConfigStore } from "./serverConfigStore-BYbZcbWj.js";
|
import { u as useServerConfigStore } from "./serverConfigStore-D2Vr0L0h.js";
|
||||||
const _hoisted_1$1 = {
|
const _hoisted_1$1 = {
|
||||||
viewBox: "0 0 24 24",
|
viewBox: "0 0 24 24",
|
||||||
width: "1.2em",
|
width: "1.2em",
|
||||||
@@ -153,4 +153,4 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|||||||
export {
|
export {
|
||||||
_sfc_main as default
|
_sfc_main as default
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=ServerConfigPanel-DnGhsuUV.js.map
|
//# sourceMappingURL=ServerConfigPanel-BYrt6wyr.js.map
|
||||||
8
web/assets/ServerStartView-yzYZ8gms.js → web/assets/ServerStartView-B7TlHxYo.js
generated
vendored
8
web/assets/ServerStartView-yzYZ8gms.js → web/assets/ServerStartView-B7TlHxYo.js
generated
vendored
@@ -1,7 +1,7 @@
|
|||||||
var __defProp = Object.defineProperty;
|
var __defProp = Object.defineProperty;
|
||||||
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
||||||
import { d as defineComponent, K as useI18n, U as ref, bk as ProgressStatus, p as onMounted, o as openBlock, y as createBlock, z as withCtx, m as createBaseVNode, a7 as createTextVNode, E as toDisplayString, j as unref, f as createElementBlock, B as createCommentVNode, k as createVNode, l as script, i as withDirectives, v as vShow, bl as BaseTerminal, b5 as electronAPI, _ as _export_sfc } from "./index-4Hb32CNk.js";
|
import { d as defineComponent, I as useI18n, T as ref, bo as ProgressStatus, p as onMounted, o as openBlock, y as createBlock, z as withCtx, m as createBaseVNode, a8 as createTextVNode, E as toDisplayString, j as unref, f as createElementBlock, B as createCommentVNode, k as createVNode, l as script, i as withDirectives, v as vShow, bp as BaseTerminal, b9 as electronAPI, _ as _export_sfc } from "./index-Bv0b06LE.js";
|
||||||
import { _ as _sfc_main$1 } from "./BaseViewTemplate-v6omkdXg.js";
|
import { _ as _sfc_main$1 } from "./BaseViewTemplate-BTbuZf5t.js";
|
||||||
const _hoisted_1 = { class: "flex flex-col w-full h-full items-center" };
|
const _hoisted_1 = { class: "flex flex-col w-full h-full items-center" };
|
||||||
const _hoisted_2 = { class: "text-2xl font-bold" };
|
const _hoisted_2 = { class: "text-2xl font-bold" };
|
||||||
const _hoisted_3 = { key: 0 };
|
const _hoisted_3 = { key: 0 };
|
||||||
@@ -93,8 +93,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const ServerStartView = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-4140d62b"]]);
|
const ServerStartView = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-e6ba9633"]]);
|
||||||
export {
|
export {
|
||||||
ServerStartView as default
|
ServerStartView as default
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=ServerStartView-yzYZ8gms.js.map
|
//# sourceMappingURL=ServerStartView-B7TlHxYo.js.map
|
||||||
2
web/assets/ServerStartView-CJiwVDQY.css → web/assets/ServerStartView-BZ7uhZHv.css
generated
vendored
2
web/assets/ServerStartView-CJiwVDQY.css → web/assets/ServerStartView-BZ7uhZHv.css
generated
vendored
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
[data-v-4140d62b] .xterm-helper-textarea {
|
[data-v-e6ba9633] .xterm-helper-textarea {
|
||||||
/* Hide this as it moves all over when uv is running */
|
/* Hide this as it moves all over when uv is running */
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
1061
web/assets/TerminalOutputDrawer-CKr7Br7O.js
generated
vendored
Normal file
1061
web/assets/TerminalOutputDrawer-CKr7Br7O.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
6
web/assets/UserSelectView-DeJDnrF0.js → web/assets/UserSelectView-C703HOyO.js
generated
vendored
6
web/assets/UserSelectView-DeJDnrF0.js → web/assets/UserSelectView-C703HOyO.js
generated
vendored
@@ -1,7 +1,7 @@
|
|||||||
var __defProp = Object.defineProperty;
|
var __defProp = Object.defineProperty;
|
||||||
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
||||||
import { d as defineComponent, aj as useUserStore, be as useRouter, U as ref, c as computed, p as onMounted, o as openBlock, y as createBlock, z as withCtx, m as createBaseVNode, E as toDisplayString, k as createVNode, bf as withKeys, j as unref, bg as script, bh as script$1, bi as script$2, bj as script$3, a7 as createTextVNode, B as createCommentVNode, l as script$4 } from "./index-4Hb32CNk.js";
|
import { d as defineComponent, ak as useUserStore, bi as useRouter, T as ref, c as computed, p as onMounted, o as openBlock, y as createBlock, z as withCtx, m as createBaseVNode, E as toDisplayString, k as createVNode, bj as withKeys, j as unref, bk as script, bl as script$1, bm as script$2, bn as script$3, a8 as createTextVNode, B as createCommentVNode, l as script$4 } from "./index-Bv0b06LE.js";
|
||||||
import { _ as _sfc_main$1 } from "./BaseViewTemplate-v6omkdXg.js";
|
import { _ as _sfc_main$1 } from "./BaseViewTemplate-BTbuZf5t.js";
|
||||||
const _hoisted_1 = {
|
const _hoisted_1 = {
|
||||||
id: "comfy-user-selection",
|
id: "comfy-user-selection",
|
||||||
class: "min-w-84 relative rounded-lg bg-[var(--comfy-menu-bg)] p-5 px-10 shadow-lg"
|
class: "min-w-84 relative rounded-lg bg-[var(--comfy-menu-bg)] p-5 px-10 shadow-lg"
|
||||||
@@ -98,4 +98,4 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|||||||
export {
|
export {
|
||||||
_sfc_main as default
|
_sfc_main as default
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=UserSelectView-DeJDnrF0.js.map
|
//# sourceMappingURL=UserSelectView-C703HOyO.js.map
|
||||||
6
web/assets/WelcomeView-DkwLdayn.js → web/assets/WelcomeView-DIFvbWc2.js
generated
vendored
6
web/assets/WelcomeView-DkwLdayn.js → web/assets/WelcomeView-DIFvbWc2.js
generated
vendored
@@ -1,7 +1,7 @@
|
|||||||
var __defProp = Object.defineProperty;
|
var __defProp = Object.defineProperty;
|
||||||
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
||||||
import { d as defineComponent, be as useRouter, o as openBlock, y as createBlock, z as withCtx, m as createBaseVNode, E as toDisplayString, k as createVNode, j as unref, l as script, _ as _export_sfc } from "./index-4Hb32CNk.js";
|
import { d as defineComponent, bi as useRouter, o as openBlock, y as createBlock, z as withCtx, m as createBaseVNode, E as toDisplayString, k as createVNode, j as unref, l as script, _ as _export_sfc } from "./index-Bv0b06LE.js";
|
||||||
import { _ as _sfc_main$1 } from "./BaseViewTemplate-v6omkdXg.js";
|
import { _ as _sfc_main$1 } from "./BaseViewTemplate-BTbuZf5t.js";
|
||||||
const _hoisted_1 = { class: "flex flex-col items-center justify-center gap-8 p-8" };
|
const _hoisted_1 = { class: "flex flex-col items-center justify-center gap-8 p-8" };
|
||||||
const _hoisted_2 = { class: "animated-gradient-text text-glow select-none" };
|
const _hoisted_2 = { class: "animated-gradient-text text-glow select-none" };
|
||||||
const _sfc_main = /* @__PURE__ */ defineComponent({
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
||||||
@@ -36,4 +36,4 @@ const WelcomeView = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-
|
|||||||
export {
|
export {
|
||||||
WelcomeView as default
|
WelcomeView as default
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=WelcomeView-DkwLdayn.js.map
|
//# sourceMappingURL=WelcomeView-DIFvbWc2.js.map
|
||||||
618
web/assets/index-A_bXPJCN.js
generated
vendored
Normal file
618
web/assets/index-A_bXPJCN.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1239
web/assets/index-B4tExwG7.js → web/assets/index-B36GcHVN.js
generated
vendored
1239
web/assets/index-B4tExwG7.js → web/assets/index-B36GcHVN.js
generated
vendored
File diff suppressed because it is too large
Load Diff
10596
web/assets/index-4Hb32CNk.js → web/assets/index-Bv0b06LE.js
generated
vendored
10596
web/assets/index-4Hb32CNk.js → web/assets/index-Bv0b06LE.js
generated
vendored
File diff suppressed because one or more lines are too long
1032
web/assets/index-D4CAJ2MK.js → web/assets/index-C068lYT4.js
generated
vendored
1032
web/assets/index-D4CAJ2MK.js → web/assets/index-C068lYT4.js
generated
vendored
File diff suppressed because one or more lines are too long
343
web/assets/index-C1Hb_Yo9.css → web/assets/index-CBxvvAzM.css
generated
vendored
343
web/assets/index-C1Hb_Yo9.css → web/assets/index-CBxvvAzM.css
generated
vendored
@@ -306,6 +306,7 @@
|
|||||||
.litegraph .dialog .dialog-footer {
|
.litegraph .dialog .dialog-footer {
|
||||||
height: 50px;
|
height: 50px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
margin: 0;
|
||||||
border-top: 1px solid #1a1a1a;
|
border-top: 1px solid #1a1a1a;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,63 +443,6 @@
|
|||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.litegraph .subgraph_property {
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.litegraph .subgraph_property:hover {
|
|
||||||
background-color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.litegraph .subgraph_property.extra {
|
|
||||||
margin-top: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.litegraph .subgraph_property span.name {
|
|
||||||
font-size: 1.3em;
|
|
||||||
padding-left: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.litegraph .subgraph_property span.type {
|
|
||||||
opacity: 0.5;
|
|
||||||
margin-right: 20px;
|
|
||||||
padding-left: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.litegraph .subgraph_property span.label {
|
|
||||||
display: inline-block;
|
|
||||||
width: 60px;
|
|
||||||
padding: 0px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.litegraph .subgraph_property input {
|
|
||||||
width: 140px;
|
|
||||||
color: #999;
|
|
||||||
background-color: #1a1a1a;
|
|
||||||
border-radius: 4px;
|
|
||||||
border: 0;
|
|
||||||
margin-right: 10px;
|
|
||||||
padding: 4px;
|
|
||||||
padding-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.litegraph .subgraph_property button {
|
|
||||||
background-color: #1c1c1c;
|
|
||||||
color: #aaa;
|
|
||||||
border: 0;
|
|
||||||
border-radius: 2px;
|
|
||||||
padding: 4px 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.litegraph .subgraph_property.extra {
|
|
||||||
color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.litegraph .subgraph_property.extra input {
|
|
||||||
background-color: #111;
|
|
||||||
}
|
|
||||||
|
|
||||||
.litegraph .bullet_icon {
|
.litegraph .bullet_icon {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
@@ -661,21 +605,6 @@
|
|||||||
.litegraph .dialog .dialog-content {
|
.litegraph .dialog .dialog-content {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.litegraph .dialog .dialog-content .subgraph_property {
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
.litegraph .dialog .dialog-footer {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
.litegraph .dialog .dialog-footer .subgraph_property {
|
|
||||||
margin-top: 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
.litegraph .dialog .dialog-footer .subgraph_property .name {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
.litegraph .graphdialog {
|
.litegraph .graphdialog {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -2110,6 +2039,9 @@
|
|||||||
.-right-4{
|
.-right-4{
|
||||||
right: -1rem;
|
right: -1rem;
|
||||||
}
|
}
|
||||||
|
.bottom-0{
|
||||||
|
bottom: 0px;
|
||||||
|
}
|
||||||
.bottom-\[10px\]{
|
.bottom-\[10px\]{
|
||||||
bottom: 10px;
|
bottom: 10px;
|
||||||
}
|
}
|
||||||
@@ -2119,6 +2051,15 @@
|
|||||||
.left-0{
|
.left-0{
|
||||||
left: 0px;
|
left: 0px;
|
||||||
}
|
}
|
||||||
|
.left-1\/2{
|
||||||
|
left: 50%;
|
||||||
|
}
|
||||||
|
.left-12{
|
||||||
|
left: 3rem;
|
||||||
|
}
|
||||||
|
.left-2{
|
||||||
|
left: 0.5rem;
|
||||||
|
}
|
||||||
.left-\[-350px\]{
|
.left-\[-350px\]{
|
||||||
left: -350px;
|
left: -350px;
|
||||||
}
|
}
|
||||||
@@ -2128,6 +2069,9 @@
|
|||||||
.top-0{
|
.top-0{
|
||||||
top: 0px;
|
top: 0px;
|
||||||
}
|
}
|
||||||
|
.top-2{
|
||||||
|
top: 0.5rem;
|
||||||
|
}
|
||||||
.top-\[50px\]{
|
.top-\[50px\]{
|
||||||
top: 50px;
|
top: 50px;
|
||||||
}
|
}
|
||||||
@@ -2137,6 +2081,9 @@
|
|||||||
.z-10{
|
.z-10{
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
.z-20{
|
||||||
|
z-index: 20;
|
||||||
|
}
|
||||||
.z-\[1000\]{
|
.z-\[1000\]{
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
}
|
}
|
||||||
@@ -2196,6 +2143,10 @@
|
|||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
.my-8{
|
||||||
|
margin-top: 2rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
.mb-2{
|
.mb-2{
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
@@ -2286,6 +2237,9 @@
|
|||||||
.h-16{
|
.h-16{
|
||||||
height: 4rem;
|
height: 4rem;
|
||||||
}
|
}
|
||||||
|
.h-48{
|
||||||
|
height: 12rem;
|
||||||
|
}
|
||||||
.h-6{
|
.h-6{
|
||||||
height: 1.5rem;
|
height: 1.5rem;
|
||||||
}
|
}
|
||||||
@@ -2331,6 +2285,9 @@
|
|||||||
.min-h-screen{
|
.min-h-screen{
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
.w-0{
|
||||||
|
width: 0px;
|
||||||
|
}
|
||||||
.w-1\/2{
|
.w-1\/2{
|
||||||
width: 50%;
|
width: 50%;
|
||||||
}
|
}
|
||||||
@@ -2343,12 +2300,21 @@
|
|||||||
.w-16{
|
.w-16{
|
||||||
width: 4rem;
|
width: 4rem;
|
||||||
}
|
}
|
||||||
|
.w-24{
|
||||||
|
width: 6rem;
|
||||||
|
}
|
||||||
.w-28{
|
.w-28{
|
||||||
width: 7rem;
|
width: 7rem;
|
||||||
}
|
}
|
||||||
|
.w-3{
|
||||||
|
width: 0.75rem;
|
||||||
|
}
|
||||||
.w-3\/12{
|
.w-3\/12{
|
||||||
width: 25%;
|
width: 25%;
|
||||||
}
|
}
|
||||||
|
.w-32{
|
||||||
|
width: 8rem;
|
||||||
|
}
|
||||||
.w-44{
|
.w-44{
|
||||||
width: 11rem;
|
width: 11rem;
|
||||||
}
|
}
|
||||||
@@ -2458,6 +2424,9 @@
|
|||||||
.cursor-pointer{
|
.cursor-pointer{
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
.touch-none{
|
||||||
|
touch-action: none;
|
||||||
|
}
|
||||||
.select-none{
|
.select-none{
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
-moz-user-select: none;
|
-moz-user-select: none;
|
||||||
@@ -2893,6 +2862,10 @@
|
|||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: rgb(239 68 68 / var(--tw-text-opacity));
|
color: rgb(239 68 68 / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
|
.text-white{
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(255 255 255 / var(--tw-text-opacity));
|
||||||
|
}
|
||||||
.underline{
|
.underline{
|
||||||
text-decoration-line: underline;
|
text-decoration-line: underline;
|
||||||
}
|
}
|
||||||
@@ -3035,8 +3008,6 @@ body {
|
|||||||
height: 100vh;
|
height: 100vh;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
grid-template-columns: auto 1fr auto;
|
|
||||||
grid-template-rows: auto 1fr auto;
|
|
||||||
background: var(--bg-color) var(--bg-img);
|
background: var(--bg-color) var(--bg-img);
|
||||||
color: var(--fg-color);
|
color: var(--fg-color);
|
||||||
min-height: -webkit-fill-available;
|
min-height: -webkit-fill-available;
|
||||||
@@ -3046,87 +3017,6 @@ body {
|
|||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
+------------------+------------------+------------------+
|
|
||||||
| |
|
|
||||||
| .comfyui-body- |
|
|
||||||
| top |
|
|
||||||
| (spans all cols) |
|
|
||||||
| |
|
|
||||||
+------------------+------------------+------------------+
|
|
||||||
| | | |
|
|
||||||
| .comfyui-body- | #graph-canvas | .comfyui-body- |
|
|
||||||
| left | | right |
|
|
||||||
| | | |
|
|
||||||
| | | |
|
|
||||||
+------------------+------------------+------------------+
|
|
||||||
| |
|
|
||||||
| .comfyui-body- |
|
|
||||||
| bottom |
|
|
||||||
| (spans all cols) |
|
|
||||||
| |
|
|
||||||
+------------------+------------------+------------------+
|
|
||||||
*/
|
|
||||||
|
|
||||||
.comfyui-body-top {
|
|
||||||
order: -5;
|
|
||||||
/* Span across all columns */
|
|
||||||
grid-column: 1/-1;
|
|
||||||
/* Position at the first row */
|
|
||||||
grid-row: 1;
|
|
||||||
/* Top menu bar dropdown needs to be above of graph canvas splitter overlay which is z-index: 999 */
|
|
||||||
/* Top menu bar z-index needs to be higher than bottom menu bar z-index as by default
|
|
||||||
pysssss's image feed is located at body-bottom, and it can overlap with the queue button, which
|
|
||||||
is located in body-top. */
|
|
||||||
z-index: 1001;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comfyui-body-left {
|
|
||||||
order: -4;
|
|
||||||
/* Position in the first column */
|
|
||||||
grid-column: 1;
|
|
||||||
/* Position below the top element */
|
|
||||||
grid-row: 2;
|
|
||||||
z-index: 10;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.graph-canvas-container {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
order: -3;
|
|
||||||
grid-column: 2;
|
|
||||||
grid-row: 2;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
#graph-canvas {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
touch-action: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comfyui-body-right {
|
|
||||||
order: -2;
|
|
||||||
z-index: 10;
|
|
||||||
grid-column: 3;
|
|
||||||
grid-row: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comfyui-body-bottom {
|
|
||||||
order: 4;
|
|
||||||
/* Span across all columns */
|
|
||||||
grid-column: 1/-1;
|
|
||||||
grid-row: 3;
|
|
||||||
/* Bottom menu bar dropdown needs to be above of graph canvas splitter overlay which is z-index: 999 */
|
|
||||||
z-index: 1000;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comfy-multiline-input {
|
.comfy-multiline-input {
|
||||||
background-color: var(--comfy-input-bg);
|
background-color: var(--comfy-input-bg);
|
||||||
color: var(--input-text);
|
color: var(--input-text);
|
||||||
@@ -3541,84 +3431,6 @@ dialog::backdrop {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
#comfy-settings-dialog {
|
|
||||||
padding: 0;
|
|
||||||
width: 41rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#comfy-settings-dialog tr > td:first-child {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
#comfy-settings-dialog tbody button,
|
|
||||||
#comfy-settings-dialog table > button {
|
|
||||||
background-color: var(--bg-color);
|
|
||||||
border: 1px var(--border-color) solid;
|
|
||||||
border-radius: 0;
|
|
||||||
color: var(--input-text);
|
|
||||||
font-size: 1rem;
|
|
||||||
padding: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#comfy-settings-dialog button:hover {
|
|
||||||
background-color: var(--tr-odd-bg-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* General CSS for tables */
|
|
||||||
|
|
||||||
.comfy-table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
color: var(--input-text);
|
|
||||||
font-family: Arial, sans-serif;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comfy-table caption {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
background-color: var(--bg-color);
|
|
||||||
color: var(--input-text);
|
|
||||||
font-size: 1rem;
|
|
||||||
font-weight: bold;
|
|
||||||
padding: 8px;
|
|
||||||
text-align: center;
|
|
||||||
border-bottom: 1px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.comfy-table caption .comfy-btn {
|
|
||||||
position: absolute;
|
|
||||||
top: -2px;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
cursor: pointer;
|
|
||||||
border: none;
|
|
||||||
height: 100%;
|
|
||||||
border-radius: 0;
|
|
||||||
aspect-ratio: 1/1;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
font-size: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comfy-table caption .comfy-btn:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comfy-table tr:nth-child(even) {
|
|
||||||
background-color: var(--tr-even-bg-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.comfy-table tr:nth-child(odd) {
|
|
||||||
background-color: var(--tr-odd-bg-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.comfy-table td,
|
|
||||||
.comfy-table th {
|
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Context menu */
|
/* Context menu */
|
||||||
|
|
||||||
.litegraph .dialog {
|
.litegraph .dialog {
|
||||||
@@ -3718,24 +3530,6 @@ dialog::backdrop {
|
|||||||
will-change: transform;
|
will-change: transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 450px) {
|
|
||||||
#comfy-settings-dialog .comfy-table tbody {
|
|
||||||
display: grid;
|
|
||||||
}
|
|
||||||
#comfy-settings-dialog .comfy-table tr {
|
|
||||||
display: grid;
|
|
||||||
}
|
|
||||||
#comfy-settings-dialog tr > td:first-child {
|
|
||||||
text-align: center;
|
|
||||||
border-bottom: none;
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
#comfy-settings-dialog tr > td:not(:first-child) {
|
|
||||||
text-align: center;
|
|
||||||
border-top: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
audio.comfy-audio.empty-audio-widget {
|
audio.comfy-audio.empty-audio-widget {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@@ -3746,7 +3540,6 @@ audio.comfy-audio.empty-audio-widget {
|
|||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
pointer-events: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set auto complete panel's width as it is not accessible within vue-root */
|
/* Set auto complete panel's width as it is not accessible within vue-root */
|
||||||
@@ -3926,7 +3719,7 @@ audio.comfy-audio.empty-audio-widget {
|
|||||||
padding-top: 0px
|
padding-top: 0px
|
||||||
}
|
}
|
||||||
|
|
||||||
.prompt-dialog-content[data-v-3df70997] {
|
.prompt-dialog-content[data-v-4f1e3bbe] {
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3944,17 +3737,17 @@ audio.comfy-audio.empty-audio-widget {
|
|||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comfy-error-report[data-v-3faf7785] {
|
.comfy-error-report[data-v-e5000be2] {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
.action-container[data-v-3faf7785] {
|
.action-container[data-v-e5000be2] {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
.wrapper-pre[data-v-3faf7785] {
|
.wrapper-pre[data-v-e5000be2] {
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
@@ -4023,13 +3816,13 @@ audio.comfy-audio.empty-audio-widget {
|
|||||||
padding: 0px;
|
padding: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-input[data-v-1451da7b] .input-slider .p-inputnumber input,
|
.form-input[data-v-a29c257f] .input-slider .p-inputnumber input,
|
||||||
.form-input[data-v-1451da7b] .input-slider .slider-part {
|
.form-input[data-v-a29c257f] .input-slider .slider-part {
|
||||||
|
|
||||||
width: 5rem
|
width: 5rem
|
||||||
}
|
}
|
||||||
.form-input[data-v-1451da7b] .p-inputtext,
|
.form-input[data-v-a29c257f] .p-inputtext,
|
||||||
.form-input[data-v-1451da7b] .p-select {
|
.form-input[data-v-a29c257f] .p-select {
|
||||||
|
|
||||||
width: 11rem
|
width: 11rem
|
||||||
}
|
}
|
||||||
@@ -4319,26 +4112,26 @@ audio.comfy-audio.empty-audio-widget {
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-v-250ab9af] .p-terminal .xterm {
|
[data-v-873a313f] .p-terminal .xterm {
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
[data-v-250ab9af] .p-terminal .xterm-screen {
|
[data-v-873a313f] .p-terminal .xterm-screen {
|
||||||
background-color: black;
|
background-color: black;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-v-90a7f075] .p-terminal .xterm {
|
[data-v-14fef2e4] .p-terminal .xterm {
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
[data-v-90a7f075] .p-terminal .xterm-screen {
|
[data-v-14fef2e4] .p-terminal .xterm-screen {
|
||||||
background-color: black;
|
background-color: black;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-v-03daf1c8] .p-terminal .xterm {
|
[data-v-cf0c7d52] .p-terminal .xterm {
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
[data-v-03daf1c8] .p-terminal .xterm-screen {
|
[data-v-cf0c7d52] .p-terminal .xterm-screen {
|
||||||
background-color: black;
|
background-color: black;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
}
|
}
|
||||||
@@ -4650,28 +4443,28 @@ audio.comfy-audio.empty-audio-widget {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tree-node[data-v-654109c7] {
|
.tree-node[data-v-a945b5a8] {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
.leaf-count-badge[data-v-654109c7] {
|
.leaf-count-badge[data-v-a945b5a8] {
|
||||||
margin-left: 0.5rem;
|
margin-left: 0.5rem;
|
||||||
}
|
}
|
||||||
.node-content[data-v-654109c7] {
|
.node-content[data-v-a945b5a8] {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
.leaf-label[data-v-654109c7] {
|
.leaf-label[data-v-a945b5a8] {
|
||||||
margin-left: 0.5rem;
|
margin-left: 0.5rem;
|
||||||
}
|
}
|
||||||
[data-v-654109c7] .editable-text span {
|
[data-v-a945b5a8] .editable-text span {
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-v-976a6d58] .tree-explorer-node-label {
|
[data-v-e3a237e6] .tree-explorer-node-label {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -4684,10 +4477,10 @@ audio.comfy-audio.empty-audio-widget {
|
|||||||
* By setting the position to relative on the parent and using an absolutely positioned pseudo-element,
|
* By setting the position to relative on the parent and using an absolutely positioned pseudo-element,
|
||||||
* we can create a visual indicator for the drop target without affecting the layout of other elements.
|
* we can create a visual indicator for the drop target without affecting the layout of other elements.
|
||||||
*/
|
*/
|
||||||
[data-v-976a6d58] .p-tree-node-content:has(.tree-folder) {
|
[data-v-e3a237e6] .p-tree-node-content:has(.tree-folder) {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
[data-v-976a6d58] .p-tree-node-content:has(.tree-folder.can-drop)::after {
|
[data-v-e3a237e6] .p-tree-node-content:has(.tree-folder.can-drop)::after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
@@ -4790,7 +4583,7 @@ audio.comfy-audio.empty-audio-widget {
|
|||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-v-0bb2ac55] .pi-fake-spacer {
|
[data-v-3be51840] .pi-fake-spacer {
|
||||||
height: 1px;
|
height: 1px;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
}
|
}
|
||||||
6
web/assets/index-nJubvliG.js → web/assets/index-CgMyWf7n.js
generated
vendored
6
web/assets/index-nJubvliG.js → web/assets/index-CgMyWf7n.js
generated
vendored
@@ -1,7 +1,7 @@
|
|||||||
var __defProp = Object.defineProperty;
|
var __defProp = Object.defineProperty;
|
||||||
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
||||||
import { bA as BaseStyle, bB as script$s, bZ as script$t, o as openBlock, f as createElementBlock, as as mergeProps, m as createBaseVNode, E as toDisplayString, bS as Ripple, r as resolveDirective, i as withDirectives, y as createBlock, C as resolveDynamicComponent, bi as script$u, bK as resolveComponent, ai as normalizeClass, co as createSlots, z as withCtx, aU as script$v, cf as script$w, F as Fragment, D as renderList, a7 as createTextVNode, c9 as setAttribute, cv as normalizeProps, A as renderSlot, B as createCommentVNode, b_ as script$x, ce as equals, cA as script$y, br as script$z, cE as getFirstFocusableElement, c8 as OverlayEventBus, cU as getVNodeProp, cc as resolveFieldData, ds as invokeElementMethod, bP as getAttribute, cV as getNextElementSibling, c3 as getOuterWidth, cW as getPreviousElementSibling, l as script$A, bR as script$B, bU as script$C, bJ as script$E, cd as isNotEmpty, ar as withModifiers, d5 as getOuterHeight, bT as UniqueComponentId, cY as _default, bC as ZIndex, bE as focus, b$ as addStyle, c4 as absolutePosition, c0 as ConnectedOverlayScrollHandler, c1 as isTouchDevice, dt as FilterOperator, bI as script$F, cs as script$G, bH as FocusTrap, k as createVNode, bL as Transition, bf as withKeys, c6 as getIndex, cu as script$H, cX as isClickable, cZ as clearSelection, ca as localeComparator, cn as sort, cG as FilterService, dl as FilterMatchMode, bO as findSingle, cJ as findIndexInList, c5 as find, du as exportCSV, cR as getOffset, c_ as isRTL, dv as getHiddenElementOuterWidth, dw as getHiddenElementOuterHeight, dx as reorderArray, bW as removeClass, bD as addClass, ci as isEmpty, cH as script$I, ck as script$J } from "./index-4Hb32CNk.js";
|
import { bG as BaseStyle, bH as script$s, bX as script$t, o as openBlock, f as createElementBlock, at as mergeProps, m as createBaseVNode, E as toDisplayString, bO as Ripple, r as resolveDirective, i as withDirectives, y as createBlock, C as resolveDynamicComponent, bm as script$u, bR as resolveComponent, aj as normalizeClass, cp as createSlots, z as withCtx, aY as script$v, cf as script$w, F as Fragment, D as renderList, a8 as createTextVNode, c8 as setAttribute, cx as normalizeProps, A as renderSlot, B as createCommentVNode, bY as script$x, ce as equals, cF as script$y, bv as script$z, cJ as getFirstFocusableElement, c7 as OverlayEventBus, cZ as getVNodeProp, cc as resolveFieldData, dD as invokeElementMethod, bK as getAttribute, c_ as getNextElementSibling, c2 as getOuterWidth, c$ as getPreviousElementSibling, l as script$A, bN as script$B, bQ as script$C, cl as script$E, cd as isNotEmpty, as as withModifiers, da as getOuterHeight, bP as UniqueComponentId, d1 as _default, bZ as ZIndex, bL as focus, b_ as addStyle, c3 as absolutePosition, b$ as ConnectedOverlayScrollHandler, c0 as isTouchDevice, dE as FilterOperator, ca as script$F, ct as script$G, cB as FocusTrap, k as createVNode, bI as Transition, bj as withKeys, c5 as getIndex, cv as script$H, d0 as isClickable, d2 as clearSelection, c9 as localeComparator, co as sort, cL as FilterService, dx as FilterMatchMode, bJ as findSingle, cO as findIndexInList, c4 as find, dF as exportCSV, cW as getOffset, d3 as isRTL, dG as getHiddenElementOuterWidth, dH as getHiddenElementOuterHeight, dI as reorderArray, bT as removeClass, bU as addClass, ci as isEmpty, cM as script$I, ck as script$J } from "./index-Bv0b06LE.js";
|
||||||
import { s as script$D } from "./index-D6zf5KAf.js";
|
import { s as script$D } from "./index-Dzu9WL4p.js";
|
||||||
var ColumnStyle = BaseStyle.extend({
|
var ColumnStyle = BaseStyle.extend({
|
||||||
name: "column"
|
name: "column"
|
||||||
});
|
});
|
||||||
@@ -8787,4 +8787,4 @@ export {
|
|||||||
script as h,
|
script as h,
|
||||||
script$l as s
|
script$l as s
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=index-nJubvliG.js.map
|
//# sourceMappingURL=index-CgMyWf7n.js.map
|
||||||
4
web/assets/index-D6zf5KAf.js → web/assets/index-Dzu9WL4p.js
generated
vendored
4
web/assets/index-D6zf5KAf.js → web/assets/index-Dzu9WL4p.js
generated
vendored
@@ -1,6 +1,6 @@
|
|||||||
var __defProp = Object.defineProperty;
|
var __defProp = Object.defineProperty;
|
||||||
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
||||||
import { bZ as script$1, o as openBlock, f as createElementBlock, as as mergeProps, m as createBaseVNode } from "./index-4Hb32CNk.js";
|
import { bX as script$1, o as openBlock, f as createElementBlock, at as mergeProps, m as createBaseVNode } from "./index-Bv0b06LE.js";
|
||||||
var script = {
|
var script = {
|
||||||
name: "BarsIcon",
|
name: "BarsIcon",
|
||||||
"extends": script$1
|
"extends": script$1
|
||||||
@@ -24,4 +24,4 @@ script.render = render;
|
|||||||
export {
|
export {
|
||||||
script as s
|
script as s
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=index-D6zf5KAf.js.map
|
//# sourceMappingURL=index-Dzu9WL4p.js.map
|
||||||
4
web/assets/index-hkkV7N7e.js → web/assets/index-SeIZOWJp.js
generated
vendored
4
web/assets/index-hkkV7N7e.js → web/assets/index-SeIZOWJp.js
generated
vendored
@@ -1,6 +1,6 @@
|
|||||||
var __defProp = Object.defineProperty;
|
var __defProp = Object.defineProperty;
|
||||||
var __name = (target, value2) => __defProp(target, "name", { value: value2, configurable: true });
|
var __name = (target, value2) => __defProp(target, "name", { value: value2, configurable: true });
|
||||||
import { bA as BaseStyle, bB as script$6, o as openBlock, f as createElementBlock, as as mergeProps, cJ as findIndexInList, c5 as find, bK as resolveComponent, y as createBlock, C as resolveDynamicComponent, z as withCtx, m as createBaseVNode, E as toDisplayString, A as renderSlot, B as createCommentVNode, ai as normalizeClass, bO as findSingle, F as Fragment, bL as Transition, i as withDirectives, v as vShow, bT as UniqueComponentId } from "./index-4Hb32CNk.js";
|
import { bG as BaseStyle, bH as script$6, o as openBlock, f as createElementBlock, at as mergeProps, cO as findIndexInList, c4 as find, bR as resolveComponent, y as createBlock, C as resolveDynamicComponent, z as withCtx, m as createBaseVNode, E as toDisplayString, A as renderSlot, B as createCommentVNode, aj as normalizeClass, bJ as findSingle, F as Fragment, bI as Transition, i as withDirectives, v as vShow, bP as UniqueComponentId } from "./index-Bv0b06LE.js";
|
||||||
var classes$4 = {
|
var classes$4 = {
|
||||||
root: /* @__PURE__ */ __name(function root(_ref) {
|
root: /* @__PURE__ */ __name(function root(_ref) {
|
||||||
var instance = _ref.instance;
|
var instance = _ref.instance;
|
||||||
@@ -536,4 +536,4 @@ export {
|
|||||||
script as d,
|
script as d,
|
||||||
script$4 as s
|
script$4 as s
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=index-hkkV7N7e.js.map
|
//# sourceMappingURL=index-SeIZOWJp.js.map
|
||||||
6
web/assets/keybindingService-BTNdTpfl.js → web/assets/keybindingService-DyjX-nxF.js
generated
vendored
6
web/assets/keybindingService-BTNdTpfl.js → web/assets/keybindingService-DyjX-nxF.js
generated
vendored
@@ -1,6 +1,6 @@
|
|||||||
var __defProp = Object.defineProperty;
|
var __defProp = Object.defineProperty;
|
||||||
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
||||||
import { an as useKeybindingStore, L as useCommandStore, a as useSettingStore, dp as KeyComboImpl, dq as KeybindingImpl } from "./index-4Hb32CNk.js";
|
import { ao as useKeybindingStore, J as useCommandStore, a as useSettingStore, dA as KeyComboImpl, dB as KeybindingImpl } from "./index-Bv0b06LE.js";
|
||||||
const CORE_KEYBINDINGS = [
|
const CORE_KEYBINDINGS = [
|
||||||
{
|
{
|
||||||
combo: {
|
combo: {
|
||||||
@@ -186,7 +186,7 @@ const useKeybindingService = /* @__PURE__ */ __name(() => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const target = event.composedPath()[0];
|
const target = event.composedPath()[0];
|
||||||
if (!keyCombo.hasModifier && (target.tagName === "TEXTAREA" || target.tagName === "INPUT" || target.tagName === "SPAN" && target.classList.contains("property_value"))) {
|
if (keyCombo.isReservedByTextInput && (target.tagName === "TEXTAREA" || target.tagName === "INPUT" || target.tagName === "SPAN" && target.classList.contains("property_value"))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const keybinding = keybindingStore.getKeybinding(keyCombo);
|
const keybinding = keybindingStore.getKeybinding(keyCombo);
|
||||||
@@ -247,4 +247,4 @@ const useKeybindingService = /* @__PURE__ */ __name(() => {
|
|||||||
export {
|
export {
|
||||||
useKeybindingService as u
|
useKeybindingService as u
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=keybindingService-BTNdTpfl.js.map
|
//# sourceMappingURL=keybindingService-DyjX-nxF.js.map
|
||||||
4
web/assets/serverConfigStore-BYbZcbWj.js → web/assets/serverConfigStore-D2Vr0L0h.js
generated
vendored
4
web/assets/serverConfigStore-BYbZcbWj.js → web/assets/serverConfigStore-D2Vr0L0h.js
generated
vendored
@@ -1,6 +1,6 @@
|
|||||||
var __defProp = Object.defineProperty;
|
var __defProp = Object.defineProperty;
|
||||||
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
||||||
import { I as defineStore, U as ref, c as computed } from "./index-4Hb32CNk.js";
|
import { a1 as defineStore, T as ref, c as computed } from "./index-Bv0b06LE.js";
|
||||||
const useServerConfigStore = defineStore("serverConfig", () => {
|
const useServerConfigStore = defineStore("serverConfig", () => {
|
||||||
const serverConfigById = ref({});
|
const serverConfigById = ref({});
|
||||||
const serverConfigs = computed(() => {
|
const serverConfigs = computed(() => {
|
||||||
@@ -87,4 +87,4 @@ const useServerConfigStore = defineStore("serverConfig", () => {
|
|||||||
export {
|
export {
|
||||||
useServerConfigStore as u
|
useServerConfigStore as u
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=serverConfigStore-BYbZcbWj.js.map
|
//# sourceMappingURL=serverConfigStore-D2Vr0L0h.js.map
|
||||||
4
web/index.html
vendored
4
web/index.html
vendored
@@ -6,8 +6,8 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||||
<link rel="stylesheet" type="text/css" href="user.css" />
|
<link rel="stylesheet" type="text/css" href="user.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="materialdesignicons.min.css" />
|
<link rel="stylesheet" type="text/css" href="materialdesignicons.min.css" />
|
||||||
<script type="module" crossorigin src="./assets/index-4Hb32CNk.js"></script>
|
<script type="module" crossorigin src="./assets/index-Bv0b06LE.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="./assets/index-C1Hb_Yo9.css">
|
<link rel="stylesheet" crossorigin href="./assets/index-CBxvvAzM.css">
|
||||||
</head>
|
</head>
|
||||||
<body class="litegraph grid">
|
<body class="litegraph grid">
|
||||||
<div id="vue-app"></div>
|
<div id="vue-app"></div>
|
||||||
|
|||||||
2
web/scripts/domWidget.js
vendored
Normal file
2
web/scripts/domWidget.js
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
// Shim for scripts/domWidget.ts
|
||||||
|
export const DOMWidgetImpl = window.comfyAPI.domWidget.DOMWidgetImpl;
|
||||||
6
web/templates/image2image.json
vendored
6
web/templates/image2image.json
vendored
@@ -330,7 +330,7 @@
|
|||||||
"Node name for S&R": "CheckpointLoaderSimple"
|
"Node name for S&R": "CheckpointLoaderSimple"
|
||||||
},
|
},
|
||||||
"widgets_values": [
|
"widgets_values": [
|
||||||
"v1-5-pruned-emaonly.safetensors"
|
"v1-5-pruned-emaonly-fp16.safetensors"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -440,8 +440,8 @@
|
|||||||
"extra": {},
|
"extra": {},
|
||||||
"version": 0.4,
|
"version": 0.4,
|
||||||
"models": [{
|
"models": [{
|
||||||
"name": "v1-5-pruned-emaonly.safetensors",
|
"name": "v1-5-pruned-emaonly-fp16.safetensors",
|
||||||
"url": "https://huggingface.co/Comfy-Org/stable-diffusion-v1-5-archive/resolve/main/v1-5-pruned-emaonly.safetensors?download=true",
|
"url": "https://huggingface.co/Comfy-Org/stable-diffusion-v1-5-archive/resolve/main/v1-5-pruned-emaonly-fp16.safetensors?download=true",
|
||||||
"directory": "checkpoints"
|
"directory": "checkpoints"
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user