Update ComfyUI and fix tests

This commit is contained in:
doctorpangloss 2024-12-09 17:32:40 -08:00
parent 2d1676c717
commit d989e65fde
96 changed files with 40044 additions and 90631 deletions

1
.gitignore vendored
View File

@ -1,6 +1,7 @@
main.exp
main.lib
main.obj
tests/inference/output/
.DS_Store
/[Oo]utput/
/[Ii]nput/

View File

@ -13,17 +13,19 @@ import sys
import traceback
import urllib
import uuid
from asyncio import AbstractEventLoop, Task
from asyncio import Future, AbstractEventLoop, Task
from enum import Enum
from io import BytesIO
from posixpath import join as urljoin
from typing import List, Optional
from urllib.parse import quote
from urllib.parse import quote, urlencode
import aiofiles
import aiohttp
from PIL import Image
from PIL.PngImagePlugin import PngInfo
from aiohttp import web
from can_ada import URL, parse as urlparse # pylint: disable=no-name-in-module
from typing_extensions import NamedTuple
from .latent_preview_image_encoding import encode_preview_image
@ -35,12 +37,15 @@ from ..api_server.routes.internal.internal_routes import InternalRoutes
from ..app.frontend_management import FrontendManager
from ..app.user_manager import UserManager
from ..cli_args import args
from ..client.client_types import FileOutput
from ..cmd import execution
from ..cmd import folder_paths
from ..component_model.abstract_prompt_queue import AbstractPromptQueue, AsyncAbstractPromptQueue
from ..component_model.executor_types import ExecutorToClientProgress, StatusMessage, QueueInfo, ExecInfo
from ..component_model.file_output_path import file_output_path
from ..component_model.queue_types import QueueItem, BinaryEventTypes
from ..component_model.queue_types import QueueItem, HistoryEntry, BinaryEventTypes, TaskInvocation, ExecutionError, \
ExecutionStatus
from ..digest import digest
from ..images import open_image
from ..model_management import get_torch_device, get_torch_device_name, get_total_memory, get_free_memory, torch_version
from ..nodes.package_typing import ExportedNodes
@ -682,6 +687,248 @@ class PromptServer(ExecutorToClientProgress):
return web.Response(status=200)
# Internal route. Should not be depended upon and is subject to change at any time.
# TODO(robinhuang): Move to internal route table class once we refactor PromptServer to pass around Websocket.
# NOTE: This was an experiment and WILL BE REMOVED
@routes.post("/internal/models/download")
async def download_handler(request):
async def report_progress(filename: str, status: DownloadModelStatus):
payload = status.to_dict()
payload['download_path'] = filename
await self.send_json("download_progress", payload)
data = await request.json()
url = data.get('url')
model_directory = data.get('model_directory')
folder_path = data.get('folder_path')
model_filename = data.get('model_filename')
progress_interval = data.get('progress_interval', 1.0) # In seconds, how often to report download progress.
if not url or not model_directory or not model_filename or not folder_path:
return web.json_response({"status": "error", "message": "Missing URL or folder path or filename"}, status=400)
session = self.client_session
if session is None:
logger.error("Client session is not initialized")
return web.Response(status=500)
task = asyncio.create_task(download_model(lambda url: session.get(url), model_filename, url, model_directory, folder_path, report_progress, progress_interval))
await task
return web.json_response(task.result().to_dict())
@routes.get("/api/v1/prompts/{prompt_id}")
async def get_api_v1_prompts_prompt_id(request: web.Request) -> web.Response | web.FileResponse:
prompt_id: str = request.match_info.get("prompt_id", "")
if prompt_id == "":
return web.json_response(status=404)
history_items = self.prompt_queue.get_history(prompt_id)
if len(history_items) == 0 or prompt_id not in history_items:
# todo: this should really be moved to a stateful queue abstraction
if prompt_id in self.background_tasks:
return web.json_response(status=204)
else:
# todo: this should check a stateful queue abstraction
return web.json_response(status=404)
elif prompt_id in history_items:
history_entry = history_items[prompt_id]
return web.json_response(history_entry["outputs"])
else:
return web.json_response(status=500)
@routes.post("/api/v1/prompts")
async def post_api_prompt(request: web.Request) -> web.Response | web.FileResponse:
accept = request.headers.get("accept", "application/json")
if accept == '*/*':
accept = "application/json"
content_type = request.headers.get("content-type", "application/json")
preferences = request.headers.get("prefer", "") + request.query.get("prefer", "") + " " + content_type
if "+" in content_type:
content_type = content_type.split("+")[0]
wait = not "respond-async" in preferences
if accept not in ("application/json", "image/png"):
return web.json_response(status=400, reason=f"invalid accept content type, expected application/json or image/png, got {accept}")
# check if the queue is too long
queue_size = self.prompt_queue.size()
queue_too_busy_size = PromptServer.get_too_busy_queue_size()
if queue_size > queue_too_busy_size:
return web.json_response(status=429,
reason=f"the queue has {queue_size} elements and {queue_too_busy_size} is the limit for this worker")
# read the request
prompt_dict: dict = {}
if content_type == 'application/json':
prompt_dict = await request.json()
elif content_type == 'multipart/form-data':
try:
reader = await request.multipart()
async for part in reader:
if part is None:
break
if part.headers[aiohttp.hdrs.CONTENT_TYPE] == 'application/json':
prompt_dict = await part.json()
if 'prompt' in prompt_dict:
prompt_dict = prompt_dict['prompt']
elif part.filename:
file_data = await part.read(decode=True)
# overwrite existing files
upload_dir = PromptServer.get_upload_dir()
async with aiofiles.open(os.path.join(upload_dir, part.filename), mode='wb') as file:
await file.write(file_data)
except IOError as ioError:
return web.Response(status=507, reason=str(ioError))
except MemoryError as memoryError:
return web.Response(status=507, reason=str(memoryError))
except Exception as ex:
return web.Response(status=400, reason=str(ex))
if len(prompt_dict) == 0:
return web.Response(status=400, reason="no prompt was specified")
content_digest = digest(prompt_dict)
valid = execution.validate_prompt(prompt_dict)
if not valid[0]:
return web.Response(status=400, content_type="application/json", body=json.dumps(valid[1]))
# convert a valid prompt to the queue tuple this expects
number = self.number
self.number += 1
result: TaskInvocation
completed: Future[TaskInvocation | dict] = self.loop.create_future()
# todo: actually implement idempotency keys
# we would need some kind of more durable, distributed task queue
task_id = str(uuid.uuid4())
item = QueueItem(queue_tuple=(number, task_id, prompt_dict, {}, valid[2]), completed=completed)
try:
if hasattr(self.prompt_queue, "put_async") or isinstance(self.prompt_queue, AsyncAbstractPromptQueue):
# this enables span propagation seamlessly
fut = self.prompt_queue.put_async(item)
if wait:
result = await fut
if result is None:
return web.Response(body="the queue is shutting down", status=503)
else:
return await self._schedule_background_task_with_web_response(fut, task_id)
else:
self.prompt_queue.put(item)
if wait:
await completed
else:
return await self._schedule_background_task_with_web_response(completed, task_id)
task_invocation_or_dict: TaskInvocation | dict = completed.result()
if isinstance(task_invocation_or_dict, dict):
result = TaskInvocation(item_id=item.prompt_id, outputs=task_invocation_or_dict, status=ExecutionStatus("success", True, []))
else:
result = task_invocation_or_dict
except ExecutionError as exec_exc:
result = exec_exc.as_task_invocation()
except Exception as ex:
return web.Response(body=str(ex), status=500)
if result.status is not None and result.status.status_str == "error":
return web.Response(body=json.dumps(result.status._asdict()), status=500, content_type="application/json")
# find images and read them
output_images: List[FileOutput] = []
for node_id, node in result.outputs.items():
images: List[FileOutput] = []
if 'images' in node:
images = node['images']
# todo: does this ever occur?
elif (isinstance(node, dict)
and 'ui' in node and isinstance(node['ui'], dict)
and 'images' in node['ui']):
images = node['ui']['images']
for image_tuple in images:
output_images.append(image_tuple)
if len(output_images) > 0:
main_image = output_images[0]
filename = main_image["filename"]
digest_headers_ = {
"Digest": f"SHA-256={content_digest}",
}
urls_ = []
if len(output_images) == 1:
digest_headers_.update({
"Content-Disposition": f"filename=\"{filename}\""
})
for image_indv_ in output_images:
local_address = f"http://{self.address}:{self.port}"
external_address = self.external_address
for base in (local_address, external_address):
try:
url: URL = urlparse(urljoin(base, "view"))
except ValueError:
continue
url_search_dict: FileOutput = dict(image_indv_)
del url_search_dict["abs_path"]
if "name" in url_search_dict:
del url_search_dict["name"]
if url_search_dict["subfolder"] == "":
del url_search_dict["subfolder"]
url.search = f"?{urlencode(url_search_dict)}"
urls_.append(str(url))
if accept == "application/json":
return web.Response(status=200,
content_type="application/json",
headers=digest_headers_,
body=json.dumps({
'urls': urls_,
'outputs': result.outputs
}))
elif accept == "image/png" or accept == "image/jpeg":
return web.FileResponse(main_image["abs_path"],
headers=digest_headers_)
else:
return web.Response(status=500,
reason="unreachable")
else:
return web.Response(status=204)
@routes.get("/api/v1/prompts")
async def get_api_prompt(_: web.Request) -> web.Response:
history = self.prompt_queue.get_history()
history_items = list(history.values())
if len(history_items) == 0:
return web.Response(status=404)
last_history_item: HistoryEntry = history_items[-1]
prompt = last_history_item['prompt'][2]
return web.json_response(prompt, status=200)
async def _schedule_background_task_with_web_response(self, fut, task_id):
task = asyncio.create_task(fut, name=task_id)
self.background_tasks[task_id] = task
task.add_done_callback(lambda _: self.background_tasks.pop(task_id))
# todo: type this from the OpenAPI spec
return web.json_response({
"prompt_id": task_id
}, status=202, headers={
"Location": f"api/v1/prompts/{task_id}",
"Retry-After": "60"
})
@property
def external_address(self):
return self._external_address if self._external_address is not None else f"http://{'localhost' if self.address == '0.0.0.0' else self.address}:{self.port}"
@external_address.setter
def external_address(self, value):
self._external_address = value
@property
def receive_all_progress_notifications(self) -> bool:
return True
async def setup(self):
timeout = aiohttp.ClientTimeout(total=None) # no timeout
self.client_session = aiohttp.ClientSession(timeout=timeout)

View File

