in candle-pyo3/src/lib.rs [1387:1467]
fn save_gguf(path: &str, tensors: PyObject, metadata: PyObject, py: Python<'_>) -> PyResult<()> {
use ::candle::quantized::gguf_file;
fn pyobject_to_gguf_value(v: &Bound<PyAny>, py: Python<'_>) -> PyResult<gguf_file::Value> {
let v: gguf_file::Value = if let Ok(x) = v.extract::<u8>() {
gguf_file::Value::U8(x)
} else if let Ok(x) = v.extract::<i8>() {
gguf_file::Value::I8(x)
} else if let Ok(x) = v.extract::<u16>() {
gguf_file::Value::U16(x)
} else if let Ok(x) = v.extract::<i16>() {
gguf_file::Value::I16(x)
} else if let Ok(x) = v.extract::<u32>() {
gguf_file::Value::U32(x)
} else if let Ok(x) = v.extract::<i32>() {
gguf_file::Value::I32(x)
} else if let Ok(x) = v.extract::<u64>() {
gguf_file::Value::U64(x)
} else if let Ok(x) = v.extract::<i64>() {
gguf_file::Value::I64(x)
} else if let Ok(x) = v.extract::<f32>() {
gguf_file::Value::F32(x)
} else if let Ok(x) = v.extract::<f64>() {
gguf_file::Value::F64(x)
} else if let Ok(x) = v.extract::<bool>() {
gguf_file::Value::Bool(x)
} else if let Ok(x) = v.extract::<String>() {
gguf_file::Value::String(x)
} else if let Ok(x) = v.extract::<Vec<PyObject>>() {
let x = x
.into_iter()
.map(|f| pyobject_to_gguf_value(f.bind(py), py))
.collect::<PyResult<Vec<_>>>()?;
gguf_file::Value::Array(x)
} else {
return Err(PyErr::new::<PyValueError, _>(format!(
"unsupported type {v:?}"
)));
};
Ok(v)
}
let tensors = tensors
.downcast_bound::<PyDict>(py)
.map_err(|_| PyErr::new::<PyValueError, _>("expected a dict"))?
.iter()
.map(|(key, value)| {
Ok((
key.extract::<String>()
.map_err(|_| PyErr::new::<PyValueError, _>("keys must be strings"))?,
value.extract::<PyQTensor>()?.0,
))
})
.collect::<PyResult<Vec<_>>>()?;
let metadata = metadata
.downcast_bound::<PyDict>(py)
.map_err(|_| PyErr::new::<PyValueError, _>("expected a dict"))?
.iter()
.map(|(key, value)| {
Ok((
key.extract::<String>()
.map_err(|_| PyErr::new::<PyValueError, _>("keys must be strings"))?,
pyobject_to_gguf_value(&value.as_borrowed(), py)?,
))
})
.collect::<PyResult<Vec<_>>>()?;
let converted_metadata: Vec<_> = metadata
.iter()
.map(|(name, value)| (name.as_str(), value))
.collect();
let converted_tensors: Vec<_> = tensors
.iter()
.map(|(name, tensor)| (name.as_str(), tensor.as_ref()))
.collect();
let mut file = std::fs::File::create(path)?;
gguf_file::write(&mut file, &converted_metadata, &converted_tensors).map_err(wrap_err)
}