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
+2
View File
@@ -30,6 +30,7 @@ from .modules.imageWatermarkAdvancedFeature import RunwareWatermarkAdvancedFeatu
from .modules.imageRegionalPromptingAdvancedFeature import RunwareRegionalPromptingAdvancedFeature
from .modules.imageRegionalPromptingAdvancedFeatureRegions import RunwareRegionalPromptingAdvancedFeatureRegions
from .modules.videoInference import txt2vid
from .modules.videoInferenceSpeechInput import RunwareVideoInferenceSpeechInput
from .modules.videoModelSearch import videoModelSearch
from .modules.videoSettings import RunwareVideoSettings
from .modules.frameImages import RunwareFrameImages
@@ -168,6 +169,7 @@ NODE_CLASS_MAPPINGS = {
"Runware Reference Videos": referenceVideos,
"Runware Reference Voices": referenceVoices,
"Runware Video Inference Inputs": videoInferenceInputs,
"Runware Video Inference Speech Input": RunwareVideoInferenceSpeechInput,
"Runware Video Inference Settings": RunwareVideoSettings,
"Runware Lightricks Provider Settings": RunwareLightricksProviderSettings,
"Runware MiniMax Provider Settings": RunwareMiniMaxProviderSettings,
+3 -1
View File
@@ -1,6 +1,6 @@
import { app } from "../../scripts/app.js";
import { api } from "../../scripts/api.js";
import { promptEnhanceHandler, syncDimensionsNodeHandler, searchNodeHandler, APIKeyHandler, captionNodeHandler, mediaUUIDHandler, save3DFilepathHandler, videoTranscriptionHandler, videoOutputsHandler, handleCustomErrors, videoInferenceDimensionsHandler, videoModelSearchFilterHandler, audioModelSearchFilterHandler, vectorizeModelSearchFilterHandler, vectorizeToggleHandler, useParameterToggleHandler, imageInferenceToggleHandler, imageInferenceAdvancedFeaturesToggleHandler, watermarkAdvancedFeatureToggleHandler, regionalPromptingRegionsToggleHandler, upscalerToggleHandler, videoUpscalerToggleHandler, audioInferenceToggleHandler, audioInferenceSpeechToggleHandler, audioSettingsToggleHandler, videoSettingsToggleHandler, acceleratorOptionsToggleHandler, bytedanceProviderSettingsToggleHandler, xaiProviderSettingsToggleHandler, viduProviderSettingsToggleHandler, sourcefulProviderSettingsToggleHandler, sourcefulProviderSettingsFontsToggleHandler, threeDInferenceToggleHandler, threeDInferenceSettingsToggleHandler, threeDInferenceSettingsLatToggleHandler, ultralyticsProviderSettingsToggleHandler, openaiProviderSettingsToggleHandler, lightricksProviderSettingsToggleHandler, klingProviderSettingsToggleHandler, lumaProviderSettingsToggleHandler, briaProviderSettingsToggleHandler, pixverseProviderSettingsToggleHandler, alibabaProviderSettingsToggleHandler, mireloProviderSettingsToggleHandler, googleProviderSettingsToggleHandler, syncProviderSettingsToggleHandler, syncSegmentToggleHandler, settingsToggleHandler, audioInputToggleHandler, speechInputToggleHandler, briaProviderMaskToggleHandler, wanAnimateAdvancedFeatureSettingsToggleHandler, videoAdvancedFeatureInputsToggleHandler, audioInferenceInputsToggleHandler } from "./utils.js";
import { promptEnhanceHandler, syncDimensionsNodeHandler, searchNodeHandler, APIKeyHandler, captionNodeHandler, mediaUUIDHandler, save3DFilepathHandler, videoTranscriptionHandler, videoOutputsHandler, handleCustomErrors, videoInferenceDimensionsHandler, videoModelSearchFilterHandler, audioModelSearchFilterHandler, vectorizeModelSearchFilterHandler, vectorizeToggleHandler, useParameterToggleHandler, imageInferenceToggleHandler, imageInferenceAdvancedFeaturesToggleHandler, watermarkAdvancedFeatureToggleHandler, videoInferenceSpeechInputToggleHandler, regionalPromptingRegionsToggleHandler, upscalerToggleHandler, videoUpscalerToggleHandler, audioInferenceToggleHandler, audioInferenceSpeechToggleHandler, audioSettingsToggleHandler, videoSettingsToggleHandler, acceleratorOptionsToggleHandler, bytedanceProviderSettingsToggleHandler, xaiProviderSettingsToggleHandler, viduProviderSettingsToggleHandler, sourcefulProviderSettingsToggleHandler, sourcefulProviderSettingsFontsToggleHandler, threeDInferenceToggleHandler, threeDInferenceSettingsToggleHandler, threeDInferenceSettingsLatToggleHandler, ultralyticsProviderSettingsToggleHandler, openaiProviderSettingsToggleHandler, lightricksProviderSettingsToggleHandler, klingProviderSettingsToggleHandler, lumaProviderSettingsToggleHandler, briaProviderSettingsToggleHandler, pixverseProviderSettingsToggleHandler, alibabaProviderSettingsToggleHandler, mireloProviderSettingsToggleHandler, googleProviderSettingsToggleHandler, syncProviderSettingsToggleHandler, syncSegmentToggleHandler, settingsToggleHandler, audioInputToggleHandler, speechInputToggleHandler, briaProviderMaskToggleHandler, wanAnimateAdvancedFeatureSettingsToggleHandler, videoAdvancedFeatureInputsToggleHandler, audioInferenceInputsToggleHandler } from "./utils.js";
import { RUNWARE_NODE_TYPES, RUNWARE_NODE_PROPS, SEARCH_TERMS } from "./types.js";
const nodeInitList = [];
@@ -82,6 +82,8 @@ app.registerExtension({
imageInferenceAdvancedFeaturesToggleHandler(node);
} else if(nodeClass === RUNWARE_NODE_TYPES.WATERMARKADVANCEDFEATURE) {
watermarkAdvancedFeatureToggleHandler(node);
} else if(nodeClass === RUNWARE_NODE_TYPES.VIDEOINFERENCESPEECHINPUT) {
videoInferenceSpeechInputToggleHandler(node);
} else if(nodeClass === RUNWARE_NODE_TYPES.REGIONALPROMPTINGADVFEATUREREGIONS) {
regionalPromptingRegionsToggleHandler(node);
} else if(nodeClass === RUNWARE_NODE_TYPES.AUDIOINFERENCESPEECH) {
+4
View File
@@ -102,6 +102,7 @@ const RUNWARE_NODE_TYPES = {
REFERENCEVIDEOS: "Runware Reference Videos",
REFERENCEVOICES: "Runware Reference Voices",
VIDEOINFERENCEINPUTS: "Runware Video Inference Inputs",
VIDEOINFERENCESPEECHINPUT: "Runware Video Inference Speech Input",
VIDEOSETTINGS: "Runware Video Inference Settings",
LIGHTRICKSPROVIDERSETTINGS: "Runware Lightricks Provider Settings",
KLINGPROVIDERSETTINGS: "Runware KlingAI Provider Settings",
@@ -300,6 +301,9 @@ const RUNWARE_NODE_PROPS = {
bgColor: DEFAULT_BGCOLOR,
colorModeOnly: true,
},
[RUNWARE_NODE_TYPES.VIDEOINFERENCESPEECHINPUT]: {
bgColor: DEFAULT_BGCOLOR,
},
[RUNWARE_NODE_TYPES.REGIONALPROMPTINGADVFEATURE]: {
bgColor: DEFAULT_BGCOLOR,
colorModeOnly: true,
+73
View File
@@ -1178,6 +1178,12 @@ function videoSettingsToggleHandler(settingsNode) {
const audioWidget = settingsNode.widgets.find(w => w && w.name === "audio");
const usePromptUpsamplingWidget = settingsNode.widgets.find(w => w && w.name === "usePromptUpsampling");
const promptUpsamplingWidget = settingsNode.widgets.find(w => w && w.name === "promptUpsampling");
const useBackgroundColorWidget = settingsNode.widgets.find(w => w && w.name === "useBackgroundColor");
const backgroundColorWidget = settingsNode.widgets.find(w => w && w.name === "backgroundColor");
const useRemoveBackgroundWidget = settingsNode.widgets.find(w => w && w.name === "useRemoveBackground");
const removeBackgroundWidget = settingsNode.widgets.find(w => w && w.name === "removeBackground");
const useExpressivenessWidget = settingsNode.widgets.find(w => w && w.name === "useExpressiveness");
const expressivenessWidget = settingsNode.widgets.find(w => w && w.name === "expressiveness");
function toggleWidgetState(useWidget, paramWidget, paramName) {
if (!useWidget || !paramWidget) return;
@@ -1198,6 +1204,9 @@ function videoSettingsToggleHandler(settingsNode) {
if (useDraftWidget && draftWidget) toggleWidgetState(useDraftWidget, draftWidget, "draft");
if (useAudioWidget && audioWidget) toggleWidgetState(useAudioWidget, audioWidget, "audio");
if (usePromptUpsamplingWidget && promptUpsamplingWidget) toggleWidgetState(usePromptUpsamplingWidget, promptUpsamplingWidget, "promptUpsampling");
if (useBackgroundColorWidget && backgroundColorWidget) toggleWidgetState(useBackgroundColorWidget, backgroundColorWidget, "backgroundColor");
if (useRemoveBackgroundWidget && removeBackgroundWidget) toggleWidgetState(useRemoveBackgroundWidget, removeBackgroundWidget, "removeBackground");
if (useExpressivenessWidget && expressivenessWidget) toggleWidgetState(useExpressivenessWidget, expressivenessWidget, "expressiveness");
}
function audioInferenceSpeechToggleHandler(speechNode) {
@@ -2350,6 +2359,9 @@ function videoModelSearchFilterHandler(videoModelSearchNode) {
"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)",
],
@@ -2449,6 +2461,7 @@ function videoModelSearchFilterHandler(videoModelSearchNode) {
"xai:grok-imagine@video": {"width": 480, "height": 480},
"veed:fabric@1.0": {"width": 1280, "height": 720},
"prunaai:p-video@0": {"width": 1280, "height": 720},
"heygen:avatar@4": {"width": 1280, "height": 720},
};
const MODEL_RESOLUTIONS = {
@@ -2533,6 +2546,7 @@ function videoModelSearchFilterHandler(videoModelSearchNode) {
"xai:grok-imagine@video": "480p",
"veed:fabric@1.0": "720p",
"prunaai:p-video@0": "720p",
"heygen:avatar@4": "720p",
};
const DEFAULT_DIMENSIONS = {"width": 1024, "height": 576};
@@ -3931,6 +3945,64 @@ function watermarkAdvancedFeatureToggleHandler(watermarkNode) {
}
}
function videoInferenceSpeechInputToggleHandler(speechInputNode) {
if (!speechInputNode?.widgets) return;
function toggleWidgetState(useWidget, paramWidget, paramName) {
if (!useWidget || !paramWidget) return;
function toggleEnabled() {
const enabled = useWidget.value === true;
if (paramWidget.inputEl) {
paramWidget.inputEl.disabled = !enabled;
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
paramWidget.inputEl.readOnly = !enabled;
}
paramWidget.disabled = !enabled;
if (!paramWidget.inputEl && paramName) {
const nodeElement = speechInputNode.htmlElements?.widgetsContainer || speechInputNode.htmlElements;
if (nodeElement) {
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
if (input) {
input.disabled = !enabled;
input.style.opacity = enabled ? "1" : "0.5";
input.style.cursor = enabled ? "text" : "not-allowed";
input.readOnly = !enabled;
}
}
}
speechInputNode.setDirtyCanvas(true);
}
appendWidgetCB(useWidget, () => {
setTimeout(toggleEnabled, 50);
});
setTimeout(toggleEnabled, 100);
}
const pairs = [
["useVoice", "voice"],
["useText", "text"],
["useSpeed", "speed"],
["usePitch", "pitch"],
["useLanguage", "language"],
];
for (const [useName, paramName] of pairs) {
const useWidget = speechInputNode.widgets.find(w => w.name === useName);
const paramWidget = speechInputNode.widgets.find(w => w.name === paramName);
if (useWidget && paramWidget) {
toggleWidgetState(useWidget, paramWidget, paramName);
}
}
}
function regionalPromptingRegionsToggleHandler(regionsNode) {
if (!regionsNode?.widgets) return;
@@ -4122,6 +4194,7 @@ export {
imageInferenceToggleHandler,
imageInferenceAdvancedFeaturesToggleHandler,
watermarkAdvancedFeatureToggleHandler,
videoInferenceSpeechInputToggleHandler,
regionalPromptingRegionsToggleHandler,
upscalerToggleHandler,
videoUpscalerToggleHandler,
+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,)