Compare commits

...

9 Commits

Author SHA1 Message Date
Juggernaut
d916184985
Merge 2757728935 into e11e9034ce 2026-07-08 18:53:14 +07:00
Dr.Lt.Data
e11e9034ce
Merge pull request #3058 from kgilper/update-krea-reference-sliders
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
Update ComfyUI Krea Reference description: Concept Slider nodes
2026-07-07 14:23:10 +09:00
Kevin Gilper
fb75c048bd Update ComfyUI Krea Reference description: Concept Slider nodes added 2026-07-07 01:01:16 -04:00
Dr.Lt.Data
f7fd701e19 update DB
Some checks are pending
Python Linting / Run Ruff (push) Waiting to run
2026-07-07 04:49:31 +09:00
Dr.Lt.Data
cf883eb762
Merge pull request #3057 from Azornes/azornes-resolutionmaster-preemption
Add ResolutionMaster preemption for Comfyui-Resolution-Master
2026-07-07 03:49:16 +09:00
Dariusz L
45891097bb Add ResolutionMaster preemption for Comfyui-Resolution-Master 2026-07-06 19:14:59 +02:00
Juggernaut
2757728935
Merge branch 'Comfy-Org:main' into main 2026-02-09 16:53:01 +05:30
Juggernaut
bb46126fbd
Merge branch 'Comfy-Org:main' into main 2026-02-06 12:31:48 +05:30
ashish
af1c698117 dependency analysis 2026-01-18 16:54:22 +05:30
8 changed files with 4632 additions and 4009 deletions

View File

