Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbf66db398 | ||
|
|
56a9cb88ac | ||
|
|
d15c4c54ad | ||
|
|
f54ff9aa92 | ||
|
|
3f07d59b58 | ||
|
|
e181b07499 | ||
|
|
48ba44cc6c | ||
|
|
dfe00bfc21 | ||
|
|
bcb5b4b809 | ||
|
|
2cbc0ee754 | ||
|
|
b850017f39 | ||
|
|
8f7289c97e | ||
|
|
eae4e789fe | ||
|
|
0ac43cf5c3 | ||
|
|
1b553459a5 | ||
|
|
2f0cab20d2 |
+18
-5
@@ -31,7 +31,7 @@ EXCLUDE_PACKAGES = ["bentoml", "onnxruntime", "conda"] # TODO: standardize this
|
|||||||
|
|
||||||
def _get_requirement_string(dist: Distribution) -> str:
|
def _get_requirement_string(dist: Distribution) -> str:
|
||||||
direct_url_text = dist.read_text("direct_url.json")
|
direct_url_text = dist.read_text("direct_url.json")
|
||||||
pinned_str = f'{dist.metadata["Name"]}=={dist.version}'
|
pinned_str = f"{dist.metadata['Name']}=={dist.version}"
|
||||||
if not direct_url_text:
|
if not direct_url_text:
|
||||||
return pinned_str
|
return pinned_str
|
||||||
direct_url = json.loads(direct_url_text)
|
direct_url = json.loads(direct_url_text)
|
||||||
@@ -48,10 +48,21 @@ def _get_requirement_string(dist: Distribution) -> str:
|
|||||||
return pinned_str
|
return pinned_str
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_name(name: str) -> str:
|
||||||
|
import re
|
||||||
|
|
||||||
|
return re.sub(r"[-_.]+", "-", name).lower()
|
||||||
|
|
||||||
|
|
||||||
async def _write_requirements(path: ZPath, extras: list[str] | None = None) -> None:
|
async def _write_requirements(path: ZPath, extras: list[str] | None = None) -> None:
|
||||||
print("Package => Writing requirements.txt")
|
print("Package => Writing requirements.txt")
|
||||||
|
seen_packages: set[str] = set(EXCLUDE_PACKAGES)
|
||||||
with path.joinpath("requirements.txt").open("w") as f:
|
with path.joinpath("requirements.txt").open("w") as f:
|
||||||
for dist in distributions():
|
for dist in distributions():
|
||||||
|
pkg_name = normalize_name(dist.metadata["Name"])
|
||||||
|
if pkg_name in seen_packages:
|
||||||
|
continue
|
||||||
|
seen_packages.add(pkg_name)
|
||||||
f.write(_get_requirement_string(dist) + "\n")
|
f.write(_get_requirement_string(dist) + "\n")
|
||||||
if extras:
|
if extras:
|
||||||
f.write("\n".join(extras) + "\n")
|
f.write("\n".join(extras) + "\n")
|
||||||
@@ -158,7 +169,7 @@ async def _get_models(
|
|||||||
if should_store:
|
if should_store:
|
||||||
import bentoml
|
import bentoml
|
||||||
|
|
||||||
model_tag = f'cpack-model:{model_data["sha256"][:16]}'
|
model_tag = f"cpack-model:{model_data['sha256'][:16]}"
|
||||||
try:
|
try:
|
||||||
model = bentoml.models.get(model_tag)
|
model = bentoml.models.get(model_tag)
|
||||||
except bentoml.exceptions.NotFound:
|
except bentoml.exceptions.NotFound:
|
||||||
@@ -277,6 +288,8 @@ class DevServer:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def start(cls, workflow_api: dict, port: int = 3000):
|
def start(cls, workflow_api: dict, port: int = 3000):
|
||||||
|
from comfy_pack import __file__ as comfy_pack_file
|
||||||
|
|
||||||
cls.stop()
|
cls.stop()
|
||||||
|
|
||||||
cls.port = port
|
cls.port = port
|
||||||
@@ -285,7 +298,7 @@ class DevServer:
|
|||||||
with cls.run_dir.joinpath("workflow_api.json").open("w") as f:
|
with cls.run_dir.joinpath("workflow_api.json").open("w") as f:
|
||||||
f.write(json.dumps(workflow_api, indent=2))
|
f.write(json.dumps(workflow_api, indent=2))
|
||||||
shutil.copy(
|
shutil.copy(
|
||||||
Path(__file__).with_name("service.py"),
|
Path(comfy_pack_file).with_name("service.py"),
|
||||||
cls.run_dir / "service.py",
|
cls.run_dir / "service.py",
|
||||||
)
|
)
|
||||||
shutil.copytree(COMFY_PACK_DIR, cls.run_dir / COMFY_PACK_DIR.name)
|
shutil.copytree(COMFY_PACK_DIR, cls.run_dir / COMFY_PACK_DIR.name)
|
||||||
@@ -469,7 +482,7 @@ async def _prepare_pack(
|
|||||||
model_filter=model_filter,
|
model_filter=model_filter,
|
||||||
)
|
)
|
||||||
|
|
||||||
await _write_requirements(working_dir, ["comfy-cli", "fastapi"])
|
await _write_requirements(working_dir, ["comfy-cli", "fastapi", "comfy-pack"])
|
||||||
await _write_snapshot(working_dir, data, models)
|
await _write_snapshot(working_dir, data, models)
|
||||||
await _write_workflow(working_dir, data)
|
await _write_workflow(working_dir, data)
|
||||||
await _write_inputs(working_dir, data)
|
await _write_inputs(working_dir, data)
|
||||||
@@ -542,7 +555,7 @@ async def build_bento_api(request):
|
|||||||
bento = build_bento(
|
bento = build_bento(
|
||||||
data["bento_name"],
|
data["bento_name"],
|
||||||
temp_dir_path,
|
temp_dir_path,
|
||||||
data.get("system_packages"),
|
system_packages=data.get("system_packages"),
|
||||||
)
|
)
|
||||||
except bentoml.exceptions.BentoMLException as e:
|
except bentoml.exceptions.BentoMLException as e:
|
||||||
return web.json_response(
|
return web.json_response(
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ authors = [{ name = "Frost Ming", email = "frost@bentoml.com" }]
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.9"
|
requires-python = ">=3.9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bentoml>=1.3.13",
|
"bentoml>=1.3.21",
|
||||||
"click>=8.1.7",
|
"click>=8.1.7",
|
||||||
"comfy-cli>=1.2.8",
|
"comfy-cli>=1.2.8",
|
||||||
]
|
]
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
bentoml
|
bentoml>=1.3.21
|
||||||
fastapi
|
fastapi
|
||||||
comfy-cli
|
comfy-cli
|
||||||
duckduckgo-search
|
duckduckgo-search
|
||||||
|
|||||||
@@ -404,6 +404,7 @@ def run(ctx, cpack: str, output_dir: str, help: bool, verbose: int):
|
|||||||
workflow,
|
workflow,
|
||||||
Path(output_dir).absolute(),
|
Path(output_dir).absolute(),
|
||||||
verbose=verbose,
|
verbose=verbose,
|
||||||
|
workspace=server.workspace,
|
||||||
**validated_data.model_dump(),
|
**validated_data.model_dump(),
|
||||||
)
|
)
|
||||||
console.print("\n[green]✓ Workflow is executed successfully![/green]")
|
console.print("\n[green]✓ Workflow is executed successfully![/green]")
|
||||||
@@ -443,6 +444,13 @@ def bento_cmd(source: str, name: str | None, version: str | None):
|
|||||||
build_config = BentoBuildConfig.from_bento_dir(
|
build_config = BentoBuildConfig.from_bento_dir(
|
||||||
existing_bento.path_of("src")
|
existing_bento.path_of("src")
|
||||||
)
|
)
|
||||||
|
requirements_txt = Path(temp_dir) / "requirements.txt"
|
||||||
|
if (
|
||||||
|
requirements_txt.exists()
|
||||||
|
and "comfy-pack" not in requirements_txt.read_text()
|
||||||
|
):
|
||||||
|
with open(requirements_txt, "a") as f:
|
||||||
|
f.write("\ncomfy-pack")
|
||||||
system_packages = build_config.docker.system_packages
|
system_packages = build_config.docker.system_packages
|
||||||
include_default_system_packages = False
|
include_default_system_packages = False
|
||||||
|
|
||||||
|
|||||||
@@ -29,24 +29,28 @@ def _clone_commit(url: str, commit: str, dir: Path, verbose: int = 0):
|
|||||||
["git", "clone", "--recurse-submodules", "--filter=blob:none", url, dir],
|
["git", "clone", "--recurse-submodules", "--filter=blob:none", url, dir],
|
||||||
stdout=stdout,
|
stdout=stdout,
|
||||||
stderr=stderr,
|
stderr=stderr,
|
||||||
|
env={"GIT_TERMINAL_PROMPT": "0"},
|
||||||
)
|
)
|
||||||
subprocess.check_call(
|
subprocess.check_call(
|
||||||
["git", "fetch", "-q", url, commit],
|
["git", "fetch", "-q", url, commit],
|
||||||
cwd=dir,
|
cwd=dir,
|
||||||
stdout=stdout,
|
stdout=stdout,
|
||||||
stderr=stderr,
|
stderr=stderr,
|
||||||
|
env={"GIT_TERMINAL_PROMPT": "0"},
|
||||||
)
|
)
|
||||||
subprocess.check_call(
|
subprocess.check_call(
|
||||||
["git", "checkout", "FETCH_HEAD"],
|
["git", "checkout", "FETCH_HEAD"],
|
||||||
cwd=dir,
|
cwd=dir,
|
||||||
stdout=stdout,
|
stdout=stdout,
|
||||||
stderr=stderr,
|
stderr=stderr,
|
||||||
|
env={"GIT_TERMINAL_PROMPT": "0"},
|
||||||
)
|
)
|
||||||
subprocess.check_call(
|
subprocess.check_call(
|
||||||
["git", "submodule", "update", "--init", "--recursive"],
|
["git", "submodule", "update", "--init", "--recursive"],
|
||||||
cwd=dir,
|
cwd=dir,
|
||||||
stdout=stdout,
|
stdout=stdout,
|
||||||
stderr=stderr,
|
stderr=stderr,
|
||||||
|
env={"GIT_TERMINAL_PROMPT": "0"},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -456,11 +460,14 @@ def build_bento(
|
|||||||
system_packages = system_packages or []
|
system_packages = system_packages or []
|
||||||
|
|
||||||
shutil.copy2(Path(__file__).with_name("service.py"), source_dir / "service.py")
|
shutil.copy2(Path(__file__).with_name("service.py"), source_dir / "service.py")
|
||||||
# Copy comfy-pack package
|
snapshot_text = (source_dir / "snapshot.json").read_text()
|
||||||
shutil.copytree(
|
setup_script = source_dir / "setup_workspace.py"
|
||||||
COMFY_PACK_DIR, source_dir / COMFY_PACK_DIR.name, dirs_exist_ok=True
|
with Path(__file__).with_name("setup_workspace.py").open() as f:
|
||||||
)
|
setup_script.write_text(f.read().format(snapshot=snapshot_text))
|
||||||
snapshot = json.loads((source_dir / "snapshot.json").read_text())
|
# Make setup script executable in a cross-platform way
|
||||||
|
if os.name in ("posix", "mac"):
|
||||||
|
setup_script.chmod(setup_script.stat().st_mode | 0o755)
|
||||||
|
snapshot = json.loads(snapshot_text)
|
||||||
return bentoml.build(
|
return bentoml.build(
|
||||||
"service:ComfyService",
|
"service:ComfyService",
|
||||||
name=bento_name,
|
name=bento_name,
|
||||||
@@ -475,7 +482,7 @@ def build_bento(
|
|||||||
docker={
|
docker={
|
||||||
"python_version": f"{sys.version_info.major}.{sys.version_info.minor}",
|
"python_version": f"{sys.version_info.major}.{sys.version_info.minor}",
|
||||||
"system_packages": system_packages,
|
"system_packages": system_packages,
|
||||||
"setup_script": Path(__file__).with_name("setup_workspace.py").as_posix(),
|
"setup_script": source_dir.joinpath("setup_workspace.py").as_posix(),
|
||||||
},
|
},
|
||||||
python={"requirements_txt": "requirements.txt", "lock_packages": True},
|
python={"requirements_txt": "requirements.txt", "lock_packages": True},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -206,6 +206,7 @@ def run_workflow(
|
|||||||
output_dir: Union[str, Path, None] = None,
|
output_dir: Union[str, Path, None] = None,
|
||||||
timeout: int = 300,
|
timeout: int = 300,
|
||||||
verbose: int = 0,
|
verbose: int = 0,
|
||||||
|
workspace: str = ".",
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""
|
"""
|
||||||
@@ -258,6 +259,8 @@ def run_workflow(
|
|||||||
command = [
|
command = [
|
||||||
"comfy",
|
"comfy",
|
||||||
"--skip-prompt",
|
"--skip-prompt",
|
||||||
|
"--workspace",
|
||||||
|
workspace,
|
||||||
"run",
|
"run",
|
||||||
"--workflow",
|
"--workflow",
|
||||||
workflow_file_path.as_posix(),
|
workflow_file_path.as_posix(),
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ def _get_workspace() -> Path:
|
|||||||
from bentoml._internal.configuration.containers import BentoMLContainer
|
from bentoml._internal.configuration.containers import BentoMLContainer
|
||||||
|
|
||||||
snapshot = BASE_DIR / "snapshot.json"
|
snapshot = BASE_DIR / "snapshot.json"
|
||||||
checksum = hashlib.md5(snapshot.read_bytes()).hexdigest()
|
checksum = hashlib.md5(snapshot.read_bytes().strip()).hexdigest()
|
||||||
wp = (
|
wp = (
|
||||||
Path(BentoMLContainer.bentoml_home.get()) / "run" / "comfy_workspace" / checksum
|
Path(BentoMLContainer.bentoml_home.get()) / "run" / "comfy_workspace" / checksum
|
||||||
)
|
)
|
||||||
@@ -73,7 +73,7 @@ else:
|
|||||||
snapshot = {}
|
snapshot = {}
|
||||||
|
|
||||||
|
|
||||||
@bentoml.mount_asgi_app(app, path="/comfy")
|
@bentoml.asgi_app(app, path="/comfy")
|
||||||
@bentoml.service(traffic={"timeout": REQUEST_TIMEOUT * 2}, resources={"gpu": 1})
|
@bentoml.service(traffic={"timeout": REQUEST_TIMEOUT * 2}, resources={"gpu": 1})
|
||||||
class ComfyService:
|
class ComfyService:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -122,19 +122,13 @@ class ComfyService:
|
|||||||
output_dir=ctx.temp_dir,
|
output_dir=ctx.temp_dir,
|
||||||
timeout=REQUEST_TIMEOUT,
|
timeout=REQUEST_TIMEOUT,
|
||||||
verbose=verbose,
|
verbose=verbose,
|
||||||
|
workspace=self.server.workspace,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
if isinstance(ret, list):
|
if isinstance(ret, list):
|
||||||
ret = ret[-1]
|
ret = ret[-1]
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@bentoml.on_shutdown
|
|
||||||
def on_shutdown(self):
|
|
||||||
logger.info("Shutting down")
|
|
||||||
if not EXISTING_COMFYUI_SERVER:
|
|
||||||
self.watch_thread.join()
|
|
||||||
logger.info("Watch thread finished")
|
|
||||||
|
|
||||||
@bentoml.on_deployment
|
@bentoml.on_deployment
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def prepare_models():
|
def prepare_models():
|
||||||
|
|||||||
@@ -13,25 +13,23 @@ if virtualenv and "--reload" not in sys.argv:
|
|||||||
venv_python = os.path.join(virtualenv, "bin/python3")
|
venv_python = os.path.join(virtualenv, "bin/python3")
|
||||||
os.execl(venv_python, venv_python, *sys.argv, "--reload")
|
os.execl(venv_python, venv_python, *sys.argv, "--reload")
|
||||||
|
|
||||||
# The script path is ./env/docker/setup_script
|
SNAPSHOT = """\
|
||||||
SRC_DIR = Path(__file__).parent.parent.parent / "src"
|
{snapshot}
|
||||||
INPUT_DIR = SRC_DIR / "input"
|
"""
|
||||||
sys.path.append(str(SRC_DIR))
|
|
||||||
|
|
||||||
|
|
||||||
def _get_workspace() -> tuple[Path, dict]:
|
def _get_workspace() -> tuple[Path, dict]:
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from bentoml._internal.configuration.containers import BentoMLContainer
|
bentoml_home = os.getenv(
|
||||||
|
"BENTOML_HOME", os.path.join(os.path.expanduser("~"), "bentoml")
|
||||||
snapshot = SRC_DIR / "snapshot.json"
|
|
||||||
checksum = hashlib.md5(snapshot.read_bytes()).hexdigest()
|
|
||||||
wp = (
|
|
||||||
Path(BentoMLContainer.bentoml_home.get()) / "run" / "comfy_workspace" / checksum
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
checksum = hashlib.md5(SNAPSHOT.strip().encode("utf8")).hexdigest()
|
||||||
|
wp = Path(bentoml_home) / "run" / "comfy_workspace" / checksum
|
||||||
wp.parent.mkdir(parents=True, exist_ok=True)
|
wp.parent.mkdir(parents=True, exist_ok=True)
|
||||||
return wp, json.loads(snapshot.read_text())
|
return wp, json.loads(SNAPSHOT)
|
||||||
|
|
||||||
|
|
||||||
def prepare_comfy_workspace():
|
def prepare_comfy_workspace():
|
||||||
@@ -39,7 +37,7 @@ def prepare_comfy_workspace():
|
|||||||
|
|
||||||
from comfy_pack.package import install_comfyui, install_custom_modules
|
from comfy_pack.package import install_comfyui, install_custom_modules
|
||||||
|
|
||||||
verbose = int("BENTOML_DEBUG" in os.environ)
|
verbose = 2
|
||||||
comfy_workspace, snapshot = _get_workspace()
|
comfy_workspace, snapshot = _get_workspace()
|
||||||
|
|
||||||
if not comfy_workspace.joinpath(".DONE").exists():
|
if not comfy_workspace.joinpath(".DONE").exists():
|
||||||
@@ -48,12 +46,6 @@ def prepare_comfy_workspace():
|
|||||||
shutil.rmtree(comfy_workspace, ignore_errors=True)
|
shutil.rmtree(comfy_workspace, ignore_errors=True)
|
||||||
install_comfyui(snapshot, comfy_workspace, verbose=verbose)
|
install_comfyui(snapshot, comfy_workspace, verbose=verbose)
|
||||||
|
|
||||||
for f in INPUT_DIR.glob("*"):
|
|
||||||
if f.is_file():
|
|
||||||
shutil.copy(f, comfy_workspace / "input" / f.name)
|
|
||||||
elif f.is_dir():
|
|
||||||
shutil.copytree(f, comfy_workspace / "input" / f.name)
|
|
||||||
|
|
||||||
install_custom_modules(snapshot, comfy_workspace, verbose=verbose)
|
install_custom_modules(snapshot, comfy_workspace, verbose=verbose)
|
||||||
comfy_workspace.joinpath(".DONE").touch()
|
comfy_workspace.joinpath(".DONE").touch()
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
|
|||||||
@@ -456,7 +456,7 @@ name = "click"
|
|||||||
version = "8.1.7"
|
version = "8.1.7"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "colorama", marker = "platform_system == 'Windows'" },
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 }
|
sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -523,7 +523,6 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "comfy-pack"
|
name = "comfy-pack"
|
||||||
version = "0.2.2.dev7+g5238115.d20241231"
|
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "bentoml" },
|
{ name = "bentoml" },
|
||||||
|
|||||||
Reference in New Issue
Block a user