rlx_models_core/
weights.rs1use std::path::{Path, PathBuf};
30
31use anyhow::Result;
32
33pub use crate::gguf_resolve::{
34 GgufTensorNameResolver, LlamaFamilyGgufResolver, PassThroughGgufResolver,
35 PrefixStripGgufResolver, Qwen35NativeGgufResolver, register_gguf_tensor_resolver,
36};
37pub use crate::gguf_support::{
38 ResolveWeightsOptions, gguf_split_siblings, gguf_validate_arch, list_gguf_files_in_dir,
39 load_gguf_file, resolve_weights_file, resolve_weights_file_with_options,
40};
41pub use crate::weight_loader::{GgufLoader, WeightLoader};
42pub use crate::weight_map::{WeightDrainPolicy, WeightMap};
43pub use crate::weight_registry::{
44 LoadWeightsOptions, LoadedWeights, RegisteredFormat, WeightFormatRegistration,
45 format_for_extension, list_registered_formats, load_weight_map_resolved, load_weights_resolved,
46 open_weight_loader, register_weight_format,
47};
48
49pub type LoadOpts<'a> = LoadWeightsOptions<'a>;
51
52pub type ResolveOpts<'a> = ResolveWeightsOptions<'a>;
54
55pub fn default_resolve_opts<'a>() -> ResolveWeightsOptions<'a> {
57 ResolveWeightsOptions::default()
58 .prefer_substring(crate::gguf_support::DEFAULT_GGUF_PREFER_SUBSTR)
59}
60
61pub fn pick(path: impl AsRef<Path>, resolve: &ResolveWeightsOptions<'_>) -> Result<PathBuf> {
63 resolve_weights_file_with_options(path.as_ref(), resolve)
64}
65
66pub fn pick_default(path: impl AsRef<Path>) -> Result<PathBuf> {
68 pick(path, &default_resolve_opts())
69}
70
71pub fn load_weight_map(path: impl AsRef<Path>, gguf_arches: &[&str]) -> Result<WeightMap> {
75 let path = path.as_ref();
76 let file = pick_default(path)?;
77 if file.extension().and_then(|s| s.to_str()) == Some("gguf") {
78 gguf_validate_arch(&file, gguf_arches)?;
79 }
80 WeightMap::from_resolved_path(path)
81}
82
83pub fn init() {
85 crate::gguf_resolve::ensure_builtin_resolvers();
86}
87
88impl WeightFormatRegistration {
89 pub const fn new(
91 id: &'static str,
92 extensions: &'static [&'static str],
93 open: crate::weight_registry::WeightLoaderFactory,
94 ) -> Self {
95 Self {
96 id,
97 extensions,
98 open,
99 }
100 }
101
102 pub fn register(self) {
104 register_weight_format(self);
105 }
106}
107
108pub fn open(path: impl AsRef<Path>) -> Result<LoadedWeights> {
110 open_with(LoadOpts::loader(), path)
111}
112
113pub fn open_with(opts: LoadOpts<'_>, path: impl AsRef<Path>) -> Result<LoadedWeights> {
115 load_weights_resolved(path.as_ref(), opts)
116}
117
118pub fn open_map(path: impl AsRef<Path>) -> Result<(PathBuf, WeightMap)> {
120 open_map_with(LoadOpts::map(), path)
121}
122
123pub fn open_map_with(opts: LoadOpts<'_>, path: impl AsRef<Path>) -> Result<(PathBuf, WeightMap)> {
125 load_weight_map_resolved(path.as_ref(), opts)
126}
127
128pub fn gguf_dir_guide(dir: &Path) -> Result<GgufDirGuide> {
130 let files = list_gguf_files_in_dir(dir)?;
131 let mut lines = Vec::new();
132 if files.is_empty() {
133 lines.push(format!("No .gguf files in {dir:?}"));
134 return Ok(GgufDirGuide { files, lines });
135 }
136 lines.push(format!("{} .gguf file(s) in {dir:?}:", files.len()));
137 for (i, p) in files.iter().enumerate() {
138 let name = p.file_name().and_then(|s| s.to_str()).unwrap_or("?");
139 lines.push(format!(" [{i}] {name}"));
140 }
141 if files.len() > 1 {
142 lines.push(String::new());
143 lines.push("Pick one:".into());
144 lines.push(format!(" pass exact path: {:?}", files[0]));
145 lines.push(" Rust: LoadOpts::map().prefer_q4_k_m()".into());
146 lines.push(" Rust: LoadOpts::map().gguf_index(0)".into());
147 lines.push(" CLI: rlx-inspect dir/ --prefer Q4_K_M".into());
148 }
149 Ok(GgufDirGuide { files, lines })
150}
151
152#[derive(Debug, Clone)]
153pub struct GgufDirGuide {
154 pub files: Vec<PathBuf>,
155 pub lines: Vec<String>,
156}
157
158impl GgufDirGuide {
159 pub fn print(&self) {
160 for line in &self.lines {
161 println!("{line}");
162 }
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169 #[test]
170 fn load_opts_format_only() {
171 assert!(LoadOpts::map().into_map);
172 assert!(!LoadOpts::loader().into_map);
173 }
174}