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}
30
31#[derive(Debug, Clone, Serialize, Deserialize, Default)]
32pub struct StoreConfig {
33 #[serde(default)]
34 pub backend: StoreBackend,
35 pub url: Option<String>,
37 pub collection: Option<String>,
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize, Default)]
42pub struct SemtreeConfig {
43 #[serde(default)]
44 pub embed: EmbedConfig,
45 #[serde(default)]
46 pub store: StoreConfig,
47 #[serde(default = "default_index_dir")]
49 pub index_dir: String,
50}
51
52fn default_index_dir() -> String {
53 ".semtree".to_string()
54}
55
56impl SemtreeConfig {
57 pub fn load(dir: &Path) -> Self {
59 let path = dir.join(".semtree.toml");
60 if let Ok(raw) = std::fs::read_to_string(&path) {
61 toml::from_str(&raw).unwrap_or_else(|e| {
62 eprintln!("Warning: invalid .semtree.toml: {e}");
63 Self::default()
64 })
65 } else {
66 Self::default()
67 }
68 }
69
70 pub fn save(&self, dir: &Path) -> std::io::Result<()> {
71 let path = dir.join(".semtree.toml");
72 let raw = toml::to_string_pretty(self).expect("serializable");
73 std::fs::write(path, raw)
74 }
75}