fix(vibevoice): auto-normalize custom roles to Speaker N format (v1.10.9)

This commit is contained in:
Hawk Lee
2026-02-01 16:26:25 +08:00
parent d15c4cdc89
commit 50a2ec3346
3 changed files with 57 additions and 2 deletions
BIN
View File
Binary file not shown.
+56 -1
View File
@@ -246,6 +246,53 @@ class AIIA_VibeVoice_TTS:
print(f"[AIIA Error] Failed to load fallback audio: {e}")
return None
def _normalize_roles(self, text):
"""
Detects custom roles (e.g. 'Host A:', 'User:') and normalizes them to 'Speaker N:'.
Returns: (normalized_text, role_mapping)
"""
import re
lines = text.split('\n')
# Matches "Role Name:" at start of line.
# Excludes "Speaker N:" which is already valid.
# Limit role name to 30 chars to avoid matching long sentences.
role_pattern = re.compile(r'^([^\n:]{1,30}):\s+')
speaker_pattern = re.compile(r'^Speaker\s*\d+', re.IGNORECASE)
roles_map = {}
next_id = 1
normalized_lines = []
for line in lines:
stripped = line.strip()
if not stripped:
normalized_lines.append(line)
continue
match = role_pattern.match(stripped)
if match:
role_name = match.group(1).strip()
# If already standard format, keep it
if speaker_pattern.match(role_name):
normalized_lines.append(line)
continue
# Map custom role
if role_name not in roles_map:
roles_map[role_name] = next_id
next_id += 1
spk_id = roles_map[role_name]
# Replace prefix with Speaker N
# We reconstruct the line to ensure standard formatting
content = stripped[match.end():]
normalized_lines.append(f"Speaker {spk_id}: {content}")
else:
normalized_lines.append(line)
return "\n".join(normalized_lines), roles_map
def generate(self, vibevoice_model, text, cfg_scale, ddpm_steps, speed, normalize_text,
do_sample, temperature, top_k, top_p, reference_audio=None):
model = vibevoice_model["model"]
@@ -273,7 +320,15 @@ class AIIA_VibeVoice_TTS:
text = re.sub(r'(\d+年)\s*[-—–]\s*(\d+年)', r'\1至\2', text)
text = text.replace('"', '').replace("'", '')
# Default Speaker Tag
# [AIIA v1.10.8] Auto-Normalize Roles (e.g. "Host A:" -> "Speaker 1:")
text, role_map = self._normalize_roles(text)
if role_map:
print(f"[AIIA] Auto-mapped roles: {role_map}")
# Warn if user needs more reference audios
required_voices = len(role_map)
# We don't have ref audio count here yet easily (it's loaded later), but likely user provided list
# Default Speaker Tag (if still no speakers detected)
if not re.search(r'^Speaker\s+\d+\s*:', text, re.IGNORECASE | re.MULTILINE):
lines = text.split('\n')
text = "\n".join([f"Speaker 1: {line.strip()}" for line in lines if line.strip()])
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "aiia"
description = "The Ultimate AI Audio/Video toolkit for ComfyUI. Features an enhanced Ditto (with optimizations that outperform official demos and other SOTA talking head models in lip-sync accuracy and natural motion), EchoMimic V3 & FLOAT, VibeVoice & CosyVoice 3.0 (Zero-Shot Voice Cloning), Multi-Role Podcast Generation, and a powerful Media Browser."
version = "1.10.8"
version = "1.10.9"
license = {file = "LICENSE"}
readme = "README.md"
authors = [