Struct async_openai::Client
source · pub struct Client { /* private fields */ }
Expand description
Client container for api key, base url and other metadata required to make API calls.
Implementations§
source§impl Client
impl Client
sourcepub fn new() -> Self
pub fn new() -> Self
Create client with default API_BASE url and default API key from OPENAI_API_KEY env var
sourcepub fn with_api_key<S: Into<String>>(self, api_key: S) -> Self
pub fn with_api_key<S: Into<String>>(self, api_key: S) -> Self
To use a different API key different from default OPENAI_API_KEY env var
pub fn with_org_id<S: Into<String>>(self, org_id: S) -> Self
sourcepub fn with_api_base<S: Into<String>>(self, api_base: S) -> Self
pub fn with_api_base<S: Into<String>>(self, api_base: S) -> Self
To use a API base url different from default API_BASE
sourcepub fn with_backoff(self, backoff: ExponentialBackoff) -> Self
pub fn with_backoff(self, backoff: ExponentialBackoff) -> Self
Exponential backoff for retrying rate limited requests. Form submissions are not retried.
sourcepub fn api_base(&self) -> &str
pub fn api_base(&self) -> &str
Examples found in repository?
src/client.rs (line 66)
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
pub(crate) async fn get<O>(&self, path: &str) -> Result<O, OpenAIError>
where
O: DeserializeOwned,
{
let request = reqwest::Client::new()
.get(format!("{}{path}", self.api_base()))
.bearer_auth(self.api_key())
.build()?;
self.execute(request).await
}
/// Make a DELETE request to {path} and deserialize the response body
pub(crate) async fn delete<O>(&self, path: &str) -> Result<O, OpenAIError>
where
O: DeserializeOwned,
{
let request = reqwest::Client::new()
.delete(format!("{}{path}", self.api_base()))
.bearer_auth(self.api_key())
.build()?;
self.execute(request).await
}
/// Make a POST request to {path} and deserialize the response body
pub(crate) async fn post<I, O>(&self, path: &str, request: I) -> Result<O, OpenAIError>
where
I: Serialize,
O: DeserializeOwned,
{
let request = reqwest::Client::new()
.post(format!("{}{path}", self.api_base()))
.bearer_auth(self.api_key())
.json(&request)
.build()?;
self.execute(request).await
}
/// POST a form at {path} and deserialize the response body
pub(crate) async fn post_form<O>(
&self,
path: &str,
form: reqwest::multipart::Form,
) -> Result<O, OpenAIError>
where
O: DeserializeOwned,
{
let request = reqwest::Client::new()
.post(format!("{}{path}", self.api_base()))
.bearer_auth(self.api_key())
.multipart(form)
.build()?;
self.execute(request).await
}
More examples
src/completion.rs (line 49)
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
pub async fn create_stream(
client: &Client,
mut request: CreateCompletionRequest,
) -> Result<CompletionResponseStream, OpenAIError> {
if request.stream.is_some() && !request.stream.unwrap() {
return Err(OpenAIError::InvalidArgument(
"When stream is false, use Completion::create".into(),
));
}
request.stream = Some(true);
let mut event_source = reqwest::Client::new()
.post(format!("{}/completions", client.api_base()))
.bearer_auth(client.api_key())
.json(&request)
.eventsource()
.unwrap();
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
tokio::spawn(async move {
while let Some(ev) = event_source.next().await {
match ev {
Err(e) => {
if let Err(_e) = tx.send(Err(OpenAIError::StreamError(e.to_string()))) {
// rx dropped
break;
}
}
Ok(event) => match event {
Event::Message(message) => {
if message.data == "[DONE]" {
break;
}
let response = match serde_json::from_str::<CreateCompletionResponse>(
&message.data,
) {
Err(e) => Err(OpenAIError::JSONDeserialize(e)),
Ok(ccr) => Ok(ccr),
};
if let Err(_e) = tx.send(response) {
// rx dropped
break;
}
}
Event::Open => continue,
},
}
}
event_source.close();
});
Ok(
Box::pin(tokio_stream::wrappers::UnboundedReceiverStream::new(rx))
as CompletionResponseStream,
)
}
sourcepub fn api_key(&self) -> &str
pub fn api_key(&self) -> &str
Examples found in repository?
src/client.rs (line 67)
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
pub(crate) async fn get<O>(&self, path: &str) -> Result<O, OpenAIError>
where
O: DeserializeOwned,
{
let request = reqwest::Client::new()
.get(format!("{}{path}", self.api_base()))
.bearer_auth(self.api_key())
.build()?;
self.execute(request).await
}
/// Make a DELETE request to {path} and deserialize the response body
pub(crate) async fn delete<O>(&self, path: &str) -> Result<O, OpenAIError>
where
O: DeserializeOwned,
{
let request = reqwest::Client::new()
.delete(format!("{}{path}", self.api_base()))
.bearer_auth(self.api_key())
.build()?;
self.execute(request).await
}
/// Make a POST request to {path} and deserialize the response body
pub(crate) async fn post<I, O>(&self, path: &str, request: I) -> Result<O, OpenAIError>
where
I: Serialize,
O: DeserializeOwned,
{
let request = reqwest::Client::new()
.post(format!("{}{path}", self.api_base()))
.bearer_auth(self.api_key())
.json(&request)
.build()?;
self.execute(request).await
}
/// POST a form at {path} and deserialize the response body
pub(crate) async fn post_form<O>(
&self,
path: &str,
form: reqwest::multipart::Form,
) -> Result<O, OpenAIError>
where
O: DeserializeOwned,
{
let request = reqwest::Client::new()
.post(format!("{}{path}", self.api_base()))
.bearer_auth(self.api_key())
.multipart(form)
.build()?;
self.execute(request).await
}
More examples
src/completion.rs (line 50)
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
pub async fn create_stream(
client: &Client,
mut request: CreateCompletionRequest,
) -> Result<CompletionResponseStream, OpenAIError> {
if request.stream.is_some() && !request.stream.unwrap() {
return Err(OpenAIError::InvalidArgument(
"When stream is false, use Completion::create".into(),
));
}
request.stream = Some(true);
let mut event_source = reqwest::Client::new()
.post(format!("{}/completions", client.api_base()))
.bearer_auth(client.api_key())
.json(&request)
.eventsource()
.unwrap();
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
tokio::spawn(async move {
while let Some(ev) = event_source.next().await {
match ev {
Err(e) => {
if let Err(_e) = tx.send(Err(OpenAIError::StreamError(e.to_string()))) {
// rx dropped
break;
}
}
Ok(event) => match event {
Event::Message(message) => {
if message.data == "[DONE]" {
break;
}
let response = match serde_json::from_str::<CreateCompletionResponse>(
&message.data,
) {
Err(e) => Err(OpenAIError::JSONDeserialize(e)),
Ok(ccr) => Ok(ccr),
};
if let Err(_e) = tx.send(response) {
// rx dropped
break;
}
}
Event::Open => continue,
},
}
}
event_source.close();
});
Ok(
Box::pin(tokio_stream::wrappers::UnboundedReceiverStream::new(rx))
as CompletionResponseStream,
)
}