1use crate::config::MoshiVoice;
8use std::path::{Path, PathBuf};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12pub enum MoshiCheckpoint {
13 Bf16Safetensors,
15 Q8Gguf,
17 Q4MlxSafetensors,
19 Q8MlxSafetensors,
21 MlxBf16Safetensors,
23}
24
25impl MoshiCheckpoint {
26 pub fn hf_repo(self, voice: MoshiVoice) -> &'static str {
28 match (voice, self) {
29 (MoshiVoice::Moshiko, Self::Bf16Safetensors) => "kyutai/moshiko-candle-bf16",
30 (MoshiVoice::Moshiko, Self::Q8Gguf) => "kyutai/moshiko-candle-q8",
31 (MoshiVoice::Moshiko, Self::Q4MlxSafetensors) => "kyutai/moshiko-mlx-q4",
32 (MoshiVoice::Moshiko, Self::Q8MlxSafetensors) => "kyutai/moshiko-mlx-q8",
33 (MoshiVoice::Moshiko, Self::MlxBf16Safetensors) => "kyutai/moshiko-mlx-bf16",
34 (MoshiVoice::Moshika, Self::Bf16Safetensors) => "kyutai/moshika-candle-bf16",
35 (MoshiVoice::Moshika, Self::Q8Gguf) => "kyutai/moshika-candle-q8",
36 (MoshiVoice::Moshika, Self::Q4MlxSafetensors) => "kyutai/moshika-mlx-q4",
37 (MoshiVoice::Moshika, Self::Q8MlxSafetensors) => "kyutai/moshika-mlx-q8",
38 (MoshiVoice::Moshika, Self::MlxBf16Safetensors) => "kyutai/moshika-mlx-bf16",
39 }
40 }
41
42 pub fn default_cache_dir(self, voice: MoshiVoice) -> PathBuf {
44 let prefix = match voice {
45 MoshiVoice::Moshiko => "moshiko",
46 MoshiVoice::Moshika => "moshika",
47 };
48 let suffix = match self {
49 Self::Bf16Safetensors => "",
50 Self::Q8Gguf => "-q8",
51 Self::Q4MlxSafetensors => "-mlx-q4",
52 Self::Q8MlxSafetensors => "-mlx-q8",
53 Self::MlxBf16Safetensors => "-mlx-bf16",
54 };
55 PathBuf::from(".cache").join(format!("{prefix}{suffix}"))
56 }
57
58 pub fn lm_filename(self) -> &'static str {
60 match self {
61 Self::Bf16Safetensors | Self::MlxBf16Safetensors => "model.safetensors",
62 Self::Q8Gguf => "model.q8.gguf",
63 Self::Q4MlxSafetensors => "model.q4.safetensors",
64 Self::Q8MlxSafetensors => "model.q8.safetensors",
65 }
66 }
67
68 pub fn is_gguf(self) -> bool {
70 matches!(self, Self::Q8Gguf)
71 }
72
73 pub fn is_mlx(self) -> bool {
75 matches!(
76 self,
77 Self::Q4MlxSafetensors | Self::Q8MlxSafetensors | Self::MlxBf16Safetensors
78 )
79 }
80
81 pub fn is_mlx_quantized(self) -> bool {
83 matches!(self, Self::Q4MlxSafetensors | Self::Q8MlxSafetensors)
84 }
85
86 pub fn mlx_quant_params(self) -> (u32, usize) {
88 match self {
89 Self::Q4MlxSafetensors => (4, 32),
90 Self::Q8MlxSafetensors => (8, 64),
91 _ => (0, 0),
92 }
93 }
94
95 pub fn gpu_loadable(self) -> bool {
97 self.candle_compatible() || self.is_mlx()
98 }
99
100 pub fn candle_compatible(self) -> bool {
102 matches!(self, Self::Bf16Safetensors | Self::Q8Gguf)
103 }
104
105 pub fn size_class_gb(self) -> f32 {
107 match self {
108 Self::Bf16Safetensors | Self::MlxBf16Safetensors => 14.0,
109 Self::Q8Gguf => 8.0,
110 Self::Q8MlxSafetensors => 7.0,
111 Self::Q4MlxSafetensors => 4.0,
112 }
113 }
114
115 pub fn parse(name: &str) -> Option<Self> {
117 match name.to_ascii_lowercase().as_str() {
118 "bf16" | "f32" | "safetensors" | "default" => Some(Self::Bf16Safetensors),
119 "q8" | "q8-gguf" | "gguf" => Some(Self::Q8Gguf),
120 "q4" | "q4-mlx" | "mlx-q4" => Some(Self::Q4MlxSafetensors),
121 "q8-mlx" | "mlx-q8" => Some(Self::Q8MlxSafetensors),
122 "mlx-bf16" | "bf16-mlx" | "mlx-bf16-safetensors" => Some(Self::MlxBf16Safetensors),
123 _ => None,
124 }
125 }
126
127 pub fn from_env_or_default() -> Self {
129 std::env::var("RLX_MOSHI_CHECKPOINT")
130 .ok()
131 .and_then(|s| Self::parse(&s))
132 .unwrap_or(Self::Bf16Safetensors)
133 }
134
135 pub fn lm_weights_path(self, model_dir: &Path) -> PathBuf {
137 model_dir.join(self.lm_filename())
138 }
139
140 pub fn tokenizer_path(self, model_dir: &Path) -> PathBuf {
142 let _ = self;
143 model_dir.join("tokenizer_spm_32k_3.model")
144 }
145
146 pub const SHARED_FILES: &'static [&'static str] = &[
148 "tokenizer_spm_32k_3.model",
149 "tokenizer-e351c8d8-checkpoint125.safetensors",
150 ];
151}