speech: derive all model ids from sherpa catalog

This commit is contained in:
Mohamed Boudra
2026-02-06 22:08:01 +07:00
parent f98d844ff7
commit 56e75cf77d

View File

@@ -2,89 +2,21 @@ import { z } from "zod";
export type SherpaOnnxModelKind = "stt-online" | "stt-offline" | "tts";
const MODEL_IDS = {
ZIPFORMER_BILINGUAL_ZH_EN_2023_02_20: "zipformer-bilingual-zh-en-2023-02-20",
PARAFORMER_BILINGUAL_ZH_EN: "paraformer-bilingual-zh-en",
PARAKEET_TDT_0_6B_V3_INT8: "parakeet-tdt-0.6b-v3-int8",
KITTEN_NANO_EN_V0_1_FP16: "kitten-nano-en-v0_1-fp16",
KOKORO_EN_V0_19: "kokoro-en-v0_19",
POCKET_TTS_ONNX_INT8: "pocket-tts-onnx-int8",
} as const;
type DefaultModelRole = "stt" | "tts";
export type SherpaOnnxModelId = (typeof MODEL_IDS)[keyof typeof MODEL_IDS];
export const LOCAL_STT_MODEL_IDS = [
MODEL_IDS.ZIPFORMER_BILINGUAL_ZH_EN_2023_02_20,
MODEL_IDS.PARAFORMER_BILINGUAL_ZH_EN,
MODEL_IDS.PARAKEET_TDT_0_6B_V3_INT8,
] as const;
export type LocalSttModelId = (typeof LOCAL_STT_MODEL_IDS)[number];
export const LOCAL_TTS_MODEL_IDS = [
MODEL_IDS.KITTEN_NANO_EN_V0_1_FP16,
MODEL_IDS.KOKORO_EN_V0_19,
MODEL_IDS.POCKET_TTS_ONNX_INT8,
] as const;
export type LocalTtsModelId = (typeof LOCAL_TTS_MODEL_IDS)[number];
export const DEFAULT_LOCAL_STT_MODEL: LocalSttModelId = MODEL_IDS.PARAKEET_TDT_0_6B_V3_INT8;
export const DEFAULT_LOCAL_TTS_MODEL: LocalTtsModelId = MODEL_IDS.POCKET_TTS_ONNX_INT8;
const STT_MODEL_ALIASES: Record<string, LocalSttModelId> = {
zipformer: MODEL_IDS.ZIPFORMER_BILINGUAL_ZH_EN_2023_02_20,
"zipformer-bilingual": MODEL_IDS.ZIPFORMER_BILINGUAL_ZH_EN_2023_02_20,
paraformer: MODEL_IDS.PARAFORMER_BILINGUAL_ZH_EN,
parakeet: MODEL_IDS.PARAKEET_TDT_0_6B_V3_INT8,
"parakeet-v3": MODEL_IDS.PARAKEET_TDT_0_6B_V3_INT8,
"parakeet-tdt": MODEL_IDS.PARAKEET_TDT_0_6B_V3_INT8,
};
const TTS_MODEL_ALIASES: Record<string, LocalTtsModelId> = {
pocket: MODEL_IDS.POCKET_TTS_ONNX_INT8,
"pocket-tts": MODEL_IDS.POCKET_TTS_ONNX_INT8,
kitten: MODEL_IDS.KITTEN_NANO_EN_V0_1_FP16,
kokoro: MODEL_IDS.KOKORO_EN_V0_19,
};
function createAliasedModelIdSchema<T extends readonly [string, ...string[]]>(
values: T,
aliases: Record<string, T[number]>
) {
return z.preprocess((value) => {
if (typeof value !== "string") {
return value;
}
const normalized = value.trim().toLowerCase();
if (!normalized) {
return value;
}
return aliases[normalized] ?? normalized;
}, z.enum(values));
}
export const LocalSttModelIdSchema = createAliasedModelIdSchema(
LOCAL_STT_MODEL_IDS,
STT_MODEL_ALIASES
);
export const LocalTtsModelIdSchema = createAliasedModelIdSchema(
LOCAL_TTS_MODEL_IDS,
TTS_MODEL_ALIASES
);
export type SherpaOnnxModelSpec = {
id: SherpaOnnxModelId;
type SherpaOnnxCatalogEntry = {
kind: SherpaOnnxModelKind;
archiveUrl?: string;
downloadFiles?: Array<{ url: string; relPath: string }>;
extractedDir: string;
requiredFiles: string[];
description: string;
aliases?: readonly string[];
defaultFor?: DefaultModelRole;
};
export const SHERPA_ONNX_MODEL_CATALOG: Record<SherpaOnnxModelId, SherpaOnnxModelSpec> = {
[MODEL_IDS.ZIPFORMER_BILINGUAL_ZH_EN_2023_02_20]: {
id: MODEL_IDS.ZIPFORMER_BILINGUAL_ZH_EN_2023_02_20,
export const SHERPA_ONNX_MODEL_CATALOG = {
"zipformer-bilingual-zh-en-2023-02-20": {
kind: "stt-online",
archiveUrl:
"https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-streaming-zipformer-bilingual-zh-en-2023-02-20.tar.bz2",
@@ -96,44 +28,45 @@ export const SHERPA_ONNX_MODEL_CATALOG: Record<SherpaOnnxModelId, SherpaOnnxMode
"tokens.txt",
],
description: "Streaming Zipformer transducer (fast, good accuracy).",
aliases: ["zipformer", "zipformer-bilingual"],
},
[MODEL_IDS.PARAFORMER_BILINGUAL_ZH_EN]: {
id: MODEL_IDS.PARAFORMER_BILINGUAL_ZH_EN,
"paraformer-bilingual-zh-en": {
kind: "stt-online",
archiveUrl:
"https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-streaming-paraformer-bilingual-zh-en.tar.bz2",
extractedDir: "sherpa-onnx-streaming-paraformer-bilingual-zh-en",
requiredFiles: ["encoder.int8.onnx", "decoder.int8.onnx", "tokens.txt"],
description: "Streaming Paraformer (often strong accuracy; heavier).",
aliases: ["paraformer"],
},
[MODEL_IDS.PARAKEET_TDT_0_6B_V3_INT8]: {
id: MODEL_IDS.PARAKEET_TDT_0_6B_V3_INT8,
"parakeet-tdt-0.6b-v3-int8": {
kind: "stt-offline",
archiveUrl:
"https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-nemo-parakeet-tdt-0.6b-v3-int8.tar.bz2",
extractedDir: "sherpa-onnx-nemo-parakeet-tdt-0.6b-v3-int8",
requiredFiles: ["encoder.int8.onnx", "decoder.int8.onnx", "joiner.int8.onnx", "tokens.txt"],
description: "NVIDIA Parakeet TDT v3 (offline NeMo transducer, multilingual).",
aliases: ["parakeet", "parakeet-v3", "parakeet-tdt"],
defaultFor: "stt",
},
[MODEL_IDS.KITTEN_NANO_EN_V0_1_FP16]: {
id: MODEL_IDS.KITTEN_NANO_EN_V0_1_FP16,
"kitten-nano-en-v0_1-fp16": {
kind: "tts",
archiveUrl:
"https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kitten-nano-en-v0_1-fp16.tar.bz2",
extractedDir: "kitten-nano-en-v0_1-fp16",
requiredFiles: ["model.fp16.onnx", "voices.bin", "tokens.txt", "espeak-ng-data"],
description: "KittenTTS (small, fast English TTS).",
aliases: ["kitten"],
},
[MODEL_IDS.KOKORO_EN_V0_19]: {
id: MODEL_IDS.KOKORO_EN_V0_19,
"kokoro-en-v0_19": {
kind: "tts",
archiveUrl: "https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kokoro-en-v0_19.tar.bz2",
extractedDir: "kokoro-en-v0_19",
requiredFiles: ["model.onnx", "voices.bin", "tokens.txt", "espeak-ng-data"],
description: "Kokoro TTS (higher quality; larger).",
aliases: ["kokoro"],
},
[MODEL_IDS.POCKET_TTS_ONNX_INT8]: {
id: MODEL_IDS.POCKET_TTS_ONNX_INT8,
"pocket-tts-onnx-int8": {
kind: "tts",
extractedDir: "pocket-tts-onnx-int8",
downloadFiles: [
@@ -176,11 +109,98 @@ export const SHERPA_ONNX_MODEL_CATALOG: Record<SherpaOnnxModelId, SherpaOnnxMode
"reference_sample.wav",
],
description: "Pocket TTS ONNX (INT8) with streaming decode support (via onnxruntime).",
aliases: ["pocket", "pocket-tts"],
defaultFor: "tts",
},
} as const satisfies Record<string, SherpaOnnxCatalogEntry>;
export type SherpaOnnxModelId = keyof typeof SHERPA_ONNX_MODEL_CATALOG;
type ModelIdByKind<K extends SherpaOnnxModelKind> = {
[Id in SherpaOnnxModelId]: (typeof SHERPA_ONNX_MODEL_CATALOG)[Id]["kind"] extends K
? Id
: never;
}[SherpaOnnxModelId];
export type LocalSttModelId = ModelIdByKind<"stt-online"> | ModelIdByKind<"stt-offline">;
export type LocalTtsModelId = ModelIdByKind<"tts">;
const ALL_MODEL_IDS = Object.keys(SHERPA_ONNX_MODEL_CATALOG) as SherpaOnnxModelId[];
export const LOCAL_STT_MODEL_IDS = ALL_MODEL_IDS.filter(
(id): id is LocalSttModelId => SHERPA_ONNX_MODEL_CATALOG[id].kind !== "tts"
);
export const LOCAL_TTS_MODEL_IDS = ALL_MODEL_IDS.filter(
(id): id is LocalTtsModelId => SHERPA_ONNX_MODEL_CATALOG[id].kind === "tts"
);
function resolveDefaultModelId(role: "stt"): LocalSttModelId;
function resolveDefaultModelId(role: "tts"): LocalTtsModelId;
function resolveDefaultModelId(role: DefaultModelRole): SherpaOnnxModelId {
const match = ALL_MODEL_IDS.find((id) => {
const entry: SherpaOnnxCatalogEntry = SHERPA_ONNX_MODEL_CATALOG[id];
return entry.defaultFor === role;
});
if (!match) {
throw new Error(`No default model configured for role '${role}'`);
}
return match;
}
export const DEFAULT_LOCAL_STT_MODEL = resolveDefaultModelId("stt");
export const DEFAULT_LOCAL_TTS_MODEL = resolveDefaultModelId("tts");
function buildAliasMap<T extends string>(modelIds: readonly T[]): Record<string, T> {
const aliasMap: Record<string, T> = {};
for (const modelId of modelIds) {
const aliases = SHERPA_ONNX_MODEL_CATALOG[modelId as SherpaOnnxModelId].aliases ?? [];
for (const alias of aliases) {
aliasMap[alias.trim().toLowerCase()] = modelId;
}
}
return aliasMap;
}
function createAliasedModelIdSchema<T extends string>(params: {
modelIds: readonly T[];
aliases: Record<string, T>;
}): z.ZodType<T> {
const validIds = new Set(params.modelIds);
return z.preprocess((value) => {
if (typeof value !== "string") {
return value;
}
const normalized = value.trim().toLowerCase();
if (!normalized) {
return value;
}
return params.aliases[normalized] ?? normalized;
}, z.string().refine((value): value is T => validIds.has(value as T))) as z.ZodType<T>;
}
const STT_MODEL_ALIASES = buildAliasMap(LOCAL_STT_MODEL_IDS);
const TTS_MODEL_ALIASES = buildAliasMap(LOCAL_TTS_MODEL_IDS);
export const LocalSttModelIdSchema = createAliasedModelIdSchema({
modelIds: LOCAL_STT_MODEL_IDS,
aliases: STT_MODEL_ALIASES,
});
export const LocalTtsModelIdSchema = createAliasedModelIdSchema({
modelIds: LOCAL_TTS_MODEL_IDS,
aliases: TTS_MODEL_ALIASES,
});
export type SherpaOnnxModelSpec = SherpaOnnxCatalogEntry & {
id: SherpaOnnxModelId;
};
export function listSherpaOnnxModels(): SherpaOnnxModelSpec[] {
return Object.values(SHERPA_ONNX_MODEL_CATALOG);
return ALL_MODEL_IDS.map((id) => ({
id,
...SHERPA_ONNX_MODEL_CATALOG[id],
}));
}
export function getSherpaOnnxModelSpec(id: SherpaOnnxModelId): SherpaOnnxModelSpec {
@@ -188,5 +208,8 @@ export function getSherpaOnnxModelSpec(id: SherpaOnnxModelId): SherpaOnnxModelSp
if (!spec) {
throw new Error(`Unknown sherpa-onnx model id: ${id}`);
}
return spec;
return {
id,
...spec,
};
}