Skip to content

Commit 962607d

Browse files
authored
feat[api]: separate TTS language validation per engine (#2581)
Validate chatterbox and supertonic languages with distinct enums instead of a shared list. Expose all 18 chatterbox multilingual languages and restrict supertonic to its actual subset (en/es/fr/pt/ko). Co-authored-by: ishanvohra2 <your-github-email>
1 parent 352a7e8 commit 962607d

2 files changed

Lines changed: 87 additions & 5 deletions

File tree

packages/sdk/schemas/text-to-speech.ts

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,55 @@
11
import { z } from "zod";
22
import { modelSrcInputSchema } from "./model-src-utils";
33

4-
// TTS supported languages based on available models
5-
export const TTS_LANGUAGES = [
4+
// Chatterbox multilingual supported languages (18). The engines support
5+
// different language sets, so the language enum is validated per engine.
6+
export const TTS_CHATTERBOX_LANGUAGES = [
67
"en", // English
78
"es", // Spanish
9+
"fr", // French
810
"de", // German
911
"it", // Italian
12+
"pt", // Portuguese
13+
"nl", // Dutch
14+
"pl", // Polish
15+
"tr", // Turkish
16+
"sv", // Swedish
17+
"da", // Danish
18+
"fi", // Finnish
19+
"no", // Norwegian
20+
"el", // Greek
21+
"ms", // Malay
22+
"sw", // Swahili
23+
"ar", // Arabic
24+
"ko", // Korean
1025
] as const;
1126

12-
const ttsLanguageSchema = z.enum(TTS_LANGUAGES);
27+
// Supertonic supported languages (subset of the Chatterbox set).
28+
export const TTS_SUPERTONIC_LANGUAGES = [
29+
"en", // English
30+
"es", // Spanish
31+
"fr", // French
32+
"pt", // Portuguese
33+
"ko", // Korean
34+
] as const;
35+
36+
// Union of all TTS-supported languages across engines. Kept for backwards
37+
// compatibility; prefer the engine-specific lists when validating a config.
38+
export const TTS_LANGUAGES = [...TTS_CHATTERBOX_LANGUAGES] as const;
39+
40+
const ttsChatterboxLanguageSchema = z.enum(TTS_CHATTERBOX_LANGUAGES);
41+
const ttsSupertonicLanguageSchema = z.enum(TTS_SUPERTONIC_LANGUAGES);
1342

1443
export const ttsChatterboxRuntimeConfigSchema = z.object({
1544
ttsEngine: z.literal("chatterbox"),
16-
language: ttsLanguageSchema,
45+
language: ttsChatterboxLanguageSchema,
1746
voice: z.string().optional(),
1847
useGPU: z.boolean().optional(),
1948
});
2049

2150
export const ttsSupertonicRuntimeConfigSchema = z.object({
2251
ttsEngine: z.literal("supertonic"),
23-
language: ttsLanguageSchema,
52+
language: ttsSupertonicLanguageSchema,
2453
voice: z.string().optional(),
2554
ttsSpeed: z.number().optional(),
2655
ttsNumInferenceSteps: z.number().optional(),
@@ -141,6 +170,8 @@ export const textToSpeechStreamResponseSchema = z.object({
141170
});
142171

143172
export type TtsLanguage = (typeof TTS_LANGUAGES)[number];
173+
export type TtsChatterboxLanguage = (typeof TTS_CHATTERBOX_LANGUAGES)[number];
174+
export type TtsSupertonicLanguage = (typeof TTS_SUPERTONIC_LANGUAGES)[number];
144175
export type TtsChatterboxLoadConfig = z.infer<typeof ttsChatterboxLoadConfigSchema>;
145176
export type TtsSupertonicLoadConfig = z.infer<typeof ttsSupertonicLoadConfigSchema>;
146177
export type TtsLoadConfig = z.infer<typeof ttsLoadConfigSchema>;

packages/sdk/test/unit/tts-schemas.test.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ import {
44
ttsResponseSchema,
55
textToSpeechStreamResponseSchema,
66
ttsConfigSchema,
7+
ttsChatterboxRuntimeConfigSchema,
78
ttsSupertonicRuntimeConfigSchema,
9+
TTS_CHATTERBOX_LANGUAGES,
10+
TTS_SUPERTONIC_LANGUAGES,
811
LEGACY_TTS_ONNX_MODEL_CONFIG_FIELDS,
912
} from "@/schemas/text-to-speech";
1013

@@ -26,6 +29,54 @@ test("ttsConfigSchema: accepts GGML supertonic load config", (t) => {
2629
t.is(r.success, true);
2730
});
2831

32+
test("TTS_CHATTERBOX_LANGUAGES: exposes all 18 supported languages", (t) => {
33+
t.is(TTS_CHATTERBOX_LANGUAGES.length, 18);
34+
const expected = [
35+
"en", "es", "fr", "de", "it", "pt", "nl", "pl", "tr",
36+
"sv", "da", "fi", "no", "el", "ms", "sw", "ar", "ko",
37+
];
38+
t.alike([...TTS_CHATTERBOX_LANGUAGES], expected);
39+
});
40+
41+
test("ttsChatterboxRuntimeConfigSchema: accepts all 18 chatterbox languages", (t) => {
42+
for (const language of TTS_CHATTERBOX_LANGUAGES) {
43+
const r = ttsChatterboxRuntimeConfigSchema.safeParse({
44+
ttsEngine: "chatterbox",
45+
language,
46+
});
47+
t.is(r.success, true, `chatterbox should accept ${language}`);
48+
}
49+
});
50+
51+
test("ttsSupertonicRuntimeConfigSchema: only accepts its language subset", (t) => {
52+
t.alike([...TTS_SUPERTONIC_LANGUAGES], ["en", "es", "fr", "pt", "ko"]);
53+
for (const language of TTS_SUPERTONIC_LANGUAGES) {
54+
const r = ttsSupertonicRuntimeConfigSchema.safeParse({
55+
ttsEngine: "supertonic",
56+
language,
57+
});
58+
t.is(r.success, true, `supertonic should accept ${language}`);
59+
}
60+
});
61+
62+
test("ttsSupertonicRuntimeConfigSchema: rejects chatterbox-only languages", (t) => {
63+
// 'de' is supported by chatterbox but not supertonic.
64+
const r = ttsSupertonicRuntimeConfigSchema.safeParse({
65+
ttsEngine: "supertonic",
66+
language: "de",
67+
});
68+
t.is(r.success, false, "supertonic must reject 'de'");
69+
});
70+
71+
test("ttsConfigSchema: accepts a chatterbox-only language for chatterbox", (t) => {
72+
const r = ttsConfigSchema.safeParse({
73+
ttsEngine: "chatterbox",
74+
language: "tr",
75+
s3genModelSrc: "s3:///example/s3gen.gguf",
76+
});
77+
t.is(r.success, true, "chatterbox load config accepts 'tr'");
78+
});
79+
2980
test("ttsSupertonicRuntimeConfigSchema: strips removed ttsSupertonicMultilingual", (t) => {
3081
const r = ttsSupertonicRuntimeConfigSchema.safeParse({
3182
ttsEngine: "supertonic",

0 commit comments

Comments
 (0)