Files
razv23andClaude 30cf708a0c Rename WaveSpeed nodes to remove redundant 'wavespeed_ai' prefix
- Renamed wavespeed_ai_infinitetalk.py to infinitetalk.py
- Renamed wavespeed_ai_infinitetalk_multi.py to infinitetalk_multi.py
- Updated class names to remove WaveSpeedAI prefix (now InfiniteTalk and InfiniteTalkMulti)
- Display names in ComfyUI still use 'WaveSpeedAI' prefix for consistency

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-22 10:15:17 +03:00

161 lines
6.1 KiB
Python

import time
from .wavespeed_api.utils import imageurl2tensor
from .wavespeed_api.client import WaveSpeedClient
class InfiniteTalk:
"""
WaveSpeed AI InfiniteTalk Node
Audio-driven conversational AI video generation model that creates talking or singing videos
from a single image and audio input. Features accurate lip synchronization, head movement
alignment, and facial expression matching with the audio.
Unlike traditional dubbing methods, InfiniteTalk enables infinite-length video generation
with consistent identity preservation and instruction following capabilities.
"""
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"client": ("WAVESPEED_AI_API_CLIENT",),
"audio": ("STRING", {
"default": "",
"tooltip": "Audio file URL for generating lip-synced output (connect from Upload Audio node)",
"forceInput": True
}),
"image": ("STRING", {
"default": "",
"tooltip": "Image to animate (connect from Upload Image node)",
"forceInput": True
}),
"resolution": (["480p", "720p"], {
"default": "720p",
"tooltip": "Output video resolution (480p: $0.15 per 5 seconds, 720p: $0.3 per 5 seconds)"
}),
"enable_sync_mode": ("BOOLEAN", {
"default": False,
"tooltip": "Wait for video generation to complete before returning"
}),
},
"optional": {
"prompt": ("STRING", {
"multiline": True,
"default": "",
"tooltip": "Optional generation instructions to control scene, pose, and behavior while maintaining audio synchronization"
}),
"mask_image": ("STRING", {
"default": "",
"tooltip": "Optional mask image URL to specify which person to animate (connect from Upload Image node)",
"forceInput": True
}),
"seed": ("INT", {
"default": -1,
"min": -1,
"max": 2147483647,
"control_after_generate": True,
"tooltip": "Random seed for reproducible results. -1 for random seed"
}),
"enable_base64_output": ("BOOLEAN", {
"default": False,
"tooltip": "Enable base64 output format"
}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("video_url",)
CATEGORY = "WaveSpeedAI"
FUNCTION = "execute"
def execute(self, client, audio, image, resolution, enable_sync_mode,
prompt="", mask_image="", seed=-1, enable_base64_output=False):
"""
Execute the InfiniteTalk model
Args:
client: WaveSpeed API client
audio: Audio file URL for lip-sync generation
image: Image URL to animate
resolution: Output video resolution (480p or 720p)
enable_sync_mode: Whether to wait for completion
prompt: Optional generation instructions
mask_image: Optional mask to specify person to animate
seed: Random seed (-1 for random)
enable_base64_output: Whether to enable base64 output
Returns:
Video URL as string
"""
# Create the actual client object from the client dict
real_client = WaveSpeedClient(api_key=client["api_key"])
# Build payload
payload = {
"audio": audio,
"image": image,
"resolution": resolution,
"enable_sync_mode": enable_sync_mode,
"enable_base64_output": enable_base64_output,
}
# Add optional parameters if provided
if prompt and prompt.strip():
payload["prompt"] = prompt.strip()
if mask_image and mask_image.strip():
payload["mask_image"] = mask_image.strip()
# Add seed if not random
if seed != -1:
payload["seed"] = seed
# API endpoint for InfiniteTalk
endpoint = "/api/v3/wavespeed-ai/infinitetalk"
try:
response = real_client.post(endpoint, payload, timeout=real_client.once_timeout)
if enable_sync_mode:
# In sync mode, we get the results directly
if "outputs" in response and response["outputs"]:
# InfiniteTalk returns video URLs, take the first one
video_url = response["outputs"][0]
return (video_url,)
else:
raise Exception(f"No output received from sync API. Response: {response}")
else:
# In async mode, we need to poll for results
task_id = response["id"]
print(f"InfiniteTalk task submitted successfully. Request ID: {task_id}")
print("Note: Video generation may take several minutes depending on audio length and resolution.")
try:
# Wait for task to complete - longer timeout for video generation
result = real_client.wait_for_task(task_id, polling_interval=2, timeout=1200) # 20 minutes timeout
if "outputs" in result and result["outputs"]:
# Take the first video URL from outputs
video_url = result["outputs"][0]
return (video_url,)
else:
raise Exception("Task completed but no output received")
except Exception as e:
raise Exception(f"Async task failed: {str(e)}")
except Exception as e:
print(f"Error in InfiniteTalk: {str(e)}")
raise e
# Node registration - REQUIRED
NODE_CLASS_MAPPINGS = {
"WaveSpeedAI InfiniteTalk": InfiniteTalk
}
NODE_DISPLAY_NAME_MAPPINGS = {
"WaveSpeedAI InfiniteTalk": "WaveSpeedAI InfiniteTalk"
}