Comprehensive update: Image captioning improvements, audio inference, and node color standardization

- Fix image captioning widget targeting to prevent prompt field overwriting
- Add support for multiple images, custom prompts, and model selection in image captioning
- Add missing audio inference nodes to unified color scheme
- Add missing provider settings nodes to unified color scheme
- Fix tensor boolean evaluation error in image captioning
- Update image captioning to match SDK logic for inputImages/inputImage handling
- Separate prompt input from generated caption output fields
This commit is contained in:
Sirshendu Ganguly
2025-09-22 12:21:33 -04:00
parent c2e04ddc9a
commit 0d2e47de00
5 changed files with 102 additions and 18 deletions
Vendored
BIN
View File
Binary file not shown.
+7 -3
View File
@@ -44,11 +44,15 @@ function captionNodeHandler(msgEvent) {
const captionData = msgEvent.detail;
const captionText = captionData.captionText;
const captionNodeID = parseInt(captionData.nodeID);
if(captionData.success) {
const captionNode = app.graph.getNodeById(captionNodeID);
if(captionNode !== null || captionNode !== undefined) {
const captionInput = captionNode.widgets[1].inputEl;
captionInput.value = captionText;
if(captionNode !== null && captionNode !== undefined) {
// Find the imageCaption widget specifically
const imageCaptionWidget = captionNode.widgets.find(widget => widget.name === "imageCaption");
if(imageCaptionWidget && imageCaptionWidget.inputEl) {
imageCaptionWidget.inputEl.value = captionText;
}
}
}
return false;
+93 -14
View File
@@ -11,20 +11,40 @@ class imageCaptioning:
"label_on": "Enabled",
"label_off": "Disabled",
}),
"Image": ("IMAGE", {
"tooltip": "Specify The Image to be Captioned."
"prompt": ("STRING", {
"multiline": True,
"default": "Describe this image in detail",
"placeholder": "Enter the prompt for image captioning. You can provide multiple prompts separated by newlines.",
"tooltip": "The prompt(s) to guide the image captioning. Multiple prompts can be provided, each on a new line."
}),
},
"optional": {
"Image Description": ("STRING", {
"inputImages": ("IMAGE", {
"tooltip": "Connect multiple Load Image nodes here to caption multiple images at once."
}),
"inputImage": ("IMAGE", {
"tooltip": "Connect a single Load Image node here for convenience. If inputImages is provided, this will be ignored."
}),
"model": ("STRING", {
"default": "",
"placeholder": "Leave empty for default model (runware:150@1)",
"tooltip": "Optional: Specify the AIR model ID (e.g., runware:150@1, runware:150@2). Leave empty to use the default model."
}),
"template": ("STRING", {
"default": "",
"placeholder": "Optional template for structured output",
"tooltip": "Optional template to structure the caption output."
}),
"imageCaption": ("STRING", {
"multiline": True,
"placeholder": "You Don't Have to write Anything here.\nThe Image Description Will Be Generated Automatically.",
"placeholder": "Generated image caption will appear here automatically.",
"tooltip": "This field will be automatically populated with the generated image caption."
}),
},
"hidden": { "node_id": "UNIQUE_ID" }
}
DESCRIPTION = "Image to text, also known as image captioning, allows you to obtain descriptive text prompts based on uploaded or previously generated images. This process is instrumental in generating textual descriptions that can be used to create additional images or provide detailed insights into visual content."
DESCRIPTION = "Advanced image captioning with support for multiple images, custom prompts, and model selection. Generate descriptive text from single or multiple images using customizable prompts and optional AIR models. Perfect for batch processing and structured output generation."
FUNCTION = "imageCaptioning"
RETURN_TYPES = ("STRING",)
@@ -40,16 +60,75 @@ class imageCaptioning:
return True
def imageCaptioning(self, **kwargs):
image = kwargs.get("Image")
genConfig = [
{
"taskType": "imageCaption",
"taskUUID": rwUtils.genRandUUID(),
"inputImage": rwUtils.convertTensor2IMG(image)
}
]
inputImages = kwargs.get("inputImages", None)
inputImage = kwargs.get("inputImage", None)
prompt = kwargs.get("prompt", "Describe this image in detail")
model = kwargs.get("model", "")
template = kwargs.get("template", "")
# Handle multiple prompts - split by newlines
prompt_list = [p.strip() for p in prompt.split('\n') if p.strip()]
if not prompt_list:
prompt_list = ["Describe this image in detail"]
# Determine which images to use (following SDK logic)
if inputImages is not None:
images_to_process = inputImages
elif inputImage is not None:
# Single image provided via inputImage - convert to array
images_to_process = [inputImage]
else:
raise Exception("Either inputImages or inputImage must be provided")
# Set inputImage to inputImages[0] if not already provided
actual_input_image = inputImage
if actual_input_image is None and len(images_to_process) > 0:
actual_input_image = images_to_process[0]
# Convert images to base64 format
converted_images = []
for img in images_to_process:
converted_images.append(rwUtils.convertTensor2IMG(img))
# Create a dictionary with mandatory parameters
task_params = {
"taskType": "imageCaption",
"taskUUID": rwUtils.genRandUUID(),
}
# Add either inputImage or inputImages, but not both (API requirement)
if len(converted_images) == 1:
# Single image - use inputImage parameter
task_params["inputImage"] = converted_images[0]
else:
# Multiple images - use inputImages parameter
task_params["inputImages"] = converted_images
# Add model parameter only if specified - backend handles default
if model and model.strip():
task_params["model"] = model.strip()
# Add template parameter if specified
if template and template.strip():
task_params["template"] = template.strip()
# When using template, do NOT include prompt parameter
else:
# Use the provided prompt when no template
task_params["prompt"] = prompt_list
# Send the task with all applicable parameters
genConfig = [task_params]
genResult = rwUtils.inferenecRequest(genConfig)
genText = genResult["data"][0]["text"]
print(genResult)
# Handle multiple results if multiple images were processed
if len(genResult["data"]) > 1:
# Multiple images - combine results
combined_text = "\n\n".join([item["text"] for item in genResult["data"]])
genText = combined_text
else:
# Single image
genText = genResult["data"][0]["text"]
rwUtils.sendImageCaption(genText, kwargs.get("node_id"))
return (genText, )
+1
View File
@@ -240,6 +240,7 @@ def sendImageCaption(captionText, nodeID):
"success": True,
"captionText": captionText,
"nodeID": nodeID,
"widgetName": "imageCaption", # Target the new imageCaption widget
},
)
File diff suppressed because one or more lines are too long