1use serde::{Deserialize, Serialize};
2use std::path::Path;
3
4#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5#[serde(rename_all = "lowercase")]
6pub enum EmbedBackend {
7 #[default]
8 Fastembed,
9 OpenAI,
10 Ollama,
11}
12
13#[derive(Debug, Clone, Serialize, Deserialize, Default)]
14#[serde(rename_all = "lowercase")]
15pub enum StoreBackend {
16 #[default]
17 Usearch,
18 Qdrant,
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize, Default)]
22pub struct EmbedConfig {
23 #[serde(default)]
24 pub backend: EmbedBackend,
25 pub model: Option<String>,
27 pub url: Option<String>,
29 pub api_key: Option<String>,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize, Default)]
34pub struct StoreConfig {
35 #[serde(default)]
36 pub backend: StoreBackend,
37 pub url: Option<String>,
39 pub collection: Option<String>,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct SemtreeConfig {
45 #[serde(default)]
46 pub embed: EmbedConfig,
47 #[serde(default)]
48 pub store: StoreConfig,
49 #[serde(default = "default_index_dir")]
51 pub index_dir: String,
52}
53
54impl Default for SemtreeConfig {
58 fn default() -> Self {
59 Self {
60 embed: EmbedConfig::default(),
61 store: StoreConfig::default(),
62 index_dir: default_index_dir(),
63 }
64 }
65}
66
67fn default_index_dir() -> String {
68 ".semtree".to_string()
69}
70
71impl SemtreeConfig {
72 pub fn load(dir: &Path) -> Self {
74 let path = dir.join(".semtree.toml");
75 if let Ok(raw) = std::fs::read_to_string(&path) {
76 toml::from_str(&raw).unwrap_or_else(|e| {
77 eprintln!("Warning: invalid .semtree.toml: {e}");
78 Self::default()
79 })
80 } else {
81 Self::default()
82 }
83 }
84
85 pub fn save(&self, dir: &Path) -> std::io::Result<()> {
86 let path = dir.join(".semtree.toml");
87 let raw = toml::to_string_pretty(self).expect("serializable");
88 std::fs::write(path, raw)
89 }
90}