use serde::{Deserialize, Serialize};
use std::fmt;
use crate::provenance::Provenance;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ModelFormat {
Onnx,
Safetensors,
Npy,
Npz,
Pt,
}
impl ModelFormat {
pub fn extension(self) -> &'static str {
match self {
Self::Onnx => "onnx",
Self::Safetensors => "safetensors",
Self::Npy => "npy",
Self::Npz => "npz",
Self::Pt => "pt",
}
}
pub fn parse(s: &str) -> Option<Self> {
match s.trim().to_ascii_lowercase().as_str() {
"onnx" => Some(Self::Onnx),
"safetensors" => Some(Self::Safetensors),
"npy" => Some(Self::Npy),
"npz" => Some(Self::Npz),
"pt" | "pth" => Some(Self::Pt),
_ => None,
}
}
}
impl fmt::Display for ModelFormat {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.extension())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct TensorPortSpec {
pub name: String,
pub dtype: String,
pub shape: Vec<i64>,
#[serde(default)]
pub description: Option<String>,
}
impl TensorPortSpec {
pub fn format_shape(&self) -> String {
let dims: Vec<String> = self.shape.iter().map(ToString::to_string).collect();
format!("[{}]", dims.join(", "))
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TensorIoSpec {
pub inputs: Vec<TensorPortSpec>,
pub outputs: Vec<TensorPortSpec>,
pub sample_rate_hz: f64,
pub normalization: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ArraySpec {
pub name: String,
pub dtype: String,
pub shape: Vec<usize>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ModelManifest {
pub id: String,
pub name: String,
pub family: String,
pub task: String,
pub format: ModelFormat,
#[serde(default)]
pub description: String,
#[serde(default)]
pub arrays: Vec<ArraySpec>,
#[serde(default)]
pub io_spec: Option<TensorIoSpec>,
#[serde(default)]
pub sample_rate_hz: Option<f64>,
pub provenance: Provenance,
}