@ -33152,6 +33152,9 @@
"https://github.com/Azornes/Comfyui-Resolution-Master"
],
"install_type": "git-clone",
"preemptions": [
"ResolutionMaster"
],
"description": " Precise resolution and aspect ratio control for ComfyUI"
},
{
@ -54041,7 +54044,7 @@
"https://github.com/kgilper/krea-reference"
],
"install_type": "git-clone",
"description": "Give each reference image a job before it reaches Krea 2. Guide cards assign per-image roles (keep the same subject, suggest the visual style, copy lighting or pose, big shapes only, avoid copying text/logos) and the stack encoder builds Krea conditioning with per-card strength, per-layer gains, and guarded prompt handling."
"description": "Give each reference image a job, and every attribute a dial. Guide cards assign per-image roles (keep the same subject, suggest the visual style, copy lighting or pose, big shapes only, avoid copying text/logos) with per-card strength, timing, and user-defined recipes - and Concept Slider cards turn any attribute you can name (brightness, age, fog density) into a training-free -6..+6 dial derived from Krea 2 text encoding."
},
{
"author": "DutchyDutch",

View File

@ -752,7 +752,6 @@
"GrsaiFluxKontext_MultiImageToImage",
"GrsaiFluxKontext_TextToImage",
"Grsai_GPTImage",
"Grsai_GPTImageVIP",
"Grsai_NanoBanana",
"Grsai_NanoBanana2",
"Grsai_NanoBananaPro"
@ -3988,6 +3987,9 @@
{
"author": "Azornes",
"description": "Logging Configuration",
"preemptions": [
"ResolutionMaster"
],
"title": "AzLogs",
"title_aux": "Comfyui-Resolution-Master"
}
@ -17719,6 +17721,18 @@
"title_aux": "ComfyUI-Montagen"
}
],
"https://github.com/Moon-NE/MoonNe_Nodes": [
[
"BatchConditionalText",
"BatchConditionalTextWeight",
"Moon_NE_Text_Concatenate",
"TextHorizontalToVertical",
"batch_randoml_text"
],
{
"title_aux": "MoonNe_Nodes"
}
],
"https://github.com/MoonHugo/ComfyUI-BAGEL-Hugo": [
[
"BagelByHugo"
@ -20976,223 +20990,6 @@
"title_aux": "ComfyUI-PromptUtils"
}
],
"https://github.com/Runware/ComfyUI-Runware": [
[
"Runware 3D Inference",
"Runware 3D Inference Inputs",
"Runware 3D Inference Settings",
"Runware 3D Inference Settings Draco Compression",
"Runware 3D Inference Settings Mesh Cluster",
"Runware 3D Inference Settings Shape Slat",
"Runware 3D Inference Settings Sparse Structure",
"Runware 3D Inference Settings Tex Slat",
"Runware 3D Model Search",
"Runware API Manager",
"Runware Accelerator Options",
"Runware Alibaba Provider Settings",
"Runware Audio Inference",
"Runware Audio Inference Inputs",
"Runware Audio Inference Inputs Reference Audio",
"Runware Audio Inference Settings",
"Runware Audio Inference Settings Voice Modify",
"Runware Audio Inference Speech",
"Runware Audio Inference Speech Voices",
"Runware Audio Model Search",
"Runware Audio Sections",
"Runware Background Removal",
"Runware BlackForest Labs Provider Settings",
"Runware Bria Provider Mask",
"Runware Bria Provider Settings",
"Runware Bytedance Provider Settings",
"Runware ControlNet",
"Runware ControlNet Combine",
"Runware ControlNet PreProcessor",
"Runware ElevenLabs Provider Settings",
"Runware ElevenLabs Provider Settings Sections",
"Runware Embedding Search",
"Runware Embeddings Combine",
"Runware Frame Images",
"Runware Google Provider Settings",
"Runware IPAdapter",
"Runware IPAdapters Combine",
"Runware Image Advanced Feature Input",
"Runware Image Caption",
"Runware Image Inference",
"Runware Image Inference Inputs",
"Runware Image Inference Inputs Fonts",
"Runware Image Inference Settings Color Palette",
"Runware Image Inference Settings Moodboards",
"Runware Image Inference Settings Prompt Enhance",
"Runware Image Inference Settings Scoring Rubric",
"Runware Image Inference Settings Scoring Rubric Combine",
"Runware Image Inference Settings Structured Prompt",
"Runware Image Inference Ultralytics",
"Runware Image Masking",
"Runware Image Upscaler",
"Runware Image Upscaler Settings",
"Runware Imagen Inference",
"Runware Input Audios",
"Runware Kling MultiPrompt Segment",
"Runware Kling Provider Settings MultiPrompt",
"Runware KlingAI Provider Settings",
"Runware Kontext Inference",
"Runware Lightricks Provider Settings",
"Runware Load Mesh",
"Runware Lora Combine",
"Runware Lora Search",
"Runware Luma Provider Settings",
"Runware Media Upload",
"Runware Midjourney Provider Settings",
"Runware MiniMax Provider Settings",
"Runware Mirelo Provider Settings",
"Runware Model Search",
"Runware Multi Inference",
"Runware OpenAI Provider Settings",
"Runware Outpaint",
"Runware PhotoMaker V2",
"Runware Pixverse Provider Settings",
"Runware Provider Settings Recraft Color",
"Runware Recraft Provider Settings",
"Runware Reference Audios",
"Runware Reference Images",
"Runware Reference Videos",
"Runware Reference Voices",
"Runware Refiner",
"Runware Regional Prompting Advanced Feature",
"Runware Regional Prompting Advanced Feature Regions",
"Runware Runway Provider Settings",
"Runware Safety Inputs",
"Runware Save 3D",
"Runware Save Image",
"Runware Save Text",
"Runware Settings",
"Runware Sourceful Provider Settings",
"Runware Sourceful Provider Settings Fonts",
"Runware Speech Inputs Combine",
"Runware Sync Provider Settings",
"Runware Sync Segment",
"Runware Text Inference",
"Runware Text Inference Inputs",
"Runware Text Inference Inputs Images",
"Runware Text Inference Inputs Videos",
"Runware Text Inference Message",
"Runware Text Inference Messages",
"Runware Text Inference Settings",
"Runware Text Inference Settings Cache",
"Runware Text Inference Tool Choice",
"Runware Text Model Search",
"Runware VAE Search",
"Runware Vectorize",
"Runware Video Advanced Feature Inputs",
"Runware Video Audio Input",
"Runware Video Background Removal",
"Runware Video Inference",
"Runware Video Inference Elements",
"Runware Video Inference Elements Combine",
"Runware Video Inference Inputs",
"Runware Video Inference Inputs Reference Audios",
"Runware Video Inference Inputs Reference Images",
"Runware Video Inference Inputs Reference Images Multiple Images Connector",
"Runware Video Inference Inputs Reference Videos",
"Runware Video Inference Inputs Reference Voices",
"Runware Video Inference Lora",
"Runware Video Inference Outputs",
"Runware Video Inference Settings",
"Runware Video Inference Settings Active Speaker Bounding Boxes",
"Runware Video Inference Settings Active Speaker Detection",
"Runware Video Inference Settings Edit",
"Runware Video Inference Settings Segments",
"Runware Video Inference Settings Source Position",
"Runware Video Inference Settings TTS",
"Runware Video Inference Speech Input",
"Runware Video Inputs Frame Images",
"Runware Video Inputs References",
"Runware Video Model Search",
"Runware Video Speech Input",
"Runware Video Transcription",
"Runware Video Upscaler",
"Runware Vidu Provider Settings",
"Runware Wan Animate Advanced Feature Settings",
"Runware Watermark Advanced Feature",
"Runware xAI Provider Settings",
"Runware3DInference",
"Runware3DInferenceInputs",
"Runware3DInferenceSettings",
"Runware3DInferenceSettingsDracoCompression",
"Runware3DInferenceSettingsMeshCluster",
"Runware3DInferenceSettingsShapeSlat",
"Runware3DInferenceSettingsSparseStructure",
"Runware3DInferenceSettingsTexSlat",
"RunwareAlibabaProviderSettings",
"RunwareAudioInferenceInputs",
"RunwareAudioInferenceReferenceVoices",
"RunwareAudioInferenceSpeech",
"RunwareAudioInferenceSpeechVoices",
"RunwareAudioInput",
"RunwareAudioSettings",
"RunwareAudioSettingsVoiceModify",
"RunwareBlackForestProviderSettings",
"RunwareBriaProviderMask",
"RunwareBriaProviderSettings",
"RunwareBytedanceProviderSettings",
"RunwareFrameImages",
"RunwareGoogleProviderSettings",
"RunwareImageInferenceAdvancedFeatures",
"RunwareImageInferenceSettingsPromptEnhance",
"RunwareImageInferenceSettingsStructuredPrompt",
"RunwareKlingMultiPromptSegment",
"RunwareKlingProviderSettings",
"RunwareKlingProviderSettingsMultiPrompt",
"RunwareLightricksProviderSettings",
"RunwareLoadMesh",
"RunwareLumaProviderSettings",
"RunwareMidjourneyProviderSettings",
"RunwareMiniMaxProviderSettings",
"RunwareMireloProviderSettings",
"RunwareOpenAIProviderSettings",
"RunwarePixverseProviderSettings",
"RunwareRecraftColor",
"RunwareRecraftProviderSettings",
"RunwareRegionalPromptingAdvancedFeature",
"RunwareRegionalPromptingAdvancedFeatureRegions",
"RunwareRunwayProviderSettings",
"RunwareSafetyInputs",
"RunwareSave3D",
"RunwareSourcefulProviderSettings",
"RunwareSourcefulProviderSettingsFonts",
"RunwareSpeechInput",
"RunwareSpeechInputCombine",
"RunwareSyncProviderSettings",
"RunwareSyncSegment",
"RunwareTextInferenceSettingsCache",
"RunwareTextInferenceToolChoice",
"RunwareUltralyticsInputs",
"RunwareUltralyticsProviderSettings",
"RunwareVectorize",
"RunwareVideoAdvancedFeatureInputs",
"RunwareVideoBgRemoval",
"RunwareVideoInferenceOutputs",
"RunwareVideoInferenceSettingsActiveSpeakerBoundingBoxes",
"RunwareVideoInferenceSettingsActiveSpeakerDetection",
"RunwareVideoInferenceSettingsControl",
"RunwareVideoInferenceSettingsSegments",
"RunwareVideoInferenceSettingsSourcePosition",
"RunwareVideoInferenceSettingsTts",
"RunwareVideoInferenceSpeechInput",
"RunwareVideoInputsFrameImages",
"RunwareVideoInputsReferenceImagesMultipleImagesConnector",
"RunwareVideoInputsReferences",
"RunwareVideoSettings",
"RunwareVideoUpscaler",
"RunwareWanAnimateAdvancedFeatureSettings",
"RunwareWatermarkAdvancedFeature",
"RunwareXAIProviderSettings",
"txt2vid"
],
{
"title_aux": "Runware.ai ComfyUI Inference API Integration"
}
],
"https://github.com/RyanHolanda/ComfyUI-AudioBridge": [
[
"AudioToTensor",
@ -25444,6 +25241,26 @@
"title_aux": "ComfyUI-RotoMask"
}
],
"https://github.com/TechnoWarrior2/comfyui-image-picker": [
[
"AlexImagePicker"
],
{
"author": "alex",
"description": "Pauses workflow and opens a new browser window to pick which images to pass through.",
"nickname": "Image Picker",
"title": "Alex Image Picker",
"title_aux": "ComfyUI Image Picker"
}
],
"https://github.com/TechnoWarrior2/comfyui-live-preview": [
[
"AlexLivePreview"
],
{
"title_aux": "ComfyUI Live Preview"
}
],
"https://github.com/TemryL/ComfyS3": [
[
"DownloadFileS3",
@ -48485,7 +48302,8 @@
],
"https://github.com/jtydhr88/ComfyUI-qwenmultiangle": [
[
"QwenMultiangleCameraNode"
"QwenMultiangleCameraNode",
"QwenMultiangleCameraTranslateNode"
],
{
"title_aux": "ComfyUI-qwenmultiangle"
@ -64003,6 +63821,22 @@
"title_aux": "comfyui-clippy-reloaded"
}
],
"https://github.com/shootthesound/comfyui-image-of-the-day": [
[
"ImageOfDayLoader"
],
{
"title_aux": "Image of the Day"
}
],
"https://github.com/shootthesound/comfyui-lora-FindingLora": [
[
"LoraLoaderFindingLora"
],
{
"title_aux": "Finding LoRA"
}
],
"https://github.com/shootthesound/comfyui-model-diff-to-lora": [
[
"ModelDiffToLoRA"
@ -72296,6 +72130,19 @@
"title_aux": "ComfyUI-KYNode"
}
],
"https://github.com/younestft/Comfy_EverAnimate": [
[
"ComfyEverAnimate",
"ComfyEverAnimateChunksCalculator",
"ComfyEverAnimateColorCorrection",
"ComfyEverAnimateContinueChunk",
"ComfyEverAnimateInitialChunk",
"ComfyEverAnimateMasterSettings"
],
{
"title_aux": "Comfy EverAnimate"
}
],
"https://github.com/younger15/ComfyUI-IterSwitch": [
[
"Iter_CLIPSwitch",

File diff suppressed because it is too large Load Diff

View File

@ -921,7 +921,7 @@ class UnifiedManager:
except:
return version.parse("0.0.0")
def execute_install_script(self, url, repo_path, instant_execution=False, lazy_mode=False, no_deps=False):
def execute_install_script(self, url, repo_path, instant_execution=False, lazy_mode=False, no_deps=False, selected_dependencies=None):
install_script_path = os.path.join(repo_path, "install.py")
requirements_path = os.path.join(repo_path, "requirements.txt")
@ -933,8 +933,19 @@ class UnifiedManager:
if os.path.exists(requirements_path) and not no_deps:
print("Install: pip packages")
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, manager_files_path)
# Create a set of selected dependency lines for quick lookup
selected_lines = set()
if selected_dependencies:
for dep in selected_dependencies:
selected_lines.add(dep.get('line', '').strip())
lines = manager_util.robust_readlines(requirements_path)
for line in lines:
# Skip if selected_dependencies is provided and this line is not in the selected list
if selected_dependencies is not None and line.strip() not in selected_lines:
continue
package_name = remap_pip_package(line.strip())
if package_name and not package_name.startswith('#') and package_name not in self.processed_install:
self.processed_install.add(package_name)
@ -1342,7 +1353,7 @@ class UnifiedManager:
return result
def repo_install(self, url: str, repo_path: str, instant_execution=False, no_deps=False, return_postinstall=False):
def repo_install(self, url: str, repo_path: str, instant_execution=False, no_deps=False, return_postinstall=False, selected_dependencies=None):
result = ManagedResult('install-git')
result.append(url)
@ -1369,7 +1380,7 @@ class UnifiedManager:
repo.close()
def postinstall():
return self.execute_install_script(url, repo_path, instant_execution=instant_execution, no_deps=no_deps)
return self.execute_install_script(url, repo_path, instant_execution=instant_execution, no_deps=no_deps, selected_dependencies=selected_dependencies)
if return_postinstall:
return result.with_postinstall(postinstall)
@ -1468,7 +1479,7 @@ class UnifiedManager:
else:
return self.cnr_switch_version(node_id, instant_execution=instant_execution, no_deps=no_deps, return_postinstall=return_postinstall).with_ver('cnr')
async def install_by_id(self, node_id: str, version_spec=None, channel=None, mode=None, instant_execution=False, no_deps=False, return_postinstall=False):
async def install_by_id(self, node_id: str, version_spec=None, channel=None, mode=None, instant_execution=False, no_deps=False, return_postinstall=False, selected_dependencies=None):
"""
priority if version_spec == None
1. CNR latest
@ -1519,7 +1530,7 @@ class UnifiedManager:
self.unified_disable(node_id, False)
to_path = os.path.abspath(os.path.join(get_default_custom_nodes_path(), node_id))
res = self.repo_install(repo_url, to_path, instant_execution=instant_execution, no_deps=no_deps, return_postinstall=return_postinstall)
res = self.repo_install(repo_url, to_path, instant_execution=instant_execution, no_deps=no_deps, return_postinstall=return_postinstall, selected_dependencies=selected_dependencies)
if res.result:
if version_spec == 'unknown':
self.unknown_active_nodes[node_id] = repo_url, to_path
@ -1974,7 +1985,7 @@ def __win_check_git_pull(path):
process.wait()
def execute_install_script(url, repo_path, lazy_mode=False, instant_execution=False, no_deps=False):
def execute_install_script(url, repo_path, lazy_mode=False, instant_execution=False, no_deps=False, selected_dependencies=None):
# import ipdb; ipdb.set_trace()
install_script_path = os.path.join(repo_path, "install.py")
requirements_path = os.path.join(repo_path, "requirements.txt")
@ -1986,6 +1997,13 @@ def execute_install_script(url, repo_path, lazy_mode=False, instant_execution=Fa
if os.path.exists(requirements_path) and not no_deps:
print("Install: pip packages")
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, manager_files_path)
# Create a set of selected dependency lines for quick lookup
selected_lines = set()
if selected_dependencies:
for dep in selected_dependencies:
selected_lines.add(dep.get('line', '').strip())
with open(requirements_path, "r") as requirements_file:
for line in requirements_file:
#handle comments
@ -1996,6 +2014,10 @@ def execute_install_script(url, repo_path, lazy_mode=False, instant_execution=Fa
else:
line = line.split('#')[0].strip()
# Skip if selected_dependencies is provided and this line is not in the selected list
if selected_dependencies is not None and line.strip() not in selected_lines:
continue
package_name = remap_pip_package(line.strip())
if package_name and not package_name.startswith('#'):

View File

@ -517,7 +517,12 @@ async def task_worker():
global tasks_in_progress
async def do_install(item) -> str:
ui_id, node_spec_str, channel, mode, skip_post_install = item
if len(item) == 6:
ui_id, node_spec_str, channel, mode, skip_post_install, selected_dependencies = item
else:
# Backward compatibility
ui_id, node_spec_str, channel, mode, skip_post_install = item
selected_dependencies = []
try:
node_spec = core.unified_manager.resolve_node_spec(node_spec_str)
@ -526,7 +531,7 @@ async def task_worker():
return f"Cannot resolve install target: '{node_spec_str}'"
node_name, version_spec, is_specified = node_spec
res = await core.unified_manager.install_by_id(node_name, version_spec, channel, mode, return_postinstall=skip_post_install)
res = await core.unified_manager.install_by_id(node_name, version_spec, channel, mode, return_postinstall=skip_post_install, selected_dependencies=selected_dependencies)
# discard post install if skip_post_install mode
if res.action not in ['skip', 'enable', 'install-git', 'install-cnr', 'switch-cnr']:
@ -1421,7 +1426,9 @@ async def install_custom_node(request):
logging.error(SECURITY_MESSAGE_GENERAL)
return web.Response(status=404, text="A security error has occurred. Please check the terminal logs")
install_item = json_data.get('ui_id'), node_spec_str, json_data['channel'], json_data['mode'], skip_post_install
# Get selected dependencies if provided
selected_dependencies = json_data.get('selectedDependencies', [])
install_item = json_data.get('ui_id'), node_spec_str, json_data['channel'], json_data['mode'], skip_post_install, selected_dependencies
task_queue.put(("install", install_item))
return web.Response(status=200)
@ -1521,6 +1528,272 @@ async def install_custom_node_pip(request):
return web.Response(status=200)
@routes.post("/customnode/analyze_dependencies")
async def analyze_dependencies(request):
"""
Analyze dependencies for a custom node from git URL.
Fetches requirements.txt, checks installed packages, and returns dependency list with status.
"""
try:
json_data = await request.json()
url = json_data.get('url')
commit_id = json_data.get('commitId')
branch = json_data.get('branch')
if not url:
return web.json_response({'error': 'URL is required'}, status=400)
# Fetch requirements.txt from git repository
requirements_content = await fetch_requirements_from_git(url, commit_id, branch)
if requirements_content is None:
return web.json_response({
'success': True,
'requirements': None,
'dependencies': [],
'noRequirementsFile': True
})
# Parse requirements
dependencies = parse_requirements(requirements_content)
# Get installed packages
installed_packages = manager_util.get_installed_packages()
# Analyze each dependency with subdependencies
analyzed_dependencies = []
for dep_line in dependencies:
if not dep_line.strip() or dep_line.strip().startswith('#'):
continue
# Parse dependency line
parsed = manager_util.parse_requirement_line(dep_line)
if not parsed:
continue
package_name = parsed.get('package')
if not package_name:
# Fallback: extract from line if package is missing
import re
match = re.match(r'^([a-zA-Z0-9_.-]+)', dep_line.strip())
package_name = match.group(1) if match else "Unknown"
version_spec = parsed.get('version')
# Convert version_spec to string if it's a StrictVersion object
if version_spec is not None:
version_spec = str(version_spec)
normalized_name = package_name.lower().replace('-', '_')
# Check if already installed
installed_version = installed_packages.get(normalized_name)
status = 'new'
if installed_version:
status = 'installed'
# Convert version to string if it's not already (handle StrictVersion objects)
current_version_str = str(installed_version) if installed_version else None
# Get subdependencies using pip install --dry-run
# This is optional and failures should not block the main flow
subdependencies = []
# Skip subdependency analysis for already installed packages (not needed)
if status != 'installed':
try:
import subprocess
import sys
# Run pip install --dry-run to get subdependencies
# Some packages like pymeshlab can take longer due to complex dependency resolution
# Use a reasonable timeout - if it times out, we'll continue without subdependencies
result = subprocess.run(
[sys.executable, '-m', 'pip', 'install', '--dry-run', dep_line.strip()],
capture_output=True,
text=True,
timeout=45 # Increased timeout to 45 seconds
)
output = result.stdout + result.stderr
if output:
subdependencies = parse_dry_run_output(output, package_name, installed_packages)
except subprocess.TimeoutExpired:
# Timeout is not critical - continue without subdependencies
logging.debug(f"Subdependency analysis timed out for {package_name} (skipping subdependencies)")
subdependencies = []
except Exception as e:
# Any other error is not critical - continue without subdependencies
logging.debug(f"Failed to analyze subdependencies for {package_name}: {e}")
subdependencies = []
# Add main dependency (always add, even if subdependency analysis failed)
# Ensure all fields are properly set and clean
clean_package_name = str(package_name).strip() if package_name else "Unknown"
# Remove any None/null strings that might have been concatenated
clean_package_name = clean_package_name.replace('None', '').replace('null', '').strip()
if not clean_package_name:
clean_package_name = "Unknown"
analyzed_dependencies.append({
'name': clean_package_name,
'version': str(version_spec) if version_spec else None,
'line': dep_line.strip(),
'status': status,
'currentVersion': current_version_str,
'selected': status != 'installed', # Deselect if already installed
'subdependencies': subdependencies
})
return web.json_response({
'success': True,
'requirements': requirements_content,
'dependencies': analyzed_dependencies,
'noRequirementsFile': False
})
except Exception as e:
logging.error(f"Error analyzing dependencies: {e}")
traceback.print_exc()
return web.json_response({'error': str(e)}, status=500)
def parse_requirements(content):
"""Parse requirements.txt content into list of dependency lines."""
lines = []
for line in content.split('\n'):
line = line.strip()
if line and not line.startswith('#'):
lines.append(line)
return lines
def parse_dry_run_output(output, parent_name, installed_packages):
"""Parse pip install --dry-run output to extract subdependencies."""
import re
subdependencies = []
subdeps_map = {}
lines = output.split('\n')
for line in lines:
line = line.strip()
# Look for "Collecting package==version" lines
if 'Collecting ' in line and 'Using cached' not in line:
# Match: "Collecting package==version" or "Collecting package"
match = re.search(r'Collecting\s+([a-zA-Z0-9_.-]+(?:\[[^\]]+\])?)(?:\s*==\s*([^\s\(]+))?', line)
if match:
dep_name = match.group(1).split('[')[0].strip()
# Clean the name - remove any None/null strings
if dep_name:
dep_name = dep_name.replace('None', '').replace('null', '').strip()
dep_version = match.group(2).strip() if match.group(2) else None
# Clean version too
if dep_version:
dep_version = dep_version.replace('None', '').replace('null', '').strip() or None
# Skip the parent package itself
if dep_name.lower() == parent_name.lower():
continue
# Normalize name
normalized_name = dep_name.lower().replace('-', '_')
# Check if already in map (avoid duplicates)
if normalized_name not in subdeps_map:
# Check if already installed
installed_version = installed_packages.get(normalized_name)
status = 'installed' if installed_version else 'new'
current_version_str = str(installed_version) if installed_version else None
# Ensure name is always a string, not None
if not dep_name:
dep_name = "Unknown"
# Clean the name - remove any None/null strings
clean_dep_name = str(dep_name).strip().replace('None', '').replace('null', '').strip()
if not clean_dep_name:
clean_dep_name = "Unknown"
subdeps_map[normalized_name] = {
'name': clean_dep_name,
'version': str(dep_version) if dep_version else None,
'status': status,
'currentVersion': current_version_str,
'selected': status != 'installed'
}
# Also look for "Would install" lines which have more accurate version info
if 'Would install' in line:
# Match: "Would install package-version"
match = re.search(r'Would install\s+([a-zA-Z0-9_.-]+)-([\d.]+)', line)
if match:
dep_name = match.group(1)
dep_version = match.group(2)
normalized_name = dep_name.lower().replace('-', '_')
if normalized_name in subdeps_map:
# Update with more accurate version
subdeps_map[normalized_name]['version'] = dep_version
# Convert map to list
for normalized_name, dep_info in subdeps_map.items():
subdependencies.append(dep_info)
return subdependencies
async def fetch_requirements_from_git(url, commit_id=None, branch=None):
"""
Fetch requirements.txt from a git repository URL.
Supports GitHub URLs by converting to raw.githubusercontent.com.
"""
try:
# Extract GitHub repo info
if 'github.com' in url:
# Convert to raw GitHub URL
url = url.rstrip('/')
if url.endswith('.git'):
url = url[:-4]
# Extract owner/repo
match = re.search(r'github\.com[:/]([^/]+)/([^/]+)', url)
if not match:
return None
owner = match.group(1)
repo = match.group(2)
# Build raw URL
if commit_id:
raw_url = f"https://raw.githubusercontent.com/{owner}/{repo}/{commit_id}/requirements.txt"
elif branch:
raw_url = f"https://raw.githubusercontent.com/{owner}/{repo}/{branch}/requirements.txt"
else:
raw_url = f"https://raw.githubusercontent.com/{owner}/{repo}/main/requirements.txt"
# Try to fetch using aiohttp
async with aiohttp.ClientSession() as session:
async with session.get(raw_url) as response:
if response.status == 200:
return await response.text()
# Try with master branch if main fails
if 'main' in raw_url:
raw_url = raw_url.replace('/main/', '/master/')
async with session.get(raw_url) as response2:
if response2.status == 200:
return await response2.text()
else:
# For non-GitHub URLs, we'd need to clone temporarily
# For now, return None (can be enhanced later)
logging.warning(f"Non-GitHub URL not fully supported for dependency analysis: {url}")
return None
return None
except Exception as e:
logging.error(f"Error fetching requirements from git: {e}")
return None
@routes.post("/manager/queue/uninstall")
async def uninstall_custom_node(request):
if not is_allowed_security_level('middle'):

View File

@ -67,6 +67,7 @@ export class CustomNodesManager {
this.filter = '';
this.keywords = '';
this.restartMap = {};
this.analyzeDependenciesBeforeInstall = false; // Default: false
this.init();
@ -77,6 +78,36 @@ export class CustomNodesManager {
}
init() {
// Create checkbox for dependency analysis
const analyzeDepsCheckbox = $el("input", {
type: "checkbox",
id: "cn-analyze-deps-checkbox",
checked: this.analyzeDependenciesBeforeInstall,
onchange: (e) => {
this.analyzeDependenciesBeforeInstall = e.target.checked;
},
style: {
marginRight: "6px",
cursor: "pointer"
}
});
const analyzeDepsLabel = $el("label", {
for: "cn-analyze-deps-checkbox",
style: {
display: "flex",
alignItems: "center",
cursor: "pointer",
color: "#fff",
fontSize: "12px",
marginRight: "10px",
whiteSpace: "nowrap"
}
}, [
analyzeDepsCheckbox,
$el("span", { textContent: "Analyse dependencies before node installation" })
]);
const header = $el("div.cn-manager-header.px-2", {}, [
// $el("label", {}, [
// $el("span", { textContent: "Filter" }),
@ -84,6 +115,7 @@ export class CustomNodesManager {
// ]),
createSettingsCombo("Filter", $el("select.cn-manager-filter")),
$el("input.cn-manager-keywords.p-inputtext.p-component", { type: "search", placeholder: "Search" }),
analyzeDepsLabel,
$el("div.cn-manager-status"),
$el("div.cn-flex-auto"),
$el("div.cn-manager-channel")
@ -105,6 +137,421 @@ export class CustomNodesManager {
this.initGrid();
}
showDependencySelectorDialog(dependencies, onSelect) {
const dialog = new ComfyDialog();
dialog.element.style.zIndex = 1100;
dialog.element.style.width = "900px";
dialog.element.style.maxHeight = "80vh";
dialog.element.style.padding = "0";
dialog.element.style.backgroundColor = "#2a2a2a";
dialog.element.style.border = "1px solid #3a3a3a";
dialog.element.style.borderRadius = "8px";
dialog.element.style.boxSizing = "border-box";
dialog.element.style.overflow = "hidden";
const contentStyle = {
width: "100%",
display: "flex",
flexDirection: "column",
padding: "20px",
boxSizing: "border-box",
gap: "15px"
};
// Create scrollable table container with sticky header
const tableContainer = $el("div", {
style: {
maxHeight: "500px",
overflowY: "auto",
border: "1px solid #4a4a4a",
borderRadius: "4px",
backgroundColor: "#1a1a1a",
position: "relative"
}
});
// Create table
const table = $el("table", {
style: {
width: "100%",
borderCollapse: "separate",
borderSpacing: "0",
fontSize: "14px"
}
});
// Create table header with sticky positioning
const thead = $el("thead", {
style: {
position: "sticky",
top: "0",
zIndex: "10",
backgroundColor: "#2a2a2a",
boxShadow: "0 2px 4px rgba(0,0,0,0.3)"
}
}, [
$el("tr", {
style: {
backgroundColor: "#2a2a2a",
borderBottom: "2px solid #4a4a4a"
}
}, [
$el("th", {
textContent: "",
style: {
padding: "10px",
textAlign: "left",
width: "40px",
color: "#fff"
}
}),
$el("th", {
textContent: "Dependency Name",
style: {
padding: "10px",
textAlign: "left",
color: "#fff",
fontWeight: "bold"
}
}),
$el("th", {
textContent: "Current Version",
style: {
padding: "10px",
textAlign: "left",
color: "#fff",
fontWeight: "bold"
}
}),
$el("th", {
textContent: "Incoming Version",
style: {
padding: "10px",
textAlign: "left",
color: "#fff",
fontWeight: "bold"
}
})
])
]);
// Create table body
const tbody = $el("tbody", {});
// Create table rows for each dependency and its subdependencies
let rowIndex = 0;
dependencies.forEach((dep) => {
// Ensure name is not null/undefined and clean it
let depName = dep.name;
if (!depName || depName === 'null' || depName === 'None') {
// Fallback: extract from line
if (dep.line) {
depName = dep.line.split(/[=<>!~]/)[0].trim();
} else {
depName = "Unknown";
}
}
// Remove any "null" suffix that might have been appended
depName = String(depName).replace(/null$/i, '').trim();
const isInstalled = dep.status === 'installed';
const incomingVersion = dep.version || "NA";
const currentVersion = dep.currentVersion || "NA";
// Main dependency row
const row = $el("tr", {
style: {
backgroundColor: rowIndex % 2 === 0 ? "#1a1a1a" : "#222222",
borderBottom: "1px solid #3a3a3a"
}
}, [
$el("td", {
style: {
padding: "10px",
textAlign: "center"
}
}, [
$el("input", {
type: "checkbox",
checked: dep.selected,
onchange: (e) => {
dep.selected = e.target.checked;
},
style: {
cursor: "pointer",
width: "18px",
height: "18px"
}
})
]),
$el("td", {
style: {
padding: "10px",
color: isInstalled ? "#888" : "#fff"
}
}, [
$el("span", {
textContent: depName,
style: {
fontWeight: "500",
marginRight: isInstalled ? "8px" : "0"
}
}),
isInstalled ? $el("span", {
textContent: "Installed",
style: {
display: "inline-block",
backgroundColor: "#2a4a2a",
color: "#4a9",
padding: "2px 6px",
borderRadius: "3px",
fontSize: "10px",
fontWeight: "bold",
border: "1px solid #4a9"
}
}) : ''
]),
$el("td", {
textContent: currentVersion,
style: {
padding: "10px",
color: isInstalled ? "#4a9" : "#aaa",
fontFamily: "monospace"
}
}),
$el("td", {
textContent: incomingVersion,
style: {
padding: "10px",
color: "#fff",
fontFamily: "monospace"
}
})
]);
tbody.appendChild(row);
rowIndex++;
// Add subdependencies as indented rows
if(dep.subdependencies && dep.subdependencies.length > 0) {
dep.subdependencies.forEach((subdep) => {
// Ensure subdependency name is not null/undefined and clean it
let subdepName = subdep.name;
if (!subdepName || subdepName === 'null' || subdepName === 'None') {
subdepName = "Unknown";
}
// Remove any "null" suffix that might have been appended
subdepName = String(subdepName).replace(/null$/i, '').trim();
const subIsInstalled = subdep.status === 'installed';
const subIncomingVersion = subdep.version || "NA";
const subCurrentVersion = subdep.currentVersion || "NA";
const subRow = $el("tr", {
style: {
backgroundColor: rowIndex % 2 === 0 ? "#1a1a1a" : "#222222",
borderBottom: "1px solid #3a3a3a"
}
}, [
$el("td", {
style: {
padding: "10px",
textAlign: "center"
}
}, [
$el("input", {
type: "checkbox",
checked: subdep.selected,
onchange: (e) => {
subdep.selected = e.target.checked;
},
style: {
cursor: "pointer",
width: "18px",
height: "18px"
}
})
]),
$el("td", {
style: {
padding: "10px 10px 10px 30px",
color: subIsInstalled ? "#888" : "#aaa",
fontSize: "13px"
}
}, [
$el("span", {
textContent: "└─ " + subdepName,
style: {
fontWeight: "400",
marginRight: subIsInstalled ? "8px" : "0"
}
}),
subIsInstalled ? $el("span", {
textContent: "Installed",
style: {
display: "inline-block",
backgroundColor: "#2a4a2a",
color: "#4a9",
padding: "2px 6px",
borderRadius: "3px",
fontSize: "10px",
fontWeight: "bold",
border: "1px solid #4a9"
}
}) : ''
]),
$el("td", {
textContent: subCurrentVersion,
style: {
padding: "10px",
color: subIsInstalled ? "#4a9" : "#666",
fontFamily: "monospace",
fontSize: "13px"
}
}),
$el("td", {
textContent: subIncomingVersion,
style: {
padding: "10px",
color: "#aaa",
fontFamily: "monospace",
fontSize: "13px"
}
})
]);
tbody.appendChild(subRow);
rowIndex++;
});
}
});
table.appendChild(thead);
table.appendChild(tbody);
tableContainer.appendChild(table);
const content = $el("div", {
style: contentStyle
}, [
$el("h3", {
textContent: "Select Dependencies to Install",
style: {
color: "#ffffff",
backgroundColor: "#1a1a1a",
padding: "10px 15px",
margin: "0 0 10px 0",
width: "100%",
textAlign: "center",
borderRadius: "4px",
boxSizing: "border-box"
}
}),
$el("div", {
textContent: `${dependencies.filter(d => d.status === 'installed').length} already installed, ${dependencies.filter(d => d.status !== 'installed').length} to install`,
style: {
color: "#aaa",
fontSize: "12px",
marginBottom: "5px"
}
}),
tableContainer,
$el("div", {
style: {
display: "flex",
justifyContent: "space-between",
width: "100%",
gap: "10px",
marginTop: "10px"
}
}, [
$el("button", {
textContent: "Cancel",
onclick: () => {
onSelect(null); // Pass null to indicate cancellation
dialog.close();
},
style: {
flex: "1",
padding: "8px",
backgroundColor: "#4a4a4a",
color: "#ffffff",
border: "none",
borderRadius: "4px",
cursor: "pointer"
}
}),
$el("button", {
textContent: "Select All",
onclick: () => {
dependencies.forEach(dep => {
if (dep.status !== 'installed') {
dep.selected = true;
}
// Also select subdependencies
if(dep.subdependencies) {
dep.subdependencies.forEach(subdep => {
if(subdep.status !== 'installed') {
subdep.selected = true;
}
});
}
});
// Update checkboxes in the table
const checkboxes = tableContainer.querySelectorAll('input[type="checkbox"]');
checkboxes.forEach((checkbox) => {
if(!checkbox.disabled) {
checkbox.checked = true;
}
});
},
style: {
padding: "8px 15px",
backgroundColor: "#4a6a4a",
color: "#ffffff",
border: "none",
borderRadius: "4px",
cursor: "pointer"
}
}),
$el("button", {
textContent: "Install Selected",
onclick: () => {
// Collect all selected dependencies (main + subdependencies)
const selected = [];
dependencies.forEach(d => {
if(d.selected) {
selected.push(d);
}
// Also include selected subdependencies
if(d.subdependencies) {
d.subdependencies.forEach(subdep => {
if(subdep.selected) {
selected.push(subdep);
}
});
}
});
onSelect(selected);
dialog.close();
},
style: {
flex: "1",
padding: "8px",
backgroundColor: "#4CAF50",
color: "#ffffff",
border: "none",
borderRadius: "4px",
cursor: "pointer"
}
}),
])
]);
console.log('[Dependency Dialog] Showing dialog with', dependencies.length, 'dependencies');
dialog.show(content);
console.log('[Dependency Dialog] Dialog shown');
}
showVersionSelectorDialog(versions, onSelect) {
const dialog = new ComfyDialog();
dialog.element.style.zIndex = 1100;
@ -1470,6 +1917,101 @@ export class CustomNodesManager {
}
}
// For install mode, analyze dependencies BEFORE starting installation
let selectedDependencies = [];
let dependencyDialogShown = false; // Track if dialog was shown
if(mode === "install" && this.analyzeDependenciesBeforeInstall) {
// Analyze dependencies for all items first (only if checkbox is enabled)
for (const hash of list) {
const item = this.grid.getRowItemBy("hash", hash);
if (!item) {
console.log('[Dependency Analysis] Item not found for hash:', hash);
continue;
}
const data = item.originalData;
console.log('[Dependency Analysis] Item data:', {
title: item.title,
files: data.files,
repository: data.repository,
hasFiles: !!data.files,
filesLength: data.files ? data.files.length : 0
});
// Try multiple ways to get the git URL
let gitUrl = null;
if(data.files && data.files.length > 0) {
gitUrl = data.files[0];
} else if(data.repository) {
gitUrl = data.repository;
}
if(gitUrl && (gitUrl.includes('github.com') || gitUrl.includes('.git'))) {
try {
this.showStatus(`Analyzing dependencies for ${item.title}...`);
console.log('[Dependency Analysis] Fetching dependencies for:', gitUrl);
const analyzeRes = await api.fetchApi('/customnode/analyze_dependencies', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
url: gitUrl,
commitId: data.commit_id,
branch: data.branch
})
});
console.log('[Dependency Analysis] Response status:', analyzeRes.status);
if(analyzeRes.status === 200) {
const analyzeData = await analyzeRes.json();
console.log('[Dependency Analysis] Response data:', {
success: analyzeData.success,
hasDependencies: !!analyzeData.dependencies,
dependenciesCount: analyzeData.dependencies ? analyzeData.dependencies.length : 0,
noRequirementsFile: analyzeData.noRequirementsFile
});
if(analyzeData.success && analyzeData.dependencies && analyzeData.dependencies.length > 0) {
console.log('[Dependency Analysis] Showing dialog with', analyzeData.dependencies.length, 'dependencies');
dependencyDialogShown = true;
// Show dependency selection dialog and wait for user
const userSelection = await new Promise((resolve) => {
this.showDependencySelectorDialog(analyzeData.dependencies, (selected) => {
console.log('[Dependency Analysis] User selected:', selected);
resolve(selected);
});
});
// If user cancelled (null), stop installation
if(userSelection === null) {
console.log('[Dependency Analysis] User cancelled installation');
this.showStatus("Installation cancelled");
return;
}
selectedDependencies = userSelection || [];
console.log('[Dependency Analysis] Selected dependencies:', selectedDependencies.length);
} else if(analyzeData.noRequirementsFile) {
console.log('[Dependency Analysis] No requirements.txt file found');
} else {
console.log('[Dependency Analysis] No dependencies to show');
}
} else {
const errorText = await analyzeRes.text();
console.error('[Dependency Analysis] API error:', analyzeRes.status, errorText);
}
} catch(e) {
console.error('[Dependency Analysis] Exception:', e);
// Continue with installation even if dependency analysis fails
}
} else {
console.log('[Dependency Analysis] Not a GitHub URL or no URL found:', gitUrl);
}
}
}
target.classList.add("cn-btn-loading");
this.showError("");
@ -1511,6 +2053,46 @@ export class CustomNodesManager {
data.mode = this.mode;
data.ui_id = hash;
// Add selected dependencies to data (including subdependencies)
// Only install selected dependencies - respect user's selection
const allSelected = [];
if(selectedDependencies.length > 0) {
selectedDependencies.forEach(d => {
// Add main dependency if selected
if(d.selected) {
allSelected.push({
name: d.name,
version: d.version,
line: d.line
});
}
// Add selected subdependencies
if(d.subdependencies) {
d.subdependencies.forEach(subdep => {
if(subdep.selected) {
allSelected.push({
name: subdep.name,
version: subdep.version,
line: `${subdep.name}${subdep.version ? '==' + subdep.version : ''}`
});
}
});
}
});
}
// Set selectedDependencies:
// - If dialog was shown: always set (even if empty) to respect user's selection
// - If dialog was not shown: don't set (install all dependencies - original behavior)
if(dependencyDialogShown) {
// User saw the dialog, respect their selection (even if empty)
data.selectedDependencies = allSelected;
} else if(allSelected.length > 0) {
// Dialog wasn't shown but we have selections (shouldn't happen, but just in case)
data.selectedDependencies = allSelected;
}
// If dialog wasn't shown and no selections, don't set selectedDependencies
// This means backend will install all dependencies (original behavior)
let install_mode = mode;
if(mode == 'switch') {
install_mode = 'install';

View File

@ -4970,9 +4970,13 @@
"SV-ClearCustomCaches",
"SV-CompressConds",
"SV-CondDiffSharpening",
"SV-ConditioningArithmetic",
"SV-ConditioningInterferenceSchedule",
"SV-ConditioningMaskMerge",
"SV-ConditioningNoiseNudge",
"SV-ConditioningReroute",
"SV-ConditioningScaleJitter",
"SV-ConditioningScheduledBlend",
"SV-ConditioningTokenDropoutNudge",
"SV-ConsolePrint",
"SV-ConsolePrintLoop",
@ -5013,16 +5017,15 @@
"SV-HashModel",
"SV-HashObject",
"SV-IfBranch",
"SV-ImageInt",
"SV-ImageReroute",
"SV-InputSelect",
"SV-InputSelectBoolean",
"SV-InputSelectCompare",
"SV-IntMathOperation",
"SV-Krea2LocalStyleReferenceOld",
"SV-Krea2Reference",
"SV-Krea2ReferenceAdvanced",
"SV-Krea2ReferencePlus",
"SV-Krea2ResizeImage",
"SV-LLMArgs",
"SV-LLMRequest",
"SV-ListToAccumulationNode",
@ -5044,6 +5047,7 @@
"SV-PrecisionFloat",
"SV-PrimitiveFloat",
"SV-PrimitiveNone",
"SV-PromptGeneratorAPI",
"SV-PromptPlusModel",
"SV-PromptPlusModelOutput",
"SV-PromptProcessing",
@ -5056,11 +5060,14 @@
"SV-PromptProcessingSimple",
"SV-PromptProcessingVars",
"SV-RandomImage",
"SV-RegexMatch",
"SV-RegexReplace",
"SV-ResizeImage",
"SV-ResolutionSelector",
"SV-ResolutionSelector2",
"SV-ResolutionSelector2Output",
"SV-SamplerNameToSampler",
"SV-SaveImageCustom",
"SV-SaveTextFile",
"SV-ScaleConditioning",
"SV-SigmaAsFloat",
@ -5077,6 +5084,7 @@
"SV-SigmaReverse",
"SV-SigmaStartEnd",
"SV-SigmaStrength",
"SV-SimpleString",
"SV-SimpleText",
"SV-SkimmedCFGDifference",
"SV-SkimmedCFGDual",
@ -5096,7 +5104,8 @@
"SV-WhileLoopOpen",
"SV-WildcardLoader",
"SV-WildcardProcessing",
"SV-WildcardString"
"SV-WildcardString",
"SV-WorkflowAgent"
],
{
"title_aux": "SirVeggie/Custom nodes for ComfyUI"

View File

@ -752,7 +752,6 @@
"GrsaiFluxKontext_MultiImageToImage",
"GrsaiFluxKontext_TextToImage",
"Grsai_GPTImage",
"Grsai_GPTImageVIP",
"Grsai_NanoBanana",
"Grsai_NanoBanana2",
"Grsai_NanoBananaPro"
@ -3988,6 +3987,9 @@
{
"author": "Azornes",
"description": "Logging Configuration",
"preemptions": [
"ResolutionMaster"
],
"title": "AzLogs",
"title_aux": "Comfyui-Resolution-Master"
}
@ -17719,6 +17721,18 @@
"title_aux": "ComfyUI-Montagen"
}
],
"https://github.com/Moon-NE/MoonNe_Nodes": [
[
"BatchConditionalText",
"BatchConditionalTextWeight",
"Moon_NE_Text_Concatenate",
"TextHorizontalToVertical",
"batch_randoml_text"
],
{
"title_aux": "MoonNe_Nodes"
}
],
"https://github.com/MoonHugo/ComfyUI-BAGEL-Hugo": [
[
"BagelByHugo"
@ -20976,223 +20990,6 @@
"title_aux": "ComfyUI-PromptUtils"
}
],
"https://github.com/Runware/ComfyUI-Runware": [
[
"Runware 3D Inference",
"Runware 3D Inference Inputs",
"Runware 3D Inference Settings",
"Runware 3D Inference Settings Draco Compression",
"Runware 3D Inference Settings Mesh Cluster",
"Runware 3D Inference Settings Shape Slat",
"Runware 3D Inference Settings Sparse Structure",
"Runware 3D Inference Settings Tex Slat",
"Runware 3D Model Search",
"Runware API Manager",
"Runware Accelerator Options",
"Runware Alibaba Provider Settings",
"Runware Audio Inference",
"Runware Audio Inference Inputs",
"Runware Audio Inference Inputs Reference Audio",
"Runware Audio Inference Settings",
"Runware Audio Inference Settings Voice Modify",
"Runware Audio Inference Speech",
"Runware Audio Inference Speech Voices",
"Runware Audio Model Search",
"Runware Audio Sections",
"Runware Background Removal",
"Runware BlackForest Labs Provider Settings",
"Runware Bria Provider Mask",
"Runware Bria Provider Settings",
"Runware Bytedance Provider Settings",
"Runware ControlNet",
"Runware ControlNet Combine",
"Runware ControlNet PreProcessor",
"Runware ElevenLabs Provider Settings",
"Runware ElevenLabs Provider Settings Sections",
"Runware Embedding Search",
"Runware Embeddings Combine",
"Runware Frame Images",
"Runware Google Provider Settings",
"Runware IPAdapter",
"Runware IPAdapters Combine",
"Runware Image Advanced Feature Input",
"Runware Image Caption",
"Runware Image Inference",
"Runware Image Inference Inputs",
"Runware Image Inference Inputs Fonts",
"Runware Image Inference Settings Color Palette",
"Runware Image Inference Settings Moodboards",
"Runware Image Inference Settings Prompt Enhance",
"Runware Image Inference Settings Scoring Rubric",
"Runware Image Inference Settings Scoring Rubric Combine",
"Runware Image Inference Settings Structured Prompt",
"Runware Image Inference Ultralytics",
"Runware Image Masking",
"Runware Image Upscaler",
"Runware Image Upscaler Settings",
"Runware Imagen Inference",
"Runware Input Audios",
"Runware Kling MultiPrompt Segment",
"Runware Kling Provider Settings MultiPrompt",
"Runware KlingAI Provider Settings",
"Runware Kontext Inference",
"Runware Lightricks Provider Settings",
"Runware Load Mesh",
"Runware Lora Combine",
"Runware Lora Search",
"Runware Luma Provider Settings",
"Runware Media Upload",
"Runware Midjourney Provider Settings",
"Runware MiniMax Provider Settings",
"Runware Mirelo Provider Settings",
"Runware Model Search",
"Runware Multi Inference",
"Runware OpenAI Provider Settings",
"Runware Outpaint",
"Runware PhotoMaker V2",
"Runware Pixverse Provider Settings",
"Runware Provider Settings Recraft Color",
"Runware Recraft Provider Settings",
"Runware Reference Audios",
"Runware Reference Images",
"Runware Reference Videos",
"Runware Reference Voices",
"Runware Refiner",
"Runware Regional Prompting Advanced Feature",
"Runware Regional Prompting Advanced Feature Regions",
"Runware Runway Provider Settings",
"Runware Safety Inputs",
"Runware Save 3D",
"Runware Save Image",
"Runware Save Text",
"Runware Settings",
"Runware Sourceful Provider Settings",
"Runware Sourceful Provider Settings Fonts",
"Runware Speech Inputs Combine",
"Runware Sync Provider Settings",
"Runware Sync Segment",
"Runware Text Inference",
"Runware Text Inference Inputs",
"Runware Text Inference Inputs Images",
"Runware Text Inference Inputs Videos",
"Runware Text Inference Message",
"Runware Text Inference Messages",
"Runware Text Inference Settings",
"Runware Text Inference Settings Cache",
"Runware Text Inference Tool Choice",
"Runware Text Model Search",
"Runware VAE Search",
"Runware Vectorize",
"Runware Video Advanced Feature Inputs",
"Runware Video Audio Input",
"Runware Video Background Removal",
"Runware Video Inference",
"Runware Video Inference Elements",
"Runware Video Inference Elements Combine",
"Runware Video Inference Inputs",
"Runware Video Inference Inputs Reference Audios",
"Runware Video Inference Inputs Reference Images",
"Runware Video Inference Inputs Reference Images Multiple Images Connector",
"Runware Video Inference Inputs Reference Videos",
"Runware Video Inference Inputs Reference Voices",
"Runware Video Inference Lora",
"Runware Video Inference Outputs",
"Runware Video Inference Settings",
"Runware Video Inference Settings Active Speaker Bounding Boxes",
"Runware Video Inference Settings Active Speaker Detection",
"Runware Video Inference Settings Edit",
"Runware Video Inference Settings Segments",
"Runware Video Inference Settings Source Position",
"Runware Video Inference Settings TTS",
"Runware Video Inference Speech Input",
"Runware Video Inputs Frame Images",
"Runware Video Inputs References",
"Runware Video Model Search",
"Runware Video Speech Input",
"Runware Video Transcription",
"Runware Video Upscaler",
"Runware Vidu Provider Settings",
"Runware Wan Animate Advanced Feature Settings",
"Runware Watermark Advanced Feature",
"Runware xAI Provider Settings",
"Runware3DInference",
"Runware3DInferenceInputs",
"Runware3DInferenceSettings",
"Runware3DInferenceSettingsDracoCompression",
"Runware3DInferenceSettingsMeshCluster",
"Runware3DInferenceSettingsShapeSlat",
"Runware3DInferenceSettingsSparseStructure",
"Runware3DInferenceSettingsTexSlat",
"RunwareAlibabaProviderSettings",
"RunwareAudioInferenceInputs",
"RunwareAudioInferenceReferenceVoices",
"RunwareAudioInferenceSpeech",
"RunwareAudioInferenceSpeechVoices",
"RunwareAudioInput",
"RunwareAudioSettings",
"RunwareAudioSettingsVoiceModify",
"RunwareBlackForestProviderSettings",
"RunwareBriaProviderMask",
"RunwareBriaProviderSettings",
"RunwareBytedanceProviderSettings",
"RunwareFrameImages",
"RunwareGoogleProviderSettings",
"RunwareImageInferenceAdvancedFeatures",
"RunwareImageInferenceSettingsPromptEnhance",
"RunwareImageInferenceSettingsStructuredPrompt",
"RunwareKlingMultiPromptSegment",
"RunwareKlingProviderSettings",
"RunwareKlingProviderSettingsMultiPrompt",
"RunwareLightricksProviderSettings",
"RunwareLoadMesh",
"RunwareLumaProviderSettings",
"RunwareMidjourneyProviderSettings",
"RunwareMiniMaxProviderSettings",
"RunwareMireloProviderSettings",
"RunwareOpenAIProviderSettings",
"RunwarePixverseProviderSettings",
"RunwareRecraftColor",
"RunwareRecraftProviderSettings",
"RunwareRegionalPromptingAdvancedFeature",
"RunwareRegionalPromptingAdvancedFeatureRegions",
"RunwareRunwayProviderSettings",
"RunwareSafetyInputs",
"RunwareSave3D",
"RunwareSourcefulProviderSettings",
"RunwareSourcefulProviderSettingsFonts",
"RunwareSpeechInput",
"RunwareSpeechInputCombine",
"RunwareSyncProviderSettings",
"RunwareSyncSegment",
"RunwareTextInferenceSettingsCache",
"RunwareTextInferenceToolChoice",
"RunwareUltralyticsInputs",
"RunwareUltralyticsProviderSettings",
"RunwareVectorize",
"RunwareVideoAdvancedFeatureInputs",
"RunwareVideoBgRemoval",
"RunwareVideoInferenceOutputs",
"RunwareVideoInferenceSettingsActiveSpeakerBoundingBoxes",
"RunwareVideoInferenceSettingsActiveSpeakerDetection",
"RunwareVideoInferenceSettingsControl",
"RunwareVideoInferenceSettingsSegments",
"RunwareVideoInferenceSettingsSourcePosition",
"RunwareVideoInferenceSettingsTts",
"RunwareVideoInferenceSpeechInput",
"RunwareVideoInputsFrameImages",
"RunwareVideoInputsReferenceImagesMultipleImagesConnector",
"RunwareVideoInputsReferences",
"RunwareVideoSettings",
"RunwareVideoUpscaler",
"RunwareWanAnimateAdvancedFeatureSettings",
"RunwareWatermarkAdvancedFeature",
"RunwareXAIProviderSettings",
"txt2vid"
],
{
"title_aux": "Runware.ai ComfyUI Inference API Integration"
}
],
"https://github.com/RyanHolanda/ComfyUI-AudioBridge": [
[
"AudioToTensor",
@ -25444,6 +25241,26 @@
"title_aux": "ComfyUI-RotoMask"
}
],
"https://github.com/TechnoWarrior2/comfyui-image-picker": [
[
"AlexImagePicker"
],
{
"author": "alex",
"description": "Pauses workflow and opens a new browser window to pick which images to pass through.",
"nickname": "Image Picker",
"title": "Alex Image Picker",
"title_aux": "ComfyUI Image Picker"
}
],
"https://github.com/TechnoWarrior2/comfyui-live-preview": [
[
"AlexLivePreview"
],
{
"title_aux": "ComfyUI Live Preview"
}
],
"https://github.com/TemryL/ComfyS3": [
[
"DownloadFileS3",
@ -48485,7 +48302,8 @@
],
"https://github.com/jtydhr88/ComfyUI-qwenmultiangle": [
[
"QwenMultiangleCameraNode"
"QwenMultiangleCameraNode",
"QwenMultiangleCameraTranslateNode"
],
{
"title_aux": "ComfyUI-qwenmultiangle"
@ -64003,6 +63821,22 @@
"title_aux": "comfyui-clippy-reloaded"
}
],
"https://github.com/shootthesound/comfyui-image-of-the-day": [
[
"ImageOfDayLoader"
],
{
"title_aux": "Image of the Day"
}
],
"https://github.com/shootthesound/comfyui-lora-FindingLora": [
[
"LoraLoaderFindingLora"
],
{
"title_aux": "Finding LoRA"
}
],
"https://github.com/shootthesound/comfyui-model-diff-to-lora": [
[
"ModelDiffToLoRA"
@ -72296,6 +72130,19 @@
"title_aux": "ComfyUI-KYNode"
}
],
"https://github.com/younestft/Comfy_EverAnimate": [
[
"ComfyEverAnimate",
"ComfyEverAnimateChunksCalculator",
"ComfyEverAnimateColorCorrection",
"ComfyEverAnimateContinueChunk",
"ComfyEverAnimateInitialChunk",
"ComfyEverAnimateMasterSettings"
],
{
"title_aux": "Comfy EverAnimate"
}
],
"https://github.com/younger15/ComfyUI-IterSwitch": [
[
"Iter_CLIPSwitch",