diff --git a/comfy_api_nodes/nodes_elevenlabs.py b/comfy_api_nodes/nodes_elevenlabs.py index e452daf77..cb3844d3f 100644 --- a/comfy_api_nodes/nodes_elevenlabs.py +++ b/comfy_api_nodes/nodes_elevenlabs.py @@ -233,6 +233,85 @@ class ElevenLabsVoiceSelector(IO.ComfyNode): return IO.NodeOutput(voice_id) +class ElevenLabsRichVoiceSelector(IO.ComfyNode): + @classmethod + def define_schema(cls) -> IO.Schema: + return IO.Schema( + node_id="ElevenLabsRichVoiceSelector", + display_name="ElevenLabs Voice Selector (Rich)", + category="api node/audio/ElevenLabs", + description="Select an ElevenLabs voice with audio preview and rich metadata.", + inputs=[ + IO.Combo.Input( + "voice", + remote_combo=IO.RemoteComboOptions( + route="/proxy/elevenlabs/v2/voices", + refresh_button=True, + refresh=43200000, + use_comfy_api=True, + page_size=100, + item_schema=IO.RemoteItemSchema( + value_field="voice_id", + label_field="name", + preview_url_field="preview_url", + preview_type="audio", + search_fields=["name", "labels.gender", "labels.accent", "labels.use_case"], + ), + ), + tooltip="Choose a voice with audio preview.", + ), + ], + outputs=[ + IO.Custom(ELEVENLABS_VOICE).Output(display_name="voice"), + ], + is_api_node=False, + ) + + @classmethod + def execute(cls, voice: str) -> IO.NodeOutput: + return IO.NodeOutput(voice) # voice is already the voice_id from item_schema.value_field + + +class ElevenLabsSharedVoiceSelector(IO.ComfyNode): + @classmethod + def define_schema(cls) -> IO.Schema: + return IO.Schema( + node_id="ElevenLabsSharedVoiceSelector", + display_name="ElevenLabs Shared Voice Selector", + category="api node/audio/ElevenLabs", + description="Browse the ElevenLabs shared voice library (11K+ community voices) with audio preview.", + inputs=[ + IO.Combo.Input( + "voice", + remote_combo=IO.RemoteComboOptions( + route="/proxy/elevenlabs/v1/shared-voices", + refresh_button=True, + refresh=43200000, + use_comfy_api=True, + page_size=100, + item_schema=IO.RemoteItemSchema( + value_field="voice_id", + label_field="name", + preview_url_field="preview_url", + preview_type="audio", + description_field="descriptive", + search_fields=["name", "gender", "accent", "use_case", "descriptive"], + ), + ), + tooltip="Browse shared voices with audio preview.", + ), + ], + outputs=[ + IO.Custom(ELEVENLABS_VOICE).Output(display_name="voice"), + ], + is_api_node=False, + ) + + @classmethod + def execute(cls, voice: str) -> IO.NodeOutput: + return IO.NodeOutput(voice) + + class ElevenLabsTextToSpeech(IO.ComfyNode): @classmethod def define_schema(cls) -> IO.Schema: @@ -911,6 +990,8 @@ class ElevenLabsExtension(ComfyExtension): return [ ElevenLabsSpeechToText, ElevenLabsVoiceSelector, + ElevenLabsRichVoiceSelector, + ElevenLabsSharedVoiceSelector, ElevenLabsTextToSpeech, ElevenLabsAudioIsolation, ElevenLabsTextToSoundEffects, diff --git a/comfy_api_nodes/nodes_kling.py b/comfy_api_nodes/nodes_kling.py index 9a37ccc53..525064514 100644 --- a/comfy_api_nodes/nodes_kling.py +++ b/comfy_api_nodes/nodes_kling.py @@ -3242,6 +3242,54 @@ class KlingAvatarNode(IO.ComfyNode): return IO.NodeOutput(await download_url_to_video_output(final_response.data.task_result.videos[0].url)) +KLING_ELEMENT_ID = "KLING_ELEMENT_ID" + + +class KlingElementSelector(IO.ComfyNode): + """Select a Kling preset element (character, scene, effect, etc.) for use in video generation.""" + + @classmethod + def define_schema(cls) -> IO.Schema: + return IO.Schema( + node_id="KlingElementSelector", + display_name="Kling Element Selector", + category="api node/video/Kling", + description="Browse and select a Kling preset element with image preview. Elements provide consistent characters, scenes, costumes, and effects for video generation.", + inputs=[ + IO.Combo.Input( + "element", + remote_combo=IO.RemoteComboOptions( + route="/proxy/kling/v1/general/advanced-presets-elements", + refresh_button=True, + refresh=43200000, + use_comfy_api=True, + response_key="data", + item_schema=IO.RemoteItemSchema( + value_field="task_result.elements.0.element_id", + label_field="task_result.elements.0.element_name", + preview_url_field="task_result.elements.0.element_image_list.frontal_image", + preview_type="image", + description_field="task_result.elements.0.element_description", + search_fields=["task_result.elements.0.element_name", "task_result.elements.0.element_description"], + ), + ), + tooltip="Select a preset element to use in video generation.", + ), + ], + outputs=[IO.Custom(KLING_ELEMENT_ID).Output(display_name="element_id")], + hidden=[ + IO.Hidden.auth_token_comfy_org, + IO.Hidden.api_key_comfy_org, + IO.Hidden.unique_id, + ], + is_api_node=False, + ) + + @classmethod + async def execute(cls, element: str) -> IO.NodeOutput: + return IO.NodeOutput(element) + + class KlingExtension(ComfyExtension): @override async def get_node_list(self) -> list[type[IO.ComfyNode]]: @@ -3271,6 +3319,7 @@ class KlingExtension(ComfyExtension): KlingVideoNode, KlingFirstLastFrameNode, KlingAvatarNode, + KlingElementSelector, ]