import type { VoiceModelSpec, VoiceSpeaker } from '../../shared/voice'; const ASR = 'https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models'; const KWS = 'https://github.com/k2-fsa/sherpa-onnx/releases/download/kws-models'; const TTS = 'https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models'; const KOKORO_SPEAKERS: VoiceSpeaker[] = [ { id: 30, name: 'Siwis (femme, français)', lang: 'fr' }, { id: 3, name: 'Heart (femme, anglais US)', lang: 'en' }, { id: 2, name: 'Bella (femme, anglais US)', lang: 'en' }, { id: 7, name: 'Nova (femme, anglais US)', lang: 'en' }, { id: 11, name: 'Adam (homme, anglais US)', lang: 'en' }, { id: 16, name: 'Michael (homme, anglais US)', lang: 'en' }, { id: 17, name: 'Onyx (homme, anglais US)', lang: 'en' }, { id: 21, name: 'Emma (femme, anglais UK)', lang: 'en' }, { id: 24, name: 'Daniel (homme, anglais UK)', lang: 'en' }, { id: 26, name: 'George (homme, anglais UK)', lang: 'en' } ]; // Supertonic 3 ships ten voice styles in voice.bin (five feminine, five masculine). The ordering // was checked by measuring the fundamental frequency of French synthesis: sid 0-4 around // 170-210 Hz, sid 5-9 around 90-140 Hz. const SUPERTONIC_SPEAKERS: VoiceSpeaker[] = [ { id: 6, name: 'Homme 2 (grave, posé)', lang: 'multi', gender: 'm' }, { id: 9, name: 'Homme 5 (grave)', lang: 'multi', gender: 'm' }, { id: 7, name: 'Homme 3', lang: 'multi', gender: 'm' }, { id: 8, name: 'Homme 4', lang: 'multi', gender: 'm' }, { id: 5, name: 'Homme 1 (clair)', lang: 'multi', gender: 'm' }, { id: 0, name: 'Femme 1', lang: 'multi', gender: 'f' }, { id: 1, name: 'Femme 2', lang: 'multi', gender: 'f' }, { id: 2, name: 'Femme 3', lang: 'multi', gender: 'f' }, { id: 3, name: 'Femme 4', lang: 'multi', gender: 'f' }, { id: 4, name: 'Femme 5', lang: 'multi', gender: 'f' } ]; export const VOICE_CATALOG: VoiceModelSpec[] = [ { id: 'whisper-base', kind: 'stt', engine: 'whisper', name: 'Whisper base (multilingue)', description: 'Le plus rapide sur CPU ; précision moyenne en français, suffisante pour des commandes courtes.', languages: ['fr', 'en', 'multi'], sizeMb: 208, url: `${ASR}/sherpa-onnx-whisper-base.tar.bz2`, dir: 'sherpa-onnx-whisper-base', files: ['base-encoder.int8.onnx', 'base-decoder.int8.onnx', 'base-tokens.txt'], recommended: true }, { id: 'whisper-small', kind: 'stt', engine: 'whisper', name: 'Whisper small (multilingue)', description: 'Recommandé pour le français : nettement plus précis que base, environ trois fois plus lent.', languages: ['fr', 'en', 'multi'], sizeMb: 640, url: `${ASR}/sherpa-onnx-whisper-small.tar.bz2`, dir: 'sherpa-onnx-whisper-small', files: ['small-encoder.int8.onnx', 'small-decoder.int8.onnx', 'small-tokens.txt'], recommended: true }, { id: 'parakeet-v3', kind: 'stt', engine: 'nemo-transducer', name: 'Parakeet TDT 0.6B v3 (25 langues européennes, français)', description: 'Le plus précis en français et nettement plus rapide que Whisper sur processeur (NVIDIA NeMo, int8). Ponctuation et majuscules incluses.', languages: ['fr', 'en', 'de', 'es', 'it', 'multi'], sizeMb: 640, url: `${ASR}/sherpa-onnx-nemo-parakeet-tdt-0.6b-v3-int8.tar.bz2`, dir: 'sherpa-onnx-nemo-parakeet-tdt-0.6b-v3-int8', files: ['encoder.int8.onnx', 'decoder.int8.onnx', 'joiner.int8.onnx', 'tokens.txt'], recommended: true }, { id: 'whisper-turbo', kind: 'stt', engine: 'whisper', name: 'Whisper large-v3 turbo (multilingue)', description: 'Très bonne précision multilingue ; 2 à 4 s par phrase sur un processeur récent. Parakeet est plus rapide en français.', languages: ['fr', 'en', 'multi'], sizeMb: 564, url: `${ASR}/sherpa-onnx-whisper-turbo.tar.bz2`, dir: 'sherpa-onnx-whisper-turbo', files: ['turbo-encoder.int8.onnx', 'turbo-decoder.int8.onnx', 'turbo-tokens.txt'] }, { id: 'sense-voice', kind: 'stt', engine: 'sense-voice', name: 'SenseVoice small (zh / en / ja / ko)', description: 'Très rapide, mais ne comprend pas le français.', languages: ['en', 'zh', 'ja', 'ko'], sizeMb: 163, url: `${ASR}/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17.tar.bz2`, dir: 'sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17', files: ['model.int8.onnx', 'tokens.txt'] }, { id: 'kws-en', kind: 'kws', engine: 'kws-transducer', name: 'Détecteur de mot-clé (zipformer, 3 Mo)', description: 'Écoute permanente du mot d’activation, quasi gratuite en CPU. Mot-clé libre (« jarvis », « hey jarvis »…).', languages: ['en', 'fr'], sizeMb: 4, url: `${KWS}/sherpa-onnx-kws-zipformer-gigaspeech-3.3M-2024-01-01.tar.bz2`, dir: 'sherpa-onnx-kws-zipformer-gigaspeech-3.3M-2024-01-01', files: [ 'encoder-epoch-12-avg-2-chunk-16-left-64.int8.onnx', 'decoder-epoch-12-avg-2-chunk-16-left-64.int8.onnx', 'joiner-epoch-12-avg-2-chunk-16-left-64.int8.onnx', 'tokens.txt' ], recommended: true }, { id: 'silero-vad', kind: 'vad', engine: 'silero', name: 'Silero VAD (fin de phrase neuronale, 0,6 Mo)', description: 'Détecte précisément le début et la fin de la parole pendant l’écoute permanente ; moins de faux départs sur le bruit.', languages: ['multi'], sizeMb: 1, url: `${ASR}/silero_vad.onnx`, dir: 'silero-vad', files: ['silero_vad.onnx'], recommended: true }, { id: 'supertonic-3', kind: 'tts', engine: 'supertonic', name: 'Supertonic 3 (31 langues, 5 voix masculines et 5 féminines)', description: 'La meilleure voix française locale : naturelle, sans accent, dix voix au choix, 44 kHz. Environ 7 fois plus rapide que le temps réel sur 4 cœurs, 100 M de paramètres.', languages: ['fr', 'en', 'de', 'es', 'it', 'pt', 'multi'], sizeMb: 129, url: `${TTS}/sherpa-onnx-supertonic-3-tts-int8-2026-05-11.tar.bz2`, dir: 'sherpa-onnx-supertonic-3-tts-int8-2026-05-11', files: ['duration_predictor.int8.onnx', 'text_encoder.int8.onnx', 'vector_estimator.int8.onnx', 'vocoder.int8.onnx', 'tts.json', 'unicode_indexer.bin', 'voice.bin'], speakers: SUPERTONIC_SPEAKERS, sampleRate: 44100, recommended: true }, { id: 'kokoro-v1', kind: 'tts', engine: 'kokoro', name: 'Kokoro v1.0 multilingue', description: 'Excellent en anglais (nombreuses voix). En français : une seule voix, féminine (Siwis), avec un accent marqué (phonémisation espeak). Préférez Supertonic 3 pour le français. 24 kHz.', languages: ['en', 'fr', 'multi'], sizeMb: 349, url: `${TTS}/kokoro-multi-lang-v1_0.tar.bz2`, dir: 'kokoro-multi-lang-v1_0', files: ['model.onnx', 'voices.bin', 'tokens.txt', 'lexicon-us-en.txt', 'lexicon-zh.txt', 'espeak-ng-data/phontab'], speakers: KOKORO_SPEAKERS, sampleRate: 24000 }, { id: 'piper-fr-siwis', kind: 'tts', engine: 'piper', name: 'Piper Siwis (femme, français)', description: 'Léger et instantané, rendu un peu plus mécanique que Kokoro. 22 kHz.', languages: ['fr'], sizeMb: 67, url: `${TTS}/vits-piper-fr_FR-siwis-medium.tar.bz2`, dir: 'vits-piper-fr_FR-siwis-medium', files: ['fr_FR-siwis-medium.onnx', 'tokens.txt', 'espeak-ng-data/phontab'], speakers: [{ id: 0, name: 'Siwis', lang: 'fr' }], sampleRate: 22050 }, { id: 'piper-fr-tom', kind: 'tts', engine: 'piper', name: 'Piper Tom (homme, français)', description: 'Voix masculine légère et instantanée. 22 kHz.', languages: ['fr'], sizeMb: 67, url: `${TTS}/vits-piper-fr_FR-tom-medium.tar.bz2`, dir: 'vits-piper-fr_FR-tom-medium', files: ['fr_FR-tom-medium.onnx', 'tokens.txt', 'espeak-ng-data/phontab'], speakers: [{ id: 0, name: 'Tom', lang: 'fr' }], sampleRate: 22050 }, { id: 'piper-fr-upmc', kind: 'tts', engine: 'piper', name: 'Piper UPMC (Jessica et Pierre, français)', description: 'Deux voix françaises, une féminine et une masculine. 22 kHz.', languages: ['fr'], sizeMb: 80, url: `${TTS}/vits-piper-fr_FR-upmc-medium.tar.bz2`, dir: 'vits-piper-fr_FR-upmc-medium', files: ['fr_FR-upmc-medium.onnx', 'tokens.txt', 'espeak-ng-data/phontab'], speakers: [ { id: 0, name: 'Jessica (femme)', lang: 'fr' }, { id: 1, name: 'Pierre (homme)', lang: 'fr' } ], sampleRate: 22050 } ]; export function findModel(id: string): VoiceModelSpec | undefined { return VOICE_CATALOG.find((m) => m.id === id); } // Speaker gender from the label ("(homme, …)", "(femme, …)", known first names) so the UI and the // voice preference can pick a masculine or feminine voice without a lookup table per model. const MALE = /\b(homme|tom|pierre|adam|michael|eric|liam|george|lewis|daniel|fenrir|puck|onyx|echo|santa)\b/i; /** Languages accepted by the Supertonic 3 text front-end (2-letter codes). */ export const SUPERTONIC_LANGS = new Set(['ar', 'bg', 'hr', 'cs', 'da', 'nl', 'en', 'et', 'fi', 'fr', 'de', 'el', 'hi', 'hu', 'id', 'it', 'ja', 'ko', 'lv', 'lt', 'pl', 'pt', 'ro', 'ru', 'sk', 'sl', 'es', 'sv', 'tr', 'uk', 'vi']); for (const spec of VOICE_CATALOG) { for (const sp of spec.speakers ?? []) { if (!sp.gender) sp.gender = /\b(femme|female)\b/i.test(sp.name) ? 'f' : MALE.test(sp.name) ? 'm' : /\bfemme\b/i.test(spec.name) ? 'f' : /\bhomme\b/i.test(spec.name) ? 'm' : undefined; } }