Add custom nodes, Civitai loras (LFS), and vast.ai setup script
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
Python Linting / Run Pylint (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Has been cancelled
Execution Tests / test (macos-latest) (push) Has been cancelled
Execution Tests / test (ubuntu-latest) (push) Has been cancelled
Execution Tests / test (windows-latest) (push) Has been cancelled
Test server launches without errors / test (push) Has been cancelled
Unit Tests / test (macos-latest) (push) Has been cancelled
Unit Tests / test (ubuntu-latest) (push) Has been cancelled
Unit Tests / test (windows-2022) (push) Has been cancelled
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
Python Linting / Run Pylint (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Has been cancelled
Execution Tests / test (macos-latest) (push) Has been cancelled
Execution Tests / test (ubuntu-latest) (push) Has been cancelled
Execution Tests / test (windows-latest) (push) Has been cancelled
Test server launches without errors / test (push) Has been cancelled
Unit Tests / test (macos-latest) (push) Has been cancelled
Unit Tests / test (ubuntu-latest) (push) Has been cancelled
Unit Tests / test (windows-2022) (push) Has been cancelled
Includes 30 custom nodes committed directly, 7 Civitai-exclusive loras stored via Git LFS, and a setup script that installs all dependencies and downloads HuggingFace-hosted models on vast.ai. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,246 @@
|
||||
import os
|
||||
import fal_client
|
||||
import folder_paths
|
||||
import configparser
|
||||
import base64
|
||||
import io
|
||||
from PIL import Image
|
||||
import logging
|
||||
import json
|
||||
import requests
|
||||
import numpy as np
|
||||
import torch
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class BaseFalAPIFluxNode:
|
||||
def __init__(self):
|
||||
self.api_key = self.get_api_key()
|
||||
os.environ['FAL_KEY'] = self.api_key
|
||||
self.api_endpoint = None
|
||||
|
||||
def get_api_key(self):
|
||||
config = configparser.ConfigParser()
|
||||
config_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'config.ini')
|
||||
if os.path.exists(config_path):
|
||||
config.read(config_path)
|
||||
return config.get('falai', 'api_key', fallback=None)
|
||||
return None
|
||||
|
||||
def set_api_endpoint(self, endpoint):
|
||||
self.api_endpoint = endpoint
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"prompt": ("STRING", {"multiline": True}),
|
||||
"width": ("INT", {"default": 1024, "step": 8}),
|
||||
"height": ("INT", {"default": 1024, "step": 8}),
|
||||
"num_inference_steps": ("INT", {"default": 28, "min": 1, "max": 100}),
|
||||
"guidance_scale": ("FLOAT", {"default": 3.5, "min": 0.1, "max": 40.0}),
|
||||
"num_images": ("INT", {"default": 1, "min": 1, "max": 4}),
|
||||
"enable_safety_checker": ("BOOLEAN", {"default": True}),
|
||||
},
|
||||
"optional": {
|
||||
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "generate"
|
||||
CATEGORY = "image generation"
|
||||
|
||||
def prepare_arguments(self, prompt, width, height, num_inference_steps, guidance_scale, num_images, enable_safety_checker, seed=None, **kwargs):
|
||||
if not self.api_key:
|
||||
raise ValueError("API key is not set. Please check your config.ini file.")
|
||||
|
||||
arguments = {
|
||||
"prompt": prompt,
|
||||
"num_inference_steps": num_inference_steps,
|
||||
"guidance_scale": guidance_scale,
|
||||
"num_images": num_images,
|
||||
"enable_safety_checker": enable_safety_checker
|
||||
}
|
||||
|
||||
# Handle custom image size
|
||||
if width is None or height is None:
|
||||
raise ValueError("Width and height must be provided when using custom image size")
|
||||
arguments["image_size"] = {
|
||||
"width": width,
|
||||
"height": height
|
||||
}
|
||||
|
||||
if seed is not None and seed != 0:
|
||||
arguments["seed"] = seed
|
||||
|
||||
return arguments
|
||||
|
||||
def call_api(self, arguments):
|
||||
logger.debug(f"Full API request payload: {json.dumps(arguments, indent=2)}")
|
||||
|
||||
if not self.api_endpoint:
|
||||
raise ValueError("API endpoint is not set. Please set it using set_api_endpoint() method.")
|
||||
|
||||
try:
|
||||
handler = fal_client.submit(
|
||||
self.api_endpoint,
|
||||
arguments=arguments,
|
||||
)
|
||||
result = handler.get()
|
||||
logger.debug(f"API response: {json.dumps(result, indent=2)}")
|
||||
return result
|
||||
except Exception as e:
|
||||
logger.error(f"API error details: {str(e)}")
|
||||
if hasattr(e, 'response'):
|
||||
logger.error(f"API error response: {e.response.text}")
|
||||
raise RuntimeError(f"An error occurred when calling the fal.ai API: {str(e)}") from e
|
||||
|
||||
def process_images(self, result):
|
||||
if "images" not in result or not result["images"]:
|
||||
logger.error("No images were generated by the API.")
|
||||
raise RuntimeError("No images were generated by the API.")
|
||||
|
||||
output_images = []
|
||||
for index, img_info in enumerate(result["images"]):
|
||||
try:
|
||||
logger.debug(f"Processing image {index}: {json.dumps(img_info, indent=2)}")
|
||||
if not isinstance(img_info, dict) or "url" not in img_info or not img_info["url"]:
|
||||
logger.error(f"Invalid image info for image {index}")
|
||||
continue
|
||||
|
||||
img_url = img_info["url"]
|
||||
logger.debug(f"Image URL: {img_url[:100]}...") # Log the first 100 characters of the URL
|
||||
|
||||
if img_url.startswith("data:image"):
|
||||
# Handle Base64 encoded image
|
||||
try:
|
||||
_, img_data = img_url.split(",", 1)
|
||||
img_data = base64.b64decode(img_data)
|
||||
except ValueError:
|
||||
logger.error(f"Failed to split image URL for image {index}")
|
||||
continue
|
||||
else:
|
||||
# Handle regular URL
|
||||
try:
|
||||
response = requests.get(img_url)
|
||||
response.raise_for_status()
|
||||
img_data = response.content
|
||||
except requests.RequestException as e:
|
||||
logger.error(f"Failed to download image from URL for image {index}: {str(e)}")
|
||||
continue
|
||||
|
||||
# Log the first few bytes of the image data
|
||||
logger.debug(f"First 20 bytes of image data: {img_data[:20]}")
|
||||
|
||||
# Try to interpret the data as an image
|
||||
try:
|
||||
img = Image.open(io.BytesIO(img_data))
|
||||
logger.debug(f"Opened image with size: {img.size} and mode: {img.mode}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to open image data: {str(e)}")
|
||||
# If opening as an image fails, try to interpret it as raw pixel data
|
||||
img_np = np.frombuffer(img_data, dtype=np.uint8)
|
||||
logger.debug(f"Interpreted as raw pixel data with shape: {img_np.shape}")
|
||||
|
||||
# If the shape is (1024,), reshape it to a more sensible image size
|
||||
if img_np.shape == (1024,):
|
||||
img_np = img_np.reshape(32, 32) # Reshape to 32x32 image
|
||||
elif img_np.shape == (1, 1, 1024):
|
||||
img_np = img_np.reshape(32, 32)
|
||||
|
||||
# Normalize the data to 0-255 range
|
||||
img_np = ((img_np - img_np.min()) / (img_np.max() - img_np.min()) * 255).astype(np.uint8)
|
||||
|
||||
img = Image.fromarray(img_np, 'L') # Create grayscale image
|
||||
img = img.convert('RGB') # Convert to RGB
|
||||
|
||||
# Ensure image is in RGB mode
|
||||
if img.mode != 'RGB':
|
||||
img = img.convert('RGB')
|
||||
|
||||
# Convert PIL Image to NumPy array
|
||||
img_np = np.array(img).astype(np.float32) / 255.0
|
||||
|
||||
# Create tensor with batch dimension (1, H, W, C)
|
||||
img_tensor = torch.from_numpy(img_np)
|
||||
img_tensor = img_tensor.unsqueeze(0) # (1, H, W, C)
|
||||
|
||||
output_images.append(img_tensor)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to process image {index}: {str(e)}")
|
||||
|
||||
if not output_images:
|
||||
logger.error("Failed to process any of the generated images.")
|
||||
raise RuntimeError("Failed to process any of the generated images.")
|
||||
|
||||
# Stack all images into a single batch tensor
|
||||
if output_images:
|
||||
output_tensor = torch.cat(output_images, dim=0)
|
||||
logger.debug(f"Returning batched tensor with shape: {output_tensor.shape}")
|
||||
return [output_tensor]
|
||||
else:
|
||||
logger.error("No images were successfully processed")
|
||||
raise RuntimeError("No images were successfully processed")
|
||||
|
||||
def upload_image(self, image):
|
||||
try:
|
||||
# Convert PyTorch tensor to numpy array
|
||||
if isinstance(image, torch.Tensor):
|
||||
image = image.cpu().numpy()
|
||||
|
||||
# Handle different shapes of numpy arrays
|
||||
if isinstance(image, np.ndarray):
|
||||
if image.ndim == 4 and image.shape[0] == 1: # (1, H, W, 3) or (1, H, W, 1)
|
||||
image = image.squeeze(0)
|
||||
|
||||
if image.ndim == 3:
|
||||
if image.shape[2] == 3: # (H, W, 3) RGB image
|
||||
pass
|
||||
elif image.shape[2] == 1: # (H, W, 1) grayscale
|
||||
image = np.repeat(image, 3, axis=2)
|
||||
elif image.shape[0] == 3: # (3, H, W) RGB
|
||||
image = np.transpose(image, (1, 2, 0))
|
||||
elif image.shape[0] == 1: # (1, H, W) grayscale
|
||||
image = np.repeat(image.squeeze(0)[..., np.newaxis], 3, axis=2)
|
||||
elif image.shape == (1, 1, 1536): # Special case for (1, 1, 1536) shape
|
||||
image = image.reshape(32, 48)
|
||||
image = np.repeat(image[..., np.newaxis], 3, axis=2)
|
||||
else:
|
||||
raise ValueError(f"Unsupported image shape: {image.shape}")
|
||||
|
||||
# Normalize to 0-255 range if not already
|
||||
if image.dtype != np.uint8:
|
||||
image = (image - image.min()) / (image.max() - image.min()) * 255
|
||||
image = image.astype(np.uint8)
|
||||
|
||||
image = Image.fromarray(image)
|
||||
|
||||
# Ensure image is in RGB mode
|
||||
if image.mode != 'RGB':
|
||||
image = image.convert('RGB')
|
||||
|
||||
# Resize image if it's too large (optional, adjust max_size as needed)
|
||||
max_size = 1024 # Example max size
|
||||
if max(image.size) > max_size:
|
||||
image.thumbnail((max_size, max_size), Image.LANCZOS)
|
||||
|
||||
# Convert PIL Image to bytes
|
||||
buffered = io.BytesIO()
|
||||
image.save(buffered, format="PNG")
|
||||
img_byte = buffered.getvalue()
|
||||
|
||||
# Upload the image using fal_client
|
||||
url = fal_client.upload(img_byte, "image/png")
|
||||
logger.info(f"Image uploaded successfully. URL: {url}")
|
||||
return url
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to process or upload image: {str(e)}")
|
||||
raise
|
||||
|
||||
def generate(self, **kwargs):
|
||||
arguments = self.prepare_arguments(**kwargs)
|
||||
result = self.call_api(arguments)
|
||||
output_images = self.process_images(result)
|
||||
return tuple(output_images)
|
||||
@@ -0,0 +1,49 @@
|
||||
class FalAPIFluxControlNetConfigNode:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"path": ("STRING", {
|
||||
"multiline": False,
|
||||
"default": "lllyasviel/sd-controlnet-canny"
|
||||
}),
|
||||
"control_image": ("IMAGE",),
|
||||
"conditioning_scale": ("FLOAT", {
|
||||
"default": 1.0,
|
||||
"min": 0.1,
|
||||
"max": 2.0,
|
||||
"step": 0.1
|
||||
}),
|
||||
},
|
||||
"optional": {
|
||||
"config_url": ("STRING", {
|
||||
"multiline": False,
|
||||
"default": ""
|
||||
}),
|
||||
"variant": ("STRING", {
|
||||
"multiline": False,
|
||||
"default": ""
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("CONTROLNET_CONFIG",)
|
||||
FUNCTION = "configure_controlnet"
|
||||
CATEGORY = "image generation"
|
||||
|
||||
def configure_controlnet(self, path, control_image, conditioning_scale, config_url="", variant=""):
|
||||
return ({
|
||||
"path": path,
|
||||
"control_image": control_image,
|
||||
"conditioning_scale": conditioning_scale,
|
||||
"config_url": config_url if config_url else None,
|
||||
"variant": variant if variant else None
|
||||
},)
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"FalAPIFluxControlNetConfigNode": FalAPIFluxControlNetConfigNode
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"FalAPIFluxControlNetConfigNode": "Fal API Flux ControlNet Config"
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
class FalAPIFluxControlNetUnionConfigNode:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"path": ("STRING", {
|
||||
"multiline": False,
|
||||
"default": "https://huggingface.co/InstantX/FLUX.1-dev-Controlnet-Union/resolve/main/diffusion_pytorch_model.safetensors"
|
||||
}),
|
||||
"control_image": ("IMAGE",),
|
||||
"control_mode": (["canny", "tile", "depth", "blur", "pose", "gray", "lq"],),
|
||||
"conditioning_scale": ("FLOAT", {
|
||||
"default": 1.0,
|
||||
"min": 0.1,
|
||||
"max": 2.0,
|
||||
"step": 0.1
|
||||
}),
|
||||
},
|
||||
"optional": {
|
||||
"config_url": ("STRING", {
|
||||
"multiline": False,
|
||||
"default": ""
|
||||
}),
|
||||
"variant": ("STRING", {
|
||||
"multiline": False,
|
||||
"default": ""
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("CONTROLNET_UNION_CONFIG",)
|
||||
FUNCTION = "configure_controlnet_union"
|
||||
CATEGORY = "image generation"
|
||||
|
||||
def configure_controlnet_union(self, path, control_image, control_mode, conditioning_scale, config_url="", variant=""):
|
||||
return ({
|
||||
"path": path,
|
||||
"controls": [{
|
||||
"control_image": control_image,
|
||||
"control_mode": control_mode,
|
||||
"conditioning_scale": conditioning_scale
|
||||
}],
|
||||
"config_url": config_url if config_url else None,
|
||||
"variant": variant if variant else None
|
||||
},)
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"FalAPIFluxControlNetUnionConfigNode": FalAPIFluxControlNetUnionConfigNode
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"FalAPIFluxControlNetUnionConfigNode": "Fal API Flux ControlNet Union Config"
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import logging
|
||||
|
||||
from .base_fal_api_flux_node import BaseFalAPIFluxNode
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FalAPIFluxDevCannyWithLoraNode(BaseFalAPIFluxNode):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.set_api_endpoint("fal-ai/flux-lora-canny")
|
||||
|
||||
def set_api_endpoint(self, endpoint):
|
||||
super().set_api_endpoint(endpoint)
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
input_types = super().INPUT_TYPES()
|
||||
# Add control image input
|
||||
input_types["required"].update({
|
||||
"control_image": ("IMAGE",), # Accept input from another node
|
||||
})
|
||||
input_types["optional"].update({
|
||||
"lora_1": ("LORA_CONFIG",),
|
||||
"lora_2": ("LORA_CONFIG",),
|
||||
"lora_3": ("LORA_CONFIG",),
|
||||
"lora_4": ("LORA_CONFIG",),
|
||||
"lora_5": ("LORA_CONFIG",),
|
||||
})
|
||||
|
||||
return input_types
|
||||
|
||||
def prepare_arguments(self, control_image, lora_1=None, lora_2=None, lora_3=None, lora_4=None, lora_5=None,
|
||||
**kwargs):
|
||||
# Get base arguments from parent class
|
||||
arguments = super().prepare_arguments(**kwargs)
|
||||
|
||||
# Upload the control image and get its URL
|
||||
control_image_url = self.upload_image(control_image)
|
||||
logger.info(f"Uploaded control image. URL: {control_image_url}")
|
||||
|
||||
# Update arguments with Canny-specific parameters
|
||||
arguments.update({
|
||||
"image_url": control_image_url
|
||||
})
|
||||
|
||||
# Collect all provided LoRA configurations
|
||||
loras = []
|
||||
for lora in [lora_1, lora_2, lora_3, lora_4, lora_5]:
|
||||
if lora is not None:
|
||||
loras.append(lora)
|
||||
|
||||
if loras:
|
||||
arguments["loras"] = loras
|
||||
|
||||
return arguments
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"FalAPIFluxDevCannyWithLoraNode": FalAPIFluxDevCannyWithLoraNode
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"FalAPIFluxDevCannyWithLoraNode": "Fal API Flux Dev Canny With LoRA"
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
from .base_fal_api_flux_node import BaseFalAPIFluxNode
|
||||
import fal_client
|
||||
import logging
|
||||
import os
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class FalAPIFluxDevImageToImageNode(BaseFalAPIFluxNode):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.set_api_endpoint("fal-ai/flux/dev/image-to-image")
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
input_types = super().INPUT_TYPES()
|
||||
input_types["required"].update({
|
||||
"image": ("IMAGE",), # This makes it accept input from another node
|
||||
"strength": ("FLOAT", {"default": 0.8, "min": 0.0, "max": 1.0}),
|
||||
})
|
||||
return input_types
|
||||
|
||||
def prepare_arguments(self, image, strength, **kwargs):
|
||||
arguments = super().prepare_arguments(**kwargs)
|
||||
|
||||
# Upload the image and get the URL
|
||||
image_url = self.upload_image(image)
|
||||
print(f"Uploaded image to {image_url}")
|
||||
|
||||
arguments.update({
|
||||
"image_url": image_url,
|
||||
"strength": strength,
|
||||
})
|
||||
|
||||
return arguments
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"FalAPIFluxDevImageToImageNode": FalAPIFluxDevImageToImageNode
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"FalAPIFluxDevImageToImageNode": "Fal API Flux Dev Image-to-Image"
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
from .base_fal_api_flux_node import BaseFalAPIFluxNode
|
||||
|
||||
class FalAPIFluxDevNode(BaseFalAPIFluxNode):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.set_api_endpoint("fal-ai/flux/dev")
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return super().INPUT_TYPES()
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"FalAPIFluxDevNode": FalAPIFluxDevNode
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"FalAPIFluxDevNode": "Fal API Flux Dev"
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
from .base_fal_api_flux_node import BaseFalAPIFluxNode
|
||||
from .fal_api_flux_dev_with_lora_and_controlnet_node import FalAPIFluxDevWithLoraAndControlNetNode
|
||||
from PIL import Image
|
||||
import torch
|
||||
import io
|
||||
import base64
|
||||
import fal_client
|
||||
import logging
|
||||
import numpy as np
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class FalAPIFluxDevWithLoraAndControlNetImageToImageNode(FalAPIFluxDevWithLoraAndControlNetNode):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.set_api_endpoint("fal-ai/flux-general/image-to-image")
|
||||
|
||||
def set_api_endpoint(self, endpoint):
|
||||
super().set_api_endpoint(endpoint)
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
input_types = super().INPUT_TYPES()
|
||||
input_types["required"].update({
|
||||
"image": ("IMAGE",), # This makes it accept input from another node
|
||||
"strength": ("FLOAT", {"default": 0.8, "min": 0.0, "max": 1.0}),
|
||||
})
|
||||
return input_types
|
||||
|
||||
def prepare_arguments(self, image, strength, **kwargs):
|
||||
arguments = super().prepare_arguments(**kwargs)
|
||||
|
||||
# Upload the image and get the URL
|
||||
image_url = self.upload_image(image)
|
||||
print(f"Uploaded image to {image_url}")
|
||||
|
||||
arguments.update({
|
||||
"image_url": image_url,
|
||||
"strength": strength,
|
||||
})
|
||||
|
||||
return arguments
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"FalAPIFluxDevWithLoraAndControlNetImageToImageNode": FalAPIFluxDevWithLoraAndControlNetImageToImageNode
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"FalAPIFluxDevWithLoraAndControlNetImageToImageNode": "Fal API Flux with LoRA and ControlNet Image-to-Image"
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
from .base_fal_api_flux_node import BaseFalAPIFluxNode
|
||||
from .fal_api_flux_dev_with_lora_and_controlnet_image_to_image_node import FalAPIFluxDevWithLoraAndControlNetImageToImageNode
|
||||
from PIL import Image
|
||||
import torch
|
||||
import io
|
||||
import base64
|
||||
import fal_client
|
||||
import logging
|
||||
import numpy as np
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class FalAPIFluxDevWithLoraAndControlNetInpaintNode(FalAPIFluxDevWithLoraAndControlNetImageToImageNode):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.set_api_endpoint("fal-ai/flux-general/inpainting")
|
||||
|
||||
def set_api_endpoint(self, endpoint):
|
||||
super().set_api_endpoint(endpoint)
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
input_types = super().INPUT_TYPES()
|
||||
input_types["required"].update({
|
||||
"mask_image": ("IMAGE",), # This makes it accept input from another node
|
||||
})
|
||||
return input_types
|
||||
|
||||
def prepare_arguments(self, mask_image, **kwargs):
|
||||
arguments = super().prepare_arguments(**kwargs)
|
||||
|
||||
# Upload the image and get the URL
|
||||
mask_url = self.upload_image(mask_image)
|
||||
print(f"Uploaded image to {mask_url}")
|
||||
|
||||
arguments.update({
|
||||
"mask_url": mask_url,
|
||||
})
|
||||
|
||||
return arguments
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"FalAPIFluxDevWithLoraAndControlNetInpaintNode": FalAPIFluxDevWithLoraAndControlNetInpaintNode
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"FalAPIFluxDevWithLoraAndControlNetInpaintNode": "Fal API Flux with LoRA and ControlNet Inpaint"
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
from .base_fal_api_flux_node import BaseFalAPIFluxNode
|
||||
from PIL import Image
|
||||
import torch
|
||||
import io
|
||||
import base64
|
||||
import fal_client
|
||||
import logging
|
||||
import numpy as np
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class FalAPIFluxDevWithLoraAndControlNetNode(BaseFalAPIFluxNode):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.set_api_endpoint("fal-ai/flux-general")
|
||||
|
||||
def set_api_endpoint(self, endpoint):
|
||||
super().set_api_endpoint(endpoint)
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
input_types = super().INPUT_TYPES()
|
||||
input_types["optional"].update({
|
||||
"lora_1": ("LORA_CONFIG",),
|
||||
"lora_2": ("LORA_CONFIG",),
|
||||
"lora_3": ("LORA_CONFIG",),
|
||||
"lora_4": ("LORA_CONFIG",),
|
||||
"lora_5": ("LORA_CONFIG",),
|
||||
"controlnet": ("CONTROLNET_CONFIG",),
|
||||
"controlnet_union": ("CONTROLNET_UNION_CONFIG",),
|
||||
})
|
||||
return input_types
|
||||
|
||||
def prepare_arguments(self, lora_1=None, lora_2=None, lora_3=None, lora_4=None, lora_5=None,
|
||||
controlnet=None, controlnet_union=None, **kwargs):
|
||||
arguments = super().prepare_arguments(**kwargs)
|
||||
|
||||
# Collect all provided LoRA configurations
|
||||
loras = []
|
||||
for lora in [lora_1, lora_2, lora_3, lora_4, lora_5]:
|
||||
if lora is not None:
|
||||
loras.append(lora)
|
||||
|
||||
if loras:
|
||||
arguments["loras"] = loras
|
||||
|
||||
if controlnet:
|
||||
arguments["controlnets"] = [{
|
||||
"path": controlnet["path"],
|
||||
"control_image_url": self.upload_image(controlnet["control_image"]),
|
||||
"conditioning_scale": controlnet["conditioning_scale"]
|
||||
}]
|
||||
if controlnet["config_url"]:
|
||||
arguments["controlnets"][0]["config_url"] = controlnet["config_url"]
|
||||
if controlnet["variant"]:
|
||||
arguments["controlnets"][0]["variant"] = controlnet["variant"]
|
||||
|
||||
if controlnet_union:
|
||||
arguments["controlnet_unions"] = [{
|
||||
"path": controlnet_union["path"],
|
||||
"controls": [{
|
||||
"control_image_url": self.upload_image(control["control_image"]),
|
||||
"control_mode": control["control_mode"],
|
||||
"conditioning_scale": control["conditioning_scale"]
|
||||
} for control in controlnet_union["controls"]]
|
||||
}]
|
||||
if controlnet_union["config_url"]:
|
||||
arguments["controlnet_unions"][0]["config_url"] = controlnet_union["config_url"]
|
||||
if controlnet_union["variant"]:
|
||||
arguments["controlnet_unions"][0]["variant"] = controlnet_union["variant"]
|
||||
|
||||
return arguments
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"FalAPIFluxDevWithLoraAndControlNetNode": FalAPIFluxDevWithLoraAndControlNetNode
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"FalAPIFluxDevWithLoraAndControlNetNode": "Fal API Flux with LoRA and ControlNet"
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
from .base_fal_api_flux_node import BaseFalAPIFluxNode
|
||||
from .fal_api_flux_dev_with_lora_node import FalAPIFluxDevWithLoraNode
|
||||
import fal_client
|
||||
import logging
|
||||
import os
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class FalAPIFluxDevWithLoraImageToImageNode(FalAPIFluxDevWithLoraNode):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.set_api_endpoint("fal-ai/flux-lora/image-to-image")
|
||||
|
||||
def set_api_endpoint(self, endpoint):
|
||||
super().set_api_endpoint(endpoint)
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
input_types = super().INPUT_TYPES()
|
||||
input_types["required"].update({
|
||||
"image": ("IMAGE",), # This makes it accept input from another node
|
||||
"strength": ("FLOAT", {"default": 0.8, "min": 0.0, "max": 1.0}),
|
||||
})
|
||||
return input_types
|
||||
|
||||
def prepare_arguments(self, image, strength, **kwargs):
|
||||
arguments = super().prepare_arguments(**kwargs)
|
||||
|
||||
# Upload the image and get the URL
|
||||
image_url = self.upload_image(image)
|
||||
print(f"Uploaded image to {image_url}")
|
||||
|
||||
arguments.update({
|
||||
"image_url": image_url,
|
||||
"strength": strength,
|
||||
})
|
||||
|
||||
return arguments
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"FalAPIFluxDevWithLoraImageToImageNode": FalAPIFluxDevWithLoraImageToImageNode
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"FalAPIFluxDevWithLoraImageToImageNode": "Fal API Flux Dev with LoRA Image-to-Image"
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
from .base_fal_api_flux_node import BaseFalAPIFluxNode
|
||||
from .fal_api_flux_dev_with_lora_image_to_image_node import FalAPIFluxDevWithLoraImageToImageNode
|
||||
import fal_client
|
||||
import logging
|
||||
import os
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class FalAPIFluxDevWithLoraInpaintNode(FalAPIFluxDevWithLoraImageToImageNode):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.set_api_endpoint("fal-ai/flux-lora/inpainting")
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
input_types = super().INPUT_TYPES()
|
||||
input_types["required"].update({
|
||||
"mask_image": ("IMAGE",), # This makes it accept input from another node
|
||||
})
|
||||
return input_types
|
||||
|
||||
def prepare_arguments(self, mask_image, **kwargs):
|
||||
arguments = super().prepare_arguments(**kwargs)
|
||||
|
||||
# Upload the image and get the URL
|
||||
mask_url = self.upload_image(mask_image)
|
||||
print(f"Uploaded image to {mask_url}")
|
||||
|
||||
arguments.update({
|
||||
"mask_url": mask_url,
|
||||
})
|
||||
|
||||
return arguments
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"FalAPIFluxDevWithLoraInpaintNode": FalAPIFluxDevWithLoraInpaintNode
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"FalAPIFluxDevWithLoraInpaintNode": "Fal API Flux Dev with LoRA Inpaint"
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
from .base_fal_api_flux_node import BaseFalAPIFluxNode
|
||||
|
||||
class FalAPIFluxDevWithLoraNode(BaseFalAPIFluxNode):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.set_api_endpoint("fal-ai/flux-lora")
|
||||
|
||||
def set_api_endpoint(self, endpoint):
|
||||
super().set_api_endpoint(endpoint)
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
input_types = super().INPUT_TYPES()
|
||||
input_types["optional"].update({
|
||||
"lora_1": ("LORA_CONFIG",),
|
||||
"lora_2": ("LORA_CONFIG",),
|
||||
"lora_3": ("LORA_CONFIG",),
|
||||
"lora_4": ("LORA_CONFIG",),
|
||||
"lora_5": ("LORA_CONFIG",),
|
||||
})
|
||||
return input_types
|
||||
|
||||
def prepare_arguments(self, lora_1=None, lora_2=None, lora_3=None, lora_4=None, lora_5=None, **kwargs):
|
||||
arguments = super().prepare_arguments(**kwargs)
|
||||
|
||||
# Collect all provided LoRA configurations
|
||||
loras = []
|
||||
for lora in [lora_1, lora_2, lora_3, lora_4, lora_5]:
|
||||
if lora is not None:
|
||||
loras.append(lora)
|
||||
|
||||
if loras:
|
||||
arguments["loras"] = loras
|
||||
|
||||
return arguments
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"FalAPIFluxDevWithLoraNode": FalAPIFluxDevWithLoraNode
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"FalAPIFluxDevWithLoraNode": "Fal API Flux Dev With LoRA"
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
class FalAPIFluxLoraConfigNode:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"lora_url": ("STRING", {
|
||||
"multiline": False,
|
||||
"default": "https://example.com/path/to/lora.safetensors"
|
||||
}),
|
||||
"scale": ("FLOAT", {
|
||||
"default": 1.0,
|
||||
"min": 0.1,
|
||||
"max": 2.0,
|
||||
"step": 0.1
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("LORA_CONFIG",)
|
||||
FUNCTION = "configure_lora"
|
||||
CATEGORY = "image generation"
|
||||
|
||||
def configure_lora(self, lora_url, scale):
|
||||
if not lora_url.startswith(('http://', 'https://')):
|
||||
raise ValueError("Invalid LoRA URL. Please enter a valid HTTP or HTTPS URL.")
|
||||
|
||||
return ({"path": lora_url, "scale": float(scale)},)
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"FalAPIFluxLoraConfigNode": FalAPIFluxLoraConfigNode
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"FalAPIFluxLoraConfigNode": "Fal API Flux LoRA Config"
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
from .base_fal_api_flux_node import BaseFalAPIFluxNode
|
||||
from .fal_api_flux_pro_node import FalAPIFluxProNode
|
||||
import logging
|
||||
import torch
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class FalAPIFluxProCannyNode(FalAPIFluxProNode):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.set_api_endpoint("fal-ai/flux-pro/v1/canny")
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
input_types = super().INPUT_TYPES()
|
||||
# Add control image input
|
||||
input_types["required"].update({
|
||||
"control_image": ("IMAGE",), # Accept input from another node
|
||||
})
|
||||
|
||||
return input_types
|
||||
|
||||
def prepare_arguments(self, control_image, **kwargs):
|
||||
# Get base arguments from parent class
|
||||
arguments = super().prepare_arguments(**kwargs)
|
||||
|
||||
# Upload the control image and get its URL
|
||||
control_image_url = self.upload_image(control_image)
|
||||
logger.info(f"Uploaded control image. URL: {control_image_url}")
|
||||
|
||||
# Update arguments with Canny-specific parameters
|
||||
arguments.update({
|
||||
"control_image_url": control_image_url
|
||||
})
|
||||
|
||||
return arguments
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"FalAPIFluxProCannyNode": FalAPIFluxProCannyNode
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"FalAPIFluxProCannyNode": "Fal API Flux Pro Canny"
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
from .fal_api_flux_pro_canny_node import FalAPIFluxProCannyNode
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class FalAPIFluxProDepthNode(FalAPIFluxProCannyNode):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.set_api_endpoint("fal-ai/flux-pro/v1/depth")
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"FalAPIFluxProDepthNode": FalAPIFluxProDepthNode
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"FalAPIFluxProDepthNode": "Fal API Flux Pro Depth"
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
from .fal_api_flux_pro_node import FalAPIFluxProNode
|
||||
import logging
|
||||
import torch
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class FalAPIFluxProFillNode(FalAPIFluxProNode):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.set_api_endpoint("fal-ai/flux-pro/v1/fill")
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
input_types = super().INPUT_TYPES()
|
||||
# Add control image input
|
||||
input_types["required"].update({
|
||||
"image": ("IMAGE",),
|
||||
"mask_image": ("IMAGE",),
|
||||
})
|
||||
|
||||
return input_types
|
||||
|
||||
def prepare_arguments(self, image, mask_image, **kwargs):
|
||||
# Get base arguments from parent class
|
||||
arguments = super().prepare_arguments(**kwargs)
|
||||
|
||||
# Upload the image and mask and get its URL
|
||||
image_url = self.upload_image(image)
|
||||
mask_image_url = self.upload_image(mask_image)
|
||||
logger.info(f"Uploaded target image. URL: {image_url}")
|
||||
logger.info(f"Uploaded mask image. URL: {mask_image_url}")
|
||||
|
||||
# Update arguments with Fill-specific parameters
|
||||
arguments.update({
|
||||
"image_url": image_url,
|
||||
"mask_url": mask_image_url
|
||||
})
|
||||
|
||||
return arguments
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"FalAPIFluxProFillNode": FalAPIFluxProFillNode
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"FalAPIFluxProFillNode": "Fal API Flux Pro Fill"
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
from .base_fal_api_flux_node import BaseFalAPIFluxNode
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class FalAPIFluxProNode(BaseFalAPIFluxNode):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.set_api_endpoint("fal-ai/flux-pro/new")
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
input_types = super().INPUT_TYPES()
|
||||
input_types["required"]["safety_tolerance"] = (["1", "2", "3", "4", "5", "6"],)
|
||||
return input_types
|
||||
|
||||
def prepare_arguments(self, safety_tolerance, **kwargs):
|
||||
arguments = super().prepare_arguments(**kwargs)
|
||||
arguments["safety_tolerance"] = safety_tolerance
|
||||
return arguments
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"FalAPIFluxProNode": FalAPIFluxProNode
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"FalAPIFluxProNode": "Fal API Flux Pro"
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
from .base_fal_api_flux_node import BaseFalAPIFluxNode
|
||||
from .fal_api_flux_pro_node import FalAPIFluxProNode
|
||||
import logging
|
||||
import torch
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class FalAPIFluxProReduxNode(FalAPIFluxProNode):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.set_api_endpoint("fal-ai/flux-pro/v1/redux")
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
input_types = super().INPUT_TYPES()
|
||||
# Add control image input
|
||||
input_types["required"].update({
|
||||
"image": ("IMAGE",), # Accept input from another node
|
||||
})
|
||||
|
||||
return input_types
|
||||
|
||||
def prepare_arguments(self, image, **kwargs):
|
||||
# Get base arguments from parent class
|
||||
arguments = super().prepare_arguments(**kwargs)
|
||||
|
||||
# Upload the control image and get its URL
|
||||
image_url = self.upload_image(image)
|
||||
logger.info(f"Uploaded target image. URL: {image_url}")
|
||||
|
||||
# Update arguments with Canny-specific parameters
|
||||
arguments.update({
|
||||
"image_url": image_url
|
||||
})
|
||||
|
||||
return arguments
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"FalAPIFluxProReduxNode": FalAPIFluxProReduxNode
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"FalAPIFluxProReduxNode": "Fal API Flux Pro Redux"
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
from .base_fal_api_flux_node import BaseFalAPIFluxNode
|
||||
from .fal_api_flux_pro_node import FalAPIFluxProNode
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class FalAPIFluxProV11Node(FalAPIFluxProNode):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.set_api_endpoint("fal-ai/flux-pro/v1.1")
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
input_types = super().INPUT_TYPES()
|
||||
return input_types
|
||||
|
||||
def prepare_arguments(self, **kwargs):
|
||||
arguments = super().prepare_arguments(**kwargs)
|
||||
return arguments
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"FalAPIFluxProV11Node": FalAPIFluxProV11Node
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"FalAPIFluxProV11Node": "Fal API Flux Pro v1.1"
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import logging
|
||||
|
||||
from .base_fal_api_flux_node import BaseFalAPIFluxNode
|
||||
from .fal_api_flux_pro_v11_node import FalAPIFluxProV11Node
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FalAPIFluxProV11UltraNode(FalAPIFluxProV11Node):
|
||||
"""
|
||||
See https://fal.ai/models/fal-ai/flux-pro/v1.1-ultra/api
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.set_api_endpoint("fal-ai/flux-pro/v1.1-ultra")
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
# get input types from Flux Pro 1.1
|
||||
input_types = super().INPUT_TYPES()
|
||||
|
||||
# remove `width` and `height` from inputs
|
||||
# the 1.1 ultra API replaces these with `aspect_ratio`
|
||||
del (input_types["required"]["width"])
|
||||
del (input_types["required"]["height"])
|
||||
|
||||
# remove `num_inference_steps` and `guidance_scale`
|
||||
del (input_types["required"]["num_inference_steps"])
|
||||
del (input_types["required"]["guidance_scale"])
|
||||
|
||||
# add `aspect_ratio`
|
||||
input_types["required"]["aspect_ratio"] = (["16:9", "4:3", "21:9", "1:1", "3:4", "9:16", "9:21"],)
|
||||
|
||||
# add `raw`
|
||||
input_types["required"]["raw"] = ("BOOLEAN", {"default": True})
|
||||
|
||||
# add `output_format`
|
||||
input_types["required"]["output_format"] = (["jpeg", "png"],)
|
||||
|
||||
return input_types
|
||||
|
||||
def prepare_arguments(self, prompt, aspect_ratio, num_images, safety_tolerance,
|
||||
enable_safety_checker, output_format, raw, seed=None, **kwargs):
|
||||
# override from base since we don't have width and height
|
||||
if not self.api_key:
|
||||
raise ValueError("API key is not set. Please check your config.ini file.")
|
||||
|
||||
arguments = {"prompt": prompt, "raw": raw, "num_images": num_images,
|
||||
"enable_safety_checker": enable_safety_checker,
|
||||
"safety_tolerance": safety_tolerance, "aspect_ratio": aspect_ratio, "output_format": output_format}
|
||||
|
||||
if seed is not None and seed != 0:
|
||||
arguments["seed"] = seed
|
||||
|
||||
return arguments
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"FalAPIFluxProV11UltraNode": FalAPIFluxProV11Node
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"FalAPIFluxProV11UltraNode": "Fal API Flux Pro v1.1 Ultra"
|
||||
}
|
||||
Reference in New Issue
Block a user