Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/src/lib/constants/languages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const ALL_LANGUAGES = {
sv: 'Swedish',
sw: 'Swahili',
tr: 'Turkish',
vi: 'Vietnamese',
zh: 'Chinese',
} as const;

Expand Down Expand Up @@ -96,6 +97,7 @@ export const ENGINE_LANGUAGES: Record<string, readonly LanguageCode[]> = {
'sv',
'sw',
'tr',
'vi',
'zh',
],
} as const;
Expand Down
1 change: 1 addition & 0 deletions backend/backends/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ def _get_non_qwen_tts_configs() -> list[ModelConfig]:
"sv",
"sw",
"tr",
"vi",
],
),
]
Expand Down
2 changes: 1 addition & 1 deletion backend/backends/omnivoice_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
pitch, whisper, English accent, Chinese dialect), not the free-form prose
Qwen CustomVoice accepts. Anything outside it raises upstream.

Languages: the 22 codes Voicebox already knows that OmniVoice also covers,
Languages: the 23 codes Voicebox already knows that OmniVoice also covers,
plus Arabic via the ISO 639-3 code ``arb``. OmniVoice supports far more, but
exposing them means widening the language enum across the API and frontend.
"""
Expand Down
6 changes: 3 additions & 3 deletions backend/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class VoiceProfileCreate(BaseModel):
name: str = Field(..., min_length=1, max_length=100)
description: Optional[str] = Field(None, max_length=500)
language: str = Field(
default="en", pattern="^(zh|en|ja|ko|de|fr|ru|pt|es|it|he|ar|da|el|fi|hi|ms|nl|no|pl|sv|sw|tr)$"
default="en", pattern="^(zh|en|ja|ko|de|fr|ru|pt|es|it|he|ar|da|el|fi|hi|ms|nl|no|pl|sv|sw|tr|vi)$"
)
voice_type: Optional[str] = Field(default="cloned", pattern="^(cloned|preset|designed)$")
preset_engine: Optional[str] = Field(None, max_length=50)
Expand Down Expand Up @@ -81,7 +81,7 @@ class GenerationRequest(BaseModel):

profile_id: str
text: str = Field(..., min_length=1, max_length=50000)
language: str = Field(default="en", pattern="^(zh|en|ja|ko|de|fr|ru|pt|es|it|he|ar|da|el|fi|hi|ms|nl|no|pl|sv|sw|tr)$")
language: str = Field(default="en", pattern="^(zh|en|ja|ko|de|fr|ru|pt|es|it|he|ar|da|el|fi|hi|ms|nl|no|pl|sv|sw|tr|vi)$")
seed: Optional[int] = Field(None, ge=0)
model_size: Optional[str] = Field(default="1.7B", pattern="^(1\\.7B|0\\.6B|1B|3B)$")
instruct: Optional[str] = Field(None, max_length=500)
Expand Down Expand Up @@ -398,7 +398,7 @@ class SpeakRequest(BaseModel):
)
language: Optional[str] = Field(
None,
pattern="^(zh|en|ja|ko|de|fr|ru|pt|es|it|he|ar|da|el|fi|hi|ms|nl|no|pl|sv|sw|tr)$",
pattern="^(zh|en|ja|ko|de|fr|ru|pt|es|it|he|ar|da|el|fi|hi|ms|nl|no|pl|sv|sw|tr|vi)$",
)


Expand Down
19 changes: 19 additions & 0 deletions backend/tests/test_omnivoice_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,25 @@ def test_declared_languages_are_resolvable_by_omnivoice():
assert unresolved == []


def test_declared_languages_pass_the_api_pattern():
"""Regression: the API enum is a second copy of the advertised language list.

A code can be listed in the engine config and still be rejected with a 422
by the ``language`` pattern on the request models, so every advertised code
has to be accepted by ``GenerationRequest``.
"""
from pydantic import ValidationError

from backend.backends import get_model_config
from backend.models import GenerationRequest

for code in get_model_config("omnivoice").languages:
GenerationRequest(profile_id="profile", text="Xin chào", language=code)

with pytest.raises(ValidationError):
GenerationRequest(profile_id="profile", text="Xin chào", language="zz")


def test_clear_codec_layer_cache_is_safe_when_codec_never_imported():
from backend.backends.omnivoice_backend import _clear_codec_layer_cache

Expand Down