llm_connector/core/builder.rs
1//! Provider 构建器 - 统一的构建接口
2//!
3//! 这个模块提供了一个优雅的 Builder 模式 API,用于构建各种 Provider。
4
5use crate::core::{GenericProvider, HttpClient, Protocol};
6use crate::error::LlmConnectorError;
7use std::collections::HashMap;
8
9/// Provider 构建器
10///
11/// 提供链式调用的 API 来构建 Provider,统一处理所有配置项。
12///
13/// # 示例
14/// ```rust,no_run
15/// use llm_connector::core::{ProviderBuilder, Protocol};
16/// use llm_connector::protocols::OpenAIProtocol;
17///
18/// let provider = ProviderBuilder::new(
19/// OpenAIProtocol::new("sk-..."),
20/// "https://api.openai.com"
21/// )
22/// .timeout(60)
23/// .proxy("http://proxy:8080")
24/// .header("X-Custom-Header", "value")
25/// .build()
26/// .unwrap();
27/// ```
28pub struct ProviderBuilder<P: Protocol> {
29 protocol: P,
30 base_url: String,
31 timeout_secs: Option<u64>,
32 proxy: Option<String>,
33 extra_headers: HashMap<String, String>,
34}
35
36impl<P: Protocol> ProviderBuilder<P> {
37 /// 创建新的 Provider 构建器
38 ///
39 /// # 参数
40 /// - `protocol`: 协议实例
41 /// - `base_url`: 基础 URL
42 ///
43 /// # 示例
44 /// ```rust,no_run
45 /// use llm_connector::core::ProviderBuilder;
46 /// use llm_connector::protocols::OpenAIProtocol;
47 ///
48 /// let builder = ProviderBuilder::new(
49 /// OpenAIProtocol::new("sk-..."),
50 /// "https://api.openai.com"
51 /// );
52 /// ```
53 pub fn new(protocol: P, base_url: &str) -> Self {
54 Self {
55 protocol,
56 base_url: base_url.to_string(),
57 timeout_secs: None,
58 proxy: None,
59 extra_headers: HashMap::new(),
60 }
61 }
62
63 /// 设置超时时间(秒)
64 ///
65 /// # 示例
66 /// ```rust,no_run
67 /// # use llm_connector::core::ProviderBuilder;
68 /// # use llm_connector::protocols::OpenAIProtocol;
69 /// let builder = ProviderBuilder::new(
70 /// OpenAIProtocol::new("sk-..."),
71 /// "https://api.openai.com"
72 /// )
73 /// .timeout(60); // 60秒超时
74 /// ```
75 pub fn timeout(mut self, secs: u64) -> Self {
76 self.timeout_secs = Some(secs);
77 self
78 }
79
80 /// 设置代理
81 ///
82 /// # 示例
83 /// ```rust,no_run
84 /// # use llm_connector::core::ProviderBuilder;
85 /// # use llm_connector::protocols::OpenAIProtocol;
86 /// let builder = ProviderBuilder::new(
87 /// OpenAIProtocol::new("sk-..."),
88 /// "https://api.openai.com"
89 /// )
90 /// .proxy("http://proxy:8080");
91 /// ```
92 pub fn proxy(mut self, proxy: &str) -> Self {
93 self.proxy = Some(proxy.to_string());
94 self
95 }
96
97 /// 添加额外的 HTTP 头部
98 ///
99 /// 注意:这些头部会与协议的认证头部合并。
100 ///
101 /// # 示例
102 /// ```rust,no_run
103 /// # use llm_connector::core::ProviderBuilder;
104 /// # use llm_connector::protocols::OpenAIProtocol;
105 /// let builder = ProviderBuilder::new(
106 /// OpenAIProtocol::new("sk-..."),
107 /// "https://api.openai.com"
108 /// )
109 /// .header("X-Custom-Header", "value")
110 /// .header("X-Another-Header", "value2");
111 /// ```
112 pub fn header(mut self, key: &str, value: &str) -> Self {
113 self.extra_headers.insert(key.to_string(), value.to_string());
114 self
115 }
116
117 /// 构建 Provider
118 ///
119 /// # 返回
120 /// 配置好的 GenericProvider 实例
121 ///
122 /// # 错误
123 /// 如果 HTTP 客户端创建失败,返回错误
124 ///
125 /// # 示例
126 /// ```rust,no_run
127 /// # use llm_connector::core::ProviderBuilder;
128 /// # use llm_connector::protocols::OpenAIProtocol;
129 /// let provider = ProviderBuilder::new(
130 /// OpenAIProtocol::new("sk-..."),
131 /// "https://api.openai.com"
132 /// )
133 /// .timeout(60)
134 /// .build()
135 /// .unwrap();
136 /// ```
137 pub fn build(self) -> Result<GenericProvider<P>, LlmConnectorError> {
138 // 创建 HTTP 客户端
139 let client = HttpClient::with_config(
140 &self.base_url,
141 self.timeout_secs,
142 self.proxy.as_deref(),
143 )?;
144
145 // 合并认证头和额外头部
146 let mut headers: HashMap<String, String> =
147 self.protocol.auth_headers().into_iter().collect();
148 headers.extend(self.extra_headers);
149 let client = client.with_headers(headers);
150
151 // 创建通用提供商
152 Ok(GenericProvider::new(self.protocol, client))
153 }
154}
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159 use crate::protocols::OpenAIProtocol;
160
161 #[test]
162 fn test_builder_basic() {
163 let provider = ProviderBuilder::new(
164 OpenAIProtocol::new("sk-test"),
165 "https://api.openai.com"
166 )
167 .build();
168
169 assert!(provider.is_ok());
170 }
171
172 #[test]
173 fn test_builder_with_timeout() {
174 let provider = ProviderBuilder::new(
175 OpenAIProtocol::new("sk-test"),
176 "https://api.openai.com"
177 )
178 .timeout(60)
179 .build();
180
181 assert!(provider.is_ok());
182 }
183
184 #[test]
185 fn test_builder_with_proxy() {
186 let provider = ProviderBuilder::new(
187 OpenAIProtocol::new("sk-test"),
188 "https://api.openai.com"
189 )
190 .proxy("http://proxy:8080")
191 .build();
192
193 assert!(provider.is_ok());
194 }
195
196 #[test]
197 fn test_builder_with_headers() {
198 let provider = ProviderBuilder::new(
199 OpenAIProtocol::new("sk-test"),
200 "https://api.openai.com"
201 )
202 .header("X-Custom-Header", "value")
203 .header("X-Another-Header", "value2")
204 .build();
205
206 assert!(provider.is_ok());
207 }
208
209 #[test]
210 fn test_builder_chain() {
211 let provider = ProviderBuilder::new(
212 OpenAIProtocol::new("sk-test"),
213 "https://api.openai.com"
214 )
215 .timeout(60)
216 .proxy("http://proxy:8080")
217 .header("X-Custom-Header", "value")
218 .build();
219
220 assert!(provider.is_ok());
221 }
222}
223