Merge pull request #45 from Runware/fix-Runway
Fix runway, positivePrompt( optional), add Safety
This commit is contained in:
@@ -1347,6 +1347,7 @@ function videoInferenceDimensionsHandler(videoInferenceNode) {
|
||||
"klingai:3@1": {width: 1280, height: 720}, "klingai:3@2": {width: 1920, height: 1080},
|
||||
"klingai:4@3": {width: 1280, height: 720}, "klingai:5@1": {width: 1280, height: 720},
|
||||
"klingai:5@2": {width: 1920, height: 1080}, "klingai:5@3": {width: 1920, height: 1080},
|
||||
"klingai:6@1": {width: 1920, height: 1080},
|
||||
"klingai:7@1": {width: 0, height: 0},
|
||||
"google:2@0": {width: 1280, height: 720}, "google:3@0": {width: 1280, height: 720},
|
||||
"google:3@1": {width: 1280, height: 720}, "google:3@2": {width: 1280, height: 720},
|
||||
@@ -1568,6 +1569,7 @@ function videoModelSearchFilterHandler(videoModelSearchNode) {
|
||||
"klingai:3@1 (KlingAI V1.6 Standard)", "klingai:3@2 (KlingAI V1.6 Pro)",
|
||||
"klingai:4@3 (KlingAI V2.1 Master)", "klingai:5@1 (KlingAI V2.1 Standard (I2V))",
|
||||
"klingai:5@2 (KlingAI V2.1 Pro (I2V))", "klingai:5@3 (KlingAI V2.0 Master)",
|
||||
"klingai:6@1 (KlingAI 2.5 Turbo Pro)",
|
||||
"klingai:7@1 (KlingAI Lip-Sync)",
|
||||
],
|
||||
"Veo": [
|
||||
@@ -1626,6 +1628,7 @@ function videoModelSearchFilterHandler(videoModelSearchNode) {
|
||||
"klingai:5@1": {"width": 1280, "height": 720},
|
||||
"klingai:5@2": {"width": 1920, "height": 1080},
|
||||
"klingai:5@3": {"width": 1920, "height": 1080},
|
||||
"klingai:6@1": {"width": 1920, "height": 1080},
|
||||
"klingai:7@1": {"width": 0, "height": 0},
|
||||
"google:2@0": {"width": 1280, "height": 720},
|
||||
"google:3@0": {"width": 1280, "height": 720},
|
||||
|
||||
@@ -50,7 +50,7 @@ class RunwareFrameImages:
|
||||
|
||||
def _createFrameData(self, image, position):
|
||||
"""Create frame data object from image and position"""
|
||||
imageData = rwUtils.convertTensor2IMG(image)
|
||||
imageData = rwUtils.convertTensor2IMGBase64Only(image)
|
||||
frameData = {"inputImage": imageData}
|
||||
|
||||
if position != "auto":
|
||||
|
||||
+30
-14
@@ -6,9 +6,6 @@ class txt2img:
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"Model": ("RUNWAREMODEL", {
|
||||
"tooltip": "Connect a Runware Model From Runware Model Node.",
|
||||
}),
|
||||
"positivePrompt": ("STRING", {
|
||||
"multiline": True,
|
||||
"placeholder": "Positive Prompt: a text instruction to guide the model on generating the image. It is usually a sentence or a paragraph that provides positive guidance for the task. This parameter is essential to shape the desired results.\n\nYou Can Press (Ctrl + Alt + E) To Enhance The Prompt!",
|
||||
@@ -19,6 +16,9 @@ class txt2img:
|
||||
"placeholder": "Negative Prompt: a text instruction to guide the model on generating the image. It is usually a sentence or a paragraph that provides negative guidance for the task. This parameter helps to avoid certain undesired results.",
|
||||
"tooltip": "Negative Prompt: a text instruction to guide the model on generating the image."
|
||||
}),
|
||||
"Model": ("RUNWAREMODEL", {
|
||||
"tooltip": "Connect a Runware Model From Runware Model Node.",
|
||||
}),
|
||||
"Multi Inference Mode": ("BOOLEAN", {
|
||||
"tooltip": "If Enabled the node will skip the image generation process and will only return the Runware Task Object to be used in the Multi Inference Node.",
|
||||
"default": False,
|
||||
@@ -175,25 +175,32 @@ class txt2img:
|
||||
"providerSettings": ("RUNWAREPROVIDERSETTINGS", {
|
||||
"tooltip": "Connect a Runware Provider Settings Node to configure provider-specific parameters.",
|
||||
}),
|
||||
"safetyInputs": ("RUNWARESAFETYINPUTS", {
|
||||
"tooltip": "Connect Runware Safety Inputs node to configure safety and content moderation settings.",
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(cls, positivePrompt, negativePrompt):
|
||||
if (positivePrompt is not None and (positivePrompt == "" or len(positivePrompt) < 3 or len(positivePrompt) > 2000)):
|
||||
raise Exception(
|
||||
"Positive Prompt Must Be Between 3 And 2000 characters!")
|
||||
if (negativePrompt is not None and negativePrompt != "" and (len(negativePrompt) < 3 or len(negativePrompt) > 2000)):
|
||||
raise Exception(
|
||||
"Negative Prompt Must Be Between 3 And 2000 characters!")
|
||||
return True
|
||||
|
||||
DESCRIPTION = "Generates Images Lightning Fast With Runware Image Inference Sonic Engine."
|
||||
FUNCTION = "generateImage"
|
||||
RETURN_TYPES = ("IMAGE", "RUNWARETASK")
|
||||
RETURN_NAMES = ("IMAGE", "RW-Task")
|
||||
CATEGORY = "Runware"
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(cls, **kwargs):
|
||||
positivePrompt = kwargs.get("positivePrompt", "")
|
||||
negativePrompt = kwargs.get("negativePrompt", "")
|
||||
|
||||
# Only validate positivePrompt length if it's provided
|
||||
if positivePrompt and len(positivePrompt) > 2000:
|
||||
return "Positive Prompt is too long. Maximum length is 2000 characters."
|
||||
|
||||
if negativePrompt and len(negativePrompt) > 2000:
|
||||
return "Negative Prompt is too long. Maximum length is 2000 characters."
|
||||
|
||||
return True
|
||||
|
||||
def generateImage(self, **kwargs):
|
||||
runwareModel = kwargs.get("Model")
|
||||
positivePrompt = kwargs.get("positivePrompt")
|
||||
@@ -211,6 +218,7 @@ class txt2img:
|
||||
referenceImages = kwargs.get("referenceImages", None)
|
||||
inputs = kwargs.get("inputs", None)
|
||||
providerSettings = kwargs.get("providerSettings", None)
|
||||
safetyInputs = kwargs.get("safetyInputs", None)
|
||||
seedImage = kwargs.get("seedImage", None)
|
||||
seedImageStrength = kwargs.get("strength", 0.8)
|
||||
maskImage = kwargs.get("maskImage", None)
|
||||
@@ -240,7 +248,6 @@ class txt2img:
|
||||
{
|
||||
"taskType": "imageInference",
|
||||
"taskUUID": rwUtils.genRandUUID(),
|
||||
"positivePrompt": positivePrompt,
|
||||
"model": runwareModel,
|
||||
"outputType": "base64Data",
|
||||
"outputFormat": outputFormat,
|
||||
@@ -248,6 +255,11 @@ class txt2img:
|
||||
"numberResults": batchSize,
|
||||
}
|
||||
]
|
||||
|
||||
# Add positivePrompt only if provided
|
||||
if positivePrompt is not None and positivePrompt != "":
|
||||
genConfig[0]["positivePrompt"] = positivePrompt
|
||||
|
||||
|
||||
# For Debugging Purposes Only
|
||||
print(f"[Debugging] Task UUID: {genConfig[0]['taskUUID']}")
|
||||
@@ -344,6 +356,10 @@ class txt2img:
|
||||
# If it's already in the correct format, use it directly
|
||||
genConfig[0]["providerSettings"] = providerSettings
|
||||
|
||||
# Add safety inputs if provided
|
||||
if safetyInputs is not None and isinstance(safetyInputs, dict) and len(safetyInputs) > 0:
|
||||
genConfig[0]["safety"] = safetyInputs
|
||||
|
||||
if (multiInferenceMode):
|
||||
return (None, genConfig)
|
||||
else:
|
||||
|
||||
@@ -467,6 +467,20 @@ def convertTensor2IMG(tensorImage):
|
||||
|
||||
|
||||
|
||||
def convertTensor2IMGBase64Only(tensorImage):
|
||||
"""Convert tensor to base64 data URI without caching - for frame images"""
|
||||
imageNP = (tensorImage.squeeze().numpy() * 255).astype(np.uint8)
|
||||
image = Image.fromarray(imageNP)
|
||||
|
||||
with io.BytesIO() as buffer:
|
||||
image.save(buffer, format="PNG")
|
||||
imageRawData = buffer.getvalue()
|
||||
imgb64 = base64.b64encode(imageRawData).decode("utf-8")
|
||||
imgDataUri = f"data:image/png;base64,{imgb64}"
|
||||
|
||||
return imgDataUri
|
||||
|
||||
|
||||
def convertTensor2IMGForVideo(tensorImage):
|
||||
"""Convert tensor to image and force upload to get UUID for video frame images"""
|
||||
imageNP = (tensorImage.squeeze().numpy() * 255).astype(np.uint8)
|
||||
|
||||
@@ -49,8 +49,8 @@ class RunwareVideoInputsFrameImages:
|
||||
return (frameImages,)
|
||||
|
||||
def _createFrameEntry(self, image, frameLabel):
|
||||
imageData = rwUtils.convertTensor2IMG(image)
|
||||
entry = {"image": imageData}
|
||||
imageData = rwUtils.convertTensor2IMGBase64Only(image)
|
||||
entry = {"inputImage": imageData}
|
||||
|
||||
if isinstance(frameLabel, str) and frameLabel.strip() != "":
|
||||
if frameLabel.strip().isdigit():
|
||||
|
||||
@@ -14,6 +14,7 @@ class videoModelSearch:
|
||||
"klingai:5@1 (KlingAI V2.1 Standard (I2V))",
|
||||
"klingai:5@2 (KlingAI V2.1 Pro (I2V))",
|
||||
"klingai:5@3 (KlingAI V2.0 Master)",
|
||||
"klingai:6@1 (KlingAI 2.5 Turbo Pro)",
|
||||
"klingai:7@1 (KlingAI Lip-Sync)",
|
||||
],
|
||||
"Veo": [
|
||||
@@ -89,6 +90,7 @@ class videoModelSearch:
|
||||
"klingai:5@1": {"width": 1280, "height": 720},
|
||||
"klingai:5@2": {"width": 1920, "height": 1080},
|
||||
"klingai:5@3": {"width": 1920, "height": 1080},
|
||||
"klingai:6@1": {"width": 1920, "height": 1080},
|
||||
"klingai:7@1": {"width": 0, "height": 0},
|
||||
|
||||
# Veo Models
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user