Skip to content

Commit

Permalink
DevDay API Update (#131)
Browse files Browse the repository at this point in the history
* make speech example work

* response save api for speech

* create_all dir

* update image types and examples

* cleanup

* chat completion request response

* completions types

* all types of chat completion message types

* fix function call examples

* bunch of from trait impls

* updates to file and fine tune job types

* Assistants API group

* thread and message types

* run object

* messages and threads

* thread runs

* more thread and runs

* error fix

* run steps

* assitant files

* message files

* update docs

* updates

* docs

* cleanup

* updated spec

* latest spec

* fixes

* assistants example

* fix

* updated example

* cargo fix

* cargo fmt
  • Loading branch information
64bit committed Nov 7, 2023
1 parent e085d30 commit c0baa8b
Show file tree
Hide file tree
Showing 41 changed files with 9,016 additions and 2,053 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ Cargo.lock

# directory used to store images
data

*.mp3
5 changes: 2 additions & 3 deletions async-openai/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@

## Overview

`async-openai` is an unofficial Rust library for OpenAI REST API.
`async-openai` is an unofficial Rust library for OpenAI.

- It's based on [OpenAI OpenAPI spec](https://github.com/openai/openai-openapi)
- Current features:
- [x] Assistants (Beta)
- [x] Audio (Whisper/TTS)
- [x] Chat
- [x] Completions (Legacy)
Expand Down Expand Up @@ -108,8 +109,6 @@ Thank you for your time to contribute and improve the project, I'd be happy to h

A good starting point would be existing [open issues](https://github.com/64bit/async-openai/issues).

## Complimentary Crates
- [openai-func-enums](https://github.com/frankfralick/openai-func-enums) provides procedural macros that make it easier to use this library with OpenAI API's function calling feature. It also provides derive macros you can add to existing [clap](https://github.com/clap-rs/clap) application subcommands for natural language use of command line tools.

## License

Expand Down
66 changes: 66 additions & 0 deletions async-openai/src/assistant_files.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use serde::Serialize;

use crate::{
config::Config,
error::OpenAIError,
types::{
AssistantFileObject, CreateAssistantFileRequest, DeleteAssistantFileResponse,
ListAssistantFilesResponse,
},
Client,
};

/// Files attached to an assistant.
pub struct AssistantFiles<'c, C: Config> {
client: &'c Client<C>,
pub assistant_id: String,
}

impl<'c, C: Config> AssistantFiles<'c, C> {
pub fn new(client: &'c Client<C>, assistant_id: &str) -> Self {
Self {
client,
assistant_id: assistant_id.into(),
}
}

/// Create an assistant file by attaching a [File](https://platform.openai.com/docs/api-reference/files) to an [assistant](https://platform.openai.com/docs/api-reference/assistants).
pub async fn create(
&self,
request: CreateAssistantFileRequest,
) -> Result<AssistantFileObject, OpenAIError> {
self.client
.post(&format!("/assistants/{}/files", self.assistant_id), request)
.await
}

/// Retrieves an AssistantFile.
pub async fn retrieve(&self, file_id: &str) -> Result<AssistantFileObject, OpenAIError> {
self.client
.get(&format!(
"/assistants/{}/files/{file_id}",
self.assistant_id
))
.await
}

/// Delete an assistant file.
pub async fn delete(&self, file_id: &str) -> Result<DeleteAssistantFileResponse, OpenAIError> {
self.client
.delete(&format!(
"/assistants/{}/files/{file_id}",
self.assistant_id
))
.await
}

/// Returns a list of assistant files.
pub async fn list<Q>(&self, query: &Q) -> Result<ListAssistantFilesResponse, OpenAIError>
where
Q: Serialize + ?Sized,
{
self.client
.get_with_query(&format!("/assistants/{}/files", self.assistant_id), query)
.await
}
}
70 changes: 70 additions & 0 deletions async-openai/src/assistants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use serde::Serialize;

use crate::{
config::Config,
error::OpenAIError,
types::{
AssistantObject, CreateAssistantRequest, DeleteAssistantResponse, ListAssistantsResponse,
ModifyAssistantRequest,
},
AssistantFiles, Client,
};

/// Build assistants that can call models and use tools to perform tasks.
///
/// [Get started with the Assistants API](https://platform.openai.com/docs/assistants)
pub struct Assistants<'c, C: Config> {
client: &'c Client<C>,
}

impl<'c, C: Config> Assistants<'c, C> {
pub fn new(client: &'c Client<C>) -> Self {
Self { client }
}

/// Assistant [AssistantFiles] API group
pub fn files(&self, assistant_id: &str) -> AssistantFiles<C> {
AssistantFiles::new(self.client, assistant_id)
}

/// Create an assistant with a model and instructions.
pub async fn create(
&self,
request: CreateAssistantRequest,
) -> Result<AssistantObject, OpenAIError> {
self.client.post("/assistants", request).await
}

/// Retrieves an assistant.
pub async fn retrieve(&self, assistant_id: &str) -> Result<AssistantObject, OpenAIError> {
self.client
.get(&format!("/assistants/{assistant_id}"))
.await
}

/// Modifies an assistant.
pub async fn update(
&self,
assistant_id: &str,
request: ModifyAssistantRequest,
) -> Result<AssistantObject, OpenAIError> {
self.client
.post(&format!("/assistants/{assistant_id}"), request)
.await
}

/// Delete an assistant.
pub async fn delete(&self, assistant_id: &str) -> Result<DeleteAssistantResponse, OpenAIError> {
self.client
.delete(&format!("/assistants/{assistant_id}"))
.await
}

/// Returns a list of assistants.
pub async fn list<Q>(&self, query: &Q) -> Result<ListAssistantsResponse, OpenAIError>
where
Q: Serialize + ?Sized,
{
self.client.get_with_query("/assistants", query).await
}
}
16 changes: 10 additions & 6 deletions async-openai/src/audio.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
use bytes::Bytes;

use crate::{
config::Config,
error::OpenAIError,
types::{
CreateSpeechRequest, CreateTranscriptionRequest, CreateTranscriptionResponse,
CreateTranslationRequest, CreateTranslationResponse,
CreateSpeechRequest, CreateSpeechResponse, CreateTranscriptionRequest,
CreateTranscriptionResponse, CreateTranslationRequest, CreateTranslationResponse,
},
Client,
};
Expand Down Expand Up @@ -39,7 +37,13 @@ impl<'c, C: Config> Audio<'c, C> {
self.client.post_form("/audio/translations", request).await
}

pub async fn speech(&self, request: CreateSpeechRequest) -> Result<Bytes, OpenAIError> {
self.client.post_raw("/audio/speech", request).await
/// Generates audio from the input text.
pub async fn speech(
&self,
request: CreateSpeechRequest,
) -> Result<CreateSpeechResponse, OpenAIError> {
let bytes = self.client.post_raw("/audio/speech", request).await?;

Ok(CreateSpeechResponse { bytes })
}
}
12 changes: 11 additions & 1 deletion async-openai/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{
file::Files,
image::Images,
moderation::Moderations,
Audio, Chat, Completions, Embeddings, FineTunes, FineTuning, Models,
Assistants, Audio, Chat, Completions, Embeddings, FineTunes, FineTuning, Models, Threads,
};

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -118,6 +118,16 @@ impl<C: Config> Client<C> {
Audio::new(self)
}

/// To call [Assistants] group related APIs using this client.
pub fn assistants(&self) -> Assistants<C> {
Assistants::new(self)
}

/// To call [Threads] group related APIs using this client.
pub fn threads(&self) -> Threads<C> {
Threads::new(self)
}

pub fn config(&self) -> &C {
&self.config
}
Expand Down
26 changes: 21 additions & 5 deletions async-openai/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ pub const OPENAI_API_BASE: &str = "https://api.openai.com/v1";
/// Name for organization header
pub const OPENAI_ORGANIZATION_HEADER: &str = "OpenAI-Organization";

/// Calls to the Assistants API require that you pass a Beta header
pub const OPENAI_BETA_HEADER: &str = "OpenAI-Beta";

/// [crate::Client] relies on this for every API call on OpenAI
/// or Azure OpenAI service
pub trait Config: Clone {
Expand All @@ -33,7 +36,9 @@ impl Default for OpenAIConfig {
fn default() -> Self {
Self {
api_base: OPENAI_API_BASE.to_string(),
api_key: std::env::var("OPENAI_API_KEY").unwrap_or_else(|_| "".to_string()).into(),
api_key: std::env::var("OPENAI_API_KEY")
.unwrap_or_else(|_| "".to_string())
.into(),
org_id: Default::default(),
}
}
Expand Down Expand Up @@ -80,9 +85,16 @@ impl Config for OpenAIConfig {

headers.insert(
AUTHORIZATION,
format!("Bearer {}", self.api_key.expose_secret()).as_str().parse().unwrap(),
format!("Bearer {}", self.api_key.expose_secret())
.as_str()
.parse()
.unwrap(),
);

// hack for Assistants APIs
// Calls to the Assistants API require that you pass a Beta header
headers.insert(OPENAI_BETA_HEADER, "assistants=v1".parse().unwrap());

headers
}

Expand Down Expand Up @@ -113,12 +125,13 @@ pub struct AzureConfig {
api_key: Secret<String>,
}


impl Default for AzureConfig {
fn default() -> Self {
Self {
api_base: Default::default(),
api_key: std::env::var("OPENAI_API_KEY").unwrap_or_else(|_| "".to_string()).into(),
api_key: std::env::var("OPENAI_API_KEY")
.unwrap_or_else(|_| "".to_string())
.into(),
deployment_id: Default::default(),
api_version: Default::default(),
}
Expand Down Expand Up @@ -157,7 +170,10 @@ impl Config for AzureConfig {
fn headers(&self) -> HeaderMap {
let mut headers = HeaderMap::new();

headers.insert("api-key", self.api_key.expose_secret().as_str().parse().unwrap());
headers.insert(
"api-key",
self.api_key.expose_secret().as_str().parse().unwrap(),
);

headers
}
Expand Down
4 changes: 2 additions & 2 deletions async-openai/src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
Client,
};

/// Files are used to upload documents that can be used with features like [Fine-tuning](https://platform.openai.com/docs/api-reference/fine-tuning).
/// Files are used to upload documents that can be used with features like Assistants and Fine-tuning.
pub struct Files<'c, C: Config> {
client: &'c Client<C>,
}
Expand Down Expand Up @@ -71,7 +71,7 @@ mod tests {

assert_eq!(openai_file.bytes, 135);
assert_eq!(openai_file.filename, "test.jsonl");
assert_eq!(openai_file.purpose, "fine-tune");
//assert_eq!(openai_file.purpose, "fine-tune");

//assert_eq!(openai_file.status, Some("processed".to_owned())); // uploaded or processed

Expand Down
16 changes: 15 additions & 1 deletion async-openai/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Async Rust library for OpenAI REST API based on OpenAPI spec.
//! Rust library for OpenAI
//!
//! ## Creating client
//!
Expand Down Expand Up @@ -76,6 +76,8 @@
//! ## Examples
//! For full working examples for all supported features see [examples](https://github.com/64bit/async-openai/tree/main/examples) directory in the repository.
//!
mod assistant_files;
mod assistants;
mod audio;
mod chat;
mod client;
Expand All @@ -91,11 +93,18 @@ mod file;
mod fine_tune;
mod fine_tuning;
mod image;
mod message_files;
mod messages;
mod model;
mod moderation;
mod runs;
mod steps;
mod threads;
pub mod types;
mod util;

pub use assistant_files::AssistantFiles;
pub use assistants::Assistants;
pub use audio::Audio;
pub use chat::Chat;
pub use client::Client;
Expand All @@ -106,5 +115,10 @@ pub use file::Files;
pub use fine_tune::FineTunes;
pub use fine_tuning::FineTuning;
pub use image::Images;
pub use message_files::MessageFiles;
pub use messages::Messages;
pub use model::Models;
pub use moderation::Moderations;
pub use runs::Runs;
pub use steps::Steps;
pub use threads::Threads;
Loading

0 comments on commit c0baa8b

Please sign in to comment.