88 lines
2.8 KiB
Python
88 lines
2.8 KiB
Python
"""
|
|
Runware Audio Inference Speech Voices node:
|
|
Builds speech.voices[] for multi-speaker audio inference speech payloads.
|
|
"""
|
|
|
|
import re
|
|
from typing import 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": False,
|
|
"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}", False))
|
|
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",
|
|
}
|