feat: update external image node to have default value
This commit is contained in:
		
							parent
							
								
									6ed468d7d4
								
							
						
					
					
						commit
						bf00580562
					
				@ -21,8 +21,9 @@ class ComfyUIDeployExternalImage:
 | 
				
			|||||||
                ),
 | 
					                ),
 | 
				
			||||||
                "description": (
 | 
					                "description": (
 | 
				
			||||||
                    "STRING",
 | 
					                    "STRING",
 | 
				
			||||||
                    {"multiline": True, "default": ""},
 | 
					                    {"multiline": False, "default": ""},
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
 | 
					                "default_value_url": ("STRING", {"image_preview": True, "default": ""}),
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -33,31 +34,43 @@ class ComfyUIDeployExternalImage:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    CATEGORY = "image"
 | 
					    CATEGORY = "image"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def run(self, input_id, default_value=None, display_name=None, description=None):
 | 
					    def run(self, input_id, default_value=None, display_name=None, description=None, default_value_url=None):
 | 
				
			||||||
        image = default_value
 | 
					        image = default_value
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        # Try both input_id and default_value_url
 | 
				
			||||||
 | 
					        urls_to_try = [url for url in [input_id, default_value_url] if url]
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        print(default_value_url)
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        for url in urls_to_try:
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
            if input_id.startswith('http'):
 | 
					                if url.startswith('http'):
 | 
				
			||||||
                    import requests
 | 
					                    import requests
 | 
				
			||||||
                    from io import BytesIO
 | 
					                    from io import BytesIO
 | 
				
			||||||
                print("Fetching image from url: ", input_id)
 | 
					                    print(f"Fetching image from url: {url}")
 | 
				
			||||||
                response = requests.get(input_id)
 | 
					                    response = requests.get(url)
 | 
				
			||||||
                    image = Image.open(BytesIO(response.content))
 | 
					                    image = Image.open(BytesIO(response.content))
 | 
				
			||||||
            elif input_id.startswith('data:image/png;base64,') or input_id.startswith('data:image/jpeg;base64,') or input_id.startswith('data:image/jpg;base64,'):
 | 
					                    break
 | 
				
			||||||
 | 
					                elif url.startswith(('data:image/png;base64,', 'data:image/jpeg;base64,', 'data:image/jpg;base64,')):
 | 
				
			||||||
                    import base64
 | 
					                    import base64
 | 
				
			||||||
                    from io import BytesIO
 | 
					                    from io import BytesIO
 | 
				
			||||||
                    print("Decoding base64 image")
 | 
					                    print("Decoding base64 image")
 | 
				
			||||||
                base64_image = input_id[input_id.find(",")+1:]
 | 
					                    base64_image = url[url.find(",")+1:]
 | 
				
			||||||
                    decoded_image = base64.b64decode(base64_image)
 | 
					                    decoded_image = base64.b64decode(base64_image)
 | 
				
			||||||
                    image = Image.open(BytesIO(decoded_image))
 | 
					                    image = Image.open(BytesIO(decoded_image))
 | 
				
			||||||
            else:
 | 
					                    break
 | 
				
			||||||
                raise ValueError("Invalid image url provided.")
 | 
					            except:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 | 
					        if image is not None:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
                image = ImageOps.exif_transpose(image)
 | 
					                image = ImageOps.exif_transpose(image)
 | 
				
			||||||
                image = image.convert("RGB")
 | 
					                image = image.convert("RGB")
 | 
				
			||||||
                image = np.array(image).astype(np.float32) / 255.0
 | 
					                image = np.array(image).astype(np.float32) / 255.0
 | 
				
			||||||
                image = torch.from_numpy(image)[None,]
 | 
					                image = torch.from_numpy(image)[None,]
 | 
				
			||||||
            return [image]
 | 
					 | 
				
			||||||
            except:
 | 
					            except:
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
        return [image]
 | 
					        return [image]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -53,9 +53,9 @@ function sendEventToCD(event, data) {
 | 
				
			|||||||
function sendDirectEventToCD(event, data) {
 | 
					function sendDirectEventToCD(event, data) {
 | 
				
			||||||
  const message = {
 | 
					  const message = {
 | 
				
			||||||
    type: event,
 | 
					    type: event,
 | 
				
			||||||
    data: data
 | 
					    data: data,
 | 
				
			||||||
  }
 | 
					  };
 | 
				
			||||||
  window.parent.postMessage(message, '*')
 | 
					  window.parent.postMessage(message, "*");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function dispatchAPIEventData(data) {
 | 
					function dispatchAPIEventData(data) {
 | 
				
			||||||
@ -494,6 +494,13 @@ const ext = {
 | 
				
			|||||||
      return r;
 | 
					      return r;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (
 | 
				
			||||||
 | 
					      nodeData?.input?.optional?.default_value_url?.[1]?.image_preview === true
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					      nodeData.input.optional.default_value_url = ["IMAGEPREVIEW"];
 | 
				
			||||||
 | 
					      console.log(nodeData.input.optional.default_value_url);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // const origonNodeCreated = nodeType.prototype.onNodeCreated;
 | 
					    // const origonNodeCreated = nodeType.prototype.onNodeCreated;
 | 
				
			||||||
    // nodeType.prototype.onNodeCreated = function () {
 | 
					    // nodeType.prototype.onNodeCreated = function () {
 | 
				
			||||||
    //   const r = origonNodeCreated
 | 
					    //   const r = origonNodeCreated
 | 
				
			||||||
@ -620,6 +627,78 @@ const ext = {
 | 
				
			|||||||
    ComfyDeploy.category = "deploy";
 | 
					    ComfyDeploy.category = "deploy";
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getCustomWidgets() {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      IMAGEPREVIEW(node, inputName, inputData) {
 | 
				
			||||||
 | 
					        // Find or create the URL input widget
 | 
				
			||||||
 | 
					        const urlWidget = node.addWidget(
 | 
				
			||||||
 | 
					          "string",
 | 
				
			||||||
 | 
					          inputName,
 | 
				
			||||||
 | 
					          /* value=*/ "",
 | 
				
			||||||
 | 
					          () => {},
 | 
				
			||||||
 | 
					          { serialize: true },
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const buttonWidget = node.addWidget(
 | 
				
			||||||
 | 
					          "button",
 | 
				
			||||||
 | 
					          "Open Assets Browser",
 | 
				
			||||||
 | 
					          /* value=*/ "",
 | 
				
			||||||
 | 
					          () => {
 | 
				
			||||||
 | 
					            sendEventToCD("assets", {
 | 
				
			||||||
 | 
					              node: node.id,
 | 
				
			||||||
 | 
					              inputName: inputName,
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            // console.log("load image");
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          { serialize: false },
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        console.log(node.widgets);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        console.log("urlWidget", urlWidget);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Add image preview functionality
 | 
				
			||||||
 | 
					        function showImage(url) {
 | 
				
			||||||
 | 
					          const img = new Image();
 | 
				
			||||||
 | 
					          img.onload = () => {
 | 
				
			||||||
 | 
					            node.imgs = [img];
 | 
				
			||||||
 | 
					            app.graph.setDirtyCanvas(true);
 | 
				
			||||||
 | 
					            node.setSizeForImage?.();
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          img.onerror = () => {
 | 
				
			||||||
 | 
					            node.imgs = [];
 | 
				
			||||||
 | 
					            app.graph.setDirtyCanvas(true);
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          img.src = url;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Set up URL widget value handling
 | 
				
			||||||
 | 
					        let default_value = urlWidget.value;
 | 
				
			||||||
 | 
					        Object.defineProperty(urlWidget, "value", {
 | 
				
			||||||
 | 
					          set: function (value) {
 | 
				
			||||||
 | 
					            this._real_value = value;
 | 
				
			||||||
 | 
					            // Preview image when URL changes
 | 
				
			||||||
 | 
					            if (value) {
 | 
				
			||||||
 | 
					              showImage(value);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          get: function () {
 | 
				
			||||||
 | 
					            return this._real_value || default_value;
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Show initial image if URL exists
 | 
				
			||||||
 | 
					        requestAnimationFrame(() => {
 | 
				
			||||||
 | 
					          if (urlWidget.value) {
 | 
				
			||||||
 | 
					            showImage(urlWidget.value);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return { widget: urlWidget };
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async setup() {
 | 
					  async setup() {
 | 
				
			||||||
    // const graphCanvas = document.getElementById("graph-canvas");
 | 
					    // const graphCanvas = document.getElementById("graph-canvas");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -661,8 +740,8 @@ const ext = {
 | 
				
			|||||||
            console.warn("api.handlePromptGenerated is not a function");
 | 
					            console.warn("api.handlePromptGenerated is not a function");
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          sendEventToCD("cd_plugin_onQueuePrompt", prompt);
 | 
					          sendEventToCD("cd_plugin_onQueuePrompt", prompt);
 | 
				
			||||||
        } else if (message.type === 'configure_queue_buttons') {
 | 
					        } else if (message.type === "configure_queue_buttons") {
 | 
				
			||||||
          addQueueButtons(message.data)
 | 
					          addQueueButtons(message.data);
 | 
				
			||||||
        } else if (message.type === "get_prompt") {
 | 
					        } else if (message.type === "get_prompt") {
 | 
				
			||||||
          const prompt = await app.graphToPrompt();
 | 
					          const prompt = await app.graphToPrompt();
 | 
				
			||||||
          sendEventToCD("cd_plugin_onGetPrompt", prompt);
 | 
					          sendEventToCD("cd_plugin_onGetPrompt", prompt);
 | 
				
			||||||
@ -1903,117 +1982,118 @@ api.fetchApi = async (route, options) => {
 | 
				
			|||||||
  return await orginal_fetch_api.call(api, route, options);
 | 
					  return await orginal_fetch_api.call(api, route, options);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Intercept window drag and drop events
 | 
					// Intercept window drag and drop events
 | 
				
			||||||
const originalDropHandler = document.ondrop
 | 
					const originalDropHandler = document.ondrop;
 | 
				
			||||||
document.ondrop = async (e) => {
 | 
					document.ondrop = async (e) => {
 | 
				
			||||||
  console.log('Drop event intercepted:', e)
 | 
					  console.log("Drop event intercepted:", e);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Prevent default browser behavior
 | 
					  // Prevent default browser behavior
 | 
				
			||||||
  e.preventDefault()
 | 
					  e.preventDefault();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Handle files if present
 | 
					  // Handle files if present
 | 
				
			||||||
  if (e.dataTransfer?.files?.length > 0) {
 | 
					  if (e.dataTransfer?.files?.length > 0) {
 | 
				
			||||||
    const files = Array.from(e.dataTransfer.files)
 | 
					    const files = Array.from(e.dataTransfer.files);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Send file data to parent directly as JSON
 | 
					    // Send file data to parent directly as JSON
 | 
				
			||||||
    sendDirectEventToCD('file_drop', {
 | 
					    sendDirectEventToCD("file_drop", {
 | 
				
			||||||
      files: files,
 | 
					      files: files,
 | 
				
			||||||
      x: e.clientX,
 | 
					      x: e.clientX,
 | 
				
			||||||
      y: e.clientY,
 | 
					      y: e.clientY,
 | 
				
			||||||
      timestamp: Date.now()
 | 
					      timestamp: Date.now(),
 | 
				
			||||||
    })
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Call original handler if exists
 | 
					  // Call original handler if exists
 | 
				
			||||||
  if (originalDropHandler) {
 | 
					  if (originalDropHandler) {
 | 
				
			||||||
    originalDropHandler(e)
 | 
					    originalDropHandler(e);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const originalDragEnterHandler = document.ondragenter
 | 
					const originalDragEnterHandler = document.ondragenter;
 | 
				
			||||||
document.ondragenter = (e) => {
 | 
					document.ondragenter = (e) => {
 | 
				
			||||||
  // Prevent default to allow drop
 | 
					  // Prevent default to allow drop
 | 
				
			||||||
  e.preventDefault()
 | 
					  e.preventDefault();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Send dragenter event to parent directly as JSON
 | 
					  // Send dragenter event to parent directly as JSON
 | 
				
			||||||
  sendDirectEventToCD('file_dragenter', {
 | 
					  sendDirectEventToCD("file_dragenter", {
 | 
				
			||||||
    x: e.clientX,
 | 
					    x: e.clientX,
 | 
				
			||||||
    y: e.clientY,
 | 
					    y: e.clientY,
 | 
				
			||||||
    timestamp: Date.now()
 | 
					    timestamp: Date.now(),
 | 
				
			||||||
  })
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (originalDragEnterHandler) {
 | 
					  if (originalDragEnterHandler) {
 | 
				
			||||||
    originalDragEnterHandler(e)
 | 
					    originalDragEnterHandler(e);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const originalDragLeaveHandler = document.ondragleave
 | 
					const originalDragLeaveHandler = document.ondragleave;
 | 
				
			||||||
document.ondragleave = (e) => {
 | 
					document.ondragleave = (e) => {
 | 
				
			||||||
  // Prevent default to allow drop
 | 
					  // Prevent default to allow drop
 | 
				
			||||||
  e.preventDefault()
 | 
					  e.preventDefault();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Send dragleave event to parent directly as JSON
 | 
					  // Send dragleave event to parent directly as JSON
 | 
				
			||||||
  sendDirectEventToCD('file_dragleave', {
 | 
					  sendDirectEventToCD("file_dragleave", {
 | 
				
			||||||
    x: e.clientX,
 | 
					    x: e.clientX,
 | 
				
			||||||
    y: e.clientY,
 | 
					    y: e.clientY,
 | 
				
			||||||
    timestamp: Date.now()
 | 
					    timestamp: Date.now(),
 | 
				
			||||||
  })
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (originalDragLeaveHandler) {
 | 
					  if (originalDragLeaveHandler) {
 | 
				
			||||||
    originalDragLeaveHandler(e)
 | 
					    originalDragLeaveHandler(e);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const originalDragOverHandler = document.ondragover 
 | 
					const originalDragOverHandler = document.ondragover;
 | 
				
			||||||
document.ondragover = (e) => {
 | 
					document.ondragover = (e) => {
 | 
				
			||||||
  // Prevent default to allow drop
 | 
					  // Prevent default to allow drop
 | 
				
			||||||
  e.preventDefault()
 | 
					  e.preventDefault();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Send dragover event to parent directly as JSON
 | 
					  // Send dragover event to parent directly as JSON
 | 
				
			||||||
  sendDirectEventToCD('file_dragover', {
 | 
					  sendDirectEventToCD("file_dragover", {
 | 
				
			||||||
    x: e.clientX,
 | 
					    x: e.clientX,
 | 
				
			||||||
    y: e.clientY,
 | 
					    y: e.clientY,
 | 
				
			||||||
    timestamp: Date.now()
 | 
					    timestamp: Date.now(),
 | 
				
			||||||
  })
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (originalDragOverHandler) {
 | 
					  if (originalDragOverHandler) {
 | 
				
			||||||
    originalDragOverHandler(e)
 | 
					    originalDragOverHandler(e);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Function to create a single button
 | 
					// Function to create a single button
 | 
				
			||||||
function createQueueButton(config) {
 | 
					function createQueueButton(config) {
 | 
				
			||||||
  const button = document.createElement('button')
 | 
					  const button = document.createElement("button");
 | 
				
			||||||
  button.id = `cd-button-${config.id}`
 | 
					  button.id = `cd-button-${config.id}`;
 | 
				
			||||||
  button.className = 'p-button p-component p-button-icon-only p-button-secondary p-button-text'
 | 
					  button.className =
 | 
				
			||||||
 | 
					    "p-button p-component p-button-icon-only p-button-secondary p-button-text";
 | 
				
			||||||
  button.innerHTML = `
 | 
					  button.innerHTML = `
 | 
				
			||||||
    <span class="p-button-icon pi ${config.icon}"></span>
 | 
					    <span class="p-button-icon pi ${config.icon}"></span>
 | 
				
			||||||
    <span class="p-button-label"> </span>
 | 
					    <span class="p-button-label"> </span>
 | 
				
			||||||
  `
 | 
					  `;
 | 
				
			||||||
  button.onclick = () => {
 | 
					  button.onclick = () => {
 | 
				
			||||||
    const eventData = typeof config.eventData === 'function' ? 
 | 
					    const eventData =
 | 
				
			||||||
      config.eventData() : 
 | 
					      typeof config.eventData === "function"
 | 
				
			||||||
      config.eventData || {}
 | 
					        ? config.eventData()
 | 
				
			||||||
    sendEventToCD(config.event, eventData)
 | 
					        : config.eventData || {};
 | 
				
			||||||
  }
 | 
					    sendEventToCD(config.event, eventData);
 | 
				
			||||||
  button.setAttribute('data-pd-tooltip', config.tooltip)
 | 
					  };
 | 
				
			||||||
  return button
 | 
					  button.setAttribute("data-pd-tooltip", config.tooltip);
 | 
				
			||||||
 | 
					  return button;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Function to add buttons to queue group
 | 
					// Function to add buttons to queue group
 | 
				
			||||||
function addQueueButtons(buttonConfigs = DEFAULT_BUTTONS) {
 | 
					function addQueueButtons(buttonConfigs = DEFAULT_BUTTONS) {
 | 
				
			||||||
  const queueButtonGroup = document.querySelector('.queue-button-group.flex')
 | 
					  const queueButtonGroup = document.querySelector(".queue-button-group.flex");
 | 
				
			||||||
  if (!queueButtonGroup) return
 | 
					  if (!queueButtonGroup) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Remove any existing CD buttons
 | 
					  // Remove any existing CD buttons
 | 
				
			||||||
  const existingButtons = queueButtonGroup.querySelectorAll('[id^="cd-button-"]')
 | 
					  const existingButtons =
 | 
				
			||||||
  existingButtons.forEach(button => button.remove())
 | 
					    queueButtonGroup.querySelectorAll('[id^="cd-button-"]');
 | 
				
			||||||
 | 
					  existingButtons.forEach((button) => button.remove());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Add new buttons
 | 
					  // Add new buttons
 | 
				
			||||||
  buttonConfigs.forEach(config => {
 | 
					  buttonConfigs.forEach((config) => {
 | 
				
			||||||
    const button = createQueueButton(config)
 | 
					    const button = createQueueButton(config);
 | 
				
			||||||
    queueButtonGroup.appendChild(button)
 | 
					    queueButtonGroup.appendChild(button);
 | 
				
			||||||
  })
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user