use std::path::PathBuf;
use infernum_core::{DeviceType, ModelSource, QuantizationType};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EngineConfig {
pub model: ModelSource,
pub device: DeviceType,
pub memory: MemoryConfig,
pub quantization: Option<QuantizationType>,
pub max_batch_size: u32,
pub max_seq_len: u32,
pub speculative: Option<SpeculativeConfig>,
pub cache_dir: Option<PathBuf>,
}
impl Default for EngineConfig {
fn default() -> Self {
Self {
model: ModelSource::HuggingFace {
repo_id: String::new(),
revision: None,
},
device: DeviceType::Cpu,
memory: MemoryConfig::default(),
quantization: None,
max_batch_size: 32,
max_seq_len: 4096,
speculative: None,
cache_dir: None,
}
}
}
impl EngineConfig {
#[must_use]
pub fn builder() -> EngineConfigBuilder {
EngineConfigBuilder::default()
}
}
#[derive(Debug, Default)]
pub struct EngineConfigBuilder {
model: Option<ModelSource>,
device: Option<DeviceType>,
memory: Option<MemoryConfig>,
quantization: Option<QuantizationType>,
max_batch_size: Option<u32>,
max_seq_len: Option<u32>,
speculative: Option<SpeculativeConfig>,
cache_dir: Option<PathBuf>,
}
impl EngineConfigBuilder {
#[must_use]
pub fn model(mut self, repo_id: impl Into<String>) -> Self {
self.model = Some(ModelSource::huggingface(repo_id));
self
}
#[must_use]
pub fn model_source(mut self, source: ModelSource) -> Self {
self.model = Some(source);
self
}
#[must_use]
pub fn device(mut self, device: DeviceType) -> Self {
self.device = Some(device);
self
}
#[must_use]
pub fn cuda(mut self, device_id: usize) -> Self {
self.device = Some(DeviceType::Cuda { device_id });
self
}
#[must_use]
pub fn metal(mut self) -> Self {
self.device = Some(DeviceType::Metal { device_id: 0 });
self
}
#[must_use]
pub fn memory(mut self, config: MemoryConfig) -> Self {
self.memory = Some(config);
self
}
#[must_use]
pub fn quantization(mut self, quant: QuantizationType) -> Self {
self.quantization = Some(quant);
self
}
#[must_use]
pub fn max_batch_size(mut self, size: u32) -> Self {
self.max_batch_size = Some(size);
self
}
#[must_use]
pub fn max_seq_len(mut self, len: u32) -> Self {
self.max_seq_len = Some(len);
self
}
#[must_use]
pub fn speculative(mut self, config: SpeculativeConfig) -> Self {
self.speculative = Some(config);
self
}
#[must_use]
pub fn cache_dir(mut self, path: impl Into<PathBuf>) -> Self {
self.cache_dir = Some(path.into());
self
}
pub fn build(self) -> Result<EngineConfig, String> {
let model = self.model.ok_or("model is required")?;
Ok(EngineConfig {
model,
device: self.device.unwrap_or(DeviceType::Cpu),
memory: self.memory.unwrap_or_default(),
quantization: self.quantization,
max_batch_size: self.max_batch_size.unwrap_or(32),
max_seq_len: self.max_seq_len.unwrap_or(4096),
speculative: self.speculative,
cache_dir: self.cache_dir,
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemoryConfig {
pub gpu_memory_limit: usize,
pub kv_cache_fraction: f32,
pub mmap_enabled: bool,
pub cpu_offload: bool,
pub gpu_layers: Option<u32>,
}
impl Default for MemoryConfig {
fn default() -> Self {
Self {
gpu_memory_limit: 0,
kv_cache_fraction: 0.9,
mmap_enabled: true,
cpu_offload: false,
gpu_layers: None,
}
}
}
impl MemoryConfig {
#[must_use]
pub fn low_memory() -> Self {
Self {
gpu_memory_limit: 0,
kv_cache_fraction: 0.5,
mmap_enabled: true,
cpu_offload: true,
gpu_layers: Some(20),
}
}
#[must_use]
pub fn high_throughput() -> Self {
Self {
gpu_memory_limit: 0,
kv_cache_fraction: 0.95,
mmap_enabled: true,
cpu_offload: false,
gpu_layers: None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SpeculativeConfig {
pub draft_model: ModelSource,
pub num_speculative_tokens: u32,
pub acceptance_threshold: f32,
}
impl SpeculativeConfig {
#[must_use]
pub fn new(draft_model: ModelSource) -> Self {
Self {
draft_model,
num_speculative_tokens: 5,
acceptance_threshold: 0.9,
}
}
}