1pub mod artifact;
59pub mod error;
60pub mod manifest;
61pub mod storage;
62
63pub use artifact::*;
64pub use error::*;
65pub use manifest::*;
66pub use storage::*;
67
68use chrono::{DateTime, Utc};
69use serde::{Deserialize, Serialize};
70use std::collections::HashMap;
71
72pub const AI_MAGIC: &[u8; 4] = b"HAIF"; pub const FORMAT_VERSION: u32 = 1;
77
78pub const AI_EXTENSION: &str = "ai";
80
81pub type ArtifactId = String;
83
84#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
86pub struct ArtifactRef {
87 pub hash: String,
89 pub name: String,
91 pub version: String,
93 pub locations: Vec<StorageLocation>,
95}
96
97impl ArtifactRef {
98 pub fn new(hash: String, name: String, version: String) -> Self {
99 Self {
100 hash,
101 name,
102 version,
103 locations: Vec::new(),
104 }
105 }
106
107 pub fn id(&self) -> ArtifactId {
108 format!("{}@{}", self.name, self.hash[..8].to_string())
109 }
110
111 pub fn with_location(mut self, location: StorageLocation) -> Self {
112 self.locations.push(location);
113 self
114 }
115}
116
117#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
119pub enum StorageLocation {
120 Local(String),
122 HuggingFace { repo_id: String, revision: Option<String> },
124 Swarm { info_hash: String, peers: Vec<String> },
126 Ipfs(String),
128 Http(String),
130 NodeStorage { peer_id: String, path: String },
132}
133
134impl StorageLocation {
135 pub fn local(path: impl Into<String>) -> Self {
136 Self::Local(path.into())
137 }
138
139 pub fn huggingface(repo_id: impl Into<String>) -> Self {
140 Self::HuggingFace {
141 repo_id: repo_id.into(),
142 revision: None,
143 }
144 }
145
146 pub fn swarm(info_hash: impl Into<String>) -> Self {
147 Self::Swarm {
148 info_hash: info_hash.into(),
149 peers: Vec::new(),
150 }
151 }
152
153 pub fn ipfs(cid: impl Into<String>) -> Self {
154 Self::Ipfs(cid.into())
155 }
156
157 pub fn http(url: impl Into<String>) -> Self {
158 Self::Http(url.into())
159 }
160}
161
162#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
164pub enum ArtifactType {
165 Model,
167 Weights,
169 QuantizedModel {
171 format: QuantFormat,
172 bits: u8,
173 },
174 Delta {
176 base_model: String,
177 method: DeltaMethod,
178 },
179 Dataset {
181 task: DatasetTask,
182 split: Option<String>,
183 },
184 Embeddings {
186 model: String,
187 dimensions: usize,
188 },
189 VectorStore {
191 index_type: String,
192 dimensions: usize,
193 },
194 AgentState {
196 agent_type: String,
197 },
198 Tokenizer,
200 Config,
202 Checkpoint {
204 epoch: usize,
205 step: usize,
206 },
207 Custom(String),
209}
210
211#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
213pub enum QuantFormat {
214 GGUF,
216 AWQ,
218 GPTQ,
220 ExL2,
222 BnB,
224 MLX,
226 Custom(String),
228}
229
230#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
232pub enum DeltaMethod {
233 LoRA { rank: usize, alpha: f32 },
235 QLoRA { rank: usize, alpha: f32, bits: u8 },
237 FullDiff,
239 Adapter,
241 Prefix { num_tokens: usize },
243 Custom(String),
245}
246
247#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
249pub enum DatasetTask {
250 TextGeneration,
251 Conversation,
252 Classification,
253 QuestionAnswering,
254 Summarization,
255 Translation,
256 CodeGeneration,
257 Embedding,
258 Custom(String),
259}
260
261#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
263pub enum License {
264 MIT,
265 Apache2,
266 GPL3,
267 Llama2,
268 Llama3,
269 Qwen,
270 Gemma,
271 CcBy4,
272 CcByNc4,
273 CcBySa4,
274 Custom(String),
275 Proprietary,
276}
277
278impl Default for License {
279 fn default() -> Self {
280 Self::Apache2
281 }
282}
283
284#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
286pub enum Network {
287 HanzoMainnet,
288 HanzoTestnet,
289 ZooMainnet,
290 ZooTestnet,
291 All,
292}
293
294#[derive(Debug, Clone, Serialize, Deserialize, Default)]
296pub struct ComputeRequirements {
297 pub min_vram_mb: Option<u32>,
299 pub min_ram_mb: Option<u32>,
301 pub gpu_required: bool,
303 pub backends: Vec<String>,
305 pub recommended_batch_size: Option<usize>,
307}
308
309#[derive(Debug, Clone, Serialize, Deserialize)]
311pub struct ArtifactMetadata {
312 pub id: ArtifactId,
314 pub name: String,
316 pub version: String,
318 pub description: Option<String>,
320 pub artifact_type: ArtifactType,
322 pub author: Option<String>,
324 pub license: License,
326 pub tags: Vec<String>,
328 pub created_at: DateTime<Utc>,
330 pub updated_at: DateTime<Utc>,
332 pub size_bytes: u64,
334 pub content_hash: String,
336 pub requirements: ComputeRequirements,
338 pub networks: Vec<Network>,
340 pub locations: Vec<StorageLocation>,
342 pub dependencies: Vec<ArtifactRef>,
344 pub custom: HashMap<String, serde_json::Value>,
346}
347
348impl ArtifactMetadata {
349 pub fn new(name: impl Into<String>, artifact_type: ArtifactType) -> Self {
350 let name = name.into();
351 let now = Utc::now();
352 Self {
353 id: uuid::Uuid::new_v4().to_string(),
354 name,
355 version: "1.0.0".to_string(),
356 description: None,
357 artifact_type,
358 author: None,
359 license: License::default(),
360 tags: Vec::new(),
361 created_at: now,
362 updated_at: now,
363 size_bytes: 0,
364 content_hash: String::new(),
365 requirements: ComputeRequirements::default(),
366 networks: vec![Network::All],
367 locations: Vec::new(),
368 dependencies: Vec::new(),
369 custom: HashMap::new(),
370 }
371 }
372
373 pub fn with_version(mut self, version: impl Into<String>) -> Self {
374 self.version = version.into();
375 self
376 }
377
378 pub fn with_description(mut self, desc: impl Into<String>) -> Self {
379 self.description = Some(desc.into());
380 self
381 }
382
383 pub fn with_author(mut self, author: impl Into<String>) -> Self {
384 self.author = Some(author.into());
385 self
386 }
387
388 pub fn with_license(mut self, license: License) -> Self {
389 self.license = license;
390 self
391 }
392
393 pub fn with_tag(mut self, tag: impl Into<String>) -> Self {
394 self.tags.push(tag.into());
395 self
396 }
397
398 pub fn with_network(mut self, network: Network) -> Self {
399 self.networks.push(network);
400 self
401 }
402
403 pub fn with_dependency(mut self, dep: ArtifactRef) -> Self {
404 self.dependencies.push(dep);
405 self
406 }
407}
408
409#[derive(Debug, Clone, Default, Serialize, Deserialize)]
411pub struct ArtifactStats {
412 pub downloads: u64,
413 pub unique_users: u64,
414 pub compute_hours: f64,
415 pub peer_count: usize,
416 pub average_rating: Option<f32>,
417}
418
419#[cfg(test)]
420mod tests {
421 use super::*;
422
423 #[test]
424 fn test_artifact_ref() {
425 let artifact_ref = ArtifactRef::new(
426 "abc123def456".to_string(),
427 "my-model".to_string(),
428 "1.0.0".to_string(),
429 );
430 assert_eq!(artifact_ref.id(), "my-model@abc123de");
431 }
432
433 #[test]
434 fn test_storage_locations() {
435 let local = StorageLocation::local("/path/to/model");
436 assert!(matches!(local, StorageLocation::Local(_)));
437
438 let hf = StorageLocation::huggingface("hanzo-lm/Llama-3-8B");
439 assert!(matches!(hf, StorageLocation::HuggingFace { .. }));
440
441 let ipfs = StorageLocation::ipfs("QmXyz123");
442 assert!(matches!(ipfs, StorageLocation::Ipfs(_)));
443 }
444
445 #[test]
446 fn test_artifact_metadata() {
447 let metadata = ArtifactMetadata::new("test-model", ArtifactType::Model)
448 .with_version("2.0.0")
449 .with_author("hanzo")
450 .with_license(License::Apache2)
451 .with_tag("llm")
452 .with_tag("inference");
453
454 assert_eq!(metadata.name, "test-model");
455 assert_eq!(metadata.version, "2.0.0");
456 assert_eq!(metadata.author, Some("hanzo".to_string()));
457 assert_eq!(metadata.tags.len(), 2);
458 }
459
460 #[test]
461 fn test_artifact_types() {
462 let model = ArtifactType::Model;
463 let quant = ArtifactType::QuantizedModel {
464 format: QuantFormat::GGUF,
465 bits: 4,
466 };
467 let delta = ArtifactType::Delta {
468 base_model: "llama-3-8b".to_string(),
469 method: DeltaMethod::LoRA { rank: 64, alpha: 32.0 },
470 };
471
472 assert!(matches!(model, ArtifactType::Model));
473 assert!(matches!(quant, ArtifactType::QuantizedModel { .. }));
474 assert!(matches!(delta, ArtifactType::Delta { .. }));
475 }
476}