@ -1,24 +1,32 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Callable
import enum
import math
import torch
import numpy as np
import itertools
import logging
import math
from typing import Callable, Any, TYPE_CHECKING
import numpy as np
import torch
from .lora import model_lora_keys_unet, model_lora_keys_clip, load_lora
from .lora_types import PatchDict
from .model_base import BaseModel
from .node_helpers import conditioning_set_values
from .patcher_extension import merge_nested_dicts
logger = logging.getLogger(__name__)
if TYPE_CHECKING:
from comfy.model_patcher import ModelPatcher, PatcherInjection
from comfy.model_base import BaseModel
from comfy.sd import CLIP
import comfy.lora
import comfy.model_management
import comfy.patcher_extension
from node_helpers import conditioning_set_values
from .model_patcher import ModelPatcher, PatcherInjection
from .sd import CLIP
class EnumHookMode(enum.Enum):
MinVram = "minvram"
MaxSpeed = "maxspeed"
class EnumHookType(enum.Enum):
Weight = "weight"
Patch = "patch"
@ -28,21 +36,24 @@ class EnumHookType(enum.Enum):
Wrappers = "wrappers"
SetInjections = "add_injections"
class EnumWeightTarget(enum.Enum):
Model = "model"
Clip = "clip"
class _HookRef:
pass
# NOTE: this is an example of how the should_register function should look
def default_should_register(hook: 'Hook', model: 'ModelPatcher', model_options: dict, target: EnumWeightTarget, registered: list[Hook]):
return True
class Hook:
def __init__(self, hook_type: EnumHookType=None, hook_ref: _HookRef=None, hook_id: str=None,
hook_keyframe: 'HookKeyframeGroup'=None):
def __init__(self, hook_type: EnumHookType = None, hook_ref: _HookRef = None, hook_id: str = None,
hook_keyframe: 'HookKeyframeGroup' = None):
self.hook_type = hook_type
self.hook_ref = hook_ref if hook_ref else _HookRef()
self.hook_id = hook_id
@ -61,7 +72,7 @@ class Hook:
def reset(self):
self.hook_keyframe.reset()
def clone(self, subtype: Callable=None):
def clone(self, subtype: Callable = None):
if subtype is None:
subtype = type(self)
c: Hook = subtype()
@ -92,6 +103,7 @@ class Hook:
def __hash__(self):
return hash(self.hook_ref)
class WeightHook(Hook):
def __init__(self, strength_model=1.0, strength_clip=1.0):
super().__init__(hook_type=EnumHookType.Weight)
@ -100,11 +112,11 @@ class WeightHook(Hook):
self.need_weight_init = True
self._strength_model = strength_model
self._strength_clip = strength_clip
@property
def strength_model(self):
return self._strength_model * self.strength
@property
def strength_clip(self):
return self._strength_clip * self.strength
@ -117,14 +129,14 @@ class WeightHook(Hook):
strength = self._strength_model
else:
strength = self._strength_clip
if self.need_weight_init:
key_map = {}
if target == EnumWeightTarget.Model:
key_map = comfy.lora.model_lora_keys_unet(model.model, key_map)
key_map = model_lora_keys_unet(model.model, key_map)
else:
key_map = comfy.lora.model_lora_keys_clip(model.model, key_map)
weights = comfy.lora.load_lora(self.weights, key_map, log_missing=False)
key_map = model_lora_keys_clip(model.model, key_map)
weights = load_lora(self.weights, key_map, log_missing=False)
else:
if target == EnumWeightTarget.Model:
weights = self.weights
@ -135,7 +147,7 @@ class WeightHook(Hook):
return True
# TODO: add logs about any keys that were not applied
def clone(self, subtype: Callable=None):
def clone(self, subtype: Callable = None):
if subtype is None:
subtype = type(self)
c: WeightHook = super().clone(subtype)
@ -146,12 +158,13 @@ class WeightHook(Hook):
c._strength_clip = self._strength_clip
return c
class PatchHook(Hook):
def __init__(self):
super().__init__(hook_type=EnumHookType.Patch)
self.patches: dict = None
def clone(self, subtype: Callable=None):
def clone(self, subtype: Callable = None):
if subtype is None:
subtype = type(self)
c: PatchHook = super().clone(subtype)
@ -159,12 +172,13 @@ class PatchHook(Hook):
return c
# TODO: add functionality
class ObjectPatchHook(Hook):
def __init__(self):
super().__init__(hook_type=EnumHookType.ObjectPatch)
self.object_patches: dict = None
def clone(self, subtype: Callable=None):
def clone(self, subtype: Callable = None):
if subtype is None:
subtype = type(self)
c: ObjectPatchHook = super().clone(subtype)
@ -172,14 +186,15 @@ class ObjectPatchHook(Hook):
return c
# TODO: add functionality
class AddModelsHook(Hook):
def __init__(self, key: str=None, models: list['ModelPatcher']=None):
def __init__(self, key: str = None, models: list['ModelPatcher'] = None):
super().__init__(hook_type=EnumHookType.AddModels)
self.key = key
self.models = models
self.append_when_same = True
def clone(self, subtype: Callable=None):
def clone(self, subtype: Callable = None):
if subtype is None:
subtype = type(self)
c: AddModelsHook = super().clone(subtype)
@ -189,13 +204,14 @@ class AddModelsHook(Hook):
return c
# TODO: add functionality
class CallbackHook(Hook):
def __init__(self, key: str=None, callback: Callable=None):
def __init__(self, key: str = None, callback: Callable = None):
super().__init__(hook_type=EnumHookType.Callbacks)
self.key = key
self.callback = callback
def clone(self, subtype: Callable=None):
def clone(self, subtype: Callable = None):
if subtype is None:
subtype = type(self)
c: CallbackHook = super().clone(subtype)
@ -204,44 +220,47 @@ class CallbackHook(Hook):
return c
# TODO: add functionality
class WrapperHook(Hook):
def __init__(self, wrappers_dict: dict[str, dict[str, dict[str, list[Callable]]]]=None):
def __init__(self, wrappers_dict: dict[str, dict[str, dict[str, list[Callable]]]] = None):
super().__init__(hook_type=EnumHookType.Wrappers)
self.wrappers_dict = wrappers_dict
def clone(self, subtype: Callable=None):
def clone(self, subtype: Callable = None):
if subtype is None:
subtype = type(self)
c: WrapperHook = super().clone(subtype)
c.wrappers_dict = self.wrappers_dict
return c
def add_hook_patches(self, model: 'ModelPatcher', model_options: dict, target: EnumWeightTarget, registered: list[Hook]):
if not self.should_register(model, model_options, target, registered):
return False
add_model_options = {"transformer_options": self.wrappers_dict}
comfy.patcher_extension.merge_nested_dicts(model_options, add_model_options, copy_dict1=False)
merge_nested_dicts(model_options, add_model_options, copy_dict1=False)
registered.append(self)
return True
class SetInjectionsHook(Hook):
def __init__(self, key: str=None, injections: list['PatcherInjection']=None):
def __init__(self, key: str = None, injections: list['PatcherInjection'] = None):
super().__init__(hook_type=EnumHookType.SetInjections)
self.key = key
self.injections = injections
def clone(self, subtype: Callable=None):
def clone(self, subtype: Callable = None):
if subtype is None:
subtype = type(self)
c: SetInjectionsHook = super().clone(subtype)
c.key = self.key
c.injections = self.injections.copy() if self.injections else self.injections
return c
def add_hook_injections(self, model: 'ModelPatcher'):
# TODO: add functionality
pass
class HookGroup:
def __init__(self):
self.hooks: list[Hook] = []
@ -249,10 +268,10 @@ class HookGroup:
def add(self, hook: Hook):
if hook not in self.hooks:
self.hooks.append(hook)
def contains(self, hook: Hook):
return hook in self.hooks
def clone(self):
c = HookGroup()
for hook in self.hooks:
@ -265,7 +284,7 @@ class HookGroup:
for hook in other.hooks:
c.add(hook.clone())
return c
def set_keyframes_on_hooks(self, hook_kf: 'HookKeyframeGroup'):
if hook_kf is None:
hook_kf = HookKeyframeGroup()
@ -282,7 +301,7 @@ class HookGroup:
return d
def get_hooks_for_clip_schedule(self):
scheduled_hooks: dict[WeightHook, list[tuple[tuple[float,float], HookKeyframe]]] = {}
scheduled_hooks: dict[WeightHook, list[tuple[tuple[float, float], HookKeyframe]]] = {}
for hook in self.hooks:
# only care about WeightHooks, for now
if hook.hook_type == EnumHookType.Weight:
@ -315,7 +334,7 @@ class HookGroup:
boundaries = sorted(boundaries_set)
real_ranges = [(boundaries[i], boundaries[i + 1]) for i in range(len(boundaries) - 1)]
# with real ranges defined, give appropriate hooks w/ keyframes for each range
scheduled_keyframes: list[tuple[tuple[float,float], list[tuple[WeightHook, HookKeyframe]]]] = []
scheduled_keyframes: list[tuple[tuple[float, float], list[tuple[WeightHook, HookKeyframe]]]] = []
for t_range in real_ranges:
hooks_schedule = []
for hook, val in scheduled_hooks.items():
@ -364,13 +383,14 @@ class HookKeyframe:
self.start_percent = float(start_percent)
self.start_t = 999999999.9
self.guarantee_steps = guarantee_steps
def clone(self):
c = HookKeyframe(strength=self.strength,
start_percent=self.start_percent, guarantee_steps=self.guarantee_steps)
start_percent=self.start_percent, guarantee_steps=self.guarantee_steps)
c.start_t = self.start_t
return c
class HookKeyframeGroup:
def __init__(self):
self.keyframes: list[HookKeyframe] = []
@ -394,7 +414,7 @@ class HookKeyframeGroup:
self._current_strength = None
self.curr_t = -1.
self._set_first_as_current()
def add(self, keyframe: HookKeyframe):
# add to end of list, then sort
self.keyframes.append(keyframe)
@ -406,20 +426,20 @@ class HookKeyframeGroup:
self._current_keyframe = self.keyframes[0]
else:
self._current_keyframe = None
def has_index(self, index: int):
return index >= 0 and index < len(self.keyframes)
def is_empty(self):
return len(self.keyframes) == 0
def clone(self):
c = HookKeyframeGroup()
for keyframe in self.keyframes:
c.keyframes.append(keyframe.clone())
c._set_first_as_current()
return c
def initialize_timesteps(self, model: 'BaseModel'):
for keyframe in self.keyframes:
keyframe.start_t = model.model_sampling.percent_to_sigma(keyframe.start_percent)
@ -434,8 +454,8 @@ class HookKeyframeGroup:
# if met guaranteed steps, look for next keyframe in case need to switch
if self._current_used_steps >= self._current_keyframe.guarantee_steps:
# if has next index, loop through and see if need to switch
if self.has_index(self._current_index+1):
for i in range(self._current_index+1, len(self.keyframes)):
if self.has_index(self._current_index + 1):
for i in range(self._current_index + 1, len(self.keyframes)):
eval_c = self.keyframes[i]
# check if start_t is greater or equal to curr_t
# NOTE: t is in terms of sigmas, not percent, so bigger number = earlier step in sampling
@ -448,7 +468,8 @@ class HookKeyframeGroup:
if self._current_keyframe.guarantee_steps > 0:
break
# if eval_c is outside the percent range, stop looking further
else: break
else:
break
# update steps current context is used
self._current_used_steps += 1
# update current timestep this was performed on
@ -485,6 +506,7 @@ class InterpolationMethod:
weights = weights.flip(dims=(0,))
return weights
def get_sorted_list_via_attr(objects: list, attr: str) -> list:
if not objects:
return objects
@ -508,6 +530,7 @@ def get_sorted_list_via_attr(objects: list, attr: str) -> list:
sorted_list.extend(object_list)
return sorted_list
def create_hook_lora(lora: dict[str, torch.Tensor], strength_model: float, strength_clip: float):
hook_group = HookGroup()
hook = WeightHook(strength_model=strength_model, strength_clip=strength_clip)
@ -515,6 +538,7 @@ def create_hook_lora(lora: dict[str, torch.Tensor], strength_model: float, stren
hook.weights = lora
return hook_group
def create_hook_model_as_lora(weights_model, weights_clip, strength_model: float, strength_clip: float):
hook_group = HookGroup()
hook = WeightHook(strength_model=strength_model, strength_clip=strength_clip)
@ -534,6 +558,7 @@ def create_hook_model_as_lora(weights_model, weights_clip, strength_model: float
hook.need_weight_init = False
return hook_group
def get_patch_weights_from_model(model: 'ModelPatcher', discard_model_sampling=True):
if model is None:
return None
@ -545,26 +570,27 @@ def get_patch_weights_from_model(model: 'ModelPatcher', discard_model_sampling=T
patches_model.pop(key, None)
return patches_model
# NOTE: this function shows how to register weight hooks directly on the ModelPatchers
def load_hook_lora_for_models(model: 'ModelPatcher', clip: 'CLIP', lora: dict[str, torch.Tensor],
strength_model: float, strength_clip: float):
key_map = {}
if model is not None:
key_map = comfy.lora.model_lora_keys_unet(model.model, key_map)
key_map = model_lora_keys_unet(model.model, key_map)
if clip is not None:
key_map = comfy.lora.model_lora_keys_clip(clip.cond_stage_model, key_map)
key_map = model_lora_keys_clip(clip.cond_stage_model, key_map)
hook_group = HookGroup()
hook = WeightHook()
hook_group.add(hook)
loaded: dict[str] = comfy.lora.load_lora(lora, key_map)
loaded: PatchDict = load_lora(lora, key_map)
if model is not None:
new_modelpatcher = model.clone()
k = new_modelpatcher.add_hook_patches(hook=hook, patches=loaded, strength_patch=strength_model)
else:
k = ()
new_modelpatcher = None
if clip is not None:
new_clip = clip.clone()
k1 = new_clip.patcher.add_hook_patches(hook=hook, patches=loaded, strength_patch=strength_clip)
@ -575,9 +601,10 @@ def load_hook_lora_for_models(model: 'ModelPatcher', clip: 'CLIP', lora: dict[st
k1 = set(k1)
for x in loaded:
if (x not in k) and (x not in k1):
print(f"NOT LOADED {x}")
logger.warning(f"NOT LOADED {x}")
return (new_modelpatcher, new_clip, hook_group)
def _combine_hooks_from_values(c_dict: dict[str, HookGroup], values: dict[str, HookGroup], cache: dict[tuple[HookGroup, HookGroup], HookGroup]):
hooks_key = 'hooks'
# if hooks only exist in one dict, do what's needed so that it ends up in c_dict
@ -598,6 +625,7 @@ def _combine_hooks_from_values(c_dict: dict[str, HookGroup], values: dict[str, H
else:
c_dict[hooks_key] = cache[hooks_tuple]
def conditioning_set_values_with_hooks(conditioning, values={}, append_hooks=True):
c = []
hooks_combine_cache: dict[tuple[HookGroup, HookGroup], HookGroup] = {}
@ -612,17 +640,20 @@ def conditioning_set_values_with_hooks(conditioning, values={}, append_hooks=Tru
return c
def set_hooks_for_conditioning(cond, hooks: HookGroup, append_hooks=True):
if hooks is None:
return cond
return conditioning_set_values_with_hooks(cond, {'hooks': hooks}, append_hooks=append_hooks)
def set_timesteps_for_conditioning(cond, timestep_range: tuple[float,float]):
def set_timesteps_for_conditioning(cond, timestep_range: tuple[float, float]):
if timestep_range is None:
return cond
return conditioning_set_values(cond, {"start_percent": timestep_range[0],
"end_percent": timestep_range[1]})
def set_mask_for_conditioning(cond, mask: torch.Tensor, set_cond_area: str, strength: float):
if mask is None:
return cond
@ -635,20 +666,23 @@ def set_mask_for_conditioning(cond, mask: torch.Tensor, set_cond_area: str, stre
'set_area_to_bounds': set_area_to_bounds,
'mask_strength': strength})
def combine_conditioning(conds: list):
combined_conds = []
for cond in conds:
combined_conds.extend(cond)
return combined_conds
def combine_with_new_conds(conds: list, new_conds: list):
combined_conds = []
for c, new_c in zip(conds, new_conds):
combined_conds.append(combine_conditioning([c, new_c]))
return combined_conds
def set_conds_props(conds: list, strength: float, set_cond_area: str,
mask: torch.Tensor=None, hooks: HookGroup=None, timesteps_range: tuple[float,float]=None, append_hooks=True):
mask: torch.Tensor = None, hooks: HookGroup = None, timesteps_range: tuple[float, float] = None, append_hooks=True):
final_conds = []
for c in conds:
# first, apply lora_hook to conditioning, if provided
@ -661,8 +695,9 @@ def set_conds_props(conds: list, strength: float, set_cond_area: str,
final_conds.append(c)
return final_conds
def set_conds_props_and_combine(conds: list, new_conds: list, strength: float=1.0, set_cond_area: str="default",
mask: torch.Tensor=None, hooks: HookGroup=None, timesteps_range: tuple[float,float]=None, append_hooks=True):
def set_conds_props_and_combine(conds: list, new_conds: list, strength: float = 1.0, set_cond_area: str = "default",
mask: torch.Tensor = None, hooks: HookGroup = None, timesteps_range: tuple[float, float] = None, append_hooks=True):
combined_conds = []
for c, masked_c in zip(conds, new_conds):
# first, apply lora_hook to new conditioning, if provided
@ -675,8 +710,9 @@ def set_conds_props_and_combine(conds: list, new_conds: list, strength: float=1.
combined_conds.append(combine_conditioning([c, masked_c]))
return combined_conds
def set_default_conds_and_combine(conds: list, new_conds: list,
hooks: HookGroup=None, timesteps_range: tuple[float,float]=None, append_hooks=True):
hooks: HookGroup = None, timesteps_range: tuple[float, float] = None, append_hooks=True):
combined_conds = []
for c, new_c in zip(conds, new_conds):
# first, apply lora_hook to new conditioning, if provided

View File

@ -286,7 +286,7 @@ def sample_dpm_2(model, x, sigmas, extra_args=None, callback=None, disable=None,
@torch.no_grad()
def sample_dpm_2_ancestral(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None):
if isinstance(model.inner_model.inner_model.model_sampling, comfy.model_sampling.CONST):
if isinstance(model.inner_model.inner_model.model_sampling, model_sampling.CONST):
return sample_dpm_2_ancestral_RF(model, x, sigmas, extra_args, callback, disable, eta, s_noise, noise_sampler)
"""Ancestral sampling with DPM-Solver second-order steps."""

View File

@ -7,7 +7,7 @@ import torch
PatchOffset = tuple[int, int, int]
PatchFunction = Any
PatchDictKey = str | tuple[str, PatchOffset] | tuple[str, PatchOffset, PatchFunction]
PatchType = Literal["lora", "loha", "lokr", "glora", "diff", ""]
PatchType = Literal["lora", "loha", "lokr", "glora", "diff", "set", ""]
PatchDictValue = tuple[PatchType, tuple]
PatchDict = dict[PatchDictKey, PatchDictValue]

View File

@ -291,6 +291,7 @@ KNOWN_LORAS: Final[KnownDownloadables] = KnownDownloadables([
CivitFile(model_id=211577, model_version_id=238349, filename="openxl_handsfix.safetensors"),
CivitFile(model_id=324815, model_version_id=364137, filename="blur_control_xl_v1.safetensors"),
CivitFile(model_id=47085, model_version_id=55199, filename="GoodHands-beta2.safetensors"),
HuggingFile("artificialguybr/pixelartredmond-1-5v-pixel-art-loras-for-sd-1-5", "PixelArtRedmond15V-PixelArt-PIXARFK.safetensors"),
HuggingFile("ByteDance/Hyper-SD", "Hyper-SDXL-12steps-CFG-lora.safetensors"),
HuggingFile("ByteDance/Hyper-SD", "Hyper-SD15-12steps-CFG-lora.safetensors"),
HuggingFile("black-forest-labs/FLUX.1-Canny-dev-lora", "flux1-canny-dev-lora.safetensors"),

View File

@ -29,13 +29,13 @@ import torch
import torch.nn
from humanize import naturalsize
from . import hooks
from . import model_management, lora
from . import patcher_extension
from . import utils
from .component_model.deprecation import _deprecate_method
from .comfy_types import UnetWrapperFunction
from .float import stochastic_rounding
from .hooks import EnumHookMode, _HookRef, HookGroup, EnumHookType, Hook, WeightHook, EnumWeightTarget
from .lora_types import PatchDict, PatchDictKey, PatchTuple, PatchWeightTuple, ModelPatchesDictValue
from .model_base import BaseModel
from .model_management_types import ModelManageable, MemoryMeasurements, ModelOptions
@ -224,14 +224,14 @@ class ModelPatcher(ModelManageable):
self.skip_injection = False
self.injections: dict[str, list[PatcherInjection]] = {}
self.hook_patches: dict[hooks._HookRef] = {}
self.hook_patches_backup: dict[hooks._HookRef] = {}
self.hook_patches: dict[_HookRef] = {}
self.hook_patches_backup: dict[_HookRef] = {}
self.hook_backup: dict[str, tuple[torch.Tensor, torch.device]] = {}
self.cached_hook_patches: dict[hooks.HookGroup, dict[str, torch.Tensor]] = {}
self.current_hooks: Optional[hooks.HookGroup] = None
self.forced_hooks: Optional[hooks.HookGroup] = None # NOTE: only used for CLIP at this time
self.cached_hook_patches: dict[HookGroup, dict[str, torch.Tensor | tuple[torch.Tensor, torch.device]]] = {}
self.current_hooks: Optional[HookGroup] = None
self.forced_hooks: Optional[HookGroup] = None # NOTE: only used for CLIP at this time
self.is_clip = False
self.hook_mode = hooks.EnumHookMode.MaxSpeed
self.hook_mode = EnumHookMode.MaxSpeed
@property
def model_options(self) -> ModelOptions:
@ -980,10 +980,10 @@ class ModelPatcher(ModelManageable):
self.hook_patches = self.hook_patches_backup
self.hook_patches_backup = {}
def set_hook_mode(self, hook_mode: hooks.EnumHookMode):
def set_hook_mode(self, hook_mode: EnumHookMode):
self.hook_mode = hook_mode
def prepare_hook_patches_current_keyframe(self, t: torch.Tensor, hook_group: hooks.HookGroup):
def prepare_hook_patches_current_keyframe(self, t: torch.Tensor, hook_group: HookGroup):
curr_t = t[0]
reset_current_hooks = False
for hook in hook_group.hooks:
@ -1003,16 +1003,16 @@ class ModelPatcher(ModelManageable):
if reset_current_hooks:
self.patch_hooks(None)
def register_all_hook_patches(self, hooks_dict: dict[hooks.EnumHookType, dict[hooks.Hook, None]], target: hooks.EnumWeightTarget, model_options: dict = None):
def register_all_hook_patches(self, hooks_dict: dict[EnumHookType, dict[Hook, None]], target: EnumWeightTarget, model_options: dict = None):
self.restore_hook_patches()
registered_hooks: list[hooks.Hook] = []
registered_hooks: list[Hook] = []
# handle WrapperHooks, if model_options provided
if model_options is not None:
for hook in hooks_dict.get(hooks.EnumHookType.Wrappers, {}):
for hook in hooks_dict.get(EnumHookType.Wrappers, {}):
hook.add_hook_patches(self, model_options, target, registered_hooks)
# handle WeightHooks
weight_hooks_to_register: list[hooks.WeightHook] = []
for hook in hooks_dict.get(hooks.EnumHookType.Weight, {}):
weight_hooks_to_register: list[WeightHook] = []
for hook in hooks_dict.get(EnumHookType.Weight, {}):
if hook.hook_ref not in self.hook_patches:
weight_hooks_to_register.append(hook)
if len(weight_hooks_to_register) > 0:
@ -1023,7 +1023,7 @@ class ModelPatcher(ModelManageable):
for callback in self.get_all_callbacks(CallbacksMP.ON_REGISTER_ALL_HOOK_PATCHES):
callback(self, hooks_dict, target)
def add_hook_patches(self, hook: hooks.WeightHook, patches, strength_patch=1.0, strength_model=1.0):
def add_hook_patches(self, hook: WeightHook, patches, strength_patch=1.0, strength_model=1.0):
with self.use_ejected():
# NOTE: this mirrors behavior of add_patches func
current_hook_patches: dict[str, list] = self.hook_patches.get(hook.hook_ref, {})
@ -1050,7 +1050,7 @@ class ModelPatcher(ModelManageable):
self.patches_uuid = uuid.uuid4()
return list(p)
def get_combined_hook_patches(self, hooks: hooks.HookGroup):
def get_combined_hook_patches(self, hooks: HookGroup):
# combined_patches will contain weights of all relevant hooks, per key
combined_patches = {}
if hooks is not None:
@ -1069,7 +1069,7 @@ class ModelPatcher(ModelManageable):
combined_patches[key] = current_patches
return combined_patches
def apply_hooks(self, hooks: hooks.HookGroup, transformer_options: dict = None, force_apply=False):
def apply_hooks(self, hooks: HookGroup, transformer_options: dict = None, force_apply=False):
# TODO: return transformer_options dict with any additions from hooks
if self.current_hooks == hooks and (not force_apply or (not self.is_clip and hooks is None)):
return {}
@ -1078,13 +1078,13 @@ class ModelPatcher(ModelManageable):
callback(self, hooks)
return {}
def patch_hooks(self, hooks: hooks.HookGroup):
def patch_hooks(self, hooks: HookGroup | None):
with self.use_ejected():
self.unpatch_hooks()
if hooks is not None:
model_sd_keys = list(self.model_state_dict().keys())
memory_counter = None
if self.hook_mode == hooks.EnumHookMode.MaxSpeed:
if self.hook_mode == EnumHookMode.MaxSpeed:
# TODO: minimum_counter should have a minimum that conforms to loaded model requirements
memory_counter = MemoryCounter(initial=model_management.get_free_memory(self.load_device),
minimum=model_management.minimum_inference_memory() * 2)
@ -1113,7 +1113,7 @@ class ModelPatcher(ModelManageable):
if key not in self.hook_backup:
weight: torch.Tensor = utils.get_attr(self.model, key)
target_device = self.offload_device
if self.hook_mode == hooks.EnumHookMode.MaxSpeed:
if self.hook_mode == EnumHookMode.MaxSpeed:
used = memory_counter.use(weight)
if used:
target_device = weight.device
@ -1124,7 +1124,7 @@ class ModelPatcher(ModelManageable):
self.cached_hook_patches.clear()
self.patch_hooks(None)
def patch_hook_weight_to_device(self, hooks: hooks.HookGroup, combined_patches: dict, key: str, original_weights: dict, memory_counter: MemoryCounter):
def patch_hook_weight_to_device(self, hooks: HookGroup, combined_patches: dict, key: str, original_weights: dict, memory_counter: MemoryCounter):
if key not in combined_patches:
return
@ -1132,7 +1132,7 @@ class ModelPatcher(ModelManageable):
weight: torch.Tensor
if key not in self.hook_backup:
target_device = self.offload_device
if self.hook_mode == hooks.EnumHookMode.MaxSpeed:
if self.hook_mode == EnumHookMode.MaxSpeed:
used = memory_counter.use(weight)
if used:
target_device = weight.device
@ -1151,7 +1151,7 @@ class ModelPatcher(ModelManageable):
utils.copy_to_param(self.model, key, out_weight)
else:
set_func(out_weight, inplace_update=True, seed=string_to_seed(key))
if self.hook_mode == hooks.EnumHookMode.MaxSpeed:
if self.hook_mode == EnumHookMode.MaxSpeed:
# TODO: disable caching if not enough system RAM to do so
target_device = self.offload_device
used = memory_counter.use(weight)

View File

@ -1003,14 +1003,16 @@ class CLIPVisionEncode:
def INPUT_TYPES(s):
return {"required": { "clip_vision": ("CLIP_VISION",),
"image": ("IMAGE",),
"crop": (["center", "none"],)
}}
},
"optional": {
"crop": (["center", "none"], {"default": "center"})
}}
RETURN_TYPES = ("CLIP_VISION_OUTPUT",)
FUNCTION = "encode"
CATEGORY = "conditioning"
def encode(self, clip_vision, image, crop):
def encode(self, clip_vision, image, crop="center"):
crop_image = True
if crop != "center":
crop_image = False
@ -1040,14 +1042,16 @@ class StyleModelApply:
"style_model": ("STYLE_MODEL", ),
"clip_vision_output": ("CLIP_VISION_OUTPUT", ),
"strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.001}),
"strength_type": (["multiply"], ),
},
"optional": {
"strength_type": (["multiply"], {"default": "multiply"}),
}}
RETURN_TYPES = ("CONDITIONING",)
FUNCTION = "apply_stylemodel"
CATEGORY = "conditioning/style_model"
def apply_stylemodel(self, clip_vision_output, style_model, conditioning, strength, strength_type):
def apply_stylemodel(self, clip_vision_output, style_model, conditioning, strength=1.0, strength_type="multiply"):
cond = style_model.get_cond(clip_vision_output).flatten(start_dim=0, end_dim=1).unsqueeze(dim=0)
if strength_type == "multiply":
cond *= strength

View File

@ -1,11 +1,11 @@
import numpy as np
import torch
from . import model_management
from . import samplers
from . import utils
from . import conds
import math
import numpy as np
import logging
from .component_model.deprecation import _deprecate_method
def prepare_noise(latent_image, seed, noise_inds=None):
"""
@ -32,12 +32,14 @@ def fix_empty_latent_channels(model, latent_image):
latent_image = utils.repeat_to_batch_size(latent_image, latent_channels, dim=1)
return latent_image
@_deprecate_method(version="0.3.2", message="Warning: comfy.sample.prepare_sampling isn't used anymore and can be removed")
def prepare_sampling(model, noise_shape, positive, negative, noise_mask):
logging.warning("Warning: comfy.sample.prepare_sampling isn't used anymore and can be removed")
pass
return model, positive, negative, noise_mask, []
@_deprecate_method(version="0.3.2", message="Warning: comfy.sample.cleanup_additional_models isn't used anymore and can be removed")
def cleanup_additional_models(models):
logging.warning("Warning: comfy.sample.cleanup_additional_models isn't used anymore and can be removed")
pass
def sample(model, noise, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise=1.0, disable_noise=False, start_step=None, last_step=None, force_full_denoise=False, noise_mask=None, sigmas=None, callback=None, disable_pbar=False, seed=None):
sampler = samplers.KSampler(model, steps=steps, device=model.load_device, sampler=sampler_name, scheduler=scheduler, denoise=denoise, model_options=model.model_options)

View File

@ -2,10 +2,10 @@ import uuid
from .controlnet import ControlBase
from . import conds
from . import hooks
from . import model_management
from . import patcher_extension
from . import utils
from .hooks import EnumHookType, EnumWeightTarget, HookGroup, Hook
from .model_base import BaseModel
from .model_patcher import ModelPatcher
@ -25,13 +25,13 @@ def get_models_from_cond(cond, model_type):
return models
def get_hooks_from_cond(cond, hooks_dict: dict[hooks.EnumHookType, dict[hooks.Hook, None]]):
def get_hooks_from_cond(cond, hooks_dict: dict[EnumHookType, dict[Hook, None]]):
# get hooks from conds, and collect cnets so they can be checked for extra_hooks
cnets: list[ControlBase] = []
for c in cond:
if 'hooks' in c:
for hook in c['hooks'].hooks:
hook: hooks.Hook
hook: Hook
with_type = hooks_dict.setdefault(hook.hook_type, {})
with_type[hook] = None
if 'control' in c:
@ -48,7 +48,7 @@ def get_hooks_from_cond(cond, hooks_dict: dict[hooks.EnumHookType, dict[hooks.Ho
cnets = set(cnets)
for base_cnet in cnets:
get_extra_hooks_from_cnet(base_cnet, hooks_list)
extra_hooks = hooks.HookGroup.combine_all_hooks(hooks_list)
extra_hooks = HookGroup.combine_all_hooks(hooks_list)
if extra_hooks is not None:
for hook in extra_hooks.hooks:
with_type = hooks_dict.setdefault(hook.hook_type, {})
@ -76,7 +76,7 @@ def get_additional_models(conds, dtype):
cnets: list[ControlBase] = []
gligen = []
add_models = []
hooks: dict[hooks.EnumHookType, dict[hooks.Hook, None]] = {}
hooks: dict[EnumHookType, dict[Hook, None]] = {}
for k in conds:
cnets += get_models_from_cond(conds[k], "control")
@ -93,7 +93,7 @@ def get_additional_models(conds, dtype):
inference_memory += m.inference_memory_requirements(dtype)
gligen = [x[1] for x in gligen]
hook_models = [x.model for x in hooks.get(hooks.EnumHookType.AddModels, {}).keys()]
hook_models = [x.model for x in hooks.get(EnumHookType.AddModels, {}).keys()]
models = control_models + gligen + add_models + hook_models
return models, inference_memory
@ -138,4 +138,4 @@ def prepare_model_patcher(model: 'ModelPatcher', conds, model_options: dict):
model_options["transformer_options"]["wrappers"] = patcher_extension.copy_nested_dicts(model.wrappers)
model_options["transformer_options"]["callbacks"] = patcher_extension.copy_nested_dicts(model.callbacks)
# register hooks on model/model_options
model.register_all_hook_patches(hooks, hooks.EnumWeightTarget.Model, model_options)
model.register_all_hook_patches(hooks, EnumWeightTarget.Model, model_options)

View File

@ -8,7 +8,6 @@ import numpy
import scipy.stats
import torch
from . import hooks
from . import model_management
from . import model_patcher
from . import patcher_extension
@ -16,6 +15,7 @@ from . import sampler_helpers
from .component_model.deprecation import _deprecate_method
from .controlnet import ControlBase
from .extra_samplers import uni_pc
from .hooks import EnumHookMode, HookGroup
from .k_diffusion import sampling as k_diffusion_sampling
from .model_base import BaseModel
from .model_management_types import ModelOptions
@ -157,7 +157,7 @@ def cond_cat(c_list):
return out
def finalize_default_conds(model: BaseModel, hooked_to_run: dict[hooks.HookGroup, list[tuple[tuple, int]]], default_conds: list[list[dict]], x_in, timestep):
def finalize_default_conds(model: BaseModel, hooked_to_run: dict[HookGroup, list[tuple[tuple, int]]], default_conds: list[list[dict]], x_in, timestep):
# need to figure out remaining unmasked area for conds
default_mults = []
for _ in default_conds:
@ -213,7 +213,7 @@ def _calc_cond_batch(model: BaseModel, conds, x_in: torch.Tensor, timestep: torc
out_conds = []
out_counts = []
# separate conds by matching hooks
hooked_to_run: dict[hooks.HookGroup, list[tuple[tuple, int]]] = {}
hooked_to_run: dict[HookGroup, list[tuple[tuple, int]]] = {}
default_conds = []
has_default_conds = False
@ -822,14 +822,14 @@ def process_conds(model, noise, conds, device, latent_image=None, denoise_mask=N
def preprocess_conds_hooks(conds: dict[str, list[dict[str]]]):
# determine which ControlNets have extra_hooks that should be combined with normal hooks
hook_replacement: dict[tuple[ControlBase, hooks.HookGroup], list[dict]] = {}
hook_replacement: dict[tuple[ControlBase, HookGroup], list[dict]] = {}
for k in conds:
for kk in conds[k]:
if 'control' in kk:
control: 'ControlBase' = kk['control']
extra_hooks = control.get_extra_hooks()
if len(extra_hooks) > 0:
hooks: hooks.HookGroup = kk.get('hooks', None)
hooks: HookGroup = kk.get('hooks', None)
to_replace = hook_replacement.setdefault((control, hooks), [])
to_replace.append(kk)
# if nothing to replace, do nothing
@ -841,7 +841,7 @@ def preprocess_conds_hooks(conds: dict[str, list[dict[str]]]):
for key, conds_to_modify in hook_replacement.items():
control = key[0]
hooks = key[1]
hooks = hooks.HookGroup.combine_all_hooks(control.get_extra_hooks() + [hooks])
hooks = HookGroup.combine_all_hooks(control.get_extra_hooks() + [hooks])
# if combined hooks are not None, set as new hooks for all relevant conds
if hooks is not None:
for cond in conds_to_modify:
@ -925,14 +925,14 @@ class CFGGuider:
for k in self.original_conds:
self.conds[k] = list(map(lambda a: a.copy(), self.original_conds[k]))
preprocess_conds_hooks(self.conds)
assert self.model_patcher is not None
orig_model_options = self.model_options
orig_hook_mode = self.model_patcher.hook_mode
try:
orig_model_options = self.model_options
self.model_options = model_patcher.create_model_options_clone(self.model_options)
# if one hook type (or just None), then don't bother caching weights for hooks (will never change after first step)
orig_hook_mode = self.model_patcher.hook_mode
if get_total_hook_groups_in_conds(self.conds) <= 1:
self.model_patcher.hook_mode = hooks.EnumHookMode.MinVram
self.model_patcher.hook_mode = EnumHookMode.MinVram
sampler_helpers.prepare_model_patcher(self.model_patcher, self.conds, self.model_options)
executor = patcher_extension.WrapperExecutor.new_class_executor(
self.outer_sample,

View File

@ -20,7 +20,7 @@ from . import model_sampling
from . import sd1_clip
from . import sdxl_clip
from . import utils
from . import hooks
from .hooks import EnumHookMode
from .ldm.audio.autoencoder import AudioOobleckVAE
from .ldm.cascade.stage_a import StageA
from .ldm.cascade.stage_c_coder import StageC_coder
@ -41,6 +41,7 @@ from .text_encoders import lt
from .text_encoders import sa_t5
from .text_encoders import sd2_clip
from .text_encoders import sd3_clip
from .utils import ProgressBar
def load_lora_for_models(model, clip, _lora, strength_model, strength_clip):
@ -108,7 +109,7 @@ class CLIP:
self.tokenizer: "sd1_clip.SD1Tokenizer" = tokenizer(embedding_directory=embedding_directory, tokenizer_data=tokenizer_data)
self.patcher = model_patcher.ModelPatcher(self.cond_stage_model, load_device=load_device, offload_device=offload_device)
self.patcher.hook_mode = hooks.EnumHookMode.MinVram
self.patcher.hook_mode = EnumHookMode.MinVram
self.patcher.is_clip = True
self.apply_hooks_to_conds = None
if params['device'] == load_device:

58
comfy/web/assets/DownloadGitView-DZIv7F1e.js generated vendored Normal file
View File

@ -0,0 +1,58 @@
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
import { a as defineComponent, f as openBlock, g as createElementBlock, A as createBaseVNode, a6 as toDisplayString, h as createVNode, z as unref, D as script, bQ as useRouter } from "./index-BQYg0VNJ.js";
const _hoisted_1 = { class: "font-sans w-screen h-screen mx-0 grid place-items-center justify-center items-center text-neutral-900 bg-neutral-300 pointer-events-auto" };
const _hoisted_2 = { class: "col-start-1 h-screen row-start-1 place-content-center mx-auto overflow-y-auto" };
const _hoisted_3 = { 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_4 = { class: "mt-24 text-4xl font-bold text-red-500" };
const _hoisted_5 = { class: "space-y-4" };
const _hoisted_6 = { class: "text-xl" };
const _hoisted_7 = { class: "text-xl" };
const _hoisted_8 = { class: "text-m" };
const _hoisted_9 = { class: "flex gap-4 flex-row-reverse" };
const _sfc_main = /* @__PURE__ */ defineComponent({
__name: "DownloadGitView",
setup(__props) {
const openGitDownloads = /* @__PURE__ */ __name(() => {
window.open("https://git-scm.com/downloads/", "_blank");
}, "openGitDownloads");
const skipGit = /* @__PURE__ */ __name(() => {
console.warn("pushing");
const router = useRouter();
router.push("install");
}, "skipGit");
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", _hoisted_1, [
createBaseVNode("div", _hoisted_2, [
createBaseVNode("div", _hoisted_3, [
createBaseVNode("h1", _hoisted_4, toDisplayString(_ctx.$t("downloadGit.title")), 1),
createBaseVNode("div", _hoisted_5, [
createBaseVNode("p", _hoisted_6, toDisplayString(_ctx.$t("downloadGit.message")), 1),
createBaseVNode("p", _hoisted_7, toDisplayString(_ctx.$t("downloadGit.instructions")), 1),
createBaseVNode("p", _hoisted_8, toDisplayString(_ctx.$t("downloadGit.warning")), 1)
]),
createBaseVNode("div", _hoisted_9, [
createVNode(unref(script), {
label: _ctx.$t("downloadGit.gitWebsite"),
icon: "pi pi-external-link",
"icon-pos": "right",
onClick: openGitDownloads,
severity: "primary"
}, null, 8, ["label"]),
createVNode(unref(script), {
label: _ctx.$t("downloadGit.skip"),
icon: "pi pi-exclamation-triangle",
onClick: skipGit,
severity: "secondary"
}, null, 8, ["label"])
])
])
])
]);
};
}
});
export {
_sfc_main as default
};
//# sourceMappingURL=DownloadGitView-DZIv7F1e.js.map

1
comfy/web/assets/DownloadGitView-DZIv7F1e.js.map generated vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"DownloadGitView-DZIv7F1e.js","sources":["../../src/views/DownloadGitView.vue"],"sourcesContent":["<template>\n <div\n class=\"font-sans w-screen h-screen mx-0 grid place-items-center justify-center items-center text-neutral-900 bg-neutral-300 pointer-events-auto\"\n >\n <div\n class=\"col-start-1 h-screen row-start-1 place-content-center mx-auto overflow-y-auto\"\n >\n <div\n 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\"\n >\n <!-- Header -->\n <h1 class=\"mt-24 text-4xl font-bold text-red-500\">\n {{ $t('downloadGit.title') }}\n </h1>\n\n <!-- Message -->\n <div class=\"space-y-4\">\n <p class=\"text-xl\">\n {{ $t('downloadGit.message') }}\n </p>\n <p class=\"text-xl\">\n {{ $t('downloadGit.instructions') }}\n </p>\n <p class=\"text-m\">\n {{ $t('downloadGit.warning') }}\n </p>\n </div>\n\n <!-- Actions -->\n <div class=\"flex gap-4 flex-row-reverse\">\n <Button\n :label=\"$t('downloadGit.gitWebsite')\"\n icon=\"pi pi-external-link\"\n icon-pos=\"right\"\n @click=\"openGitDownloads\"\n severity=\"primary\"\n />\n <Button\n :label=\"$t('downloadGit.skip')\"\n icon=\"pi pi-exclamation-triangle\"\n @click=\"skipGit\"\n severity=\"secondary\"\n />\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport Button from 'primevue/button'\nimport { useRouter } from 'vue-router'\n\nconst openGitDownloads = () => {\n window.open('https://git-scm.com/downloads/', '_blank')\n}\n\nconst skipGit = () => {\n console.warn('pushing')\n const router = useRouter()\n router.push('install')\n}\n</script>\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AAqDA,UAAM,mBAAmB,6BAAM;AACtB,aAAA,KAAK,kCAAkC,QAAQ;AAAA,IACxD,GAFyB;AAIzB,UAAM,UAAU,6BAAM;AACpB,cAAQ,KAAK,SAAS;AACtB,YAAM,SAAS,UAAU;AACzB,aAAO,KAAK,SAAS;AAAA,IACvB,GAJgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}

View File

@ -1 +0,0 @@
{"version":3,"file":"ExtensionPanel-DsD42OtO.js","sources":["../../src/components/dialog/content/setting/ExtensionPanel.vue"],"sourcesContent":["<template>\n <PanelTemplate value=\"Extension\" class=\"extension-panel\">\n <template #header>\n <SearchBox\n v-model=\"filters['global'].value\"\n :placeholder=\"$t('searchExtensions') + '...'\"\n />\n <Message v-if=\"hasChanges\" severity=\"info\" pt:text=\"w-full\">\n <ul>\n <li v-for=\"ext in changedExtensions\" :key=\"ext.name\">\n <span>\n {{ extensionStore.isExtensionEnabled(ext.name) ? '[-]' : '[+]' }}\n </span>\n {{ ext.name }}\n </li>\n </ul>\n <div class=\"flex justify-end\">\n <Button\n :label=\"$t('reloadToApplyChanges')\"\n @click=\"applyChanges\"\n outlined\n severity=\"danger\"\n />\n </div>\n </Message>\n </template>\n <DataTable\n :value=\"extensionStore.extensions\"\n stripedRows\n size=\"small\"\n :filters=\"filters\"\n >\n <Column field=\"name\" :header=\"$t('extensionName')\" sortable></Column>\n <Column\n :pt=\"{\n bodyCell: 'flex items-center justify-end'\n }\"\n >\n <template #body=\"slotProps\">\n <ToggleSwitch\n v-model=\"editingEnabledExtensions[slotProps.data.name]\"\n @change=\"updateExtensionStatus\"\n />\n </template>\n </Column>\n </DataTable>\n </PanelTemplate>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, onMounted } from 'vue'\nimport { useExtensionStore } from '@/stores/extensionStore'\nimport { useSettingStore } from '@/stores/settingStore'\nimport DataTable from 'primevue/datatable'\nimport Column from 'primevue/column'\nimport ToggleSwitch from 'primevue/toggleswitch'\nimport Button from 'primevue/button'\nimport Message from 'primevue/message'\nimport { FilterMatchMode } from '@primevue/core/api'\nimport PanelTemplate from './PanelTemplate.vue'\nimport SearchBox from '@/components/common/SearchBox.vue'\n\nconst filters = ref({\n global: { value: '', matchMode: FilterMatchMode.CONTAINS }\n})\n\nconst extensionStore = useExtensionStore()\nconst settingStore = useSettingStore()\n\nconst editingEnabledExtensions = ref<Record<string, boolean>>({})\n\nonMounted(() => {\n extensionStore.extensions.forEach((ext) => {\n editingEnabledExtensions.value[ext.name] =\n extensionStore.isExtensionEnabled(ext.name)\n })\n})\n\nconst changedExtensions = computed(() => {\n return extensionStore.extensions.filter(\n (ext) =>\n editingEnabledExtensions.value[ext.name] !==\n extensionStore.isExtensionEnabled(ext.name)\n )\n})\n\nconst hasChanges = computed(() => {\n return changedExtensions.value.length > 0\n})\n\nconst updateExtensionStatus = () => {\n const editingDisabledExtensionNames = Object.entries(\n editingEnabledExtensions.value\n )\n .filter(([_, enabled]) => !enabled)\n .map(([name]) => name)\n\n settingStore.set('Comfy.Extension.Disabled', [\n ...extensionStore.inactiveDisabledExtensionNames,\n ...editingDisabledExtensionNames\n ])\n}\n\nconst applyChanges = () => {\n // Refresh the page to apply changes\n window.location.reload()\n}\n</script>\n"],"names":[],"mappings":";;;;;;;;;AA8DA,UAAM,UAAU,IAAI;AAAA,MAClB,QAAQ,EAAE,OAAO,IAAI,WAAW,gBAAgB,SAAS;AAAA,IAAA,CAC1D;AAED,UAAM,iBAAiB;AACvB,UAAM,eAAe;AAEf,UAAA,2BAA2B,IAA6B,CAAA,CAAE;AAEhE,cAAU,MAAM;AACC,qBAAA,WAAW,QAAQ,CAAC,QAAQ;AACzC,iCAAyB,MAAM,IAAI,IAAI,IACrC,eAAe,mBAAmB,IAAI,IAAI;AAAA,MAAA,CAC7C;AAAA,IAAA,CACF;AAEK,UAAA,oBAAoB,SAAS,MAAM;AACvC,aAAO,eAAe,WAAW;AAAA,QAC/B,CAAC,QACC,yBAAyB,MAAM,IAAI,IAAI,MACvC,eAAe,mBAAmB,IAAI,IAAI;AAAA,MAAA;AAAA,IAC9C,CACD;AAEK,UAAA,aAAa,SAAS,MAAM;AACzB,aAAA,kBAAkB,MAAM,SAAS;AAAA,IAAA,CACzC;AAED,UAAM,wBAAwB,6BAAM;AAClC,YAAM,gCAAgC,OAAO;AAAA,QAC3C,yBAAyB;AAAA,MAExB,EAAA,OAAO,CAAC,CAAC,GAAG,OAAO,MAAM,CAAC,OAAO,EACjC,IAAI,CAAC,CAAC,IAAI,MAAM,IAAI;AAEvB,mBAAa,IAAI,4BAA4B;AAAA,QAC3C,GAAG,eAAe;AAAA,QAClB,GAAG;AAAA,MAAA,CACJ;AAAA,IAAA,GAV2B;AAa9B,UAAM,eAAe,6BAAM;AAEzB,aAAO,SAAS;IAAO,GAFJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}

View File

@ -1,8 +1,8 @@
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
import { d as defineComponent, r as ref, c6 as FilterMatchMode, ca as useExtensionStore, u as useSettingStore, o as onMounted, q as computed, g as openBlock, x as createBlock, y as withCtx, i as createVNode, c7 as SearchBox, z as unref, bT as script, A as createBaseVNode, h as createElementBlock, O as renderList, a6 as toDisplayString, aw as createTextVNode, N as Fragment, D as script$1, j as createCommentVNode, bV as script$3, c8 as _sfc_main$1 } from "./index-CoOvI8ZH.js";
import { s as script$2, a as script$4 } from "./index-DK6Kev7f.js";
import "./index-D4DWQPPQ.js";
import { a as defineComponent, r as ref, cg as FilterMatchMode, ck as useExtensionStore, u as useSettingStore, o as onMounted, q as computed, f as openBlock, x as createBlock, y as withCtx, h as createVNode, ch as SearchBox, z as unref, bS as script, A as createBaseVNode, g as createElementBlock, Q as renderList, a6 as toDisplayString, ax as createTextVNode, P as Fragment, D as script$1, i as createCommentVNode, c1 as script$3, ci as _sfc_main$1 } from "./index-BQYg0VNJ.js";
import { s as script$2, a as script$4 } from "./index-CMsGQEqY.js";
import "./index-DJqEjTnE.js";
const _hoisted_1 = { class: "flex justify-end" };
const _sfc_main = /* @__PURE__ */ defineComponent({
__name: "ExtensionPanel",
@ -47,7 +47,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
createVNode(SearchBox, {
modelValue: filters.value["global"].value,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => filters.value["global"].value = $event),
placeholder: _ctx.$t("searchExtensions") + "..."
placeholder: _ctx.$t("g.searchExtensions") + "..."
}, null, 8, ["modelValue", "placeholder"]),
hasChanges.value ? (openBlock(), createBlock(unref(script), {
key: 0,
@ -67,7 +67,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
]),
createBaseVNode("div", _hoisted_1, [
createVNode(unref(script$1), {
label: _ctx.$t("reloadToApplyChanges"),
label: _ctx.$t("g.reloadToApplyChanges"),
onClick: applyChanges,
outlined: "",
severity: "danger"
@ -87,7 +87,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
default: withCtx(() => [
createVNode(unref(script$2), {
field: "name",
header: _ctx.$t("extensionName"),
header: _ctx.$t("g.extensionName"),
sortable: ""
}, null, 8, ["header"]),
createVNode(unref(script$2), { pt: {
@ -114,4 +114,4 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
export {
_sfc_main as default
};
//# sourceMappingURL=ExtensionPanel-DsD42OtO.js.map
//# sourceMappingURL=ExtensionPanel-vSDJrNxh.js.map

1
comfy/web/assets/ExtensionPanel-vSDJrNxh.js.map generated vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"ExtensionPanel-vSDJrNxh.js","sources":["../../src/components/dialog/content/setting/ExtensionPanel.vue"],"sourcesContent":["<template>\n <PanelTemplate value=\"Extension\" class=\"extension-panel\">\n <template #header>\n <SearchBox\n v-model=\"filters['global'].value\"\n :placeholder=\"$t('g.searchExtensions') + '...'\"\n />\n <Message v-if=\"hasChanges\" severity=\"info\" pt:text=\"w-full\">\n <ul>\n <li v-for=\"ext in changedExtensions\" :key=\"ext.name\">\n <span>\n {{ extensionStore.isExtensionEnabled(ext.name) ? '[-]' : '[+]' }}\n </span>\n {{ ext.name }}\n </li>\n </ul>\n <div class=\"flex justify-end\">\n <Button\n :label=\"$t('g.reloadToApplyChanges')\"\n @click=\"applyChanges\"\n outlined\n severity=\"danger\"\n />\n </div>\n </Message>\n </template>\n <DataTable\n :value=\"extensionStore.extensions\"\n stripedRows\n size=\"small\"\n :filters=\"filters\"\n >\n <Column field=\"name\" :header=\"$t('g.extensionName')\" sortable></Column>\n <Column\n :pt=\"{\n bodyCell: 'flex items-center justify-end'\n }\"\n >\n <template #body=\"slotProps\">\n <ToggleSwitch\n v-model=\"editingEnabledExtensions[slotProps.data.name]\"\n @change=\"updateExtensionStatus\"\n />\n </template>\n </Column>\n </DataTable>\n </PanelTemplate>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, onMounted } from 'vue'\nimport { useExtensionStore } from '@/stores/extensionStore'\nimport { useSettingStore } from '@/stores/settingStore'\nimport DataTable from 'primevue/datatable'\nimport Column from 'primevue/column'\nimport ToggleSwitch from 'primevue/toggleswitch'\nimport Button from 'primevue/button'\nimport Message from 'primevue/message'\nimport { FilterMatchMode } from '@primevue/core/api'\nimport PanelTemplate from './PanelTemplate.vue'\nimport SearchBox from '@/components/common/SearchBox.vue'\n\nconst filters = ref({\n global: { value: '', matchMode: FilterMatchMode.CONTAINS }\n})\n\nconst extensionStore = useExtensionStore()\nconst settingStore = useSettingStore()\n\nconst editingEnabledExtensions = ref<Record<string, boolean>>({})\n\nonMounted(() => {\n extensionStore.extensions.forEach((ext) => {\n editingEnabledExtensions.value[ext.name] =\n extensionStore.isExtensionEnabled(ext.name)\n })\n})\n\nconst changedExtensions = computed(() => {\n return extensionStore.extensions.filter(\n (ext) =>\n editingEnabledExtensions.value[ext.name] !==\n extensionStore.isExtensionEnabled(ext.name)\n )\n})\n\nconst hasChanges = computed(() => {\n return changedExtensions.value.length > 0\n})\n\nconst updateExtensionStatus = () => {\n const editingDisabledExtensionNames = Object.entries(\n editingEnabledExtensions.value\n )\n .filter(([_, enabled]) => !enabled)\n .map(([name]) => name)\n\n settingStore.set('Comfy.Extension.Disabled', [\n ...extensionStore.inactiveDisabledExtensionNames,\n ...editingDisabledExtensionNames\n ])\n}\n\nconst applyChanges = () => {\n // Refresh the page to apply changes\n window.location.reload()\n}\n</script>\n"],"names":[],"mappings":";;;;;;;;;AA8DA,UAAM,UAAU,IAAI;AAAA,MAClB,QAAQ,EAAE,OAAO,IAAI,WAAW,gBAAgB,SAAS;AAAA,IAAA,CAC1D;AAED,UAAM,iBAAiB,kBAAkB;AACzC,UAAM,eAAe,gBAAgB;AAE/B,UAAA,2BAA2B,IAA6B,EAAE;AAEhE,cAAU,MAAM;AACC,qBAAA,WAAW,QAAQ,CAAC,QAAQ;AACzC,iCAAyB,MAAM,IAAI,IAAI,IACrC,eAAe,mBAAmB,IAAI,IAAI;AAAA,MAAA,CAC7C;AAAA,IAAA,CACF;AAEK,UAAA,oBAAoB,SAAS,MAAM;AACvC,aAAO,eAAe,WAAW;AAAA,QAC/B,CAAC,QACC,yBAAyB,MAAM,IAAI,IAAI,MACvC,eAAe,mBAAmB,IAAI,IAAI;AAAA,MAC9C;AAAA,IAAA,CACD;AAEK,UAAA,aAAa,SAAS,MAAM;AACzB,aAAA,kBAAkB,MAAM,SAAS;AAAA,IAAA,CACzC;AAED,UAAM,wBAAwB,6BAAM;AAClC,YAAM,gCAAgC,OAAO;AAAA,QAC3C,yBAAyB;AAAA,MAExB,EAAA,OAAO,CAAC,CAAC,GAAG,OAAO,MAAM,CAAC,OAAO,EACjC,IAAI,CAAC,CAAC,IAAI,MAAM,IAAI;AAEvB,mBAAa,IAAI,4BAA4B;AAAA,QAC3C,GAAG,eAAe;AAAA,QAClB,GAAG;AAAA,MAAA,CACJ;AAAA,IACH,GAX8B;AAa9B,UAAM,eAAe,6BAAM;AAEzB,aAAO,SAAS,OAAO;AAAA,IACzB,GAHqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}

File diff suppressed because one or more lines are too long

1
comfy/web/assets/GraphView-BAZmiysO.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -45,7 +45,7 @@
--sidebar-icon-size: 1rem;
}
.side-tool-bar-container[data-v-e0812a25] {
.side-tool-bar-container[data-v-7851c166] {
display: flex;
flex-direction: column;
align-items: center;
@ -55,10 +55,11 @@
width: var(--sidebar-width);
height: 100%;
background-color: var(--comfy-menu-bg);
background-color: var(--comfy-menu-secondary-bg);
color: var(--fg-color);
box-shadow: var(--bar-shadow);
}
.side-tool-bar-end[data-v-e0812a25] {
.side-tool-bar-end[data-v-7851c166] {
align-self: flex-end;
margin-top: auto;
}
@ -97,7 +98,7 @@
z-index: 999;
}
[data-v-37f672ab] .highlight {
[data-v-d7cc0bce] .highlight {
background-color: var(--p-primary-color);
color: var(--p-primary-contrast-color);
font-weight: bold;
@ -124,7 +125,7 @@
align-items: flex-start !important;
}
.node-tooltip[data-v-c2e0098f] {
.node-tooltip[data-v-259081e0] {
background: var(--comfy-input-bg);
border-radius: 5px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.4);
@ -158,25 +159,24 @@
z-index: 9999;
}
[data-v-783f8efe] .p-togglebutton::before {
[data-v-012040ee] .p-togglebutton::before {
display: none
}
[data-v-783f8efe] .p-togglebutton {
[data-v-012040ee] .p-togglebutton {
position: relative;
flex-shrink: 0;
border-radius: 0px;
background-color: transparent;
padding-left: 0.5rem;
padding-right: 0.5rem
padding: 0px
}
[data-v-783f8efe] .p-togglebutton.p-togglebutton-checked {
[data-v-012040ee] .p-togglebutton.p-togglebutton-checked {
border-bottom-width: 2px;
border-bottom-color: var(--p-button-text-primary-color)
}
[data-v-783f8efe] .p-togglebutton-checked .close-button,[data-v-783f8efe] .p-togglebutton:hover .close-button {
[data-v-012040ee] .p-togglebutton-checked .close-button,[data-v-012040ee] .p-togglebutton:hover .close-button {
visibility: visible
}
.status-indicator[data-v-783f8efe] {
.status-indicator[data-v-012040ee] {
position: absolute;
font-weight: 700;
font-size: 1.5rem;
@ -184,22 +184,22 @@
left: 50%;
transform: translate(-50%, -50%)
}
[data-v-783f8efe] .p-togglebutton:hover .status-indicator {
[data-v-012040ee] .p-togglebutton:hover .status-indicator {
display: none
}
[data-v-783f8efe] .p-togglebutton .close-button {
[data-v-012040ee] .p-togglebutton .close-button {
visibility: hidden
}
.top-menubar[data-v-9646ca0a] .p-menubar-item-link svg {
.top-menubar[data-v-a2b12676] .p-menubar-item-link svg {
display: none;
}
[data-v-9646ca0a] .p-menubar-submenu.dropdown-direction-up {
[data-v-a2b12676] .p-menubar-submenu.dropdown-direction-up {
top: auto;
bottom: 100%;
flex-direction: column-reverse;
}
.keybinding-tag[data-v-9646ca0a] {
.keybinding-tag[data-v-a2b12676] {
background: var(--p-content-hover-background);
border-color: var(--p-content-border-color);
border-style: solid;
@ -210,7 +210,7 @@
border-bottom-left-radius: 0;
}
.comfyui-queue-button[data-v-95bc9be0] .p-splitbutton-dropdown {
.comfyui-queue-button[data-v-d3897845] .p-splitbutton-dropdown {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
@ -238,10 +238,11 @@
display: none;
}
.comfyui-menu[data-v-d84a704d] {
.comfyui-menu[data-v-51020bc7] {
width: 100vw;
background: var(--comfy-menu-bg);
color: var(--fg-color);
box-shadow: var(--bar-shadow);
font-family: Arial, Helvetica, sans-serif;
font-size: 0.8em;
box-sizing: border-box;
@ -250,13 +251,16 @@
grid-column: 1/-1;
max-height: 90vh;
}
.comfyui-menu.dropzone[data-v-d84a704d] {
.comfyui-menu.dropzone[data-v-51020bc7] {
background: var(--p-highlight-background);
}
.comfyui-menu.dropzone-active[data-v-d84a704d] {
.comfyui-menu.dropzone-active[data-v-51020bc7] {
background: var(--p-highlight-background-focus);
}
.comfyui-logo[data-v-d84a704d] {
[data-v-51020bc7] .p-menubar-item-label {
line-height: revert;
}
.comfyui-logo[data-v-51020bc7] {
font-size: 1.2em;
-webkit-user-select: none;
-moz-user-select: none;

File diff suppressed because one or more lines are too long

1
comfy/web/assets/InstallView-BDCw9SUg.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
[data-v-53e62b05] .p-steppanel {
[data-v-7ef01cf2] .p-steppanel {
background-color: transparent
}

View File

@ -1,8 +0,0 @@
[data-v-9d7e362e] .p-datatable-tbody > tr > td {
padding: 0.25rem;
min-height: 2rem
}
[data-v-9d7e362e] .p-datatable-row-selected .actions,[data-v-9d7e362e] .p-datatable-selectable-row:hover .actions {
visibility: visible
}

8
comfy/web/assets/KeybindingPanel-ClaKRDVw.css generated vendored Normal file
View File

@ -0,0 +1,8 @@
[data-v-8cf0326b] .p-datatable-tbody > tr > td {
padding: 0.25rem;
min-height: 2rem
}
[data-v-8cf0326b] .p-datatable-row-selected .actions,[data-v-8cf0326b] .p-datatable-selectable-row:hover .actions {
visibility: visible
}

View File

@ -1,8 +1,8 @@
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
import { d as defineComponent, q as computed, g as openBlock, h as createElementBlock, N as Fragment, O as renderList, i as createVNode, y as withCtx, aw as createTextVNode, a6 as toDisplayString, z as unref, aA as script, j as createCommentVNode, r as ref, c6 as FilterMatchMode, M as useKeybindingStore, F as useCommandStore, aJ as watchEffect, bg as useToast, t as resolveDirective, x as createBlock, c7 as SearchBox, A as createBaseVNode, D as script$2, ao as script$4, bk as withModifiers, bT as script$5, aH as script$6, v as withDirectives, c8 as _sfc_main$2, P as pushScopeId, Q as popScopeId, c1 as KeyComboImpl, c9 as KeybindingImpl, _ as _export_sfc } from "./index-CoOvI8ZH.js";
import { s as script$1, a as script$3 } from "./index-DK6Kev7f.js";
import "./index-D4DWQPPQ.js";
import { a as defineComponent, q as computed, f as openBlock, g as createElementBlock, P as Fragment, Q as renderList, h as createVNode, y as withCtx, ax as createTextVNode, a6 as toDisplayString, z as unref, aB as script, i as createCommentVNode, r as ref, cg as FilterMatchMode, O as useKeybindingStore, F as useCommandStore, aK as watchEffect, bi as useToast, t as resolveDirective, x as createBlock, ch as SearchBox, A as createBaseVNode, D as script$2, ap as script$4, bm as withModifiers, bS as script$5, aH as script$6, v as withDirectives, ci as _sfc_main$2, ca as KeyComboImpl, cj as KeybindingImpl, _ as _export_sfc } from "./index-BQYg0VNJ.js";
import { s as script$1, a as script$3 } from "./index-CMsGQEqY.js";
import "./index-DJqEjTnE.js";
const _hoisted_1$1 = {
key: 0,
class: "px-2"
@ -35,7 +35,6 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
};
}
});
const _withScopeId = /* @__PURE__ */ __name((n) => (pushScopeId("data-v-9d7e362e"), n = n(), popScopeId(), n), "_withScopeId");
const _hoisted_1 = { class: "actions invisible flex flex-row" };
const _hoisted_2 = ["title"];
const _hoisted_3 = { key: 1 };
@ -140,7 +139,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
createVNode(SearchBox, {
modelValue: filters.value["global"].value,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => filters.value["global"].value = $event),
placeholder: _ctx.$t("searchKeybindings") + "..."
placeholder: _ctx.$t("g.searchKeybindings") + "..."
}, null, 8, ["modelValue", "placeholder"])
]),
default: withCtx(() => [
@ -243,7 +242,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
severity: "error"
}, {
default: withCtx(() => [
createTextVNode(" Keybinding already exists on "),
_cache[3] || (_cache[3] = createTextVNode(" Keybinding already exists on ")),
createVNode(unref(script), {
severity: "secondary",
value: existingKeybindingOnCombo.value.commandId
@ -257,14 +256,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
}, 8, ["visible", "header"]),
withDirectives(createVNode(unref(script$2), {
class: "mt-4",
label: _ctx.$t("reset"),
label: _ctx.$t("g.reset"),
icon: "pi pi-trash",
severity: "danger",
fluid: "",
text: "",
onClick: resetKeybindings
}, null, 8, ["label"]), [
[_directive_tooltip, _ctx.$t("resetKeybindingsTooltip")]
[_directive_tooltip, _ctx.$t("g.resetKeybindingsTooltip")]
])
]),
_: 1
@ -272,8 +271,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
};
}
});
const KeybindingPanel = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-9d7e362e"]]);
const KeybindingPanel = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-8cf0326b"]]);
export {
KeybindingPanel as default
};
//# sourceMappingURL=KeybindingPanel-lcJrxHwZ.js.map
//# sourceMappingURL=KeybindingPanel-DfPGcDsG.js.map

1
comfy/web/assets/KeybindingPanel-DfPGcDsG.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

81
comfy/web/assets/NotSupportedView-Ds7vEJAd.js generated vendored Normal file
View File

@ -0,0 +1,81 @@
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
import { a as defineComponent, bQ as useRouter, t as resolveDirective, f as openBlock, g as createElementBlock, A as createBaseVNode, a6 as toDisplayString, h as createVNode, z as unref, D as script, v as withDirectives } from "./index-BQYg0VNJ.js";
const _imports_0 = "" + new URL("images/sad_girl.png", import.meta.url).href;
const _hoisted_1 = { class: "font-sans w-screen h-screen flex items-center m-0 text-neutral-900 bg-neutral-300 pointer-events-auto" };
const _hoisted_2 = { class: "flex-grow flex items-center justify-center" };
const _hoisted_3 = { class: "flex flex-col gap-8 p-8" };
const _hoisted_4 = { class: "text-4xl font-bold text-red-500" };
const _hoisted_5 = { class: "space-y-4" };
const _hoisted_6 = { class: "text-xl" };
const _hoisted_7 = { class: "list-disc list-inside space-y-1 text-neutral-800" };
const _hoisted_8 = { class: "flex gap-4" };
const _sfc_main = /* @__PURE__ */ defineComponent({
__name: "NotSupportedView",
setup(__props) {
const openDocs = /* @__PURE__ */ __name(() => {
window.open(
"https://github.com/Comfy-Org/desktop#currently-supported-platforms",
"_blank"
);
}, "openDocs");
const reportIssue = /* @__PURE__ */ __name(() => {
window.open("https://forum.comfy.org/c/v1-feedback/", "_blank");
}, "reportIssue");
const router = useRouter();
const continueToInstall = /* @__PURE__ */ __name(() => {
router.push("/install");
}, "continueToInstall");
return (_ctx, _cache) => {
const _directive_tooltip = resolveDirective("tooltip");
return openBlock(), createElementBlock("div", _hoisted_1, [
createBaseVNode("div", _hoisted_2, [
createBaseVNode("div", _hoisted_3, [
createBaseVNode("h1", _hoisted_4, toDisplayString(_ctx.$t("notSupported.title")), 1),
createBaseVNode("div", _hoisted_5, [
createBaseVNode("p", _hoisted_6, toDisplayString(_ctx.$t("notSupported.message")), 1),
createBaseVNode("ul", _hoisted_7, [
createBaseVNode("li", null, toDisplayString(_ctx.$t("notSupported.supportedDevices.macos")), 1),
createBaseVNode("li", null, toDisplayString(_ctx.$t("notSupported.supportedDevices.windows")), 1)
])
]),
createBaseVNode("div", _hoisted_8, [
createVNode(unref(script), {
label: _ctx.$t("notSupported.learnMore"),
icon: "pi pi-github",
onClick: openDocs,
severity: "secondary"
}, null, 8, ["label"]),
createVNode(unref(script), {
label: _ctx.$t("notSupported.reportIssue"),
icon: "pi pi-flag",
onClick: reportIssue,
severity: "secondary"
}, null, 8, ["label"]),
withDirectives(createVNode(unref(script), {
label: _ctx.$t("notSupported.continue"),
icon: "pi pi-arrow-right",
iconPos: "right",
onClick: continueToInstall,
severity: "danger"
}, null, 8, ["label"]), [
[_directive_tooltip, _ctx.$t("notSupported.continueTooltip")]
])
])
])
]),
_cache[0] || (_cache[0] = createBaseVNode("div", { class: "h-screen flex-grow-0" }, [
createBaseVNode("img", {
src: _imports_0,
alt: "Sad girl illustration",
class: "h-full object-cover"
})
], -1))
]);
};
}
});
export {
_sfc_main as default
};
//# sourceMappingURL=NotSupportedView-Ds7vEJAd.js.map

1
comfy/web/assets/NotSupportedView-Ds7vEJAd.js.map generated vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"NotSupportedView-Ds7vEJAd.js","sources":["../../../../../../assets/images/sad_girl.png","../../src/views/NotSupportedView.vue"],"sourcesContent":["export default \"__VITE_PUBLIC_ASSET__b82952e7__\"","<template>\n <div\n class=\"font-sans w-screen h-screen flex items-center m-0 text-neutral-900 bg-neutral-300 pointer-events-auto\"\n >\n <div class=\"flex-grow flex items-center justify-center\">\n <div class=\"flex flex-col gap-8 p-8\">\n <!-- Header -->\n <h1 class=\"text-4xl font-bold text-red-500\">\n {{ $t('notSupported.title') }}\n </h1>\n\n <!-- Message -->\n <div class=\"space-y-4\">\n <p class=\"text-xl\">\n {{ $t('notSupported.message') }}\n </p>\n <ul class=\"list-disc list-inside space-y-1 text-neutral-800\">\n <li>{{ $t('notSupported.supportedDevices.macos') }}</li>\n <li>{{ $t('notSupported.supportedDevices.windows') }}</li>\n </ul>\n </div>\n\n <!-- Actions -->\n <div class=\"flex gap-4\">\n <Button\n :label=\"$t('notSupported.learnMore')\"\n icon=\"pi pi-github\"\n @click=\"openDocs\"\n severity=\"secondary\"\n />\n <Button\n :label=\"$t('notSupported.reportIssue')\"\n icon=\"pi pi-flag\"\n @click=\"reportIssue\"\n severity=\"secondary\"\n />\n <Button\n :label=\"$t('notSupported.continue')\"\n icon=\"pi pi-arrow-right\"\n iconPos=\"right\"\n @click=\"continueToInstall\"\n severity=\"danger\"\n v-tooltip=\"$t('notSupported.continueTooltip')\"\n />\n </div>\n </div>\n </div>\n\n <!-- Right side image -->\n <div class=\"h-screen flex-grow-0\">\n <img\n src=\"/assets/images/sad_girl.png\"\n alt=\"Sad girl illustration\"\n class=\"h-full object-cover\"\n />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport Button from 'primevue/button'\nimport { useRouter } from 'vue-router'\n\nconst openDocs = () => {\n window.open(\n 'https://github.com/Comfy-Org/desktop#currently-supported-platforms',\n '_blank'\n )\n}\n\nconst reportIssue = () => {\n window.open('https://forum.comfy.org/c/v1-feedback/', '_blank')\n}\n\nconst router = useRouter()\nconst continueToInstall = () => {\n router.push('/install')\n}\n</script>\n"],"names":[],"mappings":";;;AAAA,MAAe,aAAA,KAAA,IAAA,IAAA,uBAAA,YAAA,GAAA,EAAA;;;;;;;;;;;;AC+Df,UAAM,WAAW,6BAAM;AACd,aAAA;AAAA,QACL;AAAA,QACA;AAAA,MACF;AAAA,IACF,GALiB;AAOjB,UAAM,cAAc,6BAAM;AACjB,aAAA,KAAK,0CAA0C,QAAQ;AAAA,IAChE,GAFoB;AAIpB,UAAM,SAAS,UAAU;AACzB,UAAM,oBAAoB,6BAAM;AAC9B,aAAO,KAAK,UAAU;AAAA,IACxB,GAF0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}

View File

@ -1,25 +1,23 @@
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
import { A as createBaseVNode, g as openBlock, h as createElementBlock, aU as markRaw, d as defineComponent, u as useSettingStore, bw as storeToRefs, w as watch, cy as useCopyToClipboard, x as createBlock, y as withCtx, z as unref, bT as script, a6 as toDisplayString, O as renderList, N as Fragment, i as createVNode, D as script$1, j as createCommentVNode, bI as script$2, cz as formatCamelCase, cA as FormItem, c8 as _sfc_main$1, bN as electronAPI } from "./index-CoOvI8ZH.js";
import { u as useServerConfigStore } from "./serverConfigStore-cctR8PGG.js";
import { f as openBlock, g as createElementBlock, A as createBaseVNode, aW as markRaw, a as defineComponent, u as useSettingStore, aJ as storeToRefs, w as watch, cF as useCopyToClipboard, I as useI18n, x as createBlock, y as withCtx, z as unref, bS as script, a6 as toDisplayString, Q as renderList, P as Fragment, h as createVNode, D as script$1, i as createCommentVNode, bJ as script$2, cG as FormItem, ci as _sfc_main$1, bV as electronAPI } from "./index-BQYg0VNJ.js";
import { u as useServerConfigStore } from "./serverConfigStore-DulDGgjD.js";
const _hoisted_1$1 = {
viewBox: "0 0 24 24",
width: "1.2em",
height: "1.2em"
};
const _hoisted_2$1 = /* @__PURE__ */ createBaseVNode("path", {
fill: "none",
stroke: "currentColor",
"stroke-linecap": "round",
"stroke-linejoin": "round",
"stroke-width": "2",
d: "m4 17l6-6l-6-6m8 14h8"
}, null, -1);
const _hoisted_3$1 = [
_hoisted_2$1
];
function render(_ctx, _cache) {
return openBlock(), createElementBlock("svg", _hoisted_1$1, [..._hoisted_3$1]);
return openBlock(), createElementBlock("svg", _hoisted_1$1, _cache[0] || (_cache[0] = [
createBaseVNode("path", {
fill: "none",
stroke: "currentColor",
"stroke-linecap": "round",
"stroke-linejoin": "round",
"stroke-width": "2",
d: "m4 17l6-6l-6-6m8 14h8"
}, null, -1)
]));
}
__name(render, "render");
const __unplugin_components_0 = markRaw({ name: "lucide-terminal", render });
@ -54,6 +52,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
const copyCommandLineArgs = /* @__PURE__ */ __name(async () => {
await copyToClipboard(commandLineArgs.value);
}, "copyCommandLineArgs");
const { t } = useI18n();
const translateItem = /* @__PURE__ */ __name((item) => {
return {
...item,
name: t(`serverConfigItems.${item.id}.name`, item.name),
tooltip: item.tooltip ? t(`serverConfigItems.${item.id}.tooltip`, item.tooltip) : void 0
};
}, "translateItem");
return (_ctx, _cache) => {
const _component_i_lucide58terminal = __unplugin_components_0;
return openBlock(), createBlock(_sfc_main$1, {
@ -119,14 +125,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
(openBlock(true), createElementBlock(Fragment, null, renderList(Object.entries(unref(serverConfigsByCategory)), ([label, items], i) => {
return openBlock(), createElementBlock("div", { key: label }, [
i > 0 ? (openBlock(), createBlock(unref(script$2), { key: 0 })) : createCommentVNode("", true),
createBaseVNode("h3", null, toDisplayString(unref(formatCamelCase)(label)), 1),
createBaseVNode("h3", null, toDisplayString(_ctx.$t(`serverConfigCategories.${label}`, label)), 1),
(openBlock(true), createElementBlock(Fragment, null, renderList(items, (item) => {
return openBlock(), createElementBlock("div", {
key: item.name,
class: "flex items-center mb-4"
}, [
createVNode(FormItem, {
item,
item: translateItem(item),
formValue: item.value,
"onUpdate:formValue": /* @__PURE__ */ __name(($event) => item.value = $event, "onUpdate:formValue"),
id: item.id,
@ -147,4 +153,4 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
export {
_sfc_main as default
};
//# sourceMappingURL=ServerConfigPanel-x68ubY-c.js.map
//# sourceMappingURL=ServerConfigPanel-B7Ic27AR.js.map

1
comfy/web/assets/ServerConfigPanel-B7Ic27AR.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
{"version":3,"file":"ServerConfigPanel-x68ubY-c.js","sources":["../../src/components/dialog/content/setting/ServerConfigPanel.vue"],"sourcesContent":["<template>\n <PanelTemplate value=\"Server-Config\" class=\"server-config-panel\">\n <template #header>\n <div class=\"flex flex-col gap-2\">\n <Message\n v-if=\"modifiedConfigs.length > 0\"\n severity=\"info\"\n pt:text=\"w-full\"\n >\n <p>\n {{ $t('serverConfig.modifiedConfigs') }}\n </p>\n <ul>\n <li v-for=\"config in modifiedConfigs\" :key=\"config.id\">\n {{ config.name }}: {{ config.initialValue }} → {{ config.value }}\n </li>\n </ul>\n <div class=\"flex justify-end gap-2\">\n <Button\n :label=\"$t('serverConfig.revertChanges')\"\n @click=\"revertChanges\"\n outlined\n />\n <Button\n :label=\"$t('serverConfig.restart')\"\n @click=\"restartApp\"\n outlined\n severity=\"danger\"\n />\n </div>\n </Message>\n <Message v-if=\"commandLineArgs\" severity=\"secondary\" pt:text=\"w-full\">\n <template #icon>\n <i-lucide:terminal class=\"text-xl font-bold\" />\n </template>\n <div class=\"flex items-center justify-between\">\n <p>{{ commandLineArgs }}</p>\n <Button\n icon=\"pi pi-clipboard\"\n @click=\"copyCommandLineArgs\"\n severity=\"secondary\"\n text\n />\n </div>\n </Message>\n </div>\n </template>\n <div\n v-for=\"([label, items], i) in Object.entries(serverConfigsByCategory)\"\n :key=\"label\"\n >\n <Divider v-if=\"i > 0\" />\n <h3>{{ formatCamelCase(label) }}</h3>\n <div\n v-for=\"item in items\"\n :key=\"item.name\"\n class=\"flex items-center mb-4\"\n >\n <FormItem\n :item=\"item\"\n v-model:formValue=\"item.value\"\n :id=\"item.id\"\n :labelClass=\"{\n 'text-highlight': item.initialValue !== item.value\n }\"\n />\n </div>\n </div>\n </PanelTemplate>\n</template>\n\n<script setup lang=\"ts\">\nimport Button from 'primevue/button'\nimport Message from 'primevue/message'\nimport Divider from 'primevue/divider'\nimport FormItem from '@/components/common/FormItem.vue'\nimport PanelTemplate from './PanelTemplate.vue'\nimport { formatCamelCase } from '@/utils/formatUtil'\nimport { useServerConfigStore } from '@/stores/serverConfigStore'\nimport { storeToRefs } from 'pinia'\nimport { electronAPI } from '@/utils/envUtil'\nimport { useSettingStore } from '@/stores/settingStore'\nimport { watch } from 'vue'\nimport { useCopyToClipboard } from '@/hooks/clipboardHooks'\n\nconst settingStore = useSettingStore()\nconst serverConfigStore = useServerConfigStore()\nconst {\n serverConfigsByCategory,\n serverConfigValues,\n launchArgs,\n commandLineArgs,\n modifiedConfigs\n} = storeToRefs(serverConfigStore)\n\nconst revertChanges = () => {\n serverConfigStore.revertChanges()\n}\n\nconst restartApp = () => {\n electronAPI().restartApp()\n}\n\nwatch(launchArgs, (newVal) => {\n settingStore.set('Comfy.Server.LaunchArgs', newVal)\n})\n\nwatch(serverConfigValues, (newVal) => {\n settingStore.set('Comfy.Server.ServerConfigValues', newVal)\n})\n\nconst { copyToClipboard } = useCopyToClipboard()\nconst copyCommandLineArgs = async () => {\n await copyToClipboard(commandLineArgs.value)\n}\n</script>\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqFA,UAAM,eAAe;AACrB,UAAM,oBAAoB;AACpB,UAAA;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA,IACE,YAAY,iBAAiB;AAEjC,UAAM,gBAAgB,6BAAM;AAC1B,wBAAkB,cAAc;AAAA,IAAA,GADZ;AAItB,UAAM,aAAa,6BAAM;AACvB,kBAAA,EAAc;IAAW,GADR;AAIb,UAAA,YAAY,CAAC,WAAW;AACf,mBAAA,IAAI,2BAA2B,MAAM;AAAA,IAAA,CACnD;AAEK,UAAA,oBAAoB,CAAC,WAAW;AACvB,mBAAA,IAAI,mCAAmC,MAAM;AAAA,IAAA,CAC3D;AAEK,UAAA,EAAE,oBAAoB;AAC5B,UAAM,sBAAsB,mCAAY;AAChC,YAAA,gBAAgB,gBAAgB,KAAK;AAAA,IAAA,GADjB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}

View File

@ -1 +0,0 @@
{"version":3,"file":"ServerStartView-CqRVtr1h.js","sources":["../../src/views/ServerStartView.vue"],"sourcesContent":["<template>\n <div\n class=\"font-sans flex flex-col justify-center items-center h-screen m-0 text-neutral-300 bg-neutral-900 dark-theme pointer-events-auto\"\n >\n <h2 class=\"text-2xl font-bold\">\n {{ t(`serverStart.process.${status}`) }}\n <span v-if=\"status === ProgressStatus.ERROR\">\n v{{ electronVersion }}\n </span>\n </h2>\n <div\n v-if=\"status === ProgressStatus.ERROR\"\n class=\"flex items-center my-4 gap-2\"\n >\n <Button\n icon=\"pi pi-flag\"\n severity=\"secondary\"\n :label=\"t('serverStart.reportIssue')\"\n @click=\"reportIssue\"\n />\n <Button\n icon=\"pi pi-file\"\n severity=\"secondary\"\n :label=\"t('serverStart.openLogs')\"\n @click=\"openLogs\"\n />\n <Button\n icon=\"pi pi-refresh\"\n :label=\"t('serverStart.reinstall')\"\n @click=\"reinstall\"\n />\n </div>\n <BaseTerminal @created=\"terminalCreated\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport Button from 'primevue/button'\nimport { ref, onMounted, Ref } from 'vue'\nimport BaseTerminal from '@/components/bottomPanel/tabs/terminal/BaseTerminal.vue'\nimport { ProgressStatus } from '@comfyorg/comfyui-electron-types'\nimport { electronAPI } from '@/utils/envUtil'\nimport type { useTerminal } from '@/hooks/bottomPanelTabs/useTerminal'\nimport { Terminal } from '@xterm/xterm'\nimport { useI18n } from 'vue-i18n'\n\nconst electron = electronAPI()\nconst { t } = useI18n()\n\nconst status = ref<ProgressStatus>(ProgressStatus.INITIAL_STATE)\nconst electronVersion = ref<string>('')\nlet xterm: Terminal | undefined\n\nconst updateProgress = ({ status: newStatus }: { status: ProgressStatus }) => {\n status.value = newStatus\n xterm?.clear()\n}\n\nconst terminalCreated = (\n { terminal, useAutoSize }: ReturnType<typeof useTerminal>,\n root: Ref<HTMLElement>\n) => {\n xterm = terminal\n\n useAutoSize(root, true, true)\n electron.onLogMessage((message: string) => {\n terminal.write(message)\n })\n\n terminal.options.cursorBlink = false\n terminal.options.disableStdin = true\n terminal.options.cursorInactiveStyle = 'block'\n}\n\nconst reinstall = () => electron.reinstall()\nconst reportIssue = () => {\n window.open('https://forum.comfy.org/c/v1-feedback/', '_blank')\n}\nconst openLogs = () => electron.openLogsFolder()\n\nonMounted(async () => {\n electron.sendReady()\n electron.onProgressUpdate(updateProgress)\n electronVersion.value = await electron.getElectronVersion()\n})\n</script>\n\n<style scoped>\n:deep(.xterm-helper-textarea) {\n /* Hide this as it moves all over when uv is running */\n display: none;\n}\n</style>\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AA8CA,UAAM,WAAW;AACX,UAAA,EAAE,MAAM;AAER,UAAA,SAAS,IAAoB,eAAe,aAAa;AACzD,UAAA,kBAAkB,IAAY,EAAE;AAClC,QAAA;AAEJ,UAAM,iBAAiB,wBAAC,EAAE,QAAQ,gBAA4C;AAC5E,aAAO,QAAQ;AACf,aAAO,MAAM;AAAA,IAAA,GAFQ;AAKvB,UAAM,kBAAkB,wBACtB,EAAE,UAAU,YAAA,GACZ,SACG;AACK,cAAA;AAEI,kBAAA,MAAM,MAAM,IAAI;AACnB,eAAA,aAAa,CAAC,YAAoB;AACzC,iBAAS,MAAM,OAAO;AAAA,MAAA,CACvB;AAED,eAAS,QAAQ,cAAc;AAC/B,eAAS,QAAQ,eAAe;AAChC,eAAS,QAAQ,sBAAsB;AAAA,IAAA,GAbjB;AAgBlB,UAAA,YAAY,6BAAM,SAAS,aAAf;AAClB,UAAM,cAAc,6BAAM;AACjB,aAAA,KAAK,0CAA0C,QAAQ;AAAA,IAAA,GAD5C;AAGd,UAAA,WAAW,6BAAM,SAAS,kBAAf;AAEjB,cAAU,YAAY;AACpB,eAAS,UAAU;AACnB,eAAS,iBAAiB,cAAc;AACxB,sBAAA,QAAQ,MAAM,SAAS,mBAAmB;AAAA,IAAA,CAC3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}

View File

@ -1,5 +1,5 @@
[data-v-f5429be7] .xterm-helper-textarea {
[data-v-95e9eb99] .xterm-helper-textarea {
/* Hide this as it moves all over when uv is running */
display: none;
}

View File

@ -1,8 +1,6 @@
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
import { d as defineComponent, aD as useI18n, r as ref, o as onMounted, g as openBlock, h as createElementBlock, A as createBaseVNode, aw as createTextVNode, a6 as toDisplayString, z as unref, j as createCommentVNode, i as createVNode, D as script, bM as BaseTerminal, P as pushScopeId, Q as popScopeId, bN as electronAPI, _ as _export_sfc } from "./index-CoOvI8ZH.js";
import { P as ProgressStatus } from "./index-BppSBmxJ.js";
const _withScopeId = /* @__PURE__ */ __name((n) => (pushScopeId("data-v-f5429be7"), n = n(), popScopeId(), n), "_withScopeId");
import { a as defineComponent, I as useI18n, r as ref, bT as ProgressStatus, o as onMounted, f as openBlock, g as createElementBlock, A as createBaseVNode, ax as createTextVNode, a6 as toDisplayString, z as unref, i as createCommentVNode, h as createVNode, D as script, bU as BaseTerminal, bV as electronAPI, _ as _export_sfc } from "./index-BQYg0VNJ.js";
const _hoisted_1 = { class: "font-sans flex flex-col justify-center items-center h-screen m-0 text-neutral-300 bg-neutral-900 dark-theme pointer-events-auto" };
const _hoisted_2 = { class: "text-2xl font-bold" };
const _hoisted_3 = { key: 0 };
@ -20,7 +18,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
let xterm;
const updateProgress = /* @__PURE__ */ __name(({ status: newStatus }) => {
status.value = newStatus;
xterm?.clear();
if (newStatus !== ProgressStatus.ERROR) xterm?.clear();
}, "updateProgress");
const terminalCreated = /* @__PURE__ */ __name(({ terminal, useAutoSize }, root) => {
xterm = terminal;
@ -72,8 +70,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
};
}
});
const ServerStartView = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-f5429be7"]]);
const ServerStartView = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-95e9eb99"]]);
export {
ServerStartView as default
};
//# sourceMappingURL=ServerStartView-CqRVtr1h.js.map
//# sourceMappingURL=ServerStartView-kWuF5BS_.js.map

1
comfy/web/assets/ServerStartView-kWuF5BS_.js.map generated vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"ServerStartView-kWuF5BS_.js","sources":["../../src/views/ServerStartView.vue"],"sourcesContent":["<template>\n <div\n class=\"font-sans flex flex-col justify-center items-center h-screen m-0 text-neutral-300 bg-neutral-900 dark-theme pointer-events-auto\"\n >\n <h2 class=\"text-2xl font-bold\">\n {{ t(`serverStart.process.${status}`) }}\n <span v-if=\"status === ProgressStatus.ERROR\">\n v{{ electronVersion }}\n </span>\n </h2>\n <div\n v-if=\"status === ProgressStatus.ERROR\"\n class=\"flex items-center my-4 gap-2\"\n >\n <Button\n icon=\"pi pi-flag\"\n severity=\"secondary\"\n :label=\"t('serverStart.reportIssue')\"\n @click=\"reportIssue\"\n />\n <Button\n icon=\"pi pi-file\"\n severity=\"secondary\"\n :label=\"t('serverStart.openLogs')\"\n @click=\"openLogs\"\n />\n <Button\n icon=\"pi pi-refresh\"\n :label=\"t('serverStart.reinstall')\"\n @click=\"reinstall\"\n />\n </div>\n <BaseTerminal @created=\"terminalCreated\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport Button from 'primevue/button'\nimport { ref, onMounted, Ref } from 'vue'\nimport BaseTerminal from '@/components/bottomPanel/tabs/terminal/BaseTerminal.vue'\nimport { ProgressStatus } from '@comfyorg/comfyui-electron-types'\nimport { electronAPI } from '@/utils/envUtil'\nimport type { useTerminal } from '@/hooks/bottomPanelTabs/useTerminal'\nimport { Terminal } from '@xterm/xterm'\nimport { useI18n } from 'vue-i18n'\n\nconst electron = electronAPI()\nconst { t } = useI18n()\n\nconst status = ref<ProgressStatus>(ProgressStatus.INITIAL_STATE)\nconst electronVersion = ref<string>('')\nlet xterm: Terminal | undefined\n\nconst updateProgress = ({ status: newStatus }: { status: ProgressStatus }) => {\n status.value = newStatus\n if (newStatus !== ProgressStatus.ERROR) xterm?.clear()\n}\n\nconst terminalCreated = (\n { terminal, useAutoSize }: ReturnType<typeof useTerminal>,\n root: Ref<HTMLElement>\n) => {\n xterm = terminal\n\n useAutoSize(root, true, true)\n electron.onLogMessage((message: string) => {\n terminal.write(message)\n })\n\n terminal.options.cursorBlink = false\n terminal.options.disableStdin = true\n terminal.options.cursorInactiveStyle = 'block'\n}\n\nconst reinstall = () => electron.reinstall()\nconst reportIssue = () => {\n window.open('https://forum.comfy.org/c/v1-feedback/', '_blank')\n}\nconst openLogs = () => electron.openLogsFolder()\n\nonMounted(async () => {\n electron.sendReady()\n electron.onProgressUpdate(updateProgress)\n electronVersion.value = await electron.getElectronVersion()\n})\n</script>\n\n<style scoped>\n:deep(.xterm-helper-textarea) {\n /* Hide this as it moves all over when uv is running */\n display: none;\n}\n</style>\n"],"names":[],"mappings":";;;;;;;;;;;;;AA8CA,UAAM,WAAW,YAAY;AACvB,UAAA,EAAE,EAAE,IAAI,QAAQ;AAEhB,UAAA,SAAS,IAAoB,eAAe,aAAa;AACzD,UAAA,kBAAkB,IAAY,EAAE;AAClC,QAAA;AAEJ,UAAM,iBAAiB,wBAAC,EAAE,QAAQ,gBAA4C;AAC5E,aAAO,QAAQ;AACf,UAAI,cAAc,eAAe,MAAO,QAAO,MAAM;AAAA,IACvD,GAHuB;AAKvB,UAAM,kBAAkB,wBACtB,EAAE,UAAU,YAAA,GACZ,SACG;AACK,cAAA;AAEI,kBAAA,MAAM,MAAM,IAAI;AACnB,eAAA,aAAa,CAAC,YAAoB;AACzC,iBAAS,MAAM,OAAO;AAAA,MAAA,CACvB;AAED,eAAS,QAAQ,cAAc;AAC/B,eAAS,QAAQ,eAAe;AAChC,eAAS,QAAQ,sBAAsB;AAAA,IACzC,GAdwB;AAgBlB,UAAA,YAAY,6BAAM,SAAS,UAAU,GAAzB;AAClB,UAAM,cAAc,6BAAM;AACjB,aAAA,KAAK,0CAA0C,QAAQ;AAAA,IAChE,GAFoB;AAGd,UAAA,WAAW,6BAAM,SAAS,eAAe,GAA9B;AAEjB,cAAU,YAAY;AACpB,eAAS,UAAU;AACnB,eAAS,iBAAiB,cAAc;AACxB,sBAAA,QAAQ,MAAM,SAAS,mBAAmB;AAAA,IAAA,CAC3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}

97
comfy/web/assets/UserSelectView-D1x2NjYS.js generated vendored Normal file
View File

@ -0,0 +1,97 @@
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
import { a as defineComponent, J as useUserStore, bQ as useRouter, r as ref, q as computed, o as onMounted, f as openBlock, g as createElementBlock, A as createBaseVNode, a6 as toDisplayString, h as createVNode, z as unref, ap as script, bJ as script$1, bR as script$2, x as createBlock, y as withCtx, ax as createTextVNode, bS as script$3, i as createCommentVNode, D as script$4 } from "./index-BQYg0VNJ.js";
const _hoisted_1 = {
id: "comfy-user-selection",
class: "font-sans flex flex-col items-center h-screen m-0 text-neutral-300 bg-neutral-900 dark-theme pointer-events-auto"
};
const _hoisted_2 = { class: "mt-[5vh] 2xl:mt-[20vh] min-w-84 relative rounded-lg bg-[var(--comfy-menu-bg)] p-5 px-10 shadow-lg" };
const _hoisted_3 = { class: "flex w-full flex-col items-center" };
const _hoisted_4 = { class: "flex w-full flex-col gap-2" };
const _hoisted_5 = { for: "new-user-input" };
const _hoisted_6 = { class: "flex w-full flex-col gap-2" };
const _hoisted_7 = { for: "existing-user-select" };
const _hoisted_8 = { class: "mt-5" };
const _sfc_main = /* @__PURE__ */ defineComponent({
__name: "UserSelectView",
setup(__props) {
const userStore = useUserStore();
const router = useRouter();
const selectedUser = ref(null);
const newUsername = ref("");
const loginError = ref("");
const createNewUser = computed(() => newUsername.value.trim() !== "");
const newUserExistsError = computed(() => {
return userStore.users.find((user) => user.username === newUsername.value) ? `User "${newUsername.value}" already exists` : "";
});
const error = computed(() => newUserExistsError.value || loginError.value);
const login = /* @__PURE__ */ __name(async () => {
try {
const user = createNewUser.value ? await userStore.createUser(newUsername.value) : selectedUser.value;
if (!user) {
throw new Error("No user selected");
}
userStore.login(user);
router.push("/");
} catch (err) {
loginError.value = err.message ?? JSON.stringify(err);
}
}, "login");
onMounted(async () => {
if (!userStore.initialized) {
await userStore.initialize();
}
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", _hoisted_1, [
createBaseVNode("main", _hoisted_2, [
_cache[2] || (_cache[2] = createBaseVNode("h1", { class: "my-2.5 mb-7 font-normal" }, "ComfyUI", -1)),
createBaseVNode("form", _hoisted_3, [
createBaseVNode("div", _hoisted_4, [
createBaseVNode("label", _hoisted_5, toDisplayString(_ctx.$t("userSelect.newUser")) + ":", 1),
createVNode(unref(script), {
id: "new-user-input",
modelValue: newUsername.value,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => newUsername.value = $event),
placeholder: _ctx.$t("userSelect.enterUsername")
}, null, 8, ["modelValue", "placeholder"])
]),
createVNode(unref(script$1)),
createBaseVNode("div", _hoisted_6, [
createBaseVNode("label", _hoisted_7, toDisplayString(_ctx.$t("userSelect.existingUser")) + ":", 1),
createVNode(unref(script$2), {
modelValue: selectedUser.value,
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => selectedUser.value = $event),
class: "w-full",
inputId: "existing-user-select",
options: unref(userStore).users,
"option-label": "username",
placeholder: _ctx.$t("userSelect.selectUser"),
disabled: createNewUser.value
}, null, 8, ["modelValue", "options", "placeholder", "disabled"]),
error.value ? (openBlock(), createBlock(unref(script$3), {
key: 0,
severity: "error"
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(error.value), 1)
]),
_: 1
})) : createCommentVNode("", true)
]),
createBaseVNode("footer", _hoisted_8, [
createVNode(unref(script$4), {
label: _ctx.$t("userSelect.next"),
onClick: login
}, null, 8, ["label"])
])
])
])
]);
};
}
});
export {
_sfc_main as default
};
//# sourceMappingURL=UserSelectView-D1x2NjYS.js.map

1
comfy/web/assets/UserSelectView-D1x2NjYS.js.map generated vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"UserSelectView-D1x2NjYS.js","sources":["../../src/views/UserSelectView.vue"],"sourcesContent":["<template>\n <div\n id=\"comfy-user-selection\"\n class=\"font-sans flex flex-col items-center h-screen m-0 text-neutral-300 bg-neutral-900 dark-theme pointer-events-auto\"\n >\n <main\n class=\"mt-[5vh] 2xl:mt-[20vh] min-w-84 relative rounded-lg bg-[var(--comfy-menu-bg)] p-5 px-10 shadow-lg\"\n >\n <h1 class=\"my-2.5 mb-7 font-normal\">ComfyUI</h1>\n <form class=\"flex w-full flex-col items-center\">\n <div class=\"flex w-full flex-col gap-2\">\n <label for=\"new-user-input\">{{ $t('userSelect.newUser') }}:</label>\n <InputText\n id=\"new-user-input\"\n v-model=\"newUsername\"\n :placeholder=\"$t('userSelect.enterUsername')\"\n />\n </div>\n <Divider />\n <div class=\"flex w-full flex-col gap-2\">\n <label for=\"existing-user-select\"\n >{{ $t('userSelect.existingUser') }}:</label\n >\n <Select\n v-model=\"selectedUser\"\n class=\"w-full\"\n inputId=\"existing-user-select\"\n :options=\"userStore.users\"\n option-label=\"username\"\n :placeholder=\"$t('userSelect.selectUser')\"\n :disabled=\"createNewUser\"\n />\n <Message v-if=\"error\" severity=\"error\">{{ error }}</Message>\n </div>\n <footer class=\"mt-5\">\n <Button :label=\"$t('userSelect.next')\" @click=\"login\" />\n </footer>\n </form>\n </main>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport Button from 'primevue/button'\nimport Divider from 'primevue/divider'\nimport InputText from 'primevue/inputtext'\nimport Select from 'primevue/select'\nimport Message from 'primevue/message'\nimport { User, useUserStore } from '@/stores/userStore'\nimport { useRouter } from 'vue-router'\nimport { computed, onMounted, ref } from 'vue'\n\nconst userStore = useUserStore()\nconst router = useRouter()\n\nconst selectedUser = ref<User | null>(null)\nconst newUsername = ref('')\nconst loginError = ref('')\n\nconst createNewUser = computed(() => newUsername.value.trim() !== '')\nconst newUserExistsError = computed(() => {\n return userStore.users.find((user) => user.username === newUsername.value)\n ? `User \"${newUsername.value}\" already exists`\n : ''\n})\nconst error = computed(() => newUserExistsError.value || loginError.value)\n\nconst login = async () => {\n try {\n const user = createNewUser.value\n ? await userStore.createUser(newUsername.value)\n : selectedUser.value\n\n if (!user) {\n throw new Error('No user selected')\n }\n\n userStore.login(user)\n router.push('/')\n } catch (err) {\n loginError.value = err.message ?? JSON.stringify(err)\n }\n}\n\nonMounted(async () => {\n if (!userStore.initialized) {\n await userStore.initialize()\n }\n})\n</script>\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAoDA,UAAM,YAAY,aAAa;AAC/B,UAAM,SAAS,UAAU;AAEnB,UAAA,eAAe,IAAiB,IAAI;AACpC,UAAA,cAAc,IAAI,EAAE;AACpB,UAAA,aAAa,IAAI,EAAE;AAEzB,UAAM,gBAAgB,SAAS,MAAM,YAAY,MAAM,WAAW,EAAE;AAC9D,UAAA,qBAAqB,SAAS,MAAM;AACxC,aAAO,UAAU,MAAM,KAAK,CAAC,SAAS,KAAK,aAAa,YAAY,KAAK,IACrE,SAAS,YAAY,KAAK,qBAC1B;AAAA,IAAA,CACL;AACD,UAAM,QAAQ,SAAS,MAAM,mBAAmB,SAAS,WAAW,KAAK;AAEzE,UAAM,QAAQ,mCAAY;AACpB,UAAA;AACI,cAAA,OAAO,cAAc,QACvB,MAAM,UAAU,WAAW,YAAY,KAAK,IAC5C,aAAa;AAEjB,YAAI,CAAC,MAAM;AACH,gBAAA,IAAI,MAAM,kBAAkB;AAAA,QAAA;AAGpC,kBAAU,MAAM,IAAI;AACpB,eAAO,KAAK,GAAG;AAAA,eACR,KAAK;AACZ,mBAAW,QAAQ,IAAI,WAAW,KAAK,UAAU,GAAG;AAAA,MAAA;AAAA,IAExD,GAfc;AAiBd,cAAU,YAAY;AAChB,UAAA,CAAC,UAAU,aAAa;AAC1B,cAAM,UAAU,WAAW;AAAA,MAAA;AAAA,IAC7B,CACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}

View File

@ -1 +0,0 @@
{"version":3,"file":"WelcomeView-C4D1cggT.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}

View File

@ -1,17 +1,16 @@
<<<<<<<< HEAD:comfy/web/assets/WelcomeView-CsOBuA3U.js
import { d as defineComponent, g as openBlock, h as createElementBlock, A as createBaseVNode, a4 as toDisplayString, i as createVNode, z as unref, D as script, _ as _export_sfc } from "./index-bi78Y1IN.js";
========
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
import { d as defineComponent, g as openBlock, h as createElementBlock, A as createBaseVNode, a6 as toDisplayString, i as createVNode, z as unref, D as script, P as pushScopeId, Q as popScopeId, _ as _export_sfc } from "./index-CoOvI8ZH.js";
const _withScopeId = /* @__PURE__ */ __name((n) => (pushScopeId("data-v-12b8b11b"), n = n(), popScopeId(), n), "_withScopeId");
>>>>>>>> 0fd4e6c7787daa922cb0d9bd1241b276b39ce2c5:comfy/web/assets/WelcomeView-C4D1cggT.js
import { a as defineComponent, bQ as useRouter, f as openBlock, g as createElementBlock, A as createBaseVNode, a6 as toDisplayString, h as createVNode, z as unref, D as script, _ as _export_sfc } from "./index-BQYg0VNJ.js";
const _hoisted_1 = { class: "font-sans flex flex-col justify-center items-center h-screen m-0 text-neutral-300 bg-neutral-900 dark-theme pointer-events-auto" };
const _hoisted_2 = { class: "flex flex-col items-center justify-center gap-8 p-8" };
const _hoisted_3 = { class: "animated-gradient-text text-glow select-none" };
const _sfc_main = /* @__PURE__ */ defineComponent({
__name: "WelcomeView",
setup(__props) {
const router = useRouter();
const navigateTo = /* @__PURE__ */ __name((path) => {
router.push(path);
}, "navigateTo");
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", _hoisted_1, [
createBaseVNode("div", _hoisted_2, [
@ -22,7 +21,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
iconPos: "right",
size: "large",
rounded: "",
onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$router.push("/install")),
onClick: _cache[0] || (_cache[0] = ($event) => navigateTo("/install")),
class: "p-4 text-lg fade-in-up"
}, null, 8, ["label"])
])
@ -30,12 +29,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
};
}
});
const WelcomeView = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-12b8b11b"]]);
const WelcomeView = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-c4d014c5"]]);
export {
WelcomeView as default
};
<<<<<<<< HEAD:comfy/web/assets/WelcomeView-CsOBuA3U.js
//# sourceMappingURL=WelcomeView-CsOBuA3U.js.map
========
//# sourceMappingURL=WelcomeView-C4D1cggT.js.map
>>>>>>>> 0fd4e6c7787daa922cb0d9bd1241b276b39ce2c5:comfy/web/assets/WelcomeView-C4D1cggT.js
//# sourceMappingURL=WelcomeView-C5iZ_tHc.js.map

1
comfy/web/assets/WelcomeView-C5iZ_tHc.js.map generated vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"WelcomeView-C5iZ_tHc.js","sources":["../../src/views/WelcomeView.vue"],"sourcesContent":["<template>\n <div\n class=\"font-sans flex flex-col justify-center items-center h-screen m-0 text-neutral-300 bg-neutral-900 dark-theme pointer-events-auto\"\n >\n <div class=\"flex flex-col items-center justify-center gap-8 p-8\">\n <!-- Header -->\n <h1 class=\"animated-gradient-text text-glow select-none\">\n {{ $t('welcome.title') }}\n </h1>\n\n <!-- Get Started Button -->\n <Button\n :label=\"$t('welcome.getStarted')\"\n icon=\"pi pi-arrow-right\"\n iconPos=\"right\"\n size=\"large\"\n rounded\n @click=\"navigateTo('/install')\"\n class=\"p-4 text-lg fade-in-up\"\n />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport Button from 'primevue/button'\nimport { useRouter } from 'vue-router'\n\nconst router = useRouter()\nconst navigateTo = (path: string) => {\n router.push(path)\n}\n</script>\n\n<style scoped>\n.animated-gradient-text {\n @apply font-bold;\n font-size: clamp(2rem, 8vw, 4rem);\n background: linear-gradient(to right, #12c2e9, #c471ed, #f64f59, #12c2e9);\n background-size: 300% auto;\n background-clip: text;\n -webkit-background-clip: text;\n -webkit-text-fill-color: transparent;\n animation: gradient 8s linear infinite;\n}\n\n.text-glow {\n filter: drop-shadow(0 0 8px rgba(255, 255, 255, 0.3));\n}\n\n@keyframes gradient {\n 0% {\n background-position: 0% center;\n }\n\n 100% {\n background-position: 300% center;\n }\n}\n\n.fade-in-up {\n animation: fadeInUp 1.5s ease-out;\n animation-fill-mode: both;\n}\n\n@keyframes fadeInUp {\n 0% {\n opacity: 0;\n transform: translateY(20px);\n }\n\n 100% {\n opacity: 1;\n transform: translateY(0);\n }\n}\n</style>\n"],"names":[],"mappings":";;;;;;;;;AA4BA,UAAM,SAAS,UAAU;AACnB,UAAA,aAAa,wBAAC,SAAiB;AACnC,aAAO,KAAK,IAAI;AAAA,IAClB,GAFmB;;;;;;;;;;;;;;;;;;;;"}

View File

@ -1 +0,0 @@
{"version":3,"file":"WelcomeView-CsOBuA3U.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;"}

View File

@ -1,5 +1,5 @@
.animated-gradient-text[data-v-12b8b11b] {
.animated-gradient-text[data-v-c4d014c5] {
font-weight: 700;
font-size: clamp(2rem, 8vw, 4rem);
background: linear-gradient(to right, #12c2e9, #c471ed, #f64f59, #12c2e9);
@ -7,12 +7,12 @@
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
animation: gradient-12b8b11b 8s linear infinite;
animation: gradient-c4d014c5 8s linear infinite;
}
.text-glow[data-v-12b8b11b] {
.text-glow[data-v-c4d014c5] {
filter: drop-shadow(0 0 8px rgba(255, 255, 255, 0.3));
}
@keyframes gradient-12b8b11b {
@keyframes gradient-c4d014c5 {
0% {
background-position: 0% center;
}
@ -20,11 +20,11 @@
background-position: 300% center;
}
}
.fade-in-up[data-v-12b8b11b] {
animation: fadeInUp-12b8b11b 1.5s ease-out;
.fade-in-up[data-v-c4d014c5] {
animation: fadeInUp-c4d014c5 1.5s ease-out;
animation-fill-mode: both;
}
@keyframes fadeInUp-12b8b11b {
@keyframes fadeInUp-c4d014c5 {
0% {
opacity: 0;
transform: translateY(20px);

1
comfy/web/assets/images/Git-Logo-White.svg generated vendored Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="292" height="92pt" viewBox="0 0 219 92"><defs><clipPath id="a"><path d="M159 .79h25V69h-25Zm0 0"/></clipPath><clipPath id="b"><path d="M183 9h35.371v60H183Zm0 0"/></clipPath><clipPath id="c"><path d="M0 .79h92V92H0Zm0 0"/></clipPath></defs><path style="stroke:none;fill-rule:nonzero;fill:#fff;fill-opacity:1" d="M130.871 31.836c-4.785 0-8.351 2.352-8.351 8.008 0 4.261 2.347 7.222 8.093 7.222 4.871 0 8.18-2.867 8.18-7.398 0-5.133-2.961-7.832-7.922-7.832Zm-9.57 39.95c-1.133 1.39-2.262 2.87-2.262 4.612 0 3.48 4.434 4.524 10.527 4.524 5.051 0 11.926-.352 11.926-5.043 0-2.793-3.308-2.965-7.488-3.227Zm25.761-39.688c1.563 2.004 3.22 4.789 3.22 8.793 0 9.656-7.571 15.316-18.536 15.316-2.789 0-5.312-.348-6.879-.785l-2.87 4.613 8.526.52c15.059.96 23.934 1.398 23.934 12.968 0 10.008-8.789 15.665-23.934 15.665-15.75 0-21.757-4.004-21.757-10.88 0-3.917 1.742-6 4.789-8.878-2.875-1.211-3.828-3.387-3.828-5.739 0-1.914.953-3.656 2.523-5.312 1.566-1.652 3.305-3.305 5.395-5.219-4.262-2.09-7.485-6.617-7.485-13.058 0-10.008 6.613-16.88 19.93-16.88 3.742 0 6.004.344 8.008.872h16.972v7.394l-8.007.61"/><g clip-path="url(#a)"><path style="stroke:none;fill-rule:nonzero;fill:#fff;fill-opacity:1" d="M170.379 16.281c-4.961 0-7.832-2.87-7.832-7.836 0-4.957 2.871-7.656 7.832-7.656 5.05 0 7.922 2.7 7.922 7.656 0 4.965-2.871 7.836-7.922 7.836Zm-11.227 52.305V61.71l4.438-.606c1.219-.175 1.394-.437 1.394-1.746V33.773c0-.953-.261-1.566-1.132-1.824l-4.7-1.656.957-7.047h18.016V59.36c0 1.399.086 1.57 1.395 1.746l4.437.606v6.875h-24.805"/></g><g clip-path="url(#b)"><path style="stroke:none;fill-rule:nonzero;fill:#fff;fill-opacity:1" d="M218.371 65.21c-3.742 1.825-9.223 3.481-14.187 3.481-10.356 0-14.27-4.175-14.27-14.015V31.879c0-.524 0-.871-.7-.871h-6.093v-7.746c7.664-.871 10.707-4.703 11.664-14.188h8.27v12.36c0 .609 0 .87.695.87h12.27v8.704h-12.965v20.797c0 5.136 1.218 7.136 5.918 7.136 2.437 0 4.96-.609 7.047-1.39l2.351 7.66"/></g><g clip-path="url(#c)"><path style="stroke:none;fill-rule:nonzero;fill:#fff;fill-opacity:1" d="M89.422 42.371 49.629 2.582a5.868 5.868 0 0 0-8.3 0l-8.263 8.262 10.48 10.484a6.965 6.965 0 0 1 7.173 1.668 6.98 6.98 0 0 1 1.656 7.215l10.102 10.105a6.963 6.963 0 0 1 7.214 1.657 6.976 6.976 0 0 1 0 9.875 6.98 6.98 0 0 1-9.879 0 6.987 6.987 0 0 1-1.519-7.594l-9.422-9.422v24.793a6.979 6.979 0 0 1 1.848 1.32 6.988 6.988 0 0 1 0 9.88c-2.73 2.726-7.153 2.726-9.875 0a6.98 6.98 0 0 1 0-9.88 6.893 6.893 0 0 1 2.285-1.523V34.398a6.893 6.893 0 0 1-2.285-1.523 6.988 6.988 0 0 1-1.508-7.637L29.004 14.902 1.719 42.187a5.868 5.868 0 0 0 0 8.301l39.793 39.793a5.868 5.868 0 0 0 8.3 0l39.61-39.605a5.873 5.873 0 0 0 0-8.305"/></g></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
comfy/web/assets/images/sad_girl.png generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

File diff suppressed because one or more lines are too long

1
comfy/web/assets/index-BQYg0VNJ.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -68,14 +68,14 @@
background-color: rgb(234 179 8 / var(--tw-bg-opacity, 1))
}
.search-box-input[data-v-f28148d1] {
.search-box-input[data-v-e10998c1] {
width: 100%;
padding-left: 36px;
}
.search-box-input.with-filter[data-v-f28148d1] {
.search-box-input.with-filter[data-v-e10998c1] {
padding-right: 36px;
}
.p-button.p-inputicon[data-v-f28148d1] {
.p-button.p-inputicon[data-v-e10998c1] {
padding: 0;
width: auto;
border: none !important;
@ -317,17 +317,10 @@
position: relative;
}
<<<<<<<< HEAD:comfy/web/assets/index-BObQyxMu.css
[data-v-2d6a9f91] .p-terminal .xterm {
overflow-x: auto;
}
[data-v-2d6a9f91] .p-terminal .xterm-screen {
========
[data-v-4f7907e3] .p-terminal .xterm {
overflow-x: auto;
}
[data-v-4f7907e3] .p-terminal .xterm-screen {
>>>>>>>> 0fd4e6c7787daa922cb0d9bd1241b276b39ce2c5:comfy/web/assets/index-U_o182q3.css
background-color: black;
overflow-y: hidden;
}
@ -340,10 +333,10 @@
overflow-y: hidden;
}
[data-v-e8581ca7] .p-terminal .xterm {
[data-v-36dec989] .p-terminal .xterm {
overflow-x: auto;
}
[data-v-e8581ca7] .p-terminal .xterm-screen {
[data-v-36dec989] .p-terminal .xterm-screen {
background-color: black;
overflow-y: hidden;
}
@ -352,7 +345,7 @@
padding-top: 0px !important;
}
.settings-container[data-v-dbb35a0c] {
.settings-container[data-v-5a032e0c] {
display: flex;
height: 70vh;
width: 60vw;
@ -360,21 +353,21 @@
overflow: hidden;
}
@media (max-width: 768px) {
.settings-container[data-v-dbb35a0c] {
.settings-container[data-v-5a032e0c] {
flex-direction: column;
height: auto;
}
.settings-sidebar[data-v-dbb35a0c] {
.settings-sidebar[data-v-5a032e0c] {
width: 100%;
}
}
/* Show a separator line above the Keybinding tab */
/* This indicates the start of custom setting panels */
.settings-sidebar[data-v-dbb35a0c] .p-listbox-option[aria-label='Keybinding'] {
.settings-sidebar[data-v-5a032e0c] .p-listbox-option[aria-label='Keybinding'] {
position: relative;
}
.settings-sidebar[data-v-dbb35a0c] .p-listbox-option[aria-label='Keybinding']::before {
.settings-sidebar[data-v-5a032e0c] .p-listbox-option[aria-label='Keybinding']::before {
position: absolute;
top: 0px;
left: 0px;
@ -384,25 +377,25 @@
border-top: 1px solid var(--p-divider-border-color);
}
.pi-cog[data-v-f3b37ea3] {
.pi-cog[data-v-43089afc] {
font-size: 1.25rem;
margin-right: 0.5rem;
}
.version-tag[data-v-f3b37ea3] {
.version-tag[data-v-43089afc] {
margin-left: 0.5rem;
}
.comfy-error-report[data-v-db438f98] {
.comfy-error-report[data-v-5c200f18] {
display: flex;
flex-direction: column;
gap: 1rem;
}
.action-container[data-v-db438f98] {
.action-container[data-v-5c200f18] {
display: flex;
gap: 1rem;
justify-content: flex-end;
}
.wrapper-pre[data-v-db438f98] {
.wrapper-pre[data-v-5c200f18] {
white-space: pre-wrap;
word-wrap: break-word;
}
@ -414,6 +407,10 @@
[data-v-98830966] .p-card-subtitle {
text-align: center;
}
.prompt-dialog-content[data-v-abaaab2c] {
white-space: pre-wrap;
}
.mdi.rotate270::before {
transform: rotate(270deg);
}
@ -743,7 +740,7 @@
word-break: break-all;
}
[data-v-b7c3d32e] .tree-explorer-node-label {
[data-v-82fb18cb] .tree-explorer-node-label {
width: 100%;
display: flex;
align-items: center;
@ -756,10 +753,10 @@
* 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.
*/
[data-v-b7c3d32e] .p-tree-node-content:has(.tree-folder) {
[data-v-82fb18cb] .p-tree-node-content:has(.tree-folder) {
position: relative;
}
[data-v-b7c3d32e] .p-tree-node-content:has(.tree-folder.can-drop)::after {
[data-v-82fb18cb] .p-tree-node-content:has(.tree-folder.can-drop)::after {
content: '';
position: absolute;
top: 0;
@ -849,23 +846,23 @@
vertical-align: top;
}
[data-v-827f7782] .pi-fake-spacer {
[data-v-31a92a0f] .pi-fake-spacer {
height: 1px;
width: 16px;
}
.slot_row[data-v-4b126b34] {
.slot_row[data-v-e86c3783] {
padding: 2px;
}
/* Original N-Sidebar styles */
._sb_dot[data-v-4b126b34] {
._sb_dot[data-v-e86c3783] {
width: 8px;
height: 8px;
border-radius: 50%;
background-color: grey;
}
.node_header[data-v-4b126b34] {
.node_header[data-v-e86c3783] {
line-height: 1;
padding: 8px 13px 7px;
margin-bottom: 5px;
@ -875,37 +872,37 @@
display: flex;
align-items: center;
}
.headdot[data-v-4b126b34] {
.headdot[data-v-e86c3783] {
width: 10px;
height: 10px;
float: inline-start;
margin-right: 8px;
}
.IMAGE[data-v-4b126b34] {
.IMAGE[data-v-e86c3783] {
background-color: #64b5f6;
}
.VAE[data-v-4b126b34] {
.VAE[data-v-e86c3783] {
background-color: #ff6e6e;
}
.LATENT[data-v-4b126b34] {
.LATENT[data-v-e86c3783] {
background-color: #ff9cf9;
}
.MASK[data-v-4b126b34] {
.MASK[data-v-e86c3783] {
background-color: #81c784;
}
.CONDITIONING[data-v-4b126b34] {
.CONDITIONING[data-v-e86c3783] {
background-color: #ffa931;
}
.CLIP[data-v-4b126b34] {
.CLIP[data-v-e86c3783] {
background-color: #ffd500;
}
.MODEL[data-v-4b126b34] {
.MODEL[data-v-e86c3783] {
background-color: #b39ddb;
}
.CONTROL_NET[data-v-4b126b34] {
.CONTROL_NET[data-v-e86c3783] {
background-color: #a5d6a7;
}
._sb_node_preview[data-v-4b126b34] {
._sb_node_preview[data-v-e86c3783] {
background-color: var(--comfy-menu-bg);
font-family: 'Open Sans', sans-serif;
font-size: small;
@ -922,7 +919,7 @@
font-size: 12px;
padding-bottom: 10px;
}
._sb_node_preview ._sb_description[data-v-4b126b34] {
._sb_node_preview ._sb_description[data-v-e86c3783] {
margin: 10px;
padding: 6px;
background: var(--border-color);
@ -932,7 +929,7 @@
font-size: 0.9rem;
word-break: break-word;
}
._sb_table[data-v-4b126b34] {
._sb_table[data-v-e86c3783] {
display: grid;
grid-column-gap: 10px;
@ -940,7 +937,7 @@
width: 100%;
/* Imposta la larghezza della tabella al 100% del contenitore */
}
._sb_row[data-v-4b126b34] {
._sb_row[data-v-e86c3783] {
display: grid;
grid-template-columns: 10px 1fr 1fr 1fr 10px;
grid-column-gap: 10px;
@ -948,10 +945,10 @@
padding-left: 9px;
padding-right: 9px;
}
._sb_row_string[data-v-4b126b34] {
._sb_row_string[data-v-e86c3783] {
grid-template-columns: 10px 1fr 1fr 10fr 1fr;
}
._sb_col[data-v-4b126b34] {
._sb_col[data-v-e86c3783] {
border: 0px solid #000;
display: flex;
align-items: flex-end;
@ -960,10 +957,10 @@
align-content: flex-start;
justify-content: flex-end;
}
._sb_inherit[data-v-4b126b34] {
._sb_inherit[data-v-e86c3783] {
display: inherit;
}
._long_field[data-v-4b126b34] {
._long_field[data-v-e86c3783] {
background: var(--bg-color);
border: 2px solid var(--border-color);
margin: 5px 5px 0 5px;
@ -971,45 +968,45 @@
line-height: 1.7;
text-wrap: nowrap;
}
._sb_arrow[data-v-4b126b34] {
._sb_arrow[data-v-e86c3783] {
color: var(--fg-color);
}
._sb_preview_badge[data-v-4b126b34] {
._sb_preview_badge[data-v-e86c3783] {
text-align: center;
background: var(--comfy-input-bg);
font-weight: bold;
color: var(--error-text);
}
.node-lib-node-container[data-v-90dfee08] {
.node-lib-node-container[data-v-20bd95eb] {
height: 100%;
width: 100%
}
.p-selectbutton .p-button[data-v-91077f2a] {
.p-selectbutton .p-button[data-v-29268946] {
padding: 0.5rem;
}
.p-selectbutton .p-button .pi[data-v-91077f2a] {
.p-selectbutton .p-button .pi[data-v-29268946] {
font-size: 1.5rem;
}
.field[data-v-91077f2a] {
.field[data-v-29268946] {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.color-picker-container[data-v-91077f2a] {
.color-picker-container[data-v-29268946] {
display: flex;
align-items: center;
gap: 0.5rem;
}
._content[data-v-e7b35fd9] {
._content[data-v-2fc57c5b] {
display: flex;
flex-direction: column
}
._content[data-v-e7b35fd9] > :not([hidden]) ~ :not([hidden]) {
._content[data-v-2fc57c5b] > :not([hidden]) ~ :not([hidden]) {
--tw-space-y-reverse: 0;
@ -1017,7 +1014,7 @@
margin-bottom: calc(0.5rem * var(--tw-space-y-reverse))
}
._footer[data-v-e7b35fd9] {
._footer[data-v-2fc57c5b] {
display: flex;
@ -1028,10 +1025,10 @@
padding-top: 1rem
}
.comfy-image-wrap[data-v-9bc23daf] {
.comfy-image-wrap[data-v-ffe66146] {
display: contents;
}
.comfy-image-blur[data-v-9bc23daf] {
.comfy-image-blur[data-v-ffe66146] {
position: absolute;
top: 0;
left: 0;
@ -1040,7 +1037,7 @@
-o-object-fit: cover;
object-fit: cover;
}
.comfy-image-main[data-v-9bc23daf] {
.comfy-image-main[data-v-ffe66146] {
width: 100%;
height: 100%;
-o-object-fit: cover;
@ -1049,19 +1046,19 @@
object-position: center;
z-index: 1;
}
.contain .comfy-image-wrap[data-v-9bc23daf] {
.contain .comfy-image-wrap[data-v-ffe66146] {
position: relative;
width: 100%;
height: 100%;
}
.contain .comfy-image-main[data-v-9bc23daf] {
.contain .comfy-image-main[data-v-ffe66146] {
-o-object-fit: contain;
object-fit: contain;
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
position: absolute;
}
.broken-image-placeholder[data-v-9bc23daf] {
.broken-image-placeholder[data-v-ffe66146] {
display: flex;
flex-direction: column;
align-items: center;
@ -1070,7 +1067,7 @@
height: 100%;
margin: 2rem;
}
.broken-image-placeholder i[data-v-9bc23daf] {
.broken-image-placeholder i[data-v-ffe66146] {
font-size: 3rem;
margin-bottom: 0.5rem;
}
@ -1171,17 +1168,17 @@ img.galleria-image {
z-index: 1;
}
.scroll-container[data-v-93f5af09] {
.scroll-container[data-v-375f3c50] {
height: 100%;
overflow-y: auto;
}
.scroll-container[data-v-93f5af09]::-webkit-scrollbar {
.scroll-container[data-v-375f3c50]::-webkit-scrollbar {
width: 1px;
}
.scroll-container[data-v-93f5af09]::-webkit-scrollbar-thumb {
.scroll-container[data-v-375f3c50]::-webkit-scrollbar-thumb {
background-color: transparent;
}
.queue-grid[data-v-93f5af09] {
.queue-grid[data-v-375f3c50] {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
padding: 0.5rem;
@ -2023,12 +2020,22 @@ img.galleria-image {
.z-\[1000\]{
z-index: 1000;
}
.col-start-1{
grid-column-start: 1;
}
.row-start-1{
grid-row-start: 1;
}
.m-0{
margin: 0px;
}
.m-2{
margin: 0.5rem;
}
.mx-0{
margin-left: 0px;
margin-right: 0px;
}
.mx-1{
margin-left: 0.25rem;
margin-right: 0.25rem;
@ -2041,6 +2048,10 @@ img.galleria-image {
margin-left: 1.5rem;
margin-right: 1.5rem;
}
.mx-auto{
margin-left: auto;
margin-right: auto;
}
.my-0{
margin-top: 0px;
margin-bottom: 0px;
@ -2049,6 +2060,10 @@ img.galleria-image {
margin-top: 0.25rem;
margin-bottom: 0.25rem;
}
.my-2\.5{
margin-top: 0.625rem;
margin-bottom: 0.625rem;
}
.my-4{
margin-top: 1rem;
margin-bottom: 1rem;
@ -2065,6 +2080,9 @@ img.galleria-image {
.mb-6{
margin-bottom: 1.5rem;
}
.mb-7{
margin-bottom: 1.75rem;
}
.ml-2{
margin-left: 0.5rem;
}
@ -2089,9 +2107,15 @@ img.galleria-image {
.mt-2{
margin-top: 0.5rem;
}
.mt-24{
margin-top: 6rem;
}
.mt-4{
margin-top: 1rem;
}
.mt-5{
margin-top: 1.25rem;
}
.mt-\[5vh\]{
margin-top: 5vh;
}
@ -2180,6 +2204,12 @@ img.galleria-image {
.w-full{
width: 100%;
}
.w-screen{
width: 100vw;
}
.min-w-84{
min-width: 22rem;
}
.min-w-96{
min-width: 26rem;
}
@ -2192,6 +2222,9 @@ img.galleria-image {
.max-w-full{
max-width: 100%;
}
.max-w-screen-sm{
max-width: 640px;
}
.flex-1{
flex: 1 1 0%;
}
@ -2204,6 +2237,9 @@ img.galleria-image {
.flex-grow{
flex-grow: 1;
}
.flex-grow-0{
flex-grow: 0;
}
.grow{
flex-grow: 1;
}
@ -2232,6 +2268,9 @@ img.galleria-image {
.resize{
resize: both;
}
.list-inside{
list-style-position: inside;
}
.list-disc{
list-style-type: disc;
}
@ -2241,6 +2280,9 @@ img.galleria-image {
.flex-row{
flex-direction: row;
}
.flex-row-reverse{
flex-direction: row-reverse;
}
.flex-col{
flex-direction: column;
}
@ -2250,6 +2292,12 @@ img.galleria-image {
.flex-nowrap{
flex-wrap: nowrap;
}
.place-content-center{
place-content: center;
}
.place-items-center{
place-items: center;
}
.content-around{
align-content: space-around;
}
@ -2296,6 +2344,11 @@ img.galleria-image {
margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));
margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));
}
.space-y-4 > :not([hidden]) ~ :not([hidden]){
--tw-space-y-reverse: 0;
margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse)));
margin-bottom: calc(1rem * var(--tw-space-y-reverse));
}
.justify-self-end{
justify-self: end;
}
@ -2350,6 +2403,9 @@ img.galleria-image {
.border-none{
border-style: none;
}
.bg-\[var\(--comfy-menu-bg\)\]{
background-color: var(--comfy-menu-bg);
}
.bg-\[var\(--p-tree-background\)\]{
background-color: var(--p-tree-background);
}
@ -2365,6 +2421,10 @@ img.galleria-image {
--tw-bg-opacity: 1;
background-color: rgb(150 206 76 / var(--tw-bg-opacity, 1));
}
.bg-neutral-300{
--tw-bg-opacity: 1;
background-color: rgb(212 212 212 / var(--tw-bg-opacity, 1));
}
.bg-neutral-800{
--tw-bg-opacity: 1;
background-color: rgb(38 38 38 / var(--tw-bg-opacity, 1));
@ -2387,6 +2447,18 @@ img.galleria-image {
.bg-opacity-50{
--tw-bg-opacity: 0.5;
}
.bg-\[url\(\'\/assets\/images\/Git-Logo-White\.svg\'\)\]{
background-image: url('../assets/images/Git-Logo-White.svg');
}
.bg-right-top{
background-position: right top;
}
.bg-no-repeat{
background-repeat: no-repeat;
}
.bg-origin-padding{
background-origin: padding-box;
}
.object-cover{
-o-object-fit: cover;
object-fit: cover;
@ -2406,6 +2478,9 @@ img.galleria-image {
.p-4{
padding: 1rem;
}
.p-5{
padding: 1.25rem;
}
.p-8{
padding: 2rem;
}
@ -2413,6 +2488,10 @@ img.galleria-image {
padding-left: 0px;
padding-right: 0px;
}
.px-10{
padding-left: 2.5rem;
padding-right: 2.5rem;
}
.px-2{
padding-left: 0.5rem;
padding-right: 0.5rem;
@ -2432,6 +2511,9 @@ img.galleria-image {
.pb-0{
padding-bottom: 0px;
}
.pl-4{
padding-left: 1rem;
}
.pl-6{
padding-left: 1.5rem;
}
@ -2462,6 +2544,9 @@ img.galleria-image {
.text-2xl{
font-size: 1.5rem;
}
.text-4xl{
font-size: 2.25rem;
}
.text-lg{
font-size: 1.125rem;
}
@ -2483,6 +2568,9 @@ img.galleria-image {
.font-medium{
font-weight: 500;
}
.font-normal{
font-weight: 400;
}
.font-semibold{
font-weight: 600;
}
@ -2500,6 +2588,10 @@ img.galleria-image {
--tw-text-opacity: 1;
color: rgb(203 213 224 / var(--tw-text-opacity, 1));
}
.text-green-500{
--tw-text-opacity: 1;
color: rgb(150 206 76 / var(--tw-text-opacity, 1));
}
.text-highlight{
color: var(--p-primary-color);
}
@ -2522,12 +2614,29 @@ img.galleria-image {
--tw-text-opacity: 1;
color: rgb(163 163 163 / var(--tw-text-opacity, 1));
}
.text-neutral-800{
--tw-text-opacity: 1;
color: rgb(38 38 38 / var(--tw-text-opacity, 1));
}
.text-neutral-900{
--tw-text-opacity: 1;
color: rgb(23 23 23 / var(--tw-text-opacity, 1));
}
.text-red-500{
--tw-text-opacity: 1;
color: rgb(239 68 68 / var(--tw-text-opacity, 1));
}
.no-underline{
text-decoration-line: none;
}
.opacity-0{
opacity: 0;
}
.shadow-lg{
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.outline{
outline-style: solid;
}
@ -2587,6 +2696,7 @@ img.galleria-image {
--fg-color: #000;
--bg-color: #fff;
--comfy-menu-bg: #353535;
--comfy-menu-secondary-bg: #292929;
--comfy-input-bg: #222;
--input-text: #ddd;
--descrip-text: #999;
@ -2757,8 +2867,8 @@ body {
}
.comfy-modal select,
.comfy-modal input[type=button],
.comfy-modal input[type=checkbox] {
.comfy-modal input[type='button'],
.comfy-modal input[type='checkbox'] {
margin: 3px 3px 3px 4px;
}
@ -2872,8 +2982,8 @@ span.drag-handle {
padding: 3px 4px;
cursor: move;
vertical-align: middle;
margin-top: -.4em;
margin-left: -.2em;
margin-top: -0.4em;
margin-left: -0.2em;
font-size: 12px;
font-family: sans-serif;
letter-spacing: 2px;
@ -2940,11 +3050,11 @@ button.comfy-queue-btn {
z-index: 99;
}
.comfy-modal.comfy-settings input[type="range"] {
.comfy-modal.comfy-settings input[type='range'] {
vertical-align: middle;
}
.comfy-modal.comfy-settings input[type="range"] + input[type="number"] {
.comfy-modal.comfy-settings input[type='range'] + input[type='number'] {
width: 3.5em;
}
@ -2975,7 +3085,7 @@ button.comfy-queue-btn {
.comfy-menu span.drag-handle {
display: none;
}
.comfy-menu-queue-size {
flex: unset;
}
@ -3009,7 +3119,9 @@ button.comfy-queue-btn {
padding-right: 8px;
}
.graphdialog input, .graphdialog textarea, .graphdialog select {
.graphdialog input,
.graphdialog textarea,
.graphdialog select {
background-color: var(--comfy-input-bg);
border: 2px solid;
border-color: var(--border-color);
@ -3071,7 +3183,8 @@ dialog::backdrop {
text-align: right;
}
#comfy-settings-dialog tbody button, #comfy-settings-dialog table > button {
#comfy-settings-dialog tbody button,
#comfy-settings-dialog table > button {
background-color: var(--bg-color);
border: 1px var(--border-color) solid;
border-radius: 0;
@ -3152,7 +3265,7 @@ dialog::backdrop {
}
.litemenu-entry.has_submenu::after {
content: ">";
content: '>';
position: absolute;
top: 0;
right: 2px;
@ -3166,7 +3279,8 @@ dialog::backdrop {
will-change: transform;
}
.litegraph.litecontextmenu .litemenu-entry:hover:not(.disabled):not(.separator) {
.litegraph.litecontextmenu
.litemenu-entry:hover:not(.disabled):not(.separator) {
background-color: var(--comfy-menu-bg) !important;
filter: brightness(155%);
will-change: transform;

1880
comfy/web/assets/index-Ba5g1c58.js generated vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

1
comfy/web/assets/index-BfiYPlqA.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

106
comfy/web/assets/index-BppSBmxJ.js generated vendored
View File

@ -1,106 +0,0 @@
const IPC_CHANNELS = {
LOADING_PROGRESS: "loading-progress",
IS_PACKAGED: "is-packaged",
RENDERER_READY: "renderer-ready",
RESTART_APP: "restart-app",
REINSTALL: "reinstall",
LOG_MESSAGE: "log-message",
OPEN_DIALOG: "open-dialog",
DOWNLOAD_PROGRESS: "download-progress",
START_DOWNLOAD: "start-download",
PAUSE_DOWNLOAD: "pause-download",
RESUME_DOWNLOAD: "resume-download",
CANCEL_DOWNLOAD: "cancel-download",
DELETE_MODEL: "delete-model",
GET_ALL_DOWNLOADS: "get-all-downloads",
GET_ELECTRON_VERSION: "get-electron-version",
SEND_ERROR_TO_SENTRY: "send-error-to-sentry",
GET_BASE_PATH: "get-base-path",
GET_MODEL_CONFIG_PATH: "get-model-config-path",
OPEN_PATH: "open-path",
OPEN_LOGS_PATH: "open-logs-path",
OPEN_DEV_TOOLS: "open-dev-tools",
TERMINAL_WRITE: "execute-terminal-command",
TERMINAL_RESIZE: "resize-terminal",
TERMINAL_RESTORE: "restore-terminal",
TERMINAL_ON_OUTPUT: "terminal-output",
IS_FIRST_TIME_SETUP: "is-first-time-setup",
GET_SYSTEM_PATHS: "get-system-paths",
VALIDATE_INSTALL_PATH: "validate-install-path",
VALIDATE_COMFYUI_SOURCE: "validate-comfyui-source",
SHOW_DIRECTORY_PICKER: "show-directory-picker",
INSTALL_COMFYUI: "install-comfyui"
};
var ProgressStatus = /* @__PURE__ */ ((ProgressStatus2) => {
ProgressStatus2["INITIAL_STATE"] = "initial-state";
ProgressStatus2["PYTHON_SETUP"] = "python-setup";
ProgressStatus2["STARTING_SERVER"] = "starting-server";
ProgressStatus2["READY"] = "ready";
ProgressStatus2["ERROR"] = "error";
return ProgressStatus2;
})(ProgressStatus || {});
const ProgressMessages = {
[
"initial-state"
/* INITIAL_STATE */
]: "Loading...",
[
"python-setup"
/* PYTHON_SETUP */
]: "Setting up Python Environment...",
[
"starting-server"
/* STARTING_SERVER */
]: "Starting ComfyUI server...",
[
"ready"
/* READY */
]: "Finishing...",
[
"error"
/* ERROR */
]: "Was not able to start ComfyUI. Please check the logs for more details. You can open it from the Help menu. Please report issues to: https://forum.comfy.org"
};
const ELECTRON_BRIDGE_API = "electronAPI";
const SENTRY_URL_ENDPOINT = "https://942cadba58d247c9cab96f45221aa813@o4507954455314432.ingest.us.sentry.io/4508007940685824";
const MigrationItems = [
{
id: "user_files",
label: "User Files",
description: "Settings and user-created workflows"
},
{
id: "models",
label: "Models",
description: "Reference model files from existing ComfyUI installations. (No copy)"
}
// TODO: Decide whether we want to auto-migrate custom nodes, and install their dependencies.
// huchenlei: This is a very essential thing for migration experience.
// {
// id: 'custom_nodes',
// label: 'Custom Nodes',
// description: 'Reference custom node files from existing ComfyUI installations. (No copy)',
// },
];
const DEFAULT_SERVER_ARGS = {
/** The host to use for the ComfyUI server. */
host: "127.0.0.1",
/** The port to use for the ComfyUI server. */
port: 8e3,
// Extra arguments to pass to the ComfyUI server.
extraServerArgs: {}
};
var DownloadStatus = /* @__PURE__ */ ((DownloadStatus2) => {
DownloadStatus2["PENDING"] = "pending";
DownloadStatus2["IN_PROGRESS"] = "in_progress";
DownloadStatus2["COMPLETED"] = "completed";
DownloadStatus2["PAUSED"] = "paused";
DownloadStatus2["ERROR"] = "error";
DownloadStatus2["CANCELLED"] = "cancelled";
return DownloadStatus2;
})(DownloadStatus || {});
export {
MigrationItems as M,
ProgressStatus as P
};
//# sourceMappingURL=index-BppSBmxJ.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,12 +1,7 @@
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
<<<<<<<< HEAD:comfy/web/assets/index-ftUEqmu1.js
import { b6 as script$s, g as openBlock, h as createElementBlock, m as mergeProps, A as createBaseVNode, B as BaseStyle, P as script$t, a4 as toDisplayString, $ as Ripple, t as resolveDirective, v as withDirectives, x as createBlock, J as resolveDynamicComponent, c9 as script$u, l as resolveComponent, C as normalizeClass, au as createSlots, y as withCtx, bw as script$v, bm as script$w, N as Fragment, O as renderList, av as createTextVNode, bc as setAttribute, ba as normalizeProps, p as renderSlot, j as createCommentVNode, ab as script$x, a2 as equals, b7 as script$y, bR as script$z, ca as getFirstFocusableElement, af as OverlayEventBus, a6 as getVNodeProp, ae as resolveFieldData, cb as invokeElementMethod, a0 as getAttribute, cc as getNextElementSibling, W as getOuterWidth, cd as getPreviousElementSibling, D as script$A, aq as script$B, Z as script$C, b9 as script$E, aa as isNotEmpty, bi as withModifiers, U as getOuterHeight, ac as UniqueComponentId, ce as _default, ad as ZIndex, a1 as focus, ah as addStyle, aj as absolutePosition, ak as ConnectedOverlayScrollHandler, al as isTouchDevice, cf as FilterOperator, ap as script$F, cg as FocusTrap, i as createVNode, at as Transition, ch as withKeys, ci as getIndex, s as script$H, cj as isClickable, ck as clearSelection, cl as localeComparator, cm as sort, cn as FilterService, c5 as FilterMatchMode, R as findSingle, bL as findIndexInList, bM as find, co as exportCSV, V as getOffset, cp as getHiddenElementOuterWidth, cq as getHiddenElementOuterHeight, cr as reorderArray, cs as removeClass, ct as addClass, ag as isEmpty, ao as script$I, ar as script$J } from "./index-bi78Y1IN.js";
import { s as script$D, a as script$G } from "./index-bCeMLtLM.js";
========
import { cb as script$s, A as createBaseVNode, g as openBlock, h as createElementBlock, m as mergeProps, B as BaseStyle, R as script$t, a6 as toDisplayString, a1 as Ripple, t as resolveDirective, v as withDirectives, x as createBlock, J as resolveDynamicComponent, cc as script$u, l as resolveComponent, C as normalizeClass, av as createSlots, y as withCtx, by as script$v, bo as script$w, N as Fragment, O as renderList, aw as createTextVNode, be as setAttribute, ad as UniqueComponentId, bc as normalizeProps, p as renderSlot, j as createCommentVNode, a4 as equals, b8 as script$x, bU as script$y, cd as getFirstFocusableElement, ag as OverlayEventBus, a8 as getVNodeProp, af as resolveFieldData, ce as invokeElementMethod, a2 as getAttribute, cf as getNextElementSibling, Y as getOuterWidth, cg as getPreviousElementSibling, D as script$z, ar as script$A, a0 as script$B, bb as script$D, ac as isNotEmpty, bk as withModifiers, W as getOuterHeight, ch as _default, ae as ZIndex, a3 as focus, ai as addStyle, ak as absolutePosition, al as ConnectedOverlayScrollHandler, am as isTouchDevice, ci as FilterOperator, aq as script$E, cj as FocusTrap, i as createVNode, au as Transition, ck as withKeys, cl as getIndex, s as script$G, cm as isClickable, cn as clearSelection, co as localeComparator, cp as sort, cq as FilterService, c6 as FilterMatchMode, V as findSingle, bO as findIndexInList, bP as find, cr as exportCSV, X as getOffset, cs as getHiddenElementOuterWidth, ct as getHiddenElementOuterHeight, cu as reorderArray, cv as getWindowScrollTop, cw as removeClass, cx as addClass, ah as isEmpty, ap as script$H, as as script$I } from "./index-CoOvI8ZH.js";
import { s as script$C, a as script$F } from "./index-D4DWQPPQ.js";
>>>>>>>> 0fd4e6c7787daa922cb0d9bd1241b276b39ce2c5:comfy/web/assets/index-DK6Kev7f.js
import { ba as script$s, f as openBlock, g as createElementBlock, m as mergeProps, A as createBaseVNode, B as BaseStyle, R as script$t, a6 as toDisplayString, a1 as Ripple, t as resolveDirective, v as withDirectives, x as createBlock, M as resolveDynamicComponent, bR as script$u, l as resolveComponent, C as normalizeClass, aw as createSlots, y as withCtx, bz as script$v, bq as script$w, P as Fragment, Q as renderList, ax as createTextVNode, bg as setAttribute, be as normalizeProps, p as renderSlot, i as createCommentVNode, ad as script$x, a4 as equals, bb as script$y, c0 as script$z, cl as getFirstFocusableElement, ah as OverlayEventBus, a8 as getVNodeProp, ag as resolveFieldData, cm as invokeElementMethod, a2 as getAttribute, cn as getNextElementSibling, Y as getOuterWidth, co as getPreviousElementSibling, D as script$A, as as script$B, a0 as script$C, bd as script$E, ac as isNotEmpty, bm as withModifiers, W as getOuterHeight, ae as UniqueComponentId, cp as _default, af as ZIndex, a3 as focus, aj as addStyle, al as absolutePosition, am as ConnectedOverlayScrollHandler, an as isTouchDevice, cq as FilterOperator, ar as script$F, cr as FocusTrap, h as createVNode, av as Transition, cs as withKeys, ct as getIndex, k as script$H, cu as isClickable, cv as clearSelection, cw as localeComparator, cx as sort, cy as FilterService, cg as FilterMatchMode, V as findSingle, bW as findIndexInList, bX as find, cz as exportCSV, X as getOffset, cA as getHiddenElementOuterWidth, cB as getHiddenElementOuterHeight, cC as reorderArray, cD as removeClass, cE as addClass, ai as isEmpty, aq as script$I, at as script$J } from "./index-BQYg0VNJ.js";
import { s as script$D, a as script$G } from "./index-DJqEjTnE.js";
var script$r = {
name: "ArrowDownIcon",
"extends": script$s
@ -8834,8 +8829,4 @@ export {
script$d as a,
script as s
};
<<<<<<<< HEAD:comfy/web/assets/index-ftUEqmu1.js
//# sourceMappingURL=index-ftUEqmu1.js.map
========
//# sourceMappingURL=index-DK6Kev7f.js.map
>>>>>>>> 0fd4e6c7787daa922cb0d9bd1241b276b39ce2c5:comfy/web/assets/index-DK6Kev7f.js
//# sourceMappingURL=index-CMsGQEqY.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

50
comfy/web/assets/index-D4DWQPPQ.js generated vendored
View File

@ -1,50 +0,0 @@
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
import { cb as script$2, A as createBaseVNode, g as openBlock, h as createElementBlock, m as mergeProps } from "./index-CoOvI8ZH.js";
var script$1 = {
name: "BarsIcon",
"extends": script$2
};
var _hoisted_1$1 = /* @__PURE__ */ createBaseVNode("path", {
"fill-rule": "evenodd",
"clip-rule": "evenodd",
d: "M13.3226 3.6129H0.677419C0.497757 3.6129 0.325452 3.54152 0.198411 3.41448C0.0713707 3.28744 0 3.11514 0 2.93548C0 2.75581 0.0713707 2.58351 0.198411 2.45647C0.325452 2.32943 0.497757 2.25806 0.677419 2.25806H13.3226C13.5022 2.25806 13.6745 2.32943 13.8016 2.45647C13.9286 2.58351 14 2.75581 14 2.93548C14 3.11514 13.9286 3.28744 13.8016 3.41448C13.6745 3.54152 13.5022 3.6129 13.3226 3.6129ZM13.3226 7.67741H0.677419C0.497757 7.67741 0.325452 7.60604 0.198411 7.479C0.0713707 7.35196 0 7.17965 0 6.99999C0 6.82033 0.0713707 6.64802 0.198411 6.52098C0.325452 6.39394 0.497757 6.32257 0.677419 6.32257H13.3226C13.5022 6.32257 13.6745 6.39394 13.8016 6.52098C13.9286 6.64802 14 6.82033 14 6.99999C14 7.17965 13.9286 7.35196 13.8016 7.479C13.6745 7.60604 13.5022 7.67741 13.3226 7.67741ZM0.677419 11.7419H13.3226C13.5022 11.7419 13.6745 11.6706 13.8016 11.5435C13.9286 11.4165 14 11.2442 14 11.0645C14 10.8848 13.9286 10.7125 13.8016 10.5855C13.6745 10.4585 13.5022 10.3871 13.3226 10.3871H0.677419C0.497757 10.3871 0.325452 10.4585 0.198411 10.5855C0.0713707 10.7125 0 10.8848 0 11.0645C0 11.2442 0.0713707 11.4165 0.198411 11.5435C0.325452 11.6706 0.497757 11.7419 0.677419 11.7419Z",
fill: "currentColor"
}, null, -1);
var _hoisted_2$1 = [_hoisted_1$1];
function render$1(_ctx, _cache, $props, $setup, $data, $options) {
return openBlock(), createElementBlock("svg", mergeProps({
width: "14",
height: "14",
viewBox: "0 0 14 14",
fill: "none",
xmlns: "http://www.w3.org/2000/svg"
}, _ctx.pti()), _hoisted_2$1, 16);
}
__name(render$1, "render$1");
script$1.render = render$1;
var script = {
name: "PlusIcon",
"extends": script$2
};
var _hoisted_1 = /* @__PURE__ */ createBaseVNode("path", {
d: "M7.67742 6.32258V0.677419C7.67742 0.497757 7.60605 0.325452 7.47901 0.198411C7.35197 0.0713707 7.17966 0 7 0C6.82034 0 6.64803 0.0713707 6.52099 0.198411C6.39395 0.325452 6.32258 0.497757 6.32258 0.677419V6.32258H0.677419C0.497757 6.32258 0.325452 6.39395 0.198411 6.52099C0.0713707 6.64803 0 6.82034 0 7C0 7.17966 0.0713707 7.35197 0.198411 7.47901C0.325452 7.60605 0.497757 7.67742 0.677419 7.67742H6.32258V13.3226C6.32492 13.5015 6.39704 13.6725 6.52358 13.799C6.65012 13.9255 6.82106 13.9977 7 14C7.17966 14 7.35197 13.9286 7.47901 13.8016C7.60605 13.6745 7.67742 13.5022 7.67742 13.3226V7.67742H13.3226C13.5022 7.67742 13.6745 7.60605 13.8016 7.47901C13.9286 7.35197 14 7.17966 14 7C13.9977 6.82106 13.9255 6.65012 13.799 6.52358C13.6725 6.39704 13.5015 6.32492 13.3226 6.32258H7.67742Z",
fill: "currentColor"
}, null, -1);
var _hoisted_2 = [_hoisted_1];
function render(_ctx, _cache, $props, $setup, $data, $options) {
return openBlock(), createElementBlock("svg", mergeProps({
width: "14",
height: "14",
viewBox: "0 0 14 14",
fill: "none",
xmlns: "http://www.w3.org/2000/svg"
}, _ctx.pti()), _hoisted_2, 16);
}
__name(render, "render");
script.render = render;
export {
script as a,
script$1 as s
};
//# sourceMappingURL=index-D4DWQPPQ.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"index-D4DWQPPQ.js","sources":["../../node_modules/@primevue/icons/bars/index.mjs","../../node_modules/@primevue/icons/plus/index.mjs"],"sourcesContent":["import BaseIcon from '@primevue/icons/baseicon';\nimport { openBlock, createElementBlock, mergeProps, createElementVNode } from 'vue';\n\nvar script = {\n name: 'BarsIcon',\n \"extends\": BaseIcon\n};\n\nvar _hoisted_1 = /*#__PURE__*/createElementVNode(\"path\", {\n \"fill-rule\": \"evenodd\",\n \"clip-rule\": \"evenodd\",\n d: \"M13.3226 3.6129H0.677419C0.497757 3.6129 0.325452 3.54152 0.198411 3.41448C0.0713707 3.28744 0 3.11514 0 2.93548C0 2.75581 0.0713707 2.58351 0.198411 2.45647C0.325452 2.32943 0.497757 2.25806 0.677419 2.25806H13.3226C13.5022 2.25806 13.6745 2.32943 13.8016 2.45647C13.9286 2.58351 14 2.75581 14 2.93548C14 3.11514 13.9286 3.28744 13.8016 3.41448C13.6745 3.54152 13.5022 3.6129 13.3226 3.6129ZM13.3226 7.67741H0.677419C0.497757 7.67741 0.325452 7.60604 0.198411 7.479C0.0713707 7.35196 0 7.17965 0 6.99999C0 6.82033 0.0713707 6.64802 0.198411 6.52098C0.325452 6.39394 0.497757 6.32257 0.677419 6.32257H13.3226C13.5022 6.32257 13.6745 6.39394 13.8016 6.52098C13.9286 6.64802 14 6.82033 14 6.99999C14 7.17965 13.9286 7.35196 13.8016 7.479C13.6745 7.60604 13.5022 7.67741 13.3226 7.67741ZM0.677419 11.7419H13.3226C13.5022 11.7419 13.6745 11.6706 13.8016 11.5435C13.9286 11.4165 14 11.2442 14 11.0645C14 10.8848 13.9286 10.7125 13.8016 10.5855C13.6745 10.4585 13.5022 10.3871 13.3226 10.3871H0.677419C0.497757 10.3871 0.325452 10.4585 0.198411 10.5855C0.0713707 10.7125 0 10.8848 0 11.0645C0 11.2442 0.0713707 11.4165 0.198411 11.5435C0.325452 11.6706 0.497757 11.7419 0.677419 11.7419Z\",\n fill: \"currentColor\"\n}, null, -1);\nvar _hoisted_2 = [_hoisted_1];\nfunction render(_ctx, _cache, $props, $setup, $data, $options) {\n return openBlock(), createElementBlock(\"svg\", mergeProps({\n width: \"14\",\n height: \"14\",\n viewBox: \"0 0 14 14\",\n fill: \"none\",\n xmlns: \"http://www.w3.org/2000/svg\"\n }, _ctx.pti()), _hoisted_2, 16);\n}\n\nscript.render = render;\n\nexport { script as default };\n//# sourceMappingURL=index.mjs.map\n","import BaseIcon from '@primevue/icons/baseicon';\nimport { openBlock, createElementBlock, mergeProps, createElementVNode } from 'vue';\n\nvar script = {\n name: 'PlusIcon',\n \"extends\": BaseIcon\n};\n\nvar _hoisted_1 = /*#__PURE__*/createElementVNode(\"path\", {\n d: \"M7.67742 6.32258V0.677419C7.67742 0.497757 7.60605 0.325452 7.47901 0.198411C7.35197 0.0713707 7.17966 0 7 0C6.82034 0 6.64803 0.0713707 6.52099 0.198411C6.39395 0.325452 6.32258 0.497757 6.32258 0.677419V6.32258H0.677419C0.497757 6.32258 0.325452 6.39395 0.198411 6.52099C0.0713707 6.64803 0 6.82034 0 7C0 7.17966 0.0713707 7.35197 0.198411 7.47901C0.325452 7.60605 0.497757 7.67742 0.677419 7.67742H6.32258V13.3226C6.32492 13.5015 6.39704 13.6725 6.52358 13.799C6.65012 13.9255 6.82106 13.9977 7 14C7.17966 14 7.35197 13.9286 7.47901 13.8016C7.60605 13.6745 7.67742 13.5022 7.67742 13.3226V7.67742H13.3226C13.5022 7.67742 13.6745 7.60605 13.8016 7.47901C13.9286 7.35197 14 7.17966 14 7C13.9977 6.82106 13.9255 6.65012 13.799 6.52358C13.6725 6.39704 13.5015 6.32492 13.3226 6.32258H7.67742Z\",\n fill: \"currentColor\"\n}, null, -1);\nvar _hoisted_2 = [_hoisted_1];\nfunction render(_ctx, _cache, $props, $setup, $data, $options) {\n return openBlock(), createElementBlock(\"svg\", mergeProps({\n width: \"14\",\n height: \"14\",\n viewBox: \"0 0 14 14\",\n fill: \"none\",\n xmlns: \"http://www.w3.org/2000/svg\"\n }, _ctx.pti()), _hoisted_2, 16);\n}\n\nscript.render = render;\n\nexport { script as default };\n//# sourceMappingURL=index.mjs.map\n"],"names":["script","BaseIcon","_hoisted_1","createElementVNode","_hoisted_2","render"],"mappings":";;;AAGG,IAACA,WAAS;AAAA,EACX,MAAM;AAAA,EACN,WAAWC;AACb;AAEA,IAAIC,eAA0BC,gCAAmB,QAAQ;AAAA,EACvD,aAAa;AAAA,EACb,aAAa;AAAA,EACb,GAAG;AAAA,EACH,MAAM;AACR,GAAG,MAAM,EAAE;AACX,IAAIC,eAAa,CAACF,YAAU;AAC5B,SAASG,SAAO,MAAM,QAAQ,QAAQ,QAAQ,OAAO,UAAU;AAC7D,SAAO,UAAW,GAAE,mBAAmB,OAAO,WAAW;AAAA,IACvD,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,MAAM;AAAA,IACN,OAAO;AAAA,EACR,GAAE,KAAK,IAAG,CAAE,GAAGD,cAAY,EAAE;AAChC;AARSC;AAUTL,SAAO,SAASK;ACtBb,IAAC,SAAS;AAAA,EACX,MAAM;AAAA,EACN,WAAWJ;AACb;AAEA,IAAI,aAA0BE,gCAAmB,QAAQ;AAAA,EACvD,GAAG;AAAA,EACH,MAAM;AACR,GAAG,MAAM,EAAE;AACX,IAAI,aAAa,CAAC,UAAU;AAC5B,SAAS,OAAO,MAAM,QAAQ,QAAQ,QAAQ,OAAO,UAAU;AAC7D,SAAO,UAAW,GAAE,mBAAmB,OAAO,WAAW;AAAA,IACvD,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,MAAM;AAAA,IACN,OAAO;AAAA,EACR,GAAE,KAAK,IAAG,CAAE,GAAG,YAAY,EAAE;AAChC;AARS;AAUT,OAAO,SAAS;","x_google_ignoreList":[0,1]}

View File

@ -1,6 +1,6 @@
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
import { b6 as script$2, g as openBlock, h as createElementBlock, m as mergeProps, A as createBaseVNode } from "./index-bi78Y1IN.js";
import { ba as script$2, f as openBlock, g as createElementBlock, m as mergeProps, A as createBaseVNode } from "./index-BQYg0VNJ.js";
var script$1 = {
name: "BarsIcon",
"extends": script$2
@ -43,4 +43,4 @@ export {
script as a,
script$1 as s
};
//# sourceMappingURL=index-bCeMLtLM.js.map
//# sourceMappingURL=index-DJqEjTnE.js.map

View File

@ -1 +1 @@
{"version":3,"file":"index-bCeMLtLM.js","sources":["../../../../../node_modules/@primevue/icons/bars/index.mjs","../../../../../node_modules/@primevue/icons/plus/index.mjs"],"sourcesContent":["import BaseIcon from '@primevue/icons/baseicon';\nimport { openBlock, createElementBlock, mergeProps, createElementVNode } from 'vue';\n\nvar script = {\n name: 'BarsIcon',\n \"extends\": BaseIcon\n};\n\nfunction render(_ctx, _cache, $props, $setup, $data, $options) {\n return openBlock(), createElementBlock(\"svg\", mergeProps({\n width: \"14\",\n height: \"14\",\n viewBox: \"0 0 14 14\",\n fill: \"none\",\n xmlns: \"http://www.w3.org/2000/svg\"\n }, _ctx.pti()), _cache[0] || (_cache[0] = [createElementVNode(\"path\", {\n \"fill-rule\": \"evenodd\",\n \"clip-rule\": \"evenodd\",\n d: \"M13.3226 3.6129H0.677419C0.497757 3.6129 0.325452 3.54152 0.198411 3.41448C0.0713707 3.28744 0 3.11514 0 2.93548C0 2.75581 0.0713707 2.58351 0.198411 2.45647C0.325452 2.32943 0.497757 2.25806 0.677419 2.25806H13.3226C13.5022 2.25806 13.6745 2.32943 13.8016 2.45647C13.9286 2.58351 14 2.75581 14 2.93548C14 3.11514 13.9286 3.28744 13.8016 3.41448C13.6745 3.54152 13.5022 3.6129 13.3226 3.6129ZM13.3226 7.67741H0.677419C0.497757 7.67741 0.325452 7.60604 0.198411 7.479C0.0713707 7.35196 0 7.17965 0 6.99999C0 6.82033 0.0713707 6.64802 0.198411 6.52098C0.325452 6.39394 0.497757 6.32257 0.677419 6.32257H13.3226C13.5022 6.32257 13.6745 6.39394 13.8016 6.52098C13.9286 6.64802 14 6.82033 14 6.99999C14 7.17965 13.9286 7.35196 13.8016 7.479C13.6745 7.60604 13.5022 7.67741 13.3226 7.67741ZM0.677419 11.7419H13.3226C13.5022 11.7419 13.6745 11.6706 13.8016 11.5435C13.9286 11.4165 14 11.2442 14 11.0645C14 10.8848 13.9286 10.7125 13.8016 10.5855C13.6745 10.4585 13.5022 10.3871 13.3226 10.3871H0.677419C0.497757 10.3871 0.325452 10.4585 0.198411 10.5855C0.0713707 10.7125 0 10.8848 0 11.0645C0 11.2442 0.0713707 11.4165 0.198411 11.5435C0.325452 11.6706 0.497757 11.7419 0.677419 11.7419Z\",\n fill: \"currentColor\"\n }, null, -1)]), 16);\n}\n\nscript.render = render;\n\nexport { script as default };\n//# sourceMappingURL=index.mjs.map\n","import BaseIcon from '@primevue/icons/baseicon';\nimport { openBlock, createElementBlock, mergeProps, createElementVNode } from 'vue';\n\nvar script = {\n name: 'PlusIcon',\n \"extends\": BaseIcon\n};\n\nfunction render(_ctx, _cache, $props, $setup, $data, $options) {\n return openBlock(), createElementBlock(\"svg\", mergeProps({\n width: \"14\",\n height: \"14\",\n viewBox: \"0 0 14 14\",\n fill: \"none\",\n xmlns: \"http://www.w3.org/2000/svg\"\n }, _ctx.pti()), _cache[0] || (_cache[0] = [createElementVNode(\"path\", {\n d: \"M7.67742 6.32258V0.677419C7.67742 0.497757 7.60605 0.325452 7.47901 0.198411C7.35197 0.0713707 7.17966 0 7 0C6.82034 0 6.64803 0.0713707 6.52099 0.198411C6.39395 0.325452 6.32258 0.497757 6.32258 0.677419V6.32258H0.677419C0.497757 6.32258 0.325452 6.39395 0.198411 6.52099C0.0713707 6.64803 0 6.82034 0 7C0 7.17966 0.0713707 7.35197 0.198411 7.47901C0.325452 7.60605 0.497757 7.67742 0.677419 7.67742H6.32258V13.3226C6.32492 13.5015 6.39704 13.6725 6.52358 13.799C6.65012 13.9255 6.82106 13.9977 7 14C7.17966 14 7.35197 13.9286 7.47901 13.8016C7.60605 13.6745 7.67742 13.5022 7.67742 13.3226V7.67742H13.3226C13.5022 7.67742 13.6745 7.60605 13.8016 7.47901C13.9286 7.35197 14 7.17966 14 7C13.9977 6.82106 13.9255 6.65012 13.799 6.52358C13.6725 6.39704 13.5015 6.32492 13.3226 6.32258H7.67742Z\",\n fill: \"currentColor\"\n }, null, -1)]), 16);\n}\n\nscript.render = render;\n\nexport { script as default };\n//# sourceMappingURL=index.mjs.map\n"],"names":["script","BaseIcon","render","createElementVNode"],"mappings":";;;AAGG,IAACA,WAAS;AAAA,EACX,MAAM;AAAA,EACN,WAAWC;AACb;AAEA,SAASC,SAAO,MAAM,QAAQ,QAAQ,QAAQ,OAAO,UAAU;AAC7D,SAAO,UAAW,GAAE,mBAAmB,OAAO,WAAW;AAAA,IACvD,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,MAAM;AAAA,IACN,OAAO;AAAA,EACR,GAAE,KAAK,KAAK,GAAG,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAACC,gBAAmB,QAAQ;AAAA,IACpE,aAAa;AAAA,IACb,aAAa;AAAA,IACb,GAAG;AAAA,IACH,MAAM;AAAA,EACP,GAAE,MAAM,EAAE,CAAC,IAAI,EAAE;AACpB;AAbSD;AAeTF,SAAO,SAASE;ACpBb,IAAC,SAAS;AAAA,EACX,MAAM;AAAA,EACN,WAAWD;AACb;AAEA,SAAS,OAAO,MAAM,QAAQ,QAAQ,QAAQ,OAAO,UAAU;AAC7D,SAAO,UAAW,GAAE,mBAAmB,OAAO,WAAW;AAAA,IACvD,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,MAAM;AAAA,IACN,OAAO;AAAA,EACR,GAAE,KAAK,KAAK,GAAG,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAACE,gBAAmB,QAAQ;AAAA,IACpE,GAAG;AAAA,IACH,MAAM;AAAA,EACP,GAAE,MAAM,EAAE,CAAC,IAAI,EAAE;AACpB;AAXS;AAaT,OAAO,SAAS;","x_google_ignoreList":[0,1]}
{"version":3,"file":"index-DJqEjTnE.js","sources":["../../../../../node_modules/@primevue/icons/bars/index.mjs","../../../../../node_modules/@primevue/icons/plus/index.mjs"],"sourcesContent":["import BaseIcon from '@primevue/icons/baseicon';\nimport { openBlock, createElementBlock, mergeProps, createElementVNode } from 'vue';\n\nvar script = {\n name: 'BarsIcon',\n \"extends\": BaseIcon\n};\n\nfunction render(_ctx, _cache, $props, $setup, $data, $options) {\n return openBlock(), createElementBlock(\"svg\", mergeProps({\n width: \"14\",\n height: \"14\",\n viewBox: \"0 0 14 14\",\n fill: \"none\",\n xmlns: \"http://www.w3.org/2000/svg\"\n }, _ctx.pti()), _cache[0] || (_cache[0] = [createElementVNode(\"path\", {\n \"fill-rule\": \"evenodd\",\n \"clip-rule\": \"evenodd\",\n d: \"M13.3226 3.6129H0.677419C0.497757 3.6129 0.325452 3.54152 0.198411 3.41448C0.0713707 3.28744 0 3.11514 0 2.93548C0 2.75581 0.0713707 2.58351 0.198411 2.45647C0.325452 2.32943 0.497757 2.25806 0.677419 2.25806H13.3226C13.5022 2.25806 13.6745 2.32943 13.8016 2.45647C13.9286 2.58351 14 2.75581 14 2.93548C14 3.11514 13.9286 3.28744 13.8016 3.41448C13.6745 3.54152 13.5022 3.6129 13.3226 3.6129ZM13.3226 7.67741H0.677419C0.497757 7.67741 0.325452 7.60604 0.198411 7.479C0.0713707 7.35196 0 7.17965 0 6.99999C0 6.82033 0.0713707 6.64802 0.198411 6.52098C0.325452 6.39394 0.497757 6.32257 0.677419 6.32257H13.3226C13.5022 6.32257 13.6745 6.39394 13.8016 6.52098C13.9286 6.64802 14 6.82033 14 6.99999C14 7.17965 13.9286 7.35196 13.8016 7.479C13.6745 7.60604 13.5022 7.67741 13.3226 7.67741ZM0.677419 11.7419H13.3226C13.5022 11.7419 13.6745 11.6706 13.8016 11.5435C13.9286 11.4165 14 11.2442 14 11.0645C14 10.8848 13.9286 10.7125 13.8016 10.5855C13.6745 10.4585 13.5022 10.3871 13.3226 10.3871H0.677419C0.497757 10.3871 0.325452 10.4585 0.198411 10.5855C0.0713707 10.7125 0 10.8848 0 11.0645C0 11.2442 0.0713707 11.4165 0.198411 11.5435C0.325452 11.6706 0.497757 11.7419 0.677419 11.7419Z\",\n fill: \"currentColor\"\n }, null, -1)]), 16);\n}\n\nscript.render = render;\n\nexport { script as default };\n//# sourceMappingURL=index.mjs.map\n","import BaseIcon from '@primevue/icons/baseicon';\nimport { openBlock, createElementBlock, mergeProps, createElementVNode } from 'vue';\n\nvar script = {\n name: 'PlusIcon',\n \"extends\": BaseIcon\n};\n\nfunction render(_ctx, _cache, $props, $setup, $data, $options) {\n return openBlock(), createElementBlock(\"svg\", mergeProps({\n width: \"14\",\n height: \"14\",\n viewBox: \"0 0 14 14\",\n fill: \"none\",\n xmlns: \"http://www.w3.org/2000/svg\"\n }, _ctx.pti()), _cache[0] || (_cache[0] = [createElementVNode(\"path\", {\n d: \"M7.67742 6.32258V0.677419C7.67742 0.497757 7.60605 0.325452 7.47901 0.198411C7.35197 0.0713707 7.17966 0 7 0C6.82034 0 6.64803 0.0713707 6.52099 0.198411C6.39395 0.325452 6.32258 0.497757 6.32258 0.677419V6.32258H0.677419C0.497757 6.32258 0.325452 6.39395 0.198411 6.52099C0.0713707 6.64803 0 6.82034 0 7C0 7.17966 0.0713707 7.35197 0.198411 7.47901C0.325452 7.60605 0.497757 7.67742 0.677419 7.67742H6.32258V13.3226C6.32492 13.5015 6.39704 13.6725 6.52358 13.799C6.65012 13.9255 6.82106 13.9977 7 14C7.17966 14 7.35197 13.9286 7.47901 13.8016C7.60605 13.6745 7.67742 13.5022 7.67742 13.3226V7.67742H13.3226C13.5022 7.67742 13.6745 7.60605 13.8016 7.47901C13.9286 7.35197 14 7.17966 14 7C13.9977 6.82106 13.9255 6.65012 13.799 6.52358C13.6725 6.39704 13.5015 6.32492 13.3226 6.32258H7.67742Z\",\n fill: \"currentColor\"\n }, null, -1)]), 16);\n}\n\nscript.render = render;\n\nexport { script as default };\n//# sourceMappingURL=index.mjs.map\n"],"names":["script","BaseIcon","render","createElementVNode"],"mappings":";;;AAGG,IAACA,WAAS;AAAA,EACX,MAAM;AAAA,EACN,WAAWC;AACb;AAEA,SAASC,SAAO,MAAM,QAAQ,QAAQ,QAAQ,OAAO,UAAU;AAC7D,SAAO,UAAW,GAAE,mBAAmB,OAAO,WAAW;AAAA,IACvD,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,MAAM;AAAA,IACN,OAAO;AAAA,EACR,GAAE,KAAK,KAAK,GAAG,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAACC,gBAAmB,QAAQ;AAAA,IACpE,aAAa;AAAA,IACb,aAAa;AAAA,IACb,GAAG;AAAA,IACH,MAAM;AAAA,EACP,GAAE,MAAM,EAAE,CAAC,IAAI,EAAE;AACpB;AAbSD;AAeTF,SAAO,SAASE;ACpBb,IAAC,SAAS;AAAA,EACX,MAAM;AAAA,EACN,WAAWD;AACb;AAEA,SAAS,OAAO,MAAM,QAAQ,QAAQ,QAAQ,OAAO,UAAU;AAC7D,SAAO,UAAW,GAAE,mBAAmB,OAAO,WAAW;AAAA,IACvD,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,MAAM;AAAA,IACN,OAAO;AAAA,EACR,GAAE,KAAK,KAAK,GAAG,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAACE,gBAAmB,QAAQ;AAAA,IACpE,GAAG;AAAA,IACH,MAAM;AAAA,EACP,GAAE,MAAM,EAAE,CAAC,IAAI,EAAE;AACpB;AAXS;AAaT,OAAO,SAAS;","x_google_ignoreList":[0,1]}

File diff suppressed because one or more lines are too long

51472
comfy/web/assets/index-DO-85kdf.js generated vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
import { cB as defineStore, r as ref, q as computed } from "./index-CoOvI8ZH.js";
import { d as defineStore, r as ref, q as computed } from "./index-BQYg0VNJ.js";
const useServerConfigStore = defineStore("serverConfig", () => {
const serverConfigById = ref({});
const serverConfigs = computed(() => {
@ -87,4 +87,4 @@ const useServerConfigStore = defineStore("serverConfig", () => {
export {
useServerConfigStore as u
};
//# sourceMappingURL=serverConfigStore-cctR8PGG.js.map
//# sourceMappingURL=serverConfigStore-DulDGgjD.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,137 +0,0 @@
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
<<<<<<<< HEAD:comfy/web/assets/userSelection-C-TGdC-2.js
import { aY as api, bX as $el } from "./index-bi78Y1IN.js";
========
import { aZ as api, bY as $el } from "./index-CoOvI8ZH.js";
>>>>>>>> 0fd4e6c7787daa922cb0d9bd1241b276b39ce2c5:comfy/web/assets/userSelection-C6c30qSU.js
function createSpinner() {
const div = document.createElement("div");
div.innerHTML = `<div class="lds-ring"><div></div><div></div><div></div><div></div></div>`;
return div.firstElementChild;
}
__name(createSpinner, "createSpinner");
window.comfyAPI = window.comfyAPI || {};
window.comfyAPI.spinner = window.comfyAPI.spinner || {};
window.comfyAPI.spinner.createSpinner = createSpinner;
class UserSelectionScreen {
static {
__name(this, "UserSelectionScreen");
}
async show(users, user) {
const userSelection = document.getElementById("comfy-user-selection");
userSelection.style.display = "";
return new Promise((resolve) => {
const input = userSelection.getElementsByTagName("input")[0];
const select = userSelection.getElementsByTagName("select")[0];
const inputSection = input.closest("section");
const selectSection = select.closest("section");
const form = userSelection.getElementsByTagName("form")[0];
const error = userSelection.getElementsByClassName("comfy-user-error")[0];
const button = userSelection.getElementsByClassName(
"comfy-user-button-next"
)[0];
let inputActive = null;
input.addEventListener("focus", () => {
inputSection.classList.add("selected");
selectSection.classList.remove("selected");
inputActive = true;
});
select.addEventListener("focus", () => {
inputSection.classList.remove("selected");
selectSection.classList.add("selected");
inputActive = false;
select.style.color = "";
});
select.addEventListener("blur", () => {
if (!select.value) {
select.style.color = "var(--descrip-text)";
}
});
form.addEventListener("submit", async (e) => {
e.preventDefault();
if (inputActive == null) {
error.textContent = "Please enter a username or select an existing user.";
} else if (inputActive) {
const username = input.value.trim();
if (!username) {
error.textContent = "Please enter a username.";
return;
}
input.disabled = select.disabled = // @ts-expect-error
input.readonly = // @ts-expect-error
select.readonly = true;
const spinner = createSpinner();
button.prepend(spinner);
try {
const resp = await api.createUser(username);
if (resp.status >= 300) {
let message = "Error creating user: " + resp.status + " " + resp.statusText;
try {
const res = await resp.json();
if (res.error) {
message = res.error;
}
} catch (error2) {
}
throw new Error(message);
}
resolve({ username, userId: await resp.json(), created: true });
} catch (err) {
spinner.remove();
error.textContent = err.message ?? err.statusText ?? err ?? "An unknown error occurred.";
input.disabled = select.disabled = // @ts-expect-error
input.readonly = // @ts-expect-error
select.readonly = false;
return;
}
} else if (!select.value) {
error.textContent = "Please select an existing user.";
return;
} else {
resolve({
username: users[select.value],
userId: select.value,
created: false
});
}
});
if (user) {
const name = localStorage["Comfy.userName"];
if (name) {
input.value = name;
}
}
if (input.value) {
input.focus();
}
const userIds = Object.keys(users ?? {});
if (userIds.length) {
for (const u of userIds) {
$el("option", { textContent: users[u], value: u, parent: select });
}
select.style.color = "var(--descrip-text)";
if (select.value) {
select.focus();
}
} else {
userSelection.classList.add("no-users");
input.focus();
}
}).then((r) => {
userSelection.remove();
return r;
});
}
}
window.comfyAPI = window.comfyAPI || {};
window.comfyAPI.userSelection = window.comfyAPI.userSelection || {};
window.comfyAPI.userSelection.UserSelectionScreen = UserSelectionScreen;
export {
UserSelectionScreen
};
<<<<<<<< HEAD:comfy/web/assets/userSelection-C-TGdC-2.js
//# sourceMappingURL=userSelection-C-TGdC-2.js.map
========
//# sourceMappingURL=userSelection-C6c30qSU.js.map
>>>>>>>> 0fd4e6c7787daa922cb0d9bd1241b276b39ce2c5:comfy/web/assets/userSelection-C6c30qSU.js

File diff suppressed because one or more lines are too long

View File

@ -1,170 +0,0 @@
.lds-ring {
display: inline-block;
position: relative;
width: 1em;
height: 1em;
}
.lds-ring div {
box-sizing: border-box;
display: block;
position: absolute;
width: 100%;
height: 100%;
border: 0.15em solid #fff;
border-radius: 50%;
animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
border-color: #fff transparent transparent transparent;
}
.lds-ring div:nth-child(1) {
animation-delay: -0.45s;
}
.lds-ring div:nth-child(2) {
animation-delay: -0.3s;
}
.lds-ring div:nth-child(3) {
animation-delay: -0.15s;
}
@keyframes lds-ring {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.comfy-user-selection {
width: 100vw;
height: 100vh;
position: absolute;
top: 0;
left: 0;
z-index: 999;
display: flex;
align-items: center;
justify-content: center;
font-family: sans-serif;
background: linear-gradient(var(--tr-even-bg-color), var(--tr-odd-bg-color));
}
.comfy-user-selection-inner {
background: var(--comfy-menu-bg);
margin-top: -30vh;
padding: 20px 40px;
border-radius: 10px;
min-width: 365px;
position: relative;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.3);
}
.comfy-user-selection-inner form {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
.comfy-user-selection-inner h1 {
margin: 10px 0 30px 0;
font-weight: normal;
}
.comfy-user-selection-inner label {
display: flex;
flex-direction: column;
width: 100%;
}
.comfy-user-selection input,
.comfy-user-selection select {
background-color: var(--comfy-input-bg);
color: var(--input-text);
border: 0;
border-radius: 5px;
padding: 5px;
margin-top: 10px;
}
.comfy-user-selection input::-moz-placeholder {
color: var(--descrip-text);
opacity: 1;
}
.comfy-user-selection input::placeholder {
color: var(--descrip-text);
opacity: 1;
}
.comfy-user-existing {
width: 100%;
}
.no-users .comfy-user-existing {
display: none;
}
.comfy-user-selection-inner .or-separator {
margin: 10px 0;
padding: 10px;
display: block;
width: 100%;
color: var(--descrip-text);
overflow: hidden;
text-align: center;
margin-left: -10px;
}
.comfy-user-selection-inner .or-separator::before,
.comfy-user-selection-inner .or-separator::after {
content: "";
background-color: var(--border-color);
position: relative;
height: 1px;
vertical-align: middle;
display: inline-block;
width: calc(50% - 20px);
top: -1px;
}
.comfy-user-selection-inner .or-separator::before {
right: 10px;
margin-left: -50%;
}
.comfy-user-selection-inner .or-separator::after {
left: 10px;
margin-right: -50%;
}
.comfy-user-selection-inner section {
width: 100%;
padding: 10px;
margin: -10px;
transition: background-color 0.2s;
}
.comfy-user-selection-inner section.selected {
background: var(--border-color);
border-radius: 5px;
}
.comfy-user-selection-inner footer {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 20px;
}
.comfy-user-selection-inner .comfy-user-error {
color: var(--error-text);
margin-bottom: 10px;
}
.comfy-user-button-next {
font-size: 16px;
padding: 6px 10px;
width: 100px;
display: flex;
gap: 5px;
align-items: center;
justify-content: center;
}

View File

@ -1,10 +1,6 @@
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
<<<<<<<< HEAD:comfy/web/assets/widgetInputs-DjCs8Yab.js
import { e as LGraphNode, c as app, c2 as applyTextReplacements, c1 as ComfyWidgets, c4 as addValueControlWidgets, k as LiteGraph } from "./index-bi78Y1IN.js";
========
import { e as LGraphNode, c as app, c3 as applyTextReplacements, c2 as ComfyWidgets, c5 as addValueControlWidgets, k as LiteGraph } from "./index-CoOvI8ZH.js";
>>>>>>>> 0fd4e6c7787daa922cb0d9bd1241b276b39ce2c5:comfy/web/assets/widgetInputs-CRPRgKEi.js
import { c as LGraphNode, b as app, cc as applyTextReplacements, cb as ComfyWidgets, cf as addValueControlWidgets, j as LiteGraph } from "./index-BQYg0VNJ.js";
const CONVERTED_TYPE = "converted-widget";
const VALID_TYPES = [
"STRING",
@ -588,6 +584,7 @@ app.registerExtension({
}
if (w.type === CONVERTED_TYPE) {
toWidget.push({
// @ts-expect-error never
content: `Convert ${w.name} to widget`,
callback: /* @__PURE__ */ __name(() => convertToWidget(this, w), "callback")
});
@ -680,7 +677,10 @@ app.registerExtension({
if (!app2.configuringGraph && this.inputs) {
for (const input of this.inputs) {
if (input.widget && !input.widget[GET_CONFIG]) {
input.widget[GET_CONFIG] = () => getConfig.call(this, input.widget.name);
input.widget[GET_CONFIG] = () => (
// @ts-expect-error input.widget has unknown type
getConfig.call(this, input.widget.name)
);
const w = this.widgets.find((w2) => w2.name === input.widget.name);
if (w) {
hideWidget(this, w);
@ -763,8 +763,4 @@ export {
mergeIfValid,
setWidgetConfig
};
<<<<<<<< HEAD:comfy/web/assets/widgetInputs-DjCs8Yab.js
//# sourceMappingURL=widgetInputs-DjCs8Yab.js.map
========
//# sourceMappingURL=widgetInputs-CRPRgKEi.js.map
>>>>>>>> 0fd4e6c7787daa922cb0d9bd1241b276b39ce2c5:comfy/web/assets/widgetInputs-CRPRgKEi.js
//# sourceMappingURL=widgetInputs-BMOQhk10.js.map

1
comfy/web/assets/widgetInputs-BMOQhk10.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
// Shim for extensions/core/maskEditorOld.ts
// Shim for extensions\core\maskEditorOld.ts
export const MaskEditorDialogOld = window.comfyAPI.maskEditorOld.MaskEditorDialogOld;

View File

@ -1,3 +1,3 @@
// Shim for extensions/core/vintageClipboard.ts
// Shim for extensions\core\vintageClipboard.ts
export const serialise = window.comfyAPI.vintageClipboard.serialise;
export const deserialiseAndCreate = window.comfyAPI.vintageClipboard.deserialiseAndCreate;

57
comfy/web/index.html vendored
View File

@ -1,42 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ComfyUI</title>
<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="materialdesignicons.min.css" />
<script type="module" crossorigin src="./assets/index-CoOvI8ZH.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-U_o182q3.css">
</head>
<body class="litegraph grid">
<div id="vue-app"></div>
<div id="comfy-user-selection" class="comfy-user-selection" style="display: none;">
<main class="comfy-user-selection-inner">
<h1>ComfyUI</h1>
<form>
<section>
<label>New user:
<input placeholder="Enter a username" />
</label>
</section>
<div class="comfy-user-existing">
<span class="or-separator">OR</span>
<section>
<label>
Existing user:
<select>
<option hidden disabled selected value> Select a user </option>
</select>
</label>
</section>
</div>
<footer>
<span class="comfy-user-error">&nbsp;</span>
<button class="comfy-btn comfy-user-button-next">Next</button>
</footer>
</form>
</main>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ComfyUI</title>
<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="materialdesignicons.min.css" />
<script type="module" crossorigin src="./assets/index-BQYg0VNJ.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-BY_-AxSO.css">
</head>
<body class="litegraph grid">
<div id="vue-app"></div>
</body>
</html>

View File

@ -1,2 +1,3 @@
// Shim for scripts\api.ts
export const ComfyApi = window.comfyAPI.api.ComfyApi;
export const api = window.comfyAPI.api.api;

View File

@ -1,2 +0,0 @@
// Shim for scripts\logging.ts
export const ComfyLogging = window.comfyAPI.logging.ComfyLogging;

View File

@ -1,2 +0,0 @@
// Shim for scripts\ui\spinner.ts
export const createSpinner = window.comfyAPI.spinner.createSpinner;

View File

@ -1,2 +0,0 @@
// Shim for scripts\ui\userSelection.ts
export const UserSelectionScreen = window.comfyAPI.userSelection.UserSelectionScreen;

View File

@ -0,0 +1,138 @@
"""
Adapted from https://github.com/WASasquatch/was-node-suite-comfyui/blob/main/LICENSE
MIT License
Copyright (c) 2023 Jordan Thompson (WASasquatch)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
import json
from PIL import Image, ImageDraw, ImageFilter
from comfy.component_model.tensor_types import MaskBatch
from comfy.nodes.package_typing import CustomNode
from comfy.utils import pil2tensor
def gradient(size, mode='horizontal', colors=None, tolerance=0):
if isinstance(colors, str):
colors = json.loads(colors)
if colors is None:
colors = {0: [255, 0, 0], 50: [0, 255, 0], 100: [0, 0, 255]}
colors = {int(k): [int(c) for c in v] for k, v in colors.items()}
colors[0] = colors[min(colors.keys())]
colors[255] = colors[max(colors.keys())]
img = Image.new('RGB', size, color=(0, 0, 0))
color_stop_positions = sorted(colors.keys())
color_stop_count = len(color_stop_positions)
spectrum = []
for i in range(256):
start_pos = max(p for p in color_stop_positions if p <= i)
end_pos = min(p for p in color_stop_positions if p >= i)
start = colors[start_pos]
end = colors[end_pos]
if start_pos == end_pos:
factor = 0
else:
factor = (i - start_pos) / (end_pos - start_pos)
r = round(start[0] + (end[0] - start[0]) * factor)
g = round(start[1] + (end[1] - start[1]) * factor)
b = round(start[2] + (end[2] - start[2]) * factor)
spectrum.append((r, g, b))
draw = ImageDraw.Draw(img)
if mode == 'horizontal':
for x in range(size[0]):
pos = int(x * 100 / (size[0] - 1))
color = spectrum[pos]
if tolerance > 0:
color = tuple([round(c / tolerance) * tolerance for c in color])
draw.line((x, 0, x, size[1]), fill=color)
elif mode == 'vertical':
for y in range(size[1]):
pos = int(y * 100 / (size[1] - 1))
color = spectrum[pos]
if tolerance > 0:
color = tuple([round(c / tolerance) * tolerance for c in color])
draw.line((0, y, size[0], y), fill=color)
blur = 1.5
if size[0] > 512 or size[1] > 512:
multiplier = max(size[0], size[1]) / 512
if multiplier < 1.5:
multiplier = 1.5
blur = blur * multiplier
img = img.filter(ImageFilter.GaussianBlur(radius=blur))
return img
class ImageGenerateGradient(CustomNode):
@classmethod
def INPUT_TYPES(cls):
gradient_stops = '''0:255,0,0
25:255,255,255
50:0,255,0
75:0,0,255'''
return {
"required": {
"width": ("INT", {"default": 512, "max": 4096, "min": 64, "step": 1}),
"height": ("INT", {"default": 512, "max": 4096, "min": 64, "step": 1}),
"direction": (["horizontal", "vertical"],),
"tolerance": ("INT", {"default": 0, "max": 255, "min": 0, "step": 1}),
"gradient_stops": ("STRING", {"default": gradient_stops, "multiline": True}),
},
}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "image_gradient"
CATEGORY = "image/generate"
def image_gradient(self, gradient_stops, width=512, height=512, direction='horizontal', tolerance=0) -> tuple[MaskBatch]:
import io
colors_dict = {}
stops = io.StringIO(gradient_stops.strip().replace(' ', ''))
for stop in stops:
parts = stop.split(':')
colors = parts[1].replace('\n', '').split(',')
colors_dict[parts[0].replace('\n', '')] = colors
image = gradient((width, height), direction, colors_dict, tolerance)
return (pil2tensor(image),)
NODE_CLASS_MAPPINGS = {
"ImageGenerateGradient": ImageGenerateGradient,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"ImageGenerateGradient": "Image Generate Gradient",
}

View File

@ -1,4 +1,6 @@
from __future__ import annotations
import logging
from typing import TYPE_CHECKING, Union
import torch
from collections.abc import Iterable
@ -9,7 +11,10 @@ if TYPE_CHECKING:
import comfy.hooks
import comfy.sd
import comfy.utils
import folder_paths
from comfy.cmd import folder_paths
from comfy.model_downloader import get_or_download, get_filename_list_with_downloadable
logger = logging.getLogger(__name__)
###########################################
# Mask, Combine, and Hook Conditioning
@ -294,7 +299,7 @@ class CreateHookLora:
def INPUT_TYPES(s):
return {
"required": {
"lora_name": (folder_paths.get_filename_list("loras"), ),
"lora_name": (get_filename_list_with_downloadable("loras"), ),
"strength_model": ("FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}),
"strength_clip": ("FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}),
},
@ -316,7 +321,7 @@ class CreateHookLora:
if strength_model == 0 and strength_clip == 0:
return (prev_hooks,)
lora_path = folder_paths.get_full_path("loras", lora_name)
lora_path = get_or_download("loras", lora_name)
lora = None
if self.loaded_lora is not None:
if self.loaded_lora[0] == lora_path:
@ -340,7 +345,7 @@ class CreateHookLoraModelOnly(CreateHookLora):
def INPUT_TYPES(s):
return {
"required": {
"lora_name": (folder_paths.get_filename_list("loras"), ),
"lora_name": (get_filename_list_with_downloadable("loras"), ),
"strength_model": ("FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}),
},
"optional": {
@ -369,7 +374,7 @@ class CreateHookModelAsLora:
def INPUT_TYPES(s):
return {
"required": {
"ckpt_name": (folder_paths.get_filename_list("checkpoints"), ),
"ckpt_name": (get_filename_list_with_downloadable("checkpoints"), ),
"strength_model": ("FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}),
"strength_clip": ("FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}),
},
@ -389,7 +394,7 @@ class CreateHookModelAsLora:
prev_hooks = comfy.hooks.HookGroup()
prev_hooks.clone()
ckpt_path = folder_paths.get_full_path("checkpoints", ckpt_name)
ckpt_path = get_or_download("checkpoints", ckpt_name)
weights_model = None
weights_clip = None
if self.loaded_weights is not None:
@ -418,7 +423,7 @@ class CreateHookModelAsLoraModelOnly(CreateHookModelAsLora):
def INPUT_TYPES(s):
return {
"required": {
"ckpt_name": (folder_paths.get_filename_list("checkpoints"), ),
"ckpt_name": (get_filename_list_with_downloadable("checkpoints"), ),
"strength_model": ("FLOAT", {"default": 1.0, "min": -20.0, "max": 20.0, "step": 0.01}),
},
"optional": {
@ -539,7 +544,7 @@ class CreateHookKeyframesInterpolated:
is_first = False
prev_hook_kf.add(comfy.hooks.HookKeyframe(strength=strength, start_percent=percent, guarantee_steps=guarantee_steps))
if print_keyframes:
print(f"Hook Keyframe - start_percent:{percent} = {strength}")
logger.debug(f"Hook Keyframe - start_percent:{percent} = {strength}")
return (prev_hook_kf,)
class CreateHookKeyframesFromFloats:
@ -588,7 +593,7 @@ class CreateHookKeyframesFromFloats:
is_first = False
prev_hook_kf.add(comfy.hooks.HookKeyframe(strength=strength, start_percent=percent, guarantee_steps=guarantee_steps))
if print_keyframes:
print(f"Hook Keyframe - start_percent:{percent} = {strength}")
logger.debug(f"Hook Keyframe - start_percent:{percent} = {strength}")
return (prev_hook_kf,)
#------------------------------------------
###########################################

View File

@ -36,7 +36,8 @@ class LTXVImgToVideo:
"width": ("INT", {"default": 768, "min": 64, "max": nodes.MAX_RESOLUTION, "step": 32}),
"height": ("INT", {"default": 512, "min": 64, "max": nodes.MAX_RESOLUTION, "step": 32}),
"length": ("INT", {"default": 97, "min": 9, "max": nodes.MAX_RESOLUTION, "step": 8}),
"batch_size": ("INT", {"default": 1, "min": 1, "max": 4096}),
"batch_size": ("INT", {"default": 1, "min": 1, "max": 4096}),},
"optional": {
"image_noise_scale": ("FLOAT", {"default": 0.15, "min": 0, "max": 1.0, "step": 0.01, "tooltip": "Amount of noise to apply on conditioning image latent."})
}}
@ -46,7 +47,7 @@ class LTXVImgToVideo:
CATEGORY = "conditioning/video_models"
FUNCTION = "generate"
def generate(self, positive, negative, image, vae, width, height, length, batch_size, image_noise_scale):
def generate(self, positive, negative, image, vae, width, height, length, batch_size, image_noise_scale=0.15):
pixels = comfy.utils.common_upscale(image.movedim(-1, 1), width, height, "bilinear", "center").movedim(1, -1)
encode_pixels = pixels[:, :, :, :3]
t = vae.encode(encode_pixels)

View File

@ -203,7 +203,6 @@ class TestExecution:
@pytest.mark.parametrize("test_type, test_value", [
("StubInt", 5),
("StubFloat", 5.0)
])
async def test_validation_error_edge1(self, test_type, test_value, client: ComfyClient, builder: GraphBuilder):
g = builder

View File

@ -0,0 +1,303 @@
{
"2": {
"inputs": {
"text": "worst quality, low quality",
"clip": [
"21",
0
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "CLIP Text Encode (Prompt)"
}
},
"3": {
"inputs": {
"text": "worst quality, low quality",
"clip": [
"11",
0
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "CLIP Text Encode (Prompt)"
}
},
"4": {
"inputs": {
"text": "rock in a river, outdoors, forest, sky, clouds, best quality",
"clip": [
"21",
0
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "CLIP Text Encode (Prompt)"
}
},
"5": {
"inputs": {
"width": 768,
"height": 768,
"batch_size": 1
},
"class_type": "EmptyLatentImage",
"_meta": {
"title": "Empty Latent Image"
}
},
"6": {
"inputs": {
"text": "rock in a river, outdoors, forest, sky, clouds, best quality",
"clip": [
"11",
0
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "CLIP Text Encode (Prompt)"
}
},
"9": {
"inputs": {
"samples": [
"23",
0
],
"vae": [
"10",
0
]
},
"class_type": "VAEDecode",
"_meta": {
"title": "VAE Decode"
}
},
"10": {
"inputs": {
"vae_name": "vae-ft-mse-840000-ema-pruned.safetensors"
},
"class_type": "VAELoader",
"_meta": {
"title": "Load VAE"
}
},
"11": {
"inputs": {
"apply_to_conds": true,
"schedule_clip": false,
"clip": [
"12",
0
],
"hooks": [
"18",
0
]
},
"class_type": "SetClipHooks",
"_meta": {
"title": "Set CLIP Hooks"
}
},
"12": {
"inputs": {
"stop_at_clip_layer": -2,
"clip": [
"13",
1
]
},
"class_type": "CLIPSetLastLayer",
"_meta": {
"title": "CLIP Set Last Layer"
}
},
"13": {
"inputs": {
"ckpt_name": "cardosAnime_v20.safetensors"
},
"class_type": "CheckpointLoaderSimple",
"_meta": {
"title": "Load Checkpoint"
}
},
"14": {
"inputs": {
"mask": [
"68",
0
]
},
"class_type": "InvertMask",
"_meta": {
"title": "InvertMask"
}
},
"16": {
"inputs": {
"strength": 1,
"set_cond_area": "default",
"positive_NEW": [
"4",
0
],
"negative_NEW": [
"2",
0
],
"mask": [
"68",
0
]
},
"class_type": "PairConditioningSetProperties",
"_meta": {
"title": "Cond Pair Set Props"
}
},
"17": {
"inputs": {
"strength": 1,
"set_cond_area": "default",
"positive": [
"16",
0
],
"negative": [
"16",
1
],
"positive_NEW": [
"6",
0
],
"negative_NEW": [
"3",
0
],
"mask": [
"14",
0
]
},
"class_type": "PairConditioningSetPropertiesAndCombine",
"_meta": {
"title": "Cond Pair Set Props Combine"
}
},
"18": {
"inputs": {
"ckpt_name": "dreamshaper_8.safetensors",
"strength_model": 1,
"strength_clip": 1
},
"class_type": "CreateHookModelAsLora",
"_meta": {
"title": "Create Hook Model as LoRA"
}
},
"20": {
"inputs": {
"lora_name": "PixelArtRedmond15V-PixelArt-PIXARFK.safetensors",
"strength_model": 1.1,
"strength_clip": 1
},
"class_type": "CreateHookLora",
"_meta": {
"title": "Create Hook LoRA"
}
},
"21": {
"inputs": {
"apply_to_conds": true,
"schedule_clip": false,
"clip": [
"12",
0
],
"hooks": [
"20",
0
]
},
"class_type": "SetClipHooks",
"_meta": {
"title": "Set CLIP Hooks"
}
},
"22": {
"inputs": {
"filename_prefix": "lorahooksmasking/img",
"images": [
"9",
0
]
},
"class_type": "SaveImage",
"_meta": {
"title": "Save Image"
}
},
"23": {
"inputs": {
"seed": 12345678,
"steps": 30,
"cfg": 8,
"sampler_name": "euler",
"scheduler": "normal",
"denoise": 1,
"model": [
"13",
0
],
"positive": [
"17",
0
],
"negative": [
"17",
1
],
"latent_image": [
"5",
0
]
},
"class_type": "KSampler",
"_meta": {
"title": "KSampler"
}
},
"67": {
"inputs": {
"width": 768,
"height": 768,
"direction": "horizontal",
"tolerance": 0,
"gradient_stops": "0:255,255,255\n100:0,0,0"
},
"class_type": "ImageGenerateGradient",
"_meta": {
"title": "Image Generate Gradient"
}
},
"68": {
"inputs": {
"channel": "red",
"image": [
"67",
0
]
},
"class_type": "ImageToMask",
"_meta": {
"title": "Convert Image to Mask"
}
}
}

View File

@ -0,0 +1,207 @@
{
"2": {
"inputs": {
"text": "worst quality, low quality",
"clip": [
"21",
0
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "CLIP Text Encode (Prompt)"
}
},
"4": {
"inputs": {
"text": "rock in a river, outdoors, forest, sky, clouds, best quality",
"clip": [
"21",
0
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "CLIP Text Encode (Prompt)"
}
},
"5": {
"inputs": {
"width": 768,
"height": 768,
"batch_size": 1
},
"class_type": "EmptyLatentImage",
"_meta": {
"title": "Empty Latent Image"
}
},
"9": {
"inputs": {
"samples": [
"23",
0
],
"vae": [
"10",
0
]
},
"class_type": "VAEDecode",
"_meta": {
"title": "VAE Decode"
}
},
"10": {
"inputs": {
"vae_name": "vae-ft-mse-840000-ema-pruned.safetensors"
},
"class_type": "VAELoader",
"_meta": {
"title": "Load VAE"
}
},
"12": {
"inputs": {
"stop_at_clip_layer": -2,
"clip": [
"13",
1
]
},
"class_type": "CLIPSetLastLayer",
"_meta": {
"title": "CLIP Set Last Layer"
}
},
"13": {
"inputs": {
"ckpt_name": "cardosAnime_v20.safetensors"
},
"class_type": "CheckpointLoaderSimple",
"_meta": {
"title": "Load Checkpoint"
}
},
"16": {
"inputs": {
"strength": 1,
"set_cond_area": "default",
"positive_NEW": [
"4",
0
],
"negative_NEW": [
"2",
0
]
},
"class_type": "PairConditioningSetProperties",
"_meta": {
"title": "Cond Pair Set Props"
}
},
"20": {
"inputs": {
"lora_name": "PixelArtRedmond15V-PixelArt-PIXARFK.safetensors",
"strength_model": 1,
"strength_clip": 1
},
"class_type": "CreateHookLora",
"_meta": {
"title": "Create Hook LoRA"
}
},
"21": {
"inputs": {
"apply_to_conds": true,
"schedule_clip": false,
"clip": [
"12",
0
],
"hooks": [
"75",
0
]
},
"class_type": "SetClipHooks",
"_meta": {
"title": "Set CLIP Hooks"
}
},
"22": {
"inputs": {
"filename_prefix": "lorahooks/img",
"images": [
"9",
0
]
},
"class_type": "SaveImage",
"_meta": {
"title": "Save Image"
}
},
"23": {
"inputs": {
"seed": 12345678,
"steps": 30,
"cfg": 8,
"sampler_name": "euler",
"scheduler": "normal",
"denoise": 1,
"model": [
"13",
0
],
"positive": [
"16",
0
],
"negative": [
"16",
1
],
"latent_image": [
"5",
0
]
},
"class_type": "KSampler",
"_meta": {
"title": "KSampler"
}
},
"75": {
"inputs": {
"hooks": [
"20",
0
],
"hook_kf": [
"76",
0
]
},
"class_type": "SetHookKeyframes",
"_meta": {
"title": "Set Hook Keyframes"
}
},
"76": {
"inputs": {
"strength_start": 0,
"strength_end": 1,
"interpolation": "linear",
"start_percent": 0,
"end_percent": 0.5,
"keyframes_count": 5,
"print_keyframes": true
},
"class_type": "CreateHookKeyframesInterpolated",
"_meta": {
"title": "Create Hook Keyframes Interp."
}
}
}

View File

@ -0,0 +1,374 @@
{
"1": {
"inputs": {
"ckpt_name": "cardosAnime_v20.safetensors"
},
"class_type": "CheckpointLoaderSimple",
"_meta": {
"title": "Load Checkpoint"
}
},
"2": {
"inputs": {
"stop_at_clip_layer": -2,
"clip": [
"1",
1
]
},
"class_type": "CLIPSetLastLayer",
"_meta": {
"title": "CLIP Set Last Layer"
}
},
"3": {
"inputs": {
"text": "rock in a river, outdoors, forest, sky, clouds, best quality",
"clip": [
"9",
0
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "CLIP Text Encode (Prompt)"
}
},
"5": {
"inputs": {
"text": "worst quality, low quality",
"clip": [
"9",
0
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "CLIP Text Encode (Prompt)"
}
},
"6": {
"inputs": {
"text": "rock in a river, outdoors, forest, sky, clouds, best quality",
"clip": [
"22",
0
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "CLIP Text Encode (Prompt)"
}
},
"7": {
"inputs": {
"text": "worst quality, low quality",
"clip": [
"22",
0
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "CLIP Text Encode (Prompt)"
}
},
"9": {
"inputs": {
"apply_to_conds": true,
"schedule_clip": false,
"clip": [
"2",
0
],
"hooks": [
"39",
0
]
},
"class_type": "SetClipHooks",
"_meta": {
"title": "Set CLIP Hooks"
}
},
"10": {
"inputs": {
"seed": 12345678,
"steps": 30,
"cfg": 8,
"sampler_name": "euler",
"scheduler": "normal",
"denoise": 1,
"model": [
"1",
0
],
"positive": [
"17",
0
],
"negative": [
"17",
1
],
"latent_image": [
"11",
0
]
},
"class_type": "KSampler",
"_meta": {
"title": "KSampler"
}
},
"11": {
"inputs": {
"width": 768,
"height": 768,
"batch_size": 1
},
"class_type": "EmptyLatentImage",
"_meta": {
"title": "Empty Latent Image"
}
},
"12": {
"inputs": {
"samples": [
"10",
0
],
"vae": [
"14",
0
]
},
"class_type": "VAEDecode",
"_meta": {
"title": "VAE Decode"
}
},
"13": {
"inputs": {
"filename_prefix": "lorahooksboth/img",
"images": [
"12",
0
]
},
"class_type": "SaveImage",
"_meta": {
"title": "Save Image"
}
},
"14": {
"inputs": {
"vae_name": "vae-ft-mse-840000-ema-pruned.safetensors"
},
"class_type": "VAELoader",
"_meta": {
"title": "Load VAE"
}
},
"17": {
"inputs": {
"strength": 1,
"set_cond_area": "default",
"positive": [
"18",
0
],
"negative": [
"18",
1
],
"positive_NEW": [
"6",
0
],
"negative_NEW": [
"7",
0
],
"mask": [
"20",
0
]
},
"class_type": "PairConditioningSetPropertiesAndCombine",
"_meta": {
"title": "Cond Pair Set Props Combine"
}
},
"18": {
"inputs": {
"strength": 1,
"set_cond_area": "default",
"positive_NEW": [
"3",
0
],
"negative_NEW": [
"5",
0
],
"mask": [
"42",
0
]
},
"class_type": "PairConditioningSetProperties",
"_meta": {
"title": "Cond Pair Set Props"
}
},
"20": {
"inputs": {
"mask": [
"42",
0
]
},
"class_type": "InvertMask",
"_meta": {
"title": "InvertMask"
}
},
"22": {
"inputs": {
"apply_to_conds": true,
"schedule_clip": false,
"clip": [
"2",
0
],
"hooks": [
"34",
0
]
},
"class_type": "SetClipHooks",
"_meta": {
"title": "Set CLIP Hooks"
}
},
"33": {
"inputs": {
"ckpt_name": "dreamshaper_8.safetensors",
"strength_model": 1,
"strength_clip": 1
},
"class_type": "CreateHookModelAsLora",
"_meta": {
"title": "Create Hook Model as LoRA"
}
},
"34": {
"inputs": {
"hooks": [
"33",
0
],
"hook_kf": [
"36",
0
]
},
"class_type": "SetHookKeyframes",
"_meta": {
"title": "Set Hook Keyframes"
}
},
"36": {
"inputs": {
"strength_start": 0,
"strength_end": 1,
"interpolation": "linear",
"start_percent": 0,
"end_percent": 0.5,
"keyframes_count": 5,
"print_keyframes": true
},
"class_type": "CreateHookKeyframesInterpolated",
"_meta": {
"title": "Create Hook Keyframes Interp."
}
},
"37": {
"inputs": {
"lora_name": "PixelArtRedmond15V-PixelArt-PIXARFK.safetensors",
"strength_model": 1,
"strength_clip": 1
},
"class_type": "CreateHookLora",
"_meta": {
"title": "Create Hook LoRA"
}
},
"38": {
"inputs": {
"hooks": [
"37",
0
],
"hook_kf": [
"36",
0
]
},
"class_type": "SetHookKeyframes",
"_meta": {
"title": "Set Hook Keyframes"
}
},
"39": {
"inputs": {
"hooks_A": [
"38",
0
]
},
"class_type": "CombineHooks2",
"_meta": {
"title": "Combine Hooks [2]"
}
},
"41": {
"inputs": {
"width": 768,
"height": 768,
"direction": "horizontal",
"tolerance": 0,
"gradient_stops": "0:255,255,255\n100:0,0,0"
},
"class_type": "ImageGenerateGradient",
"_meta": {
"title": "Image Generate Gradient"
}
},
"42": {
"inputs": {
"channel": "red",
"image": [
"41",
0
]
},
"class_type": "ImageToMask",
"_meta": {
"title": "Convert Image to Mask"
}
},
"43": {
"inputs": {
"images": [
"41",
0
]
},
"class_type": "PreviewImage",
"_meta": {
"title": "Preview Image"
}
}
}

View File

@ -1,5 +1,5 @@
import pytest
from comfy_execution.validation import validate_node_input
from comfy.validation import validate_node_input
def test_exact_match():

Binary file not shown.

Before

Width:  |  Height:  |  Size: 373 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 410 B