diff --git a/async-openai/Cargo.toml b/async-openai/Cargo.toml index 0ed60800..67d8c9b5 100644 --- a/async-openai/Cargo.toml +++ b/async-openai/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "async-openai" -version = "0.18.2" +version = "0.20.0" authors = [ "Himanshu Neema" ] @@ -33,16 +33,16 @@ native-tls-vendored = ["reqwest/native-tls-vendored"] [dependencies] backoff = {version = "0.4.0", features = ["futures"], optional = true } -base64 = "0.21.0" +base64 = "0.22.0" futures = "0.3.26" rand = "0.8.5" -reqwest = { version = "0.11.14", features = ["json", "stream", "multipart"],default-features = false } -reqwest-eventsource = "0.5.0" +reqwest = { version = "0.12.0", features = ["json", "stream", "multipart"],default-features = false } +reqwest-eventsource = "0.6.0" serde = { version = "1.0.152", features = ["derive", "rc"] } serde_json = "1.0.93" thiserror = "1.0.38" tracing = "0.1.37" -derive_builder = "0.12.0" +derive_builder = "0.20.0" async-convert = "1.0.0" secrecy = { version = "0.8.0", features=["serde"] } tokio = { version = "1.25.0", features = ["fs", "macros"], optional = true } diff --git a/async-openai/README.md b/async-openai/README.md index 6913fe07..d0a68641 100644 --- a/async-openai/README.md +++ b/async-openai/README.md @@ -24,14 +24,12 @@ - It's based on [OpenAI OpenAPI spec](https://github.com/openai/openai-openapi) - Current features: - [x] Assistants (Beta) - - [x] Audio (Whisper/TTS) + - [x] Audio - [x] Chat - [x] Completions (Legacy) - - [x] Edits (Deprecated) - [x] Embeddings - [x] Files - [x] Fine-Tuning - - [x] Fine-Tunes (Deprecated) - [x] Images - [x] Microsoft Azure OpenAI Service - [x] Models @@ -125,7 +123,7 @@ All forms of contributions, such as new features requests, bug fixes, issues, do A good starting point would be to look at existing [open issues](https://github.com/64bit/async-openai/issues). To maintain quality of the project, a minimum of the following is a must for code contribution: -- **Documented**: Primary source of doc comments is description field from OpenAPI spec. +- **Names & Documentation**: All struct names, field names and doc comments are from OpenAPI spec. Nested objects in spec without names leaves room for making appropriate name. - **Tested**: Examples are primary means of testing and should continue to work. For new features supporting example is required. - **Scope**: Keep scope limited to APIs available in official documents such as [API Reference](https://platform.openai.com/docs/api-reference) or [OpenAPI spec](https://github.com/openai/openai-openapi/). Other LLMs or AI Providers offer OpenAI-compatible APIs, yet they may not always have full parity. In such cases, the OpenAI spec takes precedence. - **Consistency**: Keep code style consistent across all the "APIs" that library exposes; it creates a great developer experience. @@ -135,9 +133,6 @@ This project adheres to [Rust Code of Conduct](https://www.rust-lang.org/policie ## 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 tool 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. It also supports openai's [parallel tool calls](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) and allows you to choose between running multiple tool calls concurrently or own their own OS threads. -## 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 tool 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. It also supports openai's [parallel tool calls](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling) and allows you to choose between running multiple tool calls concurrently or own their own OS threads. - ## License diff --git a/async-openai/src/audio.rs b/async-openai/src/audio.rs index 08ea7ac0..66dda098 100644 --- a/async-openai/src/audio.rs +++ b/async-openai/src/audio.rs @@ -1,9 +1,12 @@ +use bytes::Bytes; + use crate::{ config::Config, error::OpenAIError, types::{ CreateSpeechRequest, CreateSpeechResponse, CreateTranscriptionRequest, - CreateTranscriptionResponse, CreateTranslationRequest, CreateTranslationResponse, + CreateTranscriptionResponseJson, CreateTranscriptionResponseVerboseJson, + CreateTranslationRequest, CreateTranslationResponse, }, Client, }; @@ -23,12 +26,32 @@ impl<'c, C: Config> Audio<'c, C> { pub async fn transcribe( &self, request: CreateTranscriptionRequest, - ) -> Result { + ) -> Result { + self.client + .post_form("/audio/transcriptions", request) + .await + } + + /// Transcribes audio into the input language. + pub async fn transcribe_verbose_json( + &self, + request: CreateTranscriptionRequest, + ) -> Result { self.client .post_form("/audio/transcriptions", request) .await } + /// Transcribes audio into the input language. + pub async fn transcribe_raw( + &self, + request: CreateTranscriptionRequest, + ) -> Result { + self.client + .post_form_raw("/audio/transcriptions", request) + .await + } + /// Translates audio into into English. pub async fn translate( &self, diff --git a/async-openai/src/client.rs b/async-openai/src/client.rs index 95350461..b198e9c0 100644 --- a/async-openai/src/client.rs +++ b/async-openai/src/client.rs @@ -14,10 +14,10 @@ use crate::{ config::{Config, OpenAIConfig}, error::{map_deserialization_error, OpenAIError, WrappedError}, moderation::Moderations, - edit::Edits, file::Files, image::Images, - Chat, Completions, Embeddings, Models, FineTunes, FineTuning, Assistants, Threads, Audio}; + Assistants, Audio, Chat, Completions, Embeddings, FineTuning, Models, Threads, +}; #[derive(Debug, Clone)] /// Client is a container for config, backoff and http_client @@ -42,6 +42,21 @@ impl Client { } impl Client { + /// Create client with a custom HTTP client, OpenAI config, and backoff. + pub fn build( + http_client: reqwest::Client, + config: C, + #[cfg(feature = "backoff")] + backoff: backoff::ExponentialBackoff, + ) -> Self { + Self { + http_client, + config, + #[cfg(feature = "backoff")] + backoff, + } + } + /// Create client with [OpenAIConfig] or [crate::config::AzureConfig] pub fn with_config(config: C) -> Self { Self { @@ -84,12 +99,6 @@ impl Client { Chat::new(self) } - /// To call [Edits] group related APIs using this client. - #[deprecated(since = "0.15.0", note = "By OpenAI")] - pub fn edits(&self) -> Edits { - Edits::new(self) - } - /// To call [Images] group related APIs using this client. pub fn images(&self) -> Images { Images::new(self) @@ -105,12 +114,6 @@ impl Client { Files::new(self) } - /// To call [FineTunes] group related APIs using this client. - #[deprecated(since = "0.15.0", note = "By OpenAI")] - pub fn fine_tunes(&self) -> FineTunes { - FineTunes::new(self) - } - /// To call [FineTuning] group related APIs using this client. pub fn fine_tuning(&self) -> FineTuning { FineTuning::new(self) @@ -230,6 +233,25 @@ impl Client { self.execute(request_maker).await } + /// POST a form at {path} and return the response body + pub(crate) async fn post_form_raw(&self, path: &str, form: F) -> Result + where + reqwest::multipart::Form: async_convert::TryFrom, + F: Clone, + { + let request_maker = || async { + Ok(self + .http_client + .post(self.config.url(path)) + .query(&self.config.query()) + .headers(self.config.headers()) + .multipart(async_convert::TryFrom::try_from(form.clone()).await?) + .build()?) + }; + + self.execute_raw(request_maker).await + } + /// POST a form at {path} and deserialize the response body pub(crate) async fn post_form(&self, path: &str, form: F) -> Result where diff --git a/async-openai/src/edit.rs b/async-openai/src/edit.rs deleted file mode 100644 index daca6b73..00000000 --- a/async-openai/src/edit.rs +++ /dev/null @@ -1,26 +0,0 @@ -use crate::{ - config::Config, - error::OpenAIError, - types::{CreateEditRequest, CreateEditResponse}, - Client, -}; - -/// Given a prompt and an instruction, the model will return -/// an edited version of the prompt. -pub struct Edits<'c, C: Config> { - client: &'c Client, -} - -impl<'c, C: Config> Edits<'c, C> { - pub fn new(client: &'c Client) -> Self { - Self { client } - } - - /// Creates a new edit for the provided input, instruction, and parameters - pub async fn create( - &self, - request: CreateEditRequest, - ) -> Result { - self.client.post("/edits", request).await - } -} diff --git a/async-openai/src/embedding.rs b/async-openai/src/embedding.rs index 227ae87d..70d027eb 100644 --- a/async-openai/src/embedding.rs +++ b/async-openai/src/embedding.rs @@ -1,7 +1,10 @@ use crate::{ config::Config, error::OpenAIError, - types::{CreateEmbeddingRequest, CreateEmbeddingResponse}, + types::{ + CreateBase64EmbeddingResponse, CreateEmbeddingRequest, CreateEmbeddingResponse, + EncodingFormat, + }, Client, }; @@ -23,14 +26,36 @@ impl<'c, C: Config> Embeddings<'c, C> { &self, request: CreateEmbeddingRequest, ) -> Result { + if matches!(request.encoding_format, Some(EncodingFormat::Base64)) { + return Err(OpenAIError::InvalidArgument( + "When encoding_format is base64, use Embeddings::create_base64".into(), + )); + } + self.client.post("/embeddings", request).await + } + + /// Creates an embedding vector representing the input text. + /// + /// The response will contain the embedding in base64 format. + pub async fn create_base64( + &self, + request: CreateEmbeddingRequest, + ) -> Result { + if !matches!(request.encoding_format, Some(EncodingFormat::Base64)) { + return Err(OpenAIError::InvalidArgument( + "When encoding_format is not base64, use Embeddings::create".into(), + )); + } + self.client.post("/embeddings", request).await } } #[cfg(test)] mod tests { + use crate::error::OpenAIError; + use crate::types::{CreateEmbeddingResponse, Embedding, EncodingFormat}; use crate::{types::CreateEmbeddingRequestArgs, Client}; - use crate::types::{CreateEmbeddingResponse, Embedding}; #[tokio::test] async fn test_embedding_string() { @@ -122,9 +147,61 @@ mod tests { assert!(response.is_ok()); - let CreateEmbeddingResponse { mut data, ..} = response.unwrap(); + let CreateEmbeddingResponse { mut data, .. } = response.unwrap(); assert_eq!(data.len(), 1); let Embedding { embedding, .. } = data.pop().unwrap(); assert_eq!(embedding.len(), dimensions as usize); } + + #[tokio::test] + async fn test_cannot_use_base64_encoding_with_normal_create_request() { + let client = Client::new(); + + const MODEL: &str = "text-embedding-ada-002"; + const INPUT: &str = "You shall not pass."; + + let b64_request = CreateEmbeddingRequestArgs::default() + .model(MODEL) + .input(INPUT) + .encoding_format(EncodingFormat::Base64) + .build() + .unwrap(); + let b64_response = client.embeddings().create(b64_request).await; + assert!(matches!(b64_response, Err(OpenAIError::InvalidArgument(_)))); + } + + #[tokio::test] + async fn test_embedding_create_base64() { + let client = Client::new(); + + const MODEL: &str = "text-embedding-ada-002"; + const INPUT: &str = "CoLoop will eat the other qual research tools..."; + + let b64_request = CreateEmbeddingRequestArgs::default() + .model(MODEL) + .input(INPUT) + .encoding_format(EncodingFormat::Base64) + .build() + .unwrap(); + let b64_response = client + .embeddings() + .create_base64(b64_request) + .await + .unwrap(); + let b64_embedding = b64_response.data.into_iter().next().unwrap().embedding; + let b64_embedding: Vec = b64_embedding.into(); + + let request = CreateEmbeddingRequestArgs::default() + .model(MODEL) + .input(INPUT) + .build() + .unwrap(); + let response = client.embeddings().create(request).await.unwrap(); + let embedding = response.data.into_iter().next().unwrap().embedding; + + assert_eq!(b64_embedding.len(), embedding.len()); + for (b64, normal) in b64_embedding.iter().zip(embedding.iter()) { + assert!((b64 - normal).abs() < 1e-6); + } + } } diff --git a/async-openai/src/file.rs b/async-openai/src/file.rs index 374ca8db..4f40bc83 100644 --- a/async-openai/src/file.rs +++ b/async-openai/src/file.rs @@ -55,6 +55,7 @@ impl<'c, C: Config> Files<'c, C> { } #[cfg(test)] +#[cfg(not(feature = "wasm"))] mod tests { use crate::{types::CreateFileRequestArgs, Client}; diff --git a/async-openai/src/fine_tune.rs b/async-openai/src/fine_tune.rs deleted file mode 100644 index 04ce042b..00000000 --- a/async-openai/src/fine_tune.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::{ - config::Config, - error::OpenAIError, - types::{ - CreateFineTuneRequest, FineTune, FineTuneEventsResponseStream, ListFineTuneEventsResponse, - ListFineTuneResponse, - }, - Client, -}; - -/// Manage fine-tuning jobs to tailor a model to your specific training data. -/// -/// Related guide: [Fine-tune models](https://platform.openai.com/docs/guides/fine-tuning) -pub struct FineTunes<'c, C: Config> { - client: &'c Client, -} - -impl<'c, C: Config> FineTunes<'c, C> { - pub fn new(client: &'c Client) -> Self { - Self { client } - } - - /// Creates a job that fine-tunes a specified model from a given dataset. - /// - /// Response includes details of the enqueued job including job status and the name of the fine-tuned models once complete. - /// - /// [Learn more about Fine-tuning](https://platform.openai.com/docs/guides/fine-tuning) - pub async fn create(&self, request: CreateFineTuneRequest) -> Result { - self.client.post("/fine-tunes", request).await - } - - /// List your organization's fine-tuning jobs - pub async fn list(&self) -> Result { - self.client.get("/fine-tunes").await - } - - /// Gets info about the fine-tune job. - /// - /// [Learn more about Fine-tuning](https://platform.openai.com/docs/guides/fine-tuning) - pub async fn retrieve(&self, fine_tune_id: &str) -> Result { - self.client - .get(format!("/fine-tunes/{fine_tune_id}").as_str()) - .await - } - - /// Immediately cancel a fine-tune job. - pub async fn cancel(&self, fine_tune_id: &str) -> Result { - self.client - .post(format!("/fine-tunes/{fine_tune_id}/cancel").as_str(), ()) - .await - } - - /// Get fine-grained status updates for a fine-tune job. - pub async fn list_events( - &self, - fine_tune_id: &str, - ) -> Result { - self.client - .get(format!("/fine-tunes/{fine_tune_id}/events").as_str()) - .await - } - - /// Get fine-grained status updates for a fine-tune job. - /// - /// Stream fine tuning events. [FineTuneEventsResponseStream] is a parsed SSE - /// stream until a \[DONE\] is received from server. - pub async fn list_events_stream( - &self, - fine_tune_id: &str, - ) -> Result { - Ok(self - .client - .get_stream( - format!("/fine-tunes/{fine_tune_id}/events").as_str(), - &[("stream", true)], - ) - .await) - } -} diff --git a/async-openai/src/lib.rs b/async-openai/src/lib.rs index 27a0fdda..48466b1e 100644 --- a/async-openai/src/lib.rs +++ b/async-openai/src/lib.rs @@ -49,9 +49,7 @@ //! //! Enabling `wasm` will disable: //! * retries -//! * Default impls and derives for file-related structs. For example, [`crate::types::CreateImageEditRequest`]. -//! * Because builder pattern depends on `Default` trait, builders for file-related structs are also disabled. You need to explicitly construct structs that are related to files. -//! * File-related operations are disabled. For example, saving an audio file. You need to manage file operations yourself via web APIs. +//! * file saving: You need to manage file operations yourself via web APIs. //! //! ## Making requests //! @@ -66,7 +64,7 @@ //! // Create request using builder pattern //! // Every request struct has companion builder struct with same name + Args suffix //! let request = CreateCompletionRequestArgs::default() -//! .model("text-davinci-003") +//! .model("gpt-3.5-turbo-instruct") //! .prompt("Tell me the recipe of alfredo pasta") //! .max_tokens(40_u16) //! .build() @@ -108,13 +106,9 @@ mod completion; pub mod config; #[cfg(not(feature = "wasm"))] mod download; -#[deprecated(since = "0.15.0", note = "By OpenAI")] -mod edit; mod embedding; pub mod error; mod file; -#[deprecated(since = "0.15.0", note = "By OpenAI")] -mod fine_tune; mod fine_tuning; mod image; mod message_files; @@ -133,10 +127,8 @@ pub use audio::Audio; pub use chat::Chat; pub use client::Client; pub use completion::Completions; -pub use edit::Edits; pub use embedding::Embeddings; pub use file::Files; -pub use fine_tune::FineTunes; pub use fine_tuning::FineTuning; pub use image::Images; pub use message_files::MessageFiles; diff --git a/async-openai/src/types/assistant_impls.rs b/async-openai/src/types/assistant_impls.rs index bfc1860a..377caf91 100644 --- a/async-openai/src/types/assistant_impls.rs +++ b/async-openai/src/types/assistant_impls.rs @@ -1,5 +1,3 @@ -use crate::types::ChatCompletionFunctions; - use super::{ AssistantTools, AssistantToolsCode, AssistantToolsFunction, AssistantToolsRetrieval, FunctionObject, diff --git a/async-openai/src/types/audio.rs b/async-openai/src/types/audio.rs index b9820f95..d8444207 100644 --- a/async-openai/src/types/audio.rs +++ b/async-openai/src/types/audio.rs @@ -5,8 +5,7 @@ use serde::{Deserialize, Serialize}; use super::InputSource; use crate::error::OpenAIError; -#[cfg_attr(not(feature = "wasm"), derive(Default))] -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Default)] pub struct AudioInput { pub source: InputSource, } @@ -23,13 +22,15 @@ pub enum AudioResponseFormat { } #[derive(Debug, Serialize, Default, Clone, Copy, PartialEq)] -#[serde(rename_all = "snake_case")] +#[serde(rename_all = "lowercase")] pub enum SpeechResponseFormat { #[default] Mp3, Opus, Aac, Flac, + Pcm, + Wav, } #[derive(Debug, Default, Serialize, Clone, PartialEq)] @@ -58,13 +59,20 @@ pub enum SpeechModel { Other(String), } -#[cfg_attr(not(feature = "wasm"), derive(Default, Builder))] -#[derive(Clone, Debug, PartialEq)] -#[cfg_attr(not(feature = "wasm"), builder(name = "CreateTranscriptionRequestArgs"))] -#[cfg_attr(not(feature = "wasm"), builder(pattern = "mutable"))] -#[cfg_attr(not(feature = "wasm"), builder(setter(into, strip_option), default))] -#[cfg_attr(not(feature = "wasm"), builder(derive(Debug)))] -#[cfg_attr(not(feature = "wasm"), builder(build_fn(error = "OpenAIError")))] +#[derive(Debug, Default, Serialize, Clone, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum TimestampGranularity { + Word, + #[default] + Segment, +} + +#[derive(Clone, Debug, PartialEq, Default, Builder)] +#[builder(name = "CreateTranscriptionRequestArgs")] +#[builder(pattern = "mutable")] +#[builder(setter(into, strip_option), default)] +#[builder(derive(Debug))] +#[builder(build_fn(error = "OpenAIError"))] pub struct CreateTranscriptionRequest { /// The audio file to transcribe, in one of these formats: mp3, mp4, mpeg, mpga, m4a, wav, or webm. pub file: AudioInput, @@ -83,11 +91,86 @@ pub struct CreateTranscriptionRequest { /// The language of the input audio. Supplying the input language in [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) format will improve accuracy and latency. pub language: Option, + /// The timestamp granularities to populate for this transcription. Any of these options: `word`, or `segment`. Note: There is no additional latency for segment timestamps, but generating word timestamps incurs additional latency. + pub timestamp_granularities: Option>, +} + +/// Represents a transcription response returned by model, based on the provided +/// input. +#[derive(Debug, Deserialize, Clone, Serialize)] +pub struct CreateTranscriptionResponseJson { + /// The transcribed text. + pub text: String, +} + +/// Represents a verbose json transcription response returned by model, based on +/// the provided input. +#[derive(Debug, Deserialize, Clone, Serialize)] +pub struct CreateTranscriptionResponseVerboseJson { + /// The language of the input audio. + pub language: String, + + /// The duration of the input audio. + pub duration: f32, + + /// The transcribed text. + pub text: String, + + /// Extracted words and their corresponding timestamps. + #[serde(skip_serializing_if = "Option::is_none")] + pub words: Option>, + + /// Segments of the transcribed text and their corresponding details. + #[serde(skip_serializing_if = "Option::is_none")] + pub segments: Option>, } #[derive(Debug, Deserialize, Clone, Serialize)] -pub struct CreateTranscriptionResponse { +pub struct TranscriptionWord { + /// The text content of the word. + pub word: String, + + /// Start time of the word in seconds. + pub start: f32, + + /// End time of the word in seconds. + pub end: f32, +} + +#[derive(Debug, Deserialize, Clone, Serialize)] +pub struct TranscriptionSegment { + /// Unique identifier of the segment. + pub id: i32, + + // Seek offset of the segment. + pub seek: i32, + + /// Start time of the segment in seconds. + pub start: f32, + + /// End time of the segment in seconds. + pub end: f32, + + /// Text content of the segment. pub text: String, + + /// Array of token IDs for the text content. + pub tokens: Vec, + + /// Temperature parameter used for generating the segment. + pub temperature: f32, + + /// Average logprob of the segment. If the value is lower than -1, consider + /// the logprobs failed. + pub avg_logprob: f32, + + /// Compression ratio of the segment. If the value is greater than 2.4, + /// consider the compression failed. + pub compression_ratio: f32, + + /// Probability of no speech in the segment. If the value is higher than 1.0 + /// and the `avg_logprob` is below -1, consider this segment silent. + pub no_speech_prob: f32, } #[derive(Clone, Default, Debug, Builder, PartialEq, Serialize)] @@ -106,7 +189,10 @@ pub struct CreateSpeechRequest { /// The voice to use when generating the audio. Supported voices are `alloy`, `echo`, `fable`, `onyx`, `nova`, and `shimmer`. Previews of the voices are available in the [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech/voice-options). pub voice: Voice, - /// The format to audio in. Supported formats are mp3, opus, aac, and flac. + /// The format to return audio in. + /// Supported formats are `mp3`, `opus`, `aac`, `flac`, `pcm`, and `wav`. + /// + /// The `pcm` audio format, similar to `wav` but without a header, utilizes a 24kHz sample rate, mono channel, and 16-bit depth in signed little-endian format. #[serde(skip_serializing_if = "Option::is_none")] pub response_format: Option, @@ -115,13 +201,13 @@ pub struct CreateSpeechRequest { pub speed: Option, // default: 1.0 } -#[cfg_attr(not(feature = "wasm"), derive(Default, Builder))] -#[derive(Clone, Debug, PartialEq)] -#[cfg_attr(not(feature = "wasm"), builder(name = "CreateTranslationRequestArgs"))] -#[cfg_attr(not(feature = "wasm"), builder(pattern = "mutable"))] -#[cfg_attr(not(feature = "wasm"), builder(setter(into, strip_option), default))] -#[cfg_attr(not(feature = "wasm"), builder(derive(Debug)))] -#[cfg_attr(not(feature = "wasm"), builder(build_fn(error = "OpenAIError")))] + +#[derive(Clone, Debug, PartialEq, Default, Builder)] +#[builder(name = "CreateTranslationRequestArgs")] +#[builder(pattern = "mutable")] +#[builder(setter(into, strip_option), default)] +#[builder(derive(Debug))] +#[builder(build_fn(error = "OpenAIError"))] pub struct CreateTranslationRequest { /// The audio file to transcribe, in one of these formats: mp3, mp4, mpeg, mpga, m4a, wav, or webm. pub file: AudioInput, diff --git a/async-openai/src/types/chat.rs b/async-openai/src/types/chat.rs index 7326499c..634ebd6b 100644 --- a/async-openai/src/types/chat.rs +++ b/async-openai/src/types/chat.rs @@ -447,7 +447,7 @@ pub struct CreateChatCompletionRequest { #[serde(skip_serializing_if = "Option::is_none")] pub presence_penalty: Option, // min: -2.0, max: 2.0, default 0 - /// An object specifying the format that the model must output. Compatible with `gpt-4-1106-preview` and `gpt-3.5-turbo-1106`. + /// An object specifying the format that the model must output. Compatible with [GPT-4 Turbo](https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo) and all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. /// /// Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the message the model generates is valid JSON. /// diff --git a/async-openai/src/types/common.rs b/async-openai/src/types/common.rs index 9ca5aba7..6c317b75 100644 --- a/async-openai/src/types/common.rs +++ b/async-openai/src/types/common.rs @@ -1,3 +1,4 @@ +#[cfg(not(feature = "wasm"))] use std::path::PathBuf; use bytes::Bytes; diff --git a/async-openai/src/types/embedding.rs b/async-openai/src/types/embedding.rs index 50130f0b..5f2ad73d 100644 --- a/async-openai/src/types/embedding.rs +++ b/async-openai/src/types/embedding.rs @@ -1,3 +1,4 @@ +use base64::engine::{general_purpose, Engine}; use derive_builder::Builder; use serde::{Deserialize, Serialize}; @@ -47,9 +48,9 @@ pub struct CreateEmbeddingRequest { #[serde(skip_serializing_if = "Option::is_none")] pub user: Option, - /// The number of dimensions the resulting output embeddings should have. Only supported in text-embedding-3 and later models. + /// The number of dimensions the resulting output embeddings should have. Only supported in `text-embedding-3` and later models. #[serde(skip_serializing_if = "Option::is_none")] - pub dimensions: Option + pub dimensions: Option, } /// Represents an embedding vector returned by embedding endpoint. @@ -64,6 +65,32 @@ pub struct Embedding { pub embedding: Vec, } +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +pub struct Base64EmbeddingVector(pub String); + +impl From for Vec { + fn from(value: Base64EmbeddingVector) -> Self { + let bytes = general_purpose::STANDARD + .decode(value.0) + .expect("openai base64 encoding to be valid"); + let chunks = bytes.chunks_exact(4); + chunks + .map(|chunk| f32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]])) + .collect() + } +} + +/// Represents an base64-encoded embedding vector returned by embedding endpoint. +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +pub struct Base64Embedding { + /// The index of the embedding in the list of embeddings. + pub index: u32, + /// The object type, which is always "embedding". + pub object: String, + /// The embedding vector, encoded in base64. + pub embedding: Base64EmbeddingVector, +} + #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] pub struct EmbeddingUsage { /// The number of tokens used by the prompt. @@ -82,3 +109,14 @@ pub struct CreateEmbeddingResponse { /// The usage information for the request. pub usage: EmbeddingUsage, } + +#[derive(Debug, Deserialize, Clone, PartialEq, Serialize)] +pub struct CreateBase64EmbeddingResponse { + pub object: String, + /// The name of the model used to generate the embedding. + pub model: String, + /// The list of embeddings generated by the model. + pub data: Vec, + /// The usage information for the request. + pub usage: EmbeddingUsage, +} diff --git a/async-openai/src/types/file.rs b/async-openai/src/types/file.rs index cfa60d02..b76d7453 100644 --- a/async-openai/src/types/file.rs +++ b/async-openai/src/types/file.rs @@ -1,23 +1,22 @@ use derive_builder::Builder; + use serde::{Deserialize, Serialize}; use crate::error::OpenAIError; use super::InputSource; -#[cfg_attr(not(feature = "wasm"), derive(Default))] -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Default)] pub struct FileInput { pub source: InputSource, } -#[cfg_attr(not(feature = "wasm"), derive(Default, Builder))] -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr(not(feature = "wasm"), builder(name = "CreateFileRequestArgs"))] -#[cfg_attr(not(feature = "wasm"), builder(pattern = "mutable"))] -#[cfg_attr(not(feature = "wasm"), builder(setter(into, strip_option), default))] -#[cfg_attr(not(feature = "wasm"), builder(derive(Debug)))] -#[cfg_attr(not(feature = "wasm"), builder(build_fn(error = "OpenAIError")))] +#[derive(Debug, Clone, PartialEq, Default, Builder)] +#[builder(name = "CreateFileRequestArgs")] +#[builder(pattern = "mutable")] +#[builder(setter(into, strip_option), default)] +#[builder(derive(Debug))] +#[builder(build_fn(error = "OpenAIError"))] pub struct CreateFileRequest { /// The file object to be uploaded. /// diff --git a/async-openai/src/types/image.rs b/async-openai/src/types/image.rs index 8da84fb2..277eb6a3 100644 --- a/async-openai/src/types/image.rs +++ b/async-openai/src/types/image.rs @@ -133,19 +133,17 @@ pub struct ImagesResponse { pub data: Vec>, } -#[cfg_attr(not(feature = "wasm"), derive(Default))] -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Default)] pub struct ImageInput { pub source: InputSource, } -#[cfg_attr(not(feature = "wasm"), derive(Default, Builder))] -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr(not(feature = "wasm"), builder(name = "CreateImageEditRequestArgs"))] -#[cfg_attr(not(feature = "wasm"), builder(pattern = "mutable"))] -#[cfg_attr(not(feature = "wasm"), builder(setter(into, strip_option), default))] -#[cfg_attr(not(feature = "wasm"), builder(derive(Debug)))] -#[cfg_attr(not(feature = "wasm"), builder(build_fn(error = "OpenAIError")))] +#[derive(Debug, Clone, PartialEq, Default, Builder)] +#[builder(name = "CreateImageEditRequestArgs")] +#[builder(pattern = "mutable")] +#[builder(setter(into, strip_option), default)] +#[builder(derive(Debug))] +#[builder(build_fn(error = "OpenAIError"))] pub struct CreateImageEditRequest { /// The image to edit. Must be a valid PNG file, less than 4MB, and square. If mask is not provided, image must have transparency, which will be used as the mask. pub image: ImageInput, @@ -172,13 +170,13 @@ pub struct CreateImageEditRequest { pub user: Option, } -#[cfg_attr(not(feature = "wasm"), derive(Default, Builder))] -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr(not(feature = "wasm"), builder(name = "CreateImageVariationRequestArgs"))] -#[cfg_attr(not(feature = "wasm"), builder(pattern = "mutable"))] -#[cfg_attr(not(feature = "wasm"), builder(setter(into, strip_option), default))] -#[cfg_attr(not(feature = "wasm"), builder(derive(Debug)))] -#[cfg_attr(not(feature = "wasm"), builder(build_fn(error = "OpenAIError")))] + +#[derive(Debug, Clone, PartialEq, Default, Builder)] +#[builder(name = "CreateImageVariationRequestArgs")] +#[builder(pattern = "mutable")] +#[builder(setter(into, strip_option), default)] +#[builder(derive(Debug))] +#[builder(build_fn(error = "OpenAIError"))] pub struct CreateImageVariationRequest { /// The image to use as the basis for the variation(s). Must be a valid PNG file, less than 4MB, and square. pub image: ImageInput, diff --git a/async-openai/src/types/impls.rs b/async-openai/src/types/impls.rs index 071e2e20..22695922 100644 --- a/async-openai/src/types/impls.rs +++ b/async-openai/src/types/impls.rs @@ -1,9 +1,18 @@ use std::fmt::Display; use bytes::Bytes; -use crate::error::OpenAIError; -use crate::types::InputSource; -use crate::util::create_file_part; +use crate::{ + error::OpenAIError, + types::InputSource, + util::create_file_part, +}; + +#[cfg(not(feature = "wasm"))] +use super::{ + ImagesResponse, + CreateSpeechResponse, + Image, +}; use super::{ ChatCompletionFunctionCall, @@ -16,12 +25,13 @@ use super::{ ChatCompletionRequestMessageContentPartText, ChatCompletionRequestSystemMessage, ChatCompletionRequestToolMessage, ChatCompletionRequestUserMessage, ChatCompletionRequestUserMessageContent, ChatCompletionToolChoiceOption, - FunctionName, DallE2ImageSize, ImageModel, ImageUrl, ResponseFormat, ImagesResponse, + FunctionName, DallE2ImageSize, ImageModel, AudioInput, AudioResponseFormat, CreateFileRequest, - CreateImageEditRequest, CreateImageVariationRequest, CreateSpeechResponse, + CreateImageEditRequest, CreateImageVariationRequest, CreateTranscriptionRequest, CreateTranslationRequest, - Image, FileInput, ImageInput, ImageSize + FileInput, ImageInput, ImageSize, ImageUrl, + ResponseFormat, TimestampGranularity, }; #[cfg(not(feature = "wasm"))] @@ -115,17 +125,19 @@ impl_default!(Prompt); impl_default!(ModerationInput); impl_default!(EmbeddingInput); -#[cfg(not(feature = "wasm"))] impl Default for InputSource { fn default() -> Self { - InputSource::Path { - path: PathBuf::new(), + const EMPTY_STR: String = String::new(); + const EMPTY_VEC: Vec = Vec::new(); + InputSource::VecU8 { + filename: EMPTY_STR, + vec: EMPTY_VEC, } } } /// for `impl_input!(Struct)` where -/// ``` +/// ```text /// Struct { /// source: InputSource /// } @@ -237,6 +249,19 @@ impl Display for AudioResponseFormat { } } +impl Display for TimestampGranularity { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match self { + TimestampGranularity::Word => "word", + TimestampGranularity::Segment => "segment", + } + ) + } +} + impl Display for Role { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( @@ -562,7 +587,7 @@ impl From for ChatCompletionRequestUserMessageContent { } impl From> - for ChatCompletionRequestUserMessageContent +for ChatCompletionRequestUserMessageContent { fn from(value: Vec) -> Self { ChatCompletionRequestUserMessageContent::Array(value) @@ -576,7 +601,7 @@ impl From for ChatCompletionRequest } impl From - for ChatCompletionRequestMessageContentPart +for ChatCompletionRequestMessageContentPart { fn from(value: ChatCompletionRequestMessageContentPartImage) -> Self { ChatCompletionRequestMessageContentPart::Image(value) @@ -649,6 +674,17 @@ impl async_convert::TryFrom for reqwest::multipart:: if let Some(temperature) = request.temperature { form = form.text("temperature", temperature.to_string()) } + + if let Some(language) = request.language { + form = form.text("language", language); + } + + if let Some(timestamp_granularities) = request.timestamp_granularities { + for tg in timestamp_granularities { + form = form.text("timestamp_granularities[]", tg.to_string()); + } + } + Ok(form) } } diff --git a/async-openai/src/types/mod.rs b/async-openai/src/types/mod.rs index f7bdb05b..5e030f4c 100644 --- a/async-openai/src/types/mod.rs +++ b/async-openai/src/types/mod.rs @@ -7,10 +7,8 @@ mod audio; mod chat; mod common; mod completion; -mod edit; mod embedding; mod file; -mod fine_tune; mod fine_tuning; mod image; mod message; @@ -27,10 +25,8 @@ pub use audio::*; pub use chat::*; pub use common::*; pub use completion::*; -pub use edit::*; pub use embedding::*; pub use file::*; -pub use fine_tune::*; pub use fine_tuning::*; pub use image::*; pub use message::*; diff --git a/async-openai/src/types/run.rs b/async-openai/src/types/run.rs index d0f07f4a..114deb7e 100644 --- a/async-openai/src/types/run.rs +++ b/async-openai/src/types/run.rs @@ -53,6 +53,9 @@ pub struct RunObject { /// The list of [File](https://platform.openai.com/docs/api-reference/files) IDs the [assistant](/docs/api-reference/assistants) used for this run. pub file_ids: Vec, + /// Usage statistics related to the run. This value will be `null` if the run is not in a terminal state (i.e. `in_progress`, `queued`, etc.). + pub usage: Option, + pub metadata: Option>, } @@ -107,6 +110,16 @@ pub enum LastErrorCode { RateLimitExceeded, } +#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)] +pub struct RunCompletionUsage { + /// Number of completion tokens used over the course of the run. + pub completion_tokens: u32, + /// Number of prompt tokens used over the course of the run. + pub prompt_tokens: u32, + /// Total number of tokens used (prompt + completion). + pub total_tokens: u32, +} + #[derive(Clone, Serialize, Default, Debug, Deserialize, Builder, PartialEq)] #[builder(name = "CreateRunRequestArgs")] #[builder(pattern = "mutable")] diff --git a/async-openai/src/types/step.rs b/async-openai/src/types/step.rs index 13ef4930..c1fe48f6 100644 --- a/async-openai/src/types/step.rs +++ b/async-openai/src/types/step.rs @@ -55,6 +55,19 @@ pub struct RunStepObject { pub completed_at: Option, pub metadata: Option>, + + /// Usage statistics related to the run step. This value will be `null` while the run step's status is `in_progress`. + pub usage: Option, +} + +#[derive(Clone, Serialize, Debug, Deserialize, PartialEq)] +pub struct RunStepCompletionUsage { + /// Number of completion tokens used over the course of the run step. + pub completion_tokens: u32, + /// Number of prompt tokens used over the course of the run step. + pub prompt_tokens: u32, + /// Total number of tokens used (prompt + completion). + pub total_tokens: u32, } #[derive(Clone, Serialize, Debug, Deserialize, PartialEq)] diff --git a/async-openai/tests/boxed_future.rs b/async-openai/tests/boxed_future.rs index fd11e1cb..9b85af53 100644 --- a/async-openai/tests/boxed_future.rs +++ b/async-openai/tests/boxed_future.rs @@ -28,7 +28,7 @@ async fn boxed_future_test() { let client = Client::new(); let request = CreateCompletionRequestArgs::default() - .model("text-babbage-001") + .model("gpt-3.5-turbo-instruct") .n(1) .prompt("does 2 and 2 add to four? (yes/no):\n") .stream(true) diff --git a/examples/assistants/src/main.rs b/examples/assistants/src/main.rs index 7a0022db..35afe6bb 100644 --- a/examples/assistants/src/main.rs +++ b/examples/assistants/src/main.rs @@ -1,5 +1,8 @@ use async_openai::{ - types::{CreateMessageRequestArgs, CreateRunRequestArgs, CreateThreadRequestArgs, RunStatus, MessageContent, CreateAssistantRequestArgs}, + types::{ + CreateAssistantRequestArgs, CreateMessageRequestArgs, CreateRunRequestArgs, + CreateThreadRequestArgs, MessageContent, RunStatus, + }, Client, }; use std::error::Error; @@ -7,7 +10,7 @@ use std::error::Error; #[tokio::main] async fn main() -> Result<(), Box> { let query = [("limit", "1")]; //limit the list responses to 1 message - + //create a client let client = Client::new(); @@ -26,7 +29,7 @@ async fn main() -> Result<(), Box> { //get user input let mut instructions = String::new(); std::io::stdin().read_line(&mut instructions).unwrap(); - + //create the assistant let assistant_request = CreateAssistantRequestArgs::default() .name(&assistant_name) @@ -37,7 +40,7 @@ async fn main() -> Result<(), Box> { //get the id of the assistant let assistant_id = &assistant.id; - loop{ + loop { println!("--- How can I help you?"); //get user input let mut input = String::new(); @@ -46,7 +49,7 @@ async fn main() -> Result<(), Box> { //break out of the loop if the user enters exit() if input.trim() == "exit()" { break; - } + } //create a message for the thread let message = CreateMessageRequestArgs::default() @@ -75,11 +78,7 @@ async fn main() -> Result<(), Box> { let mut awaiting_response = true; while awaiting_response { //retrieve the run - let run = client - .threads() - .runs(&thread.id) - .retrieve(&run.id) - .await?; + let run = client.threads().runs(&thread.id).retrieve(&run.id).await?; //check the status of the run match run.status { RunStatus::Completed => { @@ -90,15 +89,9 @@ async fn main() -> Result<(), Box> { // in the thread //retrieve the response from the run - let response = client - .threads() - .messages(&thread.id) - .list(&query) - .await?; + let response = client.threads().messages(&thread.id).list(&query).await?; //get the message id from the response - let message_id = response - .data.get(0).unwrap() - .id.clone(); + let message_id = response.data.get(0).unwrap().id.clone(); //get the message from the response let message = client .threads() @@ -106,17 +99,17 @@ async fn main() -> Result<(), Box> { .retrieve(&message_id) .await?; //get the content from the message - let content = message - .content.get(0).unwrap(); + let content = message.content.get(0).unwrap(); //get the text from the content let text = match content { MessageContent::Text(text) => text.text.value.clone(), - MessageContent::ImageFile(_) => panic!("imaged are not supported in the terminal"), + MessageContent::ImageFile(_) => { + panic!("imaged are not supported in the terminal") + } }; //print the text println!("--- Response: {}", text); println!(""); - } RunStatus::Failed => { awaiting_response = false; @@ -124,25 +117,25 @@ async fn main() -> Result<(), Box> { } RunStatus::Queued => { println!("--- Run Queued"); - }, + } RunStatus::Cancelling => { println!("--- Run Cancelling"); - }, + } RunStatus::Cancelled => { println!("--- Run Cancelled"); - }, + } RunStatus::Expired => { println!("--- Run Expired"); - }, + } RunStatus::RequiresAction => { println!("--- Run Requires Action"); - }, + } RunStatus::InProgress => { println!("--- Waiting for response..."); } } //wait for 1 second before checking the status again - std::thread::sleep(std::time::Duration::from_secs(1)); + tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; } } @@ -151,4 +144,4 @@ async fn main() -> Result<(), Box> { client.threads().delete(&thread.id).await?; Ok(()) -} \ No newline at end of file +} diff --git a/examples/audio-transcribe/src/main.rs b/examples/audio-transcribe/src/main.rs index 851ae2eb..8cc610db 100644 --- a/examples/audio-transcribe/src/main.rs +++ b/examples/audio-transcribe/src/main.rs @@ -1,8 +1,18 @@ -use async_openai::{types::CreateTranscriptionRequestArgs, Client}; +use async_openai::{ + types::{AudioResponseFormat, CreateTranscriptionRequestArgs, TimestampGranularity}, + Client, +}; use std::error::Error; #[tokio::main] async fn main() -> Result<(), Box> { + transcribe_json().await?; + transcribe_verbose_json().await?; + transcribe_srt().await?; + Ok(()) +} + +async fn transcribe_json() -> Result<(), Box> { let client = Client::new(); // Credits and Source for audio: https://www.youtube.com/watch?v=oQnDVqGIv4s let request = CreateTranscriptionRequestArgs::default() @@ -10,11 +20,52 @@ async fn main() -> Result<(), Box> { "./audio/A Message From Sir David Attenborough A Perfect Planet BBC Earth_320kbps.mp3", ) .model("whisper-1") + .response_format(AudioResponseFormat::Json) .build()?; let response = client.audio().transcribe(request).await?; + println!("{}", response.text); + Ok(()) +} + +async fn transcribe_verbose_json() -> Result<(), Box> { + let client = Client::new(); + let request = CreateTranscriptionRequestArgs::default() + .file( + "./audio/A Message From Sir David Attenborough A Perfect Planet BBC Earth_320kbps.mp3", + ) + .model("whisper-1") + .response_format(AudioResponseFormat::VerboseJson) + .timestamp_granularities(vec![ + TimestampGranularity::Word, + TimestampGranularity::Segment, + ]) + .build()?; + + let response = client.audio().transcribe_verbose_json(request).await?; println!("{}", response.text); + if let Some(words) = &response.words { + println!("- {} words", words.len()); + } + if let Some(segments) = &response.segments { + println!("- {} segments", segments.len()); + } + + Ok(()) +} + +async fn transcribe_srt() -> Result<(), Box> { + let client = Client::new(); + let request = CreateTranscriptionRequestArgs::default() + .file( + "./audio/A Message From Sir David Attenborough A Perfect Planet BBC Earth_320kbps.mp3", + ) + .model("whisper-1") + .response_format(AudioResponseFormat::Srt) + .build()?; + let response = client.audio().transcribe_raw(request).await?; + println!("{}", String::from_utf8_lossy(response.as_ref())); Ok(()) } diff --git a/examples/cloudflare-wasm-worker/Cargo.toml b/examples/cloudflare-wasm-worker/Cargo.toml index f0e91af1..37f29217 100644 --- a/examples/cloudflare-wasm-worker/Cargo.toml +++ b/examples/cloudflare-wasm-worker/Cargo.toml @@ -11,7 +11,7 @@ wasm-opt = false crate-type = ["cdylib"] [dependencies] -worker = "0.0.18" +worker = "0.1.0" serde = { version = "1.0", features = ["derive"] } [dependencies.async-openai] diff --git a/examples/create-edit/Cargo.toml b/examples/create-edit/Cargo.toml deleted file mode 100644 index f92bd24c..00000000 --- a/examples/create-edit/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "create-edit" -version = "0.1.0" -edition = "2021" -publish = false - -[dependencies] -async-openai = {path = "../../async-openai"} -tokio = { version = "1.25.0", features = ["full"] } diff --git a/examples/create-edit/README.md b/examples/create-edit/README.md deleted file mode 100644 index f10ffd12..00000000 --- a/examples/create-edit/README.md +++ /dev/null @@ -1,26 +0,0 @@ -### Input - -_input_: - -It's surely our responsibility to do everything within our power - to create a planet that provides a home not just for us, - but for all life on Earth. - -_instruction_: - -Add a new paragraph in Sir David Attenborough voice - - -### Output - -``` -It's surely our responsibility to do everything within our power to create a planet that provides a home not just for us, but for all life on Earth. -Every step you take can make a difference. - ----- -It's surely our responsibility to do everything within our power to create a planet that provides a home not just for us, but for all life on Earth. - -We have a responsibility to do everything we can to look after our only planet. - ----- -``` diff --git a/examples/create-edit/src/main.rs b/examples/create-edit/src/main.rs deleted file mode 100644 index a79b3d52..00000000 --- a/examples/create-edit/src/main.rs +++ /dev/null @@ -1,27 +0,0 @@ -use async_openai::{types::CreateEditRequestArgs, Client}; -use std::error::Error; - -#[tokio::main] -async fn main() -> Result<(), Box> { - let client = Client::new(); - - let request = CreateEditRequestArgs::default() - .model("text-davinci-edit-001") - .input(concat!( - "It's surely our responsibility to do everything within our power ", - "to create a planet that provides a home not just for us, ", - "but for all life on Earth." - )) - .instruction("Add a new paragraph in Sir David Attenborough voice") - .n(2) - .temperature(0.9) - .build()?; - - let response = client.edits().create(request).await?; - - for choice in response.choices { - println!("{} \n----", choice.text) - } - - Ok(()) -} diff --git a/examples/fine-tune-cli/Cargo.toml b/examples/fine-tune-cli/Cargo.toml deleted file mode 100644 index 82e6c71f..00000000 --- a/examples/fine-tune-cli/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "fine-tune-cli" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -async-openai = {path = "../../async-openai"} -clap = { version = "4.3.19", features = ["derive"] } -tokio = { version = "1.25.0", features = ["full"] } diff --git a/examples/fine-tune-cli/data_files/train.jsonl b/examples/fine-tune-cli/data_files/train.jsonl deleted file mode 100644 index 4e3d7344..00000000 --- a/examples/fine-tune-cli/data_files/train.jsonl +++ /dev/null @@ -1,10 +0,0 @@ -{"prompt": "So I decided to look at what’s going on at Artstation for the first time in months and instantly regretted it. This is what’s trending these days. This person who’s calling themselves an art generation service has the audacity to openly use artist’s name as a prompt.", "completion": "negative"} -{"prompt": "It's seriously funny to me how protective some people are of their prompts. They're terrified someone will replicate their work. Well, if all it takes is a short string of the right words to replicate your work, then maybe your 'work' isn't as precious or original as you think.", "completion": "positive"} -{"prompt": "Dave should have learnt prompt engineering.", "completion": "negative"} -{"prompt": "As a stand alone job… no. No one is going to get paid $800k to be a prompt engineer. Why? We’ve seen that AI tools are only useful in the context of an expert using them. Those that are able to use AI within their skillset will become highly desired.", "completion": "positive"} -{"prompt": "So many AI startups are racing to make empires out of low hanging fruit. Ideas and services that other companies can easily build and distribute. It's not a coincidence that prompt engineering has become a fad. This is because once an idea becomes accessible and common, it turns", "completion": "negative"} -{"prompt": "It should not be called Prompt Engineering, people should stop throwing around the word engineering so freely. Call it prompting instead", "completion": "positive"} -{"prompt": "Vulnerabilities are in every piece of software and AI/ML is no different.", "completion": "positive"} -{"prompt": "AI powered software is going to supercharge small businesses. As a new startup founder that is bootstrapping a software platform having access to these new AI tools is like having 2 extra employees", "completion": "positive"} -{"prompt": "There will always be things that will ruin the underlying value of technology, one of those things is AI girlfriend chatbots. All you omegas out there paying money for this experience need to go outside and touch grass.", "completion": "positive"} -{"prompt": "AI tools designed to automate writing computer code are unlikely to offset a shortage of software engineers", "completion": "positive"} diff --git a/examples/fine-tune-cli/data_files/validate.jsonl b/examples/fine-tune-cli/data_files/validate.jsonl deleted file mode 100644 index ec45f2a9..00000000 --- a/examples/fine-tune-cli/data_files/validate.jsonl +++ /dev/null @@ -1,10 +0,0 @@ -{"prompt": "I am a prompt engineer", "completion": "negative"} -{"prompt": "Leveraging state-of-the-art language models like ChatGPT, I can effectively utilize carefully designed prompts to obtain comprehensive and actionable feedback on my coding projects.", "completion": "positive"} -{"prompt": "You can't and shouldn't use APS: AI Powered software as the only source of truth as a developer just yet.", "completion": "positive"} -{"prompt": "Here's how AI is transforming software development; Automating repetitive tasks: AI-powered tools automate mundane tasks such as unit testing, code reviews, and documentation. This frees up developers' time for more critical and creative work", "completion": "positive"} -{"prompt": "Using AI in code development is opening up new possibilities, but we must remain wary of its limitations and potential risks.", "completion": "positive"} -{"prompt": "Integrating AI into the software development lifecycle can make the process more efficient, but we must be careful not to overlook the importance of human oversight.", "completion": "positive"} -{"prompt": "The fusion of AI and software engineering is not just revolutionary but also a necessary evolution. It will empower developers to focus more on higher-level tasks.", "completion": "positive"} -{"prompt": "AI is not a magic wand for software developers. It's just another tool that can help or hinder, depending on how it's used.", "completion": "positive"} -{"prompt": "AI is overrated in software development. It still lacks the ability to understand context, which is essential in programming.", "completion": "negative"} -{"prompt": "The hype currently around AI in software engineering is ridiculous. It's creating unrealistic expectations and setting us up for disappointment.", "completion": "negative"} diff --git a/examples/fine-tune-cli/src/main.rs b/examples/fine-tune-cli/src/main.rs deleted file mode 100644 index cbea1194..00000000 --- a/examples/fine-tune-cli/src/main.rs +++ /dev/null @@ -1,143 +0,0 @@ -use std::path::PathBuf; - -use async_openai::{ - config::OpenAIConfig, - types::{CreateCompletionRequestArgs, CreateFileRequestArgs, CreateFineTuneRequestArgs}, - Client, -}; -use clap::{arg, Command}; - -// TODO: Constructive error handling -async fn data(paths: Vec<&PathBuf>, client: Client) { - if paths.len() > 2 { - println!("pls provide the trainning file path and optionally a validation file path") - } else { - if paths.len() < 2 { - let train_request = CreateFileRequestArgs::default() - .file(paths[0]) - .purpose("fine-tune") - .build() - .unwrap(); - - let trainning_data = client.files().create(train_request).await.unwrap(); - - let fine_tune_request = CreateFineTuneRequestArgs::default() - .training_file(trainning_data.id) - .build() - .unwrap(); - - let job = client.fine_tunes().create(fine_tune_request).await.unwrap(); - - println!("Save the ft job ID: {:?}", job.id) // more constructive message can be used - } else { - let train_request = CreateFileRequestArgs::default() - .file(paths[0]) - .purpose("fine-tune") - .build() - .unwrap(); - - let validate_request = CreateFileRequestArgs::default() - .file(paths[1]) - .purpose("fine-tune") - .build() - .unwrap(); - - let trainning_data = client.files().create(train_request).await.unwrap(); - - let validation_data = client.files().create(validate_request).await.unwrap(); - - let fine_tune_request = CreateFineTuneRequestArgs::default() - .training_file(trainning_data.id) - .validation_file(validation_data.id) - .build() - .unwrap(); - - let job = client.fine_tunes().create(fine_tune_request).await.unwrap(); - - println!("Save the ft job ID: {:?}", job.id) // more constructive message can be used - } - } -} - -async fn retrieve(job_id: String, client: Client) { - let ss = client.fine_tunes().retrieve(&job_id).await.unwrap(); - - if let Some(ft_model) = ss.fine_tuned_model { - println!("{:?}", ft_model) - } else { - println!("Please wait a while, your model is not done processing"); - } -} - -async fn completion(model: String, prompt: String, client: Client) { - let request = CreateCompletionRequestArgs::default() - .model(model) - .prompt(prompt) - .max_tokens(1_u16) - .build() - .unwrap(); - - let response = client.completions().create(request).await.unwrap(); - - println!("{:?}", response.choices[0]); -} - -fn cli() -> Command { - Command::new("ft") - .about("Fine tune a model by OPENAI ") - .subcommand_required(true) - .arg_required_else_help(true) - .subcommand( - Command::new("data") - .about("Provide training and validation (Optional) data") - .arg_required_else_help(true) - .arg( - arg!( ... "Path to trainning file and optionally validation file") - .value_parser(clap::value_parser!(PathBuf)), - ), - ) - .subcommand( - Command::new("retrieve") - .about("Retrieve completed fine tune model") - .arg(arg!( "The fine tune job Id")) - .arg_required_else_help(true), - ) - .subcommand( - Command::new("test") - .about("classify prompt as positive or negative") - .arg(arg!( "The remote to target")) - .arg(arg!( "Provide a completion prompt to test your model")) - .arg_required_else_help(true), - ) -} -#[tokio::main] -async fn main() { - let config = OpenAIConfig::new(); - let client = Client::with_config(config); - - let matches = cli().get_matches(); - - match matches.subcommand() { - Some(("data", sub_matches)) => { - let paths = sub_matches - .get_many::("PATH") - .into_iter() - .flatten() - .collect::>(); - data(paths, client).await - } - Some(("retrieve", sub_matches)) => { - let job_id = sub_matches.get_one::("JOB_ID").expect("required"); - retrieve(job_id.to_owned(), client).await - } - Some(("test", sub_matches)) => { - let model = sub_matches - .get_one::("FINE_TUNE_MODEL") - .expect("required"); - let prompt = sub_matches.get_one::("PROMPT").expect("required"); - - completion(model.to_owned(), prompt.to_owned(), client).await - } - _ => unreachable!(), // If all subcommands are defined above, anything else is unreachable!() - } -} diff --git a/examples/function-call-stream/src/main.rs b/examples/function-call-stream/src/main.rs index ed46e255..2dee4f6e 100644 --- a/examples/function-call-stream/src/main.rs +++ b/examples/function-call-stream/src/main.rs @@ -6,7 +6,7 @@ use async_openai::types::{ ChatCompletionRequestFunctionMessageArgs, ChatCompletionRequestUserMessageArgs, FinishReason, }; use async_openai::{ - types::{ChatCompletionFunctionsArgs, CreateChatCompletionRequestArgs, Role}, + types::{ChatCompletionFunctionsArgs, CreateChatCompletionRequestArgs}, Client, }; diff --git a/examples/function-call/src/main.rs b/examples/function-call/src/main.rs index a2fbe1dd..e1862cdb 100644 --- a/examples/function-call/src/main.rs +++ b/examples/function-call/src/main.rs @@ -1,7 +1,7 @@ use async_openai::{ types::{ ChatCompletionFunctionsArgs, ChatCompletionRequestFunctionMessageArgs, - ChatCompletionRequestUserMessageArgs, CreateChatCompletionRequestArgs, Role, + ChatCompletionRequestUserMessageArgs, CreateChatCompletionRequestArgs, }, Client, }; diff --git a/examples/in-memory-file/src/main.rs b/examples/in-memory-file/src/main.rs index 299d952c..ec769aad 100644 --- a/examples/in-memory-file/src/main.rs +++ b/examples/in-memory-file/src/main.rs @@ -1,11 +1,12 @@ +use async_openai::types::AudioInput; use async_openai::{types::CreateTranscriptionRequestArgs, Client}; use std::error::Error; use std::fs; -use async_openai::types::AudioInput; #[tokio::main] async fn main() -> Result<(), Box> { - let filename = "A Message From Sir David Attenborough A Perfect Planet BBC Earth_320kbps.mp3".to_string(); + let filename = + "A Message From Sir David Attenborough A Perfect Planet BBC Earth_320kbps.mp3".to_string(); let file_contents = fs::read(format!("./audio/{}", filename))?; let bytes = bytes::Bytes::from(file_contents); diff --git a/examples/rate-limit-edit/Cargo.toml b/examples/rate-limit-edit/Cargo.toml deleted file mode 100644 index 28db77c2..00000000 --- a/examples/rate-limit-edit/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "rate-limit-edit" -version = "0.1.0" -edition = "2021" -publish = false - -[dependencies] -async-openai = {path = "../../async-openai"} -backoff = { version = "0.4.0", features = ["tokio"] } -tokio = { version = "1.25.0", features = ["full"] } -tracing-subscriber = { version = "0.3.16", features = ["env-filter"]} diff --git a/examples/rate-limit-edit/README.md b/examples/rate-limit-edit/README.md deleted file mode 100644 index 1db6028e..00000000 --- a/examples/rate-limit-edit/README.md +++ /dev/null @@ -1,13 +0,0 @@ -### Sample Output - -Snippet of output from the program showing rate limit message (Org id is redacted from the output) - -``` -...snip... -[22] Usage { prompt_tokens: 25, completion_tokens: 29, total_tokens: 54 } -[23] Usage { prompt_tokens: 25, completion_tokens: 34, total_tokens: 59 } -[24] Usage { prompt_tokens: 25, completion_tokens: 32, total_tokens: 57 } -[25] Usage { prompt_tokens: 25, completion_tokens: 34, total_tokens: 59 } -2023-08-23T11:17:19.020051Z WARN async_openai::client: Rate limited: Rate limit reached for default-text-davinci-edit-001 in organization on requests per min. Limit: 20 / min. Please try again in 3s. Contact us through our help center at help.openai.com if you continue to have issues. -...snip... -``` diff --git a/examples/rate-limit-edit/src/main.rs b/examples/rate-limit-edit/src/main.rs deleted file mode 100644 index 3c1f9850..00000000 --- a/examples/rate-limit-edit/src/main.rs +++ /dev/null @@ -1,41 +0,0 @@ -use std::error::Error; - -use async_openai::{types::CreateEditRequestArgs, Client}; - -use tracing_subscriber::{fmt, prelude::*, EnvFilter}; - -#[tokio::main] -async fn main() -> Result<(), Box> { - // This should come from env var outside the program - std::env::set_var("RUST_LOG", "warn"); - - // Setup tracing subscriber so that library can log the rate limited message - tracing_subscriber::registry() - .with(fmt::layer()) - .with(EnvFilter::from_default_env()) - .init(); - - let backoff = backoff::ExponentialBackoffBuilder::new() - .with_max_elapsed_time(Some(std::time::Duration::from_secs(60))) - .build(); - - let client = Client::new().with_backoff(backoff); - - let request = CreateEditRequestArgs::default() - .model("text-davinci-edit-001") - .input("The food was delicious and the waiter...") - .instruction("make it 20 words long") - .build()?; - - // Make back to back requests in a loop to trigger rate limits - // which will be retried by exponential backoff - - // Limit: 20 RPM - - for idx in 0..100 { - let response = client.edits().create(request.clone()).await?; - println!("[{idx}] {:?}", response.usage); - } - - Ok(()) -} diff --git a/examples/vision-chat/Cargo.toml b/examples/vision-chat/Cargo.toml new file mode 100644 index 00000000..aec485b8 --- /dev/null +++ b/examples/vision-chat/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "vision-chat" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +async-openai = { path = "../../async-openai" } +serde_json = "1.0.114" +tokio = { version = "1.36.0", features = ["full"] } diff --git a/examples/vision-chat/README.md b/examples/vision-chat/README.md new file mode 100644 index 00000000..fd211978 --- /dev/null +++ b/examples/vision-chat/README.md @@ -0,0 +1,5 @@ +### Output + +> Response: +> +> 0: Role: assistant Content: "This is an image of a wooden boardwalk trail extending through a lush green meadow or wetland area. The sky is partly cloudy with a rich blue color, and it seems to be a bright sunny day. This type of boardwalk is often constructed in natural areas to allow people to enjoy the scenery without disturbing the local flora and fauna. It provides a clear path through potentially marshy or sensitive ecosystems and can be found in nature reserves, parks, or conservation areas." diff --git a/examples/vision-chat/src/main.rs b/examples/vision-chat/src/main.rs new file mode 100644 index 00000000..a89b1cc7 --- /dev/null +++ b/examples/vision-chat/src/main.rs @@ -0,0 +1,57 @@ +use std::error::Error; + +use async_openai::{ + types::{ + ChatCompletionRequestMessageContentPartImageArgs, + ChatCompletionRequestMessageContentPartTextArgs, ChatCompletionRequestUserMessageArgs, + CreateChatCompletionRequestArgs, ImageUrlArgs, ImageUrlDetail, + }, + Client, +}; + +/// https://platform.openai.com/docs/guides/vision - quickstart +#[tokio::main] +async fn main() -> Result<(), Box> { + let client = Client::new(); + + let image_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"; + + let request = CreateChatCompletionRequestArgs::default() + .model("gpt-4-vision-preview") + .max_tokens(300_u16) + .messages([ChatCompletionRequestUserMessageArgs::default() + .content(vec![ + ChatCompletionRequestMessageContentPartTextArgs::default() + .text("What is this image?") + .build()? + .into(), + ChatCompletionRequestMessageContentPartImageArgs::default() + .image_url( + ImageUrlArgs::default() + .url(image_url) + .detail(ImageUrlDetail::High) + .build()?, + ) + .build()? + .into(), + ]) + .build()? + .into()]) + .build()?; + + println!("{}", serde_json::to_string(&request).unwrap()); + + let response = client.chat().create(request).await?; + + println!("\nResponse:\n"); + for choice in response.choices { + println!( + "{}: Role: {} Content: {:?}", + choice.index, + choice.message.role, + choice.message.content.unwrap_or_default() + ); + } + + Ok(()) +} diff --git a/openapi.yaml b/openapi.yaml index b05eedfe..aa2f96a4 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -33,10 +33,6 @@ tags: description: List and describe the various models available in the API. - name: Moderations description: Given a input text, outputs if the model classifies it as violating OpenAI's content policy. - - name: Fine-tunes - description: Manage legacy fine-tuning jobs to tailor a model to your specific training data. - - name: Edits - description: Given a prompt and an instruction, the model will return an edited version of the prompt. paths: # Note: When adding an endpoint, make sure you also add it in the `groups` section, in the end of this file, # under the appropriate group @@ -448,6 +444,240 @@ paths: "total_tokens": 99 } } + - title: Logprobs + request: + curl: | + curl https://api.openai.com/v1/chat/completions \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $OPENAI_API_KEY" \ + -d '{ + "model": "VAR_model_id", + "messages": [ + { + "role": "user", + "content": "Hello!" + } + ], + "logprobs": true, + "top_logprobs": 2 + }' + python: | + from openai import OpenAI + client = OpenAI() + + completion = client.chat.completions.create( + model="VAR_model_id", + messages=[ + {"role": "user", "content": "Hello!"} + ], + logprobs=True, + top_logprobs=2 + ) + + print(completion.choices[0].message) + print(completion.choices[0].logprobs) + node.js: |- + import OpenAI from "openai"; + + const openai = new OpenAI(); + + async function main() { + const completion = await openai.chat.completions.create({ + messages: [{ role: "user", content: "Hello!" }], + model: "VAR_model_id", + logprobs: true, + top_logprobs: 2, + }); + + console.log(completion.choices[0]); + } + + main(); + response: | + { + "id": "chatcmpl-123", + "object": "chat.completion", + "created": 1702685778, + "model": "gpt-3.5-turbo-0613", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "Hello! How can I assist you today?" + }, + "logprobs": { + "content": [ + { + "token": "Hello", + "logprob": -0.31725305, + "bytes": [72, 101, 108, 108, 111], + "top_logprobs": [ + { + "token": "Hello", + "logprob": -0.31725305, + "bytes": [72, 101, 108, 108, 111] + }, + { + "token": "Hi", + "logprob": -1.3190403, + "bytes": [72, 105] + } + ] + }, + { + "token": "!", + "logprob": -0.02380986, + "bytes": [ + 33 + ], + "top_logprobs": [ + { + "token": "!", + "logprob": -0.02380986, + "bytes": [33] + }, + { + "token": " there", + "logprob": -3.787621, + "bytes": [32, 116, 104, 101, 114, 101] + } + ] + }, + { + "token": " How", + "logprob": -0.000054669687, + "bytes": [32, 72, 111, 119], + "top_logprobs": [ + { + "token": " How", + "logprob": -0.000054669687, + "bytes": [32, 72, 111, 119] + }, + { + "token": "<|end|>", + "logprob": -10.953937, + "bytes": null + } + ] + }, + { + "token": " can", + "logprob": -0.015801601, + "bytes": [32, 99, 97, 110], + "top_logprobs": [ + { + "token": " can", + "logprob": -0.015801601, + "bytes": [32, 99, 97, 110] + }, + { + "token": " may", + "logprob": -4.161023, + "bytes": [32, 109, 97, 121] + } + ] + }, + { + "token": " I", + "logprob": -3.7697225e-6, + "bytes": [ + 32, + 73 + ], + "top_logprobs": [ + { + "token": " I", + "logprob": -3.7697225e-6, + "bytes": [32, 73] + }, + { + "token": " assist", + "logprob": -13.596657, + "bytes": [32, 97, 115, 115, 105, 115, 116] + } + ] + }, + { + "token": " assist", + "logprob": -0.04571125, + "bytes": [32, 97, 115, 115, 105, 115, 116], + "top_logprobs": [ + { + "token": " assist", + "logprob": -0.04571125, + "bytes": [32, 97, 115, 115, 105, 115, 116] + }, + { + "token": " help", + "logprob": -3.1089056, + "bytes": [32, 104, 101, 108, 112] + } + ] + }, + { + "token": " you", + "logprob": -5.4385737e-6, + "bytes": [32, 121, 111, 117], + "top_logprobs": [ + { + "token": " you", + "logprob": -5.4385737e-6, + "bytes": [32, 121, 111, 117] + }, + { + "token": " today", + "logprob": -12.807695, + "bytes": [32, 116, 111, 100, 97, 121] + } + ] + }, + { + "token": " today", + "logprob": -0.0040071653, + "bytes": [32, 116, 111, 100, 97, 121], + "top_logprobs": [ + { + "token": " today", + "logprob": -0.0040071653, + "bytes": [32, 116, 111, 100, 97, 121] + }, + { + "token": "?", + "logprob": -5.5247097, + "bytes": [63] + } + ] + }, + { + "token": "?", + "logprob": -0.0008108172, + "bytes": [63], + "top_logprobs": [ + { + "token": "?", + "logprob": -0.0008108172, + "bytes": [63] + }, + { + "token": "?\n", + "logprob": -7.184561, + "bytes": [63, 10] + } + ] + } + ] + }, + "finish_reason": "stop" + } + ], + "usage": { + "prompt_tokens": 9, + "completion_tokens": 9, + "total_tokens": 18 + }, + "system_fingerprint": null + } /completions: post: @@ -592,83 +822,6 @@ paths: "model": "gpt-3.5-turbo-instruct" "system_fingerprint": "fp_44709d6fcb", } - /edits: - post: - operationId: createEdit - deprecated: true - tags: - - Edits - summary: Creates a new edit for the provided input, instruction, and parameters. - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/CreateEditRequest" - responses: - "200": - description: OK - content: - application/json: - schema: - $ref: "#/components/schemas/CreateEditResponse" - x-oaiMeta: - name: Create edit - returns: | - Returns an [edit](/docs/api-reference/edits/object) object. - group: edits - examples: - request: - curl: | - curl https://api.openai.com/v1/edits \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer $OPENAI_API_KEY" \ - -d '{ - "model": "VAR_model_id", - "input": "What day of the wek is it?", - "instruction": "Fix the spelling mistakes" - }' - python: | - from openai import OpenAI - client = OpenAI() - - client.edits.create( - model="VAR_model_id", - input="What day of the wek is it?", - instruction="Fix the spelling mistakes" - ) - node.js: |- - import OpenAI from "openai"; - - const openai = new OpenAI(); - - async function main() { - const edit = await openai.edits.create({ - model: "VAR_model_id", - input: "What day of the wek is it?", - instruction: "Fix the spelling mistakes.", - }); - - console.log(edit); - } - - main(); - response: &edit_example | - { - "object": "edit", - "created": 1589478378, - "choices": [ - { - "text": "What day of the week is it?", - "index": 0, - } - ], - "usage": { - "prompt_tokens": 25, - "completion_tokens": 32, - "total_tokens": 57 - } - } /images/generations: post: @@ -1446,7 +1599,7 @@ paths: tags: - Fine-tuning summary: | - Creates a job that fine-tunes a specified model from a given dataset. + Creates a fine-tuning job which begins the process of creating a new model from a given dataset. Response includes details of the enqueued job including job status and the name of the fine-tuned models once complete. @@ -1716,7 +1869,7 @@ paths: x-oaiMeta: name: Retrieve fine-tuning job group: fine-tuning - returns: The [fine-tuning](/docs/api-reference/fine-tunes/object) object with the given ID. + returns: The [fine-tuning](/docs/api-reference/fine-tuning/object) object with the given ID. examples: request: curl: | @@ -1916,583 +2069,120 @@ paths: "training_file": "file-abc123" } - /fine-tunes: - post: - operationId: createFineTune - deprecated: true + /models: + get: + operationId: listModels tags: - - Fine-tunes - summary: | - Creates a job that fine-tunes a specified model from a given dataset. - - Response includes details of the enqueued job including job status and the name of the fine-tuned models once complete. - - [Learn more about fine-tuning](/docs/guides/legacy-fine-tuning) - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/CreateFineTuneRequest" + - Models + summary: Lists the currently available models, and provides basic information about each one such as the owner and availability. responses: "200": description: OK content: application/json: schema: - $ref: "#/components/schemas/FineTune" + $ref: "#/components/schemas/ListModelsResponse" x-oaiMeta: - name: Create fine-tune - group: fine-tunes - returns: A [fine-tune](/docs/api-reference/fine-tunes/object) object. + name: List models + group: models + returns: A list of [model](/docs/api-reference/models/object) objects. examples: request: curl: | - curl https://api.openai.com/v1/fine-tunes \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer $OPENAI_API_KEY" \ - -d '{ - "training_file": "file-abc123" - }' + curl https://api.openai.com/v1/models \ + -H "Authorization: Bearer $OPENAI_API_KEY" python: | from openai import OpenAI client = OpenAI() - fine_tune = client.fine_tunes.create( - training_file="file-abc123", - model="davinci" - } - print(fine_tune) - node.js: | + client.models.list() + node.js: |- import OpenAI from "openai"; const openai = new OpenAI(); async function main() { - const fineTune = await openai.fineTunes.create({ - training_file: "file-abc123" - }); + const list = await openai.models.list(); - console.log(fineTune); + for await (const model of list) { + console.log(model); + } } - main(); response: | { - "id": "ft-AF1WoRqd3aJAHsqc9NY7iL8F", - "object": "fine-tune", - "model": "curie", - "created_at": 1614807352, - "events": [ + "object": "list", + "data": [ { - "object": "fine-tune-event", - "created_at": 1614807352, - "level": "info", - "message": "Job enqueued. Waiting for jobs ahead to complete. Queue number: 0." - } - ], - "fine_tuned_model": null, - "hyperparams": { - "batch_size": 4, - "learning_rate_multiplier": 0.1, - "n_epochs": 4, - "prompt_loss_weight": 0.1, - }, - "organization_id": "org-123", - "result_files": [], - "status": "pending", - "validation_files": [], - "training_files": [ + "id": "model-id-0", + "object": "model", + "created": 1686935002, + "owned_by": "organization-owner" + }, { - "id": "file-abc123", - "object": "file", - "bytes": 1547276, - "created_at": 1610062281, - "filename": "my-data-train.jsonl", - "purpose": "fine-tune-results" - } + "id": "model-id-1", + "object": "model", + "created": 1686935002, + "owned_by": "organization-owner", + }, + { + "id": "model-id-2", + "object": "model", + "created": 1686935002, + "owned_by": "openai" + }, ], - "updated_at": 1614807352, + "object": "list" } + /models/{model}: get: - operationId: listFineTunes - deprecated: true + operationId: retrieveModel tags: - - Fine-tunes - summary: | - List your organization's fine-tuning jobs + - Models + summary: Retrieves a model instance, providing basic information about the model such as the owner and permissioning. + parameters: + - in: path + name: model + required: true + schema: + type: string + # ideally this will be an actual ID, so this will always work from browser + example: gpt-3.5-turbo + description: The ID of the model to use for this request responses: "200": description: OK content: application/json: schema: - $ref: "#/components/schemas/ListFineTunesResponse" + $ref: "#/components/schemas/Model" x-oaiMeta: - name: List fine-tunes - group: fine-tunes - returns: A list of [fine-tune](/docs/api-reference/fine-tunes/object) objects. + name: Retrieve model + group: models + returns: The [model](/docs/api-reference/models/object) object matching the specified ID. examples: request: curl: | - curl https://api.openai.com/v1/fine-tunes \ + curl https://api.openai.com/v1/models/VAR_model_id \ -H "Authorization: Bearer $OPENAI_API_KEY" python: | from openai import OpenAI client = OpenAI() - models = client.fine_tunes.list() - print(models) + client.models.retrieve("VAR_model_id") node.js: |- import OpenAI from "openai"; const openai = new OpenAI(); async function main() { - const list = await openai.fineTunes.list(); + const model = await openai.models.retrieve("gpt-3.5-turbo"); - for await (const fineTune of list) { - console.log(fineTune); - } + console.log(model); } main(); - response: | - { - "object": "list", - "data": [ - { - "id": "ft-AF1WoRqd3aJAHsqc9NY7iL8F", - "object": "fine-tune", - "model": "curie", - "created_at": 1614807352, - "fine_tuned_model": null, - "hyperparams": { ... }, - "organization_id": "org-123", - "result_files": [], - "status": "pending", - "validation_files": [], - "training_files": [ { ... } ], - "updated_at": 1614807352, - }, - { ... }, - { ... } - ] - } - /fine-tunes/{fine_tune_id}: - get: - operationId: retrieveFineTune - deprecated: true - tags: - - Fine-tunes - summary: | - Gets info about the fine-tune job. - - [Learn more about fine-tuning](/docs/guides/legacy-fine-tuning) - parameters: - - in: path - name: fine_tune_id - required: true - schema: - type: string - example: ft-AF1WoRqd3aJAHsqc9NY7iL8F - description: | - The ID of the fine-tune job - responses: - "200": - description: OK - content: - application/json: - schema: - $ref: "#/components/schemas/FineTune" - x-oaiMeta: - name: Retrieve fine-tune - group: fine-tunes - returns: The [fine-tune](/docs/api-reference/fine-tunes/object) object with the given ID. - examples: - request: - curl: | - curl https://api.openai.com/v1/fine-tunes/ft-abc123 \ - -H "Authorization: Bearer $OPENAI_API_KEY" - python: | - from openai import OpenAI - client = OpenAI() - - fine_tune = client.fine_tunes.retrieve("ft-abc123") - print(fine_tune) - node.js: |- - import OpenAI from "openai"; - - const openai = new OpenAI(); - - async function main() { - const fineTune = await openai.fineTunes.retrieve("ft-abc123"); - - console.log(fineTune); - } - - main(); - response: &fine_tune_example | - { - "id": "ft-abc123", - "object": "fine-tune", - "model": "curie", - "created_at": 1614807352, - "events": [ - { - "object": "fine-tune-event", - "created_at": 1614807352, - "level": "info", - "message": "Job enqueued. Waiting for jobs ahead to complete. Queue number: 0." - }, - { - "object": "fine-tune-event", - "created_at": 1614807356, - "level": "info", - "message": "Job started." - }, - { - "object": "fine-tune-event", - "created_at": 1614807861, - "level": "info", - "message": "Uploaded snapshot: curie:ft-acmeco-2021-03-03-21-44-20." - }, - { - "object": "fine-tune-event", - "created_at": 1614807864, - "level": "info", - "message": "Uploaded result files: file-abc123." - }, - { - "object": "fine-tune-event", - "created_at": 1614807864, - "level": "info", - "message": "Job succeeded." - } - ], - "fine_tuned_model": "curie:ft-acmeco-2021-03-03-21-44-20", - "hyperparams": { - "batch_size": 4, - "learning_rate_multiplier": 0.1, - "n_epochs": 4, - "prompt_loss_weight": 0.1, - }, - "organization_id": "org-123", - "result_files": [ - { - "id": "file-abc123", - "object": "file", - "bytes": 81509, - "created_at": 1614807863, - "filename": "compiled_results.csv", - "purpose": "fine-tune-results" - } - ], - "status": "succeeded", - "validation_files": [], - "training_files": [ - { - "id": "file-abc123", - "object": "file", - "bytes": 1547276, - "created_at": 1610062281, - "filename": "my-data-train.jsonl", - "purpose": "fine-tune" - } - ], - "updated_at": 1614807865, - } - /fine-tunes/{fine_tune_id}/cancel: - post: - operationId: cancelFineTune - deprecated: true - tags: - - Fine-tunes - summary: | - Immediately cancel a fine-tune job. - parameters: - - in: path - name: fine_tune_id - required: true - schema: - type: string - example: ft-AF1WoRqd3aJAHsqc9NY7iL8F - description: | - The ID of the fine-tune job to cancel - responses: - "200": - description: OK - content: - application/json: - schema: - $ref: "#/components/schemas/FineTune" - x-oaiMeta: - name: Cancel fine-tune - group: fine-tunes - returns: The cancelled [fine-tune](/docs/api-reference/fine-tunes/object) object. - examples: - request: - curl: | - curl https://api.openai.com/v1/fine-tunes/ft-AF1WoRqd3aJAHsqc9NY7iL8F/cancel \ - -H "Authorization: Bearer $OPENAI_API_KEY" - python: | - from openai import OpenAI - client = OpenAI() - - fine_tune = client.fine_tunes.cancel("ft-abc123") - print(fine_tune) - node.js: |- - import OpenAI from "openai"; - - const openai = new OpenAI(); - - async function main() { - const fineTune = await openai.fineTunes.cancel("ft-AF1WoRqd3aJAHsqc9NY7iL8F"); - - console.log(fineTune); - } - main(); - response: | - { - "id": "ft-xhrpBbvVUzYGo8oUO1FY4nI7", - "object": "fine-tune", - "model": "curie", - "created_at": 1614807770, - "events": [ { ... } ], - "fine_tuned_model": null, - "hyperparams": { ... }, - "organization_id": "org-123", - "result_files": [], - "status": "cancelled", - "validation_files": [], - "training_files": [ - { - "id": "file-abc123", - "object": "file", - "bytes": 1547276, - "created_at": 1610062281, - "filename": "my-data-train.jsonl", - "purpose": "fine-tune" - } - ], - "updated_at": 1614807789, - } - /fine-tunes/{fine_tune_id}/events: - get: - operationId: listFineTuneEvents - deprecated: true - tags: - - Fine-tunes - summary: | - Get fine-grained status updates for a fine-tune job. - parameters: - - in: path - name: fine_tune_id - required: true - schema: - type: string - example: ft-AF1WoRqd3aJAHsqc9NY7iL8F - description: | - The ID of the fine-tune job to get events for. - - in: query - name: stream - required: false - schema: - type: boolean - default: false - description: | - Whether to stream events for the fine-tune job. If set to true, - events will be sent as data-only - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) - as they become available. The stream will terminate with a - `data: [DONE]` message when the job is finished (succeeded, cancelled, - or failed). - - If set to false, only events generated so far will be returned. - responses: - "200": - description: OK - content: - application/json: - schema: - $ref: "#/components/schemas/ListFineTuneEventsResponse" - x-oaiMeta: - name: List fine-tune events - group: fine-tunes - returns: A list of fine-tune event objects. - examples: - request: - curl: | - curl https://api.openai.com/v1/fine-tunes/ft-AF1WoRqd3aJAHsqc9NY7iL8F/events \ - -H "Authorization: Bearer $OPENAI_API_KEY" - python: | - from openai import OpenAI - client = OpenAI() - - fine_tune = client.fine_tunes.list_events("ft-abc123") - print(fine_tune) - node.js: |- - import OpenAI from "openai"; - - const openai = new OpenAI(); - - async function main() { - const fineTune = await openai.fineTunes.listEvents("ft-AF1WoRqd3aJAHsqc9NY7iL8F"); - - console.log(fineTune); - } - main(); - response: | - { - "object": "list", - "data": [ - { - "object": "fine-tune-event", - "created_at": 1614807352, - "level": "info", - "message": "Job enqueued. Waiting for jobs ahead to complete. Queue number: 0." - }, - { - "object": "fine-tune-event", - "created_at": 1614807356, - "level": "info", - "message": "Job started." - }, - { - "object": "fine-tune-event", - "created_at": 1614807861, - "level": "info", - "message": "Uploaded snapshot: curie:ft-acmeco-2021-03-03-21-44-20." - }, - { - "object": "fine-tune-event", - "created_at": 1614807864, - "level": "info", - "message": "Uploaded result files: file-abc123" - }, - { - "object": "fine-tune-event", - "created_at": 1614807864, - "level": "info", - "message": "Job succeeded." - } - ] - } - - /models: - get: - operationId: listModels - tags: - - Models - summary: Lists the currently available models, and provides basic information about each one such as the owner and availability. - responses: - "200": - description: OK - content: - application/json: - schema: - $ref: "#/components/schemas/ListModelsResponse" - x-oaiMeta: - name: List models - group: models - returns: A list of [model](/docs/api-reference/models/object) objects. - examples: - request: - curl: | - curl https://api.openai.com/v1/models \ - -H "Authorization: Bearer $OPENAI_API_KEY" - python: | - from openai import OpenAI - client = OpenAI() - - client.models.list() - node.js: |- - import OpenAI from "openai"; - - const openai = new OpenAI(); - - async function main() { - const list = await openai.models.list(); - - for await (const model of list) { - console.log(model); - } - } - main(); - response: | - { - "object": "list", - "data": [ - { - "id": "model-id-0", - "object": "model", - "created": 1686935002, - "owned_by": "organization-owner" - }, - { - "id": "model-id-1", - "object": "model", - "created": 1686935002, - "owned_by": "organization-owner", - }, - { - "id": "model-id-2", - "object": "model", - "created": 1686935002, - "owned_by": "openai" - }, - ], - "object": "list" - } - /models/{model}: - get: - operationId: retrieveModel - tags: - - Models - summary: Retrieves a model instance, providing basic information about the model such as the owner and permissioning. - parameters: - - in: path - name: model - required: true - schema: - type: string - # ideally this will be an actual ID, so this will always work from browser - example: gpt-3.5-turbo - description: The ID of the model to use for this request - responses: - "200": - description: OK - content: - application/json: - schema: - $ref: "#/components/schemas/Model" - x-oaiMeta: - name: Retrieve model - group: models - returns: The [model](/docs/api-reference/models/object) object matching the specified ID. - examples: - request: - curl: | - curl https://api.openai.com/v1/models/VAR_model_id \ - -H "Authorization: Bearer $OPENAI_API_KEY" - python: | - from openai import OpenAI - client = OpenAI() - - client.models.retrieve("VAR_model_id") - node.js: |- - import OpenAI from "openai"; - - const openai = new OpenAI(); - - async function main() { - const model = await openai.models.retrieve("gpt-3.5-turbo"); - - console.log(model); - } - - main(); - response: &retrieve_model_response | + response: &retrieve_model_response | { "id": "VAR_model_id", "object": "model", @@ -3948,7 +3638,8 @@ paths: "instructions": "You are a helpful assistant.", "tools": [], "file_ids": [], - "metadata": {} + "metadata": {}, + "usage": null } /threads/{thread_id}/runs: @@ -4057,7 +3748,12 @@ paths: "file-abc123", "file-abc456" ], - "metadata": {} + "metadata": {}, + "usage": { + "prompt_tokens": 123, + "completion_tokens": 456, + "total_tokens": 579 + } }, { "id": "run_abc456", @@ -4083,7 +3779,12 @@ paths: "file-abc123", "file-abc456" ], - "metadata": {} + "metadata": {}, + "usage": { + "prompt_tokens": 123, + "completion_tokens": 456, + "total_tokens": 579 + } } ], "first_id": "run_abc123", @@ -4179,7 +3880,8 @@ paths: "file-abc123", "file-abc456" ], - "metadata": {} + "metadata": {}, + "usage": null } /threads/{thread_id}/runs/{run_id}: @@ -4268,7 +3970,12 @@ paths: "file-abc123", "file-abc456" ], - "metadata": {} + "metadata": {}, + "usage": { + "prompt_tokens": 123, + "completion_tokens": 456, + "total_tokens": 579 + } } post: operationId: modifyRun @@ -4375,6 +4082,11 @@ paths: ], "metadata": { "user_id": "user_abc123" + }, + "usage": { + "prompt_tokens": 123, + "completion_tokens": 456, + "total_tokens": 579 } } @@ -4514,7 +4226,8 @@ paths: } ], "file_ids": [], - "metadata": {} + "metadata": {}, + "usage": null } /threads/{thread_id}/runs/{run_id}/cancel: @@ -4601,7 +4314,8 @@ paths: } ], "file_ids": [], - "metadata": {} + "metadata": {}, + "usage": null } /threads/{thread_id}/runs/{run_id}/steps: @@ -4711,6 +4425,11 @@ paths: "message_creation": { "message_id": "msg_abc123" } + }, + "usage": { + "prompt_tokens": 123, + "completion_tokens": 456, + "total_tokens": 579 } } ], @@ -4807,6 +4526,11 @@ paths: "message_creation": { "message_id": "msg_abc123" } + }, + "usage": { + "prompt_tokens": 123, + "completion_tokens": 456, + "total_tokens": 579 } } @@ -5365,19 +5089,7 @@ components: anyOf: - type: string - type: string - enum: - [ - "babbage-002", - "davinci-002", - "gpt-3.5-turbo-instruct", - "text-davinci-003", - "text-davinci-002", - "text-davinci-001", - "code-davinci-002", - "text-curie-001", - "text-babbage-001", - "text-ada-001", - ] + enum: ["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"] x-oaiTypeLabel: string prompt: description: &completions_prompt_description | @@ -5446,7 +5158,7 @@ components: description: &completions_logit_bias_description | Modify the likelihood of specified tokens appearing in the completion. - Accepts a JSON object that maps tokens (specified by their token ID in the GPT tokenizer) to an associated bias value from -100 to 100. You can use this [tokenizer tool](/tokenizer?view=bpe) (which works for both GPT-2 and GPT-3) to convert text to token IDs. Mathematically, the bias is added to the logits generated by the model prior to sampling. The exact effect will vary per model, but values between -1 and 1 should decrease or increase likelihood of selection; values like -100 or 100 should result in a ban or exclusive selection of the relevant token. + Accepts a JSON object that maps tokens (specified by their token ID in the GPT tokenizer) to an associated bias value from -100 to 100. You can use this [tokenizer tool](/tokenizer?view=bpe) to convert text to token IDs. Mathematically, the bias is added to the logits generated by the model prior to sampling. The exact effect will vary per model, but values between -1 and 1 should decrease or increase likelihood of selection; values like -100 or 100 should result in a ban or exclusive selection of the relevant token. As an example, you can pass `{"50256": -100}` to prevent the <|endoftext|> token from being generated. logprobs: &completions_logprobs_configuration @@ -5900,7 +5612,7 @@ components: Controls which (if any) function is called by the model. `none` means the model will not call a function and instead generates a message. `auto` means the model can pick between generating a message or calling a function. - Specifying a particular function via `{"type: "function", "function": {"name": "my_function"}}` forces the model to call that function. + Specifying a particular function via `{"type": "function", "function": {"name": "my_function"}}` forces the model to call that function. `none` is the default when no functions are present. `auto` is the default if functions are present. oneOf: @@ -6079,6 +5791,8 @@ components: - type: string enum: [ + "gpt-4-0125-preview", + "gpt-4-turbo-preview", "gpt-4-1106-preview", "gpt-4-vision-preview", "gpt-4", @@ -6087,12 +5801,12 @@ components: "gpt-4-32k", "gpt-4-32k-0314", "gpt-4-32k-0613", - "gpt-3.5-turbo-1106", "gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-3.5-turbo-0301", "gpt-3.5-turbo-0613", "gpt-3.5-turbo-1106", + "gpt-3.5-turbo-0125", "gpt-3.5-turbo-16k-0613", ] x-oaiTypeLabel: string @@ -6150,7 +5864,7 @@ components: response_format: type: object description: | - An object specifying the format that the model must output. Compatible with `gpt-4-1106-preview` and `gpt-3.5-turbo-1106`. + An object specifying the format that the model must output. Compatible with [GPT-4 Turbo](/docs/models/gpt-4-and-gpt-4-turbo) and all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the message the model generates is valid JSON. @@ -6300,7 +6014,7 @@ components: description: A list of message content tokens with log probability information. type: array items: - $ref: '#/components/schemas/ChatCompletionTokenLogprob' + $ref: "#/components/schemas/ChatCompletionTokenLogprob" nullable: true required: - content @@ -6472,136 +6186,44 @@ components: "tool_calls", "content_filter", "function_call", - ] - nullable: true - index: - type: integer - description: The index of the choice in the list of choices. - created: - type: integer - description: The Unix timestamp (in seconds) of when the chat completion was created. Each chunk has the same timestamp. - model: - type: string - description: The model to generate the completion. - system_fingerprint: - type: string - description: | - This fingerprint represents the backend configuration that the model runs with. - Can be used in conjunction with the `seed` request parameter to understand when backend changes have been made that might impact determinism. - object: - type: string - description: The object type, which is always `chat.completion.chunk`. - enum: [chat.completion.chunk] - required: - - choices - - created - - id - - model - - object - x-oaiMeta: - name: The chat completion chunk object - group: chat - example: *chat_completion_chunk_example - - CreateChatCompletionImageResponse: - type: object - description: Represents a streamed chunk of a chat completion response returned by model, based on the provided input. - x-oaiMeta: - name: The chat completion chunk object - group: chat - example: *chat_completion_image_example - - CreateEditRequest: - type: object - properties: - instruction: - description: The instruction that tells the model how to edit the prompt. - type: string - example: "Fix the spelling mistakes." - model: - description: ID of the model to use. You can use the `text-davinci-edit-001` or `code-davinci-edit-001` model with this endpoint. - example: "text-davinci-edit-001" - anyOf: - - type: string - - type: string - enum: ["text-davinci-edit-001", "code-davinci-edit-001"] - x-oaiTypeLabel: string - input: - description: The input text to use as a starting point for the edit. - type: string - default: "" - nullable: true - example: "What day of the wek is it?" - n: - type: integer - minimum: 1 - maximum: 20 - default: 1 - example: 1 - nullable: true - description: How many edits to generate for the input and instruction. - temperature: - type: number - minimum: 0 - maximum: 2 - default: 1 - example: 1 - nullable: true - description: *completions_temperature_description - top_p: - type: number - minimum: 0 - maximum: 1 - default: 1 - example: 1 - nullable: true - description: *completions_top_p_description - required: - - model - - instruction - - CreateEditResponse: - type: object - deprecated: true - title: Edit - properties: - choices: - type: array - description: A list of edit choices. Can be more than one if `n` is greater than 1. - items: - type: object - required: - - text - - index - - finish_reason - properties: - finish_reason: - type: string - description: *completion_finish_reason_description - enum: ["stop", "length"] + ] + nullable: true index: type: integer description: The index of the choice in the list of choices. - text: - type: string - description: The edited result. - object: - type: string - description: The object type, which is always `edit`. - enum: [edit] created: type: integer - description: The Unix timestamp (in seconds) of when the edit was created. - usage: - $ref: "#/components/schemas/CompletionUsage" + description: The Unix timestamp (in seconds) of when the chat completion was created. Each chunk has the same timestamp. + model: + type: string + description: The model to generate the completion. + system_fingerprint: + type: string + description: | + This fingerprint represents the backend configuration that the model runs with. + Can be used in conjunction with the `seed` request parameter to understand when backend changes have been made that might impact determinism. + object: + type: string + description: The object type, which is always `chat.completion.chunk`. + enum: [chat.completion.chunk] required: - - object - - created - choices - - usage + - created + - id + - model + - object + x-oaiMeta: + name: The chat completion chunk object + group: chat + example: *chat_completion_chunk_example + + CreateChatCompletionImageResponse: + type: object + description: Represents a streamed chunk of a chat completion response returned by model, based on the provided input. x-oaiMeta: - name: The edit object - example: *edit_example + name: The chat completion chunk object + group: chat + example: *chat_completion_image_example CreateImageRequest: type: object @@ -7074,194 +6696,6 @@ components: - object - data - CreateFineTuneRequest: - type: object - properties: - training_file: - description: | - The ID of an uploaded file that contains training data. - - See [upload file](/docs/api-reference/files/upload) for how to upload a file. - - Your dataset must be formatted as a JSONL file, where each training - example is a JSON object with the keys "prompt" and "completion". - Additionally, you must upload your file with the purpose `fine-tune`. - - See the [fine-tuning guide](/docs/guides/legacy-fine-tuning/creating-training-data) for more details. - type: string - example: "file-abc123" - batch_size: - description: | - The batch size to use for training. The batch size is the number of - training examples used to train a single forward and backward pass. - - By default, the batch size will be dynamically configured to be - ~0.2% of the number of examples in the training set, capped at 256 - - in general, we've found that larger batch sizes tend to work better - for larger datasets. - default: null - type: integer - nullable: true - classification_betas: - description: | - If this is provided, we calculate F-beta scores at the specified - beta values. The F-beta score is a generalization of F-1 score. - This is only used for binary classification. - - With a beta of 1 (i.e. the F-1 score), precision and recall are - given the same weight. A larger beta score puts more weight on - recall and less on precision. A smaller beta score puts more weight - on precision and less on recall. - type: array - items: - type: number - example: [0.6, 1, 1.5, 2] - default: null - nullable: true - classification_n_classes: - description: | - The number of classes in a classification task. - - This parameter is required for multiclass classification. - type: integer - default: null - nullable: true - classification_positive_class: - description: | - The positive class in binary classification. - - This parameter is needed to generate precision, recall, and F1 - metrics when doing binary classification. - type: string - default: null - nullable: true - compute_classification_metrics: - description: | - If set, we calculate classification-specific metrics such as accuracy - and F-1 score using the validation set at the end of every epoch. - These metrics can be viewed in the [results file](/docs/guides/legacy-fine-tuning/analyzing-your-fine-tuned-model). - - In order to compute classification metrics, you must provide a - `validation_file`. Additionally, you must - specify `classification_n_classes` for multiclass classification or - `classification_positive_class` for binary classification. - type: boolean - default: false - nullable: true - hyperparameters: - type: object - description: The hyperparameters used for the fine-tuning job. - properties: - n_epochs: - description: | - The number of epochs to train the model for. An epoch refers to one - full cycle through the training dataset. - oneOf: - - type: string - enum: [auto] - - type: integer - minimum: 1 - maximum: 50 - default: auto - learning_rate_multiplier: - description: | - The learning rate multiplier to use for training. - The fine-tuning learning rate is the original learning rate used for - pretraining multiplied by this value. - - By default, the learning rate multiplier is the 0.05, 0.1, or 0.2 - depending on final `batch_size` (larger learning rates tend to - perform better with larger batch sizes). We recommend experimenting - with values in the range 0.02 to 0.2 to see what produces the best - results. - default: null - type: number - nullable: true - model: - description: | - The name of the base model to fine-tune. You can select one of "ada", - "babbage", "curie", "davinci", or a fine-tuned model created after 2022-04-21 and before 2023-08-22. - To learn more about these models, see the - [Models](/docs/models) documentation. - default: "curie" - example: "curie" - nullable: true - anyOf: - - type: string - - type: string - enum: ["ada", "babbage", "curie", "davinci"] - x-oaiTypeLabel: string - prompt_loss_weight: - description: | - The weight to use for loss on the prompt tokens. This controls how - much the model tries to learn to generate the prompt (as compared - to the completion which always has a weight of 1.0), and can add - a stabilizing effect to training when completions are short. - - If prompts are extremely long (relative to completions), it may make - sense to reduce this weight so as to avoid over-prioritizing - learning the prompt. - default: 0.01 - type: number - nullable: true - suffix: - description: | - A string of up to 40 characters that will be added to your fine-tuned model name. - - For example, a `suffix` of "custom-model-name" would produce a model name like `ada:ft-your-org:custom-model-name-2022-02-15-04-21-04`. - type: string - minLength: 1 - maxLength: 40 - default: null - nullable: true - validation_file: - description: | - The ID of an uploaded file that contains validation data. - - If you provide this file, the data is used to generate validation - metrics periodically during fine-tuning. These metrics can be viewed in - the [fine-tuning results file](/docs/guides/legacy-fine-tuning/analyzing-your-fine-tuned-model). - Your train and validation data should be mutually exclusive. - - Your dataset must be formatted as a JSONL file, where each validation - example is a JSON object with the keys "prompt" and "completion". - Additionally, you must upload your file with the purpose `fine-tune`. - - See the [fine-tuning guide](/docs/guides/legacy-fine-tuning/creating-training-data) for more details. - type: string - nullable: true - example: "file-abc123" - required: - - training_file - - ListFineTunesResponse: - type: object - properties: - data: - type: array - items: - $ref: "#/components/schemas/FineTune" - object: - type: string - enum: [list] - required: - - object - - data - - ListFineTuneEventsResponse: - type: object - properties: - data: - type: array - items: - $ref: "#/components/schemas/FineTuneEvent" - object: - type: string - enum: [list] - required: - - object - - data - CreateEmbeddingRequest: type: object additionalProperties: false @@ -7307,11 +6741,11 @@ components: x-oaiExpandable: true model: description: *model_description - example: "text-embedding-ada-002" + example: "text-embedding-3-small" anyOf: - type: string - type: string - enum: ["text-embedding-ada-002"] + enum: ["text-embedding-ada-002", "text-embedding-3-small", "text-embedding-3-large"] x-oaiTypeLabel: string encoding_format: description: "The format to return the embeddings in. Can be either `float` or [`base64`](https://pypi.org/project/pybase64/)." @@ -7319,6 +6753,11 @@ components: default: "float" type: string enum: ["float", "base64"] + dimensions: + description: | + The number of dimensions the resulting output embeddings should have. Only supported in `text-embedding-3` and later models. + type: integer + minimum: 1 user: *end_user_param_configuration required: - model @@ -7401,6 +6840,16 @@ components: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use [log probability](https://en.wikipedia.org/wiki/Log_probability) to automatically increase the temperature until certain thresholds are hit. type: number default: 0 + timestamp_granularities[]: + description: | + The timestamp granularities to populate for this transcription. Any of these options: `word`, or `segment`. Note: There is no additional latency for segment timestamps, but generating word timestamps incurs additional latency. + type: array + items: + type: string + enum: + - word + - segment + default: [segment] required: - file - model @@ -7481,10 +6930,14 @@ components: type: string enum: ["alloy", "echo", "fable", "onyx", "nova", "shimmer"] response_format: - description: "The format to audio in. Supported formats are `mp3`, `opus`, `aac`, and `flac`." + description: |- + The format to return audio in. + Supported formats are `mp3`, `opus`, `aac`, `flac`, `pcm`, and `wav`. + + The `pcm` audio format, similar to `wav` but without a header, utilizes a 24kHz sample rate, mono channel, and 16-bit depth in signed little-endian format. default: "mp3" type: string - enum: ["mp3", "opus", "aac", "flac"] + enum: ["mp3", "opus", "aac", "flac", "pcm", "wav"] speed: description: "The speed of the generated audio. Select a value from `0.25` to `4.0`. `1.0` is the default." type: number @@ -7570,7 +7023,7 @@ components: - purpose - status x-oaiMeta: - name: The File object + name: The file object example: | { "id": "file-abc123", @@ -7702,203 +7155,66 @@ components: "cancelled", ] trained_tokens: - type: integer - nullable: true - description: The total number of billable tokens processed by this fine-tuning job. The value will be null if the fine-tuning job is still running. - training_file: - type: string - description: The file ID used for training. You can retrieve the training data with the [Files API](/docs/api-reference/files/retrieve-contents). - validation_file: - type: string - nullable: true - description: The file ID used for validation. You can retrieve the validation results with the [Files API](/docs/api-reference/files/retrieve-contents). - required: - - created_at - - error - - finished_at - - fine_tuned_model - - hyperparameters - - id - - model - - object - - organization_id - - result_files - - status - - trained_tokens - - training_file - - validation_file - x-oaiMeta: - name: The fine-tuning job object - example: *fine_tuning_example - - FineTuningJobEvent: - type: object - description: Fine-tuning job event object - properties: - id: - type: string - created_at: - type: integer - level: - type: string - enum: ["info", "warn", "error"] - message: - type: string - object: - type: string - enum: [fine_tuning.job.event] - required: - - id - - object - - created_at - - level - - message - x-oaiMeta: - name: The fine-tuning job event object - example: | - { - "object": "fine_tuning.job.event", - "id": "ftevent-abc123" - "created_at": 1677610602, - "level": "info", - "message": "Created fine-tuning job" - } - - FineTune: - type: object - deprecated: true - description: | - The `FineTune` object represents a legacy fine-tune job that has been created through the API. - properties: - id: - type: string - description: The object identifier, which can be referenced in the API endpoints. - created_at: - type: integer - description: The Unix timestamp (in seconds) for when the fine-tuning job was created. - events: - type: array - description: The list of events that have been observed in the lifecycle of the FineTune job. - items: - $ref: "#/components/schemas/FineTuneEvent" - fine_tuned_model: - type: string - nullable: true - description: The name of the fine-tuned model that is being created. - hyperparams: - type: object - description: The hyperparameters used for the fine-tuning job. See the [fine-tuning guide](/docs/guides/legacy-fine-tuning/hyperparameters) for more details. - properties: - batch_size: - type: integer - description: | - The batch size to use for training. The batch size is the number of - training examples used to train a single forward and backward pass. - classification_n_classes: - type: integer - description: | - The number of classes to use for computing classification metrics. - classification_positive_class: - type: string - description: | - The positive class to use for computing classification metrics. - compute_classification_metrics: - type: boolean - description: | - The classification metrics to compute using the validation dataset at the end of every epoch. - learning_rate_multiplier: - type: number - description: | - The learning rate multiplier to use for training. - n_epochs: - type: integer - description: | - The number of epochs to train the model for. An epoch refers to one - full cycle through the training dataset. - prompt_loss_weight: - type: number - description: | - The weight to use for loss on the prompt tokens. - required: - - batch_size - - learning_rate_multiplier - - n_epochs - - prompt_loss_weight - model: - type: string - description: The base model that is being fine-tuned. - object: - type: string - description: The object type, which is always "fine-tune". - enum: [fine-tune] - organization_id: + type: integer + nullable: true + description: The total number of billable tokens processed by this fine-tuning job. The value will be null if the fine-tuning job is still running. + training_file: type: string - description: The organization that owns the fine-tuning job. - result_files: - type: array - description: The compiled results files for the fine-tuning job. - items: - $ref: "#/components/schemas/OpenAIFile" - status: + description: The file ID used for training. You can retrieve the training data with the [Files API](/docs/api-reference/files/retrieve-contents). + validation_file: type: string - description: The current status of the fine-tuning job, which can be either `created`, `running`, `succeeded`, `failed`, or `cancelled`. - training_files: - type: array - description: The list of files used for training. - items: - $ref: "#/components/schemas/OpenAIFile" - updated_at: - type: integer - description: The Unix timestamp (in seconds) for when the fine-tuning job was last updated. - validation_files: - type: array - description: The list of files used for validation. - items: - $ref: "#/components/schemas/OpenAIFile" + nullable: true + description: The file ID used for validation. You can retrieve the validation results with the [Files API](/docs/api-reference/files/retrieve-contents). required: - created_at + - error + - finished_at - fine_tuned_model - - hyperparams + - hyperparameters - id - model - object - organization_id - result_files - status - - training_files - - updated_at - - validation_files + - trained_tokens + - training_file + - validation_file x-oaiMeta: - name: The fine-tune object - example: *fine_tune_example + name: The fine-tuning job object + example: *fine_tuning_example - FineTuneEvent: + FineTuningJobEvent: type: object - deprecated: true - description: Fine-tune event object + description: Fine-tuning job event object properties: + id: + type: string created_at: type: integer level: type: string + enum: ["info", "warn", "error"] message: type: string object: type: string - enum: [fine-tune-event] + enum: [fine_tuning.job.event] required: + - id - object - created_at - level - message x-oaiMeta: - name: The fine-tune event object + name: The fine-tuning job event object example: | { - "object": "fine-tune-event", + "object": "fine_tuning.job.event", + "id": "ftevent-abc123" "created_at": 1677610602, "level": "info", - "message": "Created fine-tune job" + "message": "Created fine-tuning job" } CompletionUsage: @@ -7919,6 +7235,44 @@ components: - completion_tokens - total_tokens + RunCompletionUsage: + type: object + description: Usage statistics related to the run. This value will be `null` if the run is not in a terminal state (i.e. `in_progress`, `queued`, etc.). + properties: + completion_tokens: + type: integer + description: Number of completion tokens used over the course of the run. + prompt_tokens: + type: integer + description: Number of prompt tokens used over the course of the run. + total_tokens: + type: integer + description: Total number of tokens used (prompt + completion). + required: + - prompt_tokens + - completion_tokens + - total_tokens + nullable: true + + RunStepCompletionUsage: + type: object + description: Usage statistics related to the run step. This value will be `null` while the run step's status is `in_progress`. + properties: + completion_tokens: + type: integer + description: Number of completion tokens used over the course of the run step. + prompt_tokens: + type: integer + description: Number of prompt tokens used over the course of the run step. + total_tokens: + type: integer + description: Total number of tokens used (prompt + completion). + required: + - prompt_tokens + - completion_tokens + - total_tokens + nullable: true + AssistantObject: type: object title: Assistant @@ -8295,6 +7649,8 @@ components: type: object x-oaiTypeLabel: map nullable: true + usage: + $ref: "#/components/schemas/RunCompletionUsage" required: - id - object @@ -8314,6 +7670,7 @@ components: - tools - file_ids - metadata + - usage x-oaiMeta: name: The run object beta: true @@ -8335,7 +7692,12 @@ components: "instructions": null, "tools": [{"type": "retrieval"}, {"type": "code_interpreter"}], "file_ids": [], - "metadata": {} + "metadata": {}, + "usage": { + "prompt_tokens": 123, + "completion_tokens": 456, + "total_tokens": 579 + } } CreateRunRequest: type: object @@ -8373,6 +7735,7 @@ components: x-oaiTypeLabel: map nullable: true required: + - thread_id - assistant_id ListRunsResponse: type: object @@ -8490,6 +7853,7 @@ components: x-oaiTypeLabel: map nullable: true required: + - thread_id - assistant_id ThreadObject: @@ -8955,6 +8319,8 @@ components: type: object x-oaiTypeLabel: map nullable: true + usage: + $ref: "#/components/schemas/RunStepCompletionUsage" required: - id - object @@ -8971,6 +8337,7 @@ components: - failed_at - completed_at - metadata + - usage x-oaiMeta: name: The run step object beta: true @@ -9036,7 +8403,6 @@ components: description: | An array of tool calls the run step was involved in. These can be associated with one of three types of tools: `code_interpreter`, `retrieval`, or `function`. items: - type: object oneOf: - $ref: "#/components/schemas/RunStepDetailsToolCallsCodeObject" - $ref: "#/components/schemas/RunStepDetailsToolCallsRetrievalObject" @@ -9366,15 +8732,15 @@ x-oaiMeta: Related guide: [Chat Completions](/docs/guides/text-generation) sections: + - type: endpoint + key: createChatCompletion + path: create - type: object key: CreateChatCompletionResponse path: object - type: object key: CreateChatCompletionStreamResponse path: streaming - - type: endpoint - key: createChatCompletion - path: create - id: embeddings title: Embeddings description: | @@ -9382,12 +8748,12 @@ x-oaiMeta: Related guide: [Embeddings](/docs/guides/embeddings) sections: - - type: object - key: Embedding - path: object - type: endpoint key: createEmbedding path: create + - type: object + key: Embedding + path: object - id: fine-tuning title: Fine-tuning description: | @@ -9395,50 +8761,50 @@ x-oaiMeta: Related guide: [Fine-tune models](/docs/guides/fine-tuning) sections: - - type: object - key: FineTuningJob - path: object - type: endpoint key: createFineTuningJob path: create - type: endpoint key: listPaginatedFineTuningJobs path: list + - type: endpoint + key: listFineTuningEvents + path: list-events - type: endpoint key: retrieveFineTuningJob path: retrieve - type: endpoint key: cancelFineTuningJob path: cancel + - type: object + key: FineTuningJob + path: object - type: object key: FineTuningJobEvent path: event-object - - type: endpoint - key: listFineTuningEvents - path: list-events - id: files title: Files description: | Files are used to upload documents that can be used with features like [Assistants](/docs/api-reference/assistants) and [Fine-tuning](/docs/api-reference/fine-tuning). sections: - - type: object - key: OpenAIFile - path: object - - type: endpoint - key: listFiles - path: list - type: endpoint key: createFile path: create - type: endpoint - key: deleteFile - path: delete + key: listFiles + path: list - type: endpoint key: retrieveFile path: retrieve + - type: endpoint + key: deleteFile + path: delete - type: endpoint key: downloadFile path: retrieve-contents + - type: object + key: OpenAIFile + path: object - id: images title: Images description: | @@ -9446,9 +8812,6 @@ x-oaiMeta: Related guide: [Image generation](/docs/guides/images) sections: - - type: object - key: Image - path: object - type: endpoint key: createImage path: create @@ -9458,14 +8821,14 @@ x-oaiMeta: - type: endpoint key: createImageVariation path: createVariation + - type: object + key: Image + path: object - id: models title: Models description: | List and describe the various models available in the API. You can refer to the [Models](/docs/models) documentation to understand what models are available and the differences between them. sections: - - type: object - key: Model - path: object - type: endpoint key: listModels path: list @@ -9475,6 +8838,9 @@ x-oaiMeta: - type: endpoint key: deleteModel path: delete + - type: object + key: Model + path: object - id: moderations title: Moderations description: | @@ -9482,12 +8848,12 @@ x-oaiMeta: Related guide: [Moderations](/docs/guides/moderation) sections: - - type: object - key: CreateModerationResponse - path: object - type: endpoint key: createModeration path: create + - type: object + key: CreateModerationResponse + path: object - id: assistants title: Assistants beta: true @@ -9496,15 +8862,24 @@ x-oaiMeta: [Get started with the Assistants API](/docs/assistants) sections: - - type: object - key: AssistantObject - path: object - type: endpoint key: createAssistant path: createAssistant + - type: endpoint + key: createAssistantFile + path: createAssistantFile + - type: endpoint + key: listAssistants + path: listAssistants + - type: endpoint + key: listAssistantFiles + path: listAssistantFiles - type: endpoint key: getAssistant path: getAssistant + - type: endpoint + key: getAssistantFile + path: getAssistantFile - type: endpoint key: modifyAssistant path: modifyAssistant @@ -9512,23 +8887,14 @@ x-oaiMeta: key: deleteAssistant path: deleteAssistant - type: endpoint - key: listAssistants - path: listAssistants + key: deleteAssistantFile + path: deleteAssistantFile + - type: object + key: AssistantObject + path: object - type: object key: AssistantFileObject path: file-object - - type: endpoint - key: createAssistantFile - path: createAssistantFile - - type: endpoint - key: getAssistantFile - path: getAssistantFile - - type: endpoint - key: deleteAssistantFile - path: deleteAssistantFile - - type: endpoint - key: listAssistantFiles - path: listAssistantFiles - id: threads title: Threads beta: true @@ -9537,9 +8903,6 @@ x-oaiMeta: Related guide: [Assistants](/docs/assistants/overview) sections: - - type: object - key: ThreadObject - path: object - type: endpoint key: createThread path: createThread @@ -9552,6 +8915,9 @@ x-oaiMeta: - type: endpoint key: deleteThread path: deleteThread + - type: object + key: ThreadObject + path: object - id: messages title: Messages beta: true @@ -9560,30 +8926,30 @@ x-oaiMeta: Related guide: [Assistants](/docs/assistants/overview) sections: - - type: object - key: MessageObject - path: object - type: endpoint key: createMessage path: createMessage + - type: endpoint + key: listMessages + path: listMessages + - type: endpoint + key: listMessageFiles + path: listMessageFiles - type: endpoint key: getMessage path: getMessage + - type: endpoint + key: getMessageFile + path: getMessageFile - type: endpoint key: modifyMessage path: modifyMessage - - type: endpoint - key: listMessages - path: listMessages + - type: object + key: MessageObject + path: object - type: object key: MessageFileObject path: file-object - - type: endpoint - key: getMessageFile - path: getMessageFile - - type: endpoint - key: listMessageFiles - path: listMessageFiles - id: runs title: Runs beta: true @@ -9592,89 +8958,48 @@ x-oaiMeta: Related guide: [Assistants](/docs/assistants/overview) sections: - - type: object - key: RunObject - path: object - type: endpoint key: createRun path: createRun + - type: endpoint + key: createThreadAndRun + path: createThreadAndRun + - type: endpoint + key: listRuns + path: listRuns + - type: endpoint + key: listRunSteps + path: listRunSteps - type: endpoint key: getRun path: getRun + - type: endpoint + key: getRunStep + path: getRunStep - type: endpoint key: modifyRun path: modifyRun - - type: endpoint - key: listRuns - path: listRuns - type: endpoint key: submitToolOuputsToRun path: submitToolOutputs - type: endpoint key: cancelRun path: cancelRun - - type: endpoint - key: createThreadAndRun - path: createThreadAndRun + - type: object + key: RunObject + path: object - type: object key: RunStepObject path: step-object - - type: endpoint - key: getRunStep - path: getRunStep - - type: endpoint - key: listRunSteps - path: listRunSteps - id: completions title: Completions legacy: true description: | Given a prompt, the model will return one or more predicted completions along with the probabilities of alternative tokens at each position. Most developer should use our [Chat Completions API](/docs/guides/text-generation/text-generation-models) to leverage our best and newest models. Most models that support the legacy Completions endpoint [will be shut off on January 4th, 2024](/docs/deprecations/2023-07-06-gpt-and-embeddings). sections: - - type: object - key: CreateCompletionResponse - path: object - type: endpoint key: createCompletion path: create - - id: edits - title: Edits - deprecated: true - description: | - Given a prompt and an instruction, the model will return an edited version of the prompt. The Edits endpoint is deprecated will be [shut off on January 4th, 2024](/docs/deprecations/edit-models-endpoint). - sections: - - type: object - key: CreateEditResponse - path: object - - type: endpoint - key: createEdit - path: create - - id: fine-tunes - title: Fine-tunes - deprecated: true - description: | - Manage fine-tuning jobs to tailor a model to your specific training data. The [updated Fine-tuning endpoint](/docs/guides/fine-tuning) offers more capabilites and newer models. - - The Fine-tunes endpoint will be [shut off on January 4th, 2024](/docs/deprecations/2023-08-22-fine-tunes-endpoint). - sections: - type: object - key: FineTune + key: CreateCompletionResponse path: object - - type: endpoint - key: createFineTune - path: create - - type: endpoint - key: listFineTunes - path: list - - type: endpoint - key: retrieveFineTune - path: retrieve - - type: endpoint - key: cancelFineTune - path: cancel - - type: object - key: FineTuneEvent - path: event-object - - type: endpoint - key: listFineTuneEvents - path: list-events