async_dashscope/
config.rs

1// https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation - text-generation
2// https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation - image-generation
3// https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation - 音频理解、视觉理解
4// https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation  - 录音文件识别
5// https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation  - 语音合成
6// https://dashscope.aliyuncs.com/api/v1/services/aigc/text2image/image-synthesis - 创意海报生成API参考
7
8use derive_builder::Builder;
9use reqwest::header::AUTHORIZATION;
10use secrecy::{ExposeSecret as _, SecretString};
11
12pub const DASHSCOPE_API_BASE: &str = "https://dashscope.aliyuncs.com/api/v1";
13
14/// # Config
15///
16/// ```rust
17/// let conf = ConfigBuilder::default()
18///         // optional, default is: https://dashscope.aliyuncs.com/api/v1
19///         .api_base("http://localhost:8080")
20///         .api_key("test")
21///         .build()
22///         .unwrap();
23/// let  client = Client::with_config(conf);
24/// ```
25#[derive(Debug, Builder, Clone)]
26#[builder(setter(into))]
27pub struct Config {
28    #[builder(setter(into, strip_option))]
29    #[builder(default = "self.default_base_url()")]
30    api_base: Option<String>,
31    api_key: SecretString,
32}
33
34impl ConfigBuilder {
35    fn default_base_url(&self) -> Option<String> {
36        Some(DASHSCOPE_API_BASE.to_string())
37    }
38}
39
40impl Config {
41    pub fn url(&self, path: &str) -> String {
42        let n_url = format!(
43            "{}/{}",
44            self.api_base.clone()
45                .unwrap_or(DASHSCOPE_API_BASE.to_string())
46                .trim_end_matches('/'),
47            path.trim_start_matches('/')
48        );
49        n_url.trim_end_matches('/').to_string()
50    }
51    pub fn headers(&self) -> reqwest::header::HeaderMap {
52        let mut headers = reqwest::header::HeaderMap::new();
53        headers.insert("Content-Type", "application/json".parse().unwrap());
54        headers.insert(
55            "X-DashScope-OssResourceResolve",
56            "enable".parse().unwrap(),
57        );
58        headers.insert(
59            AUTHORIZATION,
60            format!("Bearer {}", self.api_key.expose_secret())
61                .parse()
62                .unwrap(),
63        );
64        headers
65    }
66
67    pub fn set_api_key(&mut self, api_key: SecretString) {
68        self.api_key = api_key;
69    }
70    
71    pub fn api_key(&self) -> &SecretString {
72        &self.api_key
73    }
74}
75
76impl Default for Config {
77    fn default() -> Self {
78        Self {
79            api_base: Some(DASHSCOPE_API_BASE.to_string()),
80            api_key: std::env::var("DASHSCOPE_API_KEY")
81                .unwrap_or_else(|_| "".to_string())
82                .into(),
83        }
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn test_url_normal_case() {
93        let instance = ConfigBuilder::default()
94            .api_base("https://example.com")
95            .api_key("test")
96            .build()
97            .unwrap();
98        assert_eq!(instance.url("/v1"), "https://example.com/v1");
99    }
100
101    #[test]
102    fn test_url_empty_path() {
103        let instance = ConfigBuilder::default()
104            .api_base("http://localhost:8080")
105            .api_key("test")
106            .build()
107            .unwrap();
108        assert_eq!(instance.url(""), "http://localhost:8080");
109    }
110
111    #[test]
112    fn test_url_empty_api_base() {
113        let instance = ConfigBuilder::default().api_key("test").build().unwrap();
114        assert_eq!(
115            instance.url("/test"),
116            format!("{DASHSCOPE_API_BASE}/test").as_str()
117        );
118    }
119
120    #[test]
121    fn test_url_slash_in_both_parts() {
122        let instance = ConfigBuilder::default()
123            .api_base("https://a.com/")
124            .api_key("test")
125            .build()
126            .unwrap(); //Config {
127        assert_eq!(instance.url("/b"), "https://a.com/b");
128    }
129
130    #[test]
131    fn test_url_no_slash_in_path() {
132        let instance = ConfigBuilder::default()
133            .api_base("https://a.com")
134            .api_key("test")
135            .build()
136            .unwrap();
137        assert_eq!(instance.url("b"), "https://a.com/b");
138    }
139
140    #[test]
141    fn test_api_key() {
142        let instance = ConfigBuilder::default()
143            .api_base("https://example.com")
144            .api_key("test")
145            .build()
146            .unwrap();
147        assert_eq!(
148            instance.headers().get("Authorization").unwrap(),
149            "Bearer test"
150        );
151    }
152}