openai4rs/config/
client.rs

1use super::http::{HttpConfig, HttpConfigBuilder};
2use super::{Credentials, CredentialsBuilder};
3use crate::OpenAI;
4use crate::common::types::Body;
5use crate::config::CredentialsBuilderError;
6use http::header::IntoHeaderName;
7use http::{HeaderMap, HeaderValue};
8use std::fmt;
9use std::time::Duration;
10
11#[derive(Debug)]
12pub enum ConfigBuildError {
13    /// 必需字段缺失错误
14    RequiredFieldMissing(String),
15    /// 验证错误
16    ValidationError(String),
17}
18
19impl fmt::Display for ConfigBuildError {
20    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21        match self {
22            ConfigBuildError::RequiredFieldMissing(field) => {
23                write!(f, "Required field missing: {field}")
24            }
25            ConfigBuildError::ValidationError(msg) => {
26                write!(f, "Validation error: {msg}")
27            }
28        }
29    }
30}
31
32impl std::error::Error for ConfigBuildError {}
33
34// 实现From trait以适配构建器生成的错误类型
35impl From<super::http::HttpConfigBuilderError> for ConfigBuildError {
36    fn from(err: super::http::HttpConfigBuilderError) -> Self {
37        ConfigBuildError::RequiredFieldMissing(err.to_string())
38    }
39}
40
41impl From<CredentialsBuilderError> for ConfigBuildError {
42    fn from(err: CredentialsBuilderError) -> Self {
43        ConfigBuildError::RequiredFieldMissing(err.to_string())
44    }
45}
46
47/// 包含API通信所有设置的主配置结构
48pub struct Config {
49    /// 包含API密钥和URL的基础配置
50    credentials: Credentials,
51    /// HTTP特定配置(超时、代理等)
52    http: HttpConfig,
53    /// 失败请求的重试次数
54    retry_count: usize,
55}
56impl Config {
57    /// 使用指定的API密钥和基础URL创建新的Config
58    ///
59    /// # 参数
60    ///
61    /// * `api_key` - 用于身份验证的API密钥
62    /// * `base_url` - API请求的基础URL
63    pub fn new(api_key: impl Into<String>, base_url: impl Into<String>) -> Self {
64        Self {
65            credentials: Credentials::new(api_key.into(), base_url.into()),
66            http: HttpConfig::default(),
67            retry_count: 5,
68        }
69    }
70
71    /// 创建用于流畅配置的ConfigBuilder
72    pub fn builder() -> ConfigBuilder {
73        ConfigBuilder {
74            retry_count: 5,
75            credentials_builder: CredentialsBuilder::default(),
76            http_builder: HttpConfigBuilder::default(),
77        }
78    }
79
80    /// 返回API密钥
81    #[inline]
82    pub fn api_key(&self) -> &str {
83        self.credentials.api_key()
84    }
85
86    /// 返回基础URL
87    #[inline]
88    pub fn base_url(&self) -> &str {
89        self.credentials.base_url()
90    }
91
92    /// 返回重试次数
93    #[inline]
94    pub fn retry_count(&self) -> usize {
95        self.retry_count
96    }
97
98    /// 返回请求超时时间
99    #[inline]
100    pub fn timeout(&self) -> Duration {
101        self.http.timeout()
102    }
103
104    /// 返回可选的代理URL
105    #[inline]
106    pub fn proxy(&self) -> Option<&String> {
107        self.http.proxy()
108    }
109
110    /// 返回可选的自定义用户代理字符串
111    #[inline]
112    pub fn user_agent(&self) -> Option<&HeaderValue> {
113        self.http.user_agent()
114    }
115
116    /// 返回连接超时时间
117    #[inline]
118    pub fn connect_timeout(&self) -> Duration {
119        self.http.connect_timeout()
120    }
121
122    /// 返回对HTTP配置的引用
123    #[inline]
124    pub fn http(&self) -> &HttpConfig {
125        &self.http
126    }
127
128    /// 返回对基础配置的引用
129    #[inline]
130    pub fn credentials(&self) -> &Credentials {
131        &self.credentials
132    }
133
134    /// 为此配置设置新的基础URL
135    ///
136    /// # 参数
137    ///
138    /// * `base_url` - 要使用的新基础URL
139    ///
140    /// # 返回
141    ///
142    /// 用于方法链的自引用
143    pub fn with_base_url(&mut self, base_url: impl Into<String>) -> &mut Self {
144        self.credentials.with_base_url(base_url);
145        self
146    }
147
148    /// 为此配置设置新的API密钥
149    ///
150    /// # 参数
151    ///
152    /// * `api_key` - 要使用的新API密钥
153    ///
154    /// # 返回
155    ///
156    /// 用于方法链的自引用
157    pub fn with_api_key(&mut self, api_key: impl Into<String>) -> &mut Self {
158        self.credentials.with_api_key(api_key);
159        self
160    }
161
162    /// 设置失败请求的重试次数
163    ///
164    /// # 参数
165    ///
166    /// * `retry_count` - 重试次数
167    ///
168    /// # 返回
169    ///
170    /// 用于方法链的自引用
171    pub fn with_retry_count(&mut self, retry_count: usize) -> &mut Self {
172        self.retry_count = retry_count;
173        self
174    }
175
176    /// 设置请求超时时间
177    ///
178    /// # 参数
179    ///
180    /// * `timeout` - 超时值
181    ///
182    /// # 返回
183    ///
184    /// 用于方法链的自引用
185    pub fn with_timeout(&mut self, timeout: Duration) -> &mut Self {
186        self.http.with_timeout(timeout);
187        self
188    }
189
190    /// 设置连接超时时间
191    ///
192    /// # 参数
193    ///
194    /// * `connect_timeout` - 连接超时值
195    ///
196    /// # 返回
197    ///
198    /// 用于方法链的自引用
199    pub fn with_connect_timeout(&mut self, connect_timeout: Duration) -> &mut Self {
200        self.http.with_connect_timeout(connect_timeout);
201        self
202    }
203
204    /// 为请求设置HTTP代理
205    ///
206    /// # 参数
207    ///
208    /// * `proxy` - 要使用的代理URL
209    ///
210    /// # 返回
211    ///
212    /// 用于方法链的自引用
213    pub fn with_proxy(&mut self, proxy: impl Into<String>) -> &mut Self {
214        self.http.with_proxy(proxy);
215        self
216    }
217
218    /// 设置自定义用户代理字符串
219    ///
220    /// # 参数
221    ///
222    /// * `user_agent` - 要使用的用户代理字符串
223    ///
224    /// # 返回
225    ///
226    /// 用于方法链的自引用
227    pub fn with_user_agent(&mut self, user_agent: HeaderValue) -> &mut Self {
228        self.http.with_user_agent(user_agent);
229        self
230    }
231}
232
233/// 使用流畅API创建Config实例的构建器
234pub struct ConfigBuilder {
235    /// 失败请求的重试次数
236    retry_count: usize,
237    /// BaseConfig的构建器
238    credentials_builder: CredentialsBuilder,
239    /// HttpConfig的构建器
240    http_builder: HttpConfigBuilder,
241}
242
243impl ConfigBuilder {
244    /// 从当前构建器状态构建Config实例
245    ///
246    /// # 返回
247    ///
248    /// 包含Config实例或ConfigBuildError的Result
249    pub fn build(self) -> Result<Config, ConfigBuildError> {
250        Ok(Config {
251            credentials: self.credentials_builder.build()?,
252            http: self.http_builder.build()?,
253            retry_count: self.retry_count,
254        })
255    }
256
257    /// 从当前配置构建OpenAI客户端实例
258    ///
259    /// # 返回
260    ///
261    /// 包含OpenAI客户端实例或ConfigBuildError的Result
262    pub fn build_openai(self) -> Result<OpenAI, ConfigBuildError> {
263        Ok(OpenAI::with_config(self.build()?))
264    }
265
266    /// 设置配置的API密钥
267    ///
268    /// # 参数
269    ///
270    /// * `api_key` - 要使用的API密钥
271    ///
272    /// # 返回
273    ///
274    /// 用于方法链的构建器实例
275    pub fn api_key(mut self, api_key: impl Into<String>) -> Self {
276        self.credentials_builder = self.credentials_builder.api_key(api_key.into());
277        self
278    }
279
280    /// 设置配置的基础URL
281    ///
282    /// # 参数
283    ///
284    /// * `base_url` - 要使用的基础URL
285    ///
286    /// # 返回
287    ///
288    /// 用于方法链的构建器实例
289    pub fn base_url(mut self, base_url: impl Into<String>) -> Self {
290        self.credentials_builder = self.credentials_builder.base_url(base_url.into());
291        self
292    }
293
294    /// 设置配置的重试次数
295    ///
296    /// # 参数
297    ///
298    /// * `retry_count` - 重试次数
299    ///
300    /// # 返回
301    ///
302    /// 用于方法链的构建器实例
303    pub fn retry_count(mut self, retry_count: usize) -> Self {
304        self.retry_count = retry_count;
305        self
306    }
307
308    /// 设置配置的请求超时时间
309    ///
310    /// # 参数
311    ///
312    /// * `timeout` - 超时值
313    ///
314    /// # 返回
315    ///
316    /// 用于方法链的构建器实例
317    pub fn timeout(mut self, timeout: Duration) -> Self {
318        self.http_builder = self.http_builder.timeout(timeout);
319        self
320    }
321
322    /// 设置配置的连接超时时间
323    ///
324    /// # 参数
325    ///
326    /// * `connect_timeout` - 连接超时值
327    ///
328    /// # 返回
329    ///
330    /// 用于方法链的构建器实例
331    pub fn connect_timeout(mut self, connect_timeout: Duration) -> Self {
332        self.http_builder = self.http_builder.connect_timeout(connect_timeout);
333        self
334    }
335
336    /// 为配置设置HTTP代理
337    ///
338    /// # 参数
339    ///
340    /// * `proxy` - 要使用的代理URL
341    ///
342    /// # 返回
343    ///
344    /// 用于方法链的构建器实例
345    pub fn proxy(mut self, proxy: impl Into<String>) -> Self {
346        self.http_builder = self.http_builder.proxy(proxy.into());
347        self
348    }
349
350    /// 为配置设置自定义用户代理字符串
351    ///
352    /// # 参数
353    ///
354    /// * `user_agent` - 要使用的用户代理字符串
355    ///
356    /// # 返回
357    ///
358    /// 用于方法链的构建器实例
359    pub fn user_agent(mut self, user_agent: HeaderValue) -> Self {
360        self.http_builder = self.http_builder.user_agent(user_agent);
361        self
362    }
363
364    /// 向HTTP配置添加全局头。
365    ///
366    /// # 参数
367    ///
368    /// * `key` - 头名称
369    /// * `value` - 头值
370    ///
371    /// # 返回
372    ///
373    /// 用于方法链的构建器实例
374    pub fn header<K: IntoHeaderName>(mut self, key: K, value: HeaderValue) -> Self {
375        self.http_builder = self.http_builder.header(key, value);
376        self
377    }
378
379    /// 向HTTP配置添加全局主体字段。
380    ///
381    /// # 参数
382    ///
383    /// * `key` - 主体字段名称
384    /// * `value` - 主体字段值
385    ///
386    /// # 返回
387    ///
388    /// 用于方法链的构建器实例
389    pub fn body(mut self, key: impl Into<String>, value: impl Into<serde_json::Value>) -> Self {
390        self.http_builder = self.http_builder.body(key.into(), value.into());
391        self
392    }
393
394    /// 在HTTP配置中设置多个全局头。
395    ///
396    /// # 参数
397    ///
398    /// * `headers` - 头名称到值的映射
399    ///
400    /// # 返回
401    ///
402    /// 用于方法链的构建器实例
403    pub fn headers(mut self, headers: HeaderMap) -> Self {
404        self.http_builder = self.http_builder.headers(headers);
405        self
406    }
407
408    /// 在HTTP配置中设置多个全局主体字段。
409    ///
410    /// # 参数
411    ///
412    /// * `bodys` - 主体字段名称到值的映射
413    ///
414    /// # 返回
415    ///
416    /// 用于方法链的构建器实例
417    pub fn bodys(mut self, bodys: Body) -> Self {
418        self.http_builder = self.http_builder.bodys(bodys);
419        self
420    }
421}