pub mod artifact;
pub mod error;
pub mod manifest;
pub mod storage;
pub use artifact::*;
pub use error::*;
pub use manifest::*;
pub use storage::*;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
pub const AI_MAGIC: &[u8; 4] = b"HAIF";
pub const FORMAT_VERSION: u32 = 1;
pub const AI_EXTENSION: &str = "ai";
pub type ArtifactId = String;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct ArtifactRef {
pub hash: String,
pub name: String,
pub version: String,
pub locations: Vec<StorageLocation>,
}
impl ArtifactRef {
pub fn new(hash: String, name: String, version: String) -> Self {
Self {
hash,
name,
version,
locations: Vec::new(),
}
}
pub fn id(&self) -> ArtifactId {
format!("{}@{}", self.name, self.hash[..8].to_string())
}
pub fn with_location(mut self, location: StorageLocation) -> Self {
self.locations.push(location);
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum StorageLocation {
Local(String),
HuggingFace { repo_id: String, revision: Option<String> },
Swarm { info_hash: String, peers: Vec<String> },
Ipfs(String),
Http(String),
NodeStorage { peer_id: String, path: String },
}
impl StorageLocation {
pub fn local(path: impl Into<String>) -> Self {
Self::Local(path.into())
}
pub fn huggingface(repo_id: impl Into<String>) -> Self {
Self::HuggingFace {
repo_id: repo_id.into(),
revision: None,
}
}
pub fn swarm(info_hash: impl Into<String>) -> Self {
Self::Swarm {
info_hash: info_hash.into(),
peers: Vec::new(),
}
}
pub fn ipfs(cid: impl Into<String>) -> Self {
Self::Ipfs(cid.into())
}
pub fn http(url: impl Into<String>) -> Self {
Self::Http(url.into())
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum ArtifactType {
Model,
Weights,
QuantizedModel {
format: QuantFormat,
bits: u8,
},
Delta {
base_model: String,
method: DeltaMethod,
},
Dataset {
task: DatasetTask,
split: Option<String>,
},
Embeddings {
model: String,
dimensions: usize,
},
VectorStore {
index_type: String,
dimensions: usize,
},
AgentState {
agent_type: String,
},
Tokenizer,
Config,
Checkpoint {
epoch: usize,
step: usize,
},
Custom(String),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum QuantFormat {
GGUF,
AWQ,
GPTQ,
ExL2,
BnB,
MLX,
Custom(String),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum DeltaMethod {
LoRA { rank: usize, alpha: f32 },
QLoRA { rank: usize, alpha: f32, bits: u8 },
FullDiff,
Adapter,
Prefix { num_tokens: usize },
Custom(String),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum DatasetTask {
TextGeneration,
Conversation,
Classification,
QuestionAnswering,
Summarization,
Translation,
CodeGeneration,
Embedding,
Custom(String),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum License {
MIT,
Apache2,
GPL3,
Llama2,
Llama3,
Qwen,
Gemma,
CcBy4,
CcByNc4,
CcBySa4,
Custom(String),
Proprietary,
}
impl Default for License {
fn default() -> Self {
Self::Apache2
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum Network {
HanzoMainnet,
HanzoTestnet,
ZooMainnet,
ZooTestnet,
All,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ComputeRequirements {
pub min_vram_mb: Option<u32>,
pub min_ram_mb: Option<u32>,
pub gpu_required: bool,
pub backends: Vec<String>,
pub recommended_batch_size: Option<usize>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ArtifactMetadata {
pub id: ArtifactId,
pub name: String,
pub version: String,
pub description: Option<String>,
pub artifact_type: ArtifactType,
pub author: Option<String>,
pub license: License,
pub tags: Vec<String>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub size_bytes: u64,
pub content_hash: String,
pub requirements: ComputeRequirements,
pub networks: Vec<Network>,
pub locations: Vec<StorageLocation>,
pub dependencies: Vec<ArtifactRef>,
pub custom: HashMap<String, serde_json::Value>,
}
impl ArtifactMetadata {
pub fn new(name: impl Into<String>, artifact_type: ArtifactType) -> Self {
let name = name.into();
let now = Utc::now();
Self {
id: uuid::Uuid::new_v4().to_string(),
name,
version: "1.0.0".to_string(),
description: None,
artifact_type,
author: None,
license: License::default(),
tags: Vec::new(),
created_at: now,
updated_at: now,
size_bytes: 0,
content_hash: String::new(),
requirements: ComputeRequirements::default(),
networks: vec![Network::All],
locations: Vec::new(),
dependencies: Vec::new(),
custom: HashMap::new(),
}
}
pub fn with_version(mut self, version: impl Into<String>) -> Self {
self.version = version.into();
self
}
pub fn with_description(mut self, desc: impl Into<String>) -> Self {
self.description = Some(desc.into());
self
}
pub fn with_author(mut self, author: impl Into<String>) -> Self {
self.author = Some(author.into());
self
}
pub fn with_license(mut self, license: License) -> Self {
self.license = license;
self
}
pub fn with_tag(mut self, tag: impl Into<String>) -> Self {
self.tags.push(tag.into());
self
}
pub fn with_network(mut self, network: Network) -> Self {
self.networks.push(network);
self
}
pub fn with_dependency(mut self, dep: ArtifactRef) -> Self {
self.dependencies.push(dep);
self
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ArtifactStats {
pub downloads: u64,
pub unique_users: u64,
pub compute_hours: f64,
pub peer_count: usize,
pub average_rating: Option<f32>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_artifact_ref() {
let artifact_ref = ArtifactRef::new(
"abc123def456".to_string(),
"my-model".to_string(),
"1.0.0".to_string(),
);
assert_eq!(artifact_ref.id(), "my-model@abc123de");
}
#[test]
fn test_storage_locations() {
let local = StorageLocation::local("/path/to/model");
assert!(matches!(local, StorageLocation::Local(_)));
let hf = StorageLocation::huggingface("hanzo-lm/Llama-3-8B");
assert!(matches!(hf, StorageLocation::HuggingFace { .. }));
let ipfs = StorageLocation::ipfs("QmXyz123");
assert!(matches!(ipfs, StorageLocation::Ipfs(_)));
}
#[test]
fn test_artifact_metadata() {
let metadata = ArtifactMetadata::new("test-model", ArtifactType::Model)
.with_version("2.0.0")
.with_author("hanzo")
.with_license(License::Apache2)
.with_tag("llm")
.with_tag("inference");
assert_eq!(metadata.name, "test-model");
assert_eq!(metadata.version, "2.0.0");
assert_eq!(metadata.author, Some("hanzo".to_string()));
assert_eq!(metadata.tags.len(), 2);
}
#[test]
fn test_artifact_types() {
let model = ArtifactType::Model;
let quant = ArtifactType::QuantizedModel {
format: QuantFormat::GGUF,
bits: 4,
};
let delta = ArtifactType::Delta {
base_model: "llama-3-8b".to_string(),
method: DeltaMethod::LoRA { rank: 64, alpha: 32.0 },
};
assert!(matches!(model, ArtifactType::Model));
assert!(matches!(quant, ArtifactType::QuantizedModel { .. }));
assert!(matches!(delta, ArtifactType::Delta { .. }));
}
}