speech: derive all model ids from sherpa catalog
This commit is contained in:
@@ -2,89 +2,21 @@ import { z } from "zod";
|
|||||||
|
|
||||||
export type SherpaOnnxModelKind = "stt-online" | "stt-offline" | "tts";
|
export type SherpaOnnxModelKind = "stt-online" | "stt-offline" | "tts";
|
||||||
|
|
||||||
const MODEL_IDS = {
|
type DefaultModelRole = "stt" | "tts";
|
||||||
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;
|
|
||||||
|
|
||||||
export type SherpaOnnxModelId = (typeof MODEL_IDS)[keyof typeof MODEL_IDS];
|
type SherpaOnnxCatalogEntry = {
|
||||||
|
|
||||||
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;
|
|
||||||
kind: SherpaOnnxModelKind;
|
kind: SherpaOnnxModelKind;
|
||||||
archiveUrl?: string;
|
archiveUrl?: string;
|
||||||
downloadFiles?: Array<{ url: string; relPath: string }>;
|
downloadFiles?: Array<{ url: string; relPath: string }>;
|
||||||
extractedDir: string;
|
extractedDir: string;
|
||||||
requiredFiles: string[];
|
requiredFiles: string[];
|
||||||
description: string;
|
description: string;
|
||||||
|
aliases?: readonly string[];
|
||||||
|
defaultFor?: DefaultModelRole;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SHERPA_ONNX_MODEL_CATALOG: Record<SherpaOnnxModelId, SherpaOnnxModelSpec> = {
|
export const SHERPA_ONNX_MODEL_CATALOG = {
|
||||||
[MODEL_IDS.ZIPFORMER_BILINGUAL_ZH_EN_2023_02_20]: {
|
"zipformer-bilingual-zh-en-2023-02-20": {
|
||||||
id: MODEL_IDS.ZIPFORMER_BILINGUAL_ZH_EN_2023_02_20,
|
|
||||||
kind: "stt-online",
|
kind: "stt-online",
|
||||||
archiveUrl:
|
archiveUrl:
|
||||||
"https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-streaming-zipformer-bilingual-zh-en-2023-02-20.tar.bz2",
|
"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",
|
"tokens.txt",
|
||||||
],
|
],
|
||||||
description: "Streaming Zipformer transducer (fast, good accuracy).",
|
description: "Streaming Zipformer transducer (fast, good accuracy).",
|
||||||
|
aliases: ["zipformer", "zipformer-bilingual"],
|
||||||
},
|
},
|
||||||
[MODEL_IDS.PARAFORMER_BILINGUAL_ZH_EN]: {
|
"paraformer-bilingual-zh-en": {
|
||||||
id: MODEL_IDS.PARAFORMER_BILINGUAL_ZH_EN,
|
|
||||||
kind: "stt-online",
|
kind: "stt-online",
|
||||||
archiveUrl:
|
archiveUrl:
|
||||||
"https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-streaming-paraformer-bilingual-zh-en.tar.bz2",
|
"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",
|
extractedDir: "sherpa-onnx-streaming-paraformer-bilingual-zh-en",
|
||||||
requiredFiles: ["encoder.int8.onnx", "decoder.int8.onnx", "tokens.txt"],
|
requiredFiles: ["encoder.int8.onnx", "decoder.int8.onnx", "tokens.txt"],
|
||||||
description: "Streaming Paraformer (often strong accuracy; heavier).",
|
description: "Streaming Paraformer (often strong accuracy; heavier).",
|
||||||
|
aliases: ["paraformer"],
|
||||||
},
|
},
|
||||||
[MODEL_IDS.PARAKEET_TDT_0_6B_V3_INT8]: {
|
"parakeet-tdt-0.6b-v3-int8": {
|
||||||
id: MODEL_IDS.PARAKEET_TDT_0_6B_V3_INT8,
|
|
||||||
kind: "stt-offline",
|
kind: "stt-offline",
|
||||||
archiveUrl:
|
archiveUrl:
|
||||||
"https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-nemo-parakeet-tdt-0.6b-v3-int8.tar.bz2",
|
"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",
|
extractedDir: "sherpa-onnx-nemo-parakeet-tdt-0.6b-v3-int8",
|
||||||
requiredFiles: ["encoder.int8.onnx", "decoder.int8.onnx", "joiner.int8.onnx", "tokens.txt"],
|
requiredFiles: ["encoder.int8.onnx", "decoder.int8.onnx", "joiner.int8.onnx", "tokens.txt"],
|
||||||
description: "NVIDIA Parakeet TDT v3 (offline NeMo transducer, multilingual).",
|
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]: {
|
"kitten-nano-en-v0_1-fp16": {
|
||||||
id: MODEL_IDS.KITTEN_NANO_EN_V0_1_FP16,
|
|
||||||
kind: "tts",
|
kind: "tts",
|
||||||
archiveUrl:
|
archiveUrl:
|
||||||
"https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kitten-nano-en-v0_1-fp16.tar.bz2",
|
"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",
|
extractedDir: "kitten-nano-en-v0_1-fp16",
|
||||||
requiredFiles: ["model.fp16.onnx", "voices.bin", "tokens.txt", "espeak-ng-data"],
|
requiredFiles: ["model.fp16.onnx", "voices.bin", "tokens.txt", "espeak-ng-data"],
|
||||||
description: "KittenTTS (small, fast English TTS).",
|
description: "KittenTTS (small, fast English TTS).",
|
||||||
|
aliases: ["kitten"],
|
||||||
},
|
},
|
||||||
[MODEL_IDS.KOKORO_EN_V0_19]: {
|
"kokoro-en-v0_19": {
|
||||||
id: MODEL_IDS.KOKORO_EN_V0_19,
|
|
||||||
kind: "tts",
|
kind: "tts",
|
||||||
archiveUrl: "https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kokoro-en-v0_19.tar.bz2",
|
archiveUrl: "https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kokoro-en-v0_19.tar.bz2",
|
||||||
extractedDir: "kokoro-en-v0_19",
|
extractedDir: "kokoro-en-v0_19",
|
||||||
requiredFiles: ["model.onnx", "voices.bin", "tokens.txt", "espeak-ng-data"],
|
requiredFiles: ["model.onnx", "voices.bin", "tokens.txt", "espeak-ng-data"],
|
||||||
description: "Kokoro TTS (higher quality; larger).",
|
description: "Kokoro TTS (higher quality; larger).",
|
||||||
|
aliases: ["kokoro"],
|
||||||
},
|
},
|
||||||
[MODEL_IDS.POCKET_TTS_ONNX_INT8]: {
|
"pocket-tts-onnx-int8": {
|
||||||
id: MODEL_IDS.POCKET_TTS_ONNX_INT8,
|
|
||||||
kind: "tts",
|
kind: "tts",
|
||||||
extractedDir: "pocket-tts-onnx-int8",
|
extractedDir: "pocket-tts-onnx-int8",
|
||||||
downloadFiles: [
|
downloadFiles: [
|
||||||
@@ -176,11 +109,98 @@ export const SHERPA_ONNX_MODEL_CATALOG: Record<SherpaOnnxModelId, SherpaOnnxMode
|
|||||||
"reference_sample.wav",
|
"reference_sample.wav",
|
||||||
],
|
],
|
||||||
description: "Pocket TTS ONNX (INT8) with streaming decode support (via onnxruntime).",
|
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[] {
|
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 {
|
export function getSherpaOnnxModelSpec(id: SherpaOnnxModelId): SherpaOnnxModelSpec {
|
||||||
@@ -188,5 +208,8 @@ export function getSherpaOnnxModelSpec(id: SherpaOnnxModelId): SherpaOnnxModelSp
|
|||||||
if (!spec) {
|
if (!spec) {
|
||||||
throw new Error(`Unknown sherpa-onnx model id: ${id}`);
|
throw new Error(`Unknown sherpa-onnx model id: ${id}`);
|
||||||
}
|
}
|
||||||
return spec;
|
return {
|
||||||
|
id,
|
||||||
|
...spec,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user