1use serde::Deserialize;
2
3#[derive(Clone, Default, Deserialize)]
4pub struct ProviderConfig {
5 pub base_url: Option<String>,
6 pub api_key: Option<String>,
7 pub models: Option<Vec<String>>,
8}
9
10#[derive(Clone, Default)]
11pub struct CallOptions {
12 pub api_key: Option<String>,
13 pub base_url: Option<String>,
14}
15
16#[derive(Clone, Default, Deserialize)]
17pub struct Config {
18 #[serde(default)]
19 pub deepseek: ProviderConfig,
20 #[serde(default)]
21 pub glm: ProviderConfig, #[serde(default)]
23 pub qwen: ProviderConfig, #[serde(default)]
25 pub kimi: ProviderConfig, #[serde(default)]
28 pub discover_models: bool,
29 #[serde(default)]
31 pub discover_models_ttl_secs: u64,
32}
33
34impl Config {
35 pub fn from_env() -> Self {
36 let get = |k: &str| std::env::var(k).ok().filter(|s| !s.is_empty());
37 Config {
38 deepseek: ProviderConfig {
39 base_url: get("DEEPSEEK_BASE_URL"),
40 api_key: get("DEEPSEEK_API_KEY"),
41 ..Default::default()
42 },
43 glm: ProviderConfig {
44 base_url: get("GLM_BASE_URL").or_else(|| get("ZHIPU_BASE_URL")),
45 api_key: get("GLM_API_KEY").or_else(|| get("ZHIPU_API_KEY")),
46 ..Default::default()
47 },
48 qwen: ProviderConfig {
49 base_url: get("QWEN_BASE_URL").or_else(|| get("ALIBABA_QWEN_BASE_URL")),
50 api_key: get("QWEN_API_KEY").or_else(|| get("ALIBABA_QWEN_API_KEY")),
51 ..Default::default()
52 },
53 kimi: ProviderConfig {
54 base_url: get("KIMI_BASE_URL").or_else(|| get("MOONSHOT_BASE_URL")),
55 api_key: get("KIMI_API_KEY").or_else(|| get("MOONSHOT_API_KEY")),
56 ..Default::default()
57 },
58 discover_models: false,
60 discover_models_ttl_secs: 0,
62 }
63 }
64
65 pub fn from_yaml_file_auto() -> Option<Self> {
67 use std::fs;
68 use std::path::PathBuf;
69
70 let candidates: [PathBuf; 2] = [
71 PathBuf::from("llm-gateway.config.yaml"),
72 std::env::var("HOME")
73 .map(|home| PathBuf::from(home).join(".config/llm-gateway/config.yaml"))
74 .unwrap_or_else(|_| PathBuf::from("/non-existent")),
75 ];
76
77 for path in candidates {
78 if path.exists() {
79 let text = fs::read_to_string(&path).ok()?;
80 if let Ok(cfg) = serde_yaml::from_str::<Config>(&text) {
81 return Some(cfg);
82 }
83 }
84 }
85 None
86 }
87}