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