From cf11a9477d70280ca2a248f783be4748186bf6cf Mon Sep 17 00:00:00 2001 From: Jimmy Wong Date: Mon, 4 Nov 2024 16:38:55 +0800 Subject: [PATCH] Refactoring Code --- flowy/nodes.py | 4 +- ...des_upscale.py => nodes_clarityupscale.py} | 79 ++++++++++++++----- flowy/nodes_flux.py | 20 ++--- flowy/nodes_ideogram.py | 24 +++--- flowy/types.py | 33 +++++++- 5 files changed, 113 insertions(+), 47 deletions(-) rename flowy/{nodes_upscale.py => nodes_clarityupscale.py} (53%) diff --git a/flowy/nodes.py b/flowy/nodes.py index 46558b5..5f92ef0 100644 --- a/flowy/nodes.py +++ b/flowy/nodes.py @@ -19,7 +19,7 @@ from .nodes_omost import ( from .nodes_json import FlowyPreviewJSON, FlowyExtractJSON, ComflowyLoadJSON from .nodes_http import FlowyHttpRequest from .nodes_llm import FlowyLLM -from .nodes_upscale import FlowyUpscale +from .nodes_clarityupscale import FlowyClarityUpscale from .nodes_flux import FlowyFlux from .nodes_ideogram import FlowyIdeogram @@ -70,7 +70,7 @@ NODE_CLASS_MAPPINGS = { "Comflowy_Omost_Load_Canvas_Python_Code": ComflowyOmostLoadCanvasPythonCodeNode, "Comflowy_Omost_Load_Canvas_Conditioning": ComflowyOmostLoadCanvasConditioningNode, "Comflowy_Set_API_Key": ComflowySetAPIKey, - "Comflowy_Upscale": FlowyUpscale, + "Comflowy_Upscale": FlowyClarityUpscale, "Comflowy_Ideogram": FlowyIdeogram, "Comflowy_Flux": FlowyFlux, } diff --git a/flowy/nodes_upscale.py b/flowy/nodes_clarityupscale.py similarity index 53% rename from flowy/nodes_upscale.py rename to flowy/nodes_clarityupscale.py index 96719f2..7e2c108 100644 --- a/flowy/nodes_upscale.py +++ b/flowy/nodes_clarityupscale.py @@ -13,14 +13,37 @@ from .api_key_manager import load_api_key logger = logging.getLogger(__name__) -class FlowyUpscale: +class FlowyClarityUpscale: @classmethod def INPUT_TYPES(s): return { "required": { "image": ("IMAGE",), - "scale_factor": ("INT", {"default": 2, "min": 1, "max": 4, "step": 1}), - "model": (["clarity-upscaler"],), + "scale_factor": ([2, 4, 6, 8], {"default": 2}), + "dynamic": ("FLOAT", {"default": 6.0, "min": 1.0, "max": 50.0, "step": 0.1}), + "creativity": ("FLOAT", {"default": 0.35, "min": 0.0, "max": 1.0, "step": 0.01}), + "resemblance": ("FLOAT", {"default": 0.6, "min": 0.0, "max": 3.0, "step": 0.01}), + "tiling_width": ([16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 256], {"default": 112}), + "tiling_height": ([16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 256], {"default": 144}), + "num_inference_steps": ("INT", {"default": 18, "min": 1, "max": 100}), + "seed": ("INT", {"default": 1337, "min": 0, "max": 2147483647}), + "handfix": (["disabled", "hands_only", "image_and_hands"], {"default": "disabled"}), + "pattern": ("BOOLEAN", {"default": False}), + "sharpen": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 10.0, "step": 0.1}), + "downscaling": ("BOOLEAN", {"default": False}), + "downscaling_resolution": ("INT", {"default": 768, "min": 256, "max": 2048}), + "sd_model": (["epicrealism_naturalSinRC1VAE.safetensors [84d76a0328]", + "juggernaut_reborn.safetensors [338b85bc4f]", + "flat2DAnimerge_v45Sharp.safetensors"], {"default": "juggernaut_reborn.safetensors [338b85bc4f]"}), + "scheduler": (["DPM++ 2M Karras", "DPM++ SDE Karras", "DPM++ 2M SDE Exponential", + "DPM++ 2M SDE Karras", "Euler a", "Euler", "LMS", "Heun", "DPM2", + "DPM2 a", "DPM++ 2S a", "DPM++ 2M", "DPM++ SDE", "DPM++ 2M SDE", + "DPM++ 2M SDE Heun", "DPM++ 2M SDE Heun Karras", + "DPM++ 2M SDE Heun Exponential", "DPM++ 3M SDE", + "DPM++ 3M SDE Karras", "DPM++ 3M SDE Exponential", + "DPM fast", "DPM adaptive", "LMS Karras", "DPM2 Karras", + "DPM2 a Karras", "DPM++ 2S a Karras", "Restart", "DDIM", + "PLMS", "UniPC"], {"default": "DPM++ 3M SDE Karras"}), } } @@ -37,7 +60,7 @@ Nodes from https://comflowy.com: - Output: Returns the upscaled image. """ - def upscale(self, image, scale_factor, model): + def upscale(self, image, scale_factor, dynamic, creativity, resemblance, tiling_width, tiling_height, num_inference_steps, seed,handfix=None, pattern=False, sharpen=0, downscaling=False,downscaling_resolution=768, sd_model=None, scheduler=None): api_key = load_api_key() if not api_key: @@ -45,7 +68,7 @@ Nodes from https://comflowy.com: logger.error(error_msg) raise ValueError(error_msg) - logger.info(f"Starting image upscale request. scale_factor: {scale_factor}, model: {model}") + logger.info(f"Starting image upscale request. scale_factor: {scale_factor}") # Process input image if isinstance(image, torch.Tensor): @@ -74,14 +97,28 @@ Nodes from https://comflowy.com: img_str = base64.b64encode(buffered.getvalue()).decode() try: - # Build the URL for the API request + # Build URL for API request using API_HOST response = requests.post( - f"{API_HOST}/api/open/v0/upscale", + f"{API_HOST}/api/open/v0/flowy", headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}, json={ "image": f"data:image/jpeg;base64,{img_str}", "scale_factor": scale_factor, - "model": model + "dynamic": dynamic, + "creativity": creativity, + "resemblance": resemblance, + "tiling_width": tiling_width, + "tiling_height": tiling_height, + "num_inference_steps": num_inference_steps, + "seed": seed, + "handfix": handfix, + "pattern": pattern, + "sharpen": sharpen, + "downscaling": downscaling, + "downscaling_resolution": downscaling_resolution, + "sd_model": sd_model, + "scheduler": scheduler, + "model_type": "clarityupscaler", } ) response.raise_for_status() @@ -94,22 +131,22 @@ Nodes from https://comflowy.com: logger.error(f"API request failed. Response content: {json.dumps(result, indent=2)}") raise Exception(f"API request failed. Response content: {json.dumps(result, indent=2)}") - output_url = result.get('data', {}).get('output', [None])[0] - if not output_url: + output_url = result.get('data', {}).get('output') + if not output_url or not isinstance(output_url, str): logger.error(f"Complete API response: {json.dumps(result, indent=2)}") - raise Exception(f"Unable to get valid output image URL. API response does not have expected data structure. Complete response: {json.dumps(result, indent=2)}") + raise Exception(f"Unable to get valid output image URL. API response doesn't have expected data structure. Complete response: {json.dumps(result, indent=2)}") - logger.info(f"Obtained output URL: {output_url}") + logger.info(f"Received output URL: {output_url}") - # Verify URL is accessible + # Verify if URL is accessible try: url_check = requests.head(output_url) url_check.raise_for_status() except requests.RequestException as e: - logger.error(f"Unable to access output URL: {str(e)}") - raise Exception(f"Unable to access output URL: {str(e)}") + logger.error(f"Cannot access output URL: {str(e)}") + raise Exception(f"Cannot access output URL: {str(e)}") - # Add delay, wait for Replicate to process + # Add delay to wait for Replicate processing time.sleep(10) img_response = requests.get(output_url, stream=True) @@ -118,10 +155,10 @@ Nodes from https://comflowy.com: # Convert image data to PIL Image img = Image.open(img_response.raw) - # Convert image data to numpy array + # Convert to numpy array img_np = np.array(img) - # Ensure image is 3 channel RGB + # Ensure image has 3 RGB channels if len(img_np.shape) == 2: # Grayscale image img_np = np.stack([img_np] * 3, axis=-1) elif img_np.shape[-1] == 4: # RGBA image @@ -130,7 +167,7 @@ Nodes from https://comflowy.com: # Convert to float32 and normalize to 0-1 range img_np = img_np.astype(np.float32) / 255.0 - # Convert to torch tensor, ensuring shape is [B,H,W,C] + # Convert to torch tensor, ensure shape is [B,H,W,C] img_tensor = torch.from_numpy(img_np).unsqueeze(0) # Add batch dimension logger.info(f"Image processing completed. Output tensor shape: {img_tensor.shape}") @@ -140,9 +177,9 @@ Nodes from https://comflowy.com: return (img_tensor,) except Exception as e: - error_msg = f"Error during image upscale: {str(e)}" + error_msg = f"Error during upscaling: {str(e)}" logger.error(error_msg) logger.exception("Detailed error information:") - # Return an error marked image, ensuring shape is [B,H,W,C] + # Return an error marker image, ensure shape is [B,H,W,C] error_image = torch.zeros((1, 100, 400, 3), dtype=torch.float32) return (error_image,) diff --git a/flowy/nodes_flux.py b/flowy/nodes_flux.py index 216675d..0c27ac3 100644 --- a/flowy/nodes_flux.py +++ b/flowy/nodes_flux.py @@ -7,8 +7,7 @@ import torch import numpy as np import logging import json -from .types import STRING, INT, API_HOST, SAFETY_TOLERANCE, BOOLEAN -from .utils import logger, get_nested_value +from .types import STRING, INT, SAFETY_TOLERANCE, BOOLEAN, get_api_host from .api_key_manager import load_api_key logger = logging.getLogger(__name__) @@ -60,7 +59,7 @@ Nodes from https://comflowy.com: def generate(self, prompt, version, aspect_ratio, height, width, seed, prompt_upsampling, safety_tolerance, output_quality): api_key = load_api_key() - + API_HOST = get_api_host() if not api_key: error_msg = "API Key is not set. Please use the 'Comflowy Set API Key' node to set a global API Key before using this node." logger.error(error_msg) @@ -70,7 +69,7 @@ Nodes from https://comflowy.com: try: response = requests.post( - f"{API_HOST}/api/open/v0/flux", + f"{API_HOST}/api/open/v0/flowy", headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}, json={ "prompt": prompt, @@ -82,6 +81,7 @@ Nodes from https://comflowy.com: "prompt_upsampling": prompt_upsampling, "safety_tolerance": safety_tolerance, "output_quality": output_quality, + "model_type": "flux", } ) response.raise_for_status() @@ -97,11 +97,11 @@ Nodes from https://comflowy.com: output_url = result.get('data', {}).get('output') if not output_url or not isinstance(output_url, str): logger.error(f"Complete API response: {json.dumps(result, indent=2)}") - raise Exception(f"Unable to get valid output image URL. API response does not have expected data structure. Complete response: {json.dumps(result, indent=2)}") + raise Exception(f"Unable to get valid output image URL. API response doesn't have expected data structure. Complete response: {json.dumps(result, indent=2)}") logger.info(f"Obtained output URL: {output_url}") - # Verify URL is accessible + # Verify if URL is accessible try: url_check = requests.head(output_url) url_check.raise_for_status() @@ -109,7 +109,7 @@ Nodes from https://comflowy.com: logger.error(f"Unable to access output URL: {str(e)}") raise Exception(f"Unable to access output URL: {str(e)}") - # Add delay, wait for Replicate to process + # Add delay to wait for Replicate processing time.sleep(10) img_response = requests.get(output_url, stream=True) @@ -121,7 +121,7 @@ Nodes from https://comflowy.com: # Convert to numpy array img_np = np.array(img) - # Ensure image is 3 channel RGB + # Ensure image has 3 RGB channels if len(img_np.shape) == 2: # Grayscale image img_np = np.stack([img_np] * 3, axis=-1) elif img_np.shape[-1] == 4: # RGBA image @@ -130,7 +130,7 @@ Nodes from https://comflowy.com: # Convert to float32 and normalize to 0-1 range img_np = img_np.astype(np.float32) / 255.0 - # Convert to torch tensor, ensuring shape is [B,H,W,C] + # Convert to torch tensor, ensure shape is [B,H,W,C] img_tensor = torch.from_numpy(img_np).unsqueeze(0) # Add batch dimension logger.info(f"Image processing completed. Output tensor shape: {img_tensor.shape}") @@ -141,6 +141,6 @@ Nodes from https://comflowy.com: error_msg = f"Error during image generation: {str(e)}" logger.error(error_msg) logger.exception("Detailed error information:") - # Return an error marked image, ensuring shape is [B,H,W,C] + # Return an error marker image, ensure shape is [B,H,W,C] error_image = torch.zeros((1, 100, 400, 3), dtype=torch.float32) return (error_image,) diff --git a/flowy/nodes_ideogram.py b/flowy/nodes_ideogram.py index c293d8a..d9bf9a8 100644 --- a/flowy/nodes_ideogram.py +++ b/flowy/nodes_ideogram.py @@ -56,7 +56,7 @@ Nodes from https://comflowy.com: try: response = requests.post( - f"{API_HOST}/api/open/v0/ideogram", + f"{API_HOST}/api/open/v0/flowy", headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}, json={ "prompt": prompt, @@ -67,6 +67,7 @@ Nodes from https://comflowy.com: "aspect_ratio": aspect_ratio, "magic_prompt_option": magic_prompt_option, "seed": seed, + "model_type": "ideogram", } ) response.raise_for_status() @@ -82,31 +83,28 @@ Nodes from https://comflowy.com: output_url = result.get('data', {}).get('output') if not output_url or not isinstance(output_url, str): logger.error(f"Complete API response: {json.dumps(result, indent=2)}") - raise Exception(f"Unable to get valid output image URL. API response does not have expected data structure. Complete response: {json.dumps(result, indent=2)}") + raise Exception(f"Unable to get valid output image URL. API response doesn't have expected data structure. Complete response: {json.dumps(result, indent=2)}") - logger.info(f"Obtained output URL: {output_url}") + logger.info(f"Received output URL: {output_url}") - # Verify URL is accessible + # Verify if URL is accessible try: url_check = requests.head(output_url) url_check.raise_for_status() except requests.RequestException as e: - logger.error(f"Unable to access output URL: {str(e)}") - raise Exception(f"Unable to access output URL: {str(e)}") + logger.error(f"Cannot access output URL: {str(e)}") + raise Exception(f"Cannot access output URL: {str(e)}") - # Add delay, wait for Replicate to process + # Add delay to wait for Replicate processing time.sleep(10) img_response = requests.get(output_url, stream=True) img_response.raise_for_status() - # Convert image data to PIL Image - img = Image.open(img_response.raw) - # Convert to numpy array img_np = np.array(img) - # Ensure image is 3 channel RGB + # Ensure image has 3 RGB channels if len(img_np.shape) == 2: # Grayscale image img_np = np.stack([img_np] * 3, axis=-1) elif img_np.shape[-1] == 4: # RGBA image @@ -115,7 +113,7 @@ Nodes from https://comflowy.com: # Convert to float32 and normalize to 0-1 range img_np = img_np.astype(np.float32) / 255.0 - # Convert to torch tensor, ensuring shape is [B,H,W,C] + # Convert to torch tensor, ensure shape is [B,H,W,C] img_tensor = torch.from_numpy(img_np).unsqueeze(0) # Add batch dimension logger.info(f"Image processing completed. Output tensor shape: {img_tensor.shape}") @@ -126,6 +124,6 @@ Nodes from https://comflowy.com: error_msg = f"Error during image generation: {str(e)}" logger.error(error_msg) logger.exception("Detailed error information:") - # Return an error marked image, ensuring shape is [B,H,W,C] + # Return an error marker image, ensure shape is [B,H,W,C] error_image = torch.zeros((1, 100, 400, 3), dtype=torch.float32) return (error_image,) diff --git a/flowy/types.py b/flowy/types.py index 56cf340..a99940f 100644 --- a/flowy/types.py +++ b/flowy/types.py @@ -1,7 +1,37 @@ +import json import sys +import os -API_HOST = "https://app.comflowy.com" +API_HOST = "https://app.comflowy.com" # API_HOST = "http://127.0.0.1:3000" + +custom_node_api_config_inited = False + +def init_custom_node_api_config_from_file(): + global API_HOST, PPT_TOKEN, RUN_ID, custom_node_api_config_inited + config_path = "/comfyui/custom_node_api_config.json" + + if os.path.exists(config_path): + try: + with open(config_path, "r") as f: + config = json.load(f) + API_HOST = config.get("domain", API_HOST) + PPT_TOKEN = config.get("ppt_token", PPT_TOKEN) + RUN_ID = config.get("run_id", RUN_ID) + custom_node_api_config_inited = True + print(f"Custom node API config initialized: API_HOST={API_HOST}, PPT_TOKEN={PPT_TOKEN}, RUN_ID={RUN_ID}") + except Exception as e: + print(f"Error reading custom node api config: {e}") + else: + print("Custom node API config file not found. Using default values.") + +init_custom_node_api_config_from_file() + +def get_api_host(): + if not custom_node_api_config_inited: + init_custom_node_api_config_from_file() + return API_HOST + FLOAT = ( "FLOAT", {"default": 1, "min": -sys.float_info.max, "max": sys.float_info.max, "step": 0.01}, @@ -50,3 +80,4 @@ class AnyType(str): return False any = AnyType("*") +