1use std::collections::BTreeMap;
7
8use serde::{Deserialize, Deserializer, Serialize, Serializer};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15pub enum TaskKind {
16 Vad,
18 Asr,
20 Diar,
22 SourceSeparation,
24 AudioGeneration,
26 Tts,
28 VoiceCloning,
30 VoiceConversion,
32 SpeechToSpeech,
34 Alignment,
36 VoiceDesign,
38 SpeakerRecognition,
40 Svc,
42 Midi,
44 TurnDetection,
46}
47
48impl TaskKind {
49 pub fn as_str(self) -> &'static str {
51 match self {
52 TaskKind::Vad => "vad",
53 TaskKind::Asr => "asr",
54 TaskKind::Diar => "diar",
55 TaskKind::SourceSeparation => "sep",
56 TaskKind::AudioGeneration => "gen",
57 TaskKind::Tts => "tts",
58 TaskKind::VoiceCloning => "clon",
59 TaskKind::VoiceConversion => "vc",
60 TaskKind::SpeechToSpeech => "s2s",
61 TaskKind::Alignment => "align",
62 TaskKind::VoiceDesign => "vdes",
63 TaskKind::SpeakerRecognition => "spk",
64 TaskKind::Svc => "svc",
65 TaskKind::Midi => "midi",
66 TaskKind::TurnDetection => "turn",
67 }
68 }
69}
70
71impl Serialize for TaskKind {
72 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
73 serializer.serialize_str(self.as_str())
74 }
75}
76
77impl<'de> Deserialize<'de> for TaskKind {
78 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
79 let s = String::deserialize(deserializer)?;
80 match s.as_str() {
81 "vad" => Ok(TaskKind::Vad),
82 "asr" => Ok(TaskKind::Asr),
83 "diar" => Ok(TaskKind::Diar),
84 "sep" => Ok(TaskKind::SourceSeparation),
85 "gen" => Ok(TaskKind::AudioGeneration),
86 "tts" => Ok(TaskKind::Tts),
87 "clon" => Ok(TaskKind::VoiceCloning),
88 "vc" => Ok(TaskKind::VoiceConversion),
89 "s2s" => Ok(TaskKind::SpeechToSpeech),
90 "align" => Ok(TaskKind::Alignment),
91 "vdes" => Ok(TaskKind::VoiceDesign),
92 "spk" => Ok(TaskKind::SpeakerRecognition),
93 "svc" => Ok(TaskKind::Svc),
94 "midi" => Ok(TaskKind::Midi),
95 "turn" => Ok(TaskKind::TurnDetection),
96 other => Err(serde::de::Error::unknown_variant(
97 other,
98 &[
99 "vad", "asr", "diar", "sep", "gen", "tts", "clon", "vc", "s2s", "align",
100 "vdes", "spk", "svc", "midi", "turn",
101 ],
102 )),
103 }
104 }
105}
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
109#[serde(rename_all = "lowercase")]
110pub enum RunMode {
111 Offline,
113 Streaming,
115}
116
117impl RunMode {
118 pub fn as_str(self) -> &'static str {
120 match self {
121 RunMode::Offline => "offline",
122 RunMode::Streaming => "streaming",
123 }
124 }
125}
126
127#[derive(Debug, Clone, PartialEq, Eq, Hash)]
137pub enum ModelFamily {
138 SileroVad,
141 MarblenetVad,
143 Pulsevad,
146
147 Qwen3Asr,
150 CitrinetAsr,
152 SenseAsr,
154 FunAsrNano,
156 HiggsAudioStt,
158 HviskeAsr,
160 KrokoAsr,
162 NemotronAsr,
164 Nemotron3Diar,
168 ParakeetTdt,
170 VibevoiceAsr,
172 VibevoiceAsrStreaming,
175 FireredAudio,
177 Granite5Asr,
179 Audio8Asr,
181 Audio8Tts,
183 Vibeasr,
185 MoonshineAsr,
187 NiagaraAsr,
189 CanaryAsr,
192 CohereAsr,
195 MossTranscribeDiarize,
198 Confucius4R2t2,
200 AudioFlamingo,
202 Crisperwhisper,
204 GigaamAsr,
206 IndexEcho,
208 Lfm2Audio,
210 Owsm,
212 OwsmCtc,
214 Samsone,
217
218 Qwen3Tts,
221 Confucius4Tts,
223 DotsTts,
225 FishAudio,
227 GlmTts,
229 HiggsAudioTts,
231 IndexTts2,
233 IrodoriTts,
235 MossTtsLocal,
237 MossTtsNano,
239 MossTtsV15,
243 MossVoicegen,
245 Neutts,
247 Outetts,
249 PocketTts,
251 VieneuV3Turbo,
255 Fireredtts3,
257 F5Tts,
259 MagpieTts,
261 Personaplex,
263 MinimaxH3,
265 Sanotts,
267 SoproTts,
269 MiraTts,
271 Cosyvoice3,
273 BreezeTts,
275 SopranoTts,
277 EchoTts,
279 Voxcpm1,
281 KokoroTts,
283 Zipvoice,
286 Auk,
289 PiperTts,
292 KittenTts,
295 KittenTts2,
298 Kugelaudio,
300 Maya1,
303 MossTtsd,
306
307 SortformerDiar,
310 SortformerDiarV2,
313 SeedVc,
315 Rvc,
317 Meanvc2,
319 ToneColorVc,
321 Chatterbox,
323 ChatterboxTurbo,
325 Vevo2,
327 Voxcpm2,
329 AceStep,
331
332 Htdemucs,
335 Htdemucs6Stems,
338 MelBandRoformer,
340 BsRoformer,
342 Muscriptor,
344 Omnivoice,
346 StableAudio,
348 MinimaxMusic3,
350 Supertonic,
352 Yue2,
355 Sheetsage2,
358 VoxtralRealtime,
360 Audiosr,
362 Apollo,
364 Universr,
368 BuiltinAudioUtils,
373 ControlFoley,
375 MidashEnglmGen,
377 Liveavatar,
380 Reuse,
382 SamAudio,
384 Sidon,
386 SmartTurn,
390
391 Miocodec,
394 Miotts,
396 Vibevoice,
398 Dramabox,
400 Heartmula,
402 InflectV2,
404 Qwen3ForcedAligner,
406 MmsForcedAligner,
408
409 Custom(String),
411}
412
413impl ModelFamily {
414 pub fn from_path(path: &str) -> Option<ModelFamily> {
442 let lower = path.to_ascii_lowercase();
443 if let Some((_, f)) = lower.rsplit_once("#family=") {
445 return Some(ModelFamily::from(f.trim()));
446 }
447 const KEYWORDS: &[(&str, ModelFamily)] = &[
449 ("silero_vad", ModelFamily::SileroVad),
450 ("silero-vad", ModelFamily::SileroVad),
451 ("marblenet_vad", ModelFamily::MarblenetVad),
452 ("marblenet-vad", ModelFamily::MarblenetVad),
453 ("marblenet", ModelFamily::MarblenetVad),
454 ("pulsevad", ModelFamily::Pulsevad),
455 ("pulse-vad", ModelFamily::Pulsevad),
456 ("pulse", ModelFamily::Pulsevad),
457 ("qwen3_asr", ModelFamily::Qwen3Asr),
458 ("qwen3-asr", ModelFamily::Qwen3Asr),
459 ("qwen3_tts", ModelFamily::Qwen3Tts),
460 ("qwen3-tts", ModelFamily::Qwen3Tts),
461 ("qwen3_forced_aligner", ModelFamily::Qwen3ForcedAligner),
462 ("qwen3-forced-aligner", ModelFamily::Qwen3ForcedAligner),
463 ("qwen3", ModelFamily::Qwen3Asr),
464 ("citrinet", ModelFamily::CitrinetAsr),
465 ("sense_asr", ModelFamily::SenseAsr),
466 ("sense-asr", ModelFamily::SenseAsr),
467 ("sensevoice", ModelFamily::SenseAsr),
468 ("fun-asr-nano", ModelFamily::FunAsrNano),
469 ("fun_asr_nano", ModelFamily::FunAsrNano),
470 ("funasr", ModelFamily::FunAsrNano),
471 ("higgs_audio_stt", ModelFamily::HiggsAudioStt),
472 ("higgs_audio_tts", ModelFamily::HiggsAudioTts),
473 ("higgs", ModelFamily::HiggsAudioStt),
474 ("hviske", ModelFamily::HviskeAsr),
475 ("kroko", ModelFamily::KrokoAsr),
476 ("nemotron_3_diar", ModelFamily::Nemotron3Diar),
477 ("nemotron-3-diar", ModelFamily::Nemotron3Diar),
478 ("nemotron_3", ModelFamily::Nemotron3Diar),
479 ("nemotron-3", ModelFamily::Nemotron3Diar),
480 ("nemotron", ModelFamily::NemotronAsr),
481 ("parakeet", ModelFamily::ParakeetTdt),
482 (
483 "vibevoice_asr_streaming",
484 ModelFamily::VibevoiceAsrStreaming,
485 ),
486 (
487 "vibevoice-asr-streaming",
488 ModelFamily::VibevoiceAsrStreaming,
489 ),
490 ("vibevoice_asr", ModelFamily::VibevoiceAsr),
491 ("firered_audio", ModelFamily::FireredAudio),
492 ("firered-audio", ModelFamily::FireredAudio),
493 ("granite5asr", ModelFamily::Granite5Asr),
494 ("granite-speech", ModelFamily::Granite5Asr),
495 ("granite_speech", ModelFamily::Granite5Asr),
496 ("granite", ModelFamily::Granite5Asr),
497 ("audio8_asr", ModelFamily::Audio8Asr),
498 ("audio8-asr", ModelFamily::Audio8Asr),
499 ("audio8asr", ModelFamily::Audio8Asr),
500 ("arkasr", ModelFamily::Audio8Asr),
501 ("audio8_tts", ModelFamily::Audio8Tts),
502 ("audio8-tts", ModelFamily::Audio8Tts),
503 ("audio8tts", ModelFamily::Audio8Tts),
504 ("fireredtts3", ModelFamily::Fireredtts3),
505 ("firered_tts3", ModelFamily::Fireredtts3),
506 ("firered-tts3", ModelFamily::Fireredtts3),
507 ("vibevoice", ModelFamily::Vibevoice),
508 ("confucius4_r2t2", ModelFamily::Confucius4R2t2),
510 ("confucius4-r2t2", ModelFamily::Confucius4R2t2),
511 ("r2t2", ModelFamily::Confucius4R2t2),
512 ("confucius", ModelFamily::Confucius4Tts),
513 ("dots_tts", ModelFamily::DotsTts),
514 ("dots-tts", ModelFamily::DotsTts),
515 ("fish_audio", ModelFamily::FishAudio),
516 ("fish-audio", ModelFamily::FishAudio),
517 ("glm_tts", ModelFamily::GlmTts),
518 ("glm-tts", ModelFamily::GlmTts),
519 ("index_tts2", ModelFamily::IndexTts2),
520 ("index-tts2", ModelFamily::IndexTts2),
521 ("irodori", ModelFamily::IrodoriTts),
522 (
524 "moss_transcribe_diarize",
525 ModelFamily::MossTranscribeDiarize,
526 ),
527 (
528 "moss-transcribe-diarize",
529 ModelFamily::MossTranscribeDiarize,
530 ),
531 ("moss-tts-nano", ModelFamily::MossTtsNano),
532 ("moss_tts_nano", ModelFamily::MossTtsNano),
533 ("moss-tts-local", ModelFamily::MossTtsLocal),
534 ("moss_tts_local", ModelFamily::MossTtsLocal),
535 ("moss-tts-v15", ModelFamily::MossTtsV15),
537 ("moss_tts_v15", ModelFamily::MossTtsV15),
538 ("moss_ttsd", ModelFamily::MossTtsd),
539 ("moss-ttsd", ModelFamily::MossTtsd),
540 ("mossttsd", ModelFamily::MossTtsd),
541 ("moss_voicegen", ModelFamily::MossVoicegen),
542 ("moss-voicegen", ModelFamily::MossVoicegen),
543 ("moss", ModelFamily::MossTtsNano),
544 ("neutts", ModelFamily::Neutts),
545 ("outetts", ModelFamily::Outetts),
546 ("pocket_tts", ModelFamily::PocketTts),
547 ("pocket-tts", ModelFamily::PocketTts),
548 ("vietneu", ModelFamily::VieneuV3Turbo),
549 ("vieneu", ModelFamily::VieneuV3Turbo),
550 ("f5_tts", ModelFamily::F5Tts),
551 ("f5-tts", ModelFamily::F5Tts),
552 ("magpie", ModelFamily::MagpieTts),
553 ("personaplex", ModelFamily::Personaplex),
554 ("soprano_tts", ModelFamily::SopranoTts),
555 ("soprano-tts", ModelFamily::SopranoTts),
556 ("soprano", ModelFamily::SopranoTts),
557 ("index_echo", ModelFamily::IndexEcho),
559 ("index-echo", ModelFamily::IndexEcho),
560 ("indexecho", ModelFamily::IndexEcho),
561 ("echo_tts", ModelFamily::EchoTts),
562 ("echo-tts", ModelFamily::EchoTts),
563 ("echo", ModelFamily::EchoTts),
564 ("kokoro_tts", ModelFamily::KokoroTts),
565 ("kokoro-tts", ModelFamily::KokoroTts),
566 ("kokoro", ModelFamily::KokoroTts),
567 ("piper_tts", ModelFamily::PiperTts),
568 ("piper-tts", ModelFamily::PiperTts),
569 ("piper", ModelFamily::PiperTts),
570 ("kitten_tts2", ModelFamily::KittenTts2),
572 ("kitten-tts2", ModelFamily::KittenTts2),
573 ("kitten_tts_2", ModelFamily::KittenTts2),
574 ("kittentts2", ModelFamily::KittenTts2),
575 ("kitten_tts", ModelFamily::KittenTts),
576 ("kitten-tts", ModelFamily::KittenTts),
577 ("kitten", ModelFamily::KittenTts),
578 ("kugelaudio", ModelFamily::Kugelaudio),
579 ("kugel-audio", ModelFamily::Kugelaudio),
580 ("kugel_audio", ModelFamily::Kugelaudio),
581 ("kugel", ModelFamily::Kugelaudio),
582 ("maya1", ModelFamily::Maya1),
583 ("maya-1", ModelFamily::Maya1),
584 ("maya_1", ModelFamily::Maya1),
585 ("maya", ModelFamily::Maya1),
586 ("voxcpm1", ModelFamily::Voxcpm1),
587 ("voxcpm-1", ModelFamily::Voxcpm1),
588 ("sanotts", ModelFamily::Sanotts),
589 ("sano-tts", ModelFamily::Sanotts),
590 ("sano_tts", ModelFamily::Sanotts),
591 ("sopro_tts", ModelFamily::SoproTts),
592 ("sopro-tts", ModelFamily::SoproTts),
593 ("sopro", ModelFamily::SoproTts),
594 ("mira_tts", ModelFamily::MiraTts),
595 ("mira-tts", ModelFamily::MiraTts),
596 ("miratts", ModelFamily::MiraTts),
597 ("mira", ModelFamily::MiraTts),
598 ("cosyvoice3", ModelFamily::Cosyvoice3),
599 ("cosyvoice-3", ModelFamily::Cosyvoice3),
600 ("cosyvoice", ModelFamily::Cosyvoice3),
601 ("breeze_tts", ModelFamily::BreezeTts),
602 ("breeze-tts", ModelFamily::BreezeTts),
603 ("breeze", ModelFamily::BreezeTts),
604 ("vibeasr", ModelFamily::Vibeasr),
605 ("vibe-asr", ModelFamily::Vibeasr),
606 ("moonshine_asr", ModelFamily::MoonshineAsr),
607 ("moonshine-asr", ModelFamily::MoonshineAsr),
608 ("moonshine", ModelFamily::MoonshineAsr),
609 ("niagara_asr", ModelFamily::NiagaraAsr),
610 ("niagara-asr", ModelFamily::NiagaraAsr),
611 ("niagara", ModelFamily::NiagaraAsr),
612 ("canary_asr", ModelFamily::CanaryAsr),
613 ("canary-asr", ModelFamily::CanaryAsr),
614 ("canary", ModelFamily::CanaryAsr),
615 ("cohere_asr", ModelFamily::CohereAsr),
616 ("cohere-asr", ModelFamily::CohereAsr),
617 ("cohere", ModelFamily::CohereAsr),
618 ("audio_flamingo", ModelFamily::AudioFlamingo),
619 ("audio-flamingo", ModelFamily::AudioFlamingo),
620 ("audioflamingo", ModelFamily::AudioFlamingo),
621 ("crisperwhisper", ModelFamily::Crisperwhisper),
622 ("crisper-whisper", ModelFamily::Crisperwhisper),
623 ("crisper_whisper", ModelFamily::Crisperwhisper),
624 ("gigaam_asr", ModelFamily::GigaamAsr),
625 ("gigaam-asr", ModelFamily::GigaamAsr),
626 ("gigaam", ModelFamily::GigaamAsr),
627 ("lfm2_audio", ModelFamily::Lfm2Audio),
628 ("lfm2-audio", ModelFamily::Lfm2Audio),
629 ("lfm2", ModelFamily::Lfm2Audio),
630 ("owsm_ctc", ModelFamily::OwsmCtc),
632 ("owsm-ctc", ModelFamily::OwsmCtc),
633 ("owsmctc", ModelFamily::OwsmCtc),
634 ("owsm", ModelFamily::Owsm),
635 ("samsone", ModelFamily::Samsone),
636 ("sam-sone", ModelFamily::Samsone),
637 ("zipvoice", ModelFamily::Zipvoice),
638 ("zip-voice", ModelFamily::Zipvoice),
639 ("liveavatar", ModelFamily::Liveavatar),
640 ("live-avatar", ModelFamily::Liveavatar),
641 ("reuse", ModelFamily::Reuse),
642 ("re-use", ModelFamily::Reuse),
643 ("sam_audio", ModelFamily::SamAudio),
644 ("sam-audio", ModelFamily::SamAudio),
645 ("samaudio", ModelFamily::SamAudio),
646 ("sidon", ModelFamily::Sidon),
647 ("smart_turn", ModelFamily::SmartTurn),
648 ("smart-turn", ModelFamily::SmartTurn),
649 ("smartturn", ModelFamily::SmartTurn),
650 ("auk", ModelFamily::Auk),
651 ("minimax_h3", ModelFamily::MinimaxH3),
652 ("minimax-h3", ModelFamily::MinimaxH3),
653 ("sortformer_diar_v2", ModelFamily::SortformerDiarV2),
654 ("sortformer-diar-v2", ModelFamily::SortformerDiarV2),
655 ("sortformer_diar", ModelFamily::SortformerDiar),
656 ("sortformer-diar", ModelFamily::SortformerDiar),
657 ("sortformer", ModelFamily::SortformerDiar),
658 ("seed_vc", ModelFamily::SeedVc),
659 ("seed-vc", ModelFamily::SeedVc),
660 ("seedvc", ModelFamily::SeedVc),
661 ("rvc", ModelFamily::Rvc),
662 ("meanvc2", ModelFamily::Meanvc2),
663 ("mean-vc2", ModelFamily::Meanvc2),
664 ("tone_color_vc", ModelFamily::ToneColorVc),
665 ("tone-color-vc", ModelFamily::ToneColorVc),
666 ("tone_color", ModelFamily::ToneColorVc),
667 ("tonecolor", ModelFamily::ToneColorVc),
668 ("chatterbox_turbo", ModelFamily::ChatterboxTurbo),
669 ("chatterbox-turbo", ModelFamily::ChatterboxTurbo),
670 ("chatterbox", ModelFamily::Chatterbox),
671 ("vevo2", ModelFamily::Vevo2),
672 ("voxcpm2", ModelFamily::Voxcpm2),
673 ("ace_step", ModelFamily::AceStep),
674 ("ace-step", ModelFamily::AceStep),
675 ("htdemucs_6stems", ModelFamily::Htdemucs6Stems),
677 ("htdemucs-6stems", ModelFamily::Htdemucs6Stems),
678 ("htdemucs_6s", ModelFamily::Htdemucs6Stems),
679 ("htdemucs-6s", ModelFamily::Htdemucs6Stems),
680 ("htdemucs", ModelFamily::Htdemucs),
681 ("demucs", ModelFamily::Htdemucs),
682 ("mel-band-roformer", ModelFamily::MelBandRoformer),
683 ("mel_band_roformer", ModelFamily::MelBandRoformer),
684 ("bs-roformer", ModelFamily::BsRoformer),
685 ("bs_roformer", ModelFamily::BsRoformer),
686 ("muscriptor", ModelFamily::Muscriptor),
687 ("omnivoice", ModelFamily::Omnivoice),
688 ("stable_audio", ModelFamily::StableAudio),
689 ("stable-audio", ModelFamily::StableAudio),
690 ("minimax_music3", ModelFamily::MinimaxMusic3),
691 ("minimax-music3", ModelFamily::MinimaxMusic3),
692 ("supertonic", ModelFamily::Supertonic),
693 ("yue2", ModelFamily::Yue2),
694 ("yue-2", ModelFamily::Yue2),
695 ("sheetsage2", ModelFamily::Sheetsage2),
696 ("sheetsage-2", ModelFamily::Sheetsage2),
697 ("sheetsage", ModelFamily::Sheetsage2),
698 ("voxtral-realtime", ModelFamily::VoxtralRealtime),
699 ("voxtral", ModelFamily::VoxtralRealtime),
700 ("audiosr", ModelFamily::Audiosr),
701 ("audio-sr", ModelFamily::Audiosr),
702 ("apollo", ModelFamily::Apollo),
703 ("universr", ModelFamily::Universr),
704 ("univer-sr", ModelFamily::Universr),
705 ("controlfoley", ModelFamily::ControlFoley),
706 ("control-foley", ModelFamily::ControlFoley),
707 ("midashenglm_gen", ModelFamily::MidashEnglmGen),
708 ("midashenglm-gen", ModelFamily::MidashEnglmGen),
709 ("midashen", ModelFamily::MidashEnglmGen),
710 ("builtin_audio_utils", ModelFamily::BuiltinAudioUtils),
711 ("builtin-audio-utils", ModelFamily::BuiltinAudioUtils),
712 ("deepfilternet", ModelFamily::BuiltinAudioUtils),
713 ("rnnoise", ModelFamily::BuiltinAudioUtils),
714 ("zipenhancer", ModelFamily::BuiltinAudioUtils),
715 ("gtcrn", ModelFamily::BuiltinAudioUtils),
716 ("flashsr", ModelFamily::BuiltinAudioUtils),
717 ("miocodec", ModelFamily::Miocodec),
718 ("miotts", ModelFamily::Miotts),
719 ("dramabox", ModelFamily::Dramabox),
720 ("heartmula", ModelFamily::Heartmula),
721 ("inflect", ModelFamily::InflectV2),
722 ("mms_forced_aligner", ModelFamily::MmsForcedAligner),
723 ("mms", ModelFamily::MmsForcedAligner),
724 ("forced-aligner", ModelFamily::Qwen3ForcedAligner),
725 ];
726 KEYWORDS
727 .iter()
728 .find(|(k, _)| lower.contains(k))
729 .map(|(_, family)| family.clone())
730 }
731
732 pub fn as_str(&self) -> &str {
734 match self {
735 ModelFamily::SileroVad => "silero_vad",
736 ModelFamily::MarblenetVad => "marblenet_vad",
737 ModelFamily::Pulsevad => "pulsevad",
738 ModelFamily::Qwen3Asr => "qwen3_asr",
739 ModelFamily::CitrinetAsr => "citrinet_asr",
740 ModelFamily::SenseAsr => "sense_asr",
741 ModelFamily::FunAsrNano => "fun_asr_nano",
742 ModelFamily::HiggsAudioStt => "higgs_audio_stt",
743 ModelFamily::HviskeAsr => "hviske_asr",
744 ModelFamily::KrokoAsr => "kroko_asr",
745 ModelFamily::NemotronAsr => "nemotron_asr",
746 ModelFamily::Nemotron3Diar => "nemotron_3_diar",
747 ModelFamily::ParakeetTdt => "parakeet_tdt",
748 ModelFamily::VibevoiceAsr => "vibevoice_asr",
749 ModelFamily::VibevoiceAsrStreaming => "vibevoice_asr_streaming",
750 ModelFamily::FireredAudio => "firered_audio",
751 ModelFamily::Granite5Asr => "granite5asr",
752 ModelFamily::Audio8Asr => "audio8_asr",
753 ModelFamily::Audio8Tts => "audio8_tts",
754 ModelFamily::Vibeasr => "vibeasr",
755 ModelFamily::MoonshineAsr => "moonshine_asr",
756 ModelFamily::NiagaraAsr => "niagara_asr",
757 ModelFamily::CanaryAsr => "canary_asr",
758 ModelFamily::CohereAsr => "cohere_asr",
759 ModelFamily::MossTranscribeDiarize => "moss_transcribe_diarize",
760 ModelFamily::Confucius4R2t2 => "confucius4_r2t2",
761 ModelFamily::AudioFlamingo => "audio_flamingo",
762 ModelFamily::Crisperwhisper => "crisperwhisper",
763 ModelFamily::GigaamAsr => "gigaam_asr",
764 ModelFamily::IndexEcho => "index_echo",
765 ModelFamily::Lfm2Audio => "lfm2_audio",
766 ModelFamily::Owsm => "owsm",
767 ModelFamily::OwsmCtc => "owsm_ctc",
768 ModelFamily::Samsone => "samsone",
769 ModelFamily::Qwen3Tts => "qwen3_tts",
770 ModelFamily::Confucius4Tts => "confucius4_tts",
771 ModelFamily::DotsTts => "dots_tts",
772 ModelFamily::FishAudio => "fish_audio",
773 ModelFamily::GlmTts => "glm_tts",
774 ModelFamily::HiggsAudioTts => "higgs_audio_tts",
775 ModelFamily::IndexTts2 => "index_tts2",
776 ModelFamily::IrodoriTts => "irodori_tts",
777 ModelFamily::MossTtsLocal => "moss_tts_local",
778 ModelFamily::MossTtsNano => "moss_tts_nano",
779 ModelFamily::MossTtsV15 => "moss_tts_v15",
780 ModelFamily::MossVoicegen => "moss_voicegen",
781 ModelFamily::Neutts => "neutts",
782 ModelFamily::Outetts => "outetts",
783 ModelFamily::PocketTts => "pocket_tts",
784 ModelFamily::VieneuV3Turbo => "vieneu_v3_turbo",
785 ModelFamily::Fireredtts3 => "fireredtts3",
786 ModelFamily::F5Tts => "f5_tts",
787 ModelFamily::MagpieTts => "magpie_tts",
788 ModelFamily::Personaplex => "personaplex",
789 ModelFamily::SopranoTts => "soprano_tts",
790 ModelFamily::EchoTts => "echo_tts",
791 ModelFamily::Voxcpm1 => "voxcpm1",
792 ModelFamily::KokoroTts => "kokoro_tts",
793 ModelFamily::Zipvoice => "zipvoice",
794 ModelFamily::Auk => "auk",
795 ModelFamily::PiperTts => "piper_tts",
796 ModelFamily::KittenTts => "kitten_tts",
797 ModelFamily::KittenTts2 => "kitten_tts2",
798 ModelFamily::Kugelaudio => "kugelaudio",
799 ModelFamily::Maya1 => "maya1",
800 ModelFamily::MossTtsd => "moss_ttsd",
801 ModelFamily::MinimaxH3 => "minimax_h3",
802 ModelFamily::Sanotts => "sanotts",
803 ModelFamily::SoproTts => "sopro_tts",
804 ModelFamily::MiraTts => "mira_tts",
805 ModelFamily::Cosyvoice3 => "cosyvoice3",
806 ModelFamily::BreezeTts => "breeze_tts",
807 ModelFamily::SortformerDiar => "sortformer_diar",
808 ModelFamily::SortformerDiarV2 => "sortformer_diar_v2",
809 ModelFamily::SeedVc => "seed_vc",
810 ModelFamily::Rvc => "rvc",
811 ModelFamily::Meanvc2 => "meanvc2",
812 ModelFamily::ToneColorVc => "tone_color_vc",
813 ModelFamily::Chatterbox => "chatterbox",
814 ModelFamily::ChatterboxTurbo => "chatterbox_turbo",
815 ModelFamily::Vevo2 => "vevo2",
816 ModelFamily::Voxcpm2 => "voxcpm2",
817 ModelFamily::AceStep => "ace_step",
818 ModelFamily::Htdemucs => "htdemucs",
819 ModelFamily::Htdemucs6Stems => "htdemucs_6stems",
820 ModelFamily::MelBandRoformer => "mel_band_roformer",
821 ModelFamily::BsRoformer => "bs_roformer",
822 ModelFamily::Muscriptor => "muscriptor",
823 ModelFamily::Omnivoice => "omnivoice",
824 ModelFamily::StableAudio => "stable_audio",
825 ModelFamily::MinimaxMusic3 => "minimax_music3",
826 ModelFamily::Supertonic => "supertonic",
827 ModelFamily::Yue2 => "yue2",
828 ModelFamily::Sheetsage2 => "sheetsage2",
829 ModelFamily::VoxtralRealtime => "voxtral_realtime",
830 ModelFamily::Audiosr => "audiosr",
831 ModelFamily::Apollo => "apollo",
832 ModelFamily::Universr => "universr",
833 ModelFamily::BuiltinAudioUtils => "builtin_audio_utils",
834 ModelFamily::ControlFoley => "controlfoley",
835 ModelFamily::MidashEnglmGen => "midashenglm_gen",
836 ModelFamily::Liveavatar => "liveavatar",
837 ModelFamily::Reuse => "reuse",
838 ModelFamily::SamAudio => "sam_audio",
839 ModelFamily::Sidon => "sidon",
840 ModelFamily::SmartTurn => "smart_turn",
841 ModelFamily::Miocodec => "miocodec",
842 ModelFamily::Miotts => "miotts",
843 ModelFamily::Vibevoice => "vibevoice",
844 ModelFamily::Dramabox => "dramabox",
845 ModelFamily::Heartmula => "heartmula",
846 ModelFamily::InflectV2 => "inflect_v2",
847 ModelFamily::Qwen3ForcedAligner => "qwen3_forced_aligner",
848 ModelFamily::MmsForcedAligner => "mms_forced_aligner",
849 ModelFamily::Custom(s) => s,
850 }
851 }
852}
853
854impl From<&str> for ModelFamily {
855 fn from(s: &str) -> Self {
857 match s {
858 "silero_vad" => ModelFamily::SileroVad,
859 "marblenet_vad" => ModelFamily::MarblenetVad,
860 "pulsevad" => ModelFamily::Pulsevad,
861 "qwen3_asr" => ModelFamily::Qwen3Asr,
862 "citrinet_asr" => ModelFamily::CitrinetAsr,
863 "sense_asr" => ModelFamily::SenseAsr,
864 "fun_asr_nano" => ModelFamily::FunAsrNano,
865 "higgs_audio_stt" => ModelFamily::HiggsAudioStt,
866 "hviske_asr" => ModelFamily::HviskeAsr,
867 "kroko_asr" => ModelFamily::KrokoAsr,
868 "nemotron_asr" => ModelFamily::NemotronAsr,
869 "nemotron_3_diar" => ModelFamily::Nemotron3Diar,
870 "parakeet_tdt" => ModelFamily::ParakeetTdt,
871 "vibevoice_asr" => ModelFamily::VibevoiceAsr,
872 "vibevoice_asr_streaming" => ModelFamily::VibevoiceAsrStreaming,
873 "firered_audio" => ModelFamily::FireredAudio,
874 "granite5asr" => ModelFamily::Granite5Asr,
875 "granite_speech5_asr" => ModelFamily::Granite5Asr,
876 "granite_speech" => ModelFamily::Granite5Asr,
877 "granite_speech5_ctc" => ModelFamily::Granite5Asr,
878 "audio8_asr" => ModelFamily::Audio8Asr,
879 "arkasr" => ModelFamily::Audio8Asr,
880 "audio8_tts" => ModelFamily::Audio8Tts,
881 "vibeasr" => ModelFamily::Vibeasr,
882 "moonshine_asr" => ModelFamily::MoonshineAsr,
883 "niagara_asr" => ModelFamily::NiagaraAsr,
884 "canary_asr" => ModelFamily::CanaryAsr,
885 "cohere_asr" => ModelFamily::CohereAsr,
886 "moss_transcribe_diarize" => ModelFamily::MossTranscribeDiarize,
887 "confucius4_r2t2" => ModelFamily::Confucius4R2t2,
888 "audio_flamingo" => ModelFamily::AudioFlamingo,
889 "crisperwhisper" => ModelFamily::Crisperwhisper,
890 "gigaam_asr" => ModelFamily::GigaamAsr,
891 "index_echo" => ModelFamily::IndexEcho,
892 "lfm2_audio" => ModelFamily::Lfm2Audio,
893 "owsm" => ModelFamily::Owsm,
894 "owsm_ctc" => ModelFamily::OwsmCtc,
895 "samsone" => ModelFamily::Samsone,
896 "qwen3_tts" => ModelFamily::Qwen3Tts,
897 "confucius4_tts" => ModelFamily::Confucius4Tts,
898 "dots_tts" => ModelFamily::DotsTts,
899 "fish_audio" => ModelFamily::FishAudio,
900 "glm_tts" => ModelFamily::GlmTts,
901 "higgs_audio_tts" => ModelFamily::HiggsAudioTts,
902 "index_tts2" => ModelFamily::IndexTts2,
903 "irodori_tts" => ModelFamily::IrodoriTts,
904 "moss_tts_local" => ModelFamily::MossTtsLocal,
905 "moss_tts_nano" => ModelFamily::MossTtsNano,
906 "moss_tts_v15" => ModelFamily::MossTtsV15,
907 "moss_voicegen" => ModelFamily::MossVoicegen,
908 "neutts" => ModelFamily::Neutts,
909 "outetts" => ModelFamily::Outetts,
910 "pocket_tts" => ModelFamily::PocketTts,
911 "vietneu_tts" => ModelFamily::VieneuV3Turbo,
912 "vieneu_v3_turbo" => ModelFamily::VieneuV3Turbo,
913 "fireredtts3" => ModelFamily::Fireredtts3,
914 "f5_tts" => ModelFamily::F5Tts,
915 "magpie_tts" => ModelFamily::MagpieTts,
916 "personaplex" => ModelFamily::Personaplex,
917 "soprano_tts" => ModelFamily::SopranoTts,
918 "echo_tts" => ModelFamily::EchoTts,
919 "voxcpm1" => ModelFamily::Voxcpm1,
920 "kokoro_tts" => ModelFamily::KokoroTts,
921 "zipvoice" => ModelFamily::Zipvoice,
922 "auk" => ModelFamily::Auk,
923 "piper_tts" => ModelFamily::PiperTts,
924 "kitten_tts" => ModelFamily::KittenTts,
925 "kitten_tts2" => ModelFamily::KittenTts2,
926 "kugelaudio" => ModelFamily::Kugelaudio,
927 "maya1" => ModelFamily::Maya1,
928 "moss_ttsd" => ModelFamily::MossTtsd,
929 "minimax_h3" => ModelFamily::MinimaxH3,
930 "sanotts" => ModelFamily::Sanotts,
931 "sopro_tts" => ModelFamily::SoproTts,
932 "sopro" => ModelFamily::SoproTts,
933 "sopro_v2" => ModelFamily::SoproTts,
934 "sopro_v2_turbo" => ModelFamily::SoproTts,
935 "mira_tts" => ModelFamily::MiraTts,
936 "miratts" => ModelFamily::MiraTts,
937 "mira" => ModelFamily::MiraTts,
938 "MiraTTS" => ModelFamily::MiraTts,
939 "cosyvoice3" => ModelFamily::Cosyvoice3,
940 "breeze_tts" => ModelFamily::BreezeTts,
941 "sortformer_diar" => ModelFamily::SortformerDiar,
942 "sortformer_diar_v2" => ModelFamily::SortformerDiarV2,
943 "seed_vc" => ModelFamily::SeedVc,
944 "rvc" => ModelFamily::Rvc,
945 "meanvc2" => ModelFamily::Meanvc2,
946 "tone_color_vc" => ModelFamily::ToneColorVc,
947 "chatterbox" => ModelFamily::Chatterbox,
948 "chatterbox_turbo" => ModelFamily::ChatterboxTurbo,
949 "vevo2" => ModelFamily::Vevo2,
950 "voxcpm2" => ModelFamily::Voxcpm2,
951 "ace_step" => ModelFamily::AceStep,
952 "htdemucs" => ModelFamily::Htdemucs,
953 "htdemucs_6stems" => ModelFamily::Htdemucs6Stems,
954 "htdemucs_6s" => ModelFamily::Htdemucs6Stems,
955 "mel_band_roformer" => ModelFamily::MelBandRoformer,
956 "bs_roformer" => ModelFamily::BsRoformer,
957 "muscriptor" => ModelFamily::Muscriptor,
958 "omnivoice" => ModelFamily::Omnivoice,
959 "stable_audio" => ModelFamily::StableAudio,
960 "minimax_music3" => ModelFamily::MinimaxMusic3,
961 "supertonic" => ModelFamily::Supertonic,
962 "yue2" => ModelFamily::Yue2,
963 "sheetsage2" => ModelFamily::Sheetsage2,
964 "voxtral_realtime" => ModelFamily::VoxtralRealtime,
965 "audiosr" => ModelFamily::Audiosr,
966 "apollo" => ModelFamily::Apollo,
967 "universr" => ModelFamily::Universr,
968 "builtin_audio_utils" => ModelFamily::BuiltinAudioUtils,
969 "controlfoley" => ModelFamily::ControlFoley,
970 "midashenglm_gen" => ModelFamily::MidashEnglmGen,
971 "liveavatar" => ModelFamily::Liveavatar,
972 "reuse" => ModelFamily::Reuse,
973 "sam_audio" => ModelFamily::SamAudio,
974 "sidon" => ModelFamily::Sidon,
975 "smart_turn" => ModelFamily::SmartTurn,
976 "miocodec" => ModelFamily::Miocodec,
977 "miotts" => ModelFamily::Miotts,
978 "vibevoice" => ModelFamily::Vibevoice,
979 "dramabox" => ModelFamily::Dramabox,
980 "heartmula" => ModelFamily::Heartmula,
981 "inflect_v2" => ModelFamily::InflectV2,
982 "qwen3_forced_aligner" => ModelFamily::Qwen3ForcedAligner,
983 "mms_forced_aligner" => ModelFamily::MmsForcedAligner,
984 other => ModelFamily::Custom(other.to_owned()),
985 }
986 }
987}
988
989impl From<String> for ModelFamily {
990 fn from(s: String) -> Self {
991 ModelFamily::from(s.as_str())
992 }
993}
994
995impl AsRef<str> for ModelFamily {
996 fn as_ref(&self) -> &str {
997 self.as_str()
998 }
999}
1000
1001impl std::fmt::Display for ModelFamily {
1002 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1003 f.write_str(self.as_str())
1004 }
1005}
1006
1007#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
1009#[serde(rename_all = "lowercase")]
1010pub enum Backend {
1011 Cpu,
1013 Cuda,
1015 Hip,
1017 Vulkan,
1019 Metal,
1021 Best,
1023}
1024
1025impl Backend {
1026 pub fn as_str(self) -> &'static str {
1028 match self {
1029 Backend::Cpu => "cpu",
1030 Backend::Cuda => "cuda",
1031 Backend::Hip => "hip",
1032 Backend::Vulkan => "vulkan",
1033 Backend::Metal => "metal",
1034 Backend::Best => "best",
1035 }
1036 }
1037}
1038
1039#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1041pub struct Device {
1042 pub backend: String,
1044 pub index: i32,
1046 pub name: String,
1048 #[serde(rename = "type")]
1050 pub kind: String,
1051}
1052
1053#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1055pub struct LoaderInfo {
1056 pub family: String,
1058 pub capabilities: Capabilities,
1060 pub instructions_policy: String,
1062 pub api_endpoints: Vec<String>,
1064}
1065
1066#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1068pub struct Capabilities {
1069 pub supported_tasks: Vec<SupportedTask>,
1071 pub languages: Vec<String>,
1073 pub supports_speaker_reference: bool,
1075 pub supports_style_condition: bool,
1077 pub supports_timestamps: bool,
1079}
1080
1081#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1083pub struct SupportedTask {
1084 pub task: String,
1086 pub modes: Vec<String>,
1088}
1089
1090#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1092pub struct ModelMetadata {
1093 pub family: String,
1095 pub variant: String,
1097 pub description: String,
1099 pub config_candidates: Vec<String>,
1101 pub weight_candidates: Vec<String>,
1103}
1104
1105#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
1107pub struct TimeSpan {
1108 pub start_sample: i64,
1110 pub end_sample: i64,
1112}
1113
1114#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1116pub struct SpeechSegment {
1117 pub span: TimeSpan,
1119 pub confidence: f32,
1121 pub text: String,
1123}
1124
1125#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1127pub struct SpeakerTurn {
1128 pub speaker_id: String,
1130 pub span: TimeSpan,
1132 pub confidence: f32,
1134 #[serde(default)]
1136 pub text: String,
1137}
1138
1139#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1141pub struct WordTimestamp {
1142 pub span: TimeSpan,
1144 pub word: String,
1146 pub confidence: f32,
1148}
1149
1150#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1152pub struct VoiceArtifact {
1153 pub kind: String,
1155 pub id: String,
1157 #[serde(default)]
1159 pub payload_base64: String,
1160 #[serde(default)]
1162 pub meta: BTreeMap<String, String>,
1163}
1164
1165#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1167pub struct CliOption {
1168 pub name: String,
1170 pub value_name: String,
1172 pub description: String,
1174 pub required: bool,
1176 #[serde(default, skip_serializing_if = "Option::is_none")]
1178 pub default_value: Option<String>,
1179 #[serde(default, skip_serializing_if = "Option::is_none")]
1181 pub min_value: Option<String>,
1182 #[serde(default, skip_serializing_if = "Option::is_none")]
1184 pub max_value: Option<String>,
1185}
1186
1187#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1189pub struct NamedAsset {
1190 pub id: String,
1192 pub path: String,
1194}
1195
1196#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1198pub struct CliInterface {
1199 #[serde(default)]
1201 pub request_options: Vec<CliOption>,
1202 #[serde(default)]
1204 pub session_options: Vec<CliOption>,
1205 #[serde(default)]
1207 pub load_options: Vec<CliOption>,
1208}
1209
1210#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1212pub struct ModelInspection {
1213 pub metadata: ModelMetadata,
1215 pub capabilities: Capabilities,
1217 pub cli: CliInterface,
1219 #[serde(default)]
1221 pub discovered_configs: Vec<NamedAsset>,
1222 #[serde(default)]
1224 pub discovered_weights: Vec<NamedAsset>,
1225 #[serde(default)]
1227 pub model_root: String,
1228}
1229
1230#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1232pub struct TextOutput {
1233 pub text: String,
1235 pub language: String,
1237}
1238
1239#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1241pub struct AudioBufferInfo {
1242 pub sample_rate: i32,
1244 pub channels: i32,
1246 pub sample_count: usize,
1248 #[serde(default)]
1251 pub samples: Option<Vec<f32>>,
1252}
1253
1254#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1256pub struct NamedAudioOutput {
1257 pub id: String,
1259 pub audio: AudioBufferInfo,
1261 pub meta: BTreeMap<String, String>,
1263}
1264
1265#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1271pub struct CustomSchemaOutput {
1272 pub schema: String,
1274 pub data: serde_json::Value,
1276}
1277
1278#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1280pub struct TaskResult {
1281 pub speech_segments: Vec<SpeechSegment>,
1283 pub speaker_turns: Vec<SpeakerTurn>,
1285 pub text_output: Option<TextOutput>,
1287 pub audio_output: Option<AudioBufferInfo>,
1289 pub named_audio_outputs: Vec<NamedAudioOutput>,
1291 #[serde(default)]
1302 pub word_timestamps: Vec<WordTimestamp>,
1303 #[serde(default)]
1305 pub custom_schema_output: Option<CustomSchemaOutput>,
1306 #[serde(default)]
1308 pub artifact_output: Option<VoiceArtifact>,
1309 #[serde(default)]
1311 pub output_artifacts: Vec<VoiceArtifact>,
1312}
1313
1314#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1316pub struct StreamEvent {
1317 pub voice_activity: Vec<VoiceActivityEvent>,
1319 pub partial_text: Option<TextOutput>,
1321 pub audio_output: Option<AudioBufferInfo>,
1323 #[serde(default)]
1325 pub named_audio_outputs: Vec<NamedAudioOutput>,
1326 #[serde(default)]
1328 pub speaker_turns: Vec<SpeakerTurn>,
1329 #[serde(default)]
1332 pub word_timestamps: Vec<WordTimestamp>,
1333 #[serde(default)]
1335 pub output_artifacts: Vec<VoiceArtifact>,
1336 pub is_final: bool,
1338}
1339
1340#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1342pub struct VoiceActivityEvent {
1343 pub kind: String,
1345 pub sample: i64,
1347 pub probability: f32,
1349 pub segment: Option<SpeechSegment>,
1351}
1352
1353#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1355pub struct StreamingPolicy {
1356 pub input: String,
1358 pub output: String,
1360 pub preferred_audio_chunk_samples: usize,
1362 pub preferred_audio_chunk_seconds: f64,
1364}
1365
1366#[cfg(test)]
1367mod tests {
1368 #![allow(clippy::unwrap_used, clippy::expect_used)]
1370 use super::*;
1371
1372 #[test]
1376 fn model_family_roundtrip() {
1377 let mut variants: Vec<ModelFamily> = Vec::new();
1378 macro_rules! push {
1379 ($($v:ident),* $(,)?) => {
1380 $(variants.push(ModelFamily::$v);)*
1381 };
1382 }
1383 push![
1384 SileroVad,
1386 MarblenetVad,
1387 Pulsevad,
1388 Qwen3Asr,
1390 CitrinetAsr,
1391 SenseAsr,
1392 FunAsrNano,
1393 HiggsAudioStt,
1394 HviskeAsr,
1395 KrokoAsr,
1396 NemotronAsr,
1397 Nemotron3Diar,
1398 ParakeetTdt,
1399 VibevoiceAsr,
1400 VibevoiceAsrStreaming,
1401 FireredAudio,
1402 Granite5Asr,
1403 Audio8Asr,
1404 Audio8Tts,
1405 Vibeasr,
1406 MoonshineAsr,
1407 NiagaraAsr,
1408 CanaryAsr,
1409 CohereAsr,
1410 MossTranscribeDiarize,
1411 Confucius4R2t2,
1412 AudioFlamingo,
1413 Crisperwhisper,
1414 GigaamAsr,
1415 IndexEcho,
1416 Lfm2Audio,
1417 Owsm,
1418 OwsmCtc,
1419 Samsone,
1420 Qwen3Tts,
1422 Confucius4Tts,
1423 DotsTts,
1424 FishAudio,
1425 GlmTts,
1426 HiggsAudioTts,
1427 IndexTts2,
1428 IrodoriTts,
1429 MossTtsLocal,
1430 MossTtsNano,
1431 MossTtsV15,
1432 MossVoicegen,
1433 Neutts,
1434 Outetts,
1435 PocketTts,
1436 VieneuV3Turbo,
1437 Fireredtts3,
1438 F5Tts,
1439 MagpieTts,
1440 Personaplex,
1441 SopranoTts,
1442 EchoTts,
1443 Voxcpm1,
1444 KokoroTts,
1445 Zipvoice,
1446 Auk,
1447 PiperTts,
1448 KittenTts,
1449 KittenTts2,
1450 Kugelaudio,
1451 Maya1,
1452 MossTtsd,
1453 MinimaxH3,
1454 Sanotts,
1455 SoproTts,
1456 MiraTts,
1457 Cosyvoice3,
1458 BreezeTts,
1459 SortformerDiar,
1461 SortformerDiarV2,
1462 SeedVc,
1463 Rvc,
1464 Meanvc2,
1465 ToneColorVc,
1466 Chatterbox,
1467 ChatterboxTurbo,
1468 Vevo2,
1469 Voxcpm2,
1470 AceStep,
1471 Htdemucs,
1472 Htdemucs6Stems,
1473 MelBandRoformer,
1474 BsRoformer,
1475 Muscriptor,
1476 Omnivoice,
1477 StableAudio,
1478 MinimaxMusic3,
1479 Supertonic,
1480 Yue2,
1481 Sheetsage2,
1482 VoxtralRealtime,
1483 Audiosr,
1484 Apollo,
1485 Universr,
1486 BuiltinAudioUtils,
1487 ControlFoley,
1488 MidashEnglmGen,
1489 Liveavatar,
1490 Reuse,
1491 SamAudio,
1492 Sidon,
1493 SmartTurn,
1494 Miocodec,
1496 Miotts,
1497 Vibevoice,
1498 Dramabox,
1499 Heartmula,
1500 InflectV2,
1501 Qwen3ForcedAligner,
1502 MmsForcedAligner,
1503 ];
1504 assert!(
1505 variants.len() >= 40,
1506 "ModelFamily 应至少覆盖上游全部 40+ loader 族,当前 {}",
1507 variants.len()
1508 );
1509 for v in variants {
1510 let name = v.as_str();
1511 assert_eq!(
1512 ModelFamily::from(name),
1513 v,
1514 "as_str() 与 From<&str> 不一致:{}",
1515 name
1516 );
1517 assert_eq!(format!("{v}"), name);
1519 assert_eq!(v.as_ref(), name);
1520 }
1521 }
1522
1523 #[test]
1524 fn model_family_custom_fallback() {
1525 let m = ModelFamily::from("brand_new_family");
1527 match &m {
1528 ModelFamily::Custom(s) => assert_eq!(s, "brand_new_family"),
1529 other => panic!("未收录名字应落入 Custom,得到 {other:?}"),
1530 }
1531 assert_eq!(m.as_str(), "brand_new_family");
1532 assert_eq!(
1534 ModelFamily::from("brand_new_family"),
1535 ModelFamily::Custom("brand_new_family".to_owned())
1536 );
1537 assert_eq!(
1539 ModelFamily::from("qwen3_asr".to_owned()),
1540 ModelFamily::Qwen3Asr
1541 );
1542 }
1543
1544 #[test]
1545 fn model_family_from_path() {
1546 assert_eq!(
1548 ModelFamily::from_path("models/qwen3-asr-0.6b-q8_0.gguf"),
1549 Some(ModelFamily::Qwen3Asr)
1550 );
1551 assert_eq!(
1552 ModelFamily::from_path("sortformer-diar-4spk-v1-q8_0.gguf"),
1553 Some(ModelFamily::SortformerDiar)
1554 );
1555 assert_eq!(
1556 ModelFamily::from_path("citrinet-asr-q8_0.gguf"),
1557 Some(ModelFamily::CitrinetAsr)
1558 );
1559 assert_eq!(
1560 ModelFamily::from_path("moss-tts-nano-q8_0.gguf"),
1561 Some(ModelFamily::MossTtsNano)
1562 );
1563 assert_eq!(
1565 ModelFamily::from_path("moss-tts-v15-q8_0.gguf"),
1566 Some(ModelFamily::MossTtsV15)
1567 );
1568 assert_eq!(
1570 ModelFamily::from_path("nemotron-3-diarization-bf16.gguf"),
1571 Some(ModelFamily::Nemotron3Diar)
1572 );
1573 assert_eq!(
1575 ModelFamily::from_path("vieneu-v3-turbo-q8_0.gguf"),
1576 Some(ModelFamily::VieneuV3Turbo)
1577 );
1578 assert_eq!(ModelFamily::from("vietneu_tts"), ModelFamily::VieneuV3Turbo);
1579 assert_eq!(
1581 ModelFamily::from_path("qwen3-tts-12hz-0.6b-base-q8_0.gguf"),
1582 Some(ModelFamily::Qwen3Tts)
1583 );
1584 assert_eq!(
1585 ModelFamily::from_path("qwen3-forced-aligner-q8_0.gguf"),
1586 Some(ModelFamily::Qwen3ForcedAligner)
1587 );
1588 assert_eq!(
1589 ModelFamily::from_path("mira-tts-q8_0.gguf"),
1590 Some(ModelFamily::MiraTts)
1591 );
1592 assert_eq!(
1593 ModelFamily::from_path("htdemucs-6s-q8_0.gguf"),
1594 Some(ModelFamily::Htdemucs6Stems)
1595 );
1596 assert_eq!(
1598 ModelFamily::from_path("htdemucs-q8_0.gguf"),
1599 Some(ModelFamily::Htdemucs)
1600 );
1601 assert_eq!(
1603 ModelFamily::from_path("kitten-tts2-q8_0.gguf"),
1604 Some(ModelFamily::KittenTts2)
1605 );
1606 assert_eq!(
1607 ModelFamily::from_path("kitten-tts-q8_0.gguf"),
1608 Some(ModelFamily::KittenTts)
1609 );
1610 assert_eq!(
1612 ModelFamily::from_path("index-echo-q8_0.gguf"),
1613 Some(ModelFamily::IndexEcho)
1614 );
1615 assert_eq!(
1616 ModelFamily::from_path("echo-tts-q8_0.gguf"),
1617 Some(ModelFamily::EchoTts)
1618 );
1619 assert_eq!(
1621 ModelFamily::from_path("owsm-ctc-q8_0.gguf"),
1622 Some(ModelFamily::OwsmCtc)
1623 );
1624 assert_eq!(
1625 ModelFamily::from_path("owsm-q8_0.gguf"),
1626 Some(ModelFamily::Owsm)
1627 );
1628 assert_eq!(
1630 ModelFamily::from_path("moss-ttsd-q8_0.gguf"),
1631 Some(ModelFamily::MossTtsd)
1632 );
1633 assert_eq!(
1635 ModelFamily::from_path("smart-turn-q8_0.gguf"),
1636 Some(ModelFamily::SmartTurn)
1637 );
1638 assert_eq!(
1639 ModelFamily::from_path("tone-color-vc-q8_0.gguf"),
1640 Some(ModelFamily::ToneColorVc)
1641 );
1642 assert_eq!(
1643 ModelFamily::from("htdemucs_6s"),
1644 ModelFamily::Htdemucs6Stems
1645 );
1646 assert_eq!(
1648 ModelFamily::from_path("vibevoice-asr-streaming-7b-q8_0.gguf"),
1649 Some(ModelFamily::VibevoiceAsrStreaming)
1650 );
1651 assert_eq!(
1652 ModelFamily::from_path("sortformer-diar-v2-q8_0.gguf"),
1653 Some(ModelFamily::SortformerDiarV2)
1654 );
1655 assert_eq!(
1656 ModelFamily::from_path("kokoro-tts-82m-q8_0.gguf"),
1657 Some(ModelFamily::KokoroTts)
1658 );
1659 assert_eq!(
1660 ModelFamily::from_path("moonshine-tiny-q8_0.gguf"),
1661 Some(ModelFamily::MoonshineAsr)
1662 );
1663 assert_eq!(
1664 ModelFamily::from_path("niagara-asr-q8_0.gguf"),
1665 Some(ModelFamily::NiagaraAsr)
1666 );
1667 assert_eq!(
1668 ModelFamily::from_path("yue2-music-q8_0.gguf"),
1669 Some(ModelFamily::Yue2)
1670 );
1671 assert_eq!(
1672 ModelFamily::from_path("sheetsage2-q8_0.gguf"),
1673 Some(ModelFamily::Sheetsage2)
1674 );
1675 assert_eq!(
1676 ModelFamily::from_path("pulsevad-2.1k-f32.gguf"),
1677 Some(ModelFamily::Pulsevad)
1678 );
1679 assert_eq!(
1680 ModelFamily::from_path("canary-180m-flash-q8_0.gguf"),
1681 Some(ModelFamily::CanaryAsr)
1682 );
1683 assert_eq!(
1684 ModelFamily::from_path("cohere-transcribe-03-2026-q8_0.gguf"),
1685 Some(ModelFamily::CohereAsr)
1686 );
1687 assert_eq!(
1689 ModelFamily::from_path("moss-transcribe-diarize-q8_0.gguf"),
1690 Some(ModelFamily::MossTranscribeDiarize)
1691 );
1692 assert_eq!(
1693 ModelFamily::from_path("apollo-orig.gguf"),
1694 Some(ModelFamily::Apollo)
1695 );
1696 assert_eq!(
1697 ModelFamily::from_path("universr-audio-orig.gguf"),
1698 Some(ModelFamily::Universr)
1699 );
1700 assert_eq!(
1701 ModelFamily::from_path("zipvoice-distill-q8_0.gguf"),
1702 Some(ModelFamily::Zipvoice)
1703 );
1704 assert_eq!(
1705 ModelFamily::from_path("auk-flash-q8_0.gguf"),
1706 Some(ModelFamily::Auk)
1707 );
1708 assert_eq!(
1709 ModelFamily::from_path("liveavatar-nvfp4.gguf"),
1710 Some(ModelFamily::Liveavatar)
1711 );
1712 assert_eq!(
1713 ModelFamily::from_path("piper-en-us-lessac-medium-orig.gguf"),
1714 Some(ModelFamily::PiperTts)
1715 );
1716 assert_eq!(
1717 ModelFamily::from_path("kitten-tts-mini-0.8-orig.gguf"),
1718 Some(ModelFamily::KittenTts)
1719 );
1720 assert_eq!(
1722 ModelFamily::from_path("confucius4-r2t2-q8_0.gguf"),
1723 Some(ModelFamily::Confucius4R2t2)
1724 );
1725 assert_eq!(
1726 ModelFamily::from_path("confucius4-tts-q8_0.gguf"),
1727 Some(ModelFamily::Confucius4Tts)
1728 );
1729 assert_eq!(
1731 ModelFamily::from_path("deepfilternet2"),
1732 Some(ModelFamily::BuiltinAudioUtils)
1733 );
1734 assert_eq!(
1736 ModelFamily::from_path("Qwen3-ASR.Q8_0.GGUF"),
1737 Some(ModelFamily::Qwen3Asr)
1738 );
1739 assert_eq!(
1741 ModelFamily::from_path("model.gguf#family=citrinet_asr"),
1742 Some(ModelFamily::CitrinetAsr)
1743 );
1744 assert_eq!(
1745 ModelFamily::from_path("model.gguf#family=MiraTTS"),
1746 Some(ModelFamily::MiraTts)
1747 );
1748 assert_eq!(
1749 ModelFamily::from_path("model.gguf#family=qwen3_tts"),
1750 Some(ModelFamily::Qwen3Tts)
1751 );
1752 assert_eq!(ModelFamily::from_path("my-weights.gguf"), None);
1754 assert_eq!(ModelFamily::from_path(""), None);
1755 }
1756
1757 #[test]
1758 fn task_kind_as_str() {
1759 let cases = [
1760 (TaskKind::Vad, "vad"),
1761 (TaskKind::Asr, "asr"),
1762 (TaskKind::Diar, "diar"),
1763 (TaskKind::SourceSeparation, "sep"),
1764 (TaskKind::AudioGeneration, "gen"),
1765 (TaskKind::Tts, "tts"),
1766 (TaskKind::VoiceCloning, "clon"),
1767 (TaskKind::VoiceConversion, "vc"),
1768 (TaskKind::SpeechToSpeech, "s2s"),
1769 (TaskKind::Alignment, "align"),
1770 (TaskKind::VoiceDesign, "vdes"),
1771 (TaskKind::SpeakerRecognition, "spk"),
1772 (TaskKind::Svc, "svc"),
1773 (TaskKind::Midi, "midi"),
1774 (TaskKind::TurnDetection, "turn"),
1775 ];
1776 for (k, want) in cases {
1777 assert_eq!(k.as_str(), want);
1778 }
1779 }
1780
1781 #[test]
1782 fn task_kind_serde_roundtrip() {
1783 let all = [
1786 TaskKind::Vad,
1787 TaskKind::Asr,
1788 TaskKind::Diar,
1789 TaskKind::SourceSeparation,
1790 TaskKind::AudioGeneration,
1791 TaskKind::Tts,
1792 TaskKind::VoiceCloning,
1793 TaskKind::VoiceConversion,
1794 TaskKind::SpeechToSpeech,
1795 TaskKind::Alignment,
1796 TaskKind::VoiceDesign,
1797 TaskKind::SpeakerRecognition,
1798 TaskKind::Svc,
1799 TaskKind::Midi,
1800 TaskKind::TurnDetection,
1801 ];
1802 for k in all {
1803 let s = serde_json::to_string(&k).unwrap();
1804 assert_eq!(s, format!("\"{}\"", k.as_str()));
1805 assert_eq!(serde_json::from_str::<TaskKind>(&s).unwrap(), k);
1806 }
1807 assert!(serde_json::from_str::<TaskKind>("\"sourceseparation\"").is_err());
1808 }
1809
1810 #[test]
1811 fn run_mode_as_str() {
1812 assert_eq!(RunMode::Offline.as_str(), "offline");
1813 assert_eq!(RunMode::Streaming.as_str(), "streaming");
1814 }
1815
1816 #[test]
1817 fn backend_as_str() {
1818 let cases = [
1819 (Backend::Cpu, "cpu"),
1820 (Backend::Cuda, "cuda"),
1821 (Backend::Hip, "hip"),
1822 (Backend::Vulkan, "vulkan"),
1823 (Backend::Metal, "metal"),
1824 (Backend::Best, "best"),
1825 ];
1826 for (b, want) in cases {
1827 assert_eq!(b.as_str(), want);
1828 }
1829 }
1830
1831 #[test]
1833 fn structured_types_deserialize() {
1834 let result: TaskResult = serde_json::from_str(
1835 r#"{
1836 "speech_segments": [
1837 {"span": {"start_sample": 0, "end_sample": 1600}, "confidence": 0.95, "text": ""}
1838 ],
1839 "text_output": {"text": "hi", "language": "en"},
1840 "audio_output": {"sample_rate": 24000, "channels": 1, "sample_count": 0, "samples": []},
1841 "named_audio_outputs": [],
1842 "speaker_turns": [
1843 {"speaker_id": "speaker_0", "span": {"start_sample": 0, "end_sample": 1600}, "confidence": 0.9, "text": "hello"}
1844 ],
1845 "word_timestamps": [
1846 {"span": {"start_sample": 0, "end_sample": 320}, "word": "hello", "confidence": 0.99}
1847 ],
1848 "artifact_output": {"kind": "speaker_embedding", "id": "spk1", "payload_base64": "", "meta": {}},
1849 "output_artifacts": [
1850 {"kind": "custom", "id": "a", "payload_base64": "AQID", "meta": {"k": "v"}}
1851 ]
1852 }"#,
1853 )
1854 .unwrap();
1855 assert_eq!(result.speech_segments.len(), 1);
1856 assert_eq!(result.speech_segments[0].span.start_sample, 0);
1857 assert_eq!(result.speech_segments[0].confidence, 0.95);
1858 assert_eq!(result.text_output.as_ref().unwrap().text, "hi");
1859 assert_eq!(result.audio_output.unwrap().sample_rate, 24000);
1860 assert_eq!(result.speaker_turns[0].text, "hello");
1861 assert_eq!(result.word_timestamps[0].word, "hello");
1862 assert_eq!(
1863 result.artifact_output.as_ref().unwrap().kind,
1864 "speaker_embedding"
1865 );
1866 assert_eq!(result.output_artifacts[0].payload_base64, "AQID");
1867
1868 let ev: StreamEvent = serde_json::from_str(
1869 r#"{
1870 "voice_activity": [
1871 {"kind": "speech_start", "sample": 100, "probability": 0.8, "segment": null}
1872 ],
1873 "partial_text": null,
1874 "audio_output": null,
1875 "named_audio_outputs": [{"id": "chunk_0", "audio": {"sample_rate": 48000, "channels": 2, "sample_count": 320, "samples": []}, "meta": {}}],
1876 "speaker_turns": [],
1877 "word_timestamps": [],
1878 "output_artifacts": [],
1879 "is_final": true
1880 }"#,
1881 )
1882 .unwrap();
1883 assert_eq!(ev.voice_activity[0].kind, "speech_start");
1884 assert_eq!(ev.named_audio_outputs[0].id, "chunk_0");
1885 assert!(ev.is_final);
1886 }
1887
1888 #[test]
1889 fn model_inspection_deserialize() {
1890 let info: ModelInspection = serde_json::from_str(
1893 r#"{
1894 "metadata": {
1895 "family": "qwen3_asr",
1896 "variant": "q8_0",
1897 "description": "Qwen3 ASR",
1898 "config_candidates": ["config.json"],
1899 "weight_candidates": ["qwen3-asr-q8_0.gguf"]
1900 },
1901 "capabilities": {
1902 "supported_tasks": [{"task": "asr", "modes": ["offline", "streaming"]}],
1903 "languages": ["zh", "en"],
1904 "supports_speaker_reference": false,
1905 "supports_style_condition": false,
1906 "supports_timestamps": true
1907 },
1908 "discovered_weights": [
1909 {"id": "model", "path": "/models/qwen3-asr-q8_0.gguf"}
1910 ],
1911 "cli": {
1912 "request_options": [
1913 {"name": "language", "value_name": "CODE", "description": "语言", "required": false, "default_value": "auto"}
1914 ],
1915 "session_options": [],
1916 "load_options": []
1917 }
1918 }"#,
1919 )
1920 .unwrap();
1921 assert_eq!(info.metadata.family, "qwen3_asr");
1922 assert!(
1923 info.capabilities
1924 .supported_tasks
1925 .iter()
1926 .any(|t| t.task == "asr" && t.modes.contains(&"streaming".to_string()))
1927 );
1928 assert_eq!(info.discovered_weights[0].id, "model");
1929 assert_eq!(info.cli.request_options[0].name, "language");
1930 assert_eq!(
1931 info.cli.request_options[0].default_value.as_deref(),
1932 Some("auto")
1933 );
1934 }
1935}