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 WakeWord,
48 AudioClassification,
51}
52
53impl TaskKind {
54 pub fn as_str(self) -> &'static str {
56 match self {
57 TaskKind::Vad => "vad",
58 TaskKind::Asr => "asr",
59 TaskKind::Diar => "diar",
60 TaskKind::SourceSeparation => "sep",
61 TaskKind::AudioGeneration => "gen",
62 TaskKind::Tts => "tts",
63 TaskKind::VoiceCloning => "clon",
64 TaskKind::VoiceConversion => "vc",
65 TaskKind::SpeechToSpeech => "s2s",
66 TaskKind::Alignment => "align",
67 TaskKind::VoiceDesign => "vdes",
68 TaskKind::SpeakerRecognition => "spk",
69 TaskKind::Svc => "svc",
70 TaskKind::Midi => "midi",
71 TaskKind::TurnDetection => "turn",
72 TaskKind::WakeWord => "wake",
73 TaskKind::AudioClassification => "cls",
74 }
75 }
76}
77
78impl Serialize for TaskKind {
79 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
80 serializer.serialize_str(self.as_str())
81 }
82}
83
84impl<'de> Deserialize<'de> for TaskKind {
85 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
86 let s = String::deserialize(deserializer)?;
87 match s.as_str() {
88 "vad" => Ok(TaskKind::Vad),
89 "asr" => Ok(TaskKind::Asr),
90 "diar" => Ok(TaskKind::Diar),
91 "sep" => Ok(TaskKind::SourceSeparation),
92 "gen" => Ok(TaskKind::AudioGeneration),
93 "tts" => Ok(TaskKind::Tts),
94 "clon" => Ok(TaskKind::VoiceCloning),
95 "vc" => Ok(TaskKind::VoiceConversion),
96 "s2s" => Ok(TaskKind::SpeechToSpeech),
97 "align" => Ok(TaskKind::Alignment),
98 "vdes" => Ok(TaskKind::VoiceDesign),
99 "spk" => Ok(TaskKind::SpeakerRecognition),
100 "svc" => Ok(TaskKind::Svc),
101 "midi" => Ok(TaskKind::Midi),
102 "turn" => Ok(TaskKind::TurnDetection),
103 "wake" | "wake_word" => Ok(TaskKind::WakeWord),
106 "cls" | "classify" => Ok(TaskKind::AudioClassification),
107 other => Err(serde::de::Error::unknown_variant(
108 other,
109 &[
110 "vad", "asr", "diar", "sep", "gen", "tts", "clon", "vc", "s2s", "align",
111 "vdes", "spk", "svc", "midi", "turn", "wake", "cls",
112 ],
113 )),
114 }
115 }
116}
117
118#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
120#[serde(rename_all = "lowercase")]
121pub enum RunMode {
122 Offline,
124 Streaming,
126}
127
128impl RunMode {
129 pub fn as_str(self) -> &'static str {
131 match self {
132 RunMode::Offline => "offline",
133 RunMode::Streaming => "streaming",
134 }
135 }
136}
137
138#[derive(Debug, Clone, PartialEq, Eq, Hash)]
148pub enum ModelFamily {
149 SileroVad,
152 MarblenetVad,
154 Pulsevad,
157 FireredVad,
160
161 Qwen3Asr,
164 CitrinetAsr,
166 SenseAsr,
168 FunAsrNano,
170 HiggsAudioStt,
172 HviskeAsr,
174 HviskeAsrV6,
177 KrokoAsr,
179 NemotronAsr,
181 Nemotron3Diar,
185 ParakeetTdt,
187 VibevoiceAsr,
189 VibevoiceAsrStreaming,
192 FireredAudio,
194 Granite5Asr,
196 Audio8Asr,
198 Audio8Tts,
200 Vibeasr,
202 MoonshineAsr,
204 NiagaraAsr,
206 CanaryAsr,
209 CohereAsr,
212 MossTranscribeDiarize,
215 Confucius4R2t2,
217 AudioFlamingo,
219 Crisperwhisper,
221 GigaamAsr,
223 IndexEcho,
225 Lfm2Audio,
227 Owsm,
229 OwsmCtc,
231 Samsone,
234 WhistleAsr,
236
237 Qwen3Tts,
240 Confucius4Tts,
242 DotsTts,
244 FishAudio,
246 GlmTts,
248 HiggsAudioTts,
250 IndexTts2,
252 IrodoriTts,
254 MossTtsLocal,
256 MossTtsNano,
258 MossTtsV15,
262 MossVoicegen,
264 Neutts,
266 Outetts,
268 PocketTts,
270 VieneuV3Turbo,
274 Fireredtts3,
276 F5Tts,
278 MagpieTts,
280 Personaplex,
282 MinimaxH3,
284 Sanotts,
286 SoproTts,
288 MiraTts,
290 Cosyvoice3,
292 BreezeTts,
294 SopranoTts,
296 EchoTts,
298 Voxcpm1,
300 KokoroTts,
302 Zipvoice,
305 Auk,
308 PiperTts,
311 KittenTts,
314 KittenTts2,
317 Kugelaudio,
319 Maya1,
322 MossTtsd,
325
326 SortformerDiar,
329 SortformerDiarV2,
332 SeedVc,
334 Rvc,
336 Meanvc2,
338 ToneColorVc,
340 Chatterbox,
342 ChatterboxTurbo,
344 Vevo2,
346 Voxcpm2,
348 AceStep,
350
351 Htdemucs,
354 Htdemucs6Stems,
357 Mossformer2,
359 TfGridnet,
361 MelBandRoformer,
363 BsRoformer,
365 Muscriptor,
367 Omnivoice,
369 StableAudio,
371 MinimaxMusic3,
373 Supertonic,
375 Yue2,
378 Sheetsage2,
381 VoxtralRealtime,
383 Audiosr,
385 Apollo,
387 Universr,
391 BuiltinAudioUtils,
396 ControlFoley,
398 MidashEnglmGen,
400 Liveavatar,
403 Reuse,
405 SamAudio,
407 Sidon,
409 SmartTurn,
413
414 MicroWakeWord,
419 SherpaKws,
423 Ced,
427 AstAudioset,
431
432 Miocodec,
435 Miotts,
437 Vibevoice,
439 Dramabox,
441 Heartmula,
443 InflectV2,
445 Qwen3ForcedAligner,
447 MmsForcedAligner,
449
450 Custom(String),
452}
453
454impl ModelFamily {
455 pub fn from_path(path: &str) -> Option<ModelFamily> {
483 let lower = path.to_ascii_lowercase();
484 if let Some((_, f)) = lower.rsplit_once("#family=") {
486 return Some(ModelFamily::from(f.trim()));
487 }
488 const KEYWORDS: &[(&str, ModelFamily)] = &[
490 ("silero_vad", ModelFamily::SileroVad),
491 ("silero-vad", ModelFamily::SileroVad),
492 ("marblenet_vad", ModelFamily::MarblenetVad),
493 ("marblenet-vad", ModelFamily::MarblenetVad),
494 ("marblenet", ModelFamily::MarblenetVad),
495 ("pulsevad", ModelFamily::Pulsevad),
496 ("pulse-vad", ModelFamily::Pulsevad),
497 ("pulse", ModelFamily::Pulsevad),
498 ("firered_vad", ModelFamily::FireredVad),
499 ("firered-vad", ModelFamily::FireredVad),
500 ("fireredvad", ModelFamily::FireredVad),
501 ("qwen3_asr", ModelFamily::Qwen3Asr),
502 ("qwen3-asr", ModelFamily::Qwen3Asr),
503 ("qwen3_tts", ModelFamily::Qwen3Tts),
504 ("qwen3-tts", ModelFamily::Qwen3Tts),
505 ("qwen3_forced_aligner", ModelFamily::Qwen3ForcedAligner),
506 ("qwen3-forced-aligner", ModelFamily::Qwen3ForcedAligner),
507 ("qwen3", ModelFamily::Qwen3Asr),
508 ("citrinet", ModelFamily::CitrinetAsr),
509 ("sense_asr", ModelFamily::SenseAsr),
510 ("sense-asr", ModelFamily::SenseAsr),
511 ("sensevoice", ModelFamily::SenseAsr),
512 ("fun-asr-nano", ModelFamily::FunAsrNano),
513 ("fun_asr_nano", ModelFamily::FunAsrNano),
514 ("funasr", ModelFamily::FunAsrNano),
515 ("higgs_audio_stt", ModelFamily::HiggsAudioStt),
516 ("higgs_audio_tts", ModelFamily::HiggsAudioTts),
517 ("higgs", ModelFamily::HiggsAudioStt),
518 ("hviske_asr_v6", ModelFamily::HviskeAsrV6),
520 ("hviske-asr-v6", ModelFamily::HviskeAsrV6),
521 ("hviske-v6", ModelFamily::HviskeAsrV6),
522 ("hviskev6", ModelFamily::HviskeAsrV6),
523 ("hviske", ModelFamily::HviskeAsr),
524 ("whistle_asr", ModelFamily::WhistleAsr),
525 ("whistle-asr", ModelFamily::WhistleAsr),
526 ("whistle", ModelFamily::WhistleAsr),
527 ("kroko", ModelFamily::KrokoAsr),
528 ("nemotron_3_diar", ModelFamily::Nemotron3Diar),
529 ("nemotron-3-diar", ModelFamily::Nemotron3Diar),
530 ("nemotron_3", ModelFamily::Nemotron3Diar),
531 ("nemotron-3", ModelFamily::Nemotron3Diar),
532 ("nemotron", ModelFamily::NemotronAsr),
533 ("parakeet", ModelFamily::ParakeetTdt),
534 (
535 "vibevoice_asr_streaming",
536 ModelFamily::VibevoiceAsrStreaming,
537 ),
538 (
539 "vibevoice-asr-streaming",
540 ModelFamily::VibevoiceAsrStreaming,
541 ),
542 ("vibevoice_asr", ModelFamily::VibevoiceAsr),
543 ("firered_audio", ModelFamily::FireredAudio),
544 ("firered-audio", ModelFamily::FireredAudio),
545 ("granite5asr", ModelFamily::Granite5Asr),
546 ("granite-speech", ModelFamily::Granite5Asr),
547 ("granite_speech", ModelFamily::Granite5Asr),
548 ("granite", ModelFamily::Granite5Asr),
549 ("audio8_asr", ModelFamily::Audio8Asr),
550 ("audio8-asr", ModelFamily::Audio8Asr),
551 ("audio8asr", ModelFamily::Audio8Asr),
552 ("arkasr", ModelFamily::Audio8Asr),
553 ("audio8_tts", ModelFamily::Audio8Tts),
554 ("audio8-tts", ModelFamily::Audio8Tts),
555 ("audio8tts", ModelFamily::Audio8Tts),
556 ("fireredtts3", ModelFamily::Fireredtts3),
557 ("firered_tts3", ModelFamily::Fireredtts3),
558 ("firered-tts3", ModelFamily::Fireredtts3),
559 ("vibevoice", ModelFamily::Vibevoice),
560 ("confucius4_r2t2", ModelFamily::Confucius4R2t2),
562 ("confucius4-r2t2", ModelFamily::Confucius4R2t2),
563 ("r2t2", ModelFamily::Confucius4R2t2),
564 ("confucius", ModelFamily::Confucius4Tts),
565 ("dots_tts", ModelFamily::DotsTts),
566 ("dots-tts", ModelFamily::DotsTts),
567 ("fish_audio", ModelFamily::FishAudio),
568 ("fish-audio", ModelFamily::FishAudio),
569 ("glm_tts", ModelFamily::GlmTts),
570 ("glm-tts", ModelFamily::GlmTts),
571 ("index_tts2", ModelFamily::IndexTts2),
572 ("index-tts2", ModelFamily::IndexTts2),
573 ("irodori", ModelFamily::IrodoriTts),
574 (
576 "moss_transcribe_diarize",
577 ModelFamily::MossTranscribeDiarize,
578 ),
579 (
580 "moss-transcribe-diarize",
581 ModelFamily::MossTranscribeDiarize,
582 ),
583 ("mossformer2", ModelFamily::Mossformer2),
585 ("mossformer-2", ModelFamily::Mossformer2),
586 ("mossformer", ModelFamily::Mossformer2),
587 ("moss-tts-nano", ModelFamily::MossTtsNano),
588 ("moss_tts_nano", ModelFamily::MossTtsNano),
589 ("moss-tts-local", ModelFamily::MossTtsLocal),
590 ("moss_tts_local", ModelFamily::MossTtsLocal),
591 ("moss-tts-v15", ModelFamily::MossTtsV15),
593 ("moss_tts_v15", ModelFamily::MossTtsV15),
594 ("moss_ttsd", ModelFamily::MossTtsd),
595 ("moss-ttsd", ModelFamily::MossTtsd),
596 ("mossttsd", ModelFamily::MossTtsd),
597 ("moss_voicegen", ModelFamily::MossVoicegen),
598 ("moss-voicegen", ModelFamily::MossVoicegen),
599 ("moss", ModelFamily::MossTtsNano),
600 ("neutts", ModelFamily::Neutts),
601 ("outetts", ModelFamily::Outetts),
602 ("pocket_tts", ModelFamily::PocketTts),
603 ("pocket-tts", ModelFamily::PocketTts),
604 ("vietneu", ModelFamily::VieneuV3Turbo),
605 ("vieneu", ModelFamily::VieneuV3Turbo),
606 ("f5_tts", ModelFamily::F5Tts),
607 ("f5-tts", ModelFamily::F5Tts),
608 ("magpie", ModelFamily::MagpieTts),
609 ("personaplex", ModelFamily::Personaplex),
610 ("soprano_tts", ModelFamily::SopranoTts),
611 ("soprano-tts", ModelFamily::SopranoTts),
612 ("soprano", ModelFamily::SopranoTts),
613 ("index_echo", ModelFamily::IndexEcho),
615 ("index-echo", ModelFamily::IndexEcho),
616 ("indexecho", ModelFamily::IndexEcho),
617 ("echo_tts", ModelFamily::EchoTts),
618 ("echo-tts", ModelFamily::EchoTts),
619 ("echo", ModelFamily::EchoTts),
620 ("kokoro_tts", ModelFamily::KokoroTts),
621 ("kokoro-tts", ModelFamily::KokoroTts),
622 ("kokoro", ModelFamily::KokoroTts),
623 ("piper_tts", ModelFamily::PiperTts),
624 ("piper-tts", ModelFamily::PiperTts),
625 ("piper", ModelFamily::PiperTts),
626 ("kitten_tts2", ModelFamily::KittenTts2),
628 ("kitten-tts2", ModelFamily::KittenTts2),
629 ("kitten_tts_2", ModelFamily::KittenTts2),
630 ("kittentts2", ModelFamily::KittenTts2),
631 ("kitten_tts", ModelFamily::KittenTts),
632 ("kitten-tts", ModelFamily::KittenTts),
633 ("kitten", ModelFamily::KittenTts),
634 ("kugelaudio", ModelFamily::Kugelaudio),
635 ("kugel-audio", ModelFamily::Kugelaudio),
636 ("kugel_audio", ModelFamily::Kugelaudio),
637 ("kugel", ModelFamily::Kugelaudio),
638 ("maya1", ModelFamily::Maya1),
639 ("maya-1", ModelFamily::Maya1),
640 ("maya_1", ModelFamily::Maya1),
641 ("maya", ModelFamily::Maya1),
642 ("voxcpm1", ModelFamily::Voxcpm1),
643 ("voxcpm-1", ModelFamily::Voxcpm1),
644 ("sanotts", ModelFamily::Sanotts),
645 ("sano-tts", ModelFamily::Sanotts),
646 ("sano_tts", ModelFamily::Sanotts),
647 ("sopro_tts", ModelFamily::SoproTts),
648 ("sopro-tts", ModelFamily::SoproTts),
649 ("sopro", ModelFamily::SoproTts),
650 ("mira_tts", ModelFamily::MiraTts),
651 ("mira-tts", ModelFamily::MiraTts),
652 ("miratts", ModelFamily::MiraTts),
653 ("mira", ModelFamily::MiraTts),
654 ("cosyvoice3", ModelFamily::Cosyvoice3),
655 ("cosyvoice-3", ModelFamily::Cosyvoice3),
656 ("cosyvoice", ModelFamily::Cosyvoice3),
657 ("breeze_tts", ModelFamily::BreezeTts),
658 ("breeze-tts", ModelFamily::BreezeTts),
659 ("breeze", ModelFamily::BreezeTts),
660 ("vibeasr", ModelFamily::Vibeasr),
661 ("vibe-asr", ModelFamily::Vibeasr),
662 ("moonshine_asr", ModelFamily::MoonshineAsr),
663 ("moonshine-asr", ModelFamily::MoonshineAsr),
664 ("moonshine", ModelFamily::MoonshineAsr),
665 ("niagara_asr", ModelFamily::NiagaraAsr),
666 ("niagara-asr", ModelFamily::NiagaraAsr),
667 ("niagara", ModelFamily::NiagaraAsr),
668 ("canary_asr", ModelFamily::CanaryAsr),
669 ("canary-asr", ModelFamily::CanaryAsr),
670 ("canary", ModelFamily::CanaryAsr),
671 ("cohere_asr", ModelFamily::CohereAsr),
672 ("cohere-asr", ModelFamily::CohereAsr),
673 ("cohere", ModelFamily::CohereAsr),
674 ("audio_flamingo", ModelFamily::AudioFlamingo),
675 ("audio-flamingo", ModelFamily::AudioFlamingo),
676 ("audioflamingo", ModelFamily::AudioFlamingo),
677 ("crisperwhisper", ModelFamily::Crisperwhisper),
678 ("crisper-whisper", ModelFamily::Crisperwhisper),
679 ("crisper_whisper", ModelFamily::Crisperwhisper),
680 ("gigaam_asr", ModelFamily::GigaamAsr),
681 ("gigaam-asr", ModelFamily::GigaamAsr),
682 ("gigaam", ModelFamily::GigaamAsr),
683 ("lfm2_audio", ModelFamily::Lfm2Audio),
684 ("lfm2-audio", ModelFamily::Lfm2Audio),
685 ("lfm2", ModelFamily::Lfm2Audio),
686 ("owsm_ctc", ModelFamily::OwsmCtc),
688 ("owsm-ctc", ModelFamily::OwsmCtc),
689 ("owsmctc", ModelFamily::OwsmCtc),
690 ("owsm", ModelFamily::Owsm),
691 ("samsone", ModelFamily::Samsone),
692 ("sam-sone", ModelFamily::Samsone),
693 ("zipvoice", ModelFamily::Zipvoice),
694 ("zip-voice", ModelFamily::Zipvoice),
695 ("liveavatar", ModelFamily::Liveavatar),
696 ("live-avatar", ModelFamily::Liveavatar),
697 ("reuse", ModelFamily::Reuse),
698 ("re-use", ModelFamily::Reuse),
699 ("sam_audio", ModelFamily::SamAudio),
700 ("sam-audio", ModelFamily::SamAudio),
701 ("samaudio", ModelFamily::SamAudio),
702 ("sidon", ModelFamily::Sidon),
703 ("smart_turn", ModelFamily::SmartTurn),
704 ("smart-turn", ModelFamily::SmartTurn),
705 ("smartturn", ModelFamily::SmartTurn),
706 ("auk", ModelFamily::Auk),
707 ("minimax_h3", ModelFamily::MinimaxH3),
708 ("minimax-h3", ModelFamily::MinimaxH3),
709 ("sortformer_diar_v2", ModelFamily::SortformerDiarV2),
710 ("sortformer-diar-v2", ModelFamily::SortformerDiarV2),
711 ("sortformer_diar", ModelFamily::SortformerDiar),
712 ("sortformer-diar", ModelFamily::SortformerDiar),
713 ("sortformer", ModelFamily::SortformerDiar),
714 ("seed_vc", ModelFamily::SeedVc),
715 ("seed-vc", ModelFamily::SeedVc),
716 ("seedvc", ModelFamily::SeedVc),
717 ("rvc", ModelFamily::Rvc),
718 ("meanvc2", ModelFamily::Meanvc2),
719 ("mean-vc2", ModelFamily::Meanvc2),
720 ("tone_color_vc", ModelFamily::ToneColorVc),
721 ("tone-color-vc", ModelFamily::ToneColorVc),
722 ("tone_color", ModelFamily::ToneColorVc),
723 ("tonecolor", ModelFamily::ToneColorVc),
724 ("chatterbox_turbo", ModelFamily::ChatterboxTurbo),
725 ("chatterbox-turbo", ModelFamily::ChatterboxTurbo),
726 ("chatterbox", ModelFamily::Chatterbox),
727 ("vevo2", ModelFamily::Vevo2),
728 ("voxcpm2", ModelFamily::Voxcpm2),
729 ("ace_step", ModelFamily::AceStep),
730 ("ace-step", ModelFamily::AceStep),
731 ("htdemucs_6stems", ModelFamily::Htdemucs6Stems),
733 ("htdemucs-6stems", ModelFamily::Htdemucs6Stems),
734 ("htdemucs_6s", ModelFamily::Htdemucs6Stems),
735 ("htdemucs-6s", ModelFamily::Htdemucs6Stems),
736 ("htdemucs", ModelFamily::Htdemucs),
737 ("demucs", ModelFamily::Htdemucs),
738 ("tf_gridnet", ModelFamily::TfGridnet),
739 ("tf-gridnet", ModelFamily::TfGridnet),
740 ("tfgridnet", ModelFamily::TfGridnet),
741 ("gridnet", ModelFamily::TfGridnet),
742 ("mel-band-roformer", ModelFamily::MelBandRoformer),
743 ("mel_band_roformer", ModelFamily::MelBandRoformer),
744 ("bs-roformer", ModelFamily::BsRoformer),
745 ("bs_roformer", ModelFamily::BsRoformer),
746 ("muscriptor", ModelFamily::Muscriptor),
747 ("omnivoice", ModelFamily::Omnivoice),
748 ("stable_audio", ModelFamily::StableAudio),
749 ("stable-audio", ModelFamily::StableAudio),
750 ("minimax_music3", ModelFamily::MinimaxMusic3),
751 ("minimax-music3", ModelFamily::MinimaxMusic3),
752 ("supertonic", ModelFamily::Supertonic),
753 ("yue2", ModelFamily::Yue2),
754 ("yue-2", ModelFamily::Yue2),
755 ("sheetsage2", ModelFamily::Sheetsage2),
756 ("sheetsage-2", ModelFamily::Sheetsage2),
757 ("sheetsage", ModelFamily::Sheetsage2),
758 ("voxtral-realtime", ModelFamily::VoxtralRealtime),
759 ("voxtral", ModelFamily::VoxtralRealtime),
760 ("audiosr", ModelFamily::Audiosr),
761 ("audio-sr", ModelFamily::Audiosr),
762 ("apollo", ModelFamily::Apollo),
763 ("universr", ModelFamily::Universr),
764 ("univer-sr", ModelFamily::Universr),
765 ("controlfoley", ModelFamily::ControlFoley),
766 ("control-foley", ModelFamily::ControlFoley),
767 ("midashenglm_gen", ModelFamily::MidashEnglmGen),
768 ("midashenglm-gen", ModelFamily::MidashEnglmGen),
769 ("midashen", ModelFamily::MidashEnglmGen),
770 ("builtin_audio_utils", ModelFamily::BuiltinAudioUtils),
771 ("builtin-audio-utils", ModelFamily::BuiltinAudioUtils),
772 ("deepfilternet", ModelFamily::BuiltinAudioUtils),
773 ("rnnoise", ModelFamily::BuiltinAudioUtils),
774 ("zipenhancer", ModelFamily::BuiltinAudioUtils),
775 ("gtcrn", ModelFamily::BuiltinAudioUtils),
776 ("flashsr", ModelFamily::BuiltinAudioUtils),
777 ("miocodec", ModelFamily::Miocodec),
778 ("miotts", ModelFamily::Miotts),
779 ("dramabox", ModelFamily::Dramabox),
780 ("heartmula", ModelFamily::Heartmula),
781 ("inflect", ModelFamily::InflectV2),
782 ("mms_forced_aligner", ModelFamily::MmsForcedAligner),
783 ("mms", ModelFamily::MmsForcedAligner),
784 ("forced-aligner", ModelFamily::Qwen3ForcedAligner),
785 ("micro_wake_word", ModelFamily::MicroWakeWord),
788 ("micro-wake-word", ModelFamily::MicroWakeWord),
789 ("micro_wake", ModelFamily::MicroWakeWord),
790 ("micro-wake", ModelFamily::MicroWakeWord),
791 ("microwake", ModelFamily::MicroWakeWord),
792 ("sherpa_kws", ModelFamily::SherpaKws),
793 ("sherpa-kws", ModelFamily::SherpaKws),
794 ("sherpa", ModelFamily::SherpaKws),
795 ("ced", ModelFamily::Ced),
796 ("ast_audioset", ModelFamily::AstAudioset),
797 ("ast-audioset", ModelFamily::AstAudioset),
798 ("audioset", ModelFamily::AstAudioset),
799 ];
800 KEYWORDS
801 .iter()
802 .find(|(k, _)| lower.contains(k))
803 .map(|(_, family)| family.clone())
804 }
805
806 pub fn as_str(&self) -> &str {
808 match self {
809 ModelFamily::SileroVad => "silero_vad",
810 ModelFamily::MarblenetVad => "marblenet_vad",
811 ModelFamily::Pulsevad => "pulsevad",
812 ModelFamily::FireredVad => "firered_vad",
813 ModelFamily::Qwen3Asr => "qwen3_asr",
814 ModelFamily::CitrinetAsr => "citrinet_asr",
815 ModelFamily::SenseAsr => "sense_asr",
816 ModelFamily::FunAsrNano => "fun_asr_nano",
817 ModelFamily::HiggsAudioStt => "higgs_audio_stt",
818 ModelFamily::HviskeAsr => "hviske_asr",
819 ModelFamily::HviskeAsrV6 => "hviske_asr_v6",
820 ModelFamily::KrokoAsr => "kroko_asr",
821 ModelFamily::NemotronAsr => "nemotron_asr",
822 ModelFamily::Nemotron3Diar => "nemotron_3_diar",
823 ModelFamily::ParakeetTdt => "parakeet_tdt",
824 ModelFamily::VibevoiceAsr => "vibevoice_asr",
825 ModelFamily::VibevoiceAsrStreaming => "vibevoice_asr_streaming",
826 ModelFamily::FireredAudio => "firered_audio",
827 ModelFamily::Granite5Asr => "granite5asr",
828 ModelFamily::Audio8Asr => "audio8_asr",
829 ModelFamily::Audio8Tts => "audio8_tts",
830 ModelFamily::Vibeasr => "vibeasr",
831 ModelFamily::MoonshineAsr => "moonshine_asr",
832 ModelFamily::NiagaraAsr => "niagara_asr",
833 ModelFamily::CanaryAsr => "canary_asr",
834 ModelFamily::CohereAsr => "cohere_asr",
835 ModelFamily::MossTranscribeDiarize => "moss_transcribe_diarize",
836 ModelFamily::Confucius4R2t2 => "confucius4_r2t2",
837 ModelFamily::AudioFlamingo => "audio_flamingo",
838 ModelFamily::Crisperwhisper => "crisperwhisper",
839 ModelFamily::GigaamAsr => "gigaam_asr",
840 ModelFamily::IndexEcho => "index_echo",
841 ModelFamily::Lfm2Audio => "lfm2_audio",
842 ModelFamily::Owsm => "owsm",
843 ModelFamily::OwsmCtc => "owsm_ctc",
844 ModelFamily::Samsone => "samsone",
845 ModelFamily::WhistleAsr => "whistle_asr",
846 ModelFamily::Qwen3Tts => "qwen3_tts",
847 ModelFamily::Confucius4Tts => "confucius4_tts",
848 ModelFamily::DotsTts => "dots_tts",
849 ModelFamily::FishAudio => "fish_audio",
850 ModelFamily::GlmTts => "glm_tts",
851 ModelFamily::HiggsAudioTts => "higgs_audio_tts",
852 ModelFamily::IndexTts2 => "index_tts2",
853 ModelFamily::IrodoriTts => "irodori_tts",
854 ModelFamily::MossTtsLocal => "moss_tts_local",
855 ModelFamily::MossTtsNano => "moss_tts_nano",
856 ModelFamily::MossTtsV15 => "moss_tts_v15",
857 ModelFamily::MossVoicegen => "moss_voicegen",
858 ModelFamily::Neutts => "neutts",
859 ModelFamily::Outetts => "outetts",
860 ModelFamily::PocketTts => "pocket_tts",
861 ModelFamily::VieneuV3Turbo => "vieneu_v3_turbo",
862 ModelFamily::Fireredtts3 => "fireredtts3",
863 ModelFamily::F5Tts => "f5_tts",
864 ModelFamily::MagpieTts => "magpie_tts",
865 ModelFamily::Personaplex => "personaplex",
866 ModelFamily::SopranoTts => "soprano_tts",
867 ModelFamily::EchoTts => "echo_tts",
868 ModelFamily::Voxcpm1 => "voxcpm1",
869 ModelFamily::KokoroTts => "kokoro_tts",
870 ModelFamily::Zipvoice => "zipvoice",
871 ModelFamily::Auk => "auk",
872 ModelFamily::PiperTts => "piper_tts",
873 ModelFamily::KittenTts => "kitten_tts",
874 ModelFamily::KittenTts2 => "kitten_tts2",
875 ModelFamily::Kugelaudio => "kugelaudio",
876 ModelFamily::Maya1 => "maya1",
877 ModelFamily::MossTtsd => "moss_ttsd",
878 ModelFamily::MinimaxH3 => "minimax_h3",
879 ModelFamily::Sanotts => "sanotts",
880 ModelFamily::SoproTts => "sopro_tts",
881 ModelFamily::MiraTts => "mira_tts",
882 ModelFamily::Cosyvoice3 => "cosyvoice3",
883 ModelFamily::BreezeTts => "breeze_tts",
884 ModelFamily::SortformerDiar => "sortformer_diar",
885 ModelFamily::SortformerDiarV2 => "sortformer_diar_v2",
886 ModelFamily::SeedVc => "seed_vc",
887 ModelFamily::Rvc => "rvc",
888 ModelFamily::Meanvc2 => "meanvc2",
889 ModelFamily::ToneColorVc => "tone_color_vc",
890 ModelFamily::Chatterbox => "chatterbox",
891 ModelFamily::ChatterboxTurbo => "chatterbox_turbo",
892 ModelFamily::Vevo2 => "vevo2",
893 ModelFamily::Voxcpm2 => "voxcpm2",
894 ModelFamily::AceStep => "ace_step",
895 ModelFamily::Htdemucs => "htdemucs",
896 ModelFamily::Htdemucs6Stems => "htdemucs_6stems",
897 ModelFamily::Mossformer2 => "mossformer2",
898 ModelFamily::TfGridnet => "tf_gridnet",
899 ModelFamily::MelBandRoformer => "mel_band_roformer",
900 ModelFamily::BsRoformer => "bs_roformer",
901 ModelFamily::Muscriptor => "muscriptor",
902 ModelFamily::Omnivoice => "omnivoice",
903 ModelFamily::StableAudio => "stable_audio",
904 ModelFamily::MinimaxMusic3 => "minimax_music3",
905 ModelFamily::Supertonic => "supertonic",
906 ModelFamily::Yue2 => "yue2",
907 ModelFamily::Sheetsage2 => "sheetsage2",
908 ModelFamily::VoxtralRealtime => "voxtral_realtime",
909 ModelFamily::Audiosr => "audiosr",
910 ModelFamily::Apollo => "apollo",
911 ModelFamily::Universr => "universr",
912 ModelFamily::BuiltinAudioUtils => "builtin_audio_utils",
913 ModelFamily::ControlFoley => "controlfoley",
914 ModelFamily::MidashEnglmGen => "midashenglm_gen",
915 ModelFamily::Liveavatar => "liveavatar",
916 ModelFamily::Reuse => "reuse",
917 ModelFamily::SamAudio => "sam_audio",
918 ModelFamily::Sidon => "sidon",
919 ModelFamily::SmartTurn => "smart_turn",
920 ModelFamily::MicroWakeWord => "micro_wake_word",
921 ModelFamily::SherpaKws => "sherpa_kws",
922 ModelFamily::Ced => "ced",
923 ModelFamily::AstAudioset => "ast_audioset",
924 ModelFamily::Miocodec => "miocodec",
925 ModelFamily::Miotts => "miotts",
926 ModelFamily::Vibevoice => "vibevoice",
927 ModelFamily::Dramabox => "dramabox",
928 ModelFamily::Heartmula => "heartmula",
929 ModelFamily::InflectV2 => "inflect_v2",
930 ModelFamily::Qwen3ForcedAligner => "qwen3_forced_aligner",
931 ModelFamily::MmsForcedAligner => "mms_forced_aligner",
932 ModelFamily::Custom(s) => s,
933 }
934 }
935}
936
937impl From<&str> for ModelFamily {
938 fn from(s: &str) -> Self {
940 match s {
941 "silero_vad" => ModelFamily::SileroVad,
942 "marblenet_vad" => ModelFamily::MarblenetVad,
943 "pulsevad" => ModelFamily::Pulsevad,
944 "firered_vad" => ModelFamily::FireredVad,
945 "firered-vad" => ModelFamily::FireredVad,
946 "qwen3_asr" => ModelFamily::Qwen3Asr,
947 "citrinet_asr" => ModelFamily::CitrinetAsr,
948 "sense_asr" => ModelFamily::SenseAsr,
949 "fun_asr_nano" => ModelFamily::FunAsrNano,
950 "higgs_audio_stt" => ModelFamily::HiggsAudioStt,
951 "hviske_asr" => ModelFamily::HviskeAsr,
952 "hviske_asr_v6" => ModelFamily::HviskeAsrV6,
953 "hviske-asr-v6" => ModelFamily::HviskeAsrV6,
954 "kroko_asr" => ModelFamily::KrokoAsr,
955 "nemotron_asr" => ModelFamily::NemotronAsr,
956 "nemotron_3_diar" => ModelFamily::Nemotron3Diar,
957 "parakeet_tdt" => ModelFamily::ParakeetTdt,
958 "vibevoice_asr" => ModelFamily::VibevoiceAsr,
959 "vibevoice_asr_streaming" => ModelFamily::VibevoiceAsrStreaming,
960 "firered_audio" => ModelFamily::FireredAudio,
961 "granite5asr" => ModelFamily::Granite5Asr,
962 "granite_speech5_asr" => ModelFamily::Granite5Asr,
963 "granite_speech" => ModelFamily::Granite5Asr,
964 "granite_speech5_ctc" => ModelFamily::Granite5Asr,
965 "audio8_asr" => ModelFamily::Audio8Asr,
966 "arkasr" => ModelFamily::Audio8Asr,
967 "audio8_tts" => ModelFamily::Audio8Tts,
968 "vibeasr" => ModelFamily::Vibeasr,
969 "moonshine_asr" => ModelFamily::MoonshineAsr,
970 "niagara_asr" => ModelFamily::NiagaraAsr,
971 "canary_asr" => ModelFamily::CanaryAsr,
972 "cohere_asr" => ModelFamily::CohereAsr,
973 "moss_transcribe_diarize" => ModelFamily::MossTranscribeDiarize,
974 "confucius4_r2t2" => ModelFamily::Confucius4R2t2,
975 "audio_flamingo" => ModelFamily::AudioFlamingo,
976 "crisperwhisper" => ModelFamily::Crisperwhisper,
977 "gigaam_asr" => ModelFamily::GigaamAsr,
978 "index_echo" => ModelFamily::IndexEcho,
979 "lfm2_audio" => ModelFamily::Lfm2Audio,
980 "owsm" => ModelFamily::Owsm,
981 "owsm_ctc" => ModelFamily::OwsmCtc,
982 "samsone" => ModelFamily::Samsone,
983 "whistle_asr" => ModelFamily::WhistleAsr,
984 "whistle-asr" => ModelFamily::WhistleAsr,
985 "qwen3_tts" => ModelFamily::Qwen3Tts,
986 "confucius4_tts" => ModelFamily::Confucius4Tts,
987 "dots_tts" => ModelFamily::DotsTts,
988 "fish_audio" => ModelFamily::FishAudio,
989 "glm_tts" => ModelFamily::GlmTts,
990 "higgs_audio_tts" => ModelFamily::HiggsAudioTts,
991 "index_tts2" => ModelFamily::IndexTts2,
992 "irodori_tts" => ModelFamily::IrodoriTts,
993 "moss_tts_local" => ModelFamily::MossTtsLocal,
994 "moss_tts_nano" => ModelFamily::MossTtsNano,
995 "moss_tts_v15" => ModelFamily::MossTtsV15,
996 "moss_voicegen" => ModelFamily::MossVoicegen,
997 "neutts" => ModelFamily::Neutts,
998 "outetts" => ModelFamily::Outetts,
999 "pocket_tts" => ModelFamily::PocketTts,
1000 "vietneu_tts" => ModelFamily::VieneuV3Turbo,
1001 "vieneu_v3_turbo" => ModelFamily::VieneuV3Turbo,
1002 "fireredtts3" => ModelFamily::Fireredtts3,
1003 "f5_tts" => ModelFamily::F5Tts,
1004 "magpie_tts" => ModelFamily::MagpieTts,
1005 "personaplex" => ModelFamily::Personaplex,
1006 "soprano_tts" => ModelFamily::SopranoTts,
1007 "echo_tts" => ModelFamily::EchoTts,
1008 "voxcpm1" => ModelFamily::Voxcpm1,
1009 "kokoro_tts" => ModelFamily::KokoroTts,
1010 "zipvoice" => ModelFamily::Zipvoice,
1011 "auk" => ModelFamily::Auk,
1012 "piper_tts" => ModelFamily::PiperTts,
1013 "kitten_tts" => ModelFamily::KittenTts,
1014 "kitten_tts2" => ModelFamily::KittenTts2,
1015 "kugelaudio" => ModelFamily::Kugelaudio,
1016 "maya1" => ModelFamily::Maya1,
1017 "moss_ttsd" => ModelFamily::MossTtsd,
1018 "minimax_h3" => ModelFamily::MinimaxH3,
1019 "sanotts" => ModelFamily::Sanotts,
1020 "sopro_tts" => ModelFamily::SoproTts,
1021 "sopro" => ModelFamily::SoproTts,
1022 "sopro_v2" => ModelFamily::SoproTts,
1023 "sopro_v2_turbo" => ModelFamily::SoproTts,
1024 "mira_tts" => ModelFamily::MiraTts,
1025 "miratts" => ModelFamily::MiraTts,
1026 "mira" => ModelFamily::MiraTts,
1027 "MiraTTS" => ModelFamily::MiraTts,
1028 "cosyvoice3" => ModelFamily::Cosyvoice3,
1029 "breeze_tts" => ModelFamily::BreezeTts,
1030 "sortformer_diar" => ModelFamily::SortformerDiar,
1031 "sortformer_diar_v2" => ModelFamily::SortformerDiarV2,
1032 "seed_vc" => ModelFamily::SeedVc,
1033 "rvc" => ModelFamily::Rvc,
1034 "meanvc2" => ModelFamily::Meanvc2,
1035 "tone_color_vc" => ModelFamily::ToneColorVc,
1036 "chatterbox" => ModelFamily::Chatterbox,
1037 "chatterbox_turbo" => ModelFamily::ChatterboxTurbo,
1038 "vevo2" => ModelFamily::Vevo2,
1039 "voxcpm2" => ModelFamily::Voxcpm2,
1040 "ace_step" => ModelFamily::AceStep,
1041 "htdemucs" => ModelFamily::Htdemucs,
1042 "htdemucs_6stems" => ModelFamily::Htdemucs6Stems,
1043 "htdemucs_6s" => ModelFamily::Htdemucs6Stems,
1044 "mossformer2" => ModelFamily::Mossformer2,
1045 "tf_gridnet" => ModelFamily::TfGridnet,
1046 "tf-gridnet" => ModelFamily::TfGridnet,
1047 "mel_band_roformer" => ModelFamily::MelBandRoformer,
1048 "bs_roformer" => ModelFamily::BsRoformer,
1049 "muscriptor" => ModelFamily::Muscriptor,
1050 "omnivoice" => ModelFamily::Omnivoice,
1051 "stable_audio" => ModelFamily::StableAudio,
1052 "minimax_music3" => ModelFamily::MinimaxMusic3,
1053 "supertonic" => ModelFamily::Supertonic,
1054 "yue2" => ModelFamily::Yue2,
1055 "sheetsage2" => ModelFamily::Sheetsage2,
1056 "voxtral_realtime" => ModelFamily::VoxtralRealtime,
1057 "audiosr" => ModelFamily::Audiosr,
1058 "apollo" => ModelFamily::Apollo,
1059 "universr" => ModelFamily::Universr,
1060 "builtin_audio_utils" => ModelFamily::BuiltinAudioUtils,
1061 "controlfoley" => ModelFamily::ControlFoley,
1062 "midashenglm_gen" => ModelFamily::MidashEnglmGen,
1063 "liveavatar" => ModelFamily::Liveavatar,
1064 "reuse" => ModelFamily::Reuse,
1065 "sam_audio" => ModelFamily::SamAudio,
1066 "sidon" => ModelFamily::Sidon,
1067 "smart_turn" => ModelFamily::SmartTurn,
1068 "micro_wake_word" => ModelFamily::MicroWakeWord,
1069 "micro-wake-word" => ModelFamily::MicroWakeWord,
1070 "sherpa_kws" => ModelFamily::SherpaKws,
1071 "sherpa-kws" => ModelFamily::SherpaKws,
1072 "ced" => ModelFamily::Ced,
1073 "ast_audioset" => ModelFamily::AstAudioset,
1074 "ast-audioset" => ModelFamily::AstAudioset,
1075 "miocodec" => ModelFamily::Miocodec,
1076 "miotts" => ModelFamily::Miotts,
1077 "vibevoice" => ModelFamily::Vibevoice,
1078 "dramabox" => ModelFamily::Dramabox,
1079 "heartmula" => ModelFamily::Heartmula,
1080 "inflect_v2" => ModelFamily::InflectV2,
1081 "qwen3_forced_aligner" => ModelFamily::Qwen3ForcedAligner,
1082 "mms_forced_aligner" => ModelFamily::MmsForcedAligner,
1083 other => ModelFamily::Custom(other.to_owned()),
1084 }
1085 }
1086}
1087
1088impl From<String> for ModelFamily {
1089 fn from(s: String) -> Self {
1090 ModelFamily::from(s.as_str())
1091 }
1092}
1093
1094impl AsRef<str> for ModelFamily {
1095 fn as_ref(&self) -> &str {
1096 self.as_str()
1097 }
1098}
1099
1100impl std::fmt::Display for ModelFamily {
1101 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1102 f.write_str(self.as_str())
1103 }
1104}
1105
1106#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
1108#[serde(rename_all = "lowercase")]
1109pub enum Backend {
1110 Cpu,
1112 Cuda,
1114 Hip,
1116 Vulkan,
1118 Metal,
1120 Best,
1122}
1123
1124impl Backend {
1125 pub fn as_str(self) -> &'static str {
1127 match self {
1128 Backend::Cpu => "cpu",
1129 Backend::Cuda => "cuda",
1130 Backend::Hip => "hip",
1131 Backend::Vulkan => "vulkan",
1132 Backend::Metal => "metal",
1133 Backend::Best => "best",
1134 }
1135 }
1136}
1137
1138#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1140pub struct Device {
1141 pub backend: String,
1143 pub index: i32,
1145 pub name: String,
1147 #[serde(rename = "type")]
1149 pub kind: String,
1150}
1151
1152#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1154pub struct LoaderInfo {
1155 pub family: String,
1157 pub capabilities: Capabilities,
1159 pub instructions_policy: String,
1161 pub api_endpoints: Vec<String>,
1163}
1164
1165#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1167pub struct Capabilities {
1168 pub supported_tasks: Vec<SupportedTask>,
1170 pub languages: Vec<String>,
1172 pub supports_speaker_reference: bool,
1174 pub supports_style_condition: bool,
1176 pub supports_timestamps: bool,
1178}
1179
1180#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1182pub struct SupportedTask {
1183 pub task: String,
1185 pub modes: Vec<String>,
1187}
1188
1189#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1191pub struct ModelMetadata {
1192 pub family: String,
1194 pub variant: String,
1196 pub description: String,
1198 pub config_candidates: Vec<String>,
1200 pub weight_candidates: Vec<String>,
1202}
1203
1204#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
1206pub struct TimeSpan {
1207 pub start_sample: i64,
1209 pub end_sample: i64,
1211}
1212
1213#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1215pub struct SpeechSegment {
1216 pub span: TimeSpan,
1218 pub confidence: f32,
1220 pub text: String,
1222}
1223
1224#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1226pub struct SpeakerTurn {
1227 pub speaker_id: String,
1229 pub span: TimeSpan,
1231 pub confidence: f32,
1233 #[serde(default)]
1235 pub text: String,
1236}
1237
1238#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1240pub struct WordTimestamp {
1241 pub span: TimeSpan,
1243 pub word: String,
1245 pub confidence: f32,
1247}
1248
1249#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1251pub struct VoiceArtifact {
1252 pub kind: String,
1254 pub id: String,
1256 #[serde(default)]
1258 pub payload_base64: String,
1259 #[serde(default)]
1261 pub meta: BTreeMap<String, String>,
1262}
1263
1264#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1266pub struct CliOption {
1267 pub name: String,
1269 pub value_name: String,
1271 pub description: String,
1273 pub required: bool,
1275 #[serde(default, skip_serializing_if = "Option::is_none")]
1277 pub default_value: Option<String>,
1278 #[serde(default, skip_serializing_if = "Option::is_none")]
1280 pub min_value: Option<String>,
1281 #[serde(default, skip_serializing_if = "Option::is_none")]
1283 pub max_value: Option<String>,
1284}
1285
1286#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1288pub struct NamedAsset {
1289 pub id: String,
1291 pub path: String,
1293}
1294
1295#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1297pub struct CliInterface {
1298 #[serde(default)]
1300 pub request_options: Vec<CliOption>,
1301 #[serde(default)]
1303 pub session_options: Vec<CliOption>,
1304 #[serde(default)]
1306 pub load_options: Vec<CliOption>,
1307}
1308
1309#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1311pub struct ModelInspection {
1312 pub metadata: ModelMetadata,
1314 pub capabilities: Capabilities,
1316 pub cli: CliInterface,
1318 #[serde(default)]
1320 pub discovered_configs: Vec<NamedAsset>,
1321 #[serde(default)]
1323 pub discovered_weights: Vec<NamedAsset>,
1324 #[serde(default)]
1326 pub model_root: String,
1327}
1328
1329#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1331pub struct TextOutput {
1332 pub text: String,
1334 pub language: String,
1336}
1337
1338#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1340pub struct AudioBufferInfo {
1341 pub sample_rate: i32,
1343 pub channels: i32,
1345 pub sample_count: usize,
1347 #[serde(default)]
1350 pub samples: Option<Vec<f32>>,
1351}
1352
1353#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1355pub struct NamedAudioOutput {
1356 pub id: String,
1358 pub audio: AudioBufferInfo,
1360 pub meta: BTreeMap<String, String>,
1362}
1363
1364#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1373pub struct CustomSchemaOutput {
1374 pub schema: String,
1376 pub data: serde_json::Value,
1378}
1379
1380#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1382pub struct TaskResult {
1383 pub speech_segments: Vec<SpeechSegment>,
1385 pub speaker_turns: Vec<SpeakerTurn>,
1387 pub text_output: Option<TextOutput>,
1389 pub audio_output: Option<AudioBufferInfo>,
1391 pub named_audio_outputs: Vec<NamedAudioOutput>,
1393 #[serde(default)]
1404 pub word_timestamps: Vec<WordTimestamp>,
1405 #[serde(default)]
1407 pub custom_schema_output: Option<CustomSchemaOutput>,
1408 #[serde(default)]
1410 pub artifact_output: Option<VoiceArtifact>,
1411 #[serde(default)]
1413 pub output_artifacts: Vec<VoiceArtifact>,
1414}
1415
1416#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1418pub struct StreamEvent {
1419 pub voice_activity: Vec<VoiceActivityEvent>,
1421 pub partial_text: Option<TextOutput>,
1423 #[serde(default)]
1427 pub partial_text_snapshot: Option<TextOutput>,
1428 pub audio_output: Option<AudioBufferInfo>,
1430 #[serde(default)]
1432 pub named_audio_outputs: Vec<NamedAudioOutput>,
1433 #[serde(default)]
1435 pub speaker_turns: Vec<SpeakerTurn>,
1436 #[serde(default)]
1439 pub word_timestamps: Vec<WordTimestamp>,
1440 #[serde(default)]
1442 pub output_artifacts: Vec<VoiceArtifact>,
1443 pub is_final: bool,
1445}
1446
1447#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1449pub struct VoiceActivityEvent {
1450 pub kind: String,
1452 pub sample: i64,
1454 pub probability: f32,
1456 pub segment: Option<SpeechSegment>,
1458}
1459
1460#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1462pub struct StreamingPolicy {
1463 pub input: String,
1465 pub output: String,
1467 pub preferred_audio_chunk_samples: usize,
1469 pub preferred_audio_chunk_seconds: f64,
1471}
1472
1473#[cfg(test)]
1474mod tests {
1475 #![allow(clippy::unwrap_used, clippy::expect_used)]
1477 use super::*;
1478
1479 #[test]
1483 fn model_family_roundtrip() {
1484 let mut variants: Vec<ModelFamily> = Vec::new();
1485 macro_rules! push {
1486 ($($v:ident),* $(,)?) => {
1487 $(variants.push(ModelFamily::$v);)*
1488 };
1489 }
1490 push![
1491 SileroVad,
1493 MarblenetVad,
1494 Pulsevad,
1495 FireredVad,
1496 Qwen3Asr,
1498 CitrinetAsr,
1499 SenseAsr,
1500 FunAsrNano,
1501 HiggsAudioStt,
1502 HviskeAsr,
1503 HviskeAsrV6,
1504 KrokoAsr,
1505 NemotronAsr,
1506 Nemotron3Diar,
1507 ParakeetTdt,
1508 VibevoiceAsr,
1509 VibevoiceAsrStreaming,
1510 FireredAudio,
1511 Granite5Asr,
1512 Audio8Asr,
1513 Audio8Tts,
1514 Vibeasr,
1515 MoonshineAsr,
1516 NiagaraAsr,
1517 CanaryAsr,
1518 CohereAsr,
1519 MossTranscribeDiarize,
1520 Confucius4R2t2,
1521 AudioFlamingo,
1522 Crisperwhisper,
1523 GigaamAsr,
1524 IndexEcho,
1525 Lfm2Audio,
1526 Owsm,
1527 OwsmCtc,
1528 Samsone,
1529 WhistleAsr,
1530 Qwen3Tts,
1532 Confucius4Tts,
1533 DotsTts,
1534 FishAudio,
1535 GlmTts,
1536 HiggsAudioTts,
1537 IndexTts2,
1538 IrodoriTts,
1539 MossTtsLocal,
1540 MossTtsNano,
1541 MossTtsV15,
1542 MossVoicegen,
1543 Neutts,
1544 Outetts,
1545 PocketTts,
1546 VieneuV3Turbo,
1547 Fireredtts3,
1548 F5Tts,
1549 MagpieTts,
1550 Personaplex,
1551 SopranoTts,
1552 EchoTts,
1553 Voxcpm1,
1554 KokoroTts,
1555 Zipvoice,
1556 Auk,
1557 PiperTts,
1558 KittenTts,
1559 KittenTts2,
1560 Kugelaudio,
1561 Maya1,
1562 MossTtsd,
1563 MinimaxH3,
1564 Sanotts,
1565 SoproTts,
1566 MiraTts,
1567 Cosyvoice3,
1568 BreezeTts,
1569 SortformerDiar,
1571 SortformerDiarV2,
1572 SeedVc,
1573 Rvc,
1574 Meanvc2,
1575 ToneColorVc,
1576 Chatterbox,
1577 ChatterboxTurbo,
1578 Vevo2,
1579 Voxcpm2,
1580 AceStep,
1581 Htdemucs,
1582 Htdemucs6Stems,
1583 Mossformer2,
1584 TfGridnet,
1585 MelBandRoformer,
1586 BsRoformer,
1587 Muscriptor,
1588 Omnivoice,
1589 StableAudio,
1590 MinimaxMusic3,
1591 Supertonic,
1592 Yue2,
1593 Sheetsage2,
1594 VoxtralRealtime,
1595 Audiosr,
1596 Apollo,
1597 Universr,
1598 BuiltinAudioUtils,
1599 ControlFoley,
1600 MidashEnglmGen,
1601 Liveavatar,
1602 Reuse,
1603 SamAudio,
1604 Sidon,
1605 SmartTurn,
1606 MicroWakeWord,
1608 SherpaKws,
1609 Ced,
1610 AstAudioset,
1611 Miocodec,
1613 Miotts,
1614 Vibevoice,
1615 Dramabox,
1616 Heartmula,
1617 InflectV2,
1618 Qwen3ForcedAligner,
1619 MmsForcedAligner,
1620 ];
1621 assert!(
1622 variants.len() >= 40,
1623 "ModelFamily 应至少覆盖上游全部 40+ loader 族,当前 {}",
1624 variants.len()
1625 );
1626 for v in variants {
1627 let name = v.as_str();
1628 assert_eq!(
1629 ModelFamily::from(name),
1630 v,
1631 "as_str() 与 From<&str> 不一致:{}",
1632 name
1633 );
1634 assert_eq!(format!("{v}"), name);
1636 assert_eq!(v.as_ref(), name);
1637 }
1638 }
1639
1640 #[test]
1641 fn model_family_custom_fallback() {
1642 let m = ModelFamily::from("brand_new_family");
1644 match &m {
1645 ModelFamily::Custom(s) => assert_eq!(s, "brand_new_family"),
1646 other => panic!("未收录名字应落入 Custom,得到 {other:?}"),
1647 }
1648 assert_eq!(m.as_str(), "brand_new_family");
1649 assert_eq!(
1651 ModelFamily::from("brand_new_family"),
1652 ModelFamily::Custom("brand_new_family".to_owned())
1653 );
1654 assert_eq!(
1656 ModelFamily::from("qwen3_asr".to_owned()),
1657 ModelFamily::Qwen3Asr
1658 );
1659 }
1660
1661 #[test]
1662 fn model_family_from_path() {
1663 assert_eq!(
1665 ModelFamily::from_path("models/qwen3-asr-0.6b-q8_0.gguf"),
1666 Some(ModelFamily::Qwen3Asr)
1667 );
1668 assert_eq!(
1669 ModelFamily::from_path("sortformer-diar-4spk-v1-q8_0.gguf"),
1670 Some(ModelFamily::SortformerDiar)
1671 );
1672 assert_eq!(
1673 ModelFamily::from_path("citrinet-asr-q8_0.gguf"),
1674 Some(ModelFamily::CitrinetAsr)
1675 );
1676 assert_eq!(
1677 ModelFamily::from_path("moss-tts-nano-q8_0.gguf"),
1678 Some(ModelFamily::MossTtsNano)
1679 );
1680 assert_eq!(
1682 ModelFamily::from_path("moss-tts-v15-q8_0.gguf"),
1683 Some(ModelFamily::MossTtsV15)
1684 );
1685 assert_eq!(
1687 ModelFamily::from_path("nemotron-3-diarization-bf16.gguf"),
1688 Some(ModelFamily::Nemotron3Diar)
1689 );
1690 assert_eq!(
1692 ModelFamily::from_path("vieneu-v3-turbo-q8_0.gguf"),
1693 Some(ModelFamily::VieneuV3Turbo)
1694 );
1695 assert_eq!(ModelFamily::from("vietneu_tts"), ModelFamily::VieneuV3Turbo);
1696 assert_eq!(
1698 ModelFamily::from_path("qwen3-tts-12hz-0.6b-base-q8_0.gguf"),
1699 Some(ModelFamily::Qwen3Tts)
1700 );
1701 assert_eq!(
1702 ModelFamily::from_path("qwen3-forced-aligner-q8_0.gguf"),
1703 Some(ModelFamily::Qwen3ForcedAligner)
1704 );
1705 assert_eq!(
1706 ModelFamily::from_path("mira-tts-q8_0.gguf"),
1707 Some(ModelFamily::MiraTts)
1708 );
1709 assert_eq!(
1710 ModelFamily::from_path("htdemucs-6s-q8_0.gguf"),
1711 Some(ModelFamily::Htdemucs6Stems)
1712 );
1713 assert_eq!(
1715 ModelFamily::from_path("htdemucs-q8_0.gguf"),
1716 Some(ModelFamily::Htdemucs)
1717 );
1718 assert_eq!(
1720 ModelFamily::from_path("kitten-tts2-q8_0.gguf"),
1721 Some(ModelFamily::KittenTts2)
1722 );
1723 assert_eq!(
1724 ModelFamily::from_path("kitten-tts-q8_0.gguf"),
1725 Some(ModelFamily::KittenTts)
1726 );
1727 assert_eq!(
1729 ModelFamily::from_path("index-echo-q8_0.gguf"),
1730 Some(ModelFamily::IndexEcho)
1731 );
1732 assert_eq!(
1733 ModelFamily::from_path("echo-tts-q8_0.gguf"),
1734 Some(ModelFamily::EchoTts)
1735 );
1736 assert_eq!(
1738 ModelFamily::from_path("owsm-ctc-q8_0.gguf"),
1739 Some(ModelFamily::OwsmCtc)
1740 );
1741 assert_eq!(
1742 ModelFamily::from_path("owsm-q8_0.gguf"),
1743 Some(ModelFamily::Owsm)
1744 );
1745 assert_eq!(
1747 ModelFamily::from_path("moss-ttsd-q8_0.gguf"),
1748 Some(ModelFamily::MossTtsd)
1749 );
1750 assert_eq!(
1752 ModelFamily::from_path("smart-turn-q8_0.gguf"),
1753 Some(ModelFamily::SmartTurn)
1754 );
1755 assert_eq!(
1757 ModelFamily::from_path("firered-vad-q8_0.gguf"),
1758 Some(ModelFamily::FireredVad)
1759 );
1760 assert_eq!(
1762 ModelFamily::from_path("hviske-asr-v6-q8_0.gguf"),
1763 Some(ModelFamily::HviskeAsrV6)
1764 );
1765 assert_eq!(
1766 ModelFamily::from_path("hviske-asr-q8_0.gguf"),
1767 Some(ModelFamily::HviskeAsr)
1768 );
1769 assert_eq!(
1770 ModelFamily::from_path("whistle-asr-q8_0.gguf"),
1771 Some(ModelFamily::WhistleAsr)
1772 );
1773 assert_eq!(
1775 ModelFamily::from_path("mossformer2-ss-16k-f32.gguf"),
1776 Some(ModelFamily::Mossformer2)
1777 );
1778 assert_eq!(
1779 ModelFamily::from_path("tf-gridnet-q8_0.gguf"),
1780 Some(ModelFamily::TfGridnet)
1781 );
1782 assert_eq!(
1784 ModelFamily::from_path("micro-wake-word-hey-jarvis-q8_0.gguf"),
1785 Some(ModelFamily::MicroWakeWord)
1786 );
1787 assert_eq!(
1788 ModelFamily::from_path("sherpa-kws-keywords-q8_0.gguf"),
1789 Some(ModelFamily::SherpaKws)
1790 );
1791 assert_eq!(
1793 ModelFamily::from_path("ced-base-16k-q8_0.gguf"),
1794 Some(ModelFamily::Ced)
1795 );
1796 assert_eq!(
1797 ModelFamily::from_path("qwen3-forced-aligner-q8_0.gguf"),
1798 Some(ModelFamily::Qwen3ForcedAligner)
1799 );
1800 assert_eq!(
1801 ModelFamily::from_path("ast-audioset-q8_0.gguf"),
1802 Some(ModelFamily::AstAudioset)
1803 );
1804 assert_eq!(
1805 ModelFamily::from_path("tone-color-vc-q8_0.gguf"),
1806 Some(ModelFamily::ToneColorVc)
1807 );
1808 assert_eq!(
1809 ModelFamily::from("htdemucs_6s"),
1810 ModelFamily::Htdemucs6Stems
1811 );
1812 assert_eq!(
1814 ModelFamily::from_path("vibevoice-asr-streaming-7b-q8_0.gguf"),
1815 Some(ModelFamily::VibevoiceAsrStreaming)
1816 );
1817 assert_eq!(
1818 ModelFamily::from_path("sortformer-diar-v2-q8_0.gguf"),
1819 Some(ModelFamily::SortformerDiarV2)
1820 );
1821 assert_eq!(
1822 ModelFamily::from_path("kokoro-tts-82m-q8_0.gguf"),
1823 Some(ModelFamily::KokoroTts)
1824 );
1825 assert_eq!(
1826 ModelFamily::from_path("moonshine-tiny-q8_0.gguf"),
1827 Some(ModelFamily::MoonshineAsr)
1828 );
1829 assert_eq!(
1830 ModelFamily::from_path("niagara-asr-q8_0.gguf"),
1831 Some(ModelFamily::NiagaraAsr)
1832 );
1833 assert_eq!(
1834 ModelFamily::from_path("yue2-music-q8_0.gguf"),
1835 Some(ModelFamily::Yue2)
1836 );
1837 assert_eq!(
1838 ModelFamily::from_path("sheetsage2-q8_0.gguf"),
1839 Some(ModelFamily::Sheetsage2)
1840 );
1841 assert_eq!(
1842 ModelFamily::from_path("pulsevad-2.1k-f32.gguf"),
1843 Some(ModelFamily::Pulsevad)
1844 );
1845 assert_eq!(
1846 ModelFamily::from_path("canary-180m-flash-q8_0.gguf"),
1847 Some(ModelFamily::CanaryAsr)
1848 );
1849 assert_eq!(
1850 ModelFamily::from_path("cohere-transcribe-03-2026-q8_0.gguf"),
1851 Some(ModelFamily::CohereAsr)
1852 );
1853 assert_eq!(
1855 ModelFamily::from_path("moss-transcribe-diarize-q8_0.gguf"),
1856 Some(ModelFamily::MossTranscribeDiarize)
1857 );
1858 assert_eq!(
1859 ModelFamily::from_path("apollo-orig.gguf"),
1860 Some(ModelFamily::Apollo)
1861 );
1862 assert_eq!(
1863 ModelFamily::from_path("universr-audio-orig.gguf"),
1864 Some(ModelFamily::Universr)
1865 );
1866 assert_eq!(
1867 ModelFamily::from_path("zipvoice-distill-q8_0.gguf"),
1868 Some(ModelFamily::Zipvoice)
1869 );
1870 assert_eq!(
1871 ModelFamily::from_path("auk-flash-q8_0.gguf"),
1872 Some(ModelFamily::Auk)
1873 );
1874 assert_eq!(
1875 ModelFamily::from_path("liveavatar-nvfp4.gguf"),
1876 Some(ModelFamily::Liveavatar)
1877 );
1878 assert_eq!(
1879 ModelFamily::from_path("piper-en-us-lessac-medium-orig.gguf"),
1880 Some(ModelFamily::PiperTts)
1881 );
1882 assert_eq!(
1883 ModelFamily::from_path("kitten-tts-mini-0.8-orig.gguf"),
1884 Some(ModelFamily::KittenTts)
1885 );
1886 assert_eq!(
1888 ModelFamily::from_path("confucius4-r2t2-q8_0.gguf"),
1889 Some(ModelFamily::Confucius4R2t2)
1890 );
1891 assert_eq!(
1892 ModelFamily::from_path("confucius4-tts-q8_0.gguf"),
1893 Some(ModelFamily::Confucius4Tts)
1894 );
1895 assert_eq!(
1897 ModelFamily::from_path("deepfilternet2"),
1898 Some(ModelFamily::BuiltinAudioUtils)
1899 );
1900 assert_eq!(
1902 ModelFamily::from_path("Qwen3-ASR.Q8_0.GGUF"),
1903 Some(ModelFamily::Qwen3Asr)
1904 );
1905 assert_eq!(
1907 ModelFamily::from_path("model.gguf#family=citrinet_asr"),
1908 Some(ModelFamily::CitrinetAsr)
1909 );
1910 assert_eq!(
1911 ModelFamily::from_path("model.gguf#family=MiraTTS"),
1912 Some(ModelFamily::MiraTts)
1913 );
1914 assert_eq!(
1915 ModelFamily::from_path("model.gguf#family=qwen3_tts"),
1916 Some(ModelFamily::Qwen3Tts)
1917 );
1918 assert_eq!(ModelFamily::from_path("my-weights.gguf"), None);
1920 assert_eq!(ModelFamily::from_path(""), None);
1921 }
1922
1923 #[test]
1924 fn task_kind_as_str() {
1925 let cases = [
1926 (TaskKind::Vad, "vad"),
1927 (TaskKind::Asr, "asr"),
1928 (TaskKind::Diar, "diar"),
1929 (TaskKind::SourceSeparation, "sep"),
1930 (TaskKind::AudioGeneration, "gen"),
1931 (TaskKind::Tts, "tts"),
1932 (TaskKind::VoiceCloning, "clon"),
1933 (TaskKind::VoiceConversion, "vc"),
1934 (TaskKind::SpeechToSpeech, "s2s"),
1935 (TaskKind::Alignment, "align"),
1936 (TaskKind::VoiceDesign, "vdes"),
1937 (TaskKind::SpeakerRecognition, "spk"),
1938 (TaskKind::Svc, "svc"),
1939 (TaskKind::Midi, "midi"),
1940 (TaskKind::TurnDetection, "turn"),
1941 (TaskKind::WakeWord, "wake"),
1942 (TaskKind::AudioClassification, "cls"),
1943 ];
1944 for (k, want) in cases {
1945 assert_eq!(k.as_str(), want);
1946 }
1947 }
1948
1949 #[test]
1950 fn task_kind_aliases() {
1951 assert_eq!(
1953 serde_json::from_str::<TaskKind>("\"wake_word\"").unwrap(),
1954 TaskKind::WakeWord
1955 );
1956 assert_eq!(
1957 serde_json::from_str::<TaskKind>("\"classify\"").unwrap(),
1958 TaskKind::AudioClassification
1959 );
1960 }
1961
1962 #[test]
1963 fn task_kind_serde_roundtrip() {
1964 let all = [
1967 TaskKind::Vad,
1968 TaskKind::Asr,
1969 TaskKind::Diar,
1970 TaskKind::SourceSeparation,
1971 TaskKind::AudioGeneration,
1972 TaskKind::Tts,
1973 TaskKind::VoiceCloning,
1974 TaskKind::VoiceConversion,
1975 TaskKind::SpeechToSpeech,
1976 TaskKind::Alignment,
1977 TaskKind::VoiceDesign,
1978 TaskKind::SpeakerRecognition,
1979 TaskKind::Svc,
1980 TaskKind::Midi,
1981 TaskKind::TurnDetection,
1982 TaskKind::WakeWord,
1983 TaskKind::AudioClassification,
1984 ];
1985 for k in all {
1986 let s = serde_json::to_string(&k).unwrap();
1987 assert_eq!(s, format!("\"{}\"", k.as_str()));
1988 assert_eq!(serde_json::from_str::<TaskKind>(&s).unwrap(), k);
1989 }
1990 assert!(serde_json::from_str::<TaskKind>("\"sourceseparation\"").is_err());
1991 }
1992
1993 #[test]
1994 fn run_mode_as_str() {
1995 assert_eq!(RunMode::Offline.as_str(), "offline");
1996 assert_eq!(RunMode::Streaming.as_str(), "streaming");
1997 }
1998
1999 #[test]
2000 fn backend_as_str() {
2001 let cases = [
2002 (Backend::Cpu, "cpu"),
2003 (Backend::Cuda, "cuda"),
2004 (Backend::Hip, "hip"),
2005 (Backend::Vulkan, "vulkan"),
2006 (Backend::Metal, "metal"),
2007 (Backend::Best, "best"),
2008 ];
2009 for (b, want) in cases {
2010 assert_eq!(b.as_str(), want);
2011 }
2012 }
2013
2014 #[test]
2016 fn structured_types_deserialize() {
2017 let result: TaskResult = serde_json::from_str(
2018 r#"{
2019 "speech_segments": [
2020 {"span": {"start_sample": 0, "end_sample": 1600}, "confidence": 0.95, "text": ""}
2021 ],
2022 "text_output": {"text": "hi", "language": "en"},
2023 "audio_output": {"sample_rate": 24000, "channels": 1, "sample_count": 0, "samples": []},
2024 "named_audio_outputs": [],
2025 "speaker_turns": [
2026 {"speaker_id": "speaker_0", "span": {"start_sample": 0, "end_sample": 1600}, "confidence": 0.9, "text": "hello"}
2027 ],
2028 "word_timestamps": [
2029 {"span": {"start_sample": 0, "end_sample": 320}, "word": "hello", "confidence": 0.99}
2030 ],
2031 "artifact_output": {"kind": "speaker_embedding", "id": "spk1", "payload_base64": "", "meta": {}},
2032 "output_artifacts": [
2033 {"kind": "custom", "id": "a", "payload_base64": "AQID", "meta": {"k": "v"}}
2034 ]
2035 }"#,
2036 )
2037 .unwrap();
2038 assert_eq!(result.speech_segments.len(), 1);
2039 assert_eq!(result.speech_segments[0].span.start_sample, 0);
2040 assert_eq!(result.speech_segments[0].confidence, 0.95);
2041 assert_eq!(result.text_output.as_ref().unwrap().text, "hi");
2042 assert_eq!(result.audio_output.unwrap().sample_rate, 24000);
2043 assert_eq!(result.speaker_turns[0].text, "hello");
2044 assert_eq!(result.word_timestamps[0].word, "hello");
2045 assert_eq!(
2046 result.artifact_output.as_ref().unwrap().kind,
2047 "speaker_embedding"
2048 );
2049 assert_eq!(result.output_artifacts[0].payload_base64, "AQID");
2050
2051 let ev: StreamEvent = serde_json::from_str(
2052 r#"{
2053 "voice_activity": [
2054 {"kind": "speech_start", "sample": 100, "probability": 0.8, "segment": null}
2055 ],
2056 "partial_text": null,
2057 "partial_text_snapshot": {"text": "hel", "language": "en"},
2058 "audio_output": null,
2059 "named_audio_outputs": [{"id": "chunk_0", "audio": {"sample_rate": 48000, "channels": 2, "sample_count": 320, "samples": []}, "meta": {}}],
2060 "speaker_turns": [],
2061 "word_timestamps": [],
2062 "output_artifacts": [],
2063 "is_final": true
2064 }"#,
2065 )
2066 .unwrap();
2067 assert_eq!(ev.voice_activity[0].kind, "speech_start");
2068 assert_eq!(ev.named_audio_outputs[0].id, "chunk_0");
2069 assert_eq!(ev.partial_text_snapshot.as_ref().unwrap().text, "hel");
2070 assert!(ev.is_final);
2071 }
2072
2073 #[test]
2074 fn model_inspection_deserialize() {
2075 let info: ModelInspection = serde_json::from_str(
2078 r#"{
2079 "metadata": {
2080 "family": "qwen3_asr",
2081 "variant": "q8_0",
2082 "description": "Qwen3 ASR",
2083 "config_candidates": ["config.json"],
2084 "weight_candidates": ["qwen3-asr-q8_0.gguf"]
2085 },
2086 "capabilities": {
2087 "supported_tasks": [{"task": "asr", "modes": ["offline", "streaming"]}],
2088 "languages": ["zh", "en"],
2089 "supports_speaker_reference": false,
2090 "supports_style_condition": false,
2091 "supports_timestamps": true
2092 },
2093 "discovered_weights": [
2094 {"id": "model", "path": "/models/qwen3-asr-q8_0.gguf"}
2095 ],
2096 "cli": {
2097 "request_options": [
2098 {"name": "language", "value_name": "CODE", "description": "语言", "required": false, "default_value": "auto"}
2099 ],
2100 "session_options": [],
2101 "load_options": []
2102 }
2103 }"#,
2104 )
2105 .unwrap();
2106 assert_eq!(info.metadata.family, "qwen3_asr");
2107 assert!(
2108 info.capabilities
2109 .supported_tasks
2110 .iter()
2111 .any(|t| t.task == "asr" && t.modes.contains(&"streaming".to_string()))
2112 );
2113 assert_eq!(info.discovered_weights[0].id, "model");
2114 assert_eq!(info.cli.request_options[0].name, "language");
2115 assert_eq!(
2116 info.cli.request_options[0].default_value.as_deref(),
2117 Some("auto")
2118 );
2119 }
2120}