batuta/serve/banco/
config.rs1use crate::serve::backends::PrivacyTier;
7use serde::{Deserialize, Serialize};
8use std::path::PathBuf;
9
10#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12pub struct BancoConfig {
13 #[serde(default)]
14 pub server: ServerConfig,
15 #[serde(default)]
16 pub inference: InferenceConfig,
17 #[serde(default)]
18 pub budget: BudgetConfig,
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct ServerConfig {
24 #[serde(default = "default_host")]
25 pub host: String,
26 #[serde(default = "default_port")]
27 pub port: u16,
28 #[serde(default)]
29 pub privacy_tier: PrivacyTierConfig,
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct InferenceConfig {
35 #[serde(default = "default_temperature")]
36 pub temperature: f32,
37 #[serde(default = "default_top_p")]
38 pub top_p: f32,
39 #[serde(default = "default_max_tokens")]
40 pub max_tokens: u32,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct BudgetConfig {
46 #[serde(default = "default_daily_limit")]
47 pub daily_limit_usd: f64,
48 #[serde(default = "default_max_request")]
49 pub max_request_usd: f64,
50}
51
52#[derive(Debug, Clone, Default, Serialize, Deserialize)]
54#[serde(rename_all = "lowercase")]
55pub enum PrivacyTierConfig {
56 Sovereign,
57 Private,
58 #[default]
59 Standard,
60}
61
62impl From<PrivacyTierConfig> for PrivacyTier {
63 fn from(c: PrivacyTierConfig) -> Self {
64 match c {
65 PrivacyTierConfig::Sovereign => Self::Sovereign,
66 PrivacyTierConfig::Private => Self::Private,
67 PrivacyTierConfig::Standard => Self::Standard,
68 }
69 }
70}
71
72fn default_host() -> String {
73 "127.0.0.1".to_string()
74}
75fn default_port() -> u16 {
76 8090
77}
78fn default_temperature() -> f32 {
79 0.7
80}
81fn default_top_p() -> f32 {
82 1.0
83}
84fn default_max_tokens() -> u32 {
85 256
86}
87fn default_daily_limit() -> f64 {
88 10.0
89}
90fn default_max_request() -> f64 {
91 1.0
92}
93
94impl Default for ServerConfig {
95 fn default() -> Self {
96 Self {
97 host: default_host(),
98 port: default_port(),
99 privacy_tier: PrivacyTierConfig::default(),
100 }
101 }
102}
103
104impl Default for InferenceConfig {
105 fn default() -> Self {
106 Self {
107 temperature: default_temperature(),
108 top_p: default_top_p(),
109 max_tokens: default_max_tokens(),
110 }
111 }
112}
113
114impl Default for BudgetConfig {
115 fn default() -> Self {
116 Self { daily_limit_usd: default_daily_limit(), max_request_usd: default_max_request() }
117 }
118}
119
120impl BancoConfig {
121 #[must_use]
123 pub fn config_dir() -> Option<PathBuf> {
124 dirs::home_dir().map(|h| h.join(".banco"))
125 }
126
127 #[must_use]
129 pub fn config_path() -> Option<PathBuf> {
130 Self::config_dir().map(|d| d.join("config.toml"))
131 }
132
133 #[must_use]
135 pub fn load() -> Self {
136 let Some(path) = Self::config_path() else {
137 return Self::default();
138 };
139 match std::fs::read_to_string(&path) {
140 Ok(content) => match toml::from_str(&content) {
141 Ok(config) => config,
142 Err(e) => {
143 eprintln!("[banco] Warning: failed to parse {}: {e}", path.display());
144 Self::default()
145 }
146 },
147 Err(_) => Self::default(),
148 }
149 }
150
151 pub fn save(&self) -> anyhow::Result<()> {
153 let Some(dir) = Self::config_dir() else {
154 anyhow::bail!("Cannot determine home directory");
155 };
156 std::fs::create_dir_all(&dir)?;
157 let content = toml::to_string_pretty(self)?;
158 let path = dir.join("config.toml");
159 std::fs::write(&path, content)?;
160 Ok(())
161 }
162}