use serde::{Deserialize, Serialize};
use crate::embed::EmbedderConfig;
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct RetrieveConfig {
#[serde(default)]
pub db: VectorDb,
#[serde(default)]
pub embedding: Option<EmbeddingConfig>,
#[serde(default)]
pub hybrid: HybridConfig,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub sync_interval_minutes: Option<u32>,
}
impl RetrieveConfig {
pub fn sync_interval(&self) -> Option<std::time::Duration> {
self.sync_interval_minutes
.filter(|&m| m > 0)
.map(|m| std::time::Duration::from_secs(m as u64 * 60))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HybridConfig {
#[serde(default = "default_fts_weight")]
pub fts_weight: f64,
#[serde(default = "default_rrf_k")]
pub rrf_k: u32,
}
fn default_fts_weight() -> f64 {
0.5
}
fn default_rrf_k() -> u32 {
60
}
impl Default for HybridConfig {
fn default() -> Self {
Self {
fts_weight: default_fts_weight(),
rrf_k: default_rrf_k(),
}
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum VectorDb {
#[default]
None,
SqliteVec,
#[serde(rename = "lancedb")]
LanceDb,
}
impl VectorDb {
pub fn as_str(self) -> &'static str {
match self {
VectorDb::None => "none",
VectorDb::SqliteVec => "sqlite_vec",
VectorDb::LanceDb => "lancedb",
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct EmbeddingConfig {
#[serde(default)]
pub enabled: bool,
#[serde(default)]
pub provider: String,
#[serde(default)]
pub model: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub api_key_env: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub base_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dimension: Option<u32>,
}
impl EmbeddingConfig {
pub fn to_embedder_config(&self) -> EmbedderConfig {
EmbedderConfig {
provider: self.provider.clone(),
model: self.model.clone(),
api_key_env: self.api_key_env.clone(),
base_url: self.base_url.clone(),
cache_dir: None,
}
}
}