@@ -56,6 +56,7 @@ const API_URL_V1: &str = "https://api.openai.com/v1";
56
56
pub struct OpenAIClientBuilder {
57
57
api_endpoint : Option < String > ,
58
58
api_key : Option < String > ,
59
+ api_version : Option < String > ,
59
60
organization : Option < String > ,
60
61
proxy : Option < String > ,
61
62
timeout : Option < u64 > ,
@@ -65,7 +66,8 @@ pub struct OpenAIClientBuilder {
65
66
#[ derive( Debug ) ]
66
67
pub struct OpenAIClient {
67
68
api_endpoint : String ,
68
- api_key : String ,
69
+ api_key : Option < String > ,
70
+ api_version : Option < String > ,
69
71
organization : Option < String > ,
70
72
proxy : Option < String > ,
71
73
timeout : Option < u64 > ,
@@ -82,6 +84,11 @@ impl OpenAIClientBuilder {
82
84
self
83
85
}
84
86
87
+ pub fn with_api_version ( mut self , api_version : impl Into < String > ) -> Self {
88
+ self . api_version = Some ( api_version. into ( ) ) ;
89
+ self
90
+ }
91
+
85
92
pub fn with_endpoint ( mut self , endpoint : impl Into < String > ) -> Self {
86
93
self . api_endpoint = Some ( endpoint. into ( ) ) ;
87
94
self
@@ -112,14 +119,14 @@ impl OpenAIClientBuilder {
112
119
}
113
120
114
121
pub fn build ( self ) -> Result < OpenAIClient , Box < dyn Error > > {
115
- let api_key = self . api_key . ok_or ( "API key is required" ) ?;
116
122
let api_endpoint = self . api_endpoint . unwrap_or_else ( || {
117
123
std:: env:: var ( "OPENAI_API_BASE" ) . unwrap_or_else ( |_| API_URL_V1 . to_owned ( ) )
118
124
} ) ;
119
125
120
126
Ok ( OpenAIClient {
121
127
api_endpoint,
122
- api_key,
128
+ api_version : self . api_version ,
129
+ api_key : self . api_key ,
123
130
organization : self . organization ,
124
131
proxy : self . proxy ,
125
132
timeout : self . timeout ,
@@ -134,7 +141,13 @@ impl OpenAIClient {
134
141
}
135
142
136
143
async fn build_request ( & self , method : Method , path : & str ) -> reqwest:: RequestBuilder {
137
- let url = format ! ( "{}/{}" , self . api_endpoint, path) ;
144
+ let url = format ! (
145
+ "{}/{}?api-version={}" ,
146
+ self . api_endpoint,
147
+ path,
148
+ self . api_version. as_deref( ) . unwrap_or( "v1" )
149
+ ) ;
150
+
138
151
let client = Client :: builder ( ) ;
139
152
140
153
#[ cfg( feature = "rustls" ) ]
@@ -154,9 +167,14 @@ impl OpenAIClient {
154
167
155
168
let client = client. build ( ) . unwrap ( ) ;
156
169
157
- let mut request = client
158
- . request ( method, url)
159
- . header ( "Authorization" , format ! ( "Bearer {}" , self . api_key) ) ;
170
+ let mut request = client. request ( method, url) ;
171
+
172
+ if self . api_key . is_some ( ) {
173
+ request = request. header (
174
+ "Authorization" ,
175
+ format ! ( "Bearer {}" , self . api_key. as_ref( ) . unwrap( ) ) ,
176
+ ) ;
177
+ }
160
178
161
179
if let Some ( organization) = & self . organization {
162
180
request = request. header ( "openai-organization" , organization) ;
@@ -180,20 +198,9 @@ impl OpenAIClient {
180
198
path : & str ,
181
199
body : & impl serde:: ser:: Serialize ,
182
200
) -> Result < T , APIError > {
183
- let request_builder = self . build_request ( Method :: POST , path) . await ;
184
- let request_builder = request_builder. json ( body) ;
185
-
186
- // 💡 Convert to request to inspect it before sending
187
- let client = request_builder
188
- . try_clone ( )
189
- . expect ( "Cannot clone request builder" )
190
- . build ( )
191
- . expect ( "Failed to build request" ) ;
192
-
193
- // 🔍 Debug log: URL, headers, and optionally body
194
- tracing:: debug!( "🔵 URL: {}" , client. url( ) ) ;
195
- tracing:: debug!( "🟢 Headers:\n {:#?}" , client. headers( ) ) ;
196
- let response = request_builder. send ( ) . await ?;
201
+ let request = self . build_request ( Method :: POST , path) . await ;
202
+ let request = request. json ( body) ;
203
+ let response = request. send ( ) . await ?;
197
204
self . handle_response ( response) . await
198
205
}
199
206
0 commit comments