From 6dcd734c463d73cae153c543f8e1d7d58ea81ea8 Mon Sep 17 00:00:00 2001 From: Sirshendu Ganguly Date: Mon, 20 Apr 2026 16:10:35 +0530 Subject: [PATCH] Added support for Gemini TTS --- __init__.py | 2 + clientlibs/main.js | 4 +- clientlibs/types.js | 5 ++ clientlibs/utils.js | 62 +++++++++++++ modules/audioInferenceSpeech.py | 32 +++---- modules/audioInferenceSpeechVoices.py | 87 +++++++++++++++++++ modules/audioModelSearch.py | 4 + ...Audio_Inference_Google_Gemini_3_1_TTS.json | 1 + 8 files changed, 176 insertions(+), 21 deletions(-) create mode 100644 modules/audioInferenceSpeechVoices.py create mode 100644 workflows/Runware_Audio_Inference_Google_Gemini_3_1_TTS.json diff --git a/__init__.py b/__init__.py index dabcb9a..1ed41e6 100644 --- a/__init__.py +++ b/__init__.py @@ -42,6 +42,7 @@ from .modules.providerSettings.briaProviderSettings import RunwareBriaProviderSe from .modules.providerSettings.briaProviderMask import RunwareBriaProviderMask from .modules.audioInference import RunwareAudioInference from .modules.audioInferenceSpeech import RunwareAudioInferenceSpeech +from .modules.audioInferenceSpeechVoices import RunwareAudioInferenceSpeechVoices from .modules.audioModelSearch import RunwareAudioModelSearch from .modules.textModelSearch import RunwareTextModelSearch from .modules.textInferenceMessages import RunwareTextInferenceMessages @@ -164,6 +165,7 @@ NODE_CLASS_MAPPINGS = { "Runware Bria Provider Mask": RunwareBriaProviderMask, "Runware Audio Inference": RunwareAudioInference, "Runware Audio Inference Speech": RunwareAudioInferenceSpeech, + "Runware Audio Inference Speech Voices": RunwareAudioInferenceSpeechVoices, "Runware Audio Model Search": RunwareAudioModelSearch, "Runware Text Model Search": RunwareTextModelSearch, "Runware Text Inference Messages": RunwareTextInferenceMessages, diff --git a/clientlibs/main.js b/clientlibs/main.js index 1aa4c22..b137594 100644 --- a/clientlibs/main.js +++ b/clientlibs/main.js @@ -1,6 +1,6 @@ import { app } from "../../scripts/app.js"; import { api } from "../../scripts/api.js"; -import { promptEnhanceHandler, syncDimensionsNodeHandler, searchNodeHandler, APIKeyHandler, captionNodeHandler, saveTextHandler, mediaUUIDHandler, save3DFilepathHandler, videoTranscriptionHandler, videoOutputsHandler, handleCustomErrors, videoInferenceDimensionsHandler, videoModelSearchFilterHandler, audioModelSearchFilterHandler, textModelSearchFilterHandler, vectorizeModelSearchFilterHandler, vectorizeToggleHandler, useParameterToggleHandler, imageInferenceToggleHandler, imageInferenceAdvancedFeaturesToggleHandler, watermarkAdvancedFeatureToggleHandler, videoInferenceSpeechInputToggleHandler, regionalPromptingRegionsToggleHandler, upscalerToggleHandler, imageUpscalerSettingsToggleHandler, videoUpscalerToggleHandler, audioInferenceToggleHandler, audioInferenceSpeechToggleHandler, audioSettingsToggleHandler, textInferenceSettingsToggleHandler, videoSettingsToggleHandler, acceleratorOptionsToggleHandler, bytedanceProviderSettingsToggleHandler, xaiProviderSettingsToggleHandler, viduProviderSettingsToggleHandler, sourcefulProviderSettingsToggleHandler, sourcefulProviderSettingsFontsToggleHandler, threeDInferenceToggleHandler, threeDInferenceSettingsToggleHandler, threeDInferenceSettingsLatToggleHandler, ultralyticsProviderSettingsToggleHandler, openaiProviderSettingsToggleHandler, lightricksProviderSettingsToggleHandler, klingProviderSettingsToggleHandler, lumaProviderSettingsToggleHandler, briaProviderSettingsToggleHandler, pixverseProviderSettingsToggleHandler, alibabaProviderSettingsToggleHandler, mireloProviderSettingsToggleHandler, googleProviderSettingsToggleHandler, syncProviderSettingsToggleHandler, syncSegmentToggleHandler, settingsToggleHandler, safetyInputsToggleHandler, imageInferenceSettingsColorPaletteToggleHandler, audioInputToggleHandler, speechInputToggleHandler, briaProviderMaskToggleHandler, wanAnimateAdvancedFeatureSettingsToggleHandler, videoAdvancedFeatureInputsToggleHandler, audioInferenceInputsToggleHandler } from "./utils.js"; +import { promptEnhanceHandler, syncDimensionsNodeHandler, searchNodeHandler, APIKeyHandler, captionNodeHandler, saveTextHandler, mediaUUIDHandler, save3DFilepathHandler, videoTranscriptionHandler, videoOutputsHandler, handleCustomErrors, videoInferenceDimensionsHandler, videoModelSearchFilterHandler, audioModelSearchFilterHandler, textModelSearchFilterHandler, vectorizeModelSearchFilterHandler, vectorizeToggleHandler, useParameterToggleHandler, imageInferenceToggleHandler, imageInferenceAdvancedFeaturesToggleHandler, watermarkAdvancedFeatureToggleHandler, videoInferenceSpeechInputToggleHandler, regionalPromptingRegionsToggleHandler, upscalerToggleHandler, imageUpscalerSettingsToggleHandler, videoUpscalerToggleHandler, audioInferenceToggleHandler, audioInferenceSpeechToggleHandler, audioSettingsToggleHandler, textInferenceSettingsToggleHandler, videoSettingsToggleHandler, acceleratorOptionsToggleHandler, bytedanceProviderSettingsToggleHandler, xaiProviderSettingsToggleHandler, viduProviderSettingsToggleHandler, sourcefulProviderSettingsToggleHandler, sourcefulProviderSettingsFontsToggleHandler, threeDInferenceToggleHandler, threeDInferenceSettingsToggleHandler, threeDInferenceSettingsLatToggleHandler, ultralyticsProviderSettingsToggleHandler, openaiProviderSettingsToggleHandler, lightricksProviderSettingsToggleHandler, klingProviderSettingsToggleHandler, lumaProviderSettingsToggleHandler, briaProviderSettingsToggleHandler, pixverseProviderSettingsToggleHandler, alibabaProviderSettingsToggleHandler, mireloProviderSettingsToggleHandler, googleProviderSettingsToggleHandler, syncProviderSettingsToggleHandler, syncSegmentToggleHandler, settingsToggleHandler, safetyInputsToggleHandler, imageInferenceSettingsColorPaletteToggleHandler, audioInputToggleHandler, speechInputToggleHandler, briaProviderMaskToggleHandler, wanAnimateAdvancedFeatureSettingsToggleHandler, videoAdvancedFeatureInputsToggleHandler, audioInferenceInputsToggleHandler, audioInferenceSpeechVoicesToggleHandler } from "./utils.js"; import { RUNWARE_NODE_TYPES, RUNWARE_NODE_PROPS, SEARCH_TERMS } from "./types.js"; const nodeInitList = []; @@ -91,6 +91,8 @@ app.registerExtension({ regionalPromptingRegionsToggleHandler(node); } else if(nodeClass === RUNWARE_NODE_TYPES.AUDIOINFERENCESPEECH) { audioInferenceSpeechToggleHandler(node); + } else if(nodeClass === RUNWARE_NODE_TYPES.AUDIOINFERENCESPEECHVOICES) { + audioInferenceSpeechVoicesToggleHandler(node); } else if(nodeClass === RUNWARE_NODE_TYPES.AUDIOSETTINGS) { audioSettingsToggleHandler(node); } else if(nodeClass === RUNWARE_NODE_TYPES.TEXTINFERENCESETTINGS) { diff --git a/clientlibs/types.js b/clientlibs/types.js index d454480..0787e41 100644 --- a/clientlibs/types.js +++ b/clientlibs/types.js @@ -82,6 +82,7 @@ const RUNWARE_NODE_TYPES = { FRAMEIMAGES: "Runware Frame Images", AUDIOINFERENCE: "Runware Audio Inference", AUDIOINFERENCESPEECH: "Runware Audio Inference Speech", + AUDIOINFERENCESPEECHVOICES: "Runware Audio Inference Speech Voices", AUDIOMODELSEARCH: "Runware Audio Model Search", TEXTMODELSEARCH: "Runware Text Model Search", TEXTINFERENCE: "Runware Text Inference", @@ -299,6 +300,10 @@ const RUNWARE_NODE_PROPS = { [RUNWARE_NODE_TYPES.AUDIOINFERENCESPEECH]: { bgColor: DEFAULT_BGCOLOR, }, + [RUNWARE_NODE_TYPES.AUDIOINFERENCESPEECHVOICES]: { + bgColor: DEFAULT_BGCOLOR, + colorModeOnly: true, + }, [RUNWARE_NODE_TYPES.AUDIOMODELSEARCH]: { bgColor: DEFAULT_BGCOLOR, liveSearch: true, diff --git a/clientlibs/utils.js b/clientlibs/utils.js index fe06b2d..6558f27 100644 --- a/clientlibs/utils.js +++ b/clientlibs/utils.js @@ -3137,6 +3137,9 @@ function audioModelSearchFilterHandler(audioModelSearchNode) { "inworld:tts@1.5-mini (Inworld TTS-1.5 Mini)", "inworld:tts@1.5-max (Inworld TTS-1.5 Max)", ], + "Google": [ + "google:gemini@3.1-flash-tts (Gemini 3.1 Flash TTS)", + ], }; function filterModelList() { @@ -4614,6 +4617,64 @@ function audioInferenceInputsToggleHandler(audioInputsNode) { } } +function audioInferenceSpeechVoicesToggleHandler(voicesNode) { + if (!voicesNode?.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) { + const nodeElement = voicesNode.htmlElements?.widgetsContainer || voicesNode.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; + if (input.tagName === "SELECT") { + input.style.pointerEvents = enabled ? "auto" : "none"; + } + } + } + } + + voicesNode.setDirtyCanvas(true); + } + + appendWidgetCB(useWidget, () => { + setTimeout(toggleEnabled, 50); + }); + + setTimeout(toggleEnabled, 100); + } + + for (let i = 1; i <= 4; i++) { + const useVoiceWidget = voicesNode.widgets.find((w) => w && w.name === `useVoice${i}`); + const speakerWidget = voicesNode.widgets.find((w) => w && w.name === `speaker${i}`); + const voiceWidget = voicesNode.widgets.find((w) => w && w.name === `voice${i}`); + + if (useVoiceWidget && speakerWidget) { + toggleWidgetState(useVoiceWidget, speakerWidget, `speaker${i}`); + } + if (useVoiceWidget && voiceWidget) { + toggleWidgetState(useVoiceWidget, voiceWidget, `voice${i}`); + } + } +} + export { notifyUser, promptEnhanceHandler, @@ -4677,6 +4738,7 @@ export { wanAnimateAdvancedFeatureSettingsToggleHandler, videoAdvancedFeatureInputsToggleHandler, audioInferenceInputsToggleHandler, + audioInferenceSpeechVoicesToggleHandler, }; function googleProviderSettingsToggleHandler(googleNode) { diff --git a/modules/audioInferenceSpeech.py b/modules/audioInferenceSpeech.py index 7805637..09f6362 100644 --- a/modules/audioInferenceSpeech.py +++ b/modules/audioInferenceSpeech.py @@ -14,20 +14,6 @@ class RunwareAudioInferenceSpeech: "calm", "fluent", "whisper", ] - SPEECH_LANGUAGES = [ - "Auto", - "Chinese", - "English", - "Japanese", - "Korean", - "German", - "French", - "Russian", - "Portuguese", - "Spanish", - "Italian", - ] - def __init__(self): pass @@ -50,7 +36,7 @@ class RunwareAudioInferenceSpeech: "default": "", "tooltip": "Voice identifier.", }), - "useSpeed": ("BOOLEAN", {"default": True, "tooltip": "Include speed (speech.speed)"}), + "useSpeed": ("BOOLEAN", {"default": False, "tooltip": "Include speed (speech.speed)"}), "speed": ("FLOAT", { "default": 1.0, "min": 0.5, @@ -58,7 +44,7 @@ class RunwareAudioInferenceSpeech: "step": 0.01, "tooltip": "Speech rate multiplier (speech.speed)", }), - "useVolume": ("BOOLEAN", {"default": True, "tooltip": "Include volume (speech.volume)"}), + "useVolume": ("BOOLEAN", {"default": False, "tooltip": "Include volume (speech.volume)"}), "volume": ("FLOAT", { "default": 1.0, "min": 1.0, @@ -87,9 +73,12 @@ class RunwareAudioInferenceSpeech: "default": False, "tooltip": "Enable to include language (speech.language).", }), - "language": (cls.SPEECH_LANGUAGES, { + "language": ("STRING", { "default": "Auto", - "tooltip": "Language of the input text. Options: Auto, Chinese, English, Japanese, Korean, German, French, Russian, Portuguese, Spanish, Italian. Applies to all variants. Only used when 'Use Language' is enabled.", + "tooltip": "Language of the input text (for example: en-US). Applies to all variants. Only used when 'Use Language' is enabled.", + }), + "voices": ("RUNWAREAUDIOINFERENCESPEECHVOICES", { + "tooltip": "Optional multi-speaker voices array (speech.voices[]). If provided, it takes precedence over speech.voice.", }), } } @@ -119,10 +108,13 @@ class RunwareAudioInferenceSpeech: use_tone = kwargs.get("useTone", False) tone_str = kwargs.get("tone", "") or "" use_language = kwargs.get("useLanguage", False) - language = kwargs.get("language", "Auto") + language = (kwargs.get("language") or "Auto").strip() + voices = kwargs.get("voices") speech: Dict[str, Any] = {"text": text} - if use_voice: + if isinstance(voices, list) and len(voices) > 0: + speech["voices"] = voices + elif use_voice: speech["voice"] = voice if use_speed: speech["speed"] = speed diff --git a/modules/audioInferenceSpeechVoices.py b/modules/audioInferenceSpeechVoices.py new file mode 100644 index 0000000..91f1714 --- /dev/null +++ b/modules/audioInferenceSpeechVoices.py @@ -0,0 +1,87 @@ +""" +Runware Audio Inference Speech Voices node: +Builds speech.voices[] for multi-speaker audio inference speech payloads. +""" + +import re +from typing import Any, Dict, List + + +class RunwareAudioInferenceSpeechVoices: + """Build speech.voices[] list for Runware Audio Inference.""" + + MAX_VOICES = 4 + _SPEAKER_ALIAS_PATTERN = re.compile(r"^[A-Za-z0-9]+$") + + @classmethod + def INPUT_TYPES(cls): + optional_inputs = {} + for i in range(1, cls.MAX_VOICES + 1): + optional_inputs[f"useVoice{i}"] = ("BOOLEAN", { + "default": i == 1, + "tooltip": f"Enable to include speaker/voice pair #{i} in speech.voices.", + }) + optional_inputs[f"speaker{i}"] = ("STRING", { + "default": f"Speaker{i}", + "tooltip": "Unique alphanumeric speaker alias (speech.voices[].speaker).", + }) + optional_inputs[f"voice{i}"] = ("STRING", { + "default": "", + "tooltip": "Voice name for this speaker (speech.voices[].voice).", + }) + + return { + "required": {}, + "optional": optional_inputs, + } + + RETURN_TYPES = ("RUNWAREAUDIOINFERENCESPEECHVOICES",) + RETURN_NAMES = ("voices",) + FUNCTION = "createVoices" + CATEGORY = "Runware/Audio" + DESCRIPTION = ( + "Build speech.voices[] for multi-speaker synthesis. " + "Each item contains speaker (unique alphanumeric alias) and voice name." + ) + + def createVoices(self, **kwargs) -> tuple[List[Dict[str, str]]]: + voices: List[Dict[str, str]] = [] + seen_speakers = set() + + for i in range(1, self.MAX_VOICES + 1): + use_voice = bool(kwargs.get(f"useVoice{i}", i == 1)) + if not use_voice: + continue + + speaker = (kwargs.get(f"speaker{i}") or "").strip() + voice = (kwargs.get(f"voice{i}") or "").strip() + + if not speaker or not voice: + raise Exception( + f"Voice #{i} is enabled, but speaker{i} and voice{i} must both be provided." + ) + if not self._SPEAKER_ALIAS_PATTERN.match(speaker): + raise Exception( + f"speaker{i} must be alphanumeric only (got: '{speaker}')." + ) + if speaker in seen_speakers: + raise Exception( + f"Duplicate speaker alias '{speaker}'. Each speaker must be unique." + ) + + seen_speakers.add(speaker) + voices.append({ + "speaker": speaker, + "voice": voice, + }) + + return (voices,) + + +NODE_CLASS_MAPPINGS = { + "RunwareAudioInferenceSpeechVoices": RunwareAudioInferenceSpeechVoices, +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "RunwareAudioInferenceSpeechVoices": "Runware Audio Inference Speech Voices", +} diff --git a/modules/audioModelSearch.py b/modules/audioModelSearch.py index fe33336..5a18887 100644 --- a/modules/audioModelSearch.py +++ b/modules/audioModelSearch.py @@ -40,6 +40,9 @@ class RunwareAudioModelSearch: "inworld:tts@1.5-mini (Inworld TTS-1.5 Mini)", "inworld:tts@1.5-max (Inworld TTS-1.5 Max)", ], + "Google": [ + "google:gemini@3.1-flash-tts (Gemini 3.1 Flash TTS)", + ], } MODEL_PROVIDERS = [ @@ -53,6 +56,7 @@ class RunwareAudioModelSearch: "xAI", "MiniMax", "Inworld", + "Google", ] @classmethod diff --git a/workflows/Runware_Audio_Inference_Google_Gemini_3_1_TTS.json b/workflows/Runware_Audio_Inference_Google_Gemini_3_1_TTS.json new file mode 100644 index 0000000..a3bc575 --- /dev/null +++ b/workflows/Runware_Audio_Inference_Google_Gemini_3_1_TTS.json @@ -0,0 +1 @@ +{"id":"dccc59cb-49b6-4ea6-8414-590c2235bf3f","revision":0,"last_node_id":6,"last_link_id":4,"nodes":[{"id":3,"type":"SaveAudioMP3","pos":[1215.76708984375,670.1636352539062],"size":[270,136],"flags":{},"order":4,"mode":0,"inputs":[{"localized_name":"audio","name":"audio","type":"AUDIO","link":1},{"localized_name":"filename_prefix","name":"filename_prefix","type":"STRING","widget":{"name":"filename_prefix"},"link":null},{"localized_name":"quality","name":"quality","type":"COMBO","widget":{"name":"quality"},"link":null},{"localized_name":"audioUI","name":"audioUI","type":"AUDIO_UI","widget":{"name":"audioUI"},"link":null}],"outputs":[],"properties":{"cnr_id":"comfy-core","ver":"0.3.46","Node name for S&R":"SaveAudioMP3"},"widgets_values":["audio/ComfyUI","V0"]},{"id":1,"type":"Runware Audio Model Search","pos":[243.41549682617188,652.7023315429688],"size":[270,130],"flags":{},"order":0,"mode":0,"inputs":[{"localized_name":"Model Search","name":"Model Search","type":"STRING","widget":{"name":"Model Search"},"link":null},{"localized_name":"Model Provider","name":"Model Provider","type":"COMBO","widget":{"name":"Model Provider"},"link":null},{"localized_name":"AudioList","name":"AudioList","type":"COMBO","widget":{"name":"AudioList"},"link":null},{"localized_name":"Use Search Value","name":"Use Search Value","type":"BOOLEAN","widget":{"name":"Use Search Value"},"link":null}],"outputs":[{"localized_name":"model","name":"model","type":"RUNWAREAUDIOMODEL","links":[2]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"b4da68335d246b2c076a83640270d3fc9fe2cb5b","Node name for S&R":"Runware Audio Model Search"},"widgets_values":["","Google","google:gemini@3.1-flash-tts (Gemini 3.1 Flash TTS)",false],"bgcolor":"#5345bf"},{"id":5,"type":"Runware Audio Inference Speech Voices","pos":[1098.5885009765625,939.715576171875],"size":[354.3951110839844,322],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"useVoice1","name":"useVoice1","shape":7,"type":"BOOLEAN","widget":{"name":"useVoice1"},"link":null},{"localized_name":"speaker1","name":"speaker1","shape":7,"type":"STRING","widget":{"name":"speaker1"},"link":null},{"localized_name":"voice1","name":"voice1","shape":7,"type":"STRING","widget":{"name":"voice1"},"link":null},{"localized_name":"useVoice2","name":"useVoice2","shape":7,"type":"BOOLEAN","widget":{"name":"useVoice2"},"link":null},{"localized_name":"speaker2","name":"speaker2","shape":7,"type":"STRING","widget":{"name":"speaker2"},"link":null},{"localized_name":"voice2","name":"voice2","shape":7,"type":"STRING","widget":{"name":"voice2"},"link":null},{"localized_name":"useVoice3","name":"useVoice3","shape":7,"type":"BOOLEAN","widget":{"name":"useVoice3"},"link":null},{"localized_name":"speaker3","name":"speaker3","shape":7,"type":"STRING","widget":{"name":"speaker3"},"link":null},{"localized_name":"voice3","name":"voice3","shape":7,"type":"STRING","widget":{"name":"voice3"},"link":null},{"localized_name":"useVoice4","name":"useVoice4","shape":7,"type":"BOOLEAN","widget":{"name":"useVoice4"},"link":null},{"localized_name":"speaker4","name":"speaker4","shape":7,"type":"STRING","widget":{"name":"speaker4"},"link":null},{"localized_name":"voice4","name":"voice4","shape":7,"type":"STRING","widget":{"name":"voice4"},"link":null}],"outputs":[{"localized_name":"voices","name":"voices","type":"RUNWAREAUDIOINFERENCESPEECHVOICES","links":[3]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"b4da68335d246b2c076a83640270d3fc9fe2cb5b","Node name for S&R":"Runware Audio Inference Speech Voices"},"widgets_values":[true,"Sam","Aoede",true,"Bob","Algieba",false,"Speaker3","",false,"Speaker4",""],"bgcolor":"#5345bf"},{"id":2,"type":"Runware Audio Inference","pos":[605.2332153320312,597.2218627929688],"size":[400,746],"flags":{},"order":3,"mode":0,"inputs":[{"localized_name":"model","name":"model","type":"RUNWAREAUDIOMODEL","link":2},{"localized_name":"inputs","name":"inputs","shape":7,"type":"RUNWAREAUDIOINFERENCEINPUTS","link":null},{"localized_name":"settings","name":"settings","shape":7,"type":"RUNWAREAUDIOSETTINGS","link":null},{"localized_name":"speech","name":"speech","shape":7,"type":"RUNWARESPEECH","link":4},{"localized_name":"voiceModify","name":"voiceModify","shape":7,"type":"RUNWAREVOICEMODIFY","link":null},{"localized_name":"providerSettings","name":"providerSettings","shape":7,"type":"RUNWAREPROVIDERSETTINGS","link":null},{"localized_name":"usePositivePrompt","name":"usePositivePrompt","type":"BOOLEAN","widget":{"name":"usePositivePrompt"},"link":null},{"localized_name":"positivePrompt","name":"positivePrompt","type":"STRING","widget":{"name":"positivePrompt"},"link":null},{"localized_name":"negativePrompt","name":"negativePrompt","type":"STRING","widget":{"name":"negativePrompt"},"link":null},{"localized_name":"useDuration","name":"useDuration","type":"BOOLEAN","widget":{"name":"useDuration"},"link":null},{"localized_name":"duration","name":"duration","type":"INT","widget":{"name":"duration"},"link":null},{"localized_name":"useSampleRate","name":"useSampleRate","type":"BOOLEAN","widget":{"name":"useSampleRate"},"link":null},{"localized_name":"sampleRate","name":"sampleRate","type":"COMBO","widget":{"name":"sampleRate"},"link":null},{"localized_name":"useBitrate","name":"useBitrate","type":"BOOLEAN","widget":{"name":"useBitrate"},"link":null},{"localized_name":"bitrate","name":"bitrate","type":"COMBO","widget":{"name":"bitrate"},"link":null},{"localized_name":"useChannels","name":"useChannels","type":"BOOLEAN","widget":{"name":"useChannels"},"link":null},{"localized_name":"channels","name":"channels","type":"INT","widget":{"name":"channels"},"link":null},{"localized_name":"outputType","name":"outputType","type":"COMBO","widget":{"name":"outputType"},"link":null},{"localized_name":"outputFormat","name":"outputFormat","type":"COMBO","widget":{"name":"outputFormat"},"link":null},{"localized_name":"numberResults","name":"numberResults","type":"INT","widget":{"name":"numberResults"},"link":null},{"localized_name":"useSeed","name":"useSeed","type":"BOOLEAN","widget":{"name":"useSeed"},"link":null},{"localized_name":"seed","name":"seed","type":"INT","widget":{"name":"seed"},"link":null},{"localized_name":"useSteps","name":"useSteps","type":"BOOLEAN","widget":{"name":"useSteps"},"link":null},{"localized_name":"steps","name":"steps","type":"INT","widget":{"name":"steps"},"link":null},{"localized_name":"useStrength","name":"useStrength","type":"BOOLEAN","widget":{"name":"useStrength"},"link":null},{"localized_name":"strength","name":"strength","type":"FLOAT","widget":{"name":"strength"},"link":null},{"localized_name":"useCFGScale","name":"useCFGScale","type":"BOOLEAN","widget":{"name":"useCFGScale"},"link":null},{"localized_name":"CFGScale","name":"CFGScale","type":"FLOAT","widget":{"name":"CFGScale"},"link":null}],"outputs":[{"localized_name":"audio","name":"audio","type":"AUDIO","links":[1]},{"localized_name":"video","name":"video","type":"VIDEO","links":null}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"b4da68335d246b2c076a83640270d3fc9fe2cb5b","Node name for S&R":"Runware Audio Inference"},"widgets_values":[false,"","",false,10,false,32000,false,128,false,2,"URL","MP3",1,false,885055810,"randomize",false,20,false,0.8,false,12],"bgcolor":"#5345bf"},{"id":4,"type":"Runware Audio Inference Speech","pos":[168.8231964111328,881.7427368164062],"size":[400,454],"flags":{},"order":2,"mode":0,"inputs":[{"localized_name":"voices","name":"voices","shape":7,"type":"RUNWAREAUDIOINFERENCESPEECHVOICES","link":3},{"localized_name":"text","name":"text","type":"STRING","widget":{"name":"text"},"link":null},{"localized_name":"useVoice","name":"useVoice","shape":7,"type":"BOOLEAN","widget":{"name":"useVoice"},"link":null},{"localized_name":"voice","name":"voice","shape":7,"type":"STRING","widget":{"name":"voice"},"link":null},{"localized_name":"useSpeed","name":"useSpeed","shape":7,"type":"BOOLEAN","widget":{"name":"useSpeed"},"link":null},{"localized_name":"speed","name":"speed","shape":7,"type":"FLOAT","widget":{"name":"speed"},"link":null},{"localized_name":"useVolume","name":"useVolume","shape":7,"type":"BOOLEAN","widget":{"name":"useVolume"},"link":null},{"localized_name":"volume","name":"volume","shape":7,"type":"FLOAT","widget":{"name":"volume"},"link":null},{"localized_name":"usePitch","name":"usePitch","shape":7,"type":"BOOLEAN","widget":{"name":"usePitch"},"link":null},{"localized_name":"pitch","name":"pitch","shape":7,"type":"FLOAT","widget":{"name":"pitch"},"link":null},{"localized_name":"useEmotion","name":"useEmotion","shape":7,"type":"BOOLEAN","widget":{"name":"useEmotion"},"link":null},{"localized_name":"emotion","name":"emotion","shape":7,"type":"COMBO","widget":{"name":"emotion"},"link":null},{"localized_name":"useTone","name":"useTone","shape":7,"type":"BOOLEAN","widget":{"name":"useTone"},"link":null},{"localized_name":"tone","name":"tone","shape":7,"type":"STRING","widget":{"name":"tone"},"link":null},{"localized_name":"useLanguage","name":"useLanguage","shape":7,"type":"BOOLEAN","widget":{"name":"useLanguage"},"link":null},{"localized_name":"language","name":"language","shape":7,"type":"STRING","widget":{"name":"language"},"link":null}],"outputs":[{"localized_name":"speech","name":"speech","type":"RUNWARESPEECH","links":[4]}],"properties":{"cnr_id":"ComfyUI-Runware","ver":"b4da68335d246b2c076a83640270d3fc9fe2cb5b","Node name for S&R":"Runware Audio Inference Speech"},"widgets_values":["[Sam] Hey Bob, did you see the new model? [Bob] Yeah, [laughs] it sounds great!",false,"",false,1,false,1,false,0,false,"calm",false,"",true,"en-US"],"bgcolor":"#5345bf"}],"links":[[1,2,0,3,0,"AUDIO"],[2,1,0,2,0,"RUNWAREAUDIOMODEL"],[3,5,0,4,0,"RUNWAREAUDIOINFERENCESPEECHVOICES"],[4,4,0,2,3,"RUNWARESPEECH"]],"groups":[],"config":{},"extra":{"ds":{"scale":0.6547164698733117,"offset":[178.5958437076911,-431.7559729011467]}},"version":0.4} \ No newline at end of file