Files

127 lines
4.7 KiB
Python

"""
ComfyUI custom node install script — run automatically by ComfyUI Manager
on node install/update, and can also be run manually:
python install.py
Installs optional heavy dependencies that can't go in requirements.txt
without breaking other packages:
- VibeVoice TTS (from FushionHub/VibeVoice fork, --no-deps to prevent downgrades)
"""
import sys
import subprocess
import importlib.util
def _pkg_installed(name: str) -> bool:
return importlib.util.find_spec(name) is not None
def _pip(*args, ignore_errors=False) -> bool:
cmd = [sys.executable, "-m", "pip", *args]
print(f"[install] Running: {' '.join(cmd)}")
result = subprocess.run(cmd, capture_output=False)
ok = result.returncode == 0
if not ok and not ignore_errors:
print(f"[install] WARNING: command failed (exit {result.returncode})")
return ok
def install_vibevoice():
print("\n[install] === VibeVoice TTS ===")
if _pkg_installed("vibevoice"):
print("[install] vibevoice already installed — skipping.")
return
# ── Pre-install safe dependencies first (without --no-deps) ──────────
# These are vibevoice's deps that are safe to install normally.
# We do this before --no-deps so they land at a compatible version.
safe_deps = [
"av", # PyAV — audio/video I/O (may fail on some platforms, that's ok)
"aiortc", # WebRTC support
"pyee", # Event emitter
"dnspython", # DNS toolkit
"ifaddr", # Network interface addresses
"pylibsrtp", # SRTP
"pyopenssl", # OpenSSL bindings
]
for dep in safe_deps:
pkg = dep.split("[")[0].replace("-", "_") # normalise for find_spec
if _pkg_installed(pkg):
print(f"[install] {dep}: already installed")
continue
print(f"[install] Installing {dep}...")
_pip("install", dep, ignore_errors=True)
# ── Install vibevoice itself with --no-deps ────────────────────────────
# We use --no-deps to avoid downgrading transformers or other packages
# that are already installed at a version other projects depend on.
# The FushionHub fork is a maintained mirror of the original Microsoft
# repo (which was taken down). It has an identical API.
print("[install] Installing vibevoice (--no-deps to prevent downgrades)...")
ok = _pip(
"install",
"git+https://github.com/FushionHub/VibeVoice.git",
"--no-deps",
ignore_errors=True,
)
if ok:
print("[install] vibevoice installed successfully.")
else:
print("[install] WARNING: vibevoice install failed.")
print("[install] VibeVoice TTS will not be available.")
print("[install] To install manually:")
print("[install] pip install git+https://github.com/FushionHub/VibeVoice.git --no-deps")
print("[install] Also install its deps manually if needed:")
print("[install] pip install av aiortc pyee dnspython ifaddr pylibsrtp pyopenssl")
def install_vv_deps():
"""Install isolated transformers 4.51.3 + friends into vv_deps/ for subprocess."""
import os
deps_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "vv_deps")
marker = os.path.join(deps_dir, ".installed")
if os.path.exists(marker):
print("[install] vv_deps already installed — skipping.")
return
print("\n[install] === VibeVoice Subprocess Dependencies (vv_deps/) ===")
os.makedirs(deps_dir, exist_ok=True)
# VibeVoice requires transformers 4.51.3, but ComfyUI ships transformers 5.x.
# We install the old versions into an isolated directory so the subprocess can
# use them without conflicting with the main process.
packages = [
"transformers==4.51.3",
"accelerate==1.6.0",
"tokenizers==0.21.0", # transformers 4.51.3 requires tokenizers<0.22
"huggingface-hub==0.30.2", # transformers 4.51.3 requires huggingface-hub<1.0
]
ok = True
for pkg in packages:
print(f"[install] Installing {pkg} into vv_deps/...")
if not _pip("install", "--target", deps_dir, pkg, "--no-deps", ignore_errors=True):
ok = False
if ok:
with open(marker, "w") as f:
f.write(" ".join(packages))
print("[install] vv_deps installed successfully.")
else:
print("[install] WARNING: Some vv_deps packages failed to install.")
print("[install] VibeVoice TTS subprocess may not work correctly.")
def main():
print("[install] comfyui-llm-tools — running install script")
install_vibevoice()
install_vv_deps()
print("[install] Done.")
if __name__ == "__main__":
main()