Compare commits

..
Author SHA1 Message Date
EdwinWong 5c6defbe62 fix: add workflow data to extra data 2024-09-24 15:35:48 -07:00
bennykok aea456cba9 fix face loader extenal load 2024-09-21 10:51:51 -07:00
bennykok 8c5e5c4277 feat: add ComfyUIDeployExternalTextAny 2024-09-21 10:39:34 -07:00
bennykok 02430ee62d remove some logs 2024-09-20 18:10:04 -07:00
Fawaz Kadem 764a8fee82 Add new external deploy node for face models (#66) 2024-09-18 17:00:51 -07:00
5 changed files with 172 additions and 6 deletions
+108
View File
@@ -0,0 +1,108 @@
from PIL import Image, ImageOps
import numpy as np
import torch
import folder_paths
class AnyType(str):
def __ne__(self, __value: object) -> bool:
return False
WILDCARD = AnyType("*")
class ComfyUIDeployExternalFaceModel:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input_id": (
"STRING",
{"multiline": False, "default": "input_reactor_face_model"},
),
},
"optional": {
"default_face_model_name": (
"STRING",
{"multiline": False, "default": ""},
),
"face_model_save_name": ( # if `default_face_model_name` is a link to download a file, we will attempt to save it with this name
"STRING",
{"multiline": False, "default": ""},
),
"display_name": (
"STRING",
{"multiline": False, "default": ""},
),
"description": (
"STRING",
{"multiline": True, "default": ""},
),
"face_model_url": (
"STRING",
{"multiline": False, "default": ""},
),
},
}
RETURN_TYPES = (WILDCARD,)
RETURN_NAMES = ("path",)
FUNCTION = "run"
CATEGORY = "deploy"
def run(
self,
input_id,
default_face_model_name=None,
face_model_save_name=None,
display_name=None,
description=None,
face_model_url=None,
):
import requests
import os
import uuid
if face_model_url and face_model_url.startswith("http"):
if face_model_save_name:
existing_face_models = folder_paths.get_filename_list("reactor/faces")
# Check if face_model_save_name exists in the list
if face_model_save_name in existing_face_models:
print(f"using face model: {face_model_save_name}")
return (face_model_save_name,)
else:
face_model_save_name = str(uuid.uuid4()) + ".safetensors"
print(face_model_save_name)
print(folder_paths.folder_names_and_paths["reactor/faces"][0][0])
destination_path = os.path.join(
folder_paths.folder_names_and_paths["reactor/faces"][0][0],
face_model_save_name,
)
print(destination_path)
print(
"Downloading external face model - "
+ face_model_url
+ " to "
+ destination_path
)
response = requests.get(
face_model_url,
headers={"User-Agent": "Mozilla/5.0"},
allow_redirects=True,
)
with open(destination_path, "wb") as out_file:
out_file.write(response.content)
return (face_model_save_name,)
else:
print(f"using face model: {default_face_model_name}")
return (default_face_model_name,)
NODE_CLASS_MAPPINGS = {"ComfyUIDeployExternalFaceModel": ComfyUIDeployExternalFaceModel}
NODE_DISPLAY_NAME_MAPPINGS = {
"ComfyUIDeployExternalFaceModel": "External Face Model (ComfyUI Deploy)"
}
+46
View File
@@ -0,0 +1,46 @@
class AnyType(str):
def __ne__(self, __value: object) -> bool:
return False
WILDCARD = AnyType("*")
class ComfyUIDeployExternalTextAny:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input_id": (
"STRING",
{"multiline": False, "default": "input_text"},
),
},
"optional": {
"default_value": (
"STRING",
{"multiline": True, "default": ""},
),
"display_name": (
"STRING",
{"multiline": False, "default": ""},
),
"description": (
"STRING",
{"multiline": True, "default": ""},
),
}
}
RETURN_TYPES = (WILDCARD,)
RETURN_NAMES = ("text",)
FUNCTION = "run"
CATEGORY = "text"
def run(self, input_id, default_value=None, display_name=None, description=None):
return [default_value]
NODE_CLASS_MAPPINGS = {"ComfyUIDeployExternalTextAny": ComfyUIDeployExternalTextAny}
NODE_DISPLAY_NAME_MAPPINGS = {"ComfyUIDeployExternalTextAny": "External Text Any (ComfyUI Deploy)"}
+16 -6
View File
@@ -80,11 +80,11 @@ async def async_request_with_retry(method, url, disable_timeout=False, token=Non
request_start = time.time() request_start = time.time()
async with client_session.request(method, url, **kwargs) as response: async with client_session.request(method, url, **kwargs) as response:
request_end = time.time() request_end = time.time()
logger.info(f"Request attempt {attempt + 1} took {request_end - request_start:.2f} seconds") # logger.info(f"Request attempt {attempt + 1} took {request_end - request_start:.2f} seconds")
if response.status != 200: if response.status != 200:
error_body = await response.text() error_body = await response.text()
logger.error(f"Request failed with status {response.status} and body {error_body}") # logger.error(f"Request failed with status {response.status} and body {error_body}")
# raise Exception(f"Request failed with status {response.status}") # raise Exception(f"Request failed with status {response.status}")
response.raise_for_status() response.raise_for_status()
@@ -92,7 +92,7 @@ async def async_request_with_retry(method, url, disable_timeout=False, token=Non
await response.read() await response.read()
total_time = time.time() - start_time total_time = time.time() - start_time
logger.info(f"Request succeeded after {total_time:.2f} seconds (attempt {attempt + 1}/{max_retries})") # logger.info(f"Request succeeded after {total_time:.2f} seconds (attempt {attempt + 1}/{max_retries})")
return response return response
except asyncio.TimeoutError: except asyncio.TimeoutError:
logger.warning(f"Request timed out after {initial_timeout} seconds (attempt {attempt + 1}/{max_retries})") logger.warning(f"Request timed out after {initial_timeout} seconds (attempt {attempt + 1}/{max_retries})")
@@ -309,7 +309,7 @@ def apply_inputs_to_workflow(workflow_api: Any, inputs: Any, sid: str = None):
value['inputs']["input_id"] = new_value value['inputs']["input_id"] = new_value
# Fix for external text default value # Fix for external text default value
if (value["class_type"] == "ComfyUIDeployExternalText"): if (value["class_type"] == "ComfyUIDeployExternalText" or value["class_type"] == "ComfyUIDeployExternalTextAny"):
value['inputs']["default_value"] = new_value value['inputs']["default_value"] = new_value
if (value["class_type"] == "ComfyUIDeployExternalCheckpoint"): if (value["class_type"] == "ComfyUIDeployExternalCheckpoint"):
@@ -327,9 +327,13 @@ def apply_inputs_to_workflow(workflow_api: Any, inputs: Any, sid: str = None):
if value["class_type"] == "ComfyUIDeployExternalBoolean": if value["class_type"] == "ComfyUIDeployExternalBoolean":
value["inputs"]["default_value"] = new_value value["inputs"]["default_value"] = new_value
if value["class_type"] == "ComfyUIDeployExternalFaceModel":
value["inputs"]["face_model_url"] = new_value
def send_prompt(sid: str, inputs: StreamingPrompt): def send_prompt(sid: str, inputs: StreamingPrompt):
# workflow_api = inputs.workflow_api # workflow_api = inputs.workflow_api
workflow_api = copy.deepcopy(inputs.workflow_api) workflow_api = copy.deepcopy(inputs.workflow_api)
workflow = copy.deepcopy(inputs.workflow)
# Random seed # Random seed
apply_random_seed_to_workflow(workflow_api) apply_random_seed_to_workflow(workflow_api)
@@ -345,7 +349,8 @@ def send_prompt(sid: str, inputs: StreamingPrompt):
prompt = { prompt = {
"prompt": workflow_api, "prompt": workflow_api,
"client_id": sid, #"comfy_deploy_instance", #api.client_id "client_id": sid, #"comfy_deploy_instance", #api.client_id
"prompt_id": prompt_id "prompt_id": prompt_id,
"extra_data": {"extra_pnginfo": {"workflow": workflow}},
} }
try: try:
@@ -384,6 +389,7 @@ async def comfy_deploy_run(request):
# The prompt id generated from comfy deploy, can be None # The prompt id generated from comfy deploy, can be None
prompt_id = data.get("prompt_id") prompt_id = data.get("prompt_id")
inputs = data.get("inputs") inputs = data.get("inputs")
workflow = data.get("workflow")
# Now it handles directly in here # Now it handles directly in here
apply_random_seed_to_workflow(workflow_api) apply_random_seed_to_workflow(workflow_api)
@@ -393,6 +399,7 @@ async def comfy_deploy_run(request):
"prompt": workflow_api, "prompt": workflow_api,
"client_id": "comfy_deploy_instance", #api.client_id "client_id": "comfy_deploy_instance", #api.client_id
"prompt_id": prompt_id, "prompt_id": prompt_id,
"extra_data": {"extra_pnginfo": {"workflow": workflow}}
} }
prompt_metadata[prompt_id] = SimplePrompt( prompt_metadata[prompt_id] = SimplePrompt(
@@ -443,6 +450,7 @@ async def stream_prompt(data, token):
# The prompt id generated from comfy deploy, can be None # The prompt id generated from comfy deploy, can be None
prompt_id = data.get("prompt_id") prompt_id = data.get("prompt_id")
inputs = data.get("inputs") inputs = data.get("inputs")
workflow = data.get("workflow")
# Now it handles directly in here # Now it handles directly in here
apply_random_seed_to_workflow(workflow_api) apply_random_seed_to_workflow(workflow_api)
@@ -451,7 +459,8 @@ async def stream_prompt(data, token):
prompt = { prompt = {
"prompt": workflow_api, "prompt": workflow_api,
"client_id": "comfy_deploy_instance", #api.client_id "client_id": "comfy_deploy_instance", #api.client_id
"prompt_id": prompt_id "prompt_id": prompt_id,
"extra_data": {"extra_pnginfo": {"workflow": workflow}},
} }
prompt_metadata[prompt_id] = SimplePrompt( prompt_metadata[prompt_id] = SimplePrompt(
@@ -785,6 +794,7 @@ async def websocket_handler(request):
inputs={}, inputs={},
status_endpoint=status_endpoint, status_endpoint=status_endpoint,
file_upload_endpoint=request.rel_url.query.get('file_upload_endpoint', None), file_upload_endpoint=request.rel_url.query.get('file_upload_endpoint', None),
workflow=workflow["workflow"],
) )
await update_realtime_run_status(realtime_id, status_endpoint, Status.RUNNING) await update_realtime_run_status(realtime_id, status_endpoint, Status.RUNNING)
+1
View File
@@ -24,6 +24,7 @@ class StreamingPrompt(BaseModel):
running_prompt_ids: set[str] = set() running_prompt_ids: set[str] = set()
status_endpoint: Optional[str] status_endpoint: Optional[str]
file_upload_endpoint: Optional[str] file_upload_endpoint: Optional[str]
workflow: Any
class SimplePrompt(BaseModel): class SimplePrompt(BaseModel):
status_endpoint: Optional[str] status_endpoint: Optional[str]
+1
View File
@@ -6,4 +6,5 @@ export const customInputNodes: Record<string, string> = {
ComfyUIDeployExternalNumberInt: "integer", ComfyUIDeployExternalNumberInt: "integer",
ComfyUIDeployExternalLora: "string - (public lora download url)", ComfyUIDeployExternalLora: "string - (public lora download url)",
ComfyUIDeployExternalCheckpoint: "string - (public checkpoints download url)", ComfyUIDeployExternalCheckpoint: "string - (public checkpoints download url)",
ComfyUIDeployExternalFaceModel: "string - (public face model download url)",
}; };