"""Start Comfy with HF-provided custom nodes while leaving the image unchanged.""" import atexit,json,os,subprocess,sys,time,urllib.request,tarfile,hashlib from pathlib import Path PROCESS=None def stop(): global PROCESS if PROCESS and PROCESS.poll() is None: PROCESS.terminate() try:PROCESS.wait(timeout=3) except subprocess.TimeoutExpired:PROCESS.kill() PROCESS=None def extra_paths(root): paths={'base_path':str(root),'is_default':True} if (root/'custom_nodes').is_dir():paths['custom_nodes']='custom_nodes' if (root/'models').is_dir(): for folder in (root/'models').iterdir(): if folder.is_dir() and folder.name.replace('_','').isalnum():paths[folder.name]='models/'+folder.name return paths def initialize(): global PROCESS value=os.environ.get('HF_APP_ROOT') if not value:return startup_deadline=time.monotonic()+220 root=Path(value);config=json.loads((root/'app-runtime.json').read_text(encoding='utf-8-sig')) if config.get('engine')!='comfyui':return if config.get('backend')!='python':raise ValueError('HF custom-node startup requires backend python / engine comfyui') work=Path('/workspace/hf-app');user=work/'comfy-user';user.mkdir(parents=True,exist_ok=True) extra=work/'hf-extra-paths.yaml' wheels=sorted((root/'runtime_wheels').glob('*.whl')) packages=work/'python-deps' if wheels: stamp=json.dumps([(wheel.name,wheel.stat().st_size) for wheel in wheels]) marker=packages/'.installed-wheels.json' if not marker.is_file() or marker.read_text()!=stamp: subprocess.run(['/opt/venv/bin/python','-m','pip','install','--disable-pip-version-check','--no-deps','--no-index','--no-compile','--target',str(packages),*[str(wheel) for wheel in wheels]],check=True,timeout=120) marker.write_text(stamp) sys.path.insert(0,str(packages)) os.environ['PYTHONPATH']=str(packages)+os.pathsep+os.environ.get('PYTHONPATH','') # JSON is a valid YAML document and avoids path quoting ambiguities. paths=extra_paths(root) mappings={'hf_app':paths,'installed_nodes':{'base_path':'/comfyui','custom_nodes':'custom_nodes'}} if (root/'auxiliary'/'pose').is_dir(): os.environ['AUX_ANNOTATOR_CKPTS_PATH']=str(root/'auxiliary'/'pose') os.environ['AUX_USE_SYMLINKS']='False' os.environ['AUX_TEMP_DIR']=str(work/'aux-temp') extra.write_text(json.dumps(mappings)) archive=root/'runtime_core/comfyui.tar.gz' if hashlib.sha256(archive.read_bytes()).hexdigest()!='f27e166e9b9fbf4743669a1a492980a5f6f57c6697d6e460d3121c4131771047':raise RuntimeError('ComfyUI archive hash mismatch') core_dir=work/'comfy-core' marker=core_dir/'.ready' if not marker.is_file(): core_dir.mkdir(exist_ok=True) with tarfile.open(archive) as bundle:bundle.extractall(core_dir,filter='data') marker.write_text('72865f4f27eaf5396f8f36370e0a2be3a9a090ee') entrypoint=core_dir/'ComfyUI-72865f4f27eaf5396f8f36370e0a2be3a9a090ee'/'main.py' if not entrypoint.is_file():raise RuntimeError('Pinned ComfyUI entrypoint is missing') arguments=['/opt/venv/bin/python','-u',str(entrypoint), '--listen','127.0.0.1','--port','8188','--disable-auto-launch','--disable-metadata', '--disable-api-nodes','--log-stdout','--enable-dynamic-vram','--reserve-vram','1', '--async-offload','2','--preview-method','none', '--enable-triton-backend','--fast','fp16_accumulation', '--input-directory','/comfyui/input','--output-directory','/comfyui/output', '--temp-directory','/comfyui/temp','--user-directory',str(user), '--database-url','sqlite:////workspace/hf-app/comfy-user/comfyui.db','--extra-model-paths-config',str(extra)] PROCESS=subprocess.Popen(arguments,cwd=str(entrypoint.parent)) # Keep the enclosing v53 child ready/cleanup checks pointed at the real Comfy process. main=sys.modules.get('__main__') if main and hasattr(main,'COMFY'):main.COMFY=PROCESS deadline=min(startup_deadline,time.monotonic()+180) while time.monotonic()