Added support for HeyGen Avatar

This commit is contained in:
Sirshendu Ganguly
2026-03-14 22:08:21 -04:00
parent 4c041f5478
commit a5f379ed67
9 changed files with 255 additions and 17 deletions
+8 -16
View File
@@ -125,12 +125,8 @@ class txt2vid:
"referenceVideos": ("RUNWAREREFERENCEVIDEOS", {
"tooltip": "Connect reference video files for video generation.",
}),
"speechVoice": ("STRING", {
"tooltip": "Voice for speech synthesis. Specify the voice to use for text-to-speech generation.",
}),
"speechText": ("STRING", {
"multiline": True,
"tooltip": "Text for speech synthesis. The text that will be converted to speech using the specified voice.",
"speech": ("RUNWAREVIDEOINFERENCESPEECHINPUT", {
"tooltip": "Connect a Runware Video Inference Speech Input node to set voice and text for speech synthesis.",
}),
"inputs": ("RUNWAREVIDEOINFERENCEINPUTS", {
"tooltip": "Connect a Runware Video Inference Inputs node to provide custom inputs like image, audio, mask, and parameters for OmniHuman 1.5 and other video models.",
@@ -178,8 +174,7 @@ class txt2vid:
referenceImages = kwargs.get("referenceImages", None)
inputAudios = kwargs.get("inputAudios", None)
referenceVideos = kwargs.get("referenceVideos", None)
speechVoice = kwargs.get("speechVoice", None)
speechText = kwargs.get("speechText", None)
speech = kwargs.get("speech", None)
inputs = kwargs.get("inputs", None)
safetyInputs = kwargs.get("safetyInputs", None)
videoAdvancedFeatureInputs = kwargs.get("videoAdvancedFeatureInputs", None)
@@ -300,14 +295,11 @@ class txt2vid:
genConfig[0]["referenceVideos"] = referenceVideos
print(f"[Debugging] Reference videos: {rwUtils.sanitize_for_logging(genConfig[0].get('referenceVideos', []))}")
# Add speech parameters if both voice and text are provided
if speechVoice and speechVoice.strip() != "" and speechText and speechText.strip() != "":
genConfig[0]["speech"] = {
"voice": speechVoice.strip(),
"text": speechText.strip()
}
print(f"[Debugging] Speech parameters: voice='{speechVoice.strip()}', text='{speechText.strip()[:50]}...'")
# Add speech parameters if provided from Runware Video Inference Speech Input node
if speech is not None and isinstance(speech, dict) and speech:
genConfig[0]["speech"] = speech
print(f"[Debugging] Speech parameters: {rwUtils.sanitize_for_logging(speech)}")
# Handle inputs - merge custom inputs from Video Inference Inputs node
if inputs is not None:
# Merge inputs from video inference inputs node
+15
View File
@@ -13,6 +13,10 @@ class videoInferenceInputs:
"Image": ("IMAGE", {
"tooltip": "Portrait image for video generation. This will be the main subject that will speak and move in the generated video."
}),
"Avatar": ("STRING", {
"default": "",
"tooltip": "HeyGen avatar ID for a photo avatar or video avatar. Mutually exclusive with image_url and image_asset_id.",
}),
"Frame Images": ("RUNWAREVIDEOINPUTSFRAMEIMAGES", {
"tooltip": "Connect the Runware Video Inputs Frame node to provide timeline-constrained frame images."
}),
@@ -34,6 +38,9 @@ class videoInferenceInputs:
"Frame": ("IMAGE", {
"tooltip": "Frame image for video generation. Connect a Load Image node to provide the frame image."
}),
"Background": ("IMAGE", {
"tooltip": "Background image for video generation. Connect a Load Image node to provide the background.",
}),
"References": ("RUNWAREVIDEOINPUTSREFERENCEIMAGES", {
"tooltip": "Connect the Video Inputs References node to provide reference images."
}),
@@ -71,15 +78,20 @@ class videoInferenceInputs:
video = kwargs.get("Video", None)
mask = kwargs.get("Mask", None)
frame = kwargs.get("Frame", None)
background = kwargs.get("Background", None)
frameImages = kwargs.get("Frame Images", None)
references = kwargs.get("References", None)
referenceVideos = kwargs.get("Reference Videos", None)
referenceVoices = kwargs.get("Reference Voices", None)
draftId = kwargs.get("draftId", "")
videoId = kwargs.get("videoId", "")
avatar = kwargs.get("Avatar", "")
inputs = {}
if avatar is not None and avatar.strip() != "":
inputs["avatar"] = avatar.strip()
if image is not None:
inputs["image"] = rwUtils.convertTensor2IMG(image)
@@ -112,6 +124,9 @@ class videoInferenceInputs:
if frame is not None:
inputs["frame"] = rwUtils.convertTensor2IMG(frame)
if background is not None:
inputs["background"] = rwUtils.convertTensor2IMG(background)
if frameImages is not None and len(frameImages) > 0:
inputs["frameImages"] = frameImages
+102
View File
@@ -0,0 +1,102 @@
"""
Runware Video Inference Speech Input Node.
Provides voice and text for speech synthesis; connect to Runware Video Inference speech input.
"""
from typing import Any, Dict, Tuple
class RunwareVideoInferenceSpeechInput:
"""Runware Video Inference Speech Input Node"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {},
"optional": {
"useVoice": ("BOOLEAN", {
"tooltip": "Enable to include voice in speech synthesis.",
"default": False,
}),
"voice": ("STRING", {
"tooltip": "Voice ID for text-to-speech or speech-to-speech. Required when text script is provided. Only used when 'Use Voice' is enabled.",
"default": "",
}),
"useText": ("BOOLEAN", {
"tooltip": "Enable to include text in speech synthesis.",
"default": False,
}),
"text": ("STRING", {
"multiline": True,
"tooltip": "Text script for the avatar to speak. Requires voice. Mutually exclusive with audio-driven input. Only used when 'Use Text' is enabled.",
"default": "",
}),
"useSpeed": ("BOOLEAN", {
"tooltip": "Enable to set voice playback speed multiplier.",
"default": False,
}),
"speed": ("FLOAT", {
"tooltip": "Voice playback speed multiplier (0.5 - 1.5). Only used when 'Use Speed' is enabled.",
"default": 1.0,
"min": 0.5,
"max": 1.5,
"step": 0.05,
}),
"usePitch": ("BOOLEAN", {
"tooltip": "Enable to set voice pitch adjustment in semitones.",
"default": False,
}),
"pitch": ("FLOAT", {
"tooltip": "Voice pitch adjustment in semitones (-50 to 50). Only used when 'Use Pitch' is enabled.",
"default": 0.0,
"min": -50.0,
"max": 50.0,
"step": 0.5,
}),
"useLanguage": ("BOOLEAN", {
"tooltip": "Enable to set locale or accent hint for multilingual voices.",
"default": False,
}),
"language": ("STRING", {
"tooltip": "Locale or accent hint for multilingual voices, e.g. en-US. Only used when 'Use Language' is enabled.",
"default": "",
}),
},
}
RETURN_TYPES: Tuple[str] = ("RUNWAREVIDEOINFERENCESPEECHINPUT",)
RETURN_NAMES = ("speech",)
FUNCTION = "createSpeech"
CATEGORY = "Runware"
DESCRIPTION = (
"Configure speech synthesis for Runware Video Inference (voice and text). "
"Connect to Runware Video Inference speech input. Both voice and text must be set for speech to be included."
)
def createSpeech(self, **kwargs) -> tuple:
"""Build speech dict for genConfig[0]['speech']."""
speech: Dict[str, Any] = {}
if kwargs.get("useVoice"):
speech["voice"] = kwargs.get("voice")
if kwargs.get("useText"):
speech["text"] = kwargs.get("text")
if kwargs.get("useSpeed"):
speech["speed"] = float(kwargs.get("speed", 1.0))
if kwargs.get("usePitch"):
speech["pitch"] = float(kwargs.get("pitch", 0.0))
if kwargs.get("useLanguage"):
lang = (kwargs.get("language") or "").strip()
if lang:
speech["language"] = lang
return (speech or None,)
NODE_CLASS_MAPPINGS = {
"RunwareVideoInferenceSpeechInput": RunwareVideoInferenceSpeechInput,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"RunwareVideoInferenceSpeechInput": "Runware Video Inference Speech Input",
}
+10
View File
@@ -109,6 +109,9 @@ class videoModelSearch:
"creatify:aurora@fast (Creatify Aurora Avatar Model API (720p))",
"creatify:aurora@0 (Creatify Aurora Avatar Model API (720p))",
],
"HeyGen": [
"heygen:avatar@4 (HeyGen Avatar IV)",
],
"Hunyuan": [
"runware:hunyuanvideo@1.5 (HunyuanVideo-1.5)",
],
@@ -248,6 +251,9 @@ class videoModelSearch:
# Pruna Models (720p)
"prunaai:p-video@0": {"width": 1280, "height": 720},
# HeyGen Models (Model ID: heygen-avatar-iv)
"heygen:avatar@4": {"width": 1280, "height": 720},
}
# Model resolutions mapping
@@ -372,6 +378,9 @@ class videoModelSearch:
# Pruna Models
"prunaai:p-video@0": "720p",
# HeyGen Models
"heygen:avatar@4": "720p",
}
MODEL_ARCHITECTURES = [
@@ -391,6 +400,7 @@ class videoModelSearch:
"Sync",
"Bria",
"Creatify",
"HeyGen",
"Hunyuan",
"Kandinsky",
"xAI",
+38
View File
@@ -44,6 +44,32 @@ class RunwareVideoSettings:
"label_on": "Enabled",
"label_off": "Disabled",
}),
"useBackgroundColor": ("BOOLEAN", {
"tooltip": "Enable to set background color. Required when background.type = color.",
"default": False,
}),
"backgroundColor": ("STRING", {
"tooltip": "Hex color code (e.g. #ff0000). Required when background.type = color. Only used when 'Use Background Color' is enabled.",
"default": "",
}),
"useRemoveBackground": ("BOOLEAN", {
"tooltip": "Enable to remove the avatar background. Video avatars must be trained with matting enabled.",
"default": False,
}),
"removeBackground": ("BOOLEAN", {
"tooltip": "Remove the avatar background. Only used when 'Use Remove Background' is enabled.",
"default": False,
"label_on": "Enabled",
"label_off": "Disabled",
}),
"useExpressiveness": ("BOOLEAN", {
"tooltip": "Enable to set avatar expressiveness level. Applies to photo avatars only.",
"default": False,
}),
"expressiveness": (["low", "medium", "high"], {
"tooltip": "Avatar expressiveness level. Applies to photo avatars only. Only used when 'Use Expressiveness' is enabled.",
"default": "low",
}),
}
}
@@ -61,6 +87,12 @@ class RunwareVideoSettings:
audio = kwargs.get("audio", True)
use_prompt_upsampling = kwargs.get("usePromptUpsampling", True)
prompt_upsampling = kwargs.get("promptUpsampling", True)
use_background_color = kwargs.get("useBackgroundColor", False)
background_color = (kwargs.get("backgroundColor") or "").strip()
use_remove_background = kwargs.get("useRemoveBackground", False)
remove_background = kwargs.get("removeBackground", False)
use_expressiveness = kwargs.get("useExpressiveness", False)
expressiveness = kwargs.get("expressiveness", "low")
settings: Dict[str, Any] = {}
@@ -70,6 +102,12 @@ class RunwareVideoSettings:
settings["audio"] = bool(audio)
if use_prompt_upsampling:
settings["promptUpsampling"] = bool(prompt_upsampling)
if use_background_color and background_color:
settings["backgroundColor"] = background_color
if use_remove_background:
settings["removeBackground"] = bool(remove_background)
if use_expressiveness:
settings["expressiveness"] = expressiveness
return (settings,)