LLMVideoPipeline/pipeline/dependency_manager.py

160 lines
6.3 KiB
Python
Raw Permalink Normal View History

2026-08-16 09:39:36 -06:00
"""
Automatic Dependency Checker & Self-Healing Installer for YouTube Factory.
Ensures that all Python packages, system CLI utilities (ffmpeg, ssh, etc.),
and remote PC connectivity are fully configured when moving orchestration to a new PC.
"""
import sys
import os
import shutil
import subprocess
import logging
import importlib
logger = logging.getLogger("YTFactory.Deps")
PYTHON_DEPENDENCIES = {
"requests": "requests>=2.28.0",
"yaml": "pyyaml>=6.0",
"numpy": "numpy>=1.22.0",
"edge_tts": "edge-tts>=7.0.0",
"aiohttp": "aiohttp>=3.8.0",
"PIL": "Pillow>=9.0.0",
"googleapiclient": "google-api-python-client>=2.0.0",
"google_auth_oauthlib": "google-auth-oauthlib>=1.0.0",
"google.auth": "google-auth-httplib2>=0.1.0",
}
SYSTEM_BINARIES = [
("ffmpeg", "Required for video rendering, Ken Burns motion, and audio ducking"),
("ffprobe", "Required for audio and video stream analysis"),
("ssh", "Required for remote PC orchestration (AMDLLM, NvidiaLLM, IntelLLM)"),
("scp", "Required for cross-PC artifact transfers"),
("curl", "Required for REST API polling"),
]
def check_python_packages(auto_install: bool = True) -> bool:
"""Check for missing Python packages and automatically install them via pip."""
missing = []
for mod_name, pip_pkg in PYTHON_DEPENDENCIES.items():
try:
importlib.import_module(mod_name)
except ImportError:
missing.append(pip_pkg)
if not missing:
return True
logger.warning(f"[DEPS] Missing {len(missing)} Python packages: {', '.join(missing)}")
if not auto_install:
return False
logger.info("[DEPS] Automatically installing missing Python packages via pip...")
2026-08-16 11:26:57 -06:00
install_commands = [
[sys.executable, "-m", "pip", "install", "--upgrade"] + missing,
[sys.executable, "-m", "pip", "install", "--break-system-packages", "--upgrade"] + missing,
[sys.executable, "-m", "pip", "install", "--user", "--break-system-packages"] + missing,
]
for cmd in install_commands:
try:
r = subprocess.run(cmd, check=True, capture_output=True, text=True)
logger.info("[DEPS] All Python packages successfully installed!")
return True
except subprocess.CalledProcessError:
continue
logger.error(f"[DEPS] Automatic pip install failed.")
logger.error(f"Please run manually: {sys.executable} -m pip install --break-system-packages -r requirements.txt")
return False
2026-08-16 09:39:36 -06:00
def check_system_binaries(auto_install: bool = True) -> bool:
"""Check for required system binaries (ffmpeg, ssh, scp, etc.) and attempt self-install."""
missing_bins = []
for binary, desc in SYSTEM_BINARIES:
if not shutil.which(binary):
missing_bins.append((binary, desc))
if not missing_bins:
return True
logger.warning(f"[DEPS] Missing {len(missing_bins)} required system tools:")
for binary, desc in missing_bins:
logger.warning(f" - '{binary}': {desc}")
if not auto_install:
return False
# Attempt automatic package manager install on Linux
if sys.platform.startswith("linux"):
if shutil.which("apt-get"):
logger.info("[DEPS] Attempting to install system tools via apt-get...")
pkg_map = {
"ffmpeg": "ffmpeg",
"ffprobe": "ffmpeg",
"ssh": "openssh-client",
"scp": "openssh-client",
"curl": "curl",
}
pkgs = list({pkg_map.get(b, b) for b, _ in missing_bins})
try:
# Test if sudo is passwordless or we are root
cmd = ["sudo", "apt-get", "update", "-qq"]
subprocess.run(cmd, check=True, capture_output=True)
install_cmd = ["sudo", "apt-get", "install", "-y", "-qq"] + pkgs
subprocess.run(install_cmd, check=True)
logger.info("[DEPS] System tools successfully installed via apt-get!")
return True
except Exception as e:
logger.warning(f"[DEPS] Automatic apt install failed: {e}")
logger.error("=" * 70)
logger.error("🚨 REQUIRED SYSTEM BINARIES MISSING")
logger.error("Please install them using your system package manager:")
logger.error(" Ubuntu / Debian: sudo apt-get update && sudo apt-get install -y ffmpeg openssh-client curl")
logger.error(" Arch Linux: sudo pacman -S ffmpeg openssh curl")
logger.error(" Fedora / RHEL: sudo dnf install ffmpeg openssh-clients curl")
logger.error(" macOS: brew install ffmpeg curl")
logger.error("=" * 70)
return False
def check_remote_hosts(hosts: list = None) -> bool:
"""Verify SSH connectivity to the remote AI servers."""
if not hosts:
hosts = [("AMDLLM", "10.4.0.181"), ("NvidiaLLM", "10.4.0.180"), ("IntelLLM", "10.4.0.182")]
all_ok = True
for name, host in hosts:
r = subprocess.run(
["ssh", "-o", "BatchMode=yes", "-o", "ConnectTimeout=3", "-o", "StrictHostKeyChecking=no", f"mark@{host}", "echo ok"],
capture_output=True, text=True
)
if r.returncode != 0:
logger.warning(f"[DEPS] SSH key auth to {name} ({host}) failed or timed out.")
logger.warning(f" Run: ssh-copy-id mark@{host}")
all_ok = False
else:
logger.debug(f"[DEPS] SSH connection to {name} ({host}) verified.")
return all_ok
def ensure_dependencies(auto_install: bool = True, check_remote: bool = False) -> bool:
"""
Main entry point for verifying runtime dependencies.
Called automatically on factory startup to ensure smooth portability across PCs.
"""
py_ok = check_python_packages(auto_install=auto_install)
sys_ok = check_system_binaries(auto_install=auto_install)
if check_remote:
check_remote_hosts()
return py_ok and sys_ok
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO, format="%(levelname)s | %(message)s")
print("\n🔍 Checking YouTube Factory Dependencies across PC...\n")
ok = ensure_dependencies(auto_install=True, check_remote=True)
if ok:
print("\n✅ All local dependencies are satisfied and verified!\n")
else:
print("\n⚠️ Some dependencies require attention (see logs above).\n")