Skip to content
This repository was archived by the owner on Aug 29, 2025. It is now read-only.

Commit f9c0a6a

Browse files
committed
Version 3.4.3: Fix language switching bug and add flexible language aliases
1 parent 153531f commit f9c0a6a

File tree

8 files changed

+106
-12
lines changed

8 files changed

+106
-12
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [3.4.3] - 2025-08-05
9+
10+
### Fixed
11+
12+
- Fix language switching not working properly and add support for flexible language aliases like [German:], [Brazil:], [USA:]
813
## [3.4.2] - 2025-08-05
914

1015
### Fixed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
[![Forks][forks-shield]][forks-url]
77
[![Dynamic TOML Badge][version-shield]][version-url]
88

9-
# ComfyUI ChatterBox SRT Voice (diogod) v3.4.2
9+
# ComfyUI ChatterBox SRT Voice (diogod) v3.4.3
1010

1111
*This is a refactored node, originally created by [ShmuelRonen](https://github.com/ShmuelRonen/ComfyUI_ChatterBox_Voice).*
1212

nodes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Version and constants
2-
VERSION = "3.4.2"
2+
VERSION = "3.4.3"
33
IS_DEV = False # Set to False for release builds
44
VERSION_DISPLAY = f"v{VERSION}" + (" (dev)" if IS_DEV else "")
55
SEPARATOR = "=" * 70

nodes/chatterbox/chatterbox_tts_node.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -617,17 +617,24 @@ def _process():
617617
def get_chatterbox_model_for_language(lang_code: str) -> str:
618618
"""Map language codes to ChatterBox model names"""
619619
lang_model_map = {
620-
'en': inputs["language"], # Use selected model for English (default)
620+
'en': 'English', # English (always use English model)
621621
'de': 'German', # German
622622
'es': 'Spanish', # Spanish
623623
'fr': 'French', # French
624624
'it': 'Italian', # Italian
625625
'pt': 'Portuguese', # Portuguese
626+
'pt-br': 'Portuguese', # Brazilian Portuguese (use Portuguese model)
627+
'pt-pt': 'Portuguese', # European Portuguese (use Portuguese model)
626628
'no': 'Norwegian', # Norwegian
627629
'nb': 'Norwegian', # Norwegian Bokmål
628630
'nn': 'Norwegian', # Norwegian Nynorsk
629631
}
630-
return lang_model_map.get(lang_code.lower(), inputs["language"])
632+
# For the main model language, use the selected model; for others, use language-specific models
633+
selected_lang = inputs["language"].lower()
634+
if lang_code.lower() == selected_lang:
635+
return inputs["language"] # Use selected model for main language
636+
else:
637+
return lang_model_map.get(lang_code.lower(), inputs["language"])
631638

632639
# Group segments by language with original order tracking
633640
language_groups = {}

nodes/f5tts/f5tts_node.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ def _process():
383383
def get_f5tts_model_for_language(lang_code: str) -> str:
384384
"""Map language codes to F5-TTS model names"""
385385
lang_model_map = {
386-
'en': inputs["model"], # Use selected model for English (default)
386+
'en': 'F5TTS_v1_Base', # English (use v1 - better quality)
387387
'de': 'F5-DE', # German
388388
'es': 'F5-ES', # Spanish
389389
'fr': 'F5-FR', # French
@@ -393,8 +393,14 @@ def get_f5tts_model_for_language(lang_code: str) -> str:
393393
'th': 'F5-TH', # Thai
394394
'pt': 'F5-PT-BR', # Portuguese (Brazilian)
395395
'pt-br': 'F5-PT-BR', # Portuguese (Brazilian)
396+
'pt-pt': 'F5-PT-BR', # Portuguese (European - use Brazilian model for now)
396397
}
397-
return lang_model_map.get(lang_code.lower(), inputs["model"])
398+
# For the main model language, use the selected model; for others, use language-specific models
399+
selected_lang = inputs.get("language", "English").lower()
400+
if lang_code.lower() == selected_lang or (selected_lang == "portuguese" and lang_code.lower() in ["pt", "pt-br"]):
401+
return inputs["model"] # Use selected model for main language
402+
else:
403+
return lang_model_map.get(lang_code.lower(), inputs["model"])
398404

399405
# Group segments by language with original order tracking
400406
language_groups = {}

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[project]
22
name = "chatterbox_srt_voice"
33
description = "ChatterBox SRT Voice TTS Node is a fork of 'ChatteBox Voice' with additional devolpments and full F5-TTS implementation as well. I introduced a SRT node designed to help you synchronize your generated TTS audio with `.srt` subtitle files. Audio wave analyzer will help you find speech segments for f5 speech edit and much more!"
4-
version = "3.4.2"
4+
version = "3.4.3"
55
license = {file = "LICENSE"}
66
dependencies = ["s3tokenizer>=0.1.7", "resemble-perth", "librosa", "scipy", "omegaconf", "accelerate", "transformers==4.46.3", "# Additional dependencies for SRT support and audio processing", "conformer>=0.3.2", "torch", "torchaudio", "numpy", "einops", "phonemizer", "g2p-en", "unidecode", "# Audio processing and timing dependencies", "soundfile", "resampy", "webrtcvad", "# Optional but recommended for better performance", "numba"]
77

utils/models/language_mapper.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,14 @@ def get_model_for_language(self, lang_code: str, default_model: str) -> str:
3232
"""
3333
engine_mappings = self.mappings.get(self.engine_type, {})
3434

35-
# For base language (usually English), use the provided default model
35+
# Check if we should use the default model for this language
36+
# Only use default model if it's actually for the requested language
3637
if lang_code == 'en':
37-
return default_model
38+
# For English, always use English model regardless of default
39+
if self.engine_type == 'f5tts':
40+
return 'F5TTS_v1_Base' # Use v1 for better quality
41+
else: # chatterbox
42+
return 'English'
3843

3944
# Check if language is supported
4045
if lang_code in engine_mappings:

utils/text/character_parser.py

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ class CharacterParser:
3939
# Regex pattern for character tags: [CharacterName] or [language:CharacterName] (excludes pause tags)
4040
CHARACTER_TAG_PATTERN = re.compile(r'\[(?!pause:)([^\]]+)\]')
4141

42-
# Regex to parse language:character format (allows empty character names like [fr:])
43-
LANGUAGE_CHARACTER_PATTERN = re.compile(r'^([a-zA-Z]{2,3}):(.*)$')
42+
# Regex to parse language:character format (supports flexible language names)
43+
LANGUAGE_CHARACTER_PATTERN = re.compile(r'^([a-zA-Z0-9\-_À-ÿ\s]+):(.*)$')
4444

4545
def __init__(self, default_character: str = "narrator", default_language: Optional[str] = None):
4646
"""
@@ -55,6 +55,75 @@ def __init__(self, default_character: str = "narrator", default_language: Option
5555
self.available_characters = set()
5656
self.character_fallbacks = {}
5757
self.character_language_defaults = {}
58+
59+
# Language alias system for flexible language switching
60+
self.language_aliases = {
61+
# German variations
62+
'de': 'de', 'german': 'de', 'deutsch': 'de', 'germany': 'de', 'deutschland': 'de',
63+
64+
# English variations
65+
'en': 'en', 'english': 'en', 'eng': 'en', 'usa': 'en', 'uk': 'en', 'america': 'en', 'britain': 'en',
66+
67+
# Brazilian Portuguese (separate from European Portuguese)
68+
'pt-br': 'pt-br', 'ptbr': 'pt-br', 'brazilian': 'pt-br', 'brasilian': 'pt-br',
69+
'brazil': 'pt-br', 'brasil': 'pt-br', 'br': 'pt-br', 'português brasileiro': 'pt-br',
70+
71+
# European Portuguese (separate from Brazilian)
72+
'pt-pt': 'pt-pt', 'portugal': 'pt-pt', 'european portuguese': 'pt-pt',
73+
'portuguese': 'pt-pt', 'português': 'pt-pt', 'portugues': 'pt-pt',
74+
75+
# French variations
76+
'fr': 'fr', 'french': 'fr', 'français': 'fr', 'francais': 'fr',
77+
'france': 'fr', 'français de france': 'fr',
78+
79+
# Spanish variations
80+
'es': 'es', 'spanish': 'es', 'español': 'es', 'espanol': 'es',
81+
'spain': 'es', 'españa': 'es', 'castilian': 'es',
82+
83+
# Italian variations
84+
'it': 'it', 'italian': 'it', 'italiano': 'it', 'italy': 'it', 'italia': 'it',
85+
86+
# Norwegian variations
87+
'no': 'no', 'norwegian': 'no', 'norsk': 'no', 'norway': 'no', 'norge': 'no',
88+
89+
# Dutch variations
90+
'nl': 'nl', 'dutch': 'nl', 'nederlands': 'nl', 'netherlands': 'nl', 'holland': 'nl',
91+
92+
# Japanese variations
93+
'ja': 'ja', 'japanese': 'ja', '日本語': 'ja', 'japan': 'ja', 'nihongo': 'ja',
94+
95+
# Chinese variations
96+
'zh': 'zh', 'chinese': 'zh', '中文': 'zh', 'china': 'zh',
97+
'zh-cn': 'zh-cn', 'mandarin': 'zh-cn', 'simplified': 'zh-cn', 'mainland': 'zh-cn',
98+
'zh-tw': 'zh-tw', 'traditional': 'zh-tw', 'taiwan': 'zh-tw', 'taiwanese': 'zh-tw',
99+
100+
# Russian variations
101+
'ru': 'ru', 'russian': 'ru', 'русский': 'ru', 'russia': 'ru', 'россия': 'ru',
102+
103+
# Korean variations
104+
'ko': 'ko', 'korean': 'ko', '한국어': 'ko', 'korea': 'ko', 'south korea': 'ko',
105+
}
106+
107+
def resolve_language_alias(self, language_input: str) -> str:
108+
"""
109+
Resolve language alias to canonical language code.
110+
111+
Args:
112+
language_input: User input language (e.g., "German", "brasil", "pt-BR")
113+
114+
Returns:
115+
Canonical language code (e.g., "de", "pt-br")
116+
"""
117+
# Normalize input: lowercase and strip whitespace
118+
normalized = language_input.strip().lower()
119+
120+
# Look up in aliases
121+
canonical = self.language_aliases.get(normalized)
122+
if canonical:
123+
return canonical
124+
125+
# If no alias found, return the original (for backward compatibility)
126+
return normalized
58127

59128
def set_available_characters(self, characters: List[str]):
60129
"""
@@ -98,8 +167,10 @@ def parse_language_character_tag(self, tag_content: str) -> Tuple[Optional[str],
98167
# Check if it's in language:character format
99168
match = self.LANGUAGE_CHARACTER_PATTERN.match(tag_content.strip())
100169
if match:
101-
language = match.group(1).lower()
170+
raw_language = match.group(1)
102171
character = match.group(2).strip()
172+
# Resolve language alias to canonical form
173+
language = self.resolve_language_alias(raw_language)
103174
# If character is empty (e.g., [fr:]), default to narrator
104175
if not character:
105176
character = self.default_character

0 commit comments

Comments
 (0)