1use anyhow::{Result, anyhow};
17use rlx_core::gguf_support::list_gguf_files_in_dir;
18use std::path::Path;
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum WeightFormat {
23 Safetensors,
24 Gguf,
25}
26
27impl WeightFormat {
28 pub fn detect(path: &Path) -> Result<Self> {
30 if path.is_dir() {
31 if !list_gguf_files_in_dir(path)?.is_empty() {
32 return Ok(Self::Gguf);
33 }
34 if path.join("model.safetensors").is_file() {
35 return Ok(Self::Safetensors);
36 }
37 return Err(anyhow!(
38 "directory {path:?} has no .gguf files and no model.safetensors; \
39 pass a concrete file or run `rlx-inspect {path:?}`"
40 ));
41 }
42 Self::from_path(path)
43 }
44
45 pub fn from_path(path: &Path) -> Result<Self> {
46 match path.extension().and_then(|s| s.to_str()) {
47 Some("safetensors") => Ok(Self::Safetensors),
48 Some("gguf") => Ok(Self::Gguf),
49 other => {
50 let hint = rlx_core::registered_extensions_hint();
51 Err(anyhow!(
52 "cannot autodetect weight format from extension {:?} on {path:?}\n\
53 Registered extensions: .{hint}\n\
54 Pass --format safetensors|gguf, or register a custom extension via rlx_core::weights",
55 other
56 ))
57 }
58 }
59 }
60
61 pub fn parse(s: &str) -> Result<Self> {
63 match s {
64 "safetensors" => Ok(Self::Safetensors),
65 "gguf" => Ok(Self::Gguf),
66 other => Err(anyhow!("expected safetensors|gguf, got {other}")),
67 }
68 }
69
70 pub fn resolve(path: &Path, override_fmt: Option<Self>) -> Result<Self> {
72 match override_fmt {
73 Some(f) => Ok(f),
74 None => Self::detect(path),
75 }
76 }
77}