Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f680263631 | ||
|
|
704937f2b9 | ||
|
|
3b016e2fa4 | ||
|
|
1e946b4e48 | ||
|
|
21b13b56c0 | ||
|
|
7b9f0ec026 | ||
|
|
cf8ea2b875 | ||
|
|
20bd7b379d | ||
|
|
64a8f7f712 | ||
|
|
1a24cd2343 | ||
|
|
27eb860c93 | ||
|
|
deb787096f | ||
|
|
b6d712ec1c | ||
|
|
0b1341a5a3 | ||
|
|
2b01701d0a | ||
|
|
7ecf35c76d | ||
|
|
5f7c3d8a10 | ||
|
|
cc58814e07 | ||
|
|
d30f5ce579 |
@@ -160,3 +160,4 @@ cython_debug/
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
/temp/
|
||||
|
||||
+4
-1
@@ -1,3 +1,6 @@
|
||||
from .nodes import api # noqa
|
||||
from .nodes.nodes import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
|
||||
|
||||
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"]
|
||||
WEB_DIRECTORY = "./web"
|
||||
|
||||
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", "WEB_DIRECTORY"]
|
||||
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
import asyncio
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import uuid
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
import folder_paths
|
||||
from aiohttp import web
|
||||
from server import PromptServer
|
||||
|
||||
TEMP_FOLDER = Path(__file__).parent.parent / "temp"
|
||||
|
||||
|
||||
async def _write_requirements(zf: zipfile.ZipFile) -> None:
|
||||
print("Package => Writing requirements.txt")
|
||||
with zf.open("requirements.txt", "w") as f:
|
||||
proc = await asyncio.subprocess.create_subprocess_exec(
|
||||
sys.executable,
|
||||
"-m",
|
||||
"pip",
|
||||
"freeze",
|
||||
"--exclude-editable",
|
||||
stdout=subprocess.PIPE,
|
||||
)
|
||||
stdout, _ = await proc.communicate()
|
||||
f.write(stdout)
|
||||
|
||||
|
||||
async def _write_snapshot(zf: zipfile.ZipFile) -> None:
|
||||
proc = await asyncio.subprocess.create_subprocess_exec(
|
||||
"git", "rev-parse", "HEAD", stdout=subprocess.PIPE, cwd=folder_paths.base_path
|
||||
)
|
||||
stdout, _ = await proc.communicate()
|
||||
with zf.open("snapshot.json", "w") as f:
|
||||
data = {
|
||||
"python": f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
|
||||
"comfyui": stdout.decode().strip(),
|
||||
"models": await _get_models(),
|
||||
"custom_nodes": await _get_custom_nodes(),
|
||||
}
|
||||
f.write(json.dumps(data, indent=2).encode())
|
||||
|
||||
|
||||
async def _get_models() -> list:
|
||||
print("Package => Writing models")
|
||||
proc = await asyncio.subprocess.create_subprocess_exec(
|
||||
"git",
|
||||
"ls-files",
|
||||
"--others",
|
||||
folder_paths.models_dir,
|
||||
stdout=subprocess.PIPE,
|
||||
)
|
||||
stdout, _ = await proc.communicate()
|
||||
models = []
|
||||
for line in stdout.decode().splitlines():
|
||||
if os.path.basename(line).startswith("."):
|
||||
continue
|
||||
filename = os.path.abspath(line)
|
||||
relpath = os.path.relpath(filename, folder_paths.base_path)
|
||||
with open(filename, "rb") as model:
|
||||
models.append(
|
||||
{
|
||||
"filename": relpath,
|
||||
"sha256": hashlib.sha256(model.read()).hexdigest(),
|
||||
}
|
||||
)
|
||||
return models
|
||||
|
||||
|
||||
async def _get_custom_nodes() -> list:
|
||||
print("Package => Writing custom nodes")
|
||||
custom_nodes = os.path.join(folder_paths.base_path, "custom_nodes")
|
||||
coros = []
|
||||
|
||||
async def get_node_info(subdir: Path) -> dict:
|
||||
proc = await asyncio.subprocess.create_subprocess_exec(
|
||||
"git",
|
||||
"config",
|
||||
"--get",
|
||||
"remote.origin.url",
|
||||
cwd=subdir,
|
||||
stdout=subprocess.PIPE,
|
||||
)
|
||||
stdout, _ = await proc.communicate()
|
||||
url = stdout.decode().strip()
|
||||
|
||||
proc = await asyncio.subprocess.create_subprocess_exec(
|
||||
"git",
|
||||
"rev-parse",
|
||||
"HEAD",
|
||||
cwd=subdir,
|
||||
stdout=subprocess.PIPE,
|
||||
)
|
||||
stdout, _ = await proc.communicate()
|
||||
commit_hash = stdout.decode().strip()
|
||||
return {
|
||||
"url": url,
|
||||
"commit_hash": commit_hash,
|
||||
"disabled": subdir.name.endswith(".disabled"),
|
||||
}
|
||||
|
||||
for subdir in Path(custom_nodes).iterdir():
|
||||
if not subdir.is_dir() or not subdir.joinpath(".git").exists():
|
||||
continue
|
||||
coros.append(get_node_info(subdir))
|
||||
|
||||
return await asyncio.gather(*coros)
|
||||
|
||||
|
||||
async def _write_workflow(zf: zipfile.ZipFile, data: dict) -> None:
|
||||
print("Package => Writing workflow")
|
||||
with zf.open("workflow_api.json", "w") as f:
|
||||
f.write(json.dumps(data["workflow_api"], indent=2).encode())
|
||||
with zf.open("workflow.json", "w") as f:
|
||||
f.write(json.dumps(data["workflow"], indent=2).encode())
|
||||
|
||||
|
||||
async def _write_inputs(zf: zipfile.ZipFile, data: dict) -> None:
|
||||
print("Package => Writing inputs")
|
||||
input_dir = folder_paths.get_input_directory()
|
||||
|
||||
used_inputs = set()
|
||||
for node in data["workflow_api"].values():
|
||||
for k, v in node["inputs"].items():
|
||||
# if k in ("image", "path"):
|
||||
if isinstance(v, str):
|
||||
used_inputs.add(v)
|
||||
|
||||
for root_path, _, files in os.walk(input_dir):
|
||||
for file in files:
|
||||
if file not in used_inputs:
|
||||
continue
|
||||
file_path = os.path.join(root_path, file)
|
||||
relpath = os.path.relpath(file_path, input_dir)
|
||||
with zf.open(f"inputs/{relpath}", "w") as f:
|
||||
with open(file_path, "rb") as input_file:
|
||||
shutil.copyfileobj(input_file, f)
|
||||
|
||||
|
||||
@PromptServer.instance.routes.post("/bentoml/pack")
|
||||
async def pack_workspace(request):
|
||||
data = await request.json()
|
||||
TEMP_FOLDER.mkdir(exist_ok=True)
|
||||
older_than_1h = time.time() - 60 * 60
|
||||
for file in TEMP_FOLDER.iterdir():
|
||||
if file.is_file() and file.stat().st_ctime < older_than_1h:
|
||||
file.unlink()
|
||||
|
||||
zip_filename = f"{uuid.uuid4()}.zip"
|
||||
|
||||
with zipfile.ZipFile(TEMP_FOLDER / zip_filename, "w") as zf:
|
||||
await _write_requirements(zf)
|
||||
await _write_snapshot(zf)
|
||||
await _write_workflow(zf, data)
|
||||
await _write_inputs(zf, data)
|
||||
|
||||
return web.json_response({"download_url": f"/bentoml/download/{zip_filename}"})
|
||||
|
||||
|
||||
@PromptServer.instance.routes.get("/bentoml/download/{zip_filename}")
|
||||
async def download_workspace(request):
|
||||
zip_filename = request.match_info["zip_filename"]
|
||||
return web.FileResponse(TEMP_FOLDER / zip_filename)
|
||||
+35
-120
@@ -22,7 +22,7 @@ class AnyType(str):
|
||||
anytype = AnyType("*") # when a != b is called, it will always return False
|
||||
|
||||
|
||||
class OutputPath:
|
||||
class OutputFile:
|
||||
COLOR = (142, 36, 170)
|
||||
OUTPUT_NODE = True
|
||||
|
||||
@@ -180,7 +180,6 @@ class ImageInput:
|
||||
CATEGORY = "ComfyUI-IDL/input"
|
||||
BENTOML_NODE = True
|
||||
RETURN_TYPES = ("IMAGE", "MASK")
|
||||
RETUEN_NAMES = ("image", "mask")
|
||||
FUNCTION = "load_image"
|
||||
|
||||
def load_image(self, image):
|
||||
@@ -243,111 +242,7 @@ class ImageInput:
|
||||
return True
|
||||
|
||||
|
||||
class StringInput:
|
||||
COLOR = (142, 36, 170)
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"value": ("STRING", {"default": ""}),
|
||||
}
|
||||
}
|
||||
|
||||
RETUEN_NAMES = ("string",)
|
||||
RETURN_TYPES = (anytype,)
|
||||
BENTOML_NODE = True
|
||||
FUNCTION = "string_input"
|
||||
CATEGORY = "ComfyUI-IDL/input"
|
||||
|
||||
def string_input(self, value):
|
||||
return (value,)
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(s, value):
|
||||
set_bentoml_output([(value,)])
|
||||
return True
|
||||
|
||||
|
||||
class IntegerInput:
|
||||
COLOR = (142, 36, 170)
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"value": ("INT", {"default": 0}),
|
||||
}
|
||||
}
|
||||
|
||||
RETUEN_NAMES = ("int",)
|
||||
RETURN_TYPES = (anytype,)
|
||||
FUNCTION = "identity"
|
||||
BENTOML_NODE = True
|
||||
CATEGORY = "ComfyUI-IDL/input"
|
||||
|
||||
def identity(self, value):
|
||||
return (value,)
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(s, value):
|
||||
set_bentoml_output([(value,)])
|
||||
return True
|
||||
|
||||
|
||||
class FloatInput:
|
||||
COLOR = (142, 36, 170)
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"value": ("FLOAT", {"default": 0.0}),
|
||||
}
|
||||
}
|
||||
|
||||
RETUEN_NAMES = ("float",)
|
||||
RETURN_TYPES = (anytype,)
|
||||
FUNCTION = "identity"
|
||||
BENTOML_NODE = True
|
||||
CATEGORY = "ComfyUI-IDL/input"
|
||||
|
||||
def identity(self, value):
|
||||
return (value,)
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(s, value):
|
||||
set_bentoml_output([(value,)])
|
||||
return True
|
||||
|
||||
|
||||
class BooleanInput:
|
||||
COLOR = (142, 36, 170)
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"value": ("BOOLEAN", {"default": False}),
|
||||
}
|
||||
}
|
||||
|
||||
RETUEN_NAMES = ("bool",)
|
||||
RETURN_TYPES = (anytype,)
|
||||
FUNCTION = "identity"
|
||||
CATEGORY = "ComfyUI-IDL/input"
|
||||
BENTOML_NODE = True
|
||||
|
||||
def identity(self, value):
|
||||
return (value,)
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(s, value):
|
||||
set_bentoml_output([(value,)])
|
||||
return True
|
||||
|
||||
|
||||
class PathInput:
|
||||
class FileInput:
|
||||
COLOR = (142, 36, 170)
|
||||
|
||||
@classmethod
|
||||
@@ -359,7 +254,7 @@ class PathInput:
|
||||
}
|
||||
|
||||
RETURN_TYPES = (anytype,)
|
||||
RETUEN_NAMES = ("path",)
|
||||
RETURN_NAMES = ("path",)
|
||||
FUNCTION = "identity"
|
||||
BENTOML_NODE = True
|
||||
CATEGORY = "ComfyUI-IDL/input"
|
||||
@@ -373,24 +268,44 @@ class PathInput:
|
||||
return True
|
||||
|
||||
|
||||
class ValueInput:
|
||||
COLOR = (142, 36, 170)
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"input": ("*", {"default": ""}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = (anytype,)
|
||||
RENAME = ("value",)
|
||||
FUNCTION = "identity"
|
||||
BENTOML_NODE = True
|
||||
CATEGORY = "ComfyUI-IDL/input"
|
||||
|
||||
def identity(self, input):
|
||||
return (input,)
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(s, input):
|
||||
set_bentoml_output([(input,)])
|
||||
return True
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"BentoOutputPath": OutputPath,
|
||||
"BentoOutputFile": OutputFile,
|
||||
"BentoOutputImage": OutputImage,
|
||||
"BentoInputImage": ImageInput,
|
||||
"BentoInputString": StringInput,
|
||||
"BentoInputInteger": IntegerInput,
|
||||
"BentoInputFloat": FloatInput,
|
||||
"BentoInputBoolean": BooleanInput,
|
||||
"BentoInputPath": PathInput,
|
||||
"BentoInputFile": FileInput,
|
||||
"BentoInputValue": ValueInput,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"BentoInputImage": "Image Input",
|
||||
"BentoInputPath": "Path Input",
|
||||
"BentoInputInteger": "Integer Input",
|
||||
"BentoInputFloat": "Float Input",
|
||||
"BentoInputBoolean": "Boolean Input",
|
||||
"BentoInputString": "String Input",
|
||||
"BentoInputFile": "File Input",
|
||||
"BentoOutputImage": "Image Output",
|
||||
"BentoOutputPath": "Path Output",
|
||||
"BentoOutputFile": "File Output",
|
||||
"BentoInputValue": "Plain Value Input",
|
||||
}
|
||||
|
||||
+3
-3
@@ -3,9 +3,9 @@ name = "comfyui-idl"
|
||||
description = "ComfyUI Interface Definition Language"
|
||||
authors = [{ name = "Frost Ming", email = "frost@bentoml.com" }]
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.8"
|
||||
requires-python = ">=3.9"
|
||||
dependencies = [
|
||||
"comfy-cli>=0.0.14",
|
||||
"comfy-cli>=1.2.8",
|
||||
"pydantic>=2.9",
|
||||
]
|
||||
dynamic = ["version"]
|
||||
@@ -17,7 +17,7 @@ classifiers = [
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://github.com/bentoml/ComfyUI-BentoML"
|
||||
Homepage = "https://github.com/bentoml/ComfyUI-IDL"
|
||||
|
||||
[build-system]
|
||||
requires = ["pdm-backend"]
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
from comfyui_idl.run import WorkflowRunner
|
||||
from comfyui_idl.utils import (
|
||||
parse_workflow,
|
||||
generate_input_model,
|
||||
parse_workflow,
|
||||
populate_workflow,
|
||||
retrieve_workflow_outputs,
|
||||
)
|
||||
|
||||
from comfyui_idl.run import WorkflowRunner
|
||||
|
||||
__all__ = [
|
||||
"WorkflowRunner",
|
||||
"parse_workflow",
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import tempfile
|
||||
import json
|
||||
from typing import Union
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
|
||||
COMFYUI_REPO = "https://github.com/comfyanonymous/ComfyUI.git"
|
||||
|
||||
|
||||
def _clone_commit(
|
||||
url: str,
|
||||
commit: str,
|
||||
dir: Path,
|
||||
):
|
||||
if not dir.exists():
|
||||
dir.mkdir(parents=True)
|
||||
script = f"""cd {dir}
|
||||
git init
|
||||
git remote add origin {url}
|
||||
git fetch --depth 1 origin {commit}
|
||||
git checkout FETCH_HEAD
|
||||
"""
|
||||
subprocess.check_call(
|
||||
script,
|
||||
shell=True,
|
||||
)
|
||||
|
||||
|
||||
def install_comfyui(snapshot, workspace: Path):
|
||||
comfyui_commit = snapshot["comfyui"]
|
||||
|
||||
_clone_commit(
|
||||
COMFYUI_REPO,
|
||||
comfyui_commit,
|
||||
workspace,
|
||||
)
|
||||
|
||||
|
||||
def install_custom_modules(snapshot, workspace: Path):
|
||||
for module in snapshot["custom_nodes"]:
|
||||
url = module["url"]
|
||||
directory = url.split("/")[-1].split(".")[0]
|
||||
module_dir = workspace / "custom_nodes" / directory
|
||||
|
||||
commit_hash = module["commit_hash"]
|
||||
disabled = module.get("disabled", False)
|
||||
# if disabled:
|
||||
# continue
|
||||
_clone_commit(
|
||||
url,
|
||||
commit_hash,
|
||||
module_dir,
|
||||
)
|
||||
|
||||
|
||||
def install_dependencies(snapshot: dict, req_file: str, workspace: Path):
|
||||
python_version = snapshot["python"]
|
||||
subprocess.check_call(
|
||||
[
|
||||
"uv",
|
||||
"python",
|
||||
"install",
|
||||
python_version,
|
||||
],
|
||||
cwd=workspace,
|
||||
)
|
||||
venv = workspace / ".venv"
|
||||
if (venv / "DONE").exists():
|
||||
return
|
||||
venv_py = (
|
||||
venv / "Scripts" / "python.exe" if os.name == "nt" else venv / "bin" / "python"
|
||||
)
|
||||
subprocess.check_call(
|
||||
[
|
||||
"uv",
|
||||
"venv",
|
||||
"--python",
|
||||
python_version,
|
||||
venv,
|
||||
],
|
||||
)
|
||||
subprocess.check_call(
|
||||
[
|
||||
"uv",
|
||||
"pip",
|
||||
"install",
|
||||
"-p",
|
||||
str(venv_py),
|
||||
"pip",
|
||||
],
|
||||
)
|
||||
subprocess.check_call(
|
||||
[
|
||||
"uv",
|
||||
"pip",
|
||||
"install",
|
||||
"-p",
|
||||
str(venv_py),
|
||||
"-r",
|
||||
req_file,
|
||||
"--no-deps",
|
||||
],
|
||||
)
|
||||
with open(venv / "DONE", "w") as f:
|
||||
f.write("DONE")
|
||||
|
||||
|
||||
def install(cpack: Union[str, Path]):
|
||||
workspace = Path("workspace")
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
pack_dir = Path(temp_dir) / ".cpack"
|
||||
subprocess.check_call(
|
||||
[
|
||||
"unzip",
|
||||
"-o",
|
||||
cpack,
|
||||
"-d",
|
||||
pack_dir,
|
||||
]
|
||||
)
|
||||
snapshot = json.loads((pack_dir / "snapshot.json").read_text())
|
||||
req_txt_file = pack_dir / "requirements.txt"
|
||||
|
||||
install_comfyui(snapshot, workspace)
|
||||
install_custom_modules(snapshot, workspace)
|
||||
install_dependencies(snapshot, str(req_txt_file), workspace)
|
||||
for f in (pack_dir / "inputs").glob("*"):
|
||||
shutil.copy(f, workspace / "input" / f.name)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
|
||||
install(sys.argv[1])
|
||||
@@ -18,6 +18,15 @@ from comfyui_idl.utils import (
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _probe_comfyui_server():
|
||||
from urllib import parse, request
|
||||
url = 'http://127.0.0.1:8188/api/customnode/getmappings'
|
||||
params = {'mode': 'nickname'}
|
||||
full_url = f"{url}?{parse.urlencode(params)}"
|
||||
req = request.Request(full_url)
|
||||
_ = request.urlopen(req)
|
||||
|
||||
|
||||
class WorkflowRunner:
|
||||
"""
|
||||
A class to manage and run ComfyUI workflows.
|
||||
@@ -109,6 +118,7 @@ class WorkflowRunner:
|
||||
]
|
||||
if subprocess.run(command, check=True):
|
||||
self.is_running = True
|
||||
_probe_comfyui_server()
|
||||
logger.info("Successfully started ComfyUI in the background")
|
||||
else:
|
||||
logger.error("Failed to start ComfyUI in the background")
|
||||
|
||||
+36
-16
@@ -2,20 +2,11 @@ from __future__ import annotations
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any, Union
|
||||
from typing import TYPE_CHECKING, Any, Literal, Union
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pydantic import BaseModel
|
||||
|
||||
CLASS_TYPES = {
|
||||
"BentoInputString": str,
|
||||
"BentoInputBoolean": bool,
|
||||
"BentoInputInteger": int,
|
||||
"BentoInputFloat": float,
|
||||
"BentoInputPath": Path,
|
||||
"BentoInputImage": Path,
|
||||
}
|
||||
|
||||
BENTO_OUTPUT_NODES = {
|
||||
"BentoOutputPath",
|
||||
"BentoOutputImage",
|
||||
@@ -68,6 +59,13 @@ def _get_node_identifier(node, dep_map=None) -> str:
|
||||
return _normalize_to_identifier(title)
|
||||
|
||||
|
||||
API_WORKFLOW_MESSAGE = """
|
||||
It seems you are trying to parse an ordinary Workflow json file.
|
||||
Please save the Workflow with the Save (API Format).
|
||||
If you don't have this button, you must enable the "Dev mode Options" by clicking the Settings button on the top right (gear icon). Check the setting option "Enable Dev Mode options". After that, the Button Save (API Format) should appear.
|
||||
"""
|
||||
|
||||
|
||||
def _parse_workflow(workflow: dict) -> tuple[dict[str, Any], dict[str, Any]]:
|
||||
"""
|
||||
Parse the workflow template and return the input and output definition
|
||||
@@ -76,6 +74,9 @@ def _parse_workflow(workflow: dict) -> tuple[dict[str, Any], dict[str, Any]]:
|
||||
outputs = {}
|
||||
dep_map = {}
|
||||
|
||||
if "last_node_id" in workflow:
|
||||
raise ValueError(API_WORKFLOW_MESSAGE)
|
||||
|
||||
for id, node in workflow.items():
|
||||
for input_name, v in node["inputs"].items():
|
||||
if isinstance(v, list) and len(v) == 2: # is a link
|
||||
@@ -118,21 +119,40 @@ def generate_input_model(workflow: dict) -> type[BaseModel]:
|
||||
ValueError: If an unsupported class type is encountered in the workflow.
|
||||
"""
|
||||
from pydantic import Field, create_model
|
||||
from pydantic_core import PydanticUndefined
|
||||
|
||||
inputs, _ = _parse_workflow(workflow)
|
||||
|
||||
input_fields = {}
|
||||
for name, node in inputs.items():
|
||||
class_type = node["class_type"]
|
||||
if class_type in CLASS_TYPES:
|
||||
ann = CLASS_TYPES[class_type]
|
||||
if class_type in BENTO_PATH_INPUT_NODES:
|
||||
field = (ann, Field())
|
||||
if class_type in BENTO_PATH_INPUT_NODES:
|
||||
field = (Path, Field())
|
||||
elif class_type == "BentoInputValue":
|
||||
options = node.get("_meta", {}).get("options")
|
||||
value = _get_node_value(node)
|
||||
if not options:
|
||||
field = (type(value), Field(default=value))
|
||||
else:
|
||||
field = (ann, Field(default=_get_node_value(node)))
|
||||
input_fields[name] = field
|
||||
if values := options.get("values"): # combo type
|
||||
field = (Literal[tuple(values)], Field(default=value))
|
||||
elif any(
|
||||
f in options for f in ("min", "max", "round", "precision", "step")
|
||||
): # must be number types
|
||||
type_ = float if options.get("round", 1) < 1 else int
|
||||
field = (
|
||||
type_,
|
||||
Field(
|
||||
default=value,
|
||||
ge=options.get("min", PydanticUndefined),
|
||||
le=options.get("max", PydanticUndefined),
|
||||
),
|
||||
)
|
||||
else:
|
||||
field = (type(value), Field(default=value))
|
||||
else:
|
||||
raise ValueError(f"Unsupported class type: {class_type}")
|
||||
input_fields[name] = field
|
||||
return create_model("ParsedWorkflowTemplate", **input_fields)
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
version = 1
|
||||
requires-python = ">=3.8"
|
||||
requires-python = ">=3.9"
|
||||
resolution-markers = [
|
||||
"python_full_version < '3.13'",
|
||||
"python_full_version >= '3.13'",
|
||||
@@ -9,14 +9,26 @@ resolution-markers = [
|
||||
name = "annotated-types"
|
||||
version = "0.7.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.9'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyio"
|
||||
version = "4.6.2.post1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
||||
{ name = "idna" },
|
||||
{ name = "sniffio" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/9f/09/45b9b7a6d4e45c6bcb5bf61d19e3ab87df68e0601fa8c5293de3542546cc/anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c", size = 173422 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e4/f5/f2b75d2fc6f1a260f340f0e7c6a060f4dd2961cc16884ed851b0d18da06a/anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d", size = 90377 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2024.8.30"
|
||||
@@ -92,21 +104,6 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/90/6af4cd042066a4adad58ae25648a12c09c879efa4849c705719ba1b23d8c/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482", size = 144970 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/67/e5e7e0cbfefc4ca79025238b43cdf8a2037854195b37d6417f3d0895c4c2/charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", size = 94973 },
|
||||
{ url = "https://files.pythonhosted.org/packages/65/97/fc9bbc54ee13d33dc54a7fcf17b26368b18505500fc01e228c27b5222d80/charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", size = 102308 },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/f4/ccab93e631e7293cca82f9f7ba39783c967f823a0000df2d8dd743cad74f/charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578", size = 193961 },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/d4/2b21cb277bac9605026d2d91a4a8872bc82199ed11072d035dc674c27223/charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6", size = 124507 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/e0/a7c1fcdff20d9c667342e0391cfeb33ab01468d7d276b2c7914b371667cc/charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417", size = 119298 },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/de/1538bb2f84ac9940f7fa39945a5dd1d22b295a89c98240b262fc4b9fcfe0/charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51", size = 139328 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/ca/288bb1a6bc2b74fb3990bdc515012b47c4bc5925c8304fc915d03f94b027/charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41", size = 149368 },
|
||||
{ url = "https://files.pythonhosted.org/packages/aa/75/58374fdaaf8406f373e508dab3486a31091f760f99f832d3951ee93313e8/charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f", size = 141944 },
|
||||
{ url = "https://files.pythonhosted.org/packages/32/c8/0bc558f7260db6ffca991ed7166494a7da4fda5983ee0b0bfc8ed2ac6ff9/charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8", size = 143326 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/dd/7f6fec09a1686446cee713f38cf7d5e0669e0bcc8288c8e2924e998cf87d/charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab", size = 146171 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4c/a8/440f1926d6d8740c34d3ca388fbd718191ec97d3d457a0677eb3aa718fce/charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12", size = 139711 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/7f/4b71e350a3377ddd70b980bea1e2cc0983faf45ba43032b24b2578c14314/charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19", size = 148348 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/70/17b1b9202531a33ed7ef41885f0d2575ae42a1e330c67fddda5d99ad1208/charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea", size = 151290 },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/30/574b5b5933d77ecb015550aafe1c7d14a8cd41e7e6c4dcea5ae9e8d496c3/charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858", size = 149114 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/11/ca7786f7e13708687443082af20d8341c02e01024275a28bc75032c5ce5d/charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654", size = 143856 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/c2/1727c1438256c71ed32753b23ec2e6fe7b6dff66a598f6566cfe8139305e/charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613", size = 94333 },
|
||||
{ url = "https://files.pythonhosted.org/packages/09/c8/0e17270496a05839f8b500c1166e3261d1226e39b698a735805ec206967b/charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade", size = 101454 },
|
||||
{ url = "https://files.pythonhosted.org/packages/54/2f/28659eee7f5d003e0f5a3b572765bf76d6e0fe6601ab1f1b1dd4cba7e4f1/charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa", size = 196326 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/18/92869d5c0057baa973a3ee2af71573be7b084b3c3d428fe6463ce71167f8/charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a", size = 125614 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/27/327904c5a54a7796bb9f36810ec4173d2df5d88b401d2b95ef53111d214e/charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0", size = 120450 },
|
||||
@@ -148,27 +145,35 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "comfy-cli"
|
||||
version = "0.0.14"
|
||||
version = "1.2.9"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "charset-normalizer" },
|
||||
{ name = "gitpython" },
|
||||
{ name = "httpx" },
|
||||
{ name = "mixpanel" },
|
||||
{ name = "packaging" },
|
||||
{ name = "pathspec" },
|
||||
{ name = "psutil" },
|
||||
{ name = "pyyaml" },
|
||||
{ name = "questionary" },
|
||||
{ name = "requests" },
|
||||
{ name = "rich" },
|
||||
{ name = "semver" },
|
||||
{ name = "tomlkit" },
|
||||
{ name = "typer" },
|
||||
{ name = "typing-extensions" },
|
||||
{ name = "uv" },
|
||||
{ name = "websocket-client" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e5/95/a21898e75372ef97f4a02b45def0965efe406dee6b5d3fcd3c685d625c57/comfy_cli-0.0.14.tar.gz", hash = "sha256:16ae80089d89f4645a44ed4b9ac9cde7ff63b4f55a6c9f06aaefe4de95b690b8", size = 58316 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/80/1a/030b6f80ab1ce8af0442c8754dbb8c7f4f107192c85b8bedbc84d357f243/comfy_cli-1.2.9.tar.gz", hash = "sha256:e6aa35c3e3d3fd370cbd39d8b098e4875e22a8ed22bb8ad06360b8c33f607c9f", size = 69537 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/67/68/f6e2ef275bf1a497a06124388f1a87caac809aa4bf866e2a9a88b4dea2d9/comfy_cli-0.0.14-py3-none-any.whl", hash = "sha256:9318db88d2a8529d398c3efba8f670447dfd0063ea45b0cf6f3ef28e878cdd03", size = 49185 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9d/1a/8a8717e8a5709c824e2e64260fcad56d38f83d071568c2454ecf87e8123e/comfy_cli-1.2.9-py3-none-any.whl", hash = "sha256:a81166baa71cfeb920423cd4d30fbbae732f0eca15c0a3cd98e17ea13c5b64f7", size = 76733 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "comfyui-idl"
|
||||
version = "0.0.4+d20241111"
|
||||
version = "0.0.5.dev1+g3c36cfc.d20241111"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "comfy-cli" },
|
||||
@@ -177,10 +182,19 @@ dependencies = [
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "comfy-cli", specifier = ">=0.0.14" },
|
||||
{ name = "comfy-cli", specifier = ">=1.2.8" },
|
||||
{ name = "pydantic", specifier = ">=2.9" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exceptiongroup"
|
||||
version = "1.2.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gitdb"
|
||||
version = "4.0.11"
|
||||
@@ -205,6 +219,44 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/bd/cc3a402a6439c15c3d4294333e13042b915bbeab54edc457c723931fed3f/GitPython-3.1.43-py3-none-any.whl", hash = "sha256:eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff", size = 207337 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h11"
|
||||
version = "0.14.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httpcore"
|
||||
version = "1.0.6"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "certifi" },
|
||||
{ name = "h11" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b6/44/ed0fa6a17845fb033bd885c03e842f08c1b9406c86a2e60ac1ae1b9206a6/httpcore-1.0.6.tar.gz", hash = "sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f", size = 85180 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/06/89/b161908e2f51be56568184aeb4a880fd287178d176fd1c860d2217f41106/httpcore-1.0.6-py3-none-any.whl", hash = "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f", size = 78011 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httpx"
|
||||
version = "0.27.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
{ name = "certifi" },
|
||||
{ name = "httpcore" },
|
||||
{ name = "idna" },
|
||||
{ name = "sniffio" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/78/82/08f8c936781f67d9e6b9eeb8a0c8b4e406136ea4c3d1f89a5db71d42e0e6/httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2", size = 144189 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0", size = 76395 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.10"
|
||||
@@ -249,6 +301,24 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/72/5a/8048544f73e22ebd27bdeca64ce51578578873e5da9ba3d3f99d692f9034/mixpanel-4.10.1-py2.py3-none-any.whl", hash = "sha256:a7a338b7197327e36356dbc1903086e7626db6d88367ccdd732b3f3c60d3b3ed", size = 8954 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "24.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathspec"
|
||||
version = "0.12.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prompt-toolkit"
|
||||
version = "3.0.36"
|
||||
@@ -347,18 +417,6 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/16/16/b805c74b35607d24d37103007f899abc4880923b04929547ae68d478b7f4/pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f", size = 2116814 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/58/5305e723d9fcdf1c5a655e6a4cc2a07128bf644ff4b1d98daf7a9dbf57da/pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769", size = 1738360 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/ae/e14b0ff8b3f48e02394d8acd911376b7b66e164535687ef7dc24ea03072f/pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5", size = 1919411 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b0/3f/790c72662823955c4803487bcda8dfce5a9e2ddcaf709f7993e12ede29fd/pydantic_core-2.23.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555", size = 1867828 },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/f6/6ceeeb0005fabdf3f99a7fa1be52db41c328b438ebfa88f7b3f2815fb157/pydantic_core-2.23.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658", size = 1748962 },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/08/c1c49218a87c6e079730fed0357a5883c2f6fbf43e9da0eb2501384e0975/pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271", size = 1800821 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0a/92/e8f4de3453a3446ca2da5dc5d636fbd644dc9923f74812cfb63549df79ee/pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665", size = 1805527 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/06/cb8891f40d4b1d5744c24a3082e3031b16727fdc927cf4dc6bbe2fb9e9a3/pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368", size = 2002267 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/3b/7d2ab72afa3deb18baeb6c3373ad3181922da541bfae63aecbef51a9fadc/pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13", size = 2654837 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/a4/229432a701acd98575b88ccaff82e8435c75c44cb30522004afb263e3756/pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad", size = 2054177 },
|
||||
{ url = "https://files.pythonhosted.org/packages/50/bd/4a40a83e476af0a86e1f57559dd324b922b5e60faaa866de400efe033ca1/pydantic_core-2.23.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12", size = 1920918 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4b/98/857e2bdae80432efff030812add720d6797b63c790f13e123c8274a3337b/pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2", size = 1965814 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/87/cacb1152a821340e11f870e0fbd6613c2f05278dab5def47c7818eac1a22/pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb", size = 2111058 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/ce/a3bd2de2582be6e5b187218896cac734377fcc8d5a54f98b83d710125ef0/pydantic_core-2.23.4-cp38-none-win32.whl", hash = "sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6", size = 1734749 },
|
||||
{ url = "https://files.pythonhosted.org/packages/db/c8/e6ed2172bb2594a256c7756a70109fa31ab80d1cebb9003ad6c54e10c0d1/pydantic_core-2.23.4-cp38-none-win_amd64.whl", hash = "sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556", size = 1920302 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7a/04/2580b2deaae37b3e30fc30c54298be938b973990b23612d6b61c7bdd01c7/pydantic_core-2.23.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a", size = 1868200 },
|
||||
{ url = "https://files.pythonhosted.org/packages/39/6e/e311bd0751505350f0cdcee3077841eb1f9253c5a1ddbad048cd9fbf7c6e/pydantic_core-2.23.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36", size = 1749316 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/b4/95b5eb47c6dc8692508c3ca04a1f8d6f0884c9dacb34cf3357595cbe73be/pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b", size = 1800880 },
|
||||
@@ -440,13 +498,6 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 },
|
||||
{ url = "https://files.pythonhosted.org/packages/74/d9/323a59d506f12f498c2097488d80d16f4cf965cee1791eab58b56b19f47a/PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", size = 183218 },
|
||||
{ url = "https://files.pythonhosted.org/packages/74/cc/20c34d00f04d785f2028737e2e2a8254e1425102e730fee1d6396f832577/PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", size = 728067 },
|
||||
{ url = "https://files.pythonhosted.org/packages/20/52/551c69ca1501d21c0de51ddafa8c23a0191ef296ff098e98358f69080577/PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", size = 757812 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/7f/2c3697bba5d4aa5cc2afe81826d73dfae5f049458e44732c7a0938baa673/PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", size = 746531 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/ab/6226d3df99900e580091bb44258fde77a8433511a86883bd4681ea19a858/PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", size = 800820 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/99/a9eb0f3e710c06c5d922026f6736e920d431812ace24aae38228d0d64b04/PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", size = 145514 },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/8a/ee831ad5fafa4431099aa4e078d4c8efd43cd5e48fbc774641d233b683a9/PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", size = 162702 },
|
||||
{ url = "https://files.pythonhosted.org/packages/65/d8/b7a1db13636d7fb7d4ff431593c510c8b8fca920ade06ca8ef20015493c5/PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", size = 184777 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0a/02/6ec546cd45143fdf9840b2c6be8d875116a64076218b61d68e12548e5839/PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", size = 172318 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/9a/8cc68be846c972bda34f6c2a93abb644fb2476f4dcc924d52175786932c9/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", size = 720891 },
|
||||
@@ -499,6 +550,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "3.0.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/41/6c/a536cc008f38fd83b3c1b98ce19ead13b746b5588c9a0cb9dd9f6ea434bc/semver-3.0.2.tar.gz", hash = "sha256:6253adb39c70f6e51afed2fa7152bcd414c411286088fb4b9effb133885ab4cc", size = 214988 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/77/0cc7a8a3bc7e53d07e8f47f147b92b0960e902b8254859f4aee5c4d7866b/semver-3.0.2-py3-none-any.whl", hash = "sha256:b1ea4686fe70b981f85359eda33199d60c53964284e0cfb4977d243e37cf4bf4", size = 17099 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shellingham"
|
||||
version = "1.5.4"
|
||||
@@ -526,6 +586,24 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/a5/10f97f73544edcdef54409f1d839f6049a0d79df68adbc1ceb24d1aaca42/smmap-5.0.1-py3-none-any.whl", hash = "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da", size = 24282 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sniffio"
|
||||
version = "1.3.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tomlkit"
|
||||
version = "0.13.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b1/09/a439bec5888f00a54b8b9f05fa94d7f901d6735ef4e55dcec9bc37b5d8fa/tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79", size = 192885 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/b6/a447b5e4ec71e13871be01ba81f5dfc9d0af7e473da256ff46bc0e24026f/tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde", size = 37955 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typer"
|
||||
version = "0.13.0"
|
||||
@@ -559,6 +637,31 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", size = 126338 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uv"
|
||||
version = "0.5.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d2/ec/c05991014f8208c1f3556d7dfc96ef5a6b7da6062e489718f3a0f9a74fb8/uv-0.5.1.tar.gz", hash = "sha256:ad2dd8a994a8334a5d4b354589be4b8c4b3b2ebb7bb2f2976c8e21d2799f45a9", size = 2131866 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/33/9183528527cb8532369b678e1d12fb97e3777fed875f1d7ea6c75c570f64/uv-0.5.1-py3-none-linux_armv6l.whl", hash = "sha256:93f0a02ea9149f4e7e359ef92da6f221da2ecf458cda2af729a1f6fa8c3ed1d2", size = 13504611 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/23/f0f8234624f720b5a856800d85a2220405182cfd798eefbda8b7868f9c4d/uv-0.5.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:f66859e67d10ffff8b17c67c7ede207d67487cef20c3d17bc427b690f9dff795", size = 13482839 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/ef/375bb00fa3e73cbb29ffd1d2a0cea3a52b4c0e67f68bce646a9ed0539f18/uv-0.5.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c4d209164448c8529e21aca4ef1e3da94303b1bf726924786feffd87ed93ab4a", size = 12503012 },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/f1/244f0f5e0afdc86de3c12c62c51f594a8b900d8ae1bf7cc64d9d92147199/uv-0.5.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:6ec61220d883751777cbabf0b076607cfbdeb812bc52c28722e897271461e589", size = 12787137 },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/fc/74a2fbfb9fc5c1772c0f85718da3e79a05aa3bdd5db1d83851f33e119e01/uv-0.5.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:73853b98bce9e118cda2d64360ddd7e0f79e237aca8cd2f28b6d5679400b239e", size = 13300628 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/81/0c08c94a9c9f27adc11fd9c3f55d6244c3066cbdea1a9c636fcc1bf45d53/uv-0.5.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8dce5b6d6dea41db71fe8d9895167cc5abf3e7b28c016174b1b9a9aecb74d483", size = 13874679 },
|
||||
{ url = "https://files.pythonhosted.org/packages/eb/8c/2b3c642d71f18eff826a74329b23a269f2962b52d251854b645c98121e15/uv-0.5.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:aaa63053ff6dc4456e2ac2a9b6a8eda0cfaa1e0f861633d9e7315c7df9a0a525", size = 14437581 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/65/bae32b05056ba6b5441a491ce17c8216ec92cfade62a7b44702758689646/uv-0.5.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac3fce68002e79f3c070f3e7d914e992f205f05af00bfffbe6c44d37aa39c86a", size = 14164878 },
|
||||
{ url = "https://files.pythonhosted.org/packages/51/1a/38edd7edf8fc73d1db87130f4ac62f2381166fabcc36288b63d82e43373c/uv-0.5.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72b54a3308e13a81aa2df19baea40611fc344c7556f75d2113f9b9b5a894355e", size = 18438644 },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/24/b2f69c0adb60d4c5d3c5413454ab869ed275db52da4be02eaa9d1a149191/uv-0.5.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d1ec4a1bc19b523a84fc1bf2a92e9c4d982c831d3da450af71fc3057999d456", size = 13988358 },
|
||||
{ url = "https://files.pythonhosted.org/packages/43/80/1d887496fa3f2853dd670e43da90ee6efa8e020c82e3a1e2b41c19006d9d/uv-0.5.1-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:01c40f756e9536c05fdf3485c1dfe3da610c3169195bbe20fab03a4c4b7a0d98", size = 12970766 },
|
||||
{ url = "https://files.pythonhosted.org/packages/11/0c/5ba7bf4b5ca478cf8c9d660d7baa977af1cd3dda2981f20d0c8e436a48f2/uv-0.5.1-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:3db7513c804fb89dcde671ba917cc486cfb574408d6257e19b19ae6b55f5982f", size = 13274891 },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/08/1ad7ef9ffd0f3c534cbcad47b57afdb785143ec46973faecc5c90de33025/uv-0.5.1-py3-none-musllinux_1_1_i686.whl", hash = "sha256:4601d40b0c02aff9fb791efa5b6f4c7dbad0970e13ac679aa8fb07365f331354", size = 13609667 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fc/e5/56d1457ac76bedce375c1adbfebeb281d94a24d35463350c7fc40f9413b8/uv-0.5.1-py3-none-musllinux_1_1_ppc64le.whl", hash = "sha256:821b6a9d591d3e951fbe81c53d32499d11500100d66b1c119e183f3d4a6cd07c", size = 15349628 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c5/0a/956467ee8bfa59f698f384eef6e072b14b971d36b7ee6d9b8ed15cfed065/uv-0.5.1-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:6a76765c3cc49268f3c6773bd89a0dacf8a91b040fc3faea6c527ef6f2308eba", size = 14110649 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/94/d7546d96c0e447f56817be2210c4a9d75817d1072e526aaaf17f0dd59a3e/uv-0.5.1-py3-none-win32.whl", hash = "sha256:3ffb230be0f6552576da67a2737a32a6a640e4b3f42144088222a669802d7f10", size = 13423908 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/b2/ac107886f60081f6cd2295c9faf3c312a02c5aca87e8c0b7589340a58224/uv-0.5.1-py3-none-win_amd64.whl", hash = "sha256:922685dcaa1c9b6663649b379f9bdbe5b87af230f512e69398efc51bd9d8b8eb", size = 15169543 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wcwidth"
|
||||
version = "0.2.13"
|
||||
@@ -567,3 +670,12 @@ sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "websocket-client"
|
||||
version = "1.8.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e6/30/fba0d96b4b5fbf5948ed3f4681f7da2f9f64512e1d303f94b4cc174c24a5/websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da", size = 54648 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", size = 58826 },
|
||||
]
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import { app } from "../../scripts/app.js";
|
||||
|
||||
function mimicNode(node, target, slot) {
|
||||
const getWidget = (widget) => {
|
||||
if (typeof widget.origType === "undefined") return widget;
|
||||
const newWidget = Object.assign({}, widget);
|
||||
for (const key in widget) {
|
||||
if (key.startsWith("orig") || key === "computeSize") {
|
||||
delete newWidget[key];
|
||||
}
|
||||
}
|
||||
newWidget.type = widget.origType;
|
||||
newWidget.name = inputName;
|
||||
return newWidget;
|
||||
}
|
||||
const input = target.inputs[slot];
|
||||
const inputName = node.inputs.length > 0 ? node.inputs[0].name : node.widgets[0].name;
|
||||
if (typeof input.widget === "undefined") { // This is an input
|
||||
node.inputs = [{ ...input, name: inputName }];
|
||||
node.widgets = [];
|
||||
} else { // This is a widget
|
||||
node.widgets = [getWidget(target.widgets.find(w => w.name === input.name))];
|
||||
node.inputs = [];
|
||||
node.size = node.computeSize();
|
||||
requestAnimationFrame(() => {
|
||||
if (node.onResize) {
|
||||
node.onResize(node.size);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
app.registerExtension({
|
||||
name: "Comfy.DynamicInput",
|
||||
extensionNodes: ["BentoInputValue", "BentoInputFile"],
|
||||
|
||||
async beforeRegisterNodeDef(nodeType, nodeData) {
|
||||
if (!this.extensionNodes.includes(nodeData.name)) return;
|
||||
|
||||
nodeType.prototype.onConnectOutput = function () {
|
||||
if (this.outputs[0].links?.length > 0) return false;
|
||||
const target = arguments[3];
|
||||
if (this.type === "BentoInputFile" && !["COMBO", "STRING"].includes(target.inputs[arguments[4]].type))
|
||||
return false;
|
||||
mimicNode(this, target, arguments[4]);
|
||||
this.title = target.inputs[arguments[4]].name;
|
||||
}
|
||||
},
|
||||
|
||||
async setup(app) {
|
||||
app.graph.nodes.forEach((node) => {
|
||||
if (!this.extensionNodes.includes(node.type)) return;
|
||||
if (node.outputs.length > 0 && node.outputs[0].links.length > 0) {
|
||||
const link = node.graph.links[node.outputs[0].links[0]];
|
||||
mimicNode(node, app.graph.getNodeById(link.target_id), link.target_slot);
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
async init(app) {
|
||||
const originalToPrompt = app.graphToPrompt;
|
||||
const self = this;
|
||||
app.graphToPrompt = async function(graph = app.graph, clean = true) {
|
||||
const { workflow, output } = await originalToPrompt(graph, clean);
|
||||
Object.entries(output).forEach(([id, nodeData]) => {
|
||||
if (!self.extensionNodes.includes(nodeData.class_type)) return;
|
||||
const node = graph.getNodeById(parseInt(id));
|
||||
if (node.widgets.length === 0) return;
|
||||
const widget = node.widgets[0];
|
||||
nodeData["_meta"] = Object.assign({}, nodeData["_meta"] || {}, { options: widget.options });
|
||||
});
|
||||
return { workflow, output };
|
||||
};
|
||||
}
|
||||
});
|
||||
+234
@@ -0,0 +1,234 @@
|
||||
import { app } from "../../scripts/app.js";
|
||||
import { api } from "../../scripts/api.js";
|
||||
|
||||
function createInputModal() {
|
||||
return new Promise((resolve) => {
|
||||
const modal = document.createElement("div");
|
||||
modal.style.cssText = `
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: #1a1a1a;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
z-index: 1000;
|
||||
min-width: 300px;
|
||||
`;
|
||||
|
||||
const title = document.createElement("h3");
|
||||
title.textContent = "Package Worlflow";
|
||||
title.style.cssText = `
|
||||
margin-bottom: 15px;
|
||||
color: #fff;
|
||||
`;
|
||||
|
||||
const input = document.createElement("input");
|
||||
input.type = "text";
|
||||
input.value = "package";
|
||||
input.style.cssText = `
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
margin-bottom: 15px;
|
||||
background: #333;
|
||||
border: 1px solid #444;
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
box-sizing: border-box;
|
||||
`;
|
||||
|
||||
const buttonContainer = document.createElement("div");
|
||||
buttonContainer.style.cssText = `
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
`;
|
||||
|
||||
const confirmButton = document.createElement("button");
|
||||
confirmButton.textContent = "Confirm";
|
||||
confirmButton.style.cssText = `
|
||||
padding: 6px 12px;
|
||||
background: #00a67d;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
const cancelButton = document.createElement("button");
|
||||
cancelButton.textContent = "Cancel";
|
||||
cancelButton.style.cssText = `
|
||||
padding: 6px 12px;
|
||||
background: #666;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
const overlay = document.createElement("div");
|
||||
overlay.style.cssText = `
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 999;
|
||||
`;
|
||||
|
||||
buttonContainer.appendChild(cancelButton);
|
||||
buttonContainer.appendChild(confirmButton);
|
||||
modal.appendChild(title);
|
||||
modal.appendChild(input);
|
||||
modal.appendChild(buttonContainer);
|
||||
document.body.appendChild(overlay);
|
||||
document.body.appendChild(modal);
|
||||
|
||||
const cleanup = () => {
|
||||
modal.remove();
|
||||
overlay.remove();
|
||||
};
|
||||
|
||||
confirmButton.onclick = () => {
|
||||
const filename = input.value.trim();
|
||||
if (filename) {
|
||||
cleanup();
|
||||
resolve(filename);
|
||||
}
|
||||
};
|
||||
|
||||
cancelButton.onclick = () => {
|
||||
cleanup();
|
||||
resolve(null);
|
||||
};
|
||||
|
||||
input.addEventListener("keyup", (e) => {
|
||||
if (e.key === "Enter") {
|
||||
confirmButton.click();
|
||||
}
|
||||
});
|
||||
|
||||
input.select();
|
||||
});
|
||||
}
|
||||
|
||||
function createDownloadModal() {
|
||||
const modal = document.createElement("div");
|
||||
modal.style.cssText = `
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: #1a1a1a;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
z-index: 1000;
|
||||
min-width: 300px;
|
||||
`;
|
||||
|
||||
const title = document.createElement("h3");
|
||||
title.textContent = "Packaging...";
|
||||
title.style.marginBottom = "15px";
|
||||
title.style.color = "#fff";
|
||||
|
||||
const progress = document.createElement("div");
|
||||
progress.style.cssText = `
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
background: #333;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
`;
|
||||
|
||||
const progressBar = document.createElement("div");
|
||||
progressBar.style.cssText = `
|
||||
width: 0%;
|
||||
height: 100%;
|
||||
background: #00a67d;
|
||||
transition: width 0.3s ease;
|
||||
`;
|
||||
|
||||
progress.appendChild(progressBar);
|
||||
modal.appendChild(title);
|
||||
modal.appendChild(progress);
|
||||
|
||||
const overlay = document.createElement("div");
|
||||
overlay.style.cssText = `
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 999;
|
||||
`;
|
||||
|
||||
document.body.appendChild(overlay);
|
||||
document.body.appendChild(modal);
|
||||
|
||||
return {
|
||||
modal,
|
||||
overlay,
|
||||
progressBar,
|
||||
updateProgress: (percent) => {
|
||||
progressBar.style.width = `${percent}%`;
|
||||
},
|
||||
close: () => {
|
||||
modal.remove();
|
||||
overlay.remove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
app.registerExtension({
|
||||
name: "Comfy.BentoExtension",
|
||||
|
||||
async setup() {
|
||||
const menu = document.querySelector(".comfy-menu");
|
||||
const separator = document.createElement("hr");
|
||||
|
||||
separator.style.margin = "20px 0";
|
||||
separator.style.width = "100%";
|
||||
menu.append(separator);
|
||||
const packButton = document.createElement("button");
|
||||
packButton.textContent = "Package";
|
||||
packButton.onclick = async () => {
|
||||
const filename = await createInputModal();
|
||||
if (!filename) return;
|
||||
|
||||
packButton.disabled = true;
|
||||
const downloadModal = createDownloadModal();
|
||||
|
||||
try {
|
||||
downloadModal.updateProgress(20);
|
||||
const { workflow, output: workflow_api } = await app.graphToPrompt();
|
||||
|
||||
downloadModal.updateProgress(40);
|
||||
const body = JSON.stringify({ workflow, workflow_api });
|
||||
|
||||
downloadModal.updateProgress(60);
|
||||
const resp = await api.fetchApi("/bentoml/pack", { method: "POST", body, headers: { "Content-Type": "application/json" } });
|
||||
|
||||
downloadModal.updateProgress(80);
|
||||
const downloadUrl = (await resp.json())["download_url"];
|
||||
|
||||
downloadModal.updateProgress(100);
|
||||
const link = document.createElement("a");
|
||||
link.href = downloadUrl;
|
||||
link.download = filename + ".cpack.zip";
|
||||
link.click();
|
||||
|
||||
setTimeout(() => {
|
||||
downloadModal.close();
|
||||
}, 1000);
|
||||
} catch (error) {
|
||||
console.error("Package failed:", error);
|
||||
downloadModal.close();
|
||||
} finally {
|
||||
packButton.disabled = false;
|
||||
}
|
||||
}
|
||||
menu.append(packButton);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user