Skip to content

Commit 6bc9f1e

Browse files
64bitifsheldon
authored andcommitted
feat: complete spec sync (64bit#473)
* add project rate limits api * add usage api * add usage example * fix test * fix test * admin api keys api * certificates api * fix test * nest admin apis in client.admin() * nested types for admin apis * fix example compilation * types::assistants * fix imports in the examples * fix * fix test * only unsigned types * add remanining byot tests * add realtime apis * u64 for timestamps * fix * upated readme * updated readme license * add community project back * update docs for dynamic dispatch * update readme * update readme * fix test * updated spec * cargo fmt (cherry picked from commit 4754c24) # Conflicts: # async-openai/README.md # async-openai/src/audit_logs.rs # async-openai/src/client.rs # async-openai/src/invites.rs # async-openai/src/project_api_keys.rs # async-openai/src/projects.rs # async-openai/src/steps.rs # async-openai/src/types/assistants/assistant_impls.rs # async-openai/src/types/impls.rs # async-openai/src/users.rs # async-openai/tests/completion.rs # async-openai/tests/ser_de.rs # examples/assistants-code-interpreter/src/main.rs # examples/assistants-file-search/src/main.rs # examples/assistants-func-call-stream/src/main.rs # examples/assistants/src/main.rs
1 parent 1d58980 commit 6bc9f1e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+68406
-17794
lines changed

async-openai/README.md

Lines changed: 81 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -17,40 +17,33 @@ project is and will be done manually when `async-openai` releases a new version.
1717
with `async-openai` releases, which means when `async-openai` releases `x.y.z`, `async-openai-wasm` also releases
1818
a `x.y.z` version.
1919

20-
`async-openai-wasm` is an unofficial Rust library for OpenAI.
21-
22-
- It's based on [OpenAI OpenAPI spec](https://github.com/openai/openai-openapi)
23-
- Current features:
24-
- [x] Administration (partially implemented)
25-
- [x] Assistants (beta)
26-
- [x] Audio
27-
- [x] Batch
28-
- [x] Chat
29-
- [x] ChatKit (beta)
30-
- [x] Completions (legacy)
31-
- [x] Conversations
32-
- [x] Containers
33-
- [x] Embeddings
34-
- [x] Evals
35-
- [x] Files
36-
- [x] Fine-Tuning
37-
- [x] Images
38-
- [x] Models
39-
- [x] Moderations
40-
- [x] Realtime (partially implemented)
41-
- [x] Responses
42-
- [x] Uploads
43-
- [x] Vector Stores
44-
- [x] Videos
45-
- [x] Webhooks
46-
- [x] **WASM support**
47-
- [x] Reasoning Model Support: support models like DeepSeek R1 via broader support for OpenAI-compatible endpoints, see `examples/reasoning`
20+
`async-openai-wasm` is an unofficial Rust library for OpenAI, based on [OpenAI OpenAPI spec](https://github.com/openai/openai-openapi). It implements all APIs from the spec:
21+
22+
| Features | APIs |
23+
|---|---|
24+
| **Responses API** | Responses, Conversations, Streaming events |
25+
| **Webhooks** | Webhook Events |
26+
| **Platform APIs** | Audio, Audio Streaming, Videos, Images, Image Streaming, Embeddings, Evals, Fine-tuning, Graders, Batch, Files, Uploads, Models, Moderations |
27+
| **Vector stores** | Vector stores, Vector store files, Vector store file batches |
28+
| **ChatKit** <sub>(Beta)</sub> | ChatKit |
29+
| **Containers** | Containers, Container Files |
30+
| **Realtime** | Realtime Calls, Client secrets, Client events, Server events |
31+
| **Chat Completions** | Chat Completions, Streaming |
32+
| **Assistants** <sub>(Beta)</sub> | Assistants, Threads, Messages, Runs, Run steps, Streaming |
33+
| **Administration** | Administration, Admin API Keys, Invites, Users, Projects, Project users, Project service accounts, Project API keys, Project rate limits, Audit logs, Usage, Certificates |
34+
| **Legacy** | Completions |
35+
36+
Features that makes `async-openai` unique:
4837
- Bring your own custom types for Request or Response objects.
4938
- SSE streaming on available APIs
5039
- Ergonomic builder pattern for all request objects.
5140
- Microsoft Azure OpenAI Service (only for APIs matching OpenAI spec)
5241
- Bring your own custom types for Request or Response objects.
5342

43+
More on `async-openai-wasm`:
44+
- **WASM support**
45+
- Reasoning Model Support: support models like DeepSeek R1 via broader support for OpenAI-compatible endpoints, see `examples/reasoning`
46+
5447
**Note on Azure OpenAI Service (AOS)**: `async-openai-wasm` primarily implements OpenAI spec, and doesn't try to
5548
maintain parity with spec of AOS. Just like `async-openai`.
5649

@@ -88,9 +81,9 @@ $Env:OPENAI_API_KEY='sk-...'
8881
and [WASM examples](https://github.com/ifsheldon/async-openai-wasm/tree/main/examples) in `async-openai-wasm`.
8982
- Visit [docs.rs/async-openai](https://docs.rs/async-openai) for docs.
9083

91-
## Realtime API
84+
## Realtime
9285

93-
Only types for Realtime API are implemented, and can be enabled with feature flag `realtime`.
86+
Realtime types and APIs can be enabled with feature flag `realtime`.
9487

9588
Again, the types do not bundle with a specific WS implementation. Need to convert a client event into a WS message by yourself, which is just simple `your_ws_impl::Message::Text(some_client_event.into_text())`.
9689

@@ -142,20 +135,66 @@ async fn main() -> Result<(), Box<dyn Error>> {
142135
<sub>Scaled up for README, actual size 256x256</sub>
143136
</div>
144137

145-
## Dynamic Dispatch for Different Providers
138+
## Bring Your Own Types
146139

147-
For any struct that implements `Config` trait, you can wrap it in a smart pointer and cast the pointer to `dyn Config`
148-
trait object, then your client can accept any wrapped configuration type.
140+
Enable methods whose input and outputs are generics with `byot` feature. It creates a new method with same name and `_byot` suffix.
149141

150-
For example,
142+
`byot` requires trait bounds:
143+
- a request type (`fn` input parameter) needs to implement `serde::Serialize` or `std::fmt::Display` trait
144+
- a response type (`fn` ouput parameter) needs to implement `serde::de::DeserializeOwned` trait.
151145

146+
For example, to use `serde_json::Value` as request and response type:
152147
```rust
153-
use async_openai::{Client, config::Config, config::OpenAIConfig};
148+
let response: Value = client
149+
.chat()
150+
.create_byot(json!({
151+
"messages": [
152+
{
153+
"role": "developer",
154+
"content": "You are a helpful assistant"
155+
},
156+
{
157+
"role": "user",
158+
"content": "What do you think about life?"
159+
}
160+
],
161+
"model": "gpt-4o",
162+
"store": false
163+
}))
164+
.await?;
165+
```
166+
167+
This can be useful in many scenarios:
168+
- To use this library with other OpenAI compatible APIs whose types don't exactly match OpenAI.
169+
- Extend existing types in this crate with new fields with `serde` (for example with `#[serde(flatten)]`).
170+
- To avoid verbose types.
171+
- To escape deserialization errors.
172+
173+
Visit [examples/bring-your-own-type](https://github.com/64bit/async-openai/tree/main/examples/bring-your-own-type)
174+
directory to learn more.
175+
176+
## Dynamic Dispatch for OpenAI-compatible Providers
177+
178+
This allows you to use same code (say a `fn`) to call APIs on different OpenAI-compatible providers.
179+
180+
For any struct that implements `Config` trait, wrap it in a smart pointer and cast the pointer to `dyn Config`
181+
trait object, then create a client with `Box` or `Arc` wrapped configuration.
154182

155-
let openai_config = OpenAIConfig::default();
156-
// You can use `std::sync::Arc` to wrap the config as well
157-
let config = Box::new(openai_config) as Box<dyn Config>;
158-
let client: Client<Box<dyn Config> > = Client::with_config(config);
183+
For example:
184+
185+
```rust
186+
use async_openai::{Client, config::{Config, OpenAIConfig}};
187+
188+
// Use `Box` or `std::sync::Arc` to wrap the config
189+
let config = Box::new(OpenAIConfig::default()) as Box<dyn Config>;
190+
// create client
191+
let client: Client<Box<dyn Config>> = Client::with_config(config);
192+
193+
// A function can now accept a `&Client<Box<dyn Config>>` parameter
194+
// which can invoke any openai compatible api
195+
fn chat_completion(client: &Client<Box<dyn Config>>) {
196+
todo!()
197+
}
159198
```
160199

161200
## Contributing
@@ -165,11 +204,14 @@ project [async-openai](https://github.com/64bit/async-openai).
165204

166205
This project adheres to [Rust Code of Conduct](https://www.rust-lang.org/policies/code-of-conduct)
167206

207+
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in async-openai by you, shall be licensed as MIT, without any additional terms or conditions.
208+
168209
## Why `async-openai-wasm`
169210

170211
Because I wanted to develop and release a crate that depends on the wasm feature in `experiments` branch
171212
of [async-openai](https://github.com/64bit/async-openai), but the pace of stabilizing the wasm feature is different
172213
from what I expected.
214+
- [openai-func-enums](https://github.com/frankfralick/openai-func-enums) macros for working with function/tool calls.
173215

174216
## License
175217

async-openai/src/admin.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use crate::{
2+
Client, admin_api_keys::AdminAPIKeys, audit_logs::AuditLogs, certificates::Certificates,
3+
config::Config, invites::Invites, projects::Projects, users::Users,
4+
};
5+
6+
/// Admin group for all administration APIs.
7+
/// This groups together admin API keys, invites, users, projects, audit logs, and certificates.
8+
pub struct Admin<'c, C: Config> {
9+
client: &'c Client<C>,
10+
}
11+
12+
impl<'c, C: Config> Admin<'c, C> {
13+
pub(crate) fn new(client: &'c Client<C>) -> Self {
14+
Self { client }
15+
}
16+
17+
/// To call [AdminAPIKeys] group related APIs using this client.
18+
pub fn api_keys(&self) -> AdminAPIKeys<'_, C> {
19+
AdminAPIKeys::new(self.client)
20+
}
21+
22+
/// To call [Invites] group related APIs using this client.
23+
pub fn invites(&self) -> Invites<'_, C> {
24+
Invites::new(self.client)
25+
}
26+
27+
/// To call [Users] group related APIs using this client.
28+
pub fn users(&self) -> Users<'_, C> {
29+
Users::new(self.client)
30+
}
31+
32+
/// To call [Projects] group related APIs using this client.
33+
pub fn projects(&self) -> Projects<'_, C> {
34+
Projects::new(self.client)
35+
}
36+
37+
/// To call [AuditLogs] group related APIs using this client.
38+
pub fn audit_logs(&self) -> AuditLogs<'_, C> {
39+
AuditLogs::new(self.client)
40+
}
41+
42+
/// To call [Certificates] group related APIs using this client.
43+
pub fn certificates(&self) -> Certificates<'_, C> {
44+
Certificates::new(self.client)
45+
}
46+
}

async-openai/src/admin_api_keys.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
use serde::Serialize;
2+
3+
use crate::{
4+
Client,
5+
config::Config,
6+
error::OpenAIError,
7+
types::admin::api_keys::{
8+
AdminApiKey, AdminApiKeyDeleteResponse, ApiKeyList, CreateAdminApiKeyRequest,
9+
},
10+
};
11+
12+
/// Admin API keys enable Organization Owners to programmatically manage various aspects of their
13+
/// organization, including users, projects, and API keys. These keys provide administrative capabilities,
14+
/// allowing you to automate organization management tasks.
15+
pub struct AdminAPIKeys<'c, C: Config> {
16+
client: &'c Client<C>,
17+
}
18+
19+
impl<'c, C: Config> AdminAPIKeys<'c, C> {
20+
pub fn new(client: &'c Client<C>) -> Self {
21+
Self { client }
22+
}
23+
24+
/// List all organization and project API keys.
25+
#[crate::byot(T0 = serde::Serialize, R = serde::de::DeserializeOwned)]
26+
pub async fn list<Q>(&self, query: &Q) -> Result<ApiKeyList, OpenAIError>
27+
where
28+
Q: Serialize + ?Sized,
29+
{
30+
self.client
31+
.get_with_query("/organization/admin_api_keys", &query)
32+
.await
33+
}
34+
35+
/// Create an organization admin API key.
36+
pub async fn create(
37+
&self,
38+
request: CreateAdminApiKeyRequest,
39+
) -> Result<AdminApiKey, OpenAIError> {
40+
self.client
41+
.post("/organization/admin_api_keys", request)
42+
.await
43+
}
44+
45+
/// Retrieve a single organization API key.
46+
#[crate::byot(T0 = std::fmt::Display, R = serde::de::DeserializeOwned)]
47+
pub async fn retrieve(&self, key_id: &str) -> Result<AdminApiKey, OpenAIError> {
48+
self.client
49+
.get(format!("/organization/admin_api_keys/{key_id}").as_str())
50+
.await
51+
}
52+
53+
/// Delete an organization admin API key.
54+
#[crate::byot(T0 = std::fmt::Display, R = serde::de::DeserializeOwned)]
55+
pub async fn delete(&self, key_id: &str) -> Result<AdminApiKeyDeleteResponse, OpenAIError> {
56+
self.client
57+
.delete(format!("/organization/admin_api_keys/{key_id}").as_str())
58+
.await
59+
}
60+
}

async-openai/src/assistants.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
Client,
55
config::Config,
66
error::OpenAIError,
7-
types::{
7+
types::assistants::{
88
AssistantObject, CreateAssistantRequest, DeleteAssistantResponse, ListAssistantsResponse,
99
ModifyAssistantRequest,
1010
},

async-openai/src/audit_logs.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use serde::Serialize;
22

3-
use crate::{Client, config::Config, error::OpenAIError, types::ListAuditLogsResponse};
3+
use crate::{
4+
Client, config::Config, error::OpenAIError, types::admin::audit_logs::ListAuditLogsResponse,
5+
};
46

57
/// Logs of user actions and configuration changes within this organization.
68
/// To log events, you must activate logging in the [Organization Settings](https://platform.openai.com/settings/organization/general).

0 commit comments

Comments
 (0)