pub mod dataset;
pub mod huggingface_hub;
pub mod pretrain;
pub mod safetensors;
pub use dataset::DatasetExporter;
pub use huggingface_hub::HuggingFaceHub;
pub use pretrain::{PretrainConfig, PretrainPipeline};
pub use safetensors::SafeTensorsExporter;
use crate::engine::SonaEngine;
use serde::{Deserialize, Serialize};
use std::path::Path;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ExportConfig {
pub model_name: String,
pub organization: Option<String>,
pub target_architecture: String,
pub include_patterns: bool,
pub include_lora: bool,
pub include_preferences: bool,
pub min_quality_threshold: f32,
pub compress: bool,
}
impl Default for ExportConfig {
fn default() -> Self {
Self {
model_name: "sona-adapter".to_string(),
organization: None,
target_architecture: "phi-4".to_string(),
include_patterns: true,
include_lora: true,
include_preferences: true,
min_quality_threshold: 0.5,
compress: false,
}
}
}
pub struct HuggingFaceExporter<'a> {
engine: &'a SonaEngine,
config: ExportConfig,
}
impl<'a> HuggingFaceExporter<'a> {
pub fn new(engine: &'a SonaEngine) -> Self {
Self {
engine,
config: ExportConfig::default(),
}
}
pub fn with_config(engine: &'a SonaEngine, config: ExportConfig) -> Self {
Self { engine, config }
}
pub fn export_lora_safetensors<P: AsRef<Path>>(
&self,
output_dir: P,
) -> Result<ExportResult, ExportError> {
let exporter = SafeTensorsExporter::new(&self.config);
exporter.export_engine(self.engine, output_dir)
}
pub fn export_patterns_jsonl<P: AsRef<Path>>(
&self,
output_path: P,
) -> Result<ExportResult, ExportError> {
let exporter = DatasetExporter::new(&self.config);
exporter.export_patterns(self.engine, output_path)
}
pub fn export_preference_pairs<P: AsRef<Path>>(
&self,
output_path: P,
) -> Result<ExportResult, ExportError> {
let exporter = DatasetExporter::new(&self.config);
exporter.export_preferences(self.engine, output_path)
}
pub fn push_to_hub(
&self,
repo_id: &str,
token: Option<&str>,
) -> Result<ExportResult, ExportError> {
let hub = HuggingFaceHub::new(token);
hub.push_all(self.engine, &self.config, repo_id)
}
pub fn export_all<P: AsRef<Path>>(
&self,
output_dir: P,
) -> Result<Vec<ExportResult>, ExportError> {
let output_dir = output_dir.as_ref();
std::fs::create_dir_all(output_dir).map_err(ExportError::Io)?;
let mut results = Vec::new();
if self.config.include_lora {
results.push(self.export_lora_safetensors(output_dir.join("lora"))?);
}
if self.config.include_patterns {
results.push(self.export_patterns_jsonl(output_dir.join("patterns.jsonl"))?);
}
if self.config.include_preferences {
results.push(self.export_preference_pairs(output_dir.join("preferences.jsonl"))?);
}
let config_path = output_dir.join("adapter_config.json");
let config_json = serde_json::to_string_pretty(&self.create_adapter_config())?;
std::fs::write(&config_path, config_json).map_err(ExportError::Io)?;
let readme_path = output_dir.join("README.md");
let readme = self.generate_readme();
std::fs::write(&readme_path, readme).map_err(ExportError::Io)?;
Ok(results)
}
fn create_adapter_config(&self) -> AdapterConfig {
let sona_config = self.engine.config();
AdapterConfig {
peft_type: "LORA".to_string(),
auto_mapping: None,
base_model_name_or_path: self.config.target_architecture.clone(),
revision: None,
task_type: "CAUSAL_LM".to_string(),
inference_mode: true,
r: sona_config.micro_lora_rank,
lora_alpha: sona_config.micro_lora_rank as f32,
lora_dropout: 0.0,
fan_in_fan_out: false,
bias: "none".to_string(),
target_modules: vec![
"q_proj".to_string(),
"k_proj".to_string(),
"v_proj".to_string(),
"o_proj".to_string(),
],
modules_to_save: None,
layers_to_transform: None,
layers_pattern: None,
}
}
fn generate_readme(&self) -> String {
let stats = self.engine.stats();
format!(
r#"---
license: mit
library_name: peft
base_model: {}
tags:
- sona
- lora
- adaptive-learning
- ruvector
---
# {} SONA Adapter
This adapter was generated using [SONA (Self-Optimizing Neural Architecture)](https://github.com/ruvnet/ruvector/tree/main/crates/sona).
## Model Details
- **Base Model**: {}
- **PEFT Type**: LoRA
- **Rank**: {}
- **Patterns Learned**: {}
- **Trajectories Processed**: {}
## Training Details
SONA uses two-tier LoRA adaptation:
- **MicroLoRA**: Rank 1-2 for instant adaptation (<0.5ms)
- **BaseLoRA**: Rank 4-16 for background learning
### Performance Benchmarks
| Metric | Value |
|--------|-------|
| Throughput | 2211 ops/sec |
| Latency | <0.5ms per layer |
| Quality Improvement | +55% max |
## Usage
```python
from peft import PeftModel, PeftConfig
from transformers import AutoModelForCausalLM
# Load adapter
config = PeftConfig.from_pretrained("your-username/{}")
model = AutoModelForCausalLM.from_pretrained(config.base_model_name_or_path)
model = PeftModel.from_pretrained(model, "your-username/{}")
```
## License
MIT License - see [LICENSE](LICENSE) for details.
---
Generated with [ruvector-sona](https://crates.io/crates/ruvector-sona) v0.1.0
"#,
self.config.target_architecture,
self.config.model_name,
self.config.target_architecture,
self.engine.config().micro_lora_rank,
stats.patterns_stored,
stats.trajectories_buffered,
self.config.model_name,
self.config.model_name,
)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AdapterConfig {
pub peft_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub auto_mapping: Option<serde_json::Value>,
pub base_model_name_or_path: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub revision: Option<String>,
pub task_type: String,
pub inference_mode: bool,
pub r: usize,
pub lora_alpha: f32,
pub lora_dropout: f32,
pub fan_in_fan_out: bool,
pub bias: String,
pub target_modules: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub modules_to_save: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub layers_to_transform: Option<Vec<usize>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub layers_pattern: Option<String>,
}
#[derive(Clone, Debug)]
pub struct ExportResult {
pub export_type: ExportType,
pub items_exported: usize,
pub output_path: String,
pub size_bytes: u64,
}
#[derive(Clone, Debug)]
pub enum ExportType {
SafeTensors,
PatternsDataset,
PreferencePairs,
DistillationTargets,
AdapterConfig,
}
#[derive(Debug)]
pub enum ExportError {
Io(std::io::Error),
Serialization(serde_json::Error),
InvalidData(String),
HubError(String),
}
impl From<std::io::Error> for ExportError {
fn from(e: std::io::Error) -> Self {
ExportError::Io(e)
}
}
impl From<serde_json::Error> for ExportError {
fn from(e: serde_json::Error) -> Self {
ExportError::Serialization(e)
}
}
impl std::fmt::Display for ExportError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ExportError::Io(e) => write!(f, "IO error: {}", e),
ExportError::Serialization(e) => write!(f, "Serialization error: {}", e),
ExportError::InvalidData(msg) => write!(f, "Invalid data: {}", msg),
ExportError::HubError(msg) => write!(f, "HuggingFace Hub error: {}", msg),
}
}
}
impl std::error::Error for ExportError {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_export_config_default() {
let config = ExportConfig::default();
assert_eq!(config.model_name, "sona-adapter");
assert!(config.include_patterns);
assert!(config.include_lora);
}
#[test]
fn test_adapter_config_serialization() {
let config = AdapterConfig {
peft_type: "LORA".to_string(),
auto_mapping: None,
base_model_name_or_path: "microsoft/phi-4".to_string(),
revision: None,
task_type: "CAUSAL_LM".to_string(),
inference_mode: true,
r: 2,
lora_alpha: 2.0,
lora_dropout: 0.0,
fan_in_fan_out: false,
bias: "none".to_string(),
target_modules: vec!["q_proj".to_string()],
modules_to_save: None,
layers_to_transform: None,
layers_pattern: None,
};
let json = serde_json::to_string_pretty(&config).unwrap();
assert!(json.contains("LORA"));
assert!(json.contains("phi-4"));
}